kernel: update patches

Signed-off-by: Arif Alam <arif.alam@netexperience.com>
This commit is contained in:
Arif Alam
2025-07-28 20:11:31 -04:00
parent b2dacf060c
commit aadfd5ceff
104 changed files with 12749 additions and 22671 deletions

View File

@@ -119,6 +119,7 @@
memory@40000000 {
- reg = <0 0x40000000 0 0x20000000>;
+ reg = <0 0x40000000 0 0x40000000>;
device_type = "memory";
};
reg_1p8v: regulator-1p8v {

View File

@@ -0,0 +1,31 @@
From b341f120cfc9ca1dfd48364b7f36ac2c1fbdea43 Mon Sep 17 00:00:00 2001
From: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
Date: Wed, 3 Apr 2019 16:30:01 +0800
Subject: [PATCH 3/6] mtd: spinand: disable on-die ECC
Change-Id: I9745adaed5295202fabbe8ab8947885c57a5b847
Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
---
drivers/mtd/nand/spi/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -491,7 +491,7 @@ static int spinand_mtd_read(struct mtd_i
int ret = 0;
if (ops->mode != MTD_OPS_RAW && spinand->eccinfo.ooblayout)
- enable_ecc = true;
+ enable_ecc = false;
mutex_lock(&spinand->lock);
@@ -539,7 +539,7 @@ static int spinand_mtd_write(struct mtd_
int ret = 0;
if (ops->mode != MTD_OPS_RAW && mtd->ooblayout)
- enable_ecc = true;
+ enable_ecc = false;
mutex_lock(&spinand->lock);

View File

@@ -389,25 +389,20 @@ Signed-off-by: chuanjia.liu <Chuanjia.Liu@mediatek.com>
<0 0 0 2 &pcie_intc1 1>,
--- a/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7622-rfb1.dts
@@ -254,18 +254,16 @@
@@ -184,14 +184,16 @@
};
};
-&pcie {
+&pcie0 {
pinctrl-names = "default";
- pinctrl-0 = <&pcie0_pins>, <&pcie1_pins>;
+ pinctrl-0 = <&pcie0_pins>;
pinctrl-0 = <&pcie0_pins>;
status = "okay";
+};
- pcie@0,0 {
- status = "okay";
- };
-
- pcie@1,0 {
- status = "okay";
- };
+&pcie1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pcie1_pins>;

View File

@@ -0,0 +1,980 @@
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -919,6 +919,10 @@ struct xfrmdev_ops {
bool (*xdo_dev_offload_ok) (struct sk_buff *skb,
struct xfrm_state *x);
void (*xdo_dev_state_advance_esn) (struct xfrm_state *x);
+ void (*xdo_dev_state_update_curlft) (struct xfrm_state *x);
+ int (*xdo_dev_policy_add) (struct xfrm_policy *x);
+ void (*xdo_dev_policy_delete) (struct xfrm_policy *x);
+ void (*xdo_dev_policy_free) (struct xfrm_policy *x);
};
#endif
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -125,11 +125,25 @@ struct xfrm_state_walk {
struct xfrm_address_filter *filter;
};
+enum {
+ XFRM_DEV_OFFLOAD_IN = 1,
+ XFRM_DEV_OFFLOAD_OUT,
+ XFRM_DEV_OFFLOAD_FWD,
+};
+
+enum {
+ XFRM_DEV_OFFLOAD_UNSPECIFIED,
+ XFRM_DEV_OFFLOAD_CRYPTO,
+ XFRM_DEV_OFFLOAD_PACKET,
+};
+
struct xfrm_state_offload {
struct net_device *dev;
unsigned long offload_handle;
unsigned int num_exthdrs;
u8 flags;
+ u8 dir : 2;
+ u8 type : 2;
};
struct xfrm_mode {
@@ -527,6 +541,8 @@ struct xfrm_policy {
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
struct hlist_node bydst_inexact_list;
struct rcu_head rcu;
+
+ struct xfrm_state_offload xdo;
};
static inline struct net *xp_net(const struct xfrm_policy *xp)
@@ -1084,6 +1100,29 @@ xfrm_state_addr_cmp(const struct xfrm_tm
}
#ifdef CONFIG_XFRM
+static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
+{
+ struct sec_path *sp = skb_sec_path(skb);
+
+ return sp->xvec[sp->len - 1];
+}
+#endif
+
+static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
+{
+#ifdef CONFIG_XFRM
+ struct sec_path *sp = skb_sec_path(skb);
+
+ if (!sp || !sp->olen || sp->len != sp->olen)
+ return NULL;
+
+ return &sp->ovec[sp->olen - 1];
+#else
+ return NULL;
+#endif
+}
+
+#ifdef CONFIG_XFRM
int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb,
unsigned short family);
@@ -1093,10 +1132,19 @@ static inline int __xfrm_policy_check2(s
{
struct net *net = dev_net(skb->dev);
int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0);
+ struct xfrm_offload *xo = xfrm_offload(skb);
+ struct xfrm_state *x;
if (sk && sk->sk_policy[XFRM_POLICY_IN])
return __xfrm_policy_check(sk, ndir, skb, family);
+ if (xo) {
+ x = xfrm_input_state(skb);
+ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
+ return (xo->flags & CRYPTO_DONE) &&
+ (xo->status & CRYPTO_SUCCESS);
+ }
+
return (!net->xfrm.policy_count[dir] && !secpath_exists(skb)) ||
(skb_dst(skb) && (skb_dst(skb)->flags & DST_NOPOLICY)) ||
__xfrm_policy_check(sk, ndir, skb, family);
@@ -1490,6 +1538,23 @@ struct xfrm_state *xfrm_stateonly_find(s
struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi,
unsigned short family);
int xfrm_state_check_expire(struct xfrm_state *x);
+#ifdef CONFIG_XFRM_OFFLOAD
+static inline void xfrm_dev_state_update_curlft(struct xfrm_state *x)
+{
+ struct xfrm_state_offload *xdo = &x->xso;
+ struct net_device *dev = xdo->dev;
+
+ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
+ return;
+
+ if (dev && dev->xfrmdev_ops &&
+ dev->xfrmdev_ops->xdo_dev_state_update_curlft)
+ dev->xfrmdev_ops->xdo_dev_state_update_curlft(x);
+
+}
+#else
+static inline void xfrm_dev_state_update_curlft(struct xfrm_state *x) {}
+#endif
void xfrm_state_insert(struct xfrm_state *x);
int xfrm_state_add(struct xfrm_state *x);
int xfrm_state_update(struct xfrm_state *x);
@@ -1539,6 +1604,8 @@ struct xfrm_state *xfrm_find_acq_byseq(s
int xfrm_state_delete(struct xfrm_state *x);
int xfrm_state_flush(struct net *net, u8 proto, bool task_valid, bool sync);
int xfrm_dev_state_flush(struct net *net, struct net_device *dev, bool task_valid);
+int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
+ bool task_valid);
void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si);
void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si);
u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq);
@@ -1820,29 +1887,6 @@ static inline void xfrm_states_delete(st
}
#endif
-#ifdef CONFIG_XFRM
-static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb)
-{
- struct sec_path *sp = skb_sec_path(skb);
-
- return sp->xvec[sp->len - 1];
-}
-#endif
-
-static inline struct xfrm_offload *xfrm_offload(struct sk_buff *skb)
-{
-#ifdef CONFIG_XFRM
- struct sec_path *sp = skb_sec_path(skb);
-
- if (!sp || !sp->olen || sp->len != sp->olen)
- return NULL;
-
- return &sp->ovec[sp->olen - 1];
-#else
- return NULL;
-#endif
-}
-
void __init xfrm_dev_init(void);
#ifdef CONFIG_XFRM_OFFLOAD
@@ -1851,6 +1895,9 @@ void xfrm_dev_backlog(struct softnet_dat
struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again);
int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
struct xfrm_user_offload *xuo);
+int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
+ struct xfrm_user_offload *xuo, u8 dir,
+ struct netlink_ext_ack *extack);
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x);
static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
@@ -1899,6 +1946,27 @@ static inline void xfrm_dev_state_free(s
dev_put(dev);
}
}
+
+static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
+{
+ struct xfrm_state_offload *xdo = &x->xdo;
+ struct net_device *dev = xdo->dev;
+
+ if (dev && dev->xfrmdev_ops && dev->xfrmdev_ops->xdo_dev_policy_delete)
+ dev->xfrmdev_ops->xdo_dev_policy_delete(x);
+}
+
+static inline void xfrm_dev_policy_free(struct xfrm_policy *x)
+{
+ struct xfrm_state_offload *xdo = &x->xdo;
+ struct net_device *dev = xdo->dev;
+
+ if (dev && dev->xfrmdev_ops) {
+ if (dev->xfrmdev_ops->xdo_dev_policy_free)
+ dev->xfrmdev_ops->xdo_dev_policy_free(x);
+ xdo->dev = NULL;
+ }
+}
#else
static inline void xfrm_dev_resume(struct sk_buff *skb)
{
@@ -1931,6 +1999,21 @@ static inline bool xfrm_dev_offload_ok(s
return false;
}
+static inline int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
+ struct xfrm_user_offload *xuo, u8 dir,
+ struct netlink_ext_ack *extack)
+{
+ return 0;
+}
+
+static inline void xfrm_dev_policy_delete(struct xfrm_policy *x)
+{
+}
+
+static inline void xfrm_dev_policy_free(struct xfrm_policy *x)
+{
+}
+
static inline void xfrm_dev_state_advance_esn(struct xfrm_state *x)
{
}
--- a/include/uapi/linux/xfrm.h
+++ b/include/uapi/linux/xfrm.h
@@ -512,6 +512,12 @@ struct xfrm_user_offload {
*/
#define XFRM_OFFLOAD_IPV6 1
#define XFRM_OFFLOAD_INBOUND 2
+/* Two bits above are relevant for state path only, while
+ * offload is used for both policy and state flows.
+ *
+ * In policy offload mode, they are free and can be safely reused.
+ */
+#define XFRM_OFFLOAD_PACKET 4
#ifndef __KERNEL__
/* backwards compatibility for userspace */
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -80,6 +80,7 @@ struct sk_buff *validate_xmit_xfrm(struc
struct softnet_data *sd;
netdev_features_t esp_features = features;
struct xfrm_offload *xo = xfrm_offload(skb);
+ struct net_device *dev = skb->dev;
struct sec_path *sp;
if (!xo || (xo->flags & XFRM_XMIT))
@@ -93,6 +94,17 @@ struct sk_buff *validate_xmit_xfrm(struc
if (xo->flags & XFRM_GRO || x->xso.flags & XFRM_OFFLOAD_INBOUND)
return skb;
+ /* The packet was sent to HW IPsec packet offload engine,
+ * but to wrong device. Drop the packet, so it won't skip
+ * XFRM stack.
+ */
+ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET && x->xso.dev != dev) {
+ kfree_skb(skb);
+ //dev_core_stats_tx_dropped_inc(dev);
+ atomic_long_inc(&dev->tx_dropped);
+ return NULL;
+ }
+
local_irq_save(flags);
sd = this_cpu_ptr(&softnet_data);
err = !skb_queue_empty(&sd->xfrm_backlog);
@@ -198,6 +210,7 @@ int xfrm_dev_state_add(struct net *net,
struct xfrm_state_offload *xso = &x->xso;
xfrm_address_t *saddr;
xfrm_address_t *daddr;
+ bool is_packet_offload;
if (!x->type_offload)
return -EINVAL;
@@ -206,9 +219,11 @@ int xfrm_dev_state_add(struct net *net,
if (x->encap || x->tfcpad)
return -EINVAL;
- if (xuo->flags & ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND))
+ if (xuo->flags &
+ ~(XFRM_OFFLOAD_IPV6 | XFRM_OFFLOAD_INBOUND | XFRM_OFFLOAD_PACKET))
return -EINVAL;
+ is_packet_offload = xuo->flags & XFRM_OFFLOAD_PACKET;
dev = dev_get_by_index(net, xuo->ifindex);
if (!dev) {
if (!(xuo->flags & XFRM_OFFLOAD_INBOUND)) {
@@ -223,7 +238,7 @@ int xfrm_dev_state_add(struct net *net,
x->props.family,
xfrm_smark_get(0, x));
if (IS_ERR(dst))
- return 0;
+ return (is_packet_offload) ? -EINVAL : 0;
dev = dst->dev;
@@ -234,7 +249,7 @@ int xfrm_dev_state_add(struct net *net,
if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_state_add) {
xso->dev = NULL;
dev_put(dev);
- return 0;
+ return (is_packet_offload) ? -EINVAL : 0;
}
if (x->props.flags & XFRM_STATE_ESN &&
@@ -249,14 +264,28 @@ int xfrm_dev_state_add(struct net *net,
/* Don't forward bit that is not implemented */
xso->flags = xuo->flags & ~XFRM_OFFLOAD_IPV6;
+ if (is_packet_offload)
+ xso->type = XFRM_DEV_OFFLOAD_PACKET;
+ else
+ xso->type = XFRM_DEV_OFFLOAD_CRYPTO;
+
err = dev->xfrmdev_ops->xdo_dev_state_add(x);
if (err) {
xso->num_exthdrs = 0;
xso->flags = 0;
xso->dev = NULL;
dev_put(dev);
+ xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
- if (err != -EOPNOTSUPP)
+ /* User explicitly requested packet offload mode and configured
+ * policy in addition to the XFRM state. So be civil to users,
+ * and return an error instead of taking fallback path.
+ *
+ * This WARN_ON() can be seen as a documentation for driver
+ * authors to do not return -EOPNOTSUPP in packet offload mode.
+ */
+ WARN_ON(err == -EOPNOTSUPP && is_packet_offload);
+ if (err != -EOPNOTSUPP || is_packet_offload)
return err;
}
@@ -264,6 +293,65 @@ int xfrm_dev_state_add(struct net *net,
}
EXPORT_SYMBOL_GPL(xfrm_dev_state_add);
+int xfrm_dev_policy_add(struct net *net, struct xfrm_policy *xp,
+ struct xfrm_user_offload *xuo, u8 dir,
+ struct netlink_ext_ack *extack)
+{
+ struct xfrm_state_offload *xdo = &xp->xdo;
+ struct net_device *dev;
+ int err;
+
+ if (!xuo->flags || xuo->flags & ~XFRM_OFFLOAD_PACKET) {
+ /* We support only packet offload mode and it means
+ * that user must set XFRM_OFFLOAD_PACKET bit.
+ */
+ NL_SET_ERR_MSG(extack, "Unrecognized flags in offload request");
+ return -EINVAL;
+ }
+
+ dev = dev_get_by_index(net, xuo->ifindex);
+ if (!dev)
+ return -EINVAL;
+
+ if (!dev->xfrmdev_ops || !dev->xfrmdev_ops->xdo_dev_policy_add) {
+ xdo->dev = NULL;
+ dev_put(dev);
+ NL_SET_ERR_MSG(extack, "Policy offload is not supported");
+ return -EINVAL;
+ }
+
+ xdo->dev = dev;
+ xdo->type = XFRM_DEV_OFFLOAD_PACKET;
+ switch (dir) {
+ case XFRM_POLICY_IN:
+ xdo->dir = XFRM_DEV_OFFLOAD_IN;
+ break;
+ case XFRM_POLICY_OUT:
+ xdo->dir = XFRM_DEV_OFFLOAD_OUT;
+ break;
+ case XFRM_POLICY_FWD:
+ xdo->dir = XFRM_DEV_OFFLOAD_FWD;
+ break;
+ default:
+ xdo->dev = NULL;
+ dev_put(dev);
+ NL_SET_ERR_MSG(extack, "Unrecognized oflload direction");
+ return -EINVAL;
+ }
+
+ err = dev->xfrmdev_ops->xdo_dev_policy_add(xp);
+ if (err) {
+ xdo->dev = NULL;
+ xdo->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
+ xdo->dir = 0;
+ NL_SET_ERR_MSG(extack, "Device failed to offload this policy");
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xfrm_dev_policy_add);
+
bool xfrm_dev_offload_ok(struct sk_buff *skb, struct xfrm_state *x)
{
int mtu;
@@ -274,8 +362,9 @@ bool xfrm_dev_offload_ok(struct sk_buff
if (!x->type_offload || x->encap)
return false;
- if ((!dev || (dev == xfrm_dst_path(dst)->dev)) &&
- (!xdst->child->xfrm)) {
+ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET ||
+ ((!dev || (dev == xfrm_dst_path(dst)->dev)) &&
+ !xdst->child->xfrm)) {
mtu = xfrm_state_mtu(x, xdst->child_mtu_cached);
if (skb->len <= mtu)
goto ok;
@@ -376,8 +465,10 @@ static int xfrm_dev_feat_change(struct n
static int xfrm_dev_down(struct net_device *dev)
{
- if (dev->features & NETIF_F_HW_ESP)
+ if (dev->features & NETIF_F_HW_ESP) {
xfrm_dev_state_flush(dev_net(dev), dev, true);
+ xfrm_dev_policy_flush(dev_net(dev), dev, true);
+ }
return NOTIFY_DONE;
}
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -410,7 +410,7 @@ static int xfrm_output_one(struct sk_buf
struct xfrm_state *x = dst->xfrm;
struct net *net = xs_net(x);
- if (err <= 0)
+ if (err <= 0 || x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
goto resume;
do {
@@ -568,6 +568,16 @@ int xfrm_output(struct sock *sk, struct
struct xfrm_state *x = skb_dst(skb)->xfrm;
int err;
+ if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
+ if (!xfrm_dev_offload_ok(skb, x)) {
+ XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
+ kfree_skb(skb);
+ return -EHOSTUNREACH;
+ }
+
+ return xfrm_output_resume(skb, 0);
+ }
+
secpath_reset(skb);
if (xfrm_dev_offload_ok(skb, x)) {
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -423,6 +423,7 @@ void xfrm_policy_destroy(struct xfrm_pol
if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer))
BUG();
+ xfrm_dev_policy_free(policy);
call_rcu(&policy->rcu, xfrm_policy_destroy_rcu);
}
EXPORT_SYMBOL(xfrm_policy_destroy);
@@ -533,7 +534,7 @@ redo:
__get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
pol->family, nhashmask, dbits, sbits);
- if (!entry0) {
+ if (!entry0 || pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
hlist_del_rcu(&pol->bydst);
hlist_add_head_rcu(&pol->bydst, ndsttable + h);
h0 = h;
@@ -864,7 +865,7 @@ static void xfrm_policy_inexact_list_rei
break;
}
- if (newpos)
+ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
hlist_add_behind_rcu(&policy->bydst, newpos);
else
hlist_add_head_rcu(&policy->bydst, &n->hhead);
@@ -1345,7 +1346,7 @@ static void xfrm_hash_rebuild(struct wor
else
break;
}
- if (newpos)
+ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
hlist_add_behind_rcu(&policy->bydst, newpos);
else
hlist_add_head_rcu(&policy->bydst, chain);
@@ -1522,7 +1523,7 @@ static void xfrm_policy_insert_inexact_l
break;
}
- if (newpos)
+ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
hlist_add_behind_rcu(&policy->bydst_inexact_list, newpos);
else
hlist_add_head_rcu(&policy->bydst_inexact_list, chain);
@@ -1559,9 +1560,12 @@ static struct xfrm_policy *xfrm_policy_i
break;
}
- if (newpos)
+ if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET)
hlist_add_behind_rcu(&policy->bydst, &newpos->bydst);
else
+ /* Packet offload policies enter to the head
+ * to speed-up lookups.
+ */
hlist_add_head_rcu(&policy->bydst, chain);
return delpol;
@@ -1767,12 +1771,41 @@ xfrm_policy_flush_secctx_check(struct ne
}
return err;
}
+
+static inline int xfrm_dev_policy_flush_secctx_check(struct net *net,
+ struct net_device *dev,
+ bool task_valid)
+{
+ struct xfrm_policy *pol;
+ int err = 0;
+
+ list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
+ if (pol->walk.dead ||
+ xfrm_policy_id2dir(pol->index) >= XFRM_POLICY_MAX ||
+ pol->xdo.dev != dev)
+ continue;
+
+ err = security_xfrm_policy_delete(pol->security);
+ if (err) {
+ xfrm_audit_policy_delete(pol, 0, task_valid);
+ return err;
+ }
+ }
+ return err;
+}
#else
static inline int
xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid)
{
return 0;
}
+
+static inline int xfrm_dev_policy_flush_secctx_check(struct net *net,
+ struct net_device *dev,
+ bool task_valid)
+{
+ return 0;
+}
#endif
int xfrm_policy_flush(struct net *net, u8 type, bool task_valid)
@@ -1812,6 +1845,44 @@ out:
}
EXPORT_SYMBOL(xfrm_policy_flush);
+int xfrm_dev_policy_flush(struct net *net, struct net_device *dev,
+ bool task_valid)
+{
+ int dir, err = 0, cnt = 0;
+ struct xfrm_policy *pol;
+
+ spin_lock_bh(&net->xfrm.xfrm_policy_lock);
+
+ err = xfrm_dev_policy_flush_secctx_check(net, dev, task_valid);
+ if (err)
+ goto out;
+
+again:
+ list_for_each_entry(pol, &net->xfrm.policy_all, walk.all) {
+ dir = xfrm_policy_id2dir(pol->index);
+ if (pol->walk.dead ||
+ dir >= XFRM_POLICY_MAX ||
+ pol->xdo.dev != dev)
+ continue;
+
+ __xfrm_policy_unlink(pol, dir);
+ spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
+ cnt++;
+ xfrm_audit_policy_delete(pol, 1, task_valid);
+ xfrm_policy_kill(pol);
+ spin_lock_bh(&net->xfrm.xfrm_policy_lock);
+ goto again;
+ }
+ if (cnt)
+ __xfrm_policy_inexact_flush(net);
+ else
+ err = -ESRCH;
+out:
+ spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
+ return err;
+}
+EXPORT_SYMBOL(xfrm_dev_policy_flush);
+
int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk,
int (*func)(struct xfrm_policy *, int, int, void*),
void *data)
@@ -2113,6 +2184,9 @@ static struct xfrm_policy *xfrm_policy_l
break;
}
}
+ if (ret && ret->xdo.type == XFRM_DEV_OFFLOAD_PACKET)
+ goto skip_inexact;
+
bin = xfrm_policy_inexact_lookup_rcu(net, type, family, dir, if_id);
if (!bin || !xfrm_policy_find_inexact_candidates(&cand, bin, saddr,
daddr))
@@ -2246,6 +2320,7 @@ int xfrm_policy_delete(struct xfrm_polic
pol = __xfrm_policy_unlink(pol, dir);
spin_unlock_bh(&net->xfrm.xfrm_policy_lock);
if (pol) {
+ xfrm_dev_policy_delete(pol);
xfrm_policy_kill(pol);
return 0;
}
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -78,6 +78,25 @@ xfrm_spi_hash(struct net *net, const xfr
return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask);
}
+#define XFRM_STATE_INSERT(by, _n, _h, _type) \
+ { \
+ struct xfrm_state *_x = NULL; \
+ \
+ if (_type != XFRM_DEV_OFFLOAD_PACKET) { \
+ hlist_for_each_entry_rcu(_x, _h, by) { \
+ if (_x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \
+ continue; \
+ break; \
+ } \
+ } \
+ \
+ if (!_x || _x->xso.type == XFRM_DEV_OFFLOAD_PACKET) \
+ /* SAD is empty or consist from HW SAs only */ \
+ hlist_add_head_rcu(_n, _h); \
+ else \
+ hlist_add_before_rcu(_n, &_x->by); \
+ }
+
static void xfrm_hash_transfer(struct hlist_head *list,
struct hlist_head *ndsttable,
struct hlist_head *nsrctable,
@@ -93,18 +112,19 @@ static void xfrm_hash_transfer(struct hl
h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr,
x->props.reqid, x->props.family,
nhashmask);
- hlist_add_head_rcu(&x->bydst, ndsttable + h);
+ XFRM_STATE_INSERT(bydst, &x->bydst, ndsttable + h, x->xso.type);
h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
x->props.family,
nhashmask);
- hlist_add_head_rcu(&x->bysrc, nsrctable + h);
+ XFRM_STATE_INSERT(bysrc, &x->bysrc, nsrctable + h, x->xso.type);
if (x->id.spi) {
h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
x->id.proto, x->props.family,
nhashmask);
- hlist_add_head_rcu(&x->byspi, nspitable + h);
+ XFRM_STATE_INSERT(byspi, &x->byspi, nspitable + h,
+ x->xso.type);
}
}
}
@@ -527,6 +547,8 @@ static enum hrtimer_restart xfrm_timer_h
int err = 0;
spin_lock(&x->lock);
+ xfrm_dev_state_update_curlft(x);
+
if (x->km.state == XFRM_STATE_DEAD)
goto out;
if (x->km.state == XFRM_STATE_EXPIRED)
@@ -923,6 +945,49 @@ xfrm_init_tempstate(struct xfrm_state *x
x->props.family = tmpl->encap_family;
}
+static struct xfrm_state *__xfrm_state_lookup_all(struct net *net, u32 mark,
+ const xfrm_address_t *daddr,
+ __be32 spi, u8 proto,
+ unsigned short family,
+ struct xfrm_state_offload *xdo)
+{
+ unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family);
+ struct xfrm_state *x;
+
+ hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) {
+#ifdef CONFIG_XFRM_OFFLOAD
+ if (xdo->type == XFRM_DEV_OFFLOAD_PACKET) {
+ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
+ /* HW states are in the head of list, there is
+ * no need to iterate further.
+ */
+ break;
+
+ /* Packet offload: both policy and SA should
+ * have same device.
+ */
+ if (xdo->dev != x->xso.dev)
+ continue;
+ } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
+ /* Skip HW policy for SW lookups */
+ continue;
+#endif
+ if (x->props.family != family ||
+ x->id.spi != spi ||
+ x->id.proto != proto ||
+ !xfrm_addr_equal(&x->id.daddr, daddr, family))
+ continue;
+
+ if ((mark & x->mark.m) != x->mark.v)
+ continue;
+ if (!xfrm_state_hold_rcu(x))
+ continue;
+ return x;
+ }
+
+ return NULL;
+}
+
static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark,
const xfrm_address_t *daddr,
__be32 spi, u8 proto,
@@ -1062,6 +1127,23 @@ xfrm_state_find(const xfrm_address_t *da
rcu_read_lock();
h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family);
hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) {
+#ifdef CONFIG_XFRM_OFFLOAD
+ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
+ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
+ /* HW states are in the head of list, there is
+ * no need to iterate further.
+ */
+ break;
+
+ /* Packet offload: both policy and SA should
+ * have same device.
+ */
+ if (pol->xdo.dev != x->xso.dev)
+ continue;
+ } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
+ /* Skip HW policy for SW lookups */
+ continue;
+#endif
if (x->props.family == encap_family &&
x->props.reqid == tmpl->reqid &&
(mark & x->mark.m) == x->mark.v &&
@@ -1079,6 +1161,23 @@ xfrm_state_find(const xfrm_address_t *da
h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family);
hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) {
+#ifdef CONFIG_XFRM_OFFLOAD
+ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
+ if (x->xso.type != XFRM_DEV_OFFLOAD_PACKET)
+ /* HW states are in the head of list, there is
+ * no need to iterate further.
+ */
+ break;
+
+ /* Packet offload: both policy and SA should
+ * have same device.
+ */
+ if (pol->xdo.dev != x->xso.dev)
+ continue;
+ } else if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
+ /* Skip HW policy for SW lookups */
+ continue;
+#endif
if (x->props.family == encap_family &&
x->props.reqid == tmpl->reqid &&
(mark & x->mark.m) == x->mark.v &&
@@ -1096,8 +1195,10 @@ found:
x = best;
if (!x && !error && !acquire_in_progress) {
if (tmpl->id.spi &&
- (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi,
- tmpl->id.proto, encap_family)) != NULL) {
+ (x0 = __xfrm_state_lookup_all(net, mark, daddr,
+ tmpl->id.spi, tmpl->id.proto,
+ encap_family,
+ &pol->xdo)) != NULL) {
to_put = x0;
error = -EEXIST;
goto out;
@@ -1131,17 +1232,42 @@ found:
x = NULL;
goto out;
}
-
+#ifdef CONFIG_XFRM_OFFLOAD
+ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET) {
+ struct xfrm_state_offload *xdo = &pol->xdo;
+ struct xfrm_state_offload *xso = &x->xso;
+
+ xso->type = XFRM_DEV_OFFLOAD_PACKET;
+ xso->dir = xdo->dir;
+ xso->dev = xdo->dev;
+ error = xso->dev->xfrmdev_ops->xdo_dev_state_add(x);
+ if (error) {
+ xso->dir = 0;
+ xso->dev = NULL;
+ xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
+ x->km.state = XFRM_STATE_DEAD;
+ to_put = x;
+ x = NULL;
+ goto out;
+ }
+ }
+#endif
if (km_query(x, tmpl, pol) == 0) {
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x->km.state = XFRM_STATE_ACQ;
list_add(&x->km.all, &net->xfrm.state_all);
- hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
+ XFRM_STATE_INSERT(bydst, &x->bydst,
+ net->xfrm.state_bydst + h,
+ x->xso.type);
h = xfrm_src_hash(net, daddr, saddr, encap_family);
- hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
+ XFRM_STATE_INSERT(bysrc, &x->bysrc,
+ net->xfrm.state_bysrc + h,
+ x->xso.type);
if (x->id.spi) {
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family);
- hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
+ XFRM_STATE_INSERT(byspi, &x->byspi,
+ net->xfrm.state_byspi + h,
+ x->xso.type);
}
x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires;
hrtimer_start(&x->mtimer,
@@ -1151,6 +1277,16 @@ found:
xfrm_hash_grow_check(net, x->bydst.next != NULL);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
} else {
+#ifdef CONFIG_XFRM_OFFLOAD
+ struct xfrm_state_offload *xso = &x->xso;
+
+ if (xso->type == XFRM_DEV_OFFLOAD_PACKET) {
+ xso->dev->xfrmdev_ops->xdo_dev_state_delete(x);
+ xso->dir = 0;
+ xso->dev = NULL;
+ xso->type = XFRM_DEV_OFFLOAD_UNSPECIFIED;
+ }
+#endif
x->km.state = XFRM_STATE_DEAD;
to_put = x;
x = NULL;
@@ -1246,16 +1382,19 @@ static void __xfrm_state_insert(struct x
h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr,
x->props.reqid, x->props.family);
- hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
+ XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h,
+ x->xso.type);
h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family);
- hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
+ XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h,
+ x->xso.type);
if (x->id.spi) {
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto,
x->props.family);
- hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
+ XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h,
+ x->xso.type);
}
hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL_SOFT);
@@ -1369,9 +1508,11 @@ static struct xfrm_state *__find_acq_cor
ktime_set(net->xfrm.sysctl_acq_expires, 0),
HRTIMER_MODE_REL_SOFT);
list_add(&x->km.all, &net->xfrm.state_all);
- hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h);
+ XFRM_STATE_INSERT(bydst, &x->bydst, net->xfrm.state_bydst + h,
+ x->xso.type);
h = xfrm_src_hash(net, daddr, saddr, family);
- hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h);
+ XFRM_STATE_INSERT(bysrc, &x->bysrc, net->xfrm.state_bysrc + h,
+ x->xso.type);
net->xfrm.state_num++;
@@ -1742,6 +1883,8 @@ EXPORT_SYMBOL(xfrm_state_update);
int xfrm_state_check_expire(struct xfrm_state *x)
{
+ xfrm_dev_state_update_curlft(x);
+
if (!x->curlft.use_time)
x->curlft.use_time = ktime_get_real_seconds();
@@ -2043,7 +2186,8 @@ int xfrm_alloc_spi(struct xfrm_state *x,
spin_lock_bh(&net->xfrm.xfrm_state_lock);
x->id.spi = newspi;
h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family);
- hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h);
+ XFRM_STATE_INSERT(byspi, &x->byspi, net->xfrm.state_byspi + h,
+ x->xso.type);
spin_unlock_bh(&net->xfrm.xfrm_state_lock);
err = 0;
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -844,6 +844,8 @@ static int copy_user_offload(struct xfrm
memset(xuo, 0, sizeof(*xuo));
xuo->ifindex = xso->dev->ifindex;
xuo->flags = xso->flags;
+ if (xso->type == XFRM_DEV_OFFLOAD_PACKET)
+ xuo->flags |= XFRM_OFFLOAD_PACKET;
return 0;
}
@@ -1634,6 +1636,15 @@ static struct xfrm_policy *xfrm_policy_c
if (attrs[XFRMA_IF_ID])
xp->if_id = nla_get_u32(attrs[XFRMA_IF_ID]);
+ /* configure the hardware if offload is requested */
+ if (attrs[XFRMA_OFFLOAD_DEV]) {
+ err = xfrm_dev_policy_add(net, xp,
+ nla_data(attrs[XFRMA_OFFLOAD_DEV]),
+ p->dir, 0);
+ if (err)
+ goto error;
+ }
+
return xp;
error:
*errp = err;
@@ -1672,6 +1683,7 @@ static int xfrm_add_policy(struct sk_buf
xfrm_audit_policy_add(xp, err ? 0 : 1, true);
if (err) {
+ xfrm_dev_policy_delete(xp);
security_xfrm_policy_free(xp->security);
kfree(xp);
return err;
@@ -1783,6 +1795,8 @@ static int dump_one_policy(struct xfrm_p
err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
+ if (!err && xp->xdo.dev)
+ err = copy_user_offload(&xp->xdo, skb);
if (err) {
nlmsg_cancel(skb, nlh);
return err;
@@ -2958,6 +2972,8 @@ static int build_acquire(struct sk_buff
err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
+ if (!err && xp->xdo.dev)
+ err = copy_user_offload(&xp->xdo, skb);
if (err) {
nlmsg_cancel(skb, nlh);
return err;
@@ -3076,6 +3092,8 @@ static int build_polexpire(struct sk_buf
err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
+ if (!err && xp->xdo.dev)
+ err = copy_user_offload(&xp->xdo, skb);
if (err) {
nlmsg_cancel(skb, nlh);
return err;
@@ -3159,6 +3177,8 @@ static int xfrm_notify_policy(struct xfr
err = xfrm_mark_put(skb, &xp->mark);
if (!err)
err = xfrm_if_id_put(skb, xp->if_id);
+ if (!err && xp->xdo.dev)
+ err = copy_user_offload(&xp->xdo, skb);
if (err)
goto out_free_skb;

View File

@@ -0,0 +1,37 @@
diff --git a/include/linux/bitfield.h b/include/linux/bitfield.h
index 4f1c0f8..381f28e 100644
--- a/include/linux/bitfield.h
+++ b/include/linux/bitfield.h
@@ -99,6 +99,32 @@
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
})
+#define __BF_CHECK_POW2(n) BUILD_BUG_ON_ZERO(((n) & ((n) - 1)) != 0)
+
+/**
+ * FIELD_PREP_CONST() - prepare a constant bitfield element
+ * @_mask: shifted mask defining the field's length and position
+ * @_val: value to put in the field
+ *
+ * FIELD_PREP_CONST() masks and shifts up the value. The result should
+ * be combined with other fields of the bitfield using logical OR.
+ *
+ * Unlike FIELD_PREP() this is a constant expression and can therefore
+ * be used in initializers. Error checking is less comfortable for this
+ * version, and non-constant masks cannot be used.
+ */
+#define FIELD_PREP_CONST(_mask, _val) \
+ ( \
+ /* mask must be non-zero */ \
+ BUILD_BUG_ON_ZERO((_mask) == 0) + \
+ /* check if value fits */ \
+ BUILD_BUG_ON_ZERO(~((_mask) >> __bf_shf(_mask)) & (_val)) + \
+ /* check if mask is contiguous */ \
+ __BF_CHECK_POW2((_mask) + (1ULL << __bf_shf(_mask))) + \
+ /* and create the value */ \
+ (((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask)) \
+ )
+
/**
* FIELD_GET() - extract a bitfield element
* @_mask: shifted mask defining the field's length and position

View File

@@ -0,0 +1,23 @@
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 1fdb251..24a0b27 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -197,6 +197,18 @@
*/
#define lower_32_bits(n) ((u32)(n))
+/**
+ * upper_16_bits - return bits 16-31 of a number
+ * @n: the number we're accessing
+ */
+#define upper_16_bits(n) ((u16)((n) >> 16))
+
+/**
+ * lower_16_bits - return bits 0-15 of a number
+ * @n: the number we're accessing
+ */
+#define lower_16_bits(n) ((u16)((n) & 0xffff))
+
struct completion;
struct pt_regs;
struct user;

View File

@@ -442,7 +442,7 @@ Index: linux-5.4.260/drivers/mtd/nand/spi/macronix.c
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -116,51 +118,194 @@ static const struct spinand_info macroni
@@ -116,23 +118,76 @@ static const struct spinand_info macroni
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
@@ -455,16 +455,18 @@ Index: linux-5.4.260/drivers/mtd/nand/spi/macronix.c
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
- SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
- SPINAND_INFO("MX35LF4GE4AD", 0x37,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35LF4GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x37),
+ NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
+ SPINAND_INFO("MX35LF1G24AD",
@@ -476,30 +478,16 @@ Index: linux-5.4.260/drivers/mtd/nand/spi/macronix.c
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
- SPINAND_INFO("MX35LF4GE4AD", 0x37,
- NAND_MEMORG(1, 4096, 128, 64, 2048, 40, 1, 1, 1),
- SPINAND_INFO("MX35LF2G14AC", 0x20,
+ SPINAND_INFO("MX35LF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x24),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
&write_cache_variants,
&update_cache_variants),
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
-};
-
-static int macronix_spinand_detect(struct spinand_device *spinand)
-{
- u8 *id = spinand->id.data;
- int ret;
-
- /*
- * Macronix SPI NAND read ID needs a dummy byte, so the first byte in
- * raw_id is garbage.
- */
- if (id[1] != SPINAND_MFR_MACRONIX)
- return 0;
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout, NULL)),
+ SPINAND_INFO("MX35LF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x35),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
@@ -529,131 +517,133 @@ Index: linux-5.4.260/drivers/mtd/nand/spi/macronix.c
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
- ret = spinand_match_and_init(spinand, macronix_spinand_table,
- ARRAY_SIZE(macronix_spinand_table),
- id[2]);
- if (ret)
- return ret;
+
+ SPINAND_INFO("MX35LF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x20),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -141,7 +196,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF4G24AD", 0xb5,
+ SPINAND_INFO("MX35UF4G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb5),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -150,7 +206,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF4GE4AD", 0xb7,
+ SPINAND_INFO("MX35UF4GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xb7),
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 4096, 256, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -159,7 +216,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF2G14AC", 0xa0,
+ SPINAND_INFO("MX35UF2G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa0),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -168,7 +226,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF2G24AD", 0xa4,
+ SPINAND_INFO("MX35UF2G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa4),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 2, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -177,7 +236,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF2GE4AD", 0xa6,
+ SPINAND_INFO("MX35UF2GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa6),
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 128, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -186,7 +246,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF2GE4AC", 0xa2,
+ SPINAND_INFO("MX35UF2GE4AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xa2),
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -195,7 +256,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF1G14AC", 0x90,
+ SPINAND_INFO("MX35UF1G14AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x90),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -204,7 +266,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF1G24AD", 0x94,
+ SPINAND_INFO("MX35UF1G24AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x94),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -213,7 +276,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF1GE4AD", 0x96,
+ SPINAND_INFO("MX35UF1GE4AD",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x96),
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(8, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(8, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -222,7 +286,8 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
- SPINAND_INFO("MX35UF1GE4AC", 0x92,
+ SPINAND_INFO("MX35UF1GE4AC",
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0x92),
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
+ NAND_ECCREQ(4, 512),
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
+ &write_cache_variants,
+ &update_cache_variants),
+ SPINAND_HAS_QE_BIT,
+ SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
+ mx35lf1ge4ab_ecc_get_status)),
NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
NAND_ECCREQ(4, 512),
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
@@ -231,6 +296,7 @@ static const struct spinand_info macroni
SPINAND_HAS_QE_BIT,
SPINAND_ECCINFO(&mx35lfxge4ab_ooblayout,
mx35lf1ge4ab_ecc_get_status)),
+
};
- return 1;
-}
+};
static int macronix_spinand_detect(struct spinand_device *spinand)
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -255,7 +255,6 @@ static int macronix_spinand_detect(struc
}
static const struct spinand_manufacturer_ops macronix_spinand_manuf_ops = {
- .detect = macronix_spinand_detect,
};
const struct spinand_manufacturer macronix_spinand_manufacturer = {
--- a/drivers/mtd/nand/spi/macronix.c
+++ b/drivers/mtd/nand/spi/macronix.c
@@ -326,5 +326,7 @@ static const struct spinand_manufacturer
const struct spinand_manufacturer macronix_spinand_manufacturer = {
.id = SPINAND_MFR_MACRONIX,
.name = "Macronix",
@@ -661,6 +651,7 @@ Index: linux-5.4.260/drivers/mtd/nand/spi/macronix.c
+ .nchips = ARRAY_SIZE(macronix_spinand_table),
.ops = &macronix_spinand_manuf_ops,
};
Index: linux-5.4.260/drivers/mtd/nand/spi/micron.c
===================================================================
--- linux-5.4.260.orig/drivers/mtd/nand/spi/micron.c

View File

@@ -1,22 +1,21 @@
From 1631a36b9ac022ce6ffb58b039a7e85ad3414ed5 Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Fri, 2 Jun 2023 13:06:01 +0800
Subject: [PATCH]
[backport-networking-drivers][999-1709-net-phy-sfp-add-rollball-support.patch]
From 785d2cda90b7d5d3935fd1ce06f479181ba1d9a4 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 19 Nov 2024 13:23:07 +0800
Subject: [PATCH] net: phy: sfp: add rollball support
---
drivers/net/phy/marvell.c | 2 +-
drivers/net/phy/marvell10g.c | 168 +++++++++++++--
drivers/net/phy/mdio-i2c.c | 309 +++++++++++++++++++++++++++-
drivers/net/phy/phylink.c | 74 +++++--
drivers/net/phy/sfp-bus.c | 102 +---------
drivers/net/phy/sfp.c | 373 +++++++++++++++++++++++++++++-----
drivers/net/phy/marvell10g.c | 168 ++++++++++++-
drivers/net/phy/mdio-i2c.c | 309 +++++++++++++++++++++++-
drivers/net/phy/phylink.c | 76 ++++--
drivers/net/phy/sfp-bus.c | 105 +-------
drivers/net/phy/sfp.c | 442 ++++++++++++++++++++++++++++++----
drivers/net/phy/sfp.h | 11 +-
include/linux/mdio/mdio-i2c.h | 10 +-
8 files changed, 874 insertions(+), 175 deletions(-)
8 files changed, 943 insertions(+), 180 deletions(-)
diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c
index 49801c2eb..f25881745 100644
index 49801c2..f258817 100644
--- a/drivers/net/phy/marvell.c
+++ b/drivers/net/phy/marvell.c
@@ -2175,7 +2175,7 @@ static struct phy_driver marvell_drivers[] = {
@@ -29,7 +28,7 @@ index 49801c2eb..f25881745 100644
.config_init = &m88e1111_config_init,
.config_aneg = &marvell_config_aneg,
diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 1e4631761..7d080d52e 100644
index 1e46317..7d080d5 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -32,6 +32,15 @@
@@ -302,7 +301,7 @@ index 1e4631761..7d080d52e 100644
};
diff --git a/drivers/net/phy/mdio-i2c.c b/drivers/net/phy/mdio-i2c.c
index 09200a70b..85db63c33 100644
index 09200a7..85db63c 100644
--- a/drivers/net/phy/mdio-i2c.c
+++ b/drivers/net/phy/mdio-i2c.c
@@ -12,6 +12,7 @@
@@ -654,7 +653,7 @@ index 09200a70b..85db63c33 100644
}
EXPORT_SYMBOL_GPL(mdio_i2c_alloc);
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index f360d9225..67f34ed4c 100644
index f360d92..7412a7b 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -483,62 +483,105 @@ static void phylink_resolve(struct work_struct *w)
@@ -777,6 +776,15 @@ index f360d9225..67f34ed4c 100644
pl->mac_link_dropped = false;
queue_work(system_power_efficient_wq, &pl->resolve);
}
@@ -785,7 +828,7 @@ static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
{
if (WARN_ON(pl->cfg_link_an_mode == MLO_AN_FIXED ||
(pl->cfg_link_an_mode == MLO_AN_INBAND &&
- phy_interface_mode_is_8023z(interface))))
+ phy_interface_mode_is_8023z(interface) && !pl->sfp_bus)))
return -EINVAL;
if (pl->phydev)
@@ -1014,7 +1057,8 @@ void phylink_start(struct phylink *pl)
if (irq <= 0)
mod_timer(&pl->link_poll, jiffies + HZ);
@@ -788,7 +796,7 @@ index f360d9225..67f34ed4c 100644
if (pl->phydev)
phy_start(pl->phydev);
diff --git a/drivers/net/phy/sfp-bus.c b/drivers/net/phy/sfp-bus.c
index a2f451c31..4be24406b 100644
index a2f451c..7d16e72 100644
--- a/drivers/net/phy/sfp-bus.c
+++ b/drivers/net/phy/sfp-bus.c
@@ -10,12 +10,6 @@
@@ -919,7 +927,17 @@ index a2f451c31..4be24406b 100644
}
EXPORT_SYMBOL_GPL(sfp_parse_support);
@@ -737,12 +650,13 @@ void sfp_link_down(struct sfp_bus *bus)
@@ -392,7 +305,8 @@ phy_interface_t sfp_select_interface(struct sfp_bus *bus,
if (phylink_test(link_modes, 5000baseT_Full))
return PHY_INTERFACE_MODE_5GBASER;
- if (phylink_test(link_modes, 2500baseX_Full))
+ if (phylink_test(link_modes, 2500baseX_Full) ||
+ phylink_test(link_modes, 2500baseT_Full))
return PHY_INTERFACE_MODE_2500BASEX;
if (phylink_test(link_modes, 1000baseT_Half) ||
@@ -737,12 +651,13 @@ void sfp_link_down(struct sfp_bus *bus)
}
EXPORT_SYMBOL_GPL(sfp_link_down);
@@ -936,18 +954,19 @@ index a2f451c31..4be24406b 100644
if (ops && ops->module_insert)
ret = ops->module_insert(bus->upstream, id);
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index f8d1742e0..0fdf5d6d4 100644
index a8eeb57..3ecc6aa 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -165,6 +165,7 @@ static const enum gpiod_flags gpio_flags[] = {
* on board (for a copper SFP) time to initialise.
@@ -186,7 +186,7 @@ static const enum gpiod_flags gpio_flags[] = {
* R_PHY_RETRY is the number of attempts.
*/
#define T_WAIT msecs_to_jiffies(50)
+#define T_WAIT_ROLLBALL msecs_to_jiffies(25000)
#define T_START_UP msecs_to_jiffies(300)
#define T_START_UP_BAD_GPON msecs_to_jiffies(60000)
#define T_PHY_RETRY msecs_to_jiffies(50)
-#define R_PHY_RETRY 12
+#define R_PHY_RETRY 25
@@ -204,8 +205,11 @@ static const enum gpiod_flags gpio_flags[] = {
/* SFP module presence detection is poor: the three MOD DEF signals are
* the same length on the PCB, which means it's possible for MOD DEF 0 to
@@ -204,8 +204,11 @@ static const enum gpiod_flags gpio_flags[] = {
/* SFP modules appear to always have their PHY configured for bus address
* 0x56 (which with mdio-i2c, translates to a PHY address of 22).
@@ -960,7 +979,7 @@ index f8d1742e0..0fdf5d6d4 100644
struct sff_data {
unsigned int gpios;
@@ -217,6 +221,7 @@ struct sfp {
@@ -217,6 +220,7 @@ struct sfp {
struct i2c_adapter *i2c;
struct mii_bus *i2c_mii;
struct sfp_bus *sfp_bus;
@@ -968,20 +987,22 @@ index f8d1742e0..0fdf5d6d4 100644
struct phy_device *mod_phy;
const struct sff_data *type;
size_t i2c_block_size;
@@ -233,6 +238,7 @@ struct sfp {
@@ -233,7 +237,9 @@ struct sfp {
bool need_poll;
struct mutex st_mutex; /* Protects state */
+ unsigned int state_hw_mask;
unsigned int state_soft_mask;
+ unsigned int state_ignore_mask;
unsigned int state;
struct delayed_work poll;
struct delayed_work timeout;
@@ -249,6 +255,10 @@ struct sfp {
struct sfp_eeprom_id id;
unsigned int module_power_mW;
unsigned int module_t_start_up;
+ unsigned int module_t_wait;
+ bool tx_fault_ignore;
+ unsigned int phy_t_retry;
+
+ const struct sfp_quirk *quirk;
@@ -1006,7 +1027,7 @@ index f8d1742e0..0fdf5d6d4 100644
return false;
}
@@ -303,6 +325,180 @@ static const struct of_device_id sfp_of_match[] = {
@@ -303,6 +325,235 @@ static const struct of_device_id sfp_of_match[] = {
};
MODULE_DEVICE_TABLE(of, sfp_of_match);
@@ -1015,9 +1036,18 @@ index f8d1742e0..0fdf5d6d4 100644
+ sfp->module_t_start_up = T_START_UP_BAD_GPON;
+}
+
+static void sfp_fixup_ignore_los(struct sfp *sfp)
+{
+ /* This forces LOS to zero, so we ignore transitions */
+ sfp->state_ignore_mask |= SFP_F_LOS;
+ /* Make sure that LOS options are clear */
+ sfp->id.ext.options &= ~cpu_to_be16(SFP_OPTIONS_LOS_INVERTED |
+ SFP_OPTIONS_LOS_NORMAL);
+}
+
+static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
+{
+ sfp->tx_fault_ignore = true;
+ sfp->state_ignore_mask |= SFP_F_TX_FAULT;
+}
+
+static void sfp_fixup_ruijie_gbic(struct sfp *sfp)
@@ -1025,6 +1055,43 @@ index f8d1742e0..0fdf5d6d4 100644
+ sfp->mdio_protocol = MDIO_I2C_NONE;
+}
+
+// For 10GBASE-T short-reach modules
+static void sfp_fixup_10gbaset_30m(struct sfp *sfp)
+{
+ sfp->id.base.connector = SFF8024_CONNECTOR_RJ45;
+ sfp->id.base.extended_cc = SFF8024_ECC_10GBASE_T_SR;
+}
+
+static void sfp_fixup_rollball(struct sfp *sfp)
+{
+ sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
+
+ /* RollBall modules may disallow access to PHY registers for up to 25
+ * seconds, and the reads return 0xffff before that. Increase the time
+ * between PHY probe retries from 50ms to 1s so that we will wait for
+ * the PHY for a sufficient amount of time.
+ */
+ sfp->phy_t_retry = msecs_to_jiffies(1000);
+}
+
+static void sfp_fixup_fs_2_5gt(struct sfp *sfp)
+{
+ sfp_fixup_rollball(sfp);
+ sfp_fixup_ignore_los(sfp);
+
+ /* The RollBall fixup is not enough for FS modules, the PHY chip inside
+ * them does not return 0xffff for PHY ID registers in all MMDs for the
+ * while initializing. They need a 4 second wait before accessing PHY.
+ */
+ sfp->module_t_wait = msecs_to_jiffies(4000);
+}
+
+static void sfp_fixup_fs_10gt(struct sfp *sfp)
+{
+ sfp_fixup_10gbaset_30m(sfp);
+ sfp_fixup_fs_2_5gt(sfp);
+}
+
+static void sfp_fixup_halny_gsfp(struct sfp *sfp)
+{
+ /* Ignore the TX_FAULT and LOS signals on this module.
@@ -1034,12 +1101,6 @@ index f8d1742e0..0fdf5d6d4 100644
+ sfp->state_hw_mask &= ~(SFP_F_TX_FAULT | SFP_F_LOS);
+}
+
+static void sfp_fixup_rollball(struct sfp *sfp)
+{
+ sfp->mdio_protocol = MDIO_I2C_ROLLBALL;
+ sfp->module_t_wait = T_WAIT_ROLLBALL;
+}
+
+static void sfp_fixup_rollball_cc(struct sfp *sfp)
+{
+ sfp_fixup_rollball(sfp);
@@ -1107,6 +1168,21 @@ index f8d1742e0..0fdf5d6d4 100644
+ SFP_QUIRK("ALCATELLUCENT", "3FE46541AA", '\0', sfp_quirk_2500basex,
+ sfp_fixup_long_startup),
+
+ // Fiberstore SFP-10G-T doesn't identify as copper, uses the Rollball
+ // protocol to talk to the PHY and needs 4 sec wait before probing the
+ // PHY.
+ SFP_QUIRK_F("FS", "SFP-10G-T", '\0', sfp_fixup_fs_10gt),
+
+ // Fiberstore SFP-2.5G-T uses Rollball protocol to talk to the PHY and
+ // needs 4 sec wait before probing the PHY.
+ SFP_QUIRK_F("FS", "SFP-2.5G-T", '\0', sfp_fixup_fs_2_5gt),
+ SFP_QUIRK_F("FS", "SFP-2.5G-T-I", '\0', sfp_fixup_fs_2_5gt),
+
+ // Fiberstore GPON-ONU-34-20BI can operate at 2500base-X, but report 1.2GBd
+ // NRZ in their EEPROM
+ SFP_QUIRK("FS", "GPON-ONU-34-20BI", '\0', sfp_quirk_2500basex,
+ sfp_fixup_ignore_tx_fault),
+
+ SFP_QUIRK_F("HALNy", "HL-GSFP", '\0', sfp_fixup_halny_gsfp),
+
+ // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd NRZ in
@@ -1187,7 +1263,7 @@ index f8d1742e0..0fdf5d6d4 100644
static unsigned long poll_jiffies;
static unsigned int sfp_gpio_get_state(struct sfp *sfp)
@@ -414,9 +610,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
@@ -414,9 +664,6 @@ static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
{
@@ -1197,7 +1273,7 @@ index f8d1742e0..0fdf5d6d4 100644
if (!i2c_check_functionality(i2c, I2C_FUNC_I2C))
return -EINVAL;
@@ -424,7 +617,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
@@ -424,7 +671,15 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
sfp->read = sfp_i2c_read;
sfp->write = sfp_i2c_write;
@@ -1214,7 +1290,7 @@ index f8d1742e0..0fdf5d6d4 100644
if (IS_ERR(i2c_mii))
return PTR_ERR(i2c_mii);
@@ -442,6 +643,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
@@ -442,6 +697,12 @@ static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
return 0;
}
@@ -1227,7 +1303,7 @@ index f8d1742e0..0fdf5d6d4 100644
/* Interface */
static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
{
@@ -487,17 +694,18 @@ static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
@@ -487,17 +748,19 @@ static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
static void sfp_soft_start_poll(struct sfp *sfp)
{
const struct sfp_eeprom_id *id = &sfp->id;
@@ -1251,11 +1327,12 @@ index f8d1742e0..0fdf5d6d4 100644
+ mask |= SFP_F_LOS;
+
+ // Poll the soft state for hardware pins we want to ignore
+ sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
+ sfp->state_soft_mask = ~sfp->state_hw_mask & ~sfp->state_ignore_mask &
+ mask;
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
!sfp->need_poll)
@@ -511,10 +719,11 @@ static void sfp_soft_stop_poll(struct sfp *sfp)
@@ -511,10 +774,11 @@ static void sfp_soft_stop_poll(struct sfp *sfp)
static unsigned int sfp_get_state(struct sfp *sfp)
{
@@ -1270,7 +1347,7 @@ index f8d1742e0..0fdf5d6d4 100644
state |= sfp_soft_get_state(sfp);
return state;
@@ -1448,12 +1657,12 @@ static void sfp_sm_phy_detach(struct sfp *sfp)
@@ -1448,12 +1712,12 @@ static void sfp_sm_phy_detach(struct sfp *sfp)
sfp->mod_phy = NULL;
}
@@ -1285,7 +1362,7 @@ index f8d1742e0..0fdf5d6d4 100644
if (phy == ERR_PTR(-ENODEV))
return PTR_ERR(phy);
if (IS_ERR(phy)) {
@@ -1548,6 +1757,14 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
@@ -1548,6 +1812,14 @@ static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
}
}
@@ -1300,7 +1377,7 @@ index f8d1742e0..0fdf5d6d4 100644
/* Probe a SFP for a PHY device if the module supports copper - the PHY
* normally sits at I2C bus address 0x56, and may either be a clause 22
* or clause 45 PHY.
@@ -1563,36 +1780,52 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
@@ -1563,36 +1835,52 @@ static int sfp_sm_probe_for_phy(struct sfp *sfp)
{
int err = 0;
@@ -1367,7 +1444,7 @@ index f8d1742e0..0fdf5d6d4 100644
/* The module appears not to implement bus address
* 0xa2, so assume that the module powers up in the
* indicated mode.
@@ -1609,13 +1842,21 @@ static int sfp_module_parse_power(struct sfp *sfp)
@@ -1609,13 +1897,21 @@ static int sfp_module_parse_power(struct sfp *sfp)
}
}
@@ -1391,7 +1468,7 @@ index f8d1742e0..0fdf5d6d4 100644
power_mW / 1000, (power_mW / 100) % 10);
return 0;
}
@@ -1692,7 +1933,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
@@ -1692,7 +1988,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
{
/* SFP module inserted - read I2C data */
struct sfp_eeprom_id id;
@@ -1400,7 +1477,7 @@ index f8d1742e0..0fdf5d6d4 100644
u8 check;
int ret;
@@ -1747,10 +1988,16 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
@@ -1747,10 +2043,16 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
*/
cotsworks = !memcmp(id.base.vendor_name, "COTSWORKS ", 16);
@@ -1418,7 +1495,7 @@ index f8d1742e0..0fdf5d6d4 100644
dev_warn(sfp->dev,
"EEPROM base structure checksum failure (0x%02x != 0x%02x)\n",
check, id.base.cc_base);
@@ -1819,11 +2066,33 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
@@ -1819,11 +2121,36 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
if (ret < 0)
return ret;
@@ -1436,8 +1513,9 @@ index f8d1742e0..0fdf5d6d4 100644
+
+ sfp->module_t_start_up = T_START_UP;
+ sfp->module_t_wait = T_WAIT;
+ sfp->phy_t_retry = T_PHY_RETRY;
+
+ sfp->tx_fault_ignore = false;
+ sfp->state_ignore_mask = 0;
+
+ if (sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SFI ||
+ sfp->id.base.extended_cc == SFF8024_ECC_10GBASE_T_SR ||
@@ -1453,10 +1531,12 @@ index f8d1742e0..0fdf5d6d4 100644
+ sfp->quirk = sfp_lookup_quirk(&id);
+ if (sfp->quirk && sfp->quirk->fixup)
+ sfp->quirk->fixup(sfp);
+
+ sfp->state_hw_mask &= ~sfp->state_ignore_mask;
return 0;
}
@@ -1936,7 +2205,8 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
@@ -1936,7 +2263,8 @@ static void sfp_sm_module(struct sfp *sfp, unsigned int event)
break;
/* Report the module insertion to the upstream device */
@@ -1466,7 +1546,7 @@ index f8d1742e0..0fdf5d6d4 100644
if (err < 0) {
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
break;
@@ -1995,6 +2265,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
@@ -1995,6 +2323,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
sfp_module_stop(sfp->sfp_bus);
if (sfp->mod_phy)
sfp_sm_phy_detach(sfp);
@@ -1475,7 +1555,7 @@ index f8d1742e0..0fdf5d6d4 100644
sfp_module_tx_disable(sfp);
sfp_soft_stop_poll(sfp);
sfp_sm_next(sfp, SFP_S_DOWN, 0);
@@ -2018,9 +2290,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
@@ -2018,9 +2348,10 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
/* We need to check the TX_FAULT state, which is not defined
* while TX_DISABLE is asserted. The earliest we want to do
@@ -1488,7 +1568,7 @@ index f8d1742e0..0fdf5d6d4 100644
break;
case SFP_S_WAIT:
@@ -2034,8 +2307,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
@@ -2034,8 +2365,8 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
* deasserting.
*/
timeout = sfp->module_t_start_up;
@@ -1499,7 +1579,7 @@ index f8d1742e0..0fdf5d6d4 100644
else
timeout = 1;
@@ -2057,6 +2330,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
@@ -2057,6 +2388,12 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
sfp->sm_fault_retries == N_FAULT_INIT);
} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
init_done:
@@ -1512,7 +1592,23 @@ index f8d1742e0..0fdf5d6d4 100644
sfp->sm_phy_retries = R_PHY_RETRY;
goto phy_probe;
}
@@ -2409,6 +2688,8 @@ static int sfp_probe(struct platform_device *pdev)
@@ -2070,9 +2407,13 @@ static void sfp_sm_main(struct sfp *sfp, unsigned int event)
* clear. Probe for the PHY and check the LOS state.
*/
ret = sfp_sm_probe_for_phy(sfp);
- if (ret == -ENODEV) {
+ if (ret == -ENODEV || ret == -EINVAL) {
if (--sfp->sm_phy_retries) {
- sfp_sm_next(sfp, SFP_S_INIT_PHY, T_PHY_RETRY);
+ sfp_sm_next(sfp, SFP_S_INIT_PHY,
+ sfp->phy_t_retry);
+ dev_info(sfp->dev,
+ "no PHY detected, %u tries left\n",
+ sfp->sm_phy_retries);
break;
} else {
dev_info(sfp->dev, "no PHY detected\n");
@@ -2409,6 +2750,8 @@ static int sfp_probe(struct platform_device *pdev)
return PTR_ERR(sfp->gpio[i]);
}
@@ -1522,7 +1618,7 @@ index f8d1742e0..0fdf5d6d4 100644
sfp->set_state = sfp_gpio_set_state;
diff --git a/drivers/net/phy/sfp.h b/drivers/net/phy/sfp.h
index b83f70526..f533e2dd6 100644
index b83f705..f533e2d 100644
--- a/drivers/net/phy/sfp.h
+++ b/drivers/net/phy/sfp.h
@@ -6,6 +6,14 @@
@@ -1551,7 +1647,7 @@ index b83f70526..f533e2dd6 100644
int sfp_module_start(struct sfp_bus *bus);
void sfp_module_stop(struct sfp_bus *bus);
diff --git a/include/linux/mdio/mdio-i2c.h b/include/linux/mdio/mdio-i2c.h
index 751dab281..1c2114068 100644
index 751dab2..1c21140 100644
--- a/include/linux/mdio/mdio-i2c.h
+++ b/include/linux/mdio/mdio-i2c.h
@@ -11,6 +11,14 @@ struct device;
@@ -1571,5 +1667,5 @@ index 751dab281..1c2114068 100644
#endif
--
2.34.1
2.45.2

View File

@@ -0,0 +1,109 @@
From d3fd7b4ccaf867811a777cf7aecaaa9f32d94331 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 13 May 2024 17:05:16 +0800
Subject: [PATCH] 999-1716-v6.6-net-phy-add-phylink-pcs_enable-and-pcs_disable
---
drivers/net/phy/phylink.c | 26 +++++++++++++++++++++++++-
include/linux/phylink.h | 2 ++
2 files changed, 27 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 9b9bb17..1d79f59 100644
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -32,6 +32,10 @@
enum {
PHYLINK_DISABLE_STOPPED,
PHYLINK_DISABLE_LINK,
+
+ PCS_STATE_DOWN = 0,
+ PCS_STATE_STARTING,
+ PCS_STATE_STARTED,
};
/**
@@ -69,6 +73,7 @@ struct phylink {
struct mutex state_mutex;
struct phylink_link_state phy_state;
struct work_struct resolve;
+ unsigned int pcs_state;
bool mac_link_dropped;
bool using_mac_select_pcs;
@@ -520,11 +525,20 @@ static void phylink_major_config(struct phylink *pl, bool restart,
/* If we have a new PCS, switch to the new PCS after preparing the MAC
* for the change.
*/
- if (pcs_changed)
+ if (pcs_changed) {
+ if (pl->pcs && pl->pcs->ops->pcs_disable)
+ pl->pcs->ops->pcs_disable(pl->pcs);
+
pl->pcs = pcs;
+ }
phylink_mac_config(pl, state);
+ if (pl->pcs_state == PCS_STATE_STARTING || pcs_changed) {
+ if (pl->pcs && pl->pcs->ops->pcs_enable)
+ err = pl->pcs->ops->pcs_enable(pl->pcs);
+ }
+
if (pl->pcs) {
err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
state->interface,
@@ -1022,6 +1036,7 @@ struct phylink *phylink_create(struct phylink_config *config,
pl->link_config.speed = SPEED_UNKNOWN;
pl->link_config.duplex = DUPLEX_UNKNOWN;
pl->link_config.an_enabled = true;
+ pl->pcs_state = PCS_STATE_DOWN;
pl->mac_ops = mac_ops;
__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
@@ -1370,6 +1385,8 @@ void phylink_start(struct phylink *pl)
if (pl->netdev)
netif_carrier_off(pl->netdev);
+ pl->pcs_state = PCS_STATE_STARTING;
+
/* Apply the link configuration to the MAC when starting. This allows
* a fixed-link to start with the correct parameters, and also
* ensures that we set the appropriate advertisement for Serdes links.
@@ -1381,6 +1398,8 @@ void phylink_start(struct phylink *pl)
phylink_resolve_flow(pl, &pl->link_config);
phylink_mac_initial_config(pl, true);
+ pl->pcs_state = PCS_STATE_STARTED;
+
clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
phylink_run_resolve(pl);
@@ -1442,6 +1461,11 @@ void phylink_stop(struct phylink *pl)
}
phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
+
+ pl->pcs_state = PCS_STATE_DOWN;
+
+ if (pl->pcs && pl->pcs->ops->pcs_disable)
+ pl->pcs->ops->pcs_disable(pl->pcs);
}
EXPORT_SYMBOL_GPL(phylink_stop);
diff --git a/include/linux/phylink.h b/include/linux/phylink.h
index e1c022f..fae9794 100644
--- a/include/linux/phylink.h
+++ b/include/linux/phylink.h
@@ -349,6 +349,8 @@ struct phylink_pcs {
struct phylink_pcs_ops {
int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
const struct phylink_link_state *state);
+ int (*pcs_enable)(struct phylink_pcs *pcs);
+ void (*pcs_disable)(struct phylink_pcs *pcs);
void (*pcs_get_state)(struct phylink_pcs *pcs,
struct phylink_link_state *state);
int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode,
--
2.18.0

View File

@@ -0,0 +1,107 @@
From 83e56d18e57fc46c3a25f917dbd42fb9b1599ab1 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 1 Jul 2024 16:05:32 +0800
Subject: [PATCH]
[backport-networking-drivers][999-1717-v5.12-net-phy-sfp-add-debugfs-support.patch]
---
drivers/net/phy/sfp.c | 55 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index d49a825..4bcc2bb 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <linux/acpi.h>
#include <linux/ctype.h>
+#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/hwmon.h>
@@ -268,6 +269,9 @@ struct sfp {
char *hwmon_name;
#endif
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+ struct dentry *debugfs_dir;
+#endif
};
static bool sff_module_supported(const struct sfp_eeprom_id *id)
@@ -1617,6 +1621,54 @@ static void sfp_module_tx_enable(struct sfp *sfp)
sfp_set_state(sfp, sfp->state);
}
+#if IS_ENABLED(CONFIG_DEBUG_FS)
+static int sfp_debug_state_show(struct seq_file *s, void *data)
+{
+ struct sfp *sfp = s->private;
+
+ seq_printf(s, "Module state: %s\n",
+ mod_state_to_str(sfp->sm_mod_state));
+ seq_printf(s, "Module probe attempts: %d %d\n",
+ R_PROBE_RETRY_INIT - sfp->sm_mod_tries_init,
+ R_PROBE_RETRY_SLOW - sfp->sm_mod_tries);
+ seq_printf(s, "Device state: %s\n",
+ dev_state_to_str(sfp->sm_dev_state));
+ seq_printf(s, "Main state: %s\n",
+ sm_state_to_str(sfp->sm_state));
+ seq_printf(s, "Fault recovery remaining retries: %d\n",
+ sfp->sm_fault_retries);
+ seq_printf(s, "PHY probe remaining retries: %d\n",
+ sfp->sm_phy_retries);
+ seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT));
+ seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS));
+ seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT));
+ seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE));
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(sfp_debug_state);
+
+static void sfp_debugfs_init(struct sfp *sfp)
+{
+ sfp->debugfs_dir = debugfs_create_dir(dev_name(sfp->dev), NULL);
+
+ debugfs_create_file("state", 0600, sfp->debugfs_dir, sfp,
+ &sfp_debug_state_fops);
+}
+
+static void sfp_debugfs_exit(struct sfp *sfp)
+{
+ debugfs_remove_recursive(sfp->debugfs_dir);
+}
+#else
+static void sfp_debugfs_init(struct sfp *sfp)
+{
+}
+
+static void sfp_debugfs_exit(struct sfp *sfp)
+{
+}
+#endif
+
static void sfp_module_tx_fault_reset(struct sfp *sfp)
{
unsigned int state = sfp->state;
@@ -2795,6 +2847,8 @@ static int sfp_probe(struct platform_device *pdev)
if (!sfp->sfp_bus)
return -ENOMEM;
+ sfp_debugfs_init(sfp);
+
return 0;
}
@@ -2802,6 +2856,7 @@ static int sfp_remove(struct platform_device *pdev)
{
struct sfp *sfp = platform_get_drvdata(pdev);
+ sfp_debugfs_exit(sfp);
sfp_unregister_socket(sfp->sfp_bus);
rtnl_lock();
--
2.18.0

View File

@@ -0,0 +1,202 @@
From 85fa9116d39817791f3da4dd642549db8916cb8e Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 30 Jan 2024 12:29:37 +0800
Subject: [PATCH] 999-1715-v6.2-net-ptp-introduce-adjust-by-scaled-ppm.patch
---
drivers/ptp/ptp_clock.c | 21 ------
include/linux/math64.h | 12 ++++
include/linux/ptp_clock_kernel.h | 72 +++++++++++++++++++
lib/math/div64.c | 42 +++++++++++
4 files changed, 126 insertions(+), 21 deletions(-)
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index eedf067..5cca99f 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -63,27 +63,6 @@ static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
spin_unlock_irqrestore(&queue->lock, flags);
}
-long scaled_ppm_to_ppb(long ppm)
-{
- /*
- * The 'freq' field in the 'struct timex' is in parts per
- * million, but with a 16 bit binary fractional field.
- *
- * We want to calculate
- *
- * ppb = scaled_ppm * 1000 / 2^16
- *
- * which simplifies to
- *
- * ppb = scaled_ppm * 125 / 2^13
- */
- s64 ppb = 1 + ppm;
- ppb *= 125;
- ppb >>= 13;
- return (long) ppb;
-}
-EXPORT_SYMBOL(scaled_ppm_to_ppb);
-
/* posix clock implementation */
static int ptp_clock_getres(struct posix_clock *pc, struct timespec64 *tp)
diff --git a/include/linux/math64.h b/include/linux/math64.h
index 65bef21..a593096 100644
--- a/include/linux/math64.h
+++ b/include/linux/math64.h
@@ -281,6 +281,18 @@ static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor)
}
#endif /* mul_u64_u32_div */
+u64 mul_u64_u64_div_u64(u64 a, u64 mul, u64 div);
+
+/**
+ * DIV64_U64_ROUND_UP - unsigned 64bit divide with 64bit divisor rounded up
+ * @ll: unsigned 64bit dividend
+ * @d: unsigned 64bit divisor
+ *
+ * Divide unsigned 64bit dividend by unsigned 64bit divisor
+ * and round up.
+ *
+ * Return: dividend / divisor rounded up
+ */
#define DIV64_U64_ROUND_UP(ll, d) \
({ u64 _tmp = (d); div64_u64((ll) + _tmp - 1, _tmp); })
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
index 874f7e7..2ff9afe 100644
--- a/include/linux/ptp_clock_kernel.h
+++ b/include/linux/ptp_clock_kernel.h
@@ -169,6 +169,78 @@ struct ptp_clock_event {
};
};
+/**
+ * scaled_ppm_to_ppb() - convert scaled ppm to ppb
+ *
+ * @ppm: Parts per million, but with a 16 bit binary fractional field
+ */
+static inline long scaled_ppm_to_ppb(long ppm)
+{
+ /*
+ * The 'freq' field in the 'struct timex' is in parts per
+ * million, but with a 16 bit binary fractional field.
+ *
+ * We want to calculate
+ *
+ * ppb = scaled_ppm * 1000 / 2^16
+ *
+ * which simplifies to
+ *
+ * ppb = scaled_ppm * 125 / 2^13
+ */
+ s64 ppb = 1 + ppm;
+
+ ppb *= 125;
+ ppb >>= 13;
+ return (long)ppb;
+}
+
+/**
+ * diff_by_scaled_ppm - Calculate difference using scaled ppm
+ * @base: the base increment value to adjust
+ * @scaled_ppm: scaled parts per million to adjust by
+ * @diff: on return, the absolute value of calculated diff
+ *
+ * Calculate the difference to adjust the base increment using scaled parts
+ * per million.
+ *
+ * Use mul_u64_u64_div_u64 to perform the difference calculation in avoid
+ * possible overflow.
+ *
+ * Returns: true if scaled_ppm is negative, false otherwise
+ */
+static inline bool diff_by_scaled_ppm(u64 base, long scaled_ppm, u64 *diff)
+{
+ bool negative = false;
+
+ if (scaled_ppm < 0) {
+ negative = true;
+ scaled_ppm = -scaled_ppm;
+ }
+
+ *diff = mul_u64_u64_div_u64(base, (u64)scaled_ppm, 1000000ULL << 16);
+
+ return negative;
+}
+
+/**
+ * adjust_by_scaled_ppm - Adjust a base increment by scaled parts per million
+ * @base: the base increment value to adjust
+ * @scaled_ppm: scaled parts per million frequency adjustment
+ *
+ * Helper function which calculates a new increment value based on the
+ * requested scaled parts per million adjustment.
+ */
+static inline u64 adjust_by_scaled_ppm(u64 base, long scaled_ppm)
+{
+ u64 diff;
+
+ if (diff_by_scaled_ppm(base, scaled_ppm, &diff))
+ return base - diff;
+
+ return base + diff;
+}
+
#if IS_REACHABLE(CONFIG_PTP_1588_CLOCK)
/**
diff --git a/lib/math/div64.c b/lib/math/div64.c
index 368ca7f..edd1090 100644
--- a/lib/math/div64.c
+++ b/lib/math/div64.c
@@ -190,3 +190,45 @@ u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
return __iter_div_u64_rem(dividend, divisor, remainder);
}
EXPORT_SYMBOL(iter_div_u64_rem);
+
+#ifndef mul_u64_u64_div_u64
+u64 mul_u64_u64_div_u64(u64 a, u64 b, u64 c)
+{
+ u64 res = 0, div, rem;
+ int shift;
+
+ /* can a * b overflow ? */
+ if (ilog2(a) + ilog2(b) > 62) {
+ /*
+ * (b * a) / c is equal to
+ *
+ * (b / c) * a +
+ * (b % c) * a / c
+ *
+ * if nothing overflows. Can the 1st multiplication
+ * overflow? Yes, but we do not care: this can only
+ * happen if the end result can't fit in u64 anyway.
+ *
+ * So the code below does
+ *
+ * res = (b / c) * a;
+ * b = b % c;
+ */
+ div = div64_u64_rem(b, c, &rem);
+ res = div * a;
+ b = rem;
+
+ shift = ilog2(a) + ilog2(b) - 62;
+ if (shift > 0) {
+ /* drop precision */
+ b >>= shift;
+ c >>= shift;
+ if (!c)
+ return res;
+ }
+ }
+
+ return res + div64_u64(a * b, c);
+}
+EXPORT_SYMBOL(mul_u64_u64_div_u64);
+#endif
--
2.18.0

View File

@@ -0,0 +1,80 @@
From 6afacf5f918314789d95739311978b596ea46384 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 19 Nov 2024 11:53:53 +0800
Subject: [PATCH] net: phy: add genphy_c45_pma_suspend/resume
---
drivers/net/phy/phy-c45.c | 43 +++++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 2 ++
2 files changed, 45 insertions(+)
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index bceb0dc..797946c 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -8,6 +8,49 @@
#include <linux/mii.h>
#include <linux/phy.h>
+/**
+ * genphy_c45_pma_can_sleep - checks if the PMA have sleep support
+ * @phydev: target phy_device struct
+ */
+static bool genphy_c45_pma_can_sleep(struct phy_device *phydev)
+{
+ int stat1;
+
+ stat1 = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT1);
+ if (stat1 < 0)
+ return false;
+
+ return !!(stat1 & MDIO_STAT1_LPOWERABLE);
+}
+
+/**
+ * genphy_c45_pma_resume - wakes up the PMA module
+ * @phydev: target phy_device struct
+ */
+int genphy_c45_pma_resume(struct phy_device *phydev)
+{
+ if (!genphy_c45_pma_can_sleep(phydev))
+ return -EOPNOTSUPP;
+
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+ MDIO_CTRL1_LPOWER);
+}
+EXPORT_SYMBOL_GPL(genphy_c45_pma_resume);
+
+/**
+ * genphy_c45_pma_suspend - suspends the PMA module
+ * @phydev: target phy_device struct
+ */
+int genphy_c45_pma_suspend(struct phy_device *phydev)
+{
+ if (!genphy_c45_pma_can_sleep(phydev))
+ return -EOPNOTSUPP;
+
+ return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_CTRL1,
+ MDIO_CTRL1_LPOWER);
+}
+EXPORT_SYMBOL_GPL(genphy_c45_pma_suspend);
+
/**
* genphy_c45_setup_forced - configures a forced speed
* @phydev: target phy_device struct
diff --git a/include/linux/phy.h b/include/linux/phy.h
index 83bd00b..fb21ddb 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1232,6 +1232,8 @@ int genphy_c45_read_mdix(struct phy_device *phydev);
int genphy_c45_pma_read_abilities(struct phy_device *phydev);
int genphy_c45_read_status(struct phy_device *phydev);
int genphy_c45_config_aneg(struct phy_device *phydev);
+int genphy_c45_pma_resume(struct phy_device *phydev);
+int genphy_c45_pma_suspend(struct phy_device *phydev);
/* The gen10g_* functions are the old Clause 45 stub */
int gen10g_config_aneg(struct phy_device *phydev);
--
2.45.2

View File

@@ -0,0 +1,28 @@
From d1d8518eebcb82ba7b0ee5f34c05a730da125588 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 19 Nov 2024 12:27:04 +0800
Subject: [PATCH] net: phy: add 2.5g and 5g related PMA and PCS speed constants
---
include/uapi/linux/mdio.h | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index 3f302e2..353a146 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -119,7 +119,11 @@
#define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */
#define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */
#define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */
+#define MDIO_PMA_SPEED_2_5G 0x2000 /* 2.5G capable */
+#define MDIO_PMA_SPEED_5G 0x4000 /* 5G capable */
#define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */
+#define MDIO_PCS_SPEED_2_5G 0x0040 /* 2.5G capable */
+#define MDIO_PCS_SPEED_5G 0x0080 /* 5G capable */
/* Device present registers. */
#define MDIO_DEVS_PRESENT(devad) (1 << (devad))
--
2.45.2

View File

@@ -0,0 +1,605 @@
From 9e9eecff8085737bb81f279f9283f5d67e3b5e29 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 19 Nov 2024 12:49:36 +0800
Subject: [PATCH] net: phy: realtek add rtl8221b series
---
drivers/net/phy/realtek.c | 539 ++++++++++++++++++++++++++++++++++++++
1 file changed, 539 insertions(+)
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 879ca37..b228b6d 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -9,6 +9,7 @@
* Copyright (c) 2004 Freescale Semiconductor, Inc.
*/
#include <linux/bitops.h>
+#include <linux/of.h>
#include <linux/phy.h>
#include <linux/module.h>
@@ -36,6 +37,27 @@
#define RTL8201F_ISR 0x1e
#define RTL8201F_IER 0x13
+#define RTL822X_VND1_SERDES_OPTION 0x697a
+#define RTL822X_VND1_SERDES_OPTION_MODE_MASK GENMASK(5, 0)
+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII 0
+#define RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX 2
+
+#define RTL822X_VND1_SERDES_CTRL3 0x7580
+#define RTL822X_VND1_SERDES_CTRL3_MODE_MASK GENMASK(5, 0)
+#define RTL822X_VND1_SERDES_CTRL3_MODE_SGMII 0x02
+#define RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX 0x16
+
+/* RTL822X_VND2_XXXXX registers are only accessible when phydev->is_c45
+ * is set, they cannot be accessed by C45-over-C22.
+ */
+#define RTL822X_VND2_GBCR 0xa412
+
+#define RTL822X_VND2_GANLPAR 0xa414
+
+#define RTL8221B_PHYCR1 0xa430
+#define RTL8221B_PHYCR1_ALDPS_EN BIT(2)
+#define RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN BIT(12)
+
#define RTL8366RB_POWER_SAVE 0x15
#define RTL8366RB_POWER_SAVE_ON BIT(12)
@@ -47,7 +69,16 @@
#define RTL_LPADV_5000FULL BIT(6)
#define RTL_LPADV_2500FULL BIT(5)
+#define RTL_VND2_PHYSR 0xa434
+#define RTL_VND2_PHYSR_DUPLEX BIT(3)
+#define RTL_VND2_PHYSR_SPEEDL GENMASK(5, 4)
+#define RTL_VND2_PHYSR_SPEEDH GENMASK(10, 9)
+#define RTL_VND2_PHYSR_MASTER BIT(11)
+#define RTL_VND2_PHYSR_SPEED_MASK (RTL_VND2_PHYSR_SPEEDL | RTL_VND2_PHYSR_SPEEDH)
+
#define RTL_GENERIC_PHYID 0x001cc800
+#define RTL_8221B_VB_CG 0x001cc849
+#define RTL_8221B_VN_CG 0x001cc84a
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
@@ -283,6 +314,62 @@ static int rtl8366rb_config_init(struct phy_device *phydev)
return ret;
}
+/* get actual speed to cover the downshift case */
+static void rtlgen_decode_physr(struct phy_device *phydev, int val)
+{
+ /* bit 3
+ * 0: Half Duplex
+ * 1: Full Duplex
+ */
+ if (val & RTL_VND2_PHYSR_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ switch (val & RTL_VND2_PHYSR_SPEED_MASK) {
+ case 0x0000:
+ phydev->speed = SPEED_10;
+ break;
+ case 0x0010:
+ phydev->speed = SPEED_100;
+ break;
+ case 0x0020:
+ phydev->speed = SPEED_1000;
+ break;
+ case 0x0200:
+ phydev->speed = SPEED_10000;
+ break;
+ case 0x0210:
+ phydev->speed = SPEED_2500;
+ break;
+ case 0x0220:
+ phydev->speed = SPEED_5000;
+ break;
+ default:
+ break;
+ }
+}
+
+static int rtlgen_read_status(struct phy_device *phydev)
+{
+ int ret, val;
+
+ ret = genphy_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (!phydev->link)
+ return 0;
+
+ val = phy_read_paged(phydev, 0xa43, 0x12);
+ if (val < 0)
+ return val;
+
+ rtlgen_decode_physr(phydev, val);
+
+ return 0;
+}
+
static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
{
int ret;
@@ -420,6 +507,266 @@ static int rtl8125_read_status(struct phy_device *phydev)
return genphy_read_status(phydev);
}
+static int rtl822xb_config_init(struct phy_device *phydev)
+{
+ bool has_2500 = true, has_sgmii = false;
+ int ret, val;
+ u16 mode;
+
+ /* determine SerDes option mode */
+ if (has_2500 && !has_sgmii) {
+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX;
+ phydev->rate_matching = RATE_MATCH_PAUSE;
+ } else {
+ mode = RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII;
+ phydev->rate_matching = RATE_MATCH_NONE;
+ }
+
+ /* the following sequence with magic numbers sets up the SerDes
+ * option mode
+ */
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x75f3, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND1,
+ RTL822X_VND1_SERDES_OPTION,
+ RTL822X_VND1_SERDES_OPTION_MODE_MASK,
+ mode);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6a04, 0x0503);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f10, 0xd455);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x6f11, 0x8020);
+ if (ret < 0)
+ return ret;
+
+ /* Disable SGMII AN */
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7588, 0x2);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7589, 0x71d0);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0x7587, 0x3);
+ if (ret < 0)
+ return ret;
+
+ ret = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND1, 0x7587,
+ val, !(val & BIT(0)), 500, 100000, false);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int rtl822xb_get_rate_matching(struct phy_device *phydev,
+ phy_interface_t iface)
+{
+ int val;
+
+ /* Only rate matching at 2500base-x */
+ if (iface != PHY_INTERFACE_MODE_2500BASEX)
+ return RATE_MATCH_NONE;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_OPTION);
+ if (val < 0)
+ return val;
+
+ if ((val & RTL822X_VND1_SERDES_OPTION_MODE_MASK) ==
+ RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX)
+ return RATE_MATCH_PAUSE;
+
+ /* RTL822X_VND1_SERDES_OPTION_MODE_2500BASEX_SGMII */
+ return RATE_MATCH_NONE;
+}
+
+static int rtl822x_get_features(struct phy_device *phydev)
+{
+ int val;
+
+ val = phy_read_paged(phydev, 0xa61, 0x13);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
+ phydev->supported, val & MDIO_PMA_SPEED_2_5G);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
+ phydev->supported, val & MDIO_PMA_SPEED_5G);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
+ phydev->supported, val & MDIO_SPEED_10G);
+
+ return genphy_read_abilities(phydev);
+}
+
+static int rtl822x_config_aneg(struct phy_device *phydev)
+{
+ int ret = 0;
+
+ if (phydev->autoneg == AUTONEG_ENABLE) {
+ u16 adv = linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising);
+
+ ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
+ MDIO_AN_10GBT_CTRL_ADV2_5G |
+ MDIO_AN_10GBT_CTRL_ADV5G,
+ adv);
+ if (ret < 0)
+ return ret;
+ }
+
+ return __genphy_config_aneg(phydev, ret);
+}
+
+static void rtl822xb_update_interface(struct phy_device *phydev)
+{
+ int val;
+
+ if (!phydev->link)
+ return;
+
+ /* Change interface according to serdes mode */
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL822X_VND1_SERDES_CTRL3);
+ if (val < 0)
+ return;
+
+ switch (val & RTL822X_VND1_SERDES_CTRL3_MODE_MASK) {
+ case RTL822X_VND1_SERDES_CTRL3_MODE_2500BASEX:
+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
+ break;
+ case RTL822X_VND1_SERDES_CTRL3_MODE_SGMII:
+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
+ break;
+ }
+}
+
+static int rtl822x_read_status(struct phy_device *phydev)
+{
+ int lpadv, ret;
+
+ ret = rtlgen_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_DISABLE ||
+ !phydev->autoneg_complete) {
+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
+ return 0;
+ }
+
+ lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
+ if (lpadv < 0)
+ return lpadv;
+
+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
+
+ return 0;
+}
+
+static int rtl822xb_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = rtl822x_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ rtl822xb_update_interface(phydev);
+
+ return 0;
+}
+
+static int rtl822x_c45_get_features(struct phy_device *phydev)
+{
+ linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT,
+ phydev->supported);
+
+ return genphy_c45_pma_read_abilities(phydev);
+}
+
+static int rtl822x_c45_config_aneg(struct phy_device *phydev)
+{
+ bool changed = false;
+ int ret, val;
+
+ if (phydev->autoneg == AUTONEG_DISABLE)
+ return genphy_c45_pma_setup_forced(phydev);
+
+ ret = genphy_c45_an_config_aneg(phydev);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ changed = true;
+
+ val = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
+
+ /* Vendor register as C45 has no standardized support for 1000BaseT */
+ ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, RTL822X_VND2_GBCR,
+ ADVERTISE_1000FULL, val);
+ if (ret < 0)
+ return ret;
+ if (ret > 0)
+ changed = true;
+
+ return genphy_c45_check_and_restart_aneg(phydev, changed);
+}
+
+static int rtl822x_c45_read_status(struct phy_device *phydev)
+{
+ int ret, val;
+
+ ret = genphy_c45_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ if (phydev->autoneg == AUTONEG_DISABLE ||
+ !genphy_c45_aneg_done(phydev))
+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, 0);
+
+ /* Vendor register as C45 has no standardized support for 1000BaseT */
+ if (phydev->autoneg == AUTONEG_ENABLE) {
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2,
+ RTL822X_VND2_GANLPAR);
+ if (val < 0)
+ return val;
+
+ mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, val);
+ }
+
+ if (!phydev->link)
+ return 0;
+
+ /* Read actual speed from vendor register. */
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND2, RTL_VND2_PHYSR);
+ if (val < 0)
+ return val;
+
+ rtlgen_decode_physr(phydev, val);
+
+ return 0;
+}
+
+static int rtl822xb_c45_read_status(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = rtl822x_c45_read_status(phydev);
+ if (ret < 0)
+ return ret;
+
+ rtl822xb_update_interface(phydev);
+
+ return 0;
+}
+
static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
{
int val;
@@ -443,6 +790,138 @@ static int rtl8125_match_phy_device(struct phy_device *phydev)
rtlgen_supports_2_5gbps(phydev);
}
+static int rtlgen_is_c45_match(struct phy_device *phydev, unsigned int id,
+ bool is_c45)
+{
+ if (phydev->is_c45) {
+ u32 rid;
+
+ if (!is_c45)
+ return 0;
+
+ rid = phydev->c45_ids.device_ids[1];
+ if ((rid == 0xffffffff) && phydev->mdio.bus->read) {
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID1);
+ if (val < 0)
+ return 0;
+
+ rid = val << 16;
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID2);
+ if (val < 0)
+ return 0;
+
+ rid |= val;
+ }
+
+ return (id == rid);
+ } else {
+ return !is_c45 && (id == phydev->phy_id);
+ }
+}
+
+static int rtl8221b_vb_cg_c22_match_phy_device(struct phy_device *phydev)
+{
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, false);
+}
+
+static int rtl8221b_vb_cg_c45_match_phy_device(struct phy_device *phydev)
+{
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VB_CG, true);
+}
+
+static int rtl8221b_vn_cg_c22_match_phy_device(struct phy_device *phydev)
+{
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, false);
+}
+
+static int rtl8221b_vn_cg_c45_match_phy_device(struct phy_device *phydev)
+{
+ return rtlgen_is_c45_match(phydev, RTL_8221B_VN_CG, true);
+}
+
+static int rtl822x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1);
+ if (val < 0)
+ return val;
+
+ if (of_property_read_bool(dev->of_node, "realtek,aldps-enable"))
+ val |= RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN;
+ else
+ val &= ~(RTL8221B_PHYCR1_ALDPS_EN | RTL8221B_PHYCR1_ALDPS_XTAL_OFF_EN);
+
+ phy_write_mmd(phydev, MDIO_MMD_VEND1, RTL8221B_PHYCR1, val);
+
+ return 0;
+}
+
+static int rtlgen_resume(struct phy_device *phydev)
+{
+ int ret = genphy_resume(phydev);
+
+ /* Internal PHY's from RTL8168h up may not be instantly ready */
+ msleep(20);
+
+ return ret;
+}
+
+static int rtlgen_c45_resume(struct phy_device *phydev)
+{
+ int ret = genphy_c45_pma_resume(phydev);
+
+ msleep(20);
+
+ return ret;
+}
+
+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = phy_read_mmd(phydev, MDIO_MMD_VEND2, 0xa4d4);
+
+ return (err < 0) ? err : 0;
+}
+
+static int rtl8221b_config_intr(struct phy_device *phydev)
+{
+ int err;
+
+ if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err)
+ return err;
+
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x7ff);
+ } else {
+ err = phy_write_mmd(phydev, MDIO_MMD_VEND2, 0xa4d2, 0x0);
+ if (err)
+ return err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ }
+
+ return err;
+}
+
+static int rtl8221b_handle_interrupt(struct phy_device *phydev)
+{
+ int err;
+
+ err = rtl8221b_ack_interrupt(phydev);
+ if (err)
+ return -1;
+
+ phy_queue_state_machine(phydev, 0);
+
+ return 0;
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -542,6 +1021,66 @@ static struct phy_driver realtek_drvs[] = {
.write_page = rtl821x_write_page,
.read_mmd = rtl8125_read_mmd,
.write_mmd = rtl8125_write_mmd,
+ }, {
+ .match_phy_device = rtl8221b_vb_cg_c22_match_phy_device,
+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
+ .probe = rtl822x_probe,
+ .soft_reset = genphy_soft_reset,
+ .get_features = rtl822x_get_features,
+ .config_aneg = rtl822x_config_aneg,
+ .config_init = rtl822xb_config_init,
+ .get_rate_matching = rtl822xb_get_rate_matching,
+ .read_status = rtl822xb_read_status,
+ .suspend = genphy_suspend,
+ .resume = rtlgen_resume,
+ .read_page = rtl821x_read_page,
+ .write_page = rtl821x_write_page,
+ }, {
+ .match_phy_device = rtl8221b_vb_cg_c45_match_phy_device,
+ .name = "RTL8221B-VB-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
+ .probe = rtl822x_probe,
+ /*.soft_reset = genphy_soft_reset,*/
+ .config_init = rtl822xb_config_init,
+ .get_rate_matching = rtl822xb_get_rate_matching,
+ .get_features = rtl822x_c45_get_features,
+ .config_aneg = rtl822x_c45_config_aneg,
+ .read_status = rtl822xb_c45_read_status,
+ .suspend = genphy_c45_pma_suspend,
+ .resume = rtlgen_c45_resume,
+ }, {
+ .match_phy_device = rtl8221b_vn_cg_c22_match_phy_device,
+ .name = "RTL8221B-VM-CG 2.5Gbps PHY (C22)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
+ .probe = rtl822x_probe,
+ .soft_reset = genphy_soft_reset,
+ .get_features = rtl822x_get_features,
+ .config_aneg = rtl822x_config_aneg,
+ .config_init = rtl822xb_config_init,
+ .get_rate_matching = rtl822xb_get_rate_matching,
+ .read_status = rtl822xb_read_status,
+ .suspend = genphy_suspend,
+ .resume = rtlgen_resume,
+ .read_page = rtl821x_read_page,
+ .write_page = rtl821x_write_page,
+ }, {
+ .match_phy_device = rtl8221b_vn_cg_c45_match_phy_device,
+ .name = "RTL8221B-VN-CG 2.5Gbps PHY (C45)",
+ .config_intr = rtl8221b_config_intr,
+ .handle_interrupt = rtl8221b_handle_interrupt,
+ .probe = rtl822x_probe,
+ .soft_reset = genphy_soft_reset,
+ .config_init = rtl822xb_config_init,
+ .get_rate_matching = rtl822xb_get_rate_matching,
+ .get_features = rtl822x_c45_get_features,
+ .config_aneg = rtl822x_c45_config_aneg,
+ .read_status = rtl822xb_c45_read_status,
+ .suspend = genphy_c45_pma_suspend,
+ .resume = rtlgen_c45_resume,
}, {
PHY_ID_MATCH_EXACT(0x001cc961),
.name = "RTL8366RB Gigabit Ethernet",
--
2.45.2

View File

@@ -0,0 +1,34 @@
From de404873748fcfc3a2c281851f0cc57664ceea70 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 12 May 2025 15:47:16 +0800
Subject: [PATCH] net: phy: add sanity check to read/write mmd
---
drivers/net/phy/phy-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index c34fc07..f160536 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -400,7 +400,7 @@ int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
- if (phydev->drv->read_mmd) {
+ if (phydev->drv && phydev->drv->read_mmd) {
val = phydev->drv->read_mmd(phydev, devad, regnum);
} else if (phydev->is_c45) {
u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
@@ -457,7 +457,7 @@ int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
if (regnum > (u16)~0 || devad > 32)
return -EINVAL;
- if (phydev->drv->write_mmd) {
+ if (phydev->drv && phydev->drv->write_mmd) {
ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
} else if (phydev->is_c45) {
u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
--
2.45.2

View File

@@ -0,0 +1,57 @@
diff --git a/drivers/net/phy/phy-core.c b/drivers/net/phy/phy-core.c
index 7f7cdbd..0fd9885 100644
--- a/drivers/net/phy/phy-core.c
+++ b/drivers/net/phy/phy-core.c
@@ -8,7 +8,7 @@
const char *phy_speed_to_str(int speed)
{
- BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 69,
+ BUILD_BUG_ON_MSG(__ETHTOOL_LINK_MODE_MASK_NBITS != 102,
"Enum ethtool_link_mode_bit_indices and phylib are out of sync. "
"If a speed or mode has been added please update phy_speed_to_str "
"and the PHY settings array.\n");
diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h
index ce41d2f..502baa2 100644
--- a/include/uapi/linux/ethtool.h
+++ b/include/uapi/linux/ethtool.h
@@ -1507,6 +1507,39 @@ enum ethtool_link_mode_bit_indices {
ETHTOOL_LINK_MODE_200000baseCR4_Full_BIT = 66,
ETHTOOL_LINK_MODE_100baseT1_Full_BIT = 67,
ETHTOOL_LINK_MODE_1000baseT1_Full_BIT = 68,
+ ETHTOOL_LINK_MODE_400000baseKR8_Full_BIT = 69,
+ ETHTOOL_LINK_MODE_400000baseSR8_Full_BIT = 70,
+ ETHTOOL_LINK_MODE_400000baseLR8_ER8_FR8_Full_BIT = 71,
+ ETHTOOL_LINK_MODE_400000baseDR8_Full_BIT = 72,
+ ETHTOOL_LINK_MODE_400000baseCR8_Full_BIT = 73,
+ ETHTOOL_LINK_MODE_FEC_LLRS_BIT = 74,
+ ETHTOOL_LINK_MODE_100000baseKR_Full_BIT = 75,
+ ETHTOOL_LINK_MODE_100000baseSR_Full_BIT = 76,
+ ETHTOOL_LINK_MODE_100000baseLR_ER_FR_Full_BIT = 77,
+ ETHTOOL_LINK_MODE_100000baseCR_Full_BIT = 78,
+ ETHTOOL_LINK_MODE_100000baseDR_Full_BIT = 79,
+ ETHTOOL_LINK_MODE_200000baseKR2_Full_BIT = 80,
+ ETHTOOL_LINK_MODE_200000baseSR2_Full_BIT = 81,
+ ETHTOOL_LINK_MODE_200000baseLR2_ER2_FR2_Full_BIT = 82,
+ ETHTOOL_LINK_MODE_200000baseDR2_Full_BIT = 83,
+ ETHTOOL_LINK_MODE_200000baseCR2_Full_BIT = 84,
+ ETHTOOL_LINK_MODE_400000baseKR4_Full_BIT = 85,
+ ETHTOOL_LINK_MODE_400000baseSR4_Full_BIT = 86,
+ ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87,
+ ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT = 88,
+ ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89,
+ ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90,
+ ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91,
+ ETHTOOL_LINK_MODE_10baseT1L_Full_BIT = 92,
+ ETHTOOL_LINK_MODE_800000baseCR8_Full_BIT = 93,
+ ETHTOOL_LINK_MODE_800000baseKR8_Full_BIT = 94,
+ ETHTOOL_LINK_MODE_800000baseDR8_Full_BIT = 95,
+ ETHTOOL_LINK_MODE_800000baseDR8_2_Full_BIT = 96,
+ ETHTOOL_LINK_MODE_800000baseSR8_Full_BIT = 97,
+ ETHTOOL_LINK_MODE_800000baseVR8_Full_BIT = 98,
+ ETHTOOL_LINK_MODE_10baseT1S_Full_BIT = 99,
+ ETHTOOL_LINK_MODE_10baseT1S_Half_BIT = 100,
+ ETHTOOL_LINK_MODE_10baseT1S_P2MP_Half_BIT = 101,
/* must be last entry */
__ETHTOOL_LINK_MODE_MASK_NBITS

View File

@@ -0,0 +1,394 @@
diff --git a/drivers/net/phy/phy-c45.c b/drivers/net/phy/phy-c45.c
index 797946c..4bb258b 100644
--- a/drivers/net/phy/phy-c45.c
+++ b/drivers/net/phy/phy-c45.c
@@ -8,6 +8,25 @@
#include <linux/mii.h>
#include <linux/phy.h>
+/**
+ * genphy_c45_baset1_able - checks if the PMA has BASE-T1 extended abilities
+ * @phydev: target phy_device struct
+ */
+static bool genphy_c45_baset1_able(struct phy_device *phydev)
+{
+ int val;
+
+ if (phydev->pma_extable == -ENODATA) {
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
+ if (val < 0)
+ return false;
+
+ phydev->pma_extable = val;
+ }
+
+ return !!(phydev->pma_extable & MDIO_PMA_EXTABLE_BT1);
+}
+
/**
* genphy_c45_pma_can_sleep - checks if the PMA have sleep support
* @phydev: target phy_device struct
@@ -52,7 +71,7 @@ int genphy_c45_pma_suspend(struct phy_device *phydev)
EXPORT_SYMBOL_GPL(genphy_c45_pma_suspend);
/**
- * genphy_c45_setup_forced - configures a forced speed
+ * genphy_c45_pma_setup_forced - configures a forced speed
* @phydev: target phy_device struct
*/
int genphy_c45_pma_setup_forced(struct phy_device *phydev)
@@ -178,8 +197,12 @@ EXPORT_SYMBOL_GPL(genphy_c45_an_config_aneg);
*/
int genphy_c45_an_disable_aneg(struct phy_device *phydev)
{
+ u16 reg = MDIO_CTRL1;
- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1,
+ if (genphy_c45_baset1_able(phydev))
+ reg = MDIO_AN_T1_CTRL;
+
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
}
EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg);
@@ -194,7 +217,12 @@ EXPORT_SYMBOL_GPL(genphy_c45_an_disable_aneg);
*/
int genphy_c45_restart_aneg(struct phy_device *phydev)
{
- return phy_set_bits_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1,
+ u16 reg = MDIO_CTRL1;
+
+ if (genphy_c45_baset1_able(phydev))
+ reg = MDIO_AN_T1_CTRL;
+
+ return phy_set_bits_mmd(phydev, MDIO_MMD_AN, reg,
MDIO_AN_CTRL1_ENABLE | MDIO_AN_CTRL1_RESTART);
}
EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
@@ -210,11 +238,15 @@ EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
*/
int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
{
- int ret = 0;
+ u16 reg = MDIO_CTRL1;
+ int ret;
+
+ if (genphy_c45_baset1_able(phydev))
+ reg = MDIO_AN_T1_CTRL;
if (!restart) {
/* Configure and restart aneg if it wasn't set before */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
if (ret < 0)
return ret;
@@ -223,9 +255,9 @@ int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
}
if (restart)
- ret = genphy_c45_restart_aneg(phydev);
+ return genphy_c45_restart_aneg(phydev);
- return ret;
+ return 0;
}
EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
@@ -242,7 +274,13 @@ EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
*/
int genphy_c45_aneg_done(struct phy_device *phydev)
{
- int val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
+ int reg = MDIO_STAT1;
+ int val;
+
+ if (genphy_c45_baset1_able(phydev))
+ reg = MDIO_AN_T1_STAT;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
return val < 0 ? val : val & MDIO_AN_STAT1_COMPLETE ? 1 : 0;
}
@@ -307,6 +345,49 @@ int genphy_c45_read_link(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(genphy_c45_read_link);
+/* Read the Clause 45 defined BASE-T1 AN (7.513) status register to check
+ * if autoneg is complete. If so read the BASE-T1 Autonegotiation
+ * Advertisement registers filling in the link partner advertisement,
+ * pause and asym_pause members in phydev.
+ */
+static int genphy_c45_baset1_read_lpa(struct phy_device *phydev)
+{
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_STAT);
+ if (val < 0)
+ return val;
+
+ if (!(val & MDIO_AN_STAT1_COMPLETE)) {
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->lp_advertising);
+ mii_t1_adv_l_mod_linkmode_t(phydev->lp_advertising, 0);
+ mii_t1_adv_m_mod_linkmode_t(phydev->lp_advertising, 0);
+
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+
+ return 0;
+ }
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, phydev->lp_advertising, 1);
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_LP_L);
+ if (val < 0)
+ return val;
+
+ mii_t1_adv_l_mod_linkmode_t(phydev->lp_advertising, val);
+ phydev->pause = val & MDIO_AN_T1_ADV_L_PAUSE_CAP ? 1 : 0;
+ phydev->asym_pause = val & MDIO_AN_T1_ADV_L_PAUSE_ASYM ? 1 : 0;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_LP_M);
+ if (val < 0)
+ return val;
+
+ mii_t1_adv_m_mod_linkmode_t(phydev->lp_advertising, val);
+
+ return 0;
+}
+
/**
* genphy_c45_read_lpa - read the link partner advertisement and pause
* @phydev: target phy_device struct
@@ -321,6 +402,9 @@ int genphy_c45_read_lpa(struct phy_device *phydev)
{
int val;
+ if (genphy_c45_baset1_able(phydev))
+ return genphy_c45_baset1_read_lpa(phydev);
+
val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
if (val < 0)
return val;
@@ -436,6 +520,44 @@ int genphy_c45_read_mdix(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);
+/**
+ * genphy_c45_pma_baset1_read_abilities - read supported baset1 link modes from PMA
+ * @phydev: target phy_device struct
+ *
+ * Read the supported link modes from the extended BASE-T1 ability register
+ */
+int genphy_c45_pma_baset1_read_abilities(struct phy_device *phydev)
+{
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_PMD_BT1);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_PMD_BT1_B10L_ABLE);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_PMD_BT1_B100_ABLE);
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+ phydev->supported,
+ val & MDIO_PMA_PMD_BT1_B1000_ABLE);
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_T1_STAT);
+ if (val < 0)
+ return val;
+
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
+ phydev->supported,
+ val & MDIO_AN_STAT1_ABLE);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(genphy_c45_pma_baset1_read_abilities);
+
/**
* genphy_c45_pma_read_abilities - read supported link modes from PMA
* @phydev: target phy_device struct
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 99f265a..0325030 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -611,6 +612,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
dev->autoneg = AUTONEG_ENABLE;
+ dev->pma_extable = -ENODATA;
dev->is_c45 = is_c45;
dev->phy_id = phy_id;
if (c45_ids)
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index 006d1c1..6b14894 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -326,6 +326,42 @@ static inline void mii_10gbt_stat_mod_linkmode_lpa_t(unsigned long *advertising,
advertising, lpa & MDIO_AN_10GBT_STAT_LP10G);
}
+/**
+ * mii_t1_adv_l_mod_linkmode_t
+ * @advertising: target the linkmode advertisement settings
+ * @lpa: value of the BASE-T1 Autonegotiation Advertisement [15:0] Register
+ *
+ * A small helper function that translates BASE-T1 Autonegotiation
+ * Advertisement [15:0] Register bits to linkmode advertisement settings.
+ * Other bits in advertising aren't changed.
+ */
+static inline void mii_t1_adv_l_mod_linkmode_t(unsigned long *advertising, u32 lpa)
+{
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertising,
+ lpa & MDIO_AN_T1_ADV_L_PAUSE_CAP);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertising,
+ lpa & MDIO_AN_T1_ADV_L_PAUSE_ASYM);
+}
+
+/**
+ * mii_t1_adv_m_mod_linkmode_t
+ * @advertising: target the linkmode advertisement settings
+ * @lpa: value of the BASE-T1 Autonegotiation Advertisement [31:16] Register
+ *
+ * A small helper function that translates BASE-T1 Autonegotiation
+ * Advertisement [31:16] Register bits to linkmode advertisement settings.
+ * Other bits in advertising aren't changed.
+ */
+static inline void mii_t1_adv_m_mod_linkmode_t(unsigned long *advertising, u32 lpa)
+{
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT1L_Full_BIT,
+ advertising, lpa & MDIO_AN_T1_ADV_M_B10L);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT1_Full_BIT,
+ advertising, lpa & MDIO_AN_T1_ADV_M_100BT1);
+ linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT1_Full_BIT,
+ advertising, lpa & MDIO_AN_T1_ADV_M_1000BT1);
+}
+
int __mdiobus_read(struct mii_bus *bus, int addr, u32 regnum);
int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index fb21ddb..a9c2842 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -491,6 +493,8 @@ struct phy_device {
u8 mdix;
u8 mdix_ctrl;
+ int pma_extable;
+
void (*phy_link_change)(struct phy_device *, bool up, bool do_carrier);
void (*adjust_link)(struct net_device *dev);
diff --git a/include/uapi/linux/mdio.h b/include/uapi/linux/mdio.h
index 353a146..a47cadc 100644
--- a/include/uapi/linux/mdio.h
+++ b/include/uapi/linux/mdio.h
@@ -65,6 +65,17 @@
#define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */
#define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */
#define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */
+#define MDIO_PMA_PMD_BT1 18 /* BASE-T1 PMA/PMD extended ability */
+#define MDIO_AN_T1_CTRL 512 /* BASE-T1 AN control */
+#define MDIO_AN_T1_STAT 513 /* BASE-T1 AN status */
+#define MDIO_AN_T1_ADV_L 514 /* BASE-T1 AN advertisement register [15:0] */
+#define MDIO_AN_T1_ADV_M 515 /* BASE-T1 AN advertisement register [31:16] */
+#define MDIO_AN_T1_ADV_H 516 /* BASE-T1 AN advertisement register [47:32] */
+#define MDIO_AN_T1_LP_L 517 /* BASE-T1 AN LP Base Page ability register [15:0] */
+#define MDIO_AN_T1_LP_M 518 /* BASE-T1 AN LP Base Page ability register [31:16] */
+#define MDIO_AN_T1_LP_H 519 /* BASE-T1 AN LP Base Page ability register [47:32] */
+#define MDIO_AN_10BT1_AN_CTRL 526 /* 10BASE-T1 AN control register */
+#define MDIO_AN_10BT1_AN_STAT 527 /* 10BASE-T1 AN status register */
/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */
#define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */
@@ -159,6 +170,7 @@
#define MDIO_PMA_CTRL2_10BT 0x000f /* 10BASE-T type */
#define MDIO_PMA_CTRL2_2_5GBT 0x0030 /* 2.5GBaseT type */
#define MDIO_PMA_CTRL2_5GBT 0x0031 /* 5GBaseT type */
+#define MDIO_PMA_CTRL2_BASET1 0x003D /* BASE-T1 type */
#define MDIO_PCS_CTRL2_TYPE 0x0003 /* PCS type selection */
#define MDIO_PCS_CTRL2_10GBR 0x0000 /* 10GBASE-R type */
#define MDIO_PCS_CTRL2_10GBX 0x0001 /* 10GBASE-X type */
@@ -212,6 +224,7 @@
#define MDIO_PMA_EXTABLE_1000BKX 0x0040 /* 1000BASE-KX ability */
#define MDIO_PMA_EXTABLE_100BTX 0x0080 /* 100BASE-TX ability */
#define MDIO_PMA_EXTABLE_10BT 0x0100 /* 10BASE-T ability */
+#define MDIO_PMA_EXTABLE_BT1 0x0800 /* BASE-T1 ability */
#define MDIO_PMA_EXTABLE_NBT 0x4000 /* 2.5/5GBASE-T ability */
/* PHY XGXS lane state register. */
@@ -264,6 +277,66 @@
#define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */
#define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */
+/* BASE-T1 PMA/PMD extended ability register. */
+#define MDIO_PMA_PMD_BT1_B100_ABLE 0x0001 /* 100BASE-T1 Ability */
+#define MDIO_PMA_PMD_BT1_B1000_ABLE 0x0002 /* 1000BASE-T1 Ability */
+#define MDIO_PMA_PMD_BT1_B10L_ABLE 0x0004 /* 10BASE-T1L Ability */
+
+/* BASE-T1 auto-negotiation advertisement register [15:0] */
+#define MDIO_AN_T1_ADV_L_PAUSE_CAP ADVERTISE_PAUSE_CAP
+#define MDIO_AN_T1_ADV_L_PAUSE_ASYM ADVERTISE_PAUSE_ASYM
+#define MDIO_AN_T1_ADV_L_FORCE_MS 0x1000 /* Force Master/slave Configuration */
+#define MDIO_AN_T1_ADV_L_REMOTE_FAULT ADVERTISE_RFAULT
+#define MDIO_AN_T1_ADV_L_ACK ADVERTISE_LPACK
+#define MDIO_AN_T1_ADV_L_NEXT_PAGE_REQ ADVERTISE_NPAGE
+
+/* BASE-T1 auto-negotiation advertisement register [31:16] */
+#define MDIO_AN_T1_ADV_M_B10L 0x4000 /* device is compatible with 10BASE-T1L */
+#define MDIO_AN_T1_ADV_M_1000BT1 0x0080 /* advertise 1000BASE-T1 */
+#define MDIO_AN_T1_ADV_M_100BT1 0x0020 /* advertise 100BASE-T1 */
+#define MDIO_AN_T1_ADV_M_MST 0x0010 /* advertise master preference */
+
+/* BASE-T1 auto-negotiation advertisement register [47:32] */
+#define MDIO_AN_T1_ADV_H_10L_TX_HI_REQ 0x1000 /* 10BASE-T1L High Level Transmit Request */
+#define MDIO_AN_T1_ADV_H_10L_TX_HI 0x2000 /* 10BASE-T1L High Level Transmit Ability */
+
+/* BASE-T1 AN LP Base Page ability register [15:0] */
+#define MDIO_AN_T1_LP_L_PAUSE_CAP LPA_PAUSE_CAP
+#define MDIO_AN_T1_LP_L_PAUSE_ASYM LPA_PAUSE_ASYM
+#define MDIO_AN_T1_LP_L_FORCE_MS 0x1000 /* LP Force Master/slave Configuration */
+#define MDIO_AN_T1_LP_L_REMOTE_FAULT LPA_RFAULT
+#define MDIO_AN_T1_LP_L_ACK LPA_LPACK
+#define MDIO_AN_T1_LP_L_NEXT_PAGE_REQ LPA_NPAGE
+
+/* BASE-T1 AN LP Base Page ability register [31:16] */
+#define MDIO_AN_T1_LP_M_MST 0x0010 /* LP master preference */
+#define MDIO_AN_T1_LP_M_B10L 0x4000 /* LP is compatible with 10BASE-T1L */
+
+/* BASE-T1 AN LP Base Page ability register [47:32] */
+#define MDIO_AN_T1_LP_H_10L_TX_HI_REQ 0x1000 /* 10BASE-T1L High Level LP Transmit Request */
+#define MDIO_AN_T1_LP_H_10L_TX_HI 0x2000 /* 10BASE-T1L High Level LP Transmit Ability */
+
+/* 10BASE-T1 AN control register */
+#define MDIO_AN_10BT1_AN_CTRL_ADV_EEE_T1L 0x4000 /* 10BASE-T1L EEE ability advertisement */
+
+/* 10BASE-T1 AN status register */
+#define MDIO_AN_10BT1_AN_STAT_LPA_EEE_T1L 0x4000 /* 10BASE-T1L LP EEE ability advertisement */
+
+/* BASE-T1 PMA/PMD control register */
+#define MDIO_PMA_PMD_BT1_CTRL_STRAP 0x000F /* Type selection (Strap) */
+#define MDIO_PMA_PMD_BT1_CTRL_STRAP_B1000 0x0001 /* Select 1000BASE-T1 */
+#define MDIO_PMA_PMD_BT1_CTRL_CFG_MST 0x4000 /* MASTER-SLAVE config value */
+
+/* 1000BASE-T1 PCS control register */
+#define MDIO_PCS_1000BT1_CTRL_LOW_POWER 0x0800 /* Low power mode */
+#define MDIO_PCS_1000BT1_CTRL_DISABLE_TX 0x4000 /* Global PMA transmit disable */
+#define MDIO_PCS_1000BT1_CTRL_RESET 0x8000 /* Software reset value */
+
+/* 1000BASE-T1 PCS status register */
+#define MDIO_PCS_1000BT1_STAT_LINK 0x0004 /* PCS Link is up */
+#define MDIO_PCS_1000BT1_STAT_FAULT 0x0080 /* There is a fault condition */
+
+
/* EEE Supported/Advertisement/LP Advertisement registers.
*
* EEE capability Register (3.20), Advertisement (7.60) and

View File

@@ -0,0 +1,477 @@
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index e146955..291d5de 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -255,6 +255,13 @@ config LED_TRIGGER_PHY
<Speed in megabits>Mbps OR <Speed in gigabits>Gbps OR link
for any speed known to the PHY.
+config PHYLIB_LEDS
+ def_bool OF
+ depends on LEDS_CLASS=y || LEDS_CLASS=PHYLIB
+ ---help---
+ When LED class support is enabled, phylib can automatically
+ probe LED setting from device tree.
+
comment "Switch configuration API + drivers"
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 99f265a..0325030 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -23,6 +23,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
+#include <linux/of.h>
#include <linux/ethtool.h>
#include <linux/bitmap.h>
#include <linux/phy.h>
@@ -621,6 +623,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, u32 phy_id,
device_initialize(&mdiodev->dev);
dev->state = PHY_DOWN;
+ INIT_LIST_HEAD(&dev->leds);
mutex_init(&dev->lock);
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
@@ -2515,6 +2518,208 @@ static bool phy_drv_supports_irq(struct phy_driver *phydrv)
return phydrv->config_intr && phydrv->ack_interrupt;
}
+static int phy_led_set_brightness(struct led_classdev *led_cdev,
+ enum led_brightness value)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_brightness_set(phydev, phyled->index, value);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static int phy_led_blink_set(struct led_classdev *led_cdev,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_blink_set(phydev, phyled->index,
+ delay_on, delay_off);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static __maybe_unused struct device *
+phy_led_hw_control_get_device(struct led_classdev *led_cdev)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+
+ if (phydev->attached_dev)
+ return &phydev->attached_dev->dev;
+ return NULL;
+}
+
+static int __maybe_unused
+phy_led_hw_control_get(struct led_classdev *led_cdev,
+ unsigned long *rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_get(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static int __maybe_unused
+phy_led_hw_control_set(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_control_set(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static __maybe_unused int phy_led_hw_is_supported(struct led_classdev *led_cdev,
+ unsigned long rules)
+{
+ struct phy_led *phyled = to_phy_led(led_cdev);
+ struct phy_device *phydev = phyled->phydev;
+ int err;
+
+ mutex_lock(&phydev->lock);
+ err = phydev->drv->led_hw_is_supported(phydev, phyled->index, rules);
+ mutex_unlock(&phydev->lock);
+
+ return err;
+}
+
+static void phy_leds_unregister(struct phy_device *phydev)
+{
+ struct phy_led *phyled, *tmp;
+
+ list_for_each_entry_safe(phyled, tmp, &phydev->leds, list) {
+ led_classdev_unregister(&phyled->led_cdev);
+ list_del(&phyled->list);
+ }
+}
+
+static int of_phy_led(struct phy_device *phydev,
+ struct device_node *led)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct led_init_data init_data = {};
+ struct led_classdev *cdev;
+ unsigned long modes = 0;
+ struct phy_led *phyled;
+ u32 index;
+ int err;
+
+ phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
+ if (!phyled)
+ return -ENOMEM;
+
+ cdev = &phyled->led_cdev;
+ phyled->phydev = phydev;
+
+ err = of_property_read_u32(led, "reg", &index);
+ if (err)
+ return err;
+ if (index > U8_MAX)
+ return -EINVAL;
+
+ if (of_property_read_bool(led, "active-high"))
+ set_bit(PHY_LED_ACTIVE_HIGH, &modes);
+ if (of_property_read_bool(led, "active-low"))
+ set_bit(PHY_LED_ACTIVE_LOW, &modes);
+ if (of_property_read_bool(led, "inactive-high-impedance"))
+ set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
+
+ if (WARN_ON(modes & BIT(PHY_LED_ACTIVE_LOW) &&
+ modes & BIT(PHY_LED_ACTIVE_HIGH)))
+ return -EINVAL;
+
+ if (modes) {
+ /* Return error if asked to set polarity modes but not supported */
+ if (!phydev->drv->led_polarity_set)
+ return -EINVAL;
+
+ err = phydev->drv->led_polarity_set(phydev, index, modes);
+ if (err)
+ return err;
+ }
+
+ phyled->index = index;
+ if (phydev->drv->led_brightness_set)
+ cdev->brightness_set_blocking = phy_led_set_brightness;
+ if (phydev->drv->led_blink_set)
+ cdev->blink_set = phy_led_blink_set;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+ if (phydev->drv->led_hw_is_supported &&
+ phydev->drv->led_hw_control_set &&
+ phydev->drv->led_hw_control_get) {
+ cdev->hw_control_is_supported = phy_led_hw_is_supported;
+ cdev->hw_control_set = phy_led_hw_control_set;
+ cdev->hw_control_get = phy_led_hw_control_get;
+ cdev->hw_control_trigger = "netdev";
+ }
+
+ cdev->hw_control_get_device = phy_led_hw_control_get_device;
+#endif
+ cdev->max_brightness = 1;
+ init_data.devicename = dev_name(&phydev->mdio.dev);
+ init_data.fwnode = of_fwnode_handle(led);
+ init_data.devname_mandatory = true;
+
+ err = led_classdev_register_ext(dev, cdev, &init_data);
+ if (err)
+ return err;
+
+ list_add(&phyled->list, &phydev->leds);
+
+ return 0;
+}
+
+static int of_phy_leds(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct device_node *leds, *led;
+ int err;
+
+ if (!IS_ENABLED(CONFIG_OF_MDIO))
+ return 0;
+
+ if (!node)
+ return 0;
+
+ leds = of_get_child_by_name(node, "leds");
+ if (!leds)
+ return 0;
+
+ for_each_available_child_of_node(leds, led) {
+ err = of_phy_led(phydev, led);
+ if (err) {
+ of_node_put(led);
+ of_node_put(leds);
+ phy_leds_unregister(phydev);
+ return err;
+ }
+ }
+
+ of_node_put(leds);
+ return 0;
+}
+
/**
* phy_probe - probe and init a PHY device
* @dev: device to probe and init
@@ -2613,6 +2818,12 @@ static int phy_probe(struct device *dev)
/* Set the state to READY by default */
phydev->state = PHY_READY;
+ /* Get the LEDs from the device tree, and instantiate standard
+ * LEDs for them.
+ */
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
+ err = of_phy_leds(phydev);
+
out:
mutex_unlock(&phydev->lock);
@@ -2625,6 +2836,9 @@ static int phy_remove(struct device *dev)
cancel_delayed_work_sync(&phydev->state_queue);
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS))
+ phy_leds_unregister(phydev);
+
mutex_lock(&phydev->lock);
phydev->state = PHY_DOWN;
mutex_unlock(&phydev->lock);
diff --git a/include/linux/leds.h b/include/linux/leds.h
index efb309d..d5ef91a 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -139,6 +139,49 @@ struct led_classdev {
void *trigger_data;
/* true if activated - deactivate routine uses it to do cleanup */
bool activated;
+
+ /* Unique trigger name supported by LED set in hw control mode */
+ const char *hw_control_trigger;
+ /*
+ * Check if the LED driver supports the requested mode provided by the
+ * defined supported trigger to setup the LED to hw control mode.
+ *
+ * Return 0 on success. Return -EOPNOTSUPP when the passed flags are not
+ * supported and software fallback needs to be used.
+ * Return a negative error number on any other case for check fail due
+ * to various reason like device not ready or timeouts.
+ */
+ int (*hw_control_is_supported)(struct led_classdev *led_cdev,
+ unsigned long flags);
+ /*
+ * Activate hardware control, LED driver will use the provided flags
+ * from the supported trigger and setup the LED to be driven by hardware
+ * following the requested mode from the trigger flags.
+ * Deactivate hardware blink control by setting brightness to LED_OFF via
+ * the brightness_set() callback.
+ *
+ * Return 0 on success, a negative error number on flags apply fail.
+ */
+ int (*hw_control_set)(struct led_classdev *led_cdev,
+ unsigned long flags);
+ /*
+ * Get from the LED driver the current mode that the LED is set in hw
+ * control mode and put them in flags.
+ * Trigger can use this to get the initial state of a LED already set in
+ * hardware blink control.
+ *
+ * Return 0 on success, a negative error number on failing parsing the
+ * initial mode. Error from this function is NOT FATAL as the device
+ * may be in a not supported initial state by the attached LED trigger.
+ */
+ int (*hw_control_get)(struct led_classdev *led_cdev,
+ unsigned long *flags);
+ /*
+ * Get the device this LED blinks in response to.
+ * e.g. for a PHY LED, it is the network device. If the LED is
+ * not yet associated to a device, return NULL.
+ */
+ struct device *(*hw_control_get_device)(struct led_classdev *led_cdev);
#endif
#ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED
@@ -455,6 +498,24 @@ static inline void *led_get_trigger_data(struct led_classdev *led_cdev)
#endif /* CONFIG_LEDS_TRIGGERS */
+/* Trigger specific enum */
+enum led_trigger_netdev_modes {
+ TRIGGER_NETDEV_LINK = 0,
+ TRIGGER_NETDEV_LINK_10,
+ TRIGGER_NETDEV_LINK_100,
+ TRIGGER_NETDEV_LINK_1000,
+ TRIGGER_NETDEV_LINK_2500,
+ TRIGGER_NETDEV_LINK_5000,
+ TRIGGER_NETDEV_LINK_10000,
+ TRIGGER_NETDEV_HALF_DUPLEX,
+ TRIGGER_NETDEV_FULL_DUPLEX,
+ TRIGGER_NETDEV_TX,
+ TRIGGER_NETDEV_RX,
+
+ /* Keep last */
+ __TRIGGER_NETDEV_MAX,
+};
+
/* Trigger specific functions */
#ifdef CONFIG_LEDS_TRIGGER_DISK
extern void ledtrig_disk_activity(bool write);
diff --git a/include/linux/phy.h b/include/linux/phy.h
index fb21ddb..a9c2842 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -14,6 +14,7 @@
#include <linux/compiler.h>
#include <linux/spinlock.h>
#include <linux/ethtool.h>
+#include <linux/leds.h>
#include <linux/linkmode.h>
#include <linux/mdio.h>
#include <linux/mii.h>
@@ -462,6 +463,7 @@ struct phy_device {
struct phy_led_trigger *led_link_trigger;
#endif
+ struct list_head leds;
/*
* Interrupt number for this PHY
@@ -502,6 +506,33 @@ struct phy_device {
#define to_phy_device(d) container_of(to_mdio_device(d), \
struct phy_device, mdio)
+/**
+ * struct phy_led: An LED driven by the PHY
+ *
+ * @list: List of LEDs
+ * @phydev: PHY this LED is attached to
+ * @led_cdev: Standard LED class structure
+ * @index: Number of the LED
+ */
+struct phy_led {
+ struct list_head list;
+ struct phy_device *phydev;
+ struct led_classdev led_cdev;
+ u8 index;
+};
+
+#define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
+
+/* Modes for PHY LED configuration */
+enum phy_led_modes {
+ PHY_LED_ACTIVE_HIGH = 0,
+ PHY_LED_ACTIVE_LOW = 1,
+ PHY_LED_INACTIVE_HIGH_IMPEDANCE = 2,
+
+ /* keep it last */
+ __PHY_LED_MODES_NUM,
+};
+
/* struct phy_driver: Driver structure for a particular PHY type
*
* driver_data: static driver data
@@ -705,6 +736,73 @@ struct phy_driver {
struct ethtool_tunable *tuna,
const void *data);
int (*set_loopback)(struct phy_device *dev, bool enable);
+
+ /**
+ * @led_brightness_set: Set a PHY LED brightness. Index
+ * indicates which of the PHYs led should be set. Value
+ * follows the standard LED class meaning, e.g. LED_OFF,
+ * LED_HALF, LED_FULL.
+ */
+ int (*led_brightness_set)(struct phy_device *dev,
+ u8 index, enum led_brightness value);
+
+ /**
+ * @led_blink_set: Set a PHY LED blinking. Index indicates
+ * which of the PHYs led should be configured to blink. Delays
+ * are in milliseconds and if both are zero then a sensible
+ * default should be chosen. The call should adjust the
+ * timings in that case and if it can't match the values
+ * specified exactly.
+ */
+ int (*led_blink_set)(struct phy_device *dev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off);
+ /**
+ * @led_hw_is_supported: Can the HW support the given rules.
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The core is interested in these rules
+ *
+ * Return 0 if yes, -EOPNOTSUPP if not, or an error code.
+ */
+ int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_set: Set the HW to control the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules The rules used to control the LED
+ *
+ * Returns 0, or a an error code.
+ */
+ int (*led_hw_control_set)(struct phy_device *dev, u8 index,
+ unsigned long rules);
+ /**
+ * @led_hw_control_get: Get how the HW is controlling the LED
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @rules Pointer to the rules used to control the LED
+ *
+ * Set *@rules to how the HW is currently blinking. Returns 0
+ * on success, or a error code if the current blinking cannot
+ * be represented in rules, or some other error happens.
+ */
+ int (*led_hw_control_get)(struct phy_device *dev, u8 index,
+ unsigned long *rules);
+
+ /**
+ * @led_polarity_set: Set the LED polarity modes
+ * @dev: PHY device which has the LED
+ * @index: Which LED of the PHY device
+ * @modes: bitmap of LED polarity modes
+ *
+ * Configure LED with all the required polarity modes in @modes
+ * to make it correctly turn ON or OFF.
+ *
+ * Returns 0, or an error code.
+ */
+ int (*led_polarity_set)(struct phy_device *dev, int index,
+ unsigned long modes);
};
#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \
struct phy_driver, mdiodrv)

View File

@@ -0,0 +1,654 @@
From f2f8228373e6aef6ece42b2da2273d983af581a7 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Fri, 16 May 2025 16:12:49 +0800
Subject: [PATCH] leds: trigger: netdev: add additional specific link speed and
duplex mode
---
drivers/leds/trigger/ledtrig-netdev.c | 421 +++++++++++++++++++-------
1 file changed, 308 insertions(+), 113 deletions(-)
diff --git a/drivers/leds/trigger/ledtrig-netdev.c b/drivers/leds/trigger/ledtrig-netdev.c
index f4d670e..7b56ae3 100644
--- a/drivers/leds/trigger/ledtrig-netdev.c
+++ b/drivers/leds/trigger/ledtrig-netdev.c
@@ -20,10 +20,13 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/netdevice.h>
-#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/rtnetlink.h>
#include <linux/timer.h>
#include "../leds.h"
+#define NETDEV_LED_DEFAULT_INTERVAL 50
+
/*
* Configurable sysfs attributes:
*
@@ -37,7 +40,7 @@
*/
struct led_netdev_data {
- spinlock_t lock;
+ struct mutex lock;
struct delayed_work work;
struct notifier_block notifier;
@@ -50,16 +53,11 @@ struct led_netdev_data {
unsigned int last_activity;
unsigned long mode;
-#define NETDEV_LED_LINK 0
-#define NETDEV_LED_TX 1
-#define NETDEV_LED_RX 2
-#define NETDEV_LED_MODE_LINKUP 3
-};
+ int link_speed;
+ u8 duplex;
-enum netdev_led_attr {
- NETDEV_ATTR_LINK,
- NETDEV_ATTR_TX,
- NETDEV_ATTR_RX
+ bool carrier_link_up;
+ bool hw_control;
};
static void set_baseline_state(struct led_netdev_data *trigger_data)
@@ -67,16 +65,60 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
int current_brightness;
struct led_classdev *led_cdev = trigger_data->led_cdev;
+ /* Already validated, hw control is possible with the requested mode */
+ if (trigger_data->hw_control) {
+ led_cdev->hw_control_set(led_cdev, trigger_data->mode);
+
+ return;
+ }
+
current_brightness = led_cdev->brightness;
if (current_brightness)
led_cdev->blink_brightness = current_brightness;
if (!led_cdev->blink_brightness)
led_cdev->blink_brightness = led_cdev->max_brightness;
- if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
+ if (!trigger_data->carrier_link_up) {
led_set_brightness(led_cdev, LED_OFF);
- else {
- if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
+ } else {
+ bool blink_on = false;
+
+ if (test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode))
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_10)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_100)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_1000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_2500)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_5000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) &&
+ trigger_data->link_speed == SPEED_10000)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) &&
+ trigger_data->duplex == DUPLEX_HALF)
+ blink_on = true;
+
+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode) &&
+ trigger_data->duplex == DUPLEX_FULL)
+ blink_on = true;
+
+ if (blink_on)
led_set_brightness(led_cdev,
led_cdev->blink_brightness);
else
@@ -85,44 +127,129 @@ static void set_baseline_state(struct led_netdev_data *trigger_data)
/* If we are looking for RX/TX start periodically
* checking stats
*/
- if (test_bit(NETDEV_LED_TX, &trigger_data->mode) ||
- test_bit(NETDEV_LED_RX, &trigger_data->mode))
+ if (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
schedule_delayed_work(&trigger_data->work, 0);
}
}
+static bool supports_hw_control(struct led_classdev *led_cdev)
+{
+ if (!led_cdev->hw_control_get || !led_cdev->hw_control_set ||
+ !led_cdev->hw_control_is_supported)
+ return false;
+
+ return !strcmp(led_cdev->hw_control_trigger, led_cdev->trigger->name);
+}
+
+/*
+ * Validate the configured netdev is the same as the one associated with
+ * the LED driver in hw control.
+ */
+static bool validate_net_dev(struct led_classdev *led_cdev,
+ struct net_device *net_dev)
+{
+ struct device *dev = led_cdev->hw_control_get_device(led_cdev);
+ struct net_device *ndev;
+
+ if (!dev)
+ return false;
+
+ ndev = to_net_dev(dev);
+
+ return ndev == net_dev;
+}
+
+static bool can_hw_control(struct led_netdev_data *trigger_data)
+{
+ unsigned long default_interval = msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL);
+ unsigned int interval = atomic_read(&trigger_data->interval);
+ struct led_classdev *led_cdev = trigger_data->led_cdev;
+ int ret;
+
+ if (!supports_hw_control(led_cdev))
+ return false;
+
+ /*
+ * Interval must be set to the default
+ * value. Any different value is rejected if in hw
+ * control.
+ */
+ if (interval != default_interval)
+ return false;
+
+ /*
+ * net_dev must be set with hw control, otherwise no
+ * blinking can be happening and there is nothing to
+ * offloaded. Additionally, for hw control to be
+ * valid, the configured netdev must be the same as
+ * netdev associated to the LED.
+ */
+ if (!validate_net_dev(led_cdev, trigger_data->net_dev))
+ return false;
+
+ /* Check if the requested mode is supported */
+ ret = led_cdev->hw_control_is_supported(led_cdev, trigger_data->mode);
+ /* Fall back to software blinking if not supported */
+ if (ret == -EOPNOTSUPP)
+ return false;
+ if (ret) {
+ dev_warn(led_cdev->dev,
+ "Current mode check failed with error %d\n", ret);
+ return false;
+ }
+
+ return true;
+}
+
+static void get_device_state(struct led_netdev_data *trigger_data)
+{
+ struct ethtool_link_ksettings cmd;
+
+ trigger_data->carrier_link_up = netif_carrier_ok(trigger_data->net_dev);
+ if (!trigger_data->carrier_link_up)
+ return;
+
+ if (!__ethtool_get_link_ksettings(trigger_data->net_dev, &cmd)) {
+ trigger_data->link_speed = cmd.base.speed;
+ trigger_data->duplex = cmd.base.duplex;
+ }
+}
+
static ssize_t device_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
ssize_t len;
- spin_lock_bh(&trigger_data->lock);
+ mutex_lock(&trigger_data->lock);
len = sprintf(buf, "%s\n", trigger_data->device_name);
- spin_unlock_bh(&trigger_data->lock);
+ mutex_unlock(&trigger_data->lock);
return len;
}
-static ssize_t device_name_store(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t size)
+static int set_device_name(struct led_netdev_data *trigger_data,
+ const char *name, size_t size)
{
- struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
-
if (size >= IFNAMSIZ)
return -EINVAL;
cancel_delayed_work_sync(&trigger_data->work);
- spin_lock_bh(&trigger_data->lock);
+ /*
+ * Take RTNL lock before trigger_data lock to prevent potential
+ * deadlock with netdev notifier registration.
+ */
+ rtnl_lock();
+ mutex_lock(&trigger_data->lock);
if (trigger_data->net_dev) {
dev_put(trigger_data->net_dev);
trigger_data->net_dev = NULL;
}
- memcpy(trigger_data->device_name, buf, size);
+ memcpy(trigger_data->device_name, name, size);
trigger_data->device_name[size] = 0;
if (size > 0 && trigger_data->device_name[size - 1] == '\n')
trigger_data->device_name[size - 1] = 0;
@@ -131,36 +258,56 @@ static ssize_t device_name_store(struct device *dev,
trigger_data->net_dev =
dev_get_by_name(&init_net, trigger_data->device_name);
- clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
- if (trigger_data->net_dev != NULL)
- if (netif_carrier_ok(trigger_data->net_dev))
- set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
+ trigger_data->carrier_link_up = false;
+ trigger_data->link_speed = SPEED_UNKNOWN;
+ trigger_data->duplex = DUPLEX_UNKNOWN;
+ if (trigger_data->net_dev)
+ get_device_state(trigger_data);
trigger_data->last_activity = 0;
set_baseline_state(trigger_data);
- spin_unlock_bh(&trigger_data->lock);
+ mutex_unlock(&trigger_data->lock);
+ rtnl_unlock();
+
+ return 0;
+}
+
+static ssize_t device_name_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t size)
+{
+ struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
+ int ret;
+
+ ret = set_device_name(trigger_data, buf, size);
+ if (ret < 0)
+ return ret;
return size;
}
static DEVICE_ATTR_RW(device_name);
static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
- enum netdev_led_attr attr)
+ enum led_trigger_netdev_modes attr)
{
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
int bit;
switch (attr) {
- case NETDEV_ATTR_LINK:
- bit = NETDEV_LED_LINK;
- break;
- case NETDEV_ATTR_TX:
- bit = NETDEV_LED_TX;
- break;
- case NETDEV_ATTR_RX:
- bit = NETDEV_LED_RX;
+ case TRIGGER_NETDEV_LINK:
+ case TRIGGER_NETDEV_LINK_10:
+ case TRIGGER_NETDEV_LINK_100:
+ case TRIGGER_NETDEV_LINK_1000:
+ case TRIGGER_NETDEV_LINK_2500:
+ case TRIGGER_NETDEV_LINK_5000:
+ case TRIGGER_NETDEV_LINK_10000:
+ case TRIGGER_NETDEV_HALF_DUPLEX:
+ case TRIGGER_NETDEV_FULL_DUPLEX:
+ case TRIGGER_NETDEV_TX:
+ case TRIGGER_NETDEV_RX:
+ bit = attr;
break;
default:
return -EINVAL;
@@ -170,10 +317,10 @@ static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
}
static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
- size_t size, enum netdev_led_attr attr)
+ size_t size, enum led_trigger_netdev_modes attr)
{
struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
- unsigned long state;
+ unsigned long state, mode = trigger_data->mode;
int ret;
int bit;
@@ -182,72 +329,71 @@ static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
return ret;
switch (attr) {
- case NETDEV_ATTR_LINK:
- bit = NETDEV_LED_LINK;
- break;
- case NETDEV_ATTR_TX:
- bit = NETDEV_LED_TX;
- break;
- case NETDEV_ATTR_RX:
- bit = NETDEV_LED_RX;
+ case TRIGGER_NETDEV_LINK:
+ case TRIGGER_NETDEV_LINK_10:
+ case TRIGGER_NETDEV_LINK_100:
+ case TRIGGER_NETDEV_LINK_1000:
+ case TRIGGER_NETDEV_LINK_2500:
+ case TRIGGER_NETDEV_LINK_5000:
+ case TRIGGER_NETDEV_LINK_10000:
+ case TRIGGER_NETDEV_HALF_DUPLEX:
+ case TRIGGER_NETDEV_FULL_DUPLEX:
+ case TRIGGER_NETDEV_TX:
+ case TRIGGER_NETDEV_RX:
+ bit = attr;
break;
default:
return -EINVAL;
}
- cancel_delayed_work_sync(&trigger_data->work);
-
if (state)
- set_bit(bit, &trigger_data->mode);
+ set_bit(bit, &mode);
else
- clear_bit(bit, &trigger_data->mode);
-
- set_baseline_state(trigger_data);
-
- return size;
-}
-
-static ssize_t link_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK);
-}
-
-static ssize_t link_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK);
-}
-
-static DEVICE_ATTR_RW(link);
-
-static ssize_t tx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX);
-}
+ clear_bit(bit, &mode);
+
+ if (test_bit(TRIGGER_NETDEV_LINK, &mode) &&
+ (test_bit(TRIGGER_NETDEV_LINK_10, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_100, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_2500, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_5000, &mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_10000, &mode)))
+ return -EINVAL;
-static ssize_t tx_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX);
-}
+ cancel_delayed_work_sync(&trigger_data->work);
-static DEVICE_ATTR_RW(tx);
+ trigger_data->mode = mode;
+ trigger_data->hw_control = can_hw_control(trigger_data);
-static ssize_t rx_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX);
-}
+ set_baseline_state(trigger_data);
-static ssize_t rx_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX);
+ return size;
}
-static DEVICE_ATTR_RW(rx);
+#define DEFINE_NETDEV_TRIGGER(trigger_name, trigger) \
+ static ssize_t trigger_name##_show(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
+ { \
+ return netdev_led_attr_show(dev, buf, trigger); \
+ } \
+ static ssize_t trigger_name##_store(struct device *dev, \
+ struct device_attribute *attr, const char *buf, size_t size) \
+ { \
+ return netdev_led_attr_store(dev, buf, size, trigger); \
+ } \
+ static DEVICE_ATTR_RW(trigger_name)
+
+DEFINE_NETDEV_TRIGGER(link, TRIGGER_NETDEV_LINK);
+DEFINE_NETDEV_TRIGGER(link_10, TRIGGER_NETDEV_LINK_10);
+DEFINE_NETDEV_TRIGGER(link_100, TRIGGER_NETDEV_LINK_100);
+DEFINE_NETDEV_TRIGGER(link_1000, TRIGGER_NETDEV_LINK_1000);
+DEFINE_NETDEV_TRIGGER(link_2500, TRIGGER_NETDEV_LINK_2500);
+DEFINE_NETDEV_TRIGGER(link_5000, TRIGGER_NETDEV_LINK_5000);
+DEFINE_NETDEV_TRIGGER(link_10000, TRIGGER_NETDEV_LINK_10000);
+DEFINE_NETDEV_TRIGGER(half_duplex, TRIGGER_NETDEV_HALF_DUPLEX);
+DEFINE_NETDEV_TRIGGER(full_duplex, TRIGGER_NETDEV_FULL_DUPLEX);
+DEFINE_NETDEV_TRIGGER(tx, TRIGGER_NETDEV_TX);
+DEFINE_NETDEV_TRIGGER(rx, TRIGGER_NETDEV_RX);
static ssize_t interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -266,6 +412,9 @@ static ssize_t interval_store(struct device *dev,
unsigned long value;
int ret;
+ if (trigger_data->hw_control)
+ return -EINVAL;
+
ret = kstrtoul(buf, 0, &value);
if (ret)
return ret;
@@ -283,12 +432,31 @@ static ssize_t interval_store(struct device *dev,
static DEVICE_ATTR_RW(interval);
+static ssize_t offloaded_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_netdev_data *trigger_data = led_trigger_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", trigger_data->hw_control);
+}
+
+static DEVICE_ATTR_RO(offloaded);
+
static struct attribute *netdev_trig_attrs[] = {
&dev_attr_device_name.attr,
&dev_attr_link.attr,
+ &dev_attr_link_10.attr,
+ &dev_attr_link_100.attr,
+ &dev_attr_link_1000.attr,
+ &dev_attr_link_2500.attr,
+ &dev_attr_link_5000.attr,
+ &dev_attr_link_10000.attr,
+ &dev_attr_full_duplex.attr,
+ &dev_attr_half_duplex.attr,
&dev_attr_rx.attr,
&dev_attr_tx.attr,
&dev_attr_interval.attr,
+ &dev_attr_offloaded.attr,
NULL
};
ATTRIBUTE_GROUPS(netdev_trig);
@@ -313,19 +481,19 @@ static int netdev_trig_notify(struct notifier_block *nb,
cancel_delayed_work_sync(&trigger_data->work);
- spin_lock_bh(&trigger_data->lock);
+ mutex_lock(&trigger_data->lock);
- clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
+ trigger_data->carrier_link_up = false;
+ trigger_data->link_speed = SPEED_UNKNOWN;
+ trigger_data->duplex = DUPLEX_UNKNOWN;
switch (evt) {
case NETDEV_CHANGENAME:
- if (netif_carrier_ok(dev))
- set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
- fallthrough;
case NETDEV_REGISTER:
- if (trigger_data->net_dev)
- dev_put(trigger_data->net_dev);
+ dev_put(trigger_data->net_dev);
dev_hold(dev);
trigger_data->net_dev = dev;
+ if (evt == NETDEV_CHANGENAME)
+ get_device_state(trigger_data);
break;
case NETDEV_UNREGISTER:
dev_put(trigger_data->net_dev);
@@ -333,14 +501,13 @@ static int netdev_trig_notify(struct notifier_block *nb,
break;
case NETDEV_UP:
case NETDEV_CHANGE:
- if (netif_carrier_ok(dev))
- set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
+ get_device_state(trigger_data);
break;
}
set_baseline_state(trigger_data);
- spin_unlock_bh(&trigger_data->lock);
+ mutex_unlock(&trigger_data->lock);
return NOTIFY_DONE;
}
@@ -363,21 +530,29 @@ static void netdev_trig_work(struct work_struct *work)
}
/* If we are not looking for RX/TX then return */
- if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) &&
- !test_bit(NETDEV_LED_RX, &trigger_data->mode))
+ if (!test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) &&
+ !test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode))
return;
dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
new_activity =
- (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
+ (test_bit(TRIGGER_NETDEV_TX, &trigger_data->mode) ?
dev_stats->tx_packets : 0) +
- (test_bit(NETDEV_LED_RX, &trigger_data->mode) ?
+ (test_bit(TRIGGER_NETDEV_RX, &trigger_data->mode) ?
dev_stats->rx_packets : 0);
if (trigger_data->last_activity != new_activity) {
led_stop_software_blink(trigger_data->led_cdev);
- invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode);
+ invert = test_bit(TRIGGER_NETDEV_LINK, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_10, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_100, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_1000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_2500, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_5000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_LINK_10000, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &trigger_data->mode) ||
+ test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &trigger_data->mode);
interval = jiffies_to_msecs(
atomic_read(&trigger_data->interval));
/* base state is ON (link present) */
@@ -395,13 +570,15 @@ static void netdev_trig_work(struct work_struct *work)
static int netdev_trig_activate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data;
+ unsigned long mode = 0;
+ struct device *dev;
int rc;
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
if (!trigger_data)
return -ENOMEM;
- spin_lock_init(&trigger_data->lock);
+ mutex_init(&trigger_data->lock);
trigger_data->notifier.notifier_call = netdev_trig_notify;
trigger_data->notifier.priority = 10;
@@ -413,9 +590,26 @@ static int netdev_trig_activate(struct led_classdev *led_cdev)
trigger_data->device_name[0] = 0;
trigger_data->mode = 0;
- atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
+ atomic_set(&trigger_data->interval, msecs_to_jiffies(NETDEV_LED_DEFAULT_INTERVAL));
trigger_data->last_activity = 0;
+ /* Check if hw control is active by default on the LED.
+ * Init already enabled mode in hw control.
+ */
+ if (supports_hw_control(led_cdev)) {
+ dev = led_cdev->hw_control_get_device(led_cdev);
+ if (dev) {
+ const char *name = dev_name(dev);
+
+ set_device_name(trigger_data, name, strlen(name));
+ trigger_data->hw_control = true;
+
+ rc = led_cdev->hw_control_get(led_cdev, &mode);
+ if (!rc)
+ trigger_data->mode = mode;
+ }
+ }
+
led_set_trigger_data(led_cdev, trigger_data);
rc = register_netdevice_notifier(&trigger_data->notifier);
@@ -433,8 +627,9 @@ static void netdev_trig_deactivate(struct led_classdev *led_cdev)
cancel_delayed_work_sync(&trigger_data->work);
- if (trigger_data->net_dev)
- dev_put(trigger_data->net_dev);
+ led_set_brightness(led_cdev, LED_OFF);
+
+ dev_put(trigger_data->net_dev);
kfree(trigger_data);
}
--
2.45.2

View File

@@ -109,109 +109,82 @@
return err;
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.c
@@ -506,6 +506,404 @@ int mtk_pinconf_bias_get_rev1(struct mtk
return 0;
@@ -6,7 +6,6 @@
*
*/
-#include <dt-bindings/pinctrl/mt65xx.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
@@ -67,44 +66,34 @@ static int mtk_hw_pin_field_lookup(struc
const struct mtk_pin_desc *desc,
int field, struct mtk_pin_field *pfd)
{
- const struct mtk_pin_field_calc *c;
+ const struct mtk_pin_field_calc *c, *e;
const struct mtk_pin_reg_calc *rc;
- int start = 0, end, check;
- bool found = false;
u32 bits;
if (hw->soc->reg_cal && hw->soc->reg_cal[field].range) {
rc = &hw->soc->reg_cal[field];
} else {
dev_dbg(hw->dev,
- "Not support field %d for this soc\n", field);
+ "Not support field %d for pin %d (%s)\n",
+ field, desc->number, desc->name);
return -ENOTSUPP;
}
- end = rc->nranges - 1;
+ c = rc->range;
+ e = c + rc->nranges;
- while (start <= end) {
- check = (start + end) >> 1;
- if (desc->number >= rc->range[check].s_pin
- && desc->number <= rc->range[check].e_pin) {
- found = true;
- break;
- } else if (start == end)
+ while (c < e) {
+ if (desc->number >= c->s_pin && desc->number <= c->e_pin)
break;
- else if (desc->number < rc->range[check].s_pin)
- end = check - 1;
- else
- start = check + 1;
+ c++;
}
- if (!found) {
+ if (c >= e) {
dev_dbg(hw->dev, "Not support field %d for pin = %d (%s)\n",
field, desc->number, desc->name);
return -ENOTSUPP;
}
- c = rc->range + check;
-
if (c->i_base > hw->nbase - 1) {
dev_err(hw->dev,
"Invalid base for field %d for pin = %d (%s)\n",
@@ -193,9 +182,6 @@ int mtk_hw_set_value(struct mtk_pinctrl
if (err)
return err;
- if (value < 0 || value > pf.mask)
- return -EINVAL;
-
if (!pf.next)
mtk_rmw(hw, pf.index, pf.offset, pf.mask << pf.bitpos,
(value & pf.mask) << pf.bitpos);
@@ -619,6 +605,186 @@ out:
return err;
}
+/* Combo for the following pull register type:
+ * 1. PU + PD
+ * 2. PULLSEL + PULLEN
+ * 3. PUPD + R0 + R1
+ */
+static int mtk_pinconf_bias_set_pu_pd(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 pullup, u32 arg)
+{
+ int err, pu, pd;
+
+ if (arg == MTK_DISABLE) {
+ pu = 0;
+ pd = 0;
+ } else if ((arg == MTK_ENABLE) && pullup) {
+ pu = 1;
+ pd = 0;
+ } else if ((arg == MTK_ENABLE) && !pullup) {
+ pu = 0;
+ pd = 1;
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PU, pu);
+ if (err)
+ goto out;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PD, pd);
+
+out:
+ return err;
+}
+
+static int mtk_pinconf_bias_set_pullsel_pullen(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 pullup, u32 arg)
+{
+ int err, enable;
+
+ if (arg == MTK_DISABLE)
+ enable = 0;
+ else if (arg == MTK_ENABLE)
+ enable = 1;
+ else {
+ err = -EINVAL;
+ goto out;
+ }
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable);
+ if (err)
+ goto out;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup);
+
+out:
+ return err;
+}
+
+static int mtk_pinconf_bias_set_pupd_r1_r0(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 pullup, u32 arg)
+{
+ int err, r0, r1;
+
+ if ((arg == MTK_DISABLE) || (arg == MTK_PUPD_SET_R1R0_00)) {
+ pullup = 0;
+ r0 = 0;
+ r1 = 0;
+ } else if (arg == MTK_PUPD_SET_R1R0_01) {
+ r0 = 1;
+ r1 = 0;
+ } else if (arg == MTK_PUPD_SET_R1R0_10) {
+ r0 = 0;
+ r1 = 1;
+ } else if (arg == MTK_PUPD_SET_R1R0_11) {
+ r0 = 1;
+ r1 = 1;
+ } else {
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_PUPD, !pullup);
+ if (err)
+ goto out;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R0, r0);
+ if (err)
+ goto out;
+
+ err = mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_R1, r1);
+
+out:
+ return err;
+}
+
+static int mtk_hw_pin_rsel_lookup(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 pullup, u32 arg, u32 *rsel_val)
@@ -392,105 +365,59 @@
+ return err;
+}
+
+static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 *pullup, u32 *enable)
+{
+ int err, pu, pd;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PU, &pu);
+ if (err)
+ goto out;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PD, &pd);
+ if (err)
+ goto out;
+
+ if (pu == 0 && pd == 0) {
+ *pullup = 0;
+ *enable = MTK_DISABLE;
+ } else if (pu == 1 && pd == 0) {
+ *pullup = 1;
+ *enable = MTK_ENABLE;
+ } else if (pu == 0 && pd == 1) {
+ *pullup = 0;
+ *enable = MTK_ENABLE;
+ } else
+ err = -EINVAL;
+
+out:
+ return err;
+}
+
+static int mtk_pinconf_bias_get_pullsel_pullen(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 *pullup, u32 *enable)
+{
+ int err;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLSEL, pullup);
+ if (err)
+ goto out;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PULLEN, enable);
+
+out:
+ return err;
+}
+
+static int mtk_pinconf_bias_get_pupd_r1_r0(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 *pullup, u32 *enable)
+{
+ int err, r0, r1;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_PUPD, pullup);
+ if (err)
+ goto out;
+ /* MTK HW PUPD bit: 1 for pull-down, 0 for pull-up */
+ *pullup = !(*pullup);
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R0, &r0);
+ if (err)
+ goto out;
+
+ err = mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_R1, &r1);
+ if (err)
+ goto out;
+
+ if ((r1 == 0) && (r0 == 0))
+ *enable = MTK_PUPD_SET_R1R0_00;
+ else if ((r1 == 0) && (r0 == 1))
+ *enable = MTK_PUPD_SET_R1R0_01;
+ else if ((r1 == 1) && (r0 == 0))
+ *enable = MTK_PUPD_SET_R1R0_10;
+ else if ((r1 == 1) && (r0 == 1))
+ *enable = MTK_PUPD_SET_R1R0_11;
+ else
+ err = -EINVAL;
+
+out:
+ return err;
+}
+
+int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,
+ const struct mtk_pin_desc *desc,
+ u32 *pullup, u32 *enable)
+{
static int mtk_pinconf_bias_get_pu_pd(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc,
u32 *pullup, u32 *enable)
@@ -700,45 +866,43 @@ out:
return err;
}
-int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc,
- u32 pullup, u32 arg)
-{
- int err;
-
- err = mtk_pinconf_bias_set_pu_pd(hw, desc, pullup, arg);
- if (!err)
- goto out;
-
- err = mtk_pinconf_bias_set_pullsel_pullen(hw, desc, pullup, arg);
- if (!err)
- goto out;
-
- err = mtk_pinconf_bias_set_pupd_r1_r0(hw, desc, pullup, arg);
-
-out:
- return err;
-}
-
int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc,
u32 *pullup, u32 *enable)
{
- int err;
+ int err = -ENOTSUPP;
+ u32 try_all_type;
+
- err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);
- if (!err)
- goto out;
+ if (hw->soc->pull_type)
+ try_all_type = hw->soc->pull_type[desc->number];
+ else
+ try_all_type = MTK_PULL_TYPE_MASK;
+
- err = mtk_pinconf_bias_get_pullsel_pullen(hw, desc, pullup, enable);
- if (!err)
- goto out;
+ if (try_all_type & MTK_PULL_RSEL_TYPE) {
+ err = mtk_pinconf_bias_get_rsel(hw, desc, pullup, enable);
+ if (!err)
+ return err;
+ }
+
- err = mtk_pinconf_bias_get_pupd_r1_r0(hw, desc, pullup, enable);
+ if (try_all_type & MTK_PULL_PU_PD_TYPE) {
+ err = mtk_pinconf_bias_get_pu_pd(hw, desc, pullup, enable);
+ if (!err)
@@ -506,14 +433,44 @@
+
+ if (try_all_type & MTK_PULL_PUPD_R1R0_TYPE)
+ err = mtk_pinconf_bias_get_pupd_r1_r0(hw, desc, pullup, enable);
+
+ return err;
+}
-out:
return err;
}
+EXPORT_SYMBOL_GPL(mtk_pinconf_bias_get_combo);
+
/* Revision 0 */
int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, u32 arg)
@@ -831,18 +995,6 @@ int mtk_pinconf_drive_get_rev1(struct mt
return 0;
}
-int mtk_pinconf_drive_set_raw(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc, u32 arg)
-{
- return mtk_hw_set_value(hw, desc, PINCTRL_PIN_REG_DRV, arg);
-}
-
-int mtk_pinconf_drive_get_raw(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc, int *val)
-{
- return mtk_hw_get_value(hw, desc, PINCTRL_PIN_REG_DRV, val);
-}
-
int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, bool pullup,
u32 arg)
@@ -876,9 +1028,7 @@ int mtk_pinconf_adv_pull_set(struct mtk_
if (err)
return err;
} else {
- err = mtk_pinconf_bias_set_rev1(hw, desc, pullup);
- if (err)
- err = mtk_pinconf_bias_set(hw, desc, pullup);
+ return -ENOTSUPP;
}
}
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common-v2.h
@@ -17,6 +17,34 @@
@@ -593,19 +550,22 @@
/* Specific pinconfig operations */
int (*bias_disable_set)(struct mtk_pinctrl *hw,
@@ -215,7 +264,10 @@ struct mtk_pin_soc {
@@ -215,12 +264,10 @@ struct mtk_pin_soc {
const struct mtk_pin_desc *desc, bool pullup);
int (*bias_get)(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, bool pullup, int *res);
-
+ int (*bias_set_combo)(struct mtk_pinctrl *hw,
int (*bias_set_combo)(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc, u32 pullup, u32 arg);
+ const struct mtk_pin_desc *desc, u32 pullup, u32 arg);
+ int (*bias_get_combo)(struct mtk_pinctrl *hw,
int (*bias_get_combo)(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc, u32 *pullup, u32 *arg);
-
+ const struct mtk_pin_desc *desc, u32 *pullup, u32 *arg);
int (*drive_set)(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, u32 arg);
int (*drive_get)(struct mtk_pinctrl *hw,
@@ -246,6 +298,10 @@ struct mtk_pinctrl {
@@ -251,6 +298,10 @@ struct mtk_pinctrl {
struct mtk_eint *eint;
struct mtk_pinctrl_group *groups;
const char **grp_names;
@@ -616,7 +576,18 @@
};
void mtk_rmw(struct mtk_pinctrl *pctl, u8 i, u32 reg, u32 mask, u32 set);
@@ -282,7 +338,12 @@ int mtk_pinconf_drive_set(struct mtk_pin
@@ -282,28 +333,22 @@ int mtk_pinconf_bias_set_rev1(struct mtk
int mtk_pinconf_bias_get_rev1(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, bool pullup,
int *res);
-int mtk_pinconf_bias_set_combo(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc,
- u32 pullup, u32 enable);
-int mtk_pinconf_bias_get_combo(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc,
- u32 *pullup, u32 *enable);
int mtk_pinconf_drive_set(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, u32 arg);
int mtk_pinconf_drive_get(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, int *val);
@@ -630,3 +601,13 @@
int mtk_pinconf_drive_set_rev1(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, u32 arg);
int mtk_pinconf_drive_get_rev1(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, int *val);
-int mtk_pinconf_drive_set_raw(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc, u32 arg);
-int mtk_pinconf_drive_get_raw(struct mtk_pinctrl *hw,
- const struct mtk_pin_desc *desc, int *val);
-
int mtk_pinconf_adv_pull_set(struct mtk_pinctrl *hw,
const struct mtk_pin_desc *desc, bool pullup,
u32 arg);

View File

@@ -0,0 +1,347 @@
--- a/drivers/soc/mediatek/Kconfig
+++ b/drivers/soc/mediatek/Kconfig
@@ -17,6 +17,15 @@ config MTK_CMDQ
time limitation, such as updating display configuration during the
vblank.
+config MTK_DEVAPC
+ tristate "Mediatek Device APC Support"
+ help
+ Say yes here to enable support for Mediatek Device APC driver.
+ This driver is mainly used to handle the violation which catches
+ unexpected transaction.
+ The violation information is logged for further analysis or
+ countermeasures.
+
config MTK_INFRACFG
bool "MediaTek INFRACFG Support"
select REGMAP
--- a/drivers/soc/mediatek/Makefile
+++ b/drivers/soc/mediatek/Makefile
@@ -1,5 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_MTK_CMDQ) += mtk-cmdq-helper.o
+obj-$(CONFIG_MTK_DEVAPC) += mtk-devapc.o
obj-$(CONFIG_MTK_INFRACFG) += mtk-infracfg.o
obj-$(CONFIG_MTK_PMIC_WRAP) += mtk-pmic-wrap.o
obj-$(CONFIG_MTK_SCPSYS) += mtk-scpsys.o
--- /dev/null
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -0,0 +1,317 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2020 MediaTek Inc.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/iopoll.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+
+#define VIO_MOD_TO_REG_IND(m) ((m) / 32)
+#define VIO_MOD_TO_REG_OFF(m) ((m) % 32)
+
+struct mtk_devapc_vio_dbgs {
+ union {
+ u32 vio_dbg0;
+ struct {
+ u32 mstid:16;
+ u32 dmnid:6;
+ u32 vio_w:1;
+ u32 vio_r:1;
+ u32 addr_h:4;
+ u32 resv:4;
+ } dbg0_bits;
+ };
+
+ u32 vio_dbg1;
+};
+
+struct mtk_devapc_regs_ofs {
+ /* reg offset */
+ u32 vio_mask_offset;
+ u32 vio_sta_offset;
+ u32 vio_dbg0_offset;
+ u32 vio_dbg1_offset;
+ u32 apc_con_offset;
+ u32 vio_shift_sta_offset;
+ u32 vio_shift_sel_offset;
+ u32 vio_shift_con_offset;
+};
+
+struct mtk_devapc_data {
+ /* numbers of violation index */
+ u32 vio_idx_num;
+ const struct mtk_devapc_regs_ofs *regs_ofs;
+};
+
+struct mtk_devapc_context {
+ struct device *dev;
+ void __iomem *infra_base;
+ struct clk *infra_clk;
+ const struct mtk_devapc_data *data;
+};
+
+static void clear_vio_status(struct mtk_devapc_context *ctx)
+{
+ void __iomem *reg;
+ int i;
+
+ reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
+
+ for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+ writel(GENMASK(31, 0), reg + 4 * i);
+
+ writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
+ reg + 4 * i);
+}
+
+static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
+{
+ void __iomem *reg;
+ u32 val;
+ int i;
+
+ reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
+
+ if (mask)
+ val = GENMASK(31, 0);
+ else
+ val = 0;
+
+ for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
+ writel(val, reg + 4 * i);
+
+ val = readl(reg + 4 * i);
+ if (mask)
+ val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+ 0);
+ else
+ val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
+ 0);
+
+ writel(val, reg + 4 * i);
+}
+
+#define PHY_DEVAPC_TIMEOUT 0x10000
+
+/*
+ * devapc_sync_vio_dbg - do "shift" mechansim" to get full violation information.
+ * shift mechanism is depends on devapc hardware design.
+ * Mediatek devapc set multiple slaves as a group.
+ * When violation is triggered, violation info is kept
+ * inside devapc hardware.
+ * Driver should do shift mechansim to sync full violation
+ * info to VIO_DBGs registers.
+ *
+ */
+static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
+{
+ void __iomem *pd_vio_shift_sta_reg;
+ void __iomem *pd_vio_shift_sel_reg;
+ void __iomem *pd_vio_shift_con_reg;
+ int min_shift_group;
+ int ret;
+ u32 val;
+
+ pd_vio_shift_sta_reg = ctx->infra_base +
+ ctx->data->regs_ofs->vio_shift_sta_offset;
+ pd_vio_shift_sel_reg = ctx->infra_base +
+ ctx->data->regs_ofs->vio_shift_sel_offset;
+ pd_vio_shift_con_reg = ctx->infra_base +
+ ctx->data->regs_ofs->vio_shift_con_offset;
+
+ /* Find the minimum shift group which has violation */
+ val = readl(pd_vio_shift_sta_reg);
+ if (!val)
+ return false;
+
+ min_shift_group = __ffs(val);
+
+ /* Assign the group to sync */
+ writel(0x1 << min_shift_group, pd_vio_shift_sel_reg);
+
+ /* Start syncing */
+ writel(0x1, pd_vio_shift_con_reg);
+
+ ret = readl_poll_timeout(pd_vio_shift_con_reg, val, val == 0x3, 0,
+ PHY_DEVAPC_TIMEOUT);
+ if (ret) {
+ dev_err(ctx->dev, "%s: Shift violation info failed\n", __func__);
+ return false;
+ }
+
+ /* Stop syncing */
+ writel(0x0, pd_vio_shift_con_reg);
+
+ /* Write clear */
+ writel(0x1 << min_shift_group, pd_vio_shift_sta_reg);
+
+ return true;
+}
+
+/*
+ * devapc_extract_vio_dbg - extract full violation information after doing
+ * shift mechanism.
+ */
+static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
+{
+ struct mtk_devapc_vio_dbgs vio_dbgs;
+ void __iomem *vio_dbg0_reg;
+ void __iomem *vio_dbg1_reg;
+
+ vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
+ vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
+
+ vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
+ vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
+
+ /* Print violation information */
+ if (vio_dbgs.dbg0_bits.vio_w)
+ dev_info(ctx->dev, "Write Violation\n");
+ else if (vio_dbgs.dbg0_bits.vio_r)
+ dev_info(ctx->dev, "Read Violation\n");
+
+ dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
+ vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
+ vio_dbgs.vio_dbg1);
+}
+
+/*
+ * devapc_violation_irq - the devapc Interrupt Service Routine (ISR) will dump
+ * violation information including which master violates
+ * access slave.
+ */
+static irqreturn_t devapc_violation_irq(int irq_number, void *data)
+{
+ struct mtk_devapc_context *ctx = data;
+
+ while (devapc_sync_vio_dbg(ctx))
+ devapc_extract_vio_dbg(ctx);
+
+ clear_vio_status(ctx);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * start_devapc - unmask slave's irq to start receiving devapc violation.
+ */
+static void start_devapc(struct mtk_devapc_context *ctx)
+{
+ writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+
+ mask_module_irq(ctx, false);
+}
+
+/*
+ * stop_devapc - mask slave's irq to stop service.
+ */
+static void stop_devapc(struct mtk_devapc_context *ctx)
+{
+ mask_module_irq(ctx, true);
+
+ writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
+}
+
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
+ .vio_mask_offset = 0x0,
+ .vio_sta_offset = 0x400,
+ .vio_dbg0_offset = 0x900,
+ .vio_dbg1_offset = 0x904,
+ .apc_con_offset = 0xF00,
+ .vio_shift_sta_offset = 0xF10,
+ .vio_shift_sel_offset = 0xF14,
+ .vio_shift_con_offset = 0xF20,
+};
+
+static const struct mtk_devapc_data devapc_mt6779 = {
+ .vio_idx_num = 511,
+ .regs_ofs = &devapc_regs_ofs_mt6779,
+};
+
+static const struct mtk_devapc_data devapc_mt8186 = {
+ .vio_idx_num = 519,
+ .regs_ofs = &devapc_regs_ofs_mt6779,
+};
+
+static const struct of_device_id mtk_devapc_dt_match[] = {
+ {
+ .compatible = "mediatek,mt6779-devapc",
+ .data = &devapc_mt6779,
+ }, {
+ .compatible = "mediatek,mt8186-devapc",
+ .data = &devapc_mt8186,
+ }, {
+ },
+};
+MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
+
+static int mtk_devapc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct mtk_devapc_context *ctx;
+ u32 devapc_irq;
+ int ret;
+
+ if (IS_ERR(node))
+ return -ENODEV;
+
+ ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->data = of_device_get_match_data(&pdev->dev);
+ ctx->dev = &pdev->dev;
+
+ ctx->infra_base = of_iomap(node, 0);
+ if (!ctx->infra_base)
+ return -EINVAL;
+
+ devapc_irq = irq_of_parse_and_map(node, 0);
+ if (!devapc_irq)
+ return -EINVAL;
+
+ ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
+ if (IS_ERR(ctx->infra_clk))
+ return -EINVAL;
+
+ ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
+ IRQF_TRIGGER_NONE, "devapc", ctx);
+ if (ret)
+ return ret;
+
+ platform_set_drvdata(pdev, ctx);
+
+ start_devapc(ctx);
+
+ return 0;
+}
+
+static int mtk_devapc_remove(struct platform_device *pdev)
+{
+ struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
+
+ stop_devapc(ctx);
+
+ return 0;
+}
+
+static struct platform_driver mtk_devapc_driver = {
+ .probe = mtk_devapc_probe,
+ .remove = mtk_devapc_remove,
+ .driver = {
+ .name = "mtk-devapc",
+ .of_match_table = mtk_devapc_dt_match,
+ },
+};
+
+module_platform_driver(mtk_devapc_driver);
+
+MODULE_DESCRIPTION("Mediatek Device APC Driver");
+MODULE_AUTHOR("Neal Liu <neal.liu@mediatek.com>");
+MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,33 @@
diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig
index cf3a53e..be40a84 100644
--- a/drivers/clk/mediatek/Kconfig
+++ b/drivers/clk/mediatek/Kconfig
@@ -275,6 +275,14 @@ config COMMON_CLK_MT7981
This driver supports MediaTek MT7981 basic clocks and clocks
required for various periperals found on MediaTek.
+config COMMON_CLK_MT7987
+ bool "Clock driver for MediaTek MT7987"
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ select COMMON_CLK_MEDIATEK
+ ---help---
+ This driver supports MediaTek MT7987 basic clocks and clocks
+ required for various periperals found on MediaTek.
+
config COMMON_CLK_MT7988
bool "Clock driver for MediaTek MT7988"
depends on ARCH_MEDIATEK || COMPILE_TEST
--- a/drivers/clk/mediatek/Makefile
+++ b/drivers/clk/mediatek/Makefile
@@ -41,6 +41,11 @@ obj-$(CONFIG_COMMON_CLK_MT7629_ETHSYS) += clk-mt7629-eth.o
obj-$(CONFIG_COMMON_CLK_MT7629_HIFSYS) += clk-mt7629-hif.o
obj-$(CONFIG_COMMON_CLK_MT7986) += clk-mt7986.o
obj-$(CONFIG_COMMON_CLK_MT7981) += clk-mt7981.o
+obj-$(CONFIG_COMMON_CLK_MT7987) += clk-mt7987-apmixed.o
+obj-$(CONFIG_COMMON_CLK_MT7987) += clk-mt7987-topckgen.o
+obj-$(CONFIG_COMMON_CLK_MT7987) += clk-mt7987-infracfg.o
+obj-$(CONFIG_COMMON_CLK_MT7987) += clk-mt7987-mcusys.o
+obj-$(CONFIG_COMMON_CLK_MT7987) += clk-mt7987-eth.o
obj-$(CONFIG_COMMON_CLK_MT7988) += clk-mt7988.o
obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o
obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o

View File

@@ -0,0 +1,26 @@
--- a/drivers/pinctrl/mediatek/Kconfig
+++ b/drivers/pinctrl/mediatek/Kconfig
@@ -112,6 +112,13 @@ config PINCTRL_MT7986
default ARM64 && ARCH_MEDIATEK
select PINCTRL_MTK_MOORE
+config PINCTRL_MT7987
+ bool "Mediatek MT7987 pin control"
+ depends on OF
+ depends on ARM64 || COMPILE_TEST
+ default ARM64 && ARCH_MEDIATEK
+ select PINCTRL_MTK_MOORE
+
config PINCTRL_MT7988
bool "Mediatek MT7988 pin control"
depends on OF
--- a/drivers/pinctrl/mediatek/Makefile
+++ b/drivers/pinctrl/mediatek/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_MT7623) += pinctrl-
obj-$(CONFIG_PINCTRL_MT7629) += pinctrl-mt7629.o
obj-$(CONFIG_PINCTRL_MT7981) += pinctrl-mt7981.o
obj-$(CONFIG_PINCTRL_MT7986) += pinctrl-mt7986.o
+obj-$(CONFIG_PINCTRL_MT7987) += pinctrl-mt7987.o
obj-$(CONFIG_PINCTRL_MT7988) += pinctrl-mt7988.o
obj-$(CONFIG_PINCTRL_MT8173) += pinctrl-mt8173.o
obj-$(CONFIG_PINCTRL_MT8183) += pinctrl-mt8183.o

View File

@@ -164,7 +164,7 @@ index a8bd06da7..75fca4cef 100644
+};
+
+static const struct mtk_rng_of_data mt7986_rng_data = {
+ .rng_version = 1,
+ .rng_version = 2,
+};
+
+static const struct mtk_rng_of_data mt7623_rng_data = {

View File

@@ -10,11 +10,9 @@ Subject: [PATCH]
drivers/char/tpm/tpm_tis_spi.c | 7 +++++++
3 files changed, 28 insertions(+)
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 70f785994..b9898a56d 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -817,6 +817,21 @@ static const struct tpm_class_ops tpm_tis = {
@@ -823,6 +823,21 @@ static const struct tpm_class_ops tpm_ti
.clk_enable = tpm_tis_clkrun_enable,
};
@@ -36,19 +34,19 @@ index 70f785994..b9898a56d 100644
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
const struct tpm_tis_phy_ops *phy_ops,
acpi_handle acpi_dev_handle)
@@ -864,6 +879,10 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
@@ -870,6 +885,12 @@ int tpm_tis_core_init(struct device *dev
if (chip->ops->clk_enable != NULL)
chip->ops->clk_enable(chip, true);
+ rc = priv->phy_ops->do_calibration(priv, dev);
+ if (rc)
+ goto out_err;
+ if (phy_ops->do_calibration) {
+ rc = priv->phy_ops->do_calibration(priv, dev);
+ if (rc)
+ goto out_err;
+ }
+
if (wait_startup(chip, 0) != 0) {
rc = -ENODEV;
goto out_err;
diff --git a/drivers/char/tpm/tpm_tis_core.h b/drivers/char/tpm/tpm_tis_core.h
index 7337819f5..7bb0bc8b6 100644
--- a/drivers/char/tpm/tpm_tis_core.h
+++ b/drivers/char/tpm/tpm_tis_core.h
@@ -106,6 +106,7 @@ struct tpm_tis_phy_ops {
@@ -67,11 +65,9 @@ index 7337819f5..7bb0bc8b6 100644
int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
const struct tpm_tis_phy_ops *phy_ops,
acpi_handle acpi_dev_handle);
diff --git a/drivers/char/tpm/tpm_tis_spi.c b/drivers/char/tpm/tpm_tis_spi.c
index 19513e622..3be2d53a5 100644
--- a/drivers/char/tpm/tpm_tis_spi.c
+++ b/drivers/char/tpm/tpm_tis_spi.c
@@ -184,12 +184,19 @@ static int tpm_tis_spi_write32(struct tpm_tis_data *data, u32 addr, u32 value)
@@ -184,12 +184,19 @@ static int tpm_tis_spi_write32(struct tp
return rc;
}
@@ -91,6 +87,3 @@ index 19513e622..3be2d53a5 100644
};
static int tpm_tis_spi_probe(struct spi_device *dev)
--
2.34.1

View File

@@ -0,0 +1,21 @@
--- a/drivers/char/hw_random/mtk-rng.c
+++ b/drivers/char/hw_random/mtk-rng.c
@@ -231,6 +231,10 @@ static const struct mtk_rng_of_data mt79
.rng_version = 2,
};
+static const struct mtk_rng_of_data mt7987_rng_data = {
+ .rng_version = 2,
+};
+
static const struct mtk_rng_of_data mt7988_rng_data = {
.rng_version = 2,
};
@@ -242,6 +246,7 @@ static const struct mtk_rng_of_data mt76
static const struct of_device_id mtk_rng_match[] = {
{ .compatible = "mediatek,mt7981-rng", .data = &mt7981_rng_data },
{ .compatible = "mediatek,mt7986-rng", .data = &mt7986_rng_data },
+ { .compatible = "mediatek,mt7987-rng", .data = &mt7987_rng_data },
{ .compatible = "mediatek,mt7988-rng", .data = &mt7988_rng_data },
{ .compatible = "mediatek,mt7623-rng", .data = &mt7623_rng_data },
{},

View File

@@ -0,0 +1,78 @@
From 7f4532a2bffdb0aebcabc2a672c4b97670e002a5 Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Mon, 3 Mar 2025 14:33:33 +0800
Subject: [PATCH] add pwm reg-v3 support for mt7987
---
drivers/pwm/pwm-mediatek.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index 79d15a9c..ad7cb2aa 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -34,6 +34,7 @@
#define PWM_CLK_DIV_MAX 7
#define REG_V1 1
#define REG_V2 2
+#define REG_V3 3
struct pwm_mediatek_of_data {
unsigned int num_pwms;
@@ -67,6 +68,10 @@ static const unsigned int mtk_pwm_reg_offset_v2[] = {
0x0080, 0x00c0, 0x0100, 0x0140, 0x0180, 0x1c0, 0x200, 0x0240
};
+static const unsigned int mtk_pwm_reg_offset_v3[] = {
+ 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x600, 0x700, 0x0800
+};
+
static inline struct pwm_mediatek_chip *
to_pwm_mediatek_chip(struct pwm_chip *chip)
{
@@ -117,6 +122,10 @@ static inline u32 pwm_mediatek_readl(struct pwm_mediatek_chip *chip,
u32 pwm_offset;
switch (chip->soc->reg_ver) {
+ case REG_V3:
+ pwm_offset = mtk_pwm_reg_offset_v3[num];
+ break;
+
case REG_V2:
pwm_offset = mtk_pwm_reg_offset_v2[num];
break;
@@ -136,6 +145,10 @@ static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
u32 pwm_offset;
switch (chip->soc->reg_ver) {
+ case REG_V3:
+ pwm_offset = mtk_pwm_reg_offset_v3[num];
+ break;
+
case REG_V2:
pwm_offset = mtk_pwm_reg_offset_v2[num];
break;
@@ -376,6 +389,12 @@ static const struct pwm_mediatek_of_data mt7986_pwm_data = {
.reg_ver = REG_V1,
};
+static const struct pwm_mediatek_of_data mt7987_pwm_data = {
+ .num_pwms = 3,
+ .pwm45_fixup = false,
+ .reg_ver = REG_V3,
+};
+
static const struct pwm_mediatek_of_data mt7988_pwm_data = {
.num_pwms = 8,
.pwm45_fixup = false,
@@ -396,6 +415,7 @@ static const struct of_device_id pwm_mediatek_of_match[] = {
{ .compatible = "mediatek,mt7629-pwm", .data = &mt7629_pwm_data },
{ .compatible = "mediatek,mt7981-pwm", .data = &mt7981_pwm_data },
{ .compatible = "mediatek,mt7986-pwm", .data = &mt7986_pwm_data },
+ { .compatible = "mediatek,mt7987-pwm", .data = &mt7987_pwm_data },
{ .compatible = "mediatek,mt7988-pwm", .data = &mt7988_pwm_data },
{ .compatible = "mediatek,mt8516-pwm", .data = &mt8516_pwm_data },
{ },
--
2.18.0

View File

@@ -0,0 +1,220 @@
From eecc1e7982d4f5da63b129e5437d79ced3aeb26f Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Mon, 3 Mar 2025 14:38:41 +0800
Subject: [PATCH] add pwm hw breathing light support for mt7987
---
drivers/pwm/pwm-mediatek.c | 118 ++++++++++++++++++++++++++++++++++++-
1 file changed, 116 insertions(+), 2 deletions(-)
diff --git a/drivers/pwm/pwm-mediatek.c b/drivers/pwm/pwm-mediatek.c
index ad7cb2aa..6e5ba9da 100644
--- a/drivers/pwm/pwm-mediatek.c
+++ b/drivers/pwm/pwm-mediatek.c
@@ -31,6 +31,11 @@
#define PWMTHRES 0x30
#define PWM45THRES_FIXUP 0x34
+#define PWM_BREATHING_THRES_MAX 32
+#define PWM_BREATHING_CON 0xb8
+#define PWM_BREATHING_THRES_0 0xbc
+#define PWM_BREATHING_THRES_1 0xd0
+
#define PWM_CLK_DIV_MAX 7
#define REG_V1 1
#define REG_V2 2
@@ -40,6 +45,8 @@ struct pwm_mediatek_of_data {
unsigned int num_pwms;
bool pwm45_fixup;
int reg_ver;
+ int hw_breathing_light;
+ int hw_breathing_light_thres_num;
};
/**
@@ -58,6 +65,7 @@ struct pwm_mediatek_chip {
struct clk *clk_main;
struct clk **clk_pwms;
const struct pwm_mediatek_of_data *soc;
+ bool bw_mode[8];
};
static const unsigned int mtk_pwm_reg_offset_v1[] = {
@@ -161,6 +169,85 @@ static inline void pwm_mediatek_writel(struct pwm_mediatek_chip *chip,
writel(value, chip->regs + pwm_offset + offset);
}
+static inline int pwm_bl_set_thres(struct pwm_mediatek_chip *chip, int pwm,
+ int idx, int value, int scale)
+{
+ u32 offset;
+ u32 shift;
+ u32 tmp;
+
+ value = value / scale;
+ if ((idx < 0) || (idx >= PWM_BREATHING_THRES_MAX))
+ return -EINVAL;
+ if ((value < 0) || (value > 255))
+ return -EINVAL;
+ if (idx < 4) {
+ offset = PWM_BREATHING_THRES_0;
+ shift = (idx % 4) * 8;
+ } else {
+ offset = PWM_BREATHING_THRES_1 + ((idx / 4) - 1) * 4;
+ shift = (idx % 4) * 8;
+ }
+ tmp = readl(chip->regs + mtk_pwm_reg_offset_v3[pwm] + offset);
+ tmp &= ~(0xff << shift);
+ tmp |= (value << shift);
+ writel(tmp, chip->regs + mtk_pwm_reg_offset_v3[pwm] + offset);
+
+ return 0;
+}
+
+static inline int pwm_config_bl_thres(struct pwm_mediatek_chip *chip, int pwm,
+ int max_counter, int num_thres)
+{
+ /* use x_scale to make the wavefrom display smoothly */
+ const int x_scale = 1000;
+ int c, x;
+ int ret;
+ int i;
+ /*
+ * [Breathing Light Pattern]
+ * - x : max_counter / (num_thres / 2)
+ * - 100% duty : (num_thres / 2) * x
+ * - 0% duty : 0 * x
+ * - per period: T(0)~T(num_thres)
+ * (If period = 10^9 (ns), 1T = 10^9 (ns) / num_thres)
+ *
+ * | num_thres | T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 10 11 12 13 14 15 ... |
+ * |-----------|-----------------------------------------------------|
+ * | 8 | 4x 3x 2x 1x 0x 1x 2x 3x (repeat) .................. |
+ * | 16 | 8x 7x 6x 5x 4x 3x 2x 1x 0x 1x 2x 3x 4x 5x 6x 7x ... |
+ * | 24 | 12x ............................................... |
+ * | 32 (max) | 16x ............................................... |
+ */
+ int pattern[PWM_BREATHING_THRES_MAX];
+
+ if ((num_thres < 2) || (num_thres % 2))
+ return -EINVAL;
+
+ c = num_thres / 2;
+ x = (max_counter * x_scale) / (num_thres / 2);
+
+ /* create breathing ligh pattern according to previous table */
+ /* use (x_scale * max_counter) instead of (x * num_thres) */
+ pattern[0] = max_counter * x_scale;
+ /* caculate each pattern according to (i) */
+ for (i = 1 ; i < c ; i++)
+ pattern[i] = x * (c - i);
+ for (i = c ; i < num_thres ; i++)
+ pattern[i] = x * (i - c);
+ for (i = 0 ; i < num_thres ; i++) {
+ ret = pwm_bl_set_thres(chip, pwm, i, pattern[i], x_scale);
+ if (ret)
+ return ret;
+ }
+
+ /* enable breathing light mode */
+ writel(((num_thres - 1) << 8 | 0x1),
+ chip->regs + mtk_pwm_reg_offset_v3[pwm] + PWM_BREATHING_CON);
+
+ return 0;
+}
+
static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
int duty_ns, int period_ns)
{
@@ -171,6 +258,8 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
u32 clkdiv = 0, clksel = 0, cnt_period, cnt_duty,
reg_width = PWMDWIDTH, reg_thres = PWMTHRES;
u64 resolution;
+ u32 max_cnt_period = 8191;
+ int thres_num;
int ret;
ret = pwm_mediatek_clk_enable(chip, pwm);
@@ -178,15 +267,24 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
if (ret < 0)
return ret;
+ if (pc->bw_mode[pwm->hwpwm]) {
+ thres_num = pc->soc->hw_breathing_light_thres_num;
+ period_ns = period_ns / thres_num;
+ max_cnt_period = 255;
+ }
+
/* Using resolution in picosecond gets accuracy higher */
resolution = (u64)NSEC_PER_SEC * 1000;
+
/* Calculate resolution based on current clock frequency */
do_div(resolution, clk_get_rate(pc->clk_pwms[pwm->hwpwm]));
+
/* Using resolution to calculate cnt_period which represents
* the effective range of the PWM period counter
*/
cnt_period = DIV_ROUND_CLOSEST_ULL((u64)period_ns * 1000, resolution);
- while (cnt_period > 8191) {
+
+ while (cnt_period > max_cnt_period) {
/* Using clkdiv to reduce clock frequency and calculate
* new resolution based on new clock speed
*/
@@ -230,8 +328,14 @@ static int pwm_mediatek_config(struct pwm_chip *chip, struct pwm_device *pwm,
clkdiv);
else
pwm_mediatek_writel(pc, pwm->hwpwm, PWMCON, BIT(15) | clkdiv);
+
pwm_mediatek_writel(pc, pwm->hwpwm, reg_width, cnt_period);
- pwm_mediatek_writel(pc, pwm->hwpwm, reg_thres, cnt_duty);
+
+ /* use array of bw_thres instead of normal thres in bw_mode */
+ if (pc->bw_mode[pwm->hwpwm])
+ pwm_config_bl_thres(pc, pwm->hwpwm, cnt_period, thres_num);
+ else
+ pwm_mediatek_writel(pc, pwm->hwpwm, reg_thres, cnt_duty);
pwm_mediatek_clk_disable(chip, pwm);
@@ -276,6 +380,7 @@ static const struct pwm_ops pwm_mediatek_ops = {
static int pwm_mediatek_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct pwm_mediatek_chip *pc;
struct resource *res;
unsigned int i;
@@ -313,6 +418,7 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
for (i = 0; i < pc->soc->num_pwms; i++) {
char name[8];
+ char bw_name[32];
snprintf(name, sizeof(name), "pwm%d", i + 1);
@@ -322,6 +428,12 @@ static int pwm_mediatek_probe(struct platform_device *pdev)
name, PTR_ERR(pc->clk_pwms[i]));
return PTR_ERR(pc->clk_pwms[i]);
}
+
+ if (pc->soc->hw_breathing_light) {
+ snprintf(bw_name, sizeof(bw_name),
+ "mediatek,pwm%d-breathing-light", i);
+ pc->bw_mode[i] = of_property_read_bool(np, bw_name);
+ }
}
platform_set_drvdata(pdev, pc);
@@ -393,6 +505,8 @@ static const struct pwm_mediatek_of_data mt7987_pwm_data = {
.num_pwms = 3,
.pwm45_fixup = false,
.reg_ver = REG_V3,
+ .hw_breathing_light = 1,
+ .hw_breathing_light_thres_num = 32,
};
static const struct pwm_mediatek_of_data mt7988_pwm_data = {
--
2.18.0

View File

@@ -0,0 +1,34 @@
Index: linux-5.4.281/drivers/mtd/spi-nor/spi-nor.c
===================================================================
--- linux-5.4.281.orig/drivers/mtd/spi-nor/spi-nor.c
+++ linux-5.4.281/drivers/mtd/spi-nor/spi-nor.c
@@ -2242,14 +2242,13 @@ static const struct flash_info spi_nor_i
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
{ "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) },
- { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256, 0) },
{ "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16,
SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25qh32", INFO(0x1c7016, 0, 64 * 1024, 64, 0) },
{ "en25qh64", INFO(0x1c7017, 0, 64 * 1024, 128,
SECT_4K | SPI_NOR_DUAL_READ) },
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
- { "en25qx128", INFO(0x1c7118, 0, 64 * 1024, 256,
+ { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
@@ -2360,10 +2359,13 @@ static const struct flash_info spi_nor_i
{ "mx25u4035", INFO(0xc22533, 0, 64 * 1024, 8, SECT_4K) },
{ "mx25u8035", INFO(0xc22534, 0, 64 * 1024, 16, SECT_4K) },
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
+ { "mx25l12833f", INFO(0xc22018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
{ "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
+ { "mx25l25645g", INFO(0xc22019, 0, 64 * 1024, 512,
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512,
SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ)
.fixups = &mx25l25635_fixups },

View File

@@ -9,11 +9,9 @@ Subject: [PATCH]
include/linux/spi/spi.h | 42 ++++++++++++
2 files changed, 183 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index e562735a3..28bad4a8b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1109,6 +1109,74 @@ static int spi_transfer_wait(struct spi_controller *ctlr,
@@ -1109,6 +1109,82 @@ static int spi_transfer_wait(struct spi_
return 0;
}
@@ -32,8 +30,13 @@ index e562735a3..28bad4a8b 100644
+ bool hit;
+
+ /* Make sure we can start calibration */
+ if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata)
+ if(!ctlr->cal_target || !ctlr->cal_rule) {
+ return 0;
+ } else if(!ctlr->append_caldata) {
+ pr_err("%s: calibration is enabled but no controller data.\n",
+ __func__);
+ return -EINVAL;
+ }
+ datalen = ctlr->cal_rule->datalen;
+ addrlen = ctlr->cal_rule->addrlen;
+
@@ -70,9 +73,12 @@ index e562735a3..28bad4a8b 100644
+ *target->cal_item = DIV_ROUND_CLOSEST(hit_val, total_hit);
+ dev_info(&spi->dev, "calibration result: 0x%x", *target->cal_item);
+ } else {
+ /* We don't return error in this case because you don't know calibration
+ * failure is caused by bus error or wrong calibration data provided by
+ * user or driver.
+ */
+ *target->cal_item = origin;
+ dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin);
+ ret = -EIO;
+ }
+
+ list_del(pos);
@@ -88,7 +94,7 @@ index e562735a3..28bad4a8b 100644
static void _spi_transfer_delay_ns(u32 ns)
{
if (!ns)
@@ -1720,6 +1788,75 @@ void spi_flush_queue(struct spi_controller *ctlr)
@@ -1720,6 +1796,75 @@ void spi_flush_queue(struct spi_controll
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_OF)
@@ -164,7 +170,7 @@ index e562735a3..28bad4a8b 100644
static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
struct device_node *nc)
{
@@ -1841,6 +1978,10 @@ of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
@@ -1841,6 +1986,10 @@ of_register_spi_device(struct spi_contro
if (rc)
goto err_out;
@@ -175,8 +181,6 @@ index e562735a3..28bad4a8b 100644
/* Store a pointer to the node in the device structure */
of_node_get(nc);
spi->dev.of_node = nc;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 7067f85ce..5330cd9b0 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -264,6 +264,40 @@ struct spi_driver {
@@ -232,7 +236,7 @@ index 7067f85ce..5330cd9b0 100644
int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
};
@@ -1369,6 +1408,9 @@ spi_register_board_info(struct spi_board_info const *info, unsigned n)
@@ -1369,6 +1408,9 @@ spi_register_board_info(struct spi_board
{ return 0; }
#endif
@@ -242,6 +246,3 @@ index 7067f85ce..5330cd9b0 100644
/* If you're hotplugging an adapter with devices (parport, usb, etc)
* use spi_new_device() to describe each device. You can also call
* spi_unregister_device() to start making that device vanish, but
--
2.34.1

View File

@@ -0,0 +1,162 @@
--- a/drivers/mtd/nand/raw/nand_onfi.c
+++ b/drivers/mtd/nand/raw/nand_onfi.c
@@ -12,20 +12,14 @@
* This file contains all ONFI helpers.
*/
+#include <linux/mtd/param.h>
#include <linux/slab.h>
#include "internals.h"
u16 onfi_crc16(u16 crc, u8 const *p, size_t len)
{
- int i;
- while (len--) {
- crc ^= *p++ << 8;
- for (i = 0; i < 8; i++)
- crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
- }
-
- return crc;
+ return nanddev_crc16(crc, p, len);
}
/* Parse the Extended Parameter Page. */
@@ -104,37 +98,6 @@ ext_out:
}
/*
- * Recover data with bit-wise majority
- */
-static void nand_bit_wise_majority(const void **srcbufs,
- unsigned int nsrcbufs,
- void *dstbuf,
- unsigned int bufsize)
-{
- int i, j, k;
-
- for (i = 0; i < bufsize; i++) {
- u8 val = 0;
-
- for (j = 0; j < 8; j++) {
- unsigned int cnt = 0;
-
- for (k = 0; k < nsrcbufs; k++) {
- const u8 *srcbuf = srcbufs[k];
-
- if (srcbuf[i] & BIT(j))
- cnt++;
- }
-
- if (cnt > nsrcbufs / 2)
- val |= BIT(j);
- }
-
- ((u8 *)dstbuf)[i] = val;
- }
-}
-
-/*
* Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
*/
int nand_onfi_detect(struct nand_chip *chip)
@@ -184,7 +147,7 @@ int nand_onfi_detect(struct nand_chip *c
const void *srcbufs[3] = {p, p + 1, p + 2};
pr_warn("Could not find a valid ONFI parameter page, trying bit-wise majority to recover it\n");
- nand_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
+ nanddev_bit_wise_majority(srcbufs, ARRAY_SIZE(srcbufs), p,
sizeof(*p));
if (onfi_crc16(ONFI_CRC_BASE, (u8 *)p, 254) !=
--- /dev/null
+++ b/drivers/mtd/nand/param.c
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 - Mediatek
+ *
+ * Author: SkyLake <SkyLake.Huang@mediatek.com>
+ */
+
+#include <linux/mtd/param.h>
+
+u16 nanddev_crc16(u16 crc, u8 const *p, size_t len)
+{
+ int i;
+
+ while (len--) {
+ crc ^= *p++ << 8;
+ for (i = 0; i < 8; i++)
+ crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
+ }
+
+ return crc;
+}
+
+/*
+ * Recover data with bit-wise majority
+ */
+void nanddev_bit_wise_majority(const void **srcbufs,
+ unsigned int nsrcbufs,
+ void *dstbuf,
+ unsigned int bufsize)
+{
+ int i, j, k;
+
+ for (i = 0; i < bufsize; i++) {
+ u8 val = 0;
+
+ for (j = 0; j < 8; j++) {
+ unsigned int cnt = 0;
+
+ for (k = 0; k < nsrcbufs; k++) {
+ const u8 *srcbuf = srcbufs[k];
+
+ if (srcbuf[i] & BIT(j))
+ cnt++;
+ }
+
+ if (cnt > nsrcbufs / 2)
+ val |= BIT(j);
+ }
+
+ ((u8 *)dstbuf)[i] = val;
+ }
+}
--- /dev/null
+++ b/include/linux/mtd/param.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2023 - Mediatek
+ *
+ * Author: SkyLake <SkyLake.Huang@mediatek.com>
+ */
+
+#ifndef __LINUX_NAND_PARAM
+#define __LINUX_NAND_PARAM
+
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <stddef.h>
+
+u16 nanddev_crc16(u16 crc, u8 const *p, size_t len);
+void nanddev_bit_wise_majority(const void **srcbufs,
+ unsigned int nsrcbufs,
+ void *dstbuf,
+ unsigned int bufsize);
+
+#endif /* __LINUX_NAND_PARAM */
+
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
-nandcore-objs := core.o bbt.o
+nandcore-objs := core.o bbt.o param.o
obj-$(CONFIG_MTD_NAND_CORE) += nandcore.o
obj-y += onenand/

View File

@@ -0,0 +1,89 @@
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2252,7 +2252,7 @@ static const struct flash_info spi_nor_i
{ "en25qx128", INFO(0x1c7118, 0, 64 * 1024, 256,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
- { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
+ { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, SPI_NOR_4B_OPCODES) },
{ "en25qx256a", INFO(0x1c7119, 0, 64 * 1024, 512,
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
@@ -4904,7 +4904,6 @@ static void spi_nor_debugfs_init(struct
static int spi_nor_cal_read(void *priv, u32 *addr, int addrlen, u8 *buf, int readlen)
{
- int ret;
struct spi_nor *nor = (struct spi_nor *)priv;
nor->reg_proto = SNOR_PROTO_1_1_1;
@@ -4919,7 +4918,6 @@ static int spi_nor_cal_read(void *priv,
static int spi_nor_cal_read_4B(void *priv, u32 *addr, int addrlen, u8 *buf,
int readlen)
{
- int ret;
struct spi_nor *nor = (struct spi_nor *)priv;
nor->reg_proto = SNOR_PROTO_1_1_1;
@@ -4971,6 +4969,15 @@ static const struct flash_info *spi_nor_
return info;
}
+void spi_nor_reset_read(struct spi_nor *nor)
+{
+ nor->reg_proto = SNOR_PROTO_1_1_1;
+ nor->read_proto = SNOR_PROTO_1_1_1;
+ nor->write_proto = SNOR_PROTO_1_1_1;
+ nor->addr_width = 0;
+ nor->read_dummy = 0;
+}
+
int spi_nor_scan(struct spi_nor *nor, const char *name,
const struct spi_nor_hwcaps *hwcaps)
{
@@ -5009,11 +5016,11 @@ int spi_nor_scan(struct spi_nor *nor, co
ret = spi_mem_do_calibration(nor->spimem,
spi_nor_cal_read, nor);
if (ret) {
+ dev_info(dev, "Switch to 4B mode to do SPI calibration\n");
ret = spi_mem_do_calibration(nor->spimem,
spi_nor_cal_read_4B, nor);
- if (ret)
- return ret;
}
+ spi_nor_reset_read(nor);
}
info = spi_nor_get_flash_info(nor, name);
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1177,6 +1177,7 @@ int spi_do_calibration(struct spi_contro
*/
*target->cal_item = origin;
dev_warn(&spi->dev, "calibration failed, fallback to default: 0x%x", origin);
+ ret = -EIO;
}
list_del(pos);
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -888,7 +888,7 @@ int tpm_tis_core_init(struct device *dev
if (phy_ops->do_calibration) {
rc = priv->phy_ops->do_calibration(priv, dev);
if (rc)
- goto out_err;
+ dev_info(dev, "Use default SPI calibration value.\n");
}
if (wait_startup(chip, 0) != 0) {
--- a/drivers/mtd/nand/spi/core.c
+++ b/drivers/mtd/nand/spi/core.c
@@ -1779,7 +1779,7 @@ static int spinand_init(struct spinand_d
ret = spi_mem_do_calibration(spinand->spimem, spinand_cal_read, spinand);
if (ret)
- dev_err(dev, "Failed to calibrate SPI-NAND (err = %d)\n", ret);
+ dev_info(dev, "Use default SPI calibration value.\n");
ret = spinand_detect(spinand);
if (ret)

View File

@@ -0,0 +1,40 @@
diff --git a/drivers/mtd/mtdsplit/mtdsplit_squashfs.c b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
index f6353da..6e5c569 100644
--- a/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
+++ b/drivers/mtd/mtdsplit/mtdsplit_squashfs.c
@@ -30,6 +30,9 @@ mtdsplit_parse_squashfs(struct mtd_info *master,
struct mtd_info *parent_mtd;
size_t part_offset;
size_t squashfs_len;
+ size_t dm_off, dm_len;
+ size_t retlen;
+ char verity[7];
int err;
err = mtd_get_squashfs_len(master, 0, &squashfs_len);
@@ -39,6 +42,25 @@ mtdsplit_parse_squashfs(struct mtd_info *master,
parent_mtd = mtd_get_master(master);
part_offset = mtdpart_get_offset(master);
+#define DM_VERITY_STR "verity"
+#define DM_VERITY_BLK_SZ 4096
+ /* Try to find DM-verity */
+ dm_off = roundup(squashfs_len, DM_VERITY_BLK_SZ);
+ dm_len = 7;
+ err = mtd_read(master, dm_off, dm_len, &retlen, (void *)&verity);
+ if (err || (retlen != dm_len)) {
+ pr_alert("error occured while reading from \"%s\"\n",
+ master->name);
+ return -EIO;
+ }
+ if (!strcmp(verity, DM_VERITY_STR)) {
+ int dm_sz;
+
+ dm_sz = roundup(squashfs_len / 128, DM_VERITY_BLK_SZ);
+ dm_sz += DM_VERITY_BLK_SZ * 2;
+ squashfs_len += dm_sz;
+ }
+
part = kzalloc(sizeof(*part), GFP_KERNEL);
if (!part) {
pr_alert("unable to allocate memory for \"%s\" partition\n",

View File

@@ -0,0 +1,403 @@
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index c229451..9ae8840 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -10,6 +10,7 @@
#include <linux/cpumask.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/pm_opp.h>
#include <linux/regulator/consumer.h>
@@ -22,6 +23,21 @@
#define MAX_VOLT_LIMIT (1150000)
#define VOLT_TOL (10000)
+struct mtk_cpufreq_vspec {
+ unsigned int freq;
+ unsigned int vbase;
+ unsigned int vscale;
+ unsigned int vmax;
+};
+
+struct mtk_cpufreq_platform_data {
+ const struct mtk_cpufreq_vspec *vspec;
+ unsigned char adjust_voltage;
+ unsigned char has_cci_clk;
+ unsigned int cpu_clk_mult;
+ unsigned int cci_clk_mult;
+};
+
/*
* The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS
* on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in
@@ -34,6 +50,7 @@
* the original PLL becomes stable at target frequency.
*/
struct mtk_cpu_dvfs_info {
+ const struct mtk_cpufreq_platform_data *soc_data;
struct cpumask cpus;
struct device *cpu_dev;
struct regulator *proc_reg;
@@ -194,6 +211,9 @@ static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info,
static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc)
{
+ if (!info->soc_data->adjust_voltage)
+ return 0;
+
if (info->need_voltage_tracking)
return mtk_cpufreq_voltage_tracking(info, vproc);
else
@@ -219,7 +239,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
old_freq_hz = clk_get_rate(cpu_clk);
- if (!IS_ERR(info->cci_clk)) {
+ if (info->soc_data->has_cci_clk) {
cci_clk = info->cci_clk;
ccipll = clk_get_parent(cci_clk);
cci_old_freq_hz = clk_get_rate(cci_clk);
@@ -231,8 +251,14 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
return old_vproc;
}
- freq_hz = freq_table[index].frequency * 1000;
- cci_freq_hz = freq_table[index].frequency * 600;
+ /* Caculate the target frequency for armpll (cpupll) and ccipll
+ * The values of freq_table[index] are recorded in Khz
+ * The target frequency for armpll = frequency * cpu_clk_mult (Hz)
+ * The target frequency for ccipll = frequency * cci_clk_mult (Hz)
+ */
+ freq_hz = freq_table[index].frequency * info->soc_data->cpu_clk_mult;
+ cci_freq_hz =
+ freq_table[index].frequency * info->soc_data->cci_clk_mult;
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz);
if (IS_ERR(opp)) {
@@ -259,7 +285,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
}
/* Reparent the CCI clock to intermediate clock. */
- if (!IS_ERR(cci_clk)) {
+ if (info->soc_data->has_cci_clk) {
ret = clk_set_parent(cci_clk, info->inter_clk);
if (ret) {
pr_err("cpu%d: failed to re-parent cci clock!\n",
@@ -291,7 +317,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
}
/* Set the original PLL to target rate. */
- if (!IS_ERR(cci_clk)) {
+ if (info->soc_data->has_cci_clk) {
ret = clk_set_rate(ccipll, cci_freq_hz);
if (ret) {
pr_err("cpu%d: failed to scale cci clock rate!\n",
@@ -313,7 +339,7 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
}
/* Set parent of CCI clock back to the original PLL. */
- if (!IS_ERR(cci_clk)) {
+ if (info->soc_data->has_cci_clk) {
ret = clk_set_parent(cci_clk, ccipll);
if (ret) {
pr_err("cpu%d: failed to re-parent cci clock!\n",
@@ -332,18 +358,18 @@ static int mtk_cpufreq_set_target(struct cpufreq_policy *policy,
if (ret) {
pr_err("cpu%d: failed to scale down voltage!\n",
policy->cpu);
- if (!IS_ERR(cci_clk))
+ if (info->soc_data->has_cci_clk)
clk_set_parent(cci_clk, info->inter_clk);
clk_set_parent(cpu_clk, info->inter_clk);
clk_set_rate(armpll, old_freq_hz);
- if (!IS_ERR(cci_clk))
+ if (info->soc_data->has_cci_clk)
clk_set_rate(ccipll, cci_old_freq_hz);
clk_set_parent(cpu_clk, armpll);
- if (!IS_ERR(cci_clk))
+ if (info->soc_data->has_cci_clk)
clk_set_parent(cci_clk, ccipll);
return ret;
@@ -397,7 +423,21 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
goto out_free_resources;
}
- cci_clk = clk_get(cpu_dev, "cci");
+ if (info->soc_data->has_cci_clk) {
+ cci_clk = clk_get(cpu_dev, "cci");
+
+ if (IS_ERR(cci_clk)) {
+ if (PTR_ERR(cci_clk) == -EPROBE_DEFER)
+ pr_warn("cci clk for cpu%d not ready, retry.\n",
+ cpu);
+ else
+ pr_err("failed to get cci clk for cpu%d\n",
+ cpu);
+
+ ret = PTR_ERR(cci_clk);
+ return ret;
+ }
+ }
proc_reg = regulator_get_optional(cpu_dev, "proc");
if (IS_ERR(proc_reg)) {
@@ -444,7 +484,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
if (ret)
goto out_disable_mux_clock;
- if(!(IS_ERR(cci_clk))) {
+ if (info->soc_data->has_cci_clk) {
ret = clk_prepare_enable(cci_clk);
if(ret)
goto out_disable_inter_clock;
@@ -465,7 +505,10 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
info->proc_reg = proc_reg;
info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg;
info->cpu_clk = cpu_clk;
- info->cci_clk = cci_clk;
+
+ if (info->soc_data->has_cci_clk)
+ info->cci_clk = cci_clk;
+
info->inter_clk = inter_clk;
/*
@@ -477,7 +520,7 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
return 0;
out_disable_cci_clock:
- if(!IS_ERR(cci_clk))
+ if (info->soc_data->has_cci_clk)
clk_disable_unprepare(cci_clk);
out_disable_inter_clock:
@@ -505,8 +548,9 @@ static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu)
clk_put(cpu_clk);
if (!IS_ERR(inter_clk))
clk_put(inter_clk);
- if (!IS_ERR(cci_clk))
- clk_put(cci_clk);
+ if (info->soc_data->has_cci_clk)
+ if (!IS_ERR(cci_clk))
+ clk_put(cci_clk);
return ret;
}
@@ -527,24 +571,67 @@ static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info)
clk_disable_unprepare(info->inter_clk);
clk_put(info->inter_clk);
}
- if (!IS_ERR(info->cci_clk)){
- clk_disable_unprepare(info->cci_clk);
- clk_put(info->cci_clk);
+ if (info->soc_data->has_cci_clk) {
+ if (!IS_ERR(info->cci_clk)) {
+ clk_disable_unprepare(info->cci_clk);
+ clk_put(info->cci_clk);
+ }
}
dev_pm_opp_of_cpumask_remove_table(&info->cpus);
}
+static int mtk_cpufreq_adjust_voltage(struct mtk_cpu_dvfs_info *info,
+ struct cpufreq_policy *policy)
+{
+ const struct mtk_cpufreq_vspec *vspec;
+ unsigned int target_voltage;
+ struct nvmem_cell *cell;
+ struct dev_pm_opp *opp;
+ unsigned int cal_data;
+ const u8 *buf;
+ size_t len;
+ int ret;
+ int i;
+
+ cell = nvmem_cell_get(info->cpu_dev, "calibration-data");
+ if (IS_ERR(cell))
+ return PTR_ERR(cell);
+
+ buf = nvmem_cell_read(cell, &len);
+ nvmem_cell_put(cell);
+ if (IS_ERR(buf))
+ return PTR_ERR(buf);
+
+ cal_data = buf[0] & 0x1f;
+ pr_debug("%s: read vbinning value: %d\n", __func__, cal_data);
+ kfree(buf);
+ if (!info->soc_data->vspec) {
+ pr_err("voltage spec not found\n");
+ return -EINVAL;
+ }
+
+ vspec = &info->soc_data->vspec[0];
+ for (i = 0 ; i < vspec->freq ; i++) {
+ target_voltage = vspec->vbase + cal_data * vspec->vscale;
+ if (target_voltage > vspec->vmax) {
+ pr_warn("freq %u exceeds max voltage\n", vspec->freq);
+ pr_warn("force update voltage to %u\n", vspec->vmax);
+ target_voltage = vspec->vmax;
+ }
+ dev_pm_opp_remove(info->cpu_dev, vspec->freq);
+ dev_pm_opp_add(info->cpu_dev, vspec->freq, target_voltage);
+ vspec = &info->soc_data->vspec[i + 1];
+ }
+
+ return 0;
+}
+
static int mtk_cpufreq_init(struct cpufreq_policy *policy)
{
struct mtk_cpu_dvfs_info *info;
struct cpufreq_frequency_table *freq_table;
int ret;
- int target_vproc;
- u8 reg_val;
- struct nvmem_cell *cell;
- size_t len;
- u8 *buf;
info = mtk_cpu_dvfs_info_lookup(policy->cpu);
if (!info) {
@@ -553,19 +640,12 @@ static int mtk_cpufreq_init(struct cpufreq_policy *policy)
return -EINVAL;
}
- cell = nvmem_cell_get(info->cpu_dev, "calibration-data");
- if (!IS_ERR(cell)) {
- buf = (u8 *)nvmem_cell_read(cell, &len);
- nvmem_cell_put(cell);
- if (!IS_ERR(buf)) {
- reg_val = buf[0] & 0x1f;
- pr_debug("%s: read vbinning value: %d\n", __func__, reg_val);
- if (reg_val > 0) {
- target_vproc = 850000 + reg_val * 10000;
- dev_pm_opp_remove(info->cpu_dev, 1800000000);
- dev_pm_opp_add(info->cpu_dev, 1800000000, target_vproc);
- }
- kfree(buf);
+ if (info->soc_data->adjust_voltage) {
+ ret = mtk_cpufreq_adjust_voltage(info, policy);
+ if (ret) {
+ pr_err("failed to adjust voltage for cpu%d: %d\n",
+ policy->cpu, ret);
+ return ret;
}
}
@@ -610,9 +690,17 @@ static struct cpufreq_driver mtk_cpufreq_driver = {
static int mtk_cpufreq_probe(struct platform_device *pdev)
{
+ const struct mtk_cpufreq_platform_data *data;
struct mtk_cpu_dvfs_info *info, *tmp;
int cpu, ret;
+ data = dev_get_platdata(&pdev->dev);
+ if (!data) {
+ dev_err(&pdev->dev,
+ "failed to get mtk cpufreq platform data\n");
+ return -ENODEV;
+ }
+
for_each_possible_cpu(cpu) {
info = mtk_cpu_dvfs_info_lookup(cpu);
if (info)
@@ -624,6 +712,7 @@ static int mtk_cpufreq_probe(struct platform_device *pdev)
goto release_dvfs_info_list;
}
+ info->soc_data = data;
ret = mtk_cpu_dvfs_info_init(info, cpu);
if (ret) {
dev_err(&pdev->dev,
@@ -659,20 +748,43 @@ static struct platform_driver mtk_cpufreq_platdrv = {
.probe = mtk_cpufreq_probe,
};
+struct mtk_cpufreq_vspec mt7988_voltage_spec[] = {
+ {
+ .freq = 1800000000,
+ .vbase = 850000,
+ .vscale = 10000,
+ .vmax = 1120000,
+ },
+ { } /* sentinel */
+};
+
+static const struct mtk_cpufreq_platform_data mt2701_platform_data = {
+ .adjust_voltage = 0,
+ .has_cci_clk = 0,
+ .cpu_clk_mult = 1000,
+};
+
+static const struct mtk_cpufreq_platform_data mt7988_platform_data = {
+ .vspec = mt7988_voltage_spec,
+ .adjust_voltage = 1,
+ .has_cci_clk = 1,
+ .cpu_clk_mult = 1000,
+ .cci_clk_mult = 600,
+};
+
/* List of machines supported by this driver */
static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
- { .compatible = "mediatek,mt2701", },
- { .compatible = "mediatek,mt2712", },
- { .compatible = "mediatek,mt7622", },
- { .compatible = "mediatek,mt7623", },
- { .compatible = "mediatek,mt817x", },
- { .compatible = "mediatek,mt8173", },
- { .compatible = "mediatek,mt8176", },
- { .compatible = "mediatek,mt8183", },
- { .compatible = "mediatek,mt8516", },
- { .compatible = "mediatek,mt7988", },
-
- { }
+ { .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7622", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7623", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt817x", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8173", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8183", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7988", .data = &mt7988_platform_data },
+ {}
};
MODULE_DEVICE_TABLE(of, mtk_cpufreq_machines);
@@ -680,6 +792,7 @@ static int __init mtk_cpufreq_driver_init(void)
{
struct device_node *np;
const struct of_device_id *match;
+ const struct mtk_cpufreq_platform_data *data;
struct platform_device *pdev;
int err;
@@ -694,6 +807,8 @@ static int __init mtk_cpufreq_driver_init(void)
return -ENODEV;
}
+ data = match->data;
+
err = platform_driver_register(&mtk_cpufreq_platdrv);
if (err)
return err;
@@ -704,7 +819,8 @@ static int __init mtk_cpufreq_driver_init(void)
* and the device registration codes are put here to handle defer
* probing.
*/
- pdev = platform_device_register_simple("mtk-cpufreq", -1, NULL, 0);
+ pdev = platform_device_register_data(NULL, "mtk-cpufreq", -1, data,
+ sizeof(*data));
if (IS_ERR(pdev)) {
pr_err("failed to register mtk-cpufreq platform device\n");
platform_driver_unregister(&mtk_cpufreq_platdrv);

View File

@@ -0,0 +1,12 @@
diff --git a/drivers/cpufreq/mediatek-cpufreq.c b/drivers/cpufreq/mediatek-cpufreq.c
index 9ae8840..1d0d8c3 100644
--- a/drivers/cpufreq/mediatek-cpufreq.c
+++ b/drivers/cpufreq/mediatek-cpufreq.c
@@ -783,6 +783,7 @@ static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
{ .compatible = "mediatek,mt8176", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8183", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt8516", .data = &mt2701_platform_data },
+ { .compatible = "mediatek,mt7987", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7988", .data = &mt7988_platform_data },
{}
};

View File

@@ -0,0 +1,30 @@
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -71,6 +71,17 @@ config ZTS8032
help
Support for the Zilltek ZTS8032 barometric pressure sensor.
+config ZTS8232
+ tristate "Zilltek ZTS8232 pressure and temperature sensor"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ Support for the Zilltek ZTS8232 digital barometric pressure sensor.
+ It can be accessed over I2C bus.
+
+ This driver can also be built as a module. If so, the module will be
+ called zts8232.
+
config HID_SENSOR_PRESS
depends on HID_SENSOR_HUB
select IIO_BUFFER
--- a/drivers/iio/pressure/Makefile
+++ b/drivers/iio/pressure/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_BMP280_I2C) += bmp280-i2c.o
obj-$(CONFIG_BMP280_SPI) += bmp280-spi.o
obj-$(CONFIG_DPS310) += dps310.o
obj-$(CONFIG_ZTS8032) += zts8032.o
+obj-$(CONFIG_ZTS8232) += zts8232.o
obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o
obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o
obj-$(CONFIG_HP03) += hp03.o

View File

@@ -0,0 +1,183 @@
--- a/drivers/soc/mediatek/mtk-devapc.c
+++ b/drivers/soc/mediatek/mtk-devapc.c
@@ -9,13 +9,14 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#define VIO_MOD_TO_REG_IND(m) ((m) / 32)
#define VIO_MOD_TO_REG_OFF(m) ((m) % 32)
-struct mtk_devapc_vio_dbgs {
+struct mtk_devapc_vio_dbgs_v1 {
union {
u32 vio_dbg0;
struct {
@@ -31,12 +32,29 @@ struct mtk_devapc_vio_dbgs {
u32 vio_dbg1;
};
+struct mtk_devapc_vio_dbgs_v2 {
+ union {
+ u32 vio_dbg0;
+ struct {
+ u32 dmnid:6;
+ u32 vio_w:1;
+ u32 vio_r:1;
+ } dbg0_bits;
+ };
+
+ u32 vio_dbg1;
+ u32 vio_dbg2;
+ u32 vio_dbg3;
+};
+
struct mtk_devapc_regs_ofs {
/* reg offset */
u32 vio_mask_offset;
u32 vio_sta_offset;
u32 vio_dbg0_offset;
u32 vio_dbg1_offset;
+ u32 vio_dbg2_offset;
+ u32 vio_dbg3_offset;
u32 apc_con_offset;
u32 vio_shift_sta_offset;
u32 vio_shift_sel_offset;
@@ -46,6 +64,7 @@ struct mtk_devapc_regs_ofs {
struct mtk_devapc_data {
/* numbers of violation index */
u32 vio_idx_num;
+ u32 version;
const struct mtk_devapc_regs_ofs *regs_ofs;
};
@@ -154,13 +173,10 @@ static int devapc_sync_vio_dbg(struct mt
return true;
}
-/*
- * devapc_extract_vio_dbg - extract full violation information after doing
- * shift mechanism.
- */
-static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
+
+static void devapc_extract_vio_dbg_v1(struct mtk_devapc_context *ctx)
{
- struct mtk_devapc_vio_dbgs vio_dbgs;
+ struct mtk_devapc_vio_dbgs_v1 vio_dbgs;
void __iomem *vio_dbg0_reg;
void __iomem *vio_dbg1_reg;
@@ -181,6 +197,46 @@ static void devapc_extract_vio_dbg(struc
vio_dbgs.vio_dbg1);
}
+static void devapc_extract_vio_dbg_v2(struct mtk_devapc_context *ctx)
+{
+ struct mtk_devapc_vio_dbgs_v2 vio_dbgs;
+ void __iomem *vio_dbg0_reg;
+ void __iomem *vio_dbg1_reg;
+ void __iomem *vio_dbg2_reg;
+ void __iomem *vio_dbg3_reg;
+
+ vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
+ vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
+ vio_dbg2_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg2_offset;
+ vio_dbg3_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg3_offset;
+
+ vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
+ vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
+ vio_dbgs.vio_dbg2 = readl(vio_dbg2_reg);
+ vio_dbgs.vio_dbg3 = readl(vio_dbg3_reg);
+
+ if (vio_dbgs.dbg0_bits.vio_w)
+ dev_info(ctx->dev, "Write Violation\n");
+ else if (vio_dbgs.dbg0_bits.vio_r)
+ dev_info(ctx->dev, "Read Violation\n");
+
+ dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%llx\n",
+ vio_dbgs.vio_dbg1, vio_dbgs.dbg0_bits.dmnid,
+ ((u64)vio_dbgs.vio_dbg3 << 32) | vio_dbgs.vio_dbg2);
+}
+
+/*
+ * devapc_extract_vio_dbg - extract full violation information after doing
+ * shift mechanism.
+ */
+static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
+{
+ if (ctx->data->version == 1)
+ devapc_extract_vio_dbg_v1(ctx);
+ else
+ devapc_extract_vio_dbg_v2(ctx);
+}
+
/*
* devapc_violation_irq - the devapc Interrupt Service Routine (ISR) will dump
* violation information including which master violates
@@ -229,16 +285,37 @@ static const struct mtk_devapc_regs_ofs
.vio_shift_con_offset = 0xF20,
};
+static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt7987 = {
+ .vio_mask_offset = 0x0,
+ .vio_sta_offset = 0x400,
+ .vio_dbg0_offset = 0x900,
+ .vio_dbg1_offset = 0x904,
+ .vio_dbg2_offset = 0x908,
+ .vio_dbg3_offset = 0x90C,
+ .apc_con_offset = 0xF00,
+ .vio_shift_sta_offset = 0xF20,
+ .vio_shift_sel_offset = 0xF30,
+ .vio_shift_con_offset = 0xF10,
+};
+
static const struct mtk_devapc_data devapc_mt6779 = {
.vio_idx_num = 511,
+ .version = 1,
.regs_ofs = &devapc_regs_ofs_mt6779,
};
static const struct mtk_devapc_data devapc_mt8186 = {
.vio_idx_num = 519,
+ .version = 1,
.regs_ofs = &devapc_regs_ofs_mt6779,
};
+static const struct mtk_devapc_data devapc_mt7987 = {
+ .vio_idx_num = 283,
+ .version = 2,
+ .regs_ofs = &devapc_regs_ofs_mt7987,
+};
+
static const struct of_device_id mtk_devapc_dt_match[] = {
{
.compatible = "mediatek,mt6779-devapc",
@@ -247,6 +324,9 @@ static const struct of_device_id mtk_dev
.compatible = "mediatek,mt8186-devapc",
.data = &devapc_mt8186,
}, {
+ .compatible = "mediatek,mt7987-devapc",
+ .data = &devapc_mt7987,
+ }, {
},
};
MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
@@ -276,9 +356,11 @@ static int mtk_devapc_probe(struct platf
if (!devapc_irq)
return -EINVAL;
- ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
- if (IS_ERR(ctx->infra_clk))
- return -EINVAL;
+ if (ctx->data->version == 1) {
+ ctx->infra_clk = devm_clk_get_enabled(&pdev->dev, "devapc-infra-clock");
+ if (IS_ERR(ctx->infra_clk))
+ return -EINVAL;
+ }
ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
IRQF_TRIGGER_NONE, "devapc", ctx);

View File

@@ -0,0 +1,69 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 15 Mar 2018 20:46:31 +0100
Subject: [PATCH] netfilter: nf_flow_table: support hw offload through
virtual interfaces
There are hardware offload devices that support offloading VLANs and
PPPoE devices. Additionally, it is useful to be able to offload packets
routed through bridge interfaces as well.
Add support for finding the path to the offload device through these
virtual interfaces, while collecting useful parameters for the offload
device, like VLAN ID/protocol, PPPoE session and Ethernet MAC address.
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 2d1aa35..b60b506 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -989,6 +989,7 @@ struct dev_ifalias {
struct devlink;
struct tlsdev_ops;
+struct flow_offload_hw_path;
/*
* This structure defines the management hooks for network devices.
@@ -1222,6 +1223,11 @@ struct tlsdev_ops;
* int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh,
* u16 flags);
*
+ * int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
+ * For virtual devices like bridges, vlan, and pppoe, fill in the
+ * underlying network device that can be used for offloading connections.
+ * Return an error if offloading is not supported.
+ *
* int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier);
* Called to change device carrier. Soft-devices (like dummy, team, etc)
* which do not represent real hardware may define this to allow their
@@ -1471,6 +1477,7 @@ struct net_device_ops {
int (*ndo_bridge_dellink)(struct net_device *dev,
struct nlmsghdr *nlh,
u16 flags);
+ int (*ndo_flow_offload_check)(struct flow_offload_hw_path *path);
int (*ndo_change_carrier)(struct net_device *dev,
bool new_carrier);
int (*ndo_get_phys_port_id)(struct net_device *dev,
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 7374cb2..e0c0a80 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -179,6 +179,17 @@ struct flow_offload {
struct rcu_head rcu_head;
};
+struct flow_offload_hw_path {
+ struct net_device *dev;
+ u32 flags;
+
+ u8 eth_src[ETH_ALEN];
+ u8 eth_dest[ETH_ALEN];
+ u16 vlan_proto;
+ u16 vlan_id;
+ u16 pppoe_sid;
+};
+
#define NF_FLOW_TIMEOUT (30 * HZ)
#define nf_flowtable_time_stamp (u32)jiffies

View File

@@ -0,0 +1,63 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 15 Mar 2018 20:49:58 +0100
Subject: [PATCH] net: 8021q: support hardware flow table offload
Add the VLAN ID and protocol information
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index c373f1d..f45abd5 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -27,6 +27,11 @@
#include <linux/phy.h>
#include <net/arp.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
+
#include "vlan.h"
#include "vlanproc.h"
#include <linux/if_vlan.h>
@@ -791,6 +796,27 @@ static int vlan_dev_fill_forward_path(struct net_device_path_ctx *ctx,
return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
+
+ if (path->flags & BIT(DEV_PATH_VLAN))
+ return -EEXIST;
+
+ path->flags |= BIT(DEV_PATH_VLAN);
+ path->vlan_proto = vlan->vlan_proto;
+ path->vlan_id = vlan->vlan_id;
+ path->dev = vlan->real_dev;
+
+ if (vlan->real_dev->netdev_ops->ndo_flow_offload_check)
+ return vlan->real_dev->netdev_ops->ndo_flow_offload_check(path);
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct ethtool_ops vlan_ethtool_ops = {
.get_link_ksettings = vlan_ethtool_get_link_ksettings,
.get_drvinfo = vlan_ethtool_get_drvinfo,
@@ -830,6 +856,9 @@ static const struct net_device_ops vlan_netdev_ops = {
.ndo_fix_features = vlan_dev_fix_features,
.ndo_get_iflink = vlan_dev_get_iflink,
.ndo_fill_forward_path = vlan_dev_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = vlan_dev_flow_offload_check,
+#endif
};
static void vlan_dev_free(struct net_device *dev)

View File

@@ -0,0 +1,63 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 15 Mar 2018 20:50:37 +0100
Subject: [PATCH] net: bridge: support hardware flow table offload
Look up the real device and pass it on
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index 03934dd..094b2b1 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -14,6 +14,10 @@
#include <linux/ethtool.h>
#include <linux/list.h>
#include <linux/netfilter_bridge.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
#include <linux/uaccess.h>
#include "br_private.h"
@@ -440,6 +444,28 @@ static const struct ethtool_ops br_ethtool_ops = {
.get_link = ethtool_op_get_link,
};
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int br_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct net_bridge *br = netdev_priv(dev);
+ struct net_bridge_fdb_entry *dst;
+
+ if (!(path->flags & BIT(DEV_PATH_ETHERNET)))
+ return -EINVAL;
+
+ dst = br_fdb_find_rcu(br, path->eth_dest, path->vlan_id);
+ if (!dst || !dst->dst)
+ return -ENOENT;
+
+ path->dev = dst->dst->dev;
+ if (path->dev->netdev_ops->ndo_flow_offload_check)
+ return path->dev->netdev_ops->ndo_flow_offload_check(path);
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct net_device_ops br_netdev_ops = {
.ndo_open = br_dev_open,
.ndo_stop = br_dev_stop,
@@ -469,6 +495,9 @@ static const struct net_device_ops br_netdev_ops = {
.ndo_bridge_dellink = br_dellink,
.ndo_features_check = passthru_features_check,
.ndo_fill_forward_path = br_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = br_flow_offload_check,
+#endif
};
static struct device_type br_type = {

View File

@@ -0,0 +1,132 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 15 Mar 2018 21:15:00 +0100
Subject: [PATCH] net: pppoe: support hardware flow table offload
Pass on the PPPoE session ID and the remote MAC address
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c
index ec2fbd1..f361b52 100644
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -53,6 +53,11 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
+
#define PPP_VERSION "2.4.2"
/*
@@ -1416,6 +1421,28 @@ static int ppp_fill_forward_path(struct net_device_path_ctx *ctx,
return chan->ops->fill_forward_path(ctx, path, chan);
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int ppp_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct ppp *ppp = netdev_priv(path->dev);
+ struct ppp_channel *chan;
+ struct channel *pch;
+
+ if (ppp->flags & SC_MULTILINK)
+ return -EOPNOTSUPP;
+
+ if (list_empty(&ppp->channels))
+ return -ENODEV;
+
+ pch = list_first_entry(&ppp->channels, struct channel, clist);
+ chan = pch->chan;
+ if (!chan->ops->flow_offload_check)
+ return -EOPNOTSUPP;
+
+ return chan->ops->flow_offload_check(chan, path);
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct net_device_ops ppp_netdev_ops = {
.ndo_init = ppp_dev_init,
.ndo_uninit = ppp_dev_uninit,
@@ -1423,6 +1450,9 @@ static const struct net_device_ops ppp_netdev_ops = {
.ndo_do_ioctl = ppp_net_ioctl,
.ndo_get_stats64 = ppp_get_stats64,
.ndo_fill_forward_path = ppp_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = ppp_flow_offload_check,
+#endif
};
static struct device_type ppp_type = {
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
index 7a8c246..1018464 100644
--- a/drivers/net/ppp/pppoe.c
+++ b/drivers/net/ppp/pppoe.c
@@ -73,6 +73,11 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
+
#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
@@ -997,9 +1002,37 @@ static int pppoe_fill_forward_path(struct net_device_path_ctx *ctx,
return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int pppoe_flow_offload_check(struct ppp_channel *chan,
+ struct flow_offload_hw_path *path)
+{
+ struct sock *sk = (struct sock *)chan->private;
+ struct pppox_sock *po = pppox_sk(sk);
+ struct net_device *dev = po->pppoe_dev;
+
+ if (sock_flag(sk, SOCK_DEAD) ||
+ !(sk->sk_state & PPPOX_CONNECTED) || !dev)
+ return -ENODEV;
+
+ path->dev = po->pppoe_dev;
+ path->flags |= BIT(DEV_PATH_PPPOE);
+ memcpy(path->eth_src, po->pppoe_dev->dev_addr, ETH_ALEN);
+ memcpy(path->eth_dest, po->pppoe_pa.remote, ETH_ALEN);
+ path->pppoe_sid = be16_to_cpu(po->num);
+
+ if (path->dev->netdev_ops->ndo_flow_offload_check)
+ return path->dev->netdev_ops->ndo_flow_offload_check(path);
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct ppp_channel_ops pppoe_chan_ops = {
.start_xmit = pppoe_xmit,
.fill_forward_path = pppoe_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .flow_offload_check = pppoe_flow_offload_check,
+#endif
};
static int pppoe_recvmsg(struct socket *sock, struct msghdr *m,
diff --git a/include/linux/ppp_channel.h b/include/linux/ppp_channel.h
index 91f9a92..4a1729b 100644
--- a/include/linux/ppp_channel.h
+++ b/include/linux/ppp_channel.h
@@ -31,6 +31,9 @@ struct ppp_channel_ops {
int (*fill_forward_path)(struct net_device_path_ctx *,
struct net_device_path *,
const struct ppp_channel *);
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ int (*flow_offload_check)(struct ppp_channel *, struct flow_offload_hw_path *);
+#endif
};
struct ppp_channel {

View File

@@ -0,0 +1,74 @@
From: Felix Fietkau <nbd@nbd.name>
Date: Thu, 17 Sep 2020 18:41:23 +0200
Subject: [PATCH] net: dsa: support hardware flow table offload
Look up the master device and the port id
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index e0c0a80..a1b4ab5 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -188,6 +188,7 @@ struct flow_offload_hw_path {
u16 vlan_proto;
u16 vlan_id;
u16 pppoe_sid;
+ u16 dsa_port;
};
#define NF_FLOW_TIMEOUT (30 * HZ)
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index 2ea9ec1..eab4e4a 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -19,6 +19,10 @@
#include <linux/if_bridge.h>
#include <linux/netpoll.h>
#include <linux/ptp_classify.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
#include "dsa_priv.h"
@@ -1257,6 +1261,27 @@ static int dsa_slave_fill_forward_path(struct net_device_path_ctx *ctx,
return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int dsa_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct dsa_port *dp;
+
+ if (!(path->flags & BIT(DEV_PATH_ETHERNET)))
+ return -EINVAL;
+
+ dp = dsa_slave_to_port(dev);
+ path->dsa_port = dp->index;
+ path->dev = dsa_slave_to_master(dev);
+ path->flags |= BIT(DEV_PATH_DSA);
+
+ if (path->dev->netdev_ops->ndo_flow_offload_check)
+ return path->dev->netdev_ops->ndo_flow_offload_check(path);
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct net_device_ops dsa_slave_netdev_ops = {
.ndo_open = dsa_slave_open,
.ndo_stop = dsa_slave_close,
@@ -1282,6 +1307,9 @@ static const struct net_device_ops dsa_slave_netdev_ops = {
.ndo_vlan_rx_kill_vid = dsa_slave_vlan_rx_kill_vid,
.ndo_get_devlink_port = dsa_slave_get_devlink_port,
.ndo_fill_forward_path = dsa_slave_fill_forward_path,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = dsa_flow_offload_check,
+#endif
};
static struct device_type dsa_type = {

View File

@@ -9,11 +9,9 @@ Subject: [PATCH]
drivers/crypto/inside-secure/safexcel.h | 15 ++++++
2 files changed, 78 insertions(+), 6 deletions(-)
diff --git a/drivers/crypto/inside-secure/safexcel.c b/drivers/crypto/inside-secure/safexcel.c
index 647c5a0c1..6f4fc15b7 100644
--- a/drivers/crypto/inside-secure/safexcel.c
+++ b/drivers/crypto/inside-secure/safexcel.c
@@ -304,6 +304,11 @@ static void eip197_init_firmware(struct safexcel_crypto_priv *priv)
@@ -304,6 +304,11 @@ static void eip197_init_firmware(struct
/* Enable access to all IFPP program memories */
writel(EIP197_PE_ICE_RAM_CTRL_FPP_PROG_EN,
EIP197_PE(priv) + EIP197_PE_ICE_RAM_CTRL(pe));
@@ -25,7 +23,7 @@ index 647c5a0c1..6f4fc15b7 100644
}
}
@@ -403,13 +408,13 @@ static int eip197_load_firmwares(struct safexcel_crypto_priv *priv)
@@ -403,13 +408,13 @@ static int eip197_load_firmwares(struct
const struct firmware *fw[FW_NB];
char fw_path[37], *dir = NULL;
int i, j, ret = 0, pe;
@@ -51,7 +49,7 @@ index 647c5a0c1..6f4fc15b7 100644
if (eip197_start_firmware(priv, ipuesz, ifppsz, minifw)) {
dev_dbg(priv->dev, "Firmware loaded successfully\n");
return 0;
@@ -592,6 +600,11 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
@@ -592,6 +600,11 @@ static int safexcel_hw_init(struct safex
*/
if (priv->flags & SAFEXCEL_HW_EIP197) {
val = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
@@ -63,7 +61,7 @@ index 647c5a0c1..6f4fc15b7 100644
val |= EIP197_MST_CTRL_TX_MAX_CMD(5);
writel(val, EIP197_HIA_AIC(priv) + EIP197_HIA_MST_CTRL);
}
@@ -792,6 +805,12 @@ static int safexcel_hw_init(struct safexcel_crypto_priv *priv)
@@ -792,6 +805,12 @@ static int safexcel_hw_init(struct safex
return ret;
}
@@ -76,7 +74,7 @@ index 647c5a0c1..6f4fc15b7 100644
return safexcel_hw_setup_cdesc_rings(priv) ?:
safexcel_hw_setup_rdesc_rings(priv) ?:
0;
@@ -1498,6 +1517,9 @@ static int safexcel_probe_generic(void *pdev,
@@ -1503,6 +1522,9 @@ static int safexcel_probe_generic(void *
hwopt = readl(EIP197_GLOBAL(priv) + EIP197_OPTIONS);
hiaopt = readl(EIP197_HIA_AIC(priv) + EIP197_HIA_OPTIONS);
@@ -86,7 +84,7 @@ index 647c5a0c1..6f4fc15b7 100644
if (priv->flags & SAFEXCEL_HW_EIP197) {
/* EIP197 */
peopt = readl(EIP197_PE(priv) + EIP197_PE_OPTIONS(0));
@@ -1516,8 +1538,37 @@ static int safexcel_probe_generic(void *pdev,
@@ -1521,8 +1543,37 @@ static int safexcel_probe_generic(void *
EIP197_N_RINGS_MASK;
if (hiaopt & EIP197_HIA_OPT_HAS_PE_ARB)
priv->flags |= EIP197_PE_ARB;
@@ -125,7 +123,7 @@ index 647c5a0c1..6f4fc15b7 100644
/* If not a full TRC, then assume simple TRC */
if (!(hwopt & EIP197_OPT_HAS_TRC))
priv->flags |= EIP197_SIMPLE_TRC;
@@ -1555,13 +1606,14 @@ static int safexcel_probe_generic(void *pdev,
@@ -1560,13 +1611,14 @@ static int safexcel_probe_generic(void *
EIP197_PE_EIP96_OPTIONS(0));
/* Print single info line describing what we just detected */
@@ -142,29 +140,6 @@ index 647c5a0c1..6f4fc15b7 100644
safexcel_configure(priv);
@@ -1690,6 +1742,7 @@ static int safexcel_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct safexcel_crypto_priv *priv;
+ struct resource *res;
int ret;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
@@ -1701,7 +1754,11 @@ static int safexcel_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- priv->base = devm_platform_ioremap_resource(pdev, 0);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -EINVAL;
+
+ priv->base = devm_ioremap(dev, res->start, resource_size(res));
if (IS_ERR(priv->base)) {
dev_err(dev, "failed to get resource\n");
return PTR_ERR(priv->base);
diff --git a/drivers/crypto/inside-secure/safexcel.h b/drivers/crypto/inside-secure/safexcel.h
index c031c197e..e9909c336 100644
--- a/drivers/crypto/inside-secure/safexcel.h
+++ b/drivers/crypto/inside-secure/safexcel.h
@@ -22,6 +22,7 @@
@@ -217,7 +192,7 @@ index c031c197e..e9909c336 100644
/* EIP197_STRC_CONFIG */
#define EIP197_STRC_CONFIG_INIT BIT(31)
#define EIP197_STRC_CONFIG_LARGE_REC(s) (s<<8)
@@ -777,6 +788,7 @@ enum safexcel_flags {
@@ -780,6 +791,7 @@ enum safexcel_flags {
EIP197_PE_ARB = BIT(2),
EIP197_ICE = BIT(3),
EIP197_SIMPLE_TRC = BIT(4),
@@ -225,7 +200,7 @@ index c031c197e..e9909c336 100644
};
struct safexcel_hwconfig {
@@ -784,7 +796,10 @@ struct safexcel_hwconfig {
@@ -787,7 +799,10 @@ struct safexcel_hwconfig {
int hwver;
int hiaver;
int ppver;
@@ -236,6 +211,3 @@ index c031c197e..e9909c336 100644
int hwdataw;
int hwcfsize;
int hwrfsize;
--
2.34.1

View File

@@ -0,0 +1,152 @@
From fd6e50fdeb1d943b889a5aa093790a798ae598d3 Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Fri, 2 Jun 2023 13:06:29 +0800
Subject: [PATCH]
[networking][999-2708-mtkhnat-add-support-for-virtual-interface-acceleration.patch]
---
include/linux/netdevice.h | 1 +
include/net/netfilter/nf_flow_table.h | 1 +
net/8021q/vlan_dev.c | 1 +
net/ipv6/ip6_tunnel.c | 24 ++++++++++++++++++++++++
net/ipv6/sit.c | 24 ++++++++++++++++++++++++
5 files changed, 51 insertions(+)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index b60b506..c30952f 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -849,6 +849,8 @@ enum net_device_path_type {
DEV_PATH_BRIDGE,
DEV_PATH_PPPOE,
DEV_PATH_DSA,
+ DEV_PATH_DSLITE,
+ DEV_PATH_6RD,
};
struct net_device_path {
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index a1b4ab5..7a2945e 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -181,6 +181,7 @@ struct flow_offload {
struct flow_offload_hw_path {
struct net_device *dev;
+ struct net_device *virt_dev;
u32 flags;
u8 eth_src[ETH_ALEN];
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index f45abd5..db5867d 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -808,6 +808,7 @@ static int vlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
path->flags |= BIT(DEV_PATH_VLAN);
path->vlan_proto = vlan->vlan_proto;
path->vlan_id = vlan->vlan_id;
+ path->virt_dev = dev;
path->dev = vlan->real_dev;
if (vlan->real_dev->netdev_ops->ndo_flow_offload_check)
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c
index 2e8a528..0bf25b0 100644
--- a/net/ipv6/ip6_tunnel.c
+++ b/net/ipv6/ip6_tunnel.c
@@ -57,6 +57,11 @@
#include <net/netns/generic.h>
#include <net/dst_metadata.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
+
MODULE_AUTHOR("Ville Nuorvala");
MODULE_DESCRIPTION("IPv6 tunneling device");
MODULE_LICENSE("GPL");
@@ -1889,6 +1894,22 @@ int ip6_tnl_get_iflink(const struct net_device *dev)
}
EXPORT_SYMBOL(ip6_tnl_get_iflink);
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int ipip6_dev_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct ip6_tnl *tnl = netdev_priv(dev);
+
+ if (path->flags & BIT(DEV_PATH_DSLITE))
+ return -EEXIST;
+
+ path->flags |= BIT(DEV_PATH_DSLITE);
+ path->dev = tnl->dev;
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
int ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops,
unsigned int num)
{
@@ -1950,6 +1971,9 @@ static const struct net_device_ops ip6_tnl_netdev_ops = {
.ndo_change_mtu = ip6_tnl_change_mtu,
.ndo_get_stats = ip6_get_stats,
.ndo_get_iflink = ip6_tnl_get_iflink,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = ipip6_dev_flow_offload_check,
+#endif
};
#define IPXIPX_FEATURES (NETIF_F_SG | \
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 8d704ea..c50bbef 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -52,6 +52,11 @@
#include <net/net_namespace.h>
#include <net/netns/generic.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
+
/*
This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c
@@ -1344,6 +1349,22 @@ ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
return err;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int ipip6_dev_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct ip_tunnel *tnl = netdev_priv(dev);
+
+ if (path->flags & BIT(DEV_PATH_6RD))
+ return -EEXIST;
+
+ path->flags |= BIT(DEV_PATH_6RD);
+ path->dev = tnl->dev;
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct net_device_ops ipip6_netdev_ops = {
.ndo_init = ipip6_tunnel_init,
.ndo_uninit = ipip6_tunnel_uninit,
@@ -1351,6 +1372,9 @@ static const struct net_device_ops ipip6_netdev_ops = {
.ndo_do_ioctl = ipip6_tunnel_ioctl,
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = ipip6_dev_flow_offload_check,
+#endif
};
static void ipip6_dev_free(struct net_device *dev)
--
2.34.1

View File

@@ -0,0 +1,44 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -592,27 +592,7 @@ config MESON_GXL_PHY
---help---
Currently has a driver for the Amlogic Meson GXL Internal PHY
-config MEDIATEK_GE_PHY
- tristate "MediaTek Gigabit Ethernet PHYs"
- help
- Supports the MediaTek Gigabit Ethernet PHYs.
-
-config MEDIATEK_GE_SOC_PHY
- bool "MediaTek SoC Ethernet PHYs"
- depends on (ARM64 && ARCH_MEDIATEK) || COMPILE_TEST
- select NVMEM_MTK_EFUSE
- help
- Supports MediaTek SoC built-in Gigabit Ethernet PHYs.
-
- Include support for built-in Ethernet PHYs which are present in
- the MT7981 and MT7988 SoCs. These PHYs need calibration data
- present in the SoCs efuse and will dynamically calibrate VCM
- (common-mode voltage) during startup.
-
-config MEDIATEK_2P5GE_PHY
- tristate "MediaTek 2.5Gb Ethernet PHYs"
- ---help---
- Supports MediaTek internal 2.5Gb Ethernet PHYs.
+source "drivers/net/phy/mediatek/Kconfig"
config MICREL_PHY
tristate "Micrel PHYs"
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -105,9 +105,7 @@ obj-$(CONFIG_LXT_PHY) += lxt.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_MARVELL_10G_PHY) += marvell10g.o
obj-$(CONFIG_MAXLINEAR_GPHY) += mxl-gpy.o
-obj-$(CONFIG_MEDIATEK_GE_PHY) += mediatek-ge.o
-obj-$(CONFIG_MEDIATEK_GE_SOC_PHY) += mediatek-ge-soc.o
-obj-$(CONFIG_MEDIATEK_2P5GE_PHY)+= mediatek-2p5ge.o
+obj-y += mediatek/
obj-$(CONFIG_MESON_GXL_PHY) += meson-gxl.o
obj-$(CONFIG_MICREL_KS8995MA) += spi_ks8995.o
obj-$(CONFIG_MICREL_PHY) += micrel.o

View File

@@ -153,7 +153,7 @@ new file mode 100644
index 000000000..d2828aad4
--- /dev/null
+++ b/drivers/net/phy/aquantia_firmware.c
@@ -0,0 +1,1109 @@
@@ -0,0 +1,1110 @@
+// SPDX-License-Identifier: GPL-2.0
+/* FW download driver for Aquantia PHY
+ */
@@ -1227,7 +1227,6 @@ index 000000000..d2828aad4
+ PTR_ERR(gangload_kthread));
+ return PTR_ERR(gangload_kthread);
+ }
+ wake_up_process(gangload_kthread);
+ }
+
+ for (i = 0; i < gangload; i++) {
@@ -1250,6 +1249,8 @@ index 000000000..d2828aad4
+ gangload_phydevs[gangload] = phydev;
+ gangload++;
+
+ wake_up_process(gangload_kthread);
+
+ return 0;
+}
+

View File

@@ -0,0 +1,66 @@
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c30952f..6c0860b 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -851,6 +851,7 @@ enum net_device_path_type {
DEV_PATH_DSA,
DEV_PATH_DSLITE,
DEV_PATH_6RD,
+ DEV_PATH_TNL,
};
struct net_device_path {
diff --git a/net/l2tp/l2tp_ppp.c b/net/l2tp/l2tp_ppp.c
index 7d3c782..d7a5a9a 100644
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -89,6 +89,7 @@
#include <linux/nsproxy.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
+#include <net/netfilter/nf_flow_table.h>
#include <net/ip.h>
#include <net/udp.h>
#include <net/inet_common.h>
@@ -124,9 +125,14 @@ struct pppol2tp_session {
};
static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb);
+static int l2tp_ppp_flow_offload_check(struct ppp_channel *chan,
+ struct flow_offload_hw_path *path);
static const struct ppp_channel_ops pppol2tp_chan_ops = {
.start_xmit = pppol2tp_xmit,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .flow_offload_check = l2tp_ppp_flow_offload_check,
+#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
};
static const struct proto_ops pppol2tp_ops;
@@ -335,6 +341,26 @@ static int pppol2tp_sendmsg(struct socket *sock, struct msghdr *m,
return error;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int l2tp_ppp_flow_offload_check(struct ppp_channel *chan,
+ struct flow_offload_hw_path *path)
+{
+ struct sock *sk = (struct sock *)chan->private;
+ struct l2tp_session *session;
+
+ if (path->flags & BIT(DEV_PATH_TNL))
+ return -EEXIST;
+
+ session = pppol2tp_sock_to_session(sk);
+ if (!session)
+ return -EINVAL;
+
+ path->flags |= BIT(DEV_PATH_TNL);
+
+ return 0;
+}
+#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
+
/* Transmit function called by generic PPP driver. Sends PPP frame
* over PPPoL2TP socket.
*

View File

@@ -6,9 +6,9 @@ Subject: [PATCH] 999-2727-net-phy-sfp-add-debug-info.patch
---
drivers/net/phy/phylink.c | 11 +++++++-
drivers/net/phy/sfp-bus.c | 3 +++
drivers/net/phy/sfp.c | 51 +++++++++++++++++++++++++++++------
drivers/net/phy/sfp.c | 50 +++++++++++++++++++++++++++++------
include/linux/mdio/mdio-i2c.h | 16 +++++++++++
4 files changed, 72 insertions(+), 9 deletions(-)
4 files changed, 71 insertions(+), 9 deletions(-)
diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
index 949e3b8..bb4cd28 100644
@@ -141,11 +141,10 @@ index 0fdf5d6..0c335b1 100644
err = sfp_add_phy(sfp->sfp_bus, phy);
if (err) {
phy_device_remove(phy);
@@ -1779,6 +1810,10 @@ static int sfp_sm_add_mdio_bus(struct sfp *sfp)
@@ -1779,6 +1810,9 @@ static int sfp_sm_add_mdio_bus(struct sfp *sfp)
static int sfp_sm_probe_for_phy(struct sfp *sfp)
{
int err = 0;
+ struct phy_device *phy;
+
+ dev_info(sfp->dev, "probing phy device through the [%s] protocol\n",
+ mdio_i2c_proto_type(sfp->mdio_protocol));

View File

@@ -0,0 +1,88 @@
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -410,7 +410,7 @@ static int xfrm_output_one(struct sk_buf
struct xfrm_state *x = dst->xfrm;
struct net *net = xs_net(x);
- if (err <= 0 || x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
+ if (err <= 0)
goto resume;
do {
@@ -570,12 +570,10 @@ int xfrm_output(struct sock *sk, struct
if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET) {
if (!xfrm_dev_offload_ok(skb, x)) {
- XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR);
- kfree_skb(skb);
- return -EHOSTUNREACH;
+ secpath_reset(skb);
+ goto sw_path;
}
-
- return xfrm_output_resume(skb, 0);
+ return 0;
}
secpath_reset(skb);
@@ -606,6 +604,7 @@ int xfrm_output(struct sock *sk, struct
if (x->xso.dev && x->xso.dev->features & NETIF_F_HW_ESP_TX_CSUM)
goto out;
} else {
+sw_path:
if (skb_is_gso(skb))
return xfrm_output_gso(net, sk, skb);
}
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -3701,6 +3701,10 @@ int __xfrm_policy_check(struct sock *sk,
}
}
#endif
+ /* Inbound HW offload packets, pass the check directly */
+ if (pol->xdo.type == XFRM_DEV_OFFLOAD_PACKET &&
+ (pol->xdo.dir == XFRM_DEV_OFFLOAD_IN || pol->xdo.dir == XFRM_DEV_OFFLOAD_FWD))
+ return 1;
if (pol->action == XFRM_POLICY_ALLOW) {
static struct sec_path dummy;
@@ -3710,6 +3714,14 @@ int __xfrm_policy_check(struct sock *sk,
int ti = 0;
int i, k;
+ /* Strongswan install FWD policy for inbound HW offload
+ * packets. But cannot find corresponding packet offload
+ * state here and will be drop. So, we bypass following
+ * check for FWD policy with acction allow.
+ */
+ if (dir == XFRM_POLICY_FWD)
+ return 1;
+
sp = skb_sec_path(skb);
if (!sp)
sp = &dummy;
--- a/net/xfrm/xfrm_device.c
+++ b/net/xfrm/xfrm_device.c
@@ -215,8 +215,8 @@ int xfrm_dev_state_add(struct net *net,
if (!x->type_offload)
return -EINVAL;
- /* We don't yet support UDP encapsulation and TFC padding. */
- if (x->encap || x->tfcpad)
+ /* We don't yet support TFC padding. */
+ if (x->tfcpad)
return -EINVAL;
if (xuo->flags &
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -653,6 +653,9 @@ static netdev_features_t vlan_dev_fix_fe
features |= old_features & (NETIF_F_SOFT_FEATURES | NETIF_F_GSO_SOFTWARE);
features |= NETIF_F_LLTX;
+ if (old_features & NETIF_F_HW_ESP)
+ features |= NETIF_F_HW_ESP;
+
return features;
}

View File

@@ -1,14 +0,0 @@
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -686,7 +686,10 @@ static void phylink_link_up(struct phyli
* the link_state) to the interface speed, and will send
* pause frames to the MAC to limit its transmission speed.
*/
- speed = phylink_interface_max_speed(link_state.interface);
+ /* For tunnel HW offload, we need to get true link rate to
+ * set QDMA rate limit as link rate.
+ */
+ // speed = phylink_interface_max_speed(link_state.interface);
duplex = DUPLEX_FULL;
rx_pause = true;
break;

View File

@@ -1,16 +1,4 @@
From 90508a46a0fd6416dcaad2c7f0ef25a5a421bf4f Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Fri, 2 Jun 2023 13:06:00 +0800
Subject: [PATCH]
[backport-networking-drivers][999-1706-net-dsa-support-mt7988.patch]
---
drivers/net/dsa/mt7530.c | 191 ++++++++++++++++++++++++++++++++-------
drivers/net/dsa/mt7530.h | 11 ++-
2 files changed, 164 insertions(+), 38 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 63f8a632b..2cd5dae9c 100644
===================================================================
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -19,6 +19,7 @@
@@ -21,7 +9,7 @@ index 63f8a632b..2cd5dae9c 100644
#include "mt7530.h"
#include "mt7530_nl.h"
@@ -170,28 +171,44 @@ core_clear(struct mt7530_priv *priv, u32 reg, u32 val)
@@ -170,28 +171,44 @@ core_clear(struct mt7530_priv *priv, u32
core_rmw(priv, reg, val, 0);
}
@@ -43,12 +31,21 @@ index 63f8a632b..2cd5dae9c 100644
struct mii_bus *bus = priv->bus;
u16 page, r, lo, hi;
- int ret;
+ int ret = 0;
-
- page = (reg >> 6) & 0x3ff;
- r = (reg >> 2) & 0xf;
- lo = val & 0xffff;
- hi = val >> 16;
-
- /* MT7530 uses 31 as the pseudo port */
- ret = bus->write(bus, 0x1f, 0x1f, page);
- if (ret < 0)
- goto err;
+ int ret = 0;
- ret = bus->write(bus, 0x1f, r, lo);
- if (ret < 0)
- goto err;
+ if (priv->direct_access){
+ mtk_w32(priv, val, reg);
+ } else {
@@ -56,19 +53,12 @@ index 63f8a632b..2cd5dae9c 100644
+ r = (reg >> 2) & 0xf;
+ lo = val & 0xffff;
+ hi = val >> 16;
- /* MT7530 uses 31 as the pseudo port */
- ret = bus->write(bus, 0x1f, 0x1f, page);
- if (ret < 0)
- goto err;
+
+ /* MT7530 uses 31 as the pseudo port */
+ ret = bus->write(bus, 0x1f, 0x1f, page);
+ if (ret < 0)
+ goto err;
- ret = bus->write(bus, 0x1f, r, lo);
- if (ret < 0)
- goto err;
+
+ ret = bus->write(bus, 0x1f, r, lo);
+ if (ret < 0)
+ goto err;
@@ -79,7 +69,7 @@ index 63f8a632b..2cd5dae9c 100644
err:
if (ret < 0)
dev_err(&bus->dev,
@@ -206,21 +223,25 @@ mt7530_mii_read(struct mt7530_priv *priv, u32 reg)
@@ -206,21 +223,25 @@ mt7530_mii_read(struct mt7530_priv *priv
u16 page, r, lo, hi;
int ret;
@@ -117,7 +107,7 @@ index 63f8a632b..2cd5dae9c 100644
}
void
@@ -1907,9 +1928,9 @@ mt7531_phy_supported(struct dsa_switch *ds, int port,
@@ -1907,9 +1928,9 @@ mt7531_phy_supported(struct dsa_switch *
if (mt7531_is_rgmii_port(priv, port))
return phy_interface_mode_is_rgmii(state->interface);
fallthrough;
@@ -130,7 +120,7 @@ index 63f8a632b..2cd5dae9c 100644
goto unsupported;
break;
default:
@@ -2018,6 +2039,13 @@ static void mt7531_sgmii_validate(struct mt7530_priv *priv, int port,
@@ -2018,6 +2039,13 @@ static void mt7531_sgmii_validate(struct
phylink_set(supported, 1000baseX_Full);
phylink_set(supported, 2500baseX_Full);
phylink_set(supported, 2500baseT_Full);
@@ -144,7 +134,7 @@ index 63f8a632b..2cd5dae9c 100644
}
}
@@ -2166,6 +2194,8 @@ mt7531_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
@@ -2166,6 +2194,8 @@ mt7531_mac_config(struct dsa_switch *ds,
case PHY_INTERFACE_MODE_NA:
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX:
@@ -153,7 +143,7 @@ index 63f8a632b..2cd5dae9c 100644
if (phylink_autoneg_inband(mode))
return -EINVAL;
@@ -2303,8 +2333,8 @@ static void mt753x_phylink_mac_link_up(struct dsa_switch *ds, int port,
@@ -2303,8 +2333,8 @@ static void mt753x_phylink_mac_link_up(s
/* MT753x MAC works in 1G full duplex mode for all up-clocked
* variants.
*/
@@ -164,7 +154,25 @@ index 63f8a632b..2cd5dae9c 100644
speed = SPEED_1000;
duplex = DUPLEX_FULL;
}
@@ -2403,8 +2433,8 @@ mt753x_phylink_validate(struct dsa_switch *ds, int port,
@@ -2336,7 +2366,7 @@ static int
mt7531_cpu_port_config(struct dsa_switch *ds, int port)
{
struct mt7530_priv *priv = ds->priv;
- phy_interface_t interface;
+ phy_interface_t interface = PHY_INTERFACE_MODE_NA;
int speed;
switch (port) {
@@ -2356,6 +2386,8 @@ mt7531_cpu_port_config(struct dsa_switch
priv->p6_interface = interface;
break;
};
+ if (interface == PHY_INTERFACE_MODE_NA)
+ dev_err(priv->dev, "invalid interface\n");
if (interface == PHY_INTERFACE_MODE_2500BASEX)
speed = SPEED_2500;
@@ -2403,8 +2435,8 @@ mt753x_phylink_validate(struct dsa_switc
phylink_set_port_modes(mask);
@@ -175,7 +183,7 @@ index 63f8a632b..2cd5dae9c 100644
phylink_set(mask, 10baseT_Half);
phylink_set(mask, 10baseT_Full);
phylink_set(mask, 100baseT_Half);
@@ -2608,6 +2638,66 @@ mt753x_phy_write(struct dsa_switch *ds, int port, int regnum, u16 val)
@@ -2608,6 +2640,74 @@ mt753x_phy_write(struct dsa_switch *ds,
return priv->info->phy_write(ds, port, regnum, val);
}
@@ -191,10 +199,18 @@ index 63f8a632b..2cd5dae9c 100644
+ struct mt7530_priv *priv = ds->priv;
+ u32 unused_pm = 0;
+ int ret, i;
+ struct regmap *reset;
+
+ /* Reset the switch through internal reset */
+ mt7530_write(priv, MT7530_SYS_CTRL,
+ SYS_CTRL_PHY_RST | SYS_CTRL_SW_RST);
+ reset = syscon_regmap_lookup_by_phandle(priv->dev->of_node, "mediatek,sysctrl");
+ if (IS_ERR(reset)) {
+ dev_err(priv->dev, "Reset failed\n");
+ return -ENODEV;
+ }
+ regmap_write(reset, 8, 0x200);
+ udelay(20);
+ regmap_write(reset, 8, 0);
+ udelay(20);
+
+ /* BPDU to CPU port */
+ mt7530_rmw(priv, MT7531_CFC, MT7531_CPU_PMAP_MASK,
@@ -242,7 +258,7 @@ index 63f8a632b..2cd5dae9c 100644
static const struct dsa_switch_ops mt7530_switch_ops = {
.get_tag_protocol = mtk_get_tag_protocol,
.setup = mt753x_setup,
@@ -2677,12 +2767,28 @@ static const struct mt753x_info mt753x_table[] = {
@@ -2677,12 +2777,28 @@ static const struct mt753x_info mt753x_t
.mac_pcs_an_restart = mt7531_sgmii_restart_an,
.mac_pcs_link_up = mt7531_sgmii_link_up_force,
},
@@ -271,7 +287,7 @@ index 63f8a632b..2cd5dae9c 100644
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, mt7530_of_match);
@@ -2692,6 +2798,7 @@ mt7530_probe(struct mdio_device *mdiodev)
@@ -2692,6 +2808,7 @@ mt7530_probe(struct mdio_device *mdiodev
{
struct mt7530_priv *priv;
struct device_node *dn;
@@ -279,7 +295,7 @@ index 63f8a632b..2cd5dae9c 100644
int ret;
dn = mdiodev->dev.of_node;
@@ -2761,6 +2868,16 @@ mt7530_probe(struct mdio_device *mdiodev)
@@ -2761,6 +2878,16 @@ mt7530_probe(struct mdio_device *mdiodev
}
}
@@ -296,7 +312,7 @@ index 63f8a632b..2cd5dae9c 100644
priv->bus = mdiodev->bus;
priv->dev = &mdiodev->dev;
priv->ds->priv = priv;
@@ -2769,9 +2886,12 @@ mt7530_probe(struct mdio_device *mdiodev)
@@ -2769,9 +2896,12 @@ mt7530_probe(struct mdio_device *mdiodev
dev_set_drvdata(&mdiodev->dev, priv);
ret = dsa_register_switch(priv->ds);
@@ -311,7 +327,7 @@ index 63f8a632b..2cd5dae9c 100644
mt7530_nl_init(&priv);
return 0;
@@ -2796,6 +2916,9 @@ mt7530_remove(struct mdio_device *mdiodev)
@@ -2796,6 +2926,9 @@ mt7530_remove(struct mdio_device *mdiode
dsa_unregister_switch(priv->ds);
mutex_destroy(&priv->reg_mutex);
@@ -321,8 +337,7 @@ index 63f8a632b..2cd5dae9c 100644
mt7530_nl_exit();
}
diff --git a/drivers/net/dsa/mt7530.h b/drivers/net/dsa/mt7530.h
index 130d7e5ec..7b175c5f2 100644
===================================================================
--- a/drivers/net/dsa/mt7530.h
+++ b/drivers/net/dsa/mt7530.h
@@ -16,6 +16,7 @@ enum mt753x_id {
@@ -366,6 +381,3 @@ index 130d7e5ec..7b175c5f2 100644
const struct mt753x_info *info;
unsigned int id;
bool mcm;
--
2.34.1

View File

@@ -1,18 +1,7 @@
From c816d165754d8fd002478cce6eb774b9390c795f Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Fri, 2 Jun 2023 13:06:01 +0800
Subject: [PATCH]
[backport-networking-drivers][999-1707-add-mdio-bus-for-gphy-calibration.patch]
---
drivers/net/dsa/mt7530.c | 115 +++++++++++++++++++++++++++++++++++++++
1 file changed, 115 insertions(+)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 2cd5dae9c..290a2e77a 100644
===================================================================
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -847,6 +847,117 @@ mt7531_ind_phy_write(struct dsa_switch *ds, int port, int regnum,
@@ -847,6 +847,117 @@ mt7531_ind_phy_write(struct dsa_switch *
return ret;
}
@@ -130,7 +119,7 @@ index 2cd5dae9c..290a2e77a 100644
static void
mt7530_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data)
@@ -2695,6 +2806,10 @@ mt7988_setup(struct dsa_switch *ds)
@@ -2705,6 +2816,10 @@ mt7988_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
@@ -141,6 +130,3 @@ index 2cd5dae9c..290a2e77a 100644
return 0;
}
--
2.34.1

View File

@@ -4,32 +4,9 @@ Date: Fri, 2 Jun 2023 13:06:32 +0800
Subject: [PATCH] [networking][999-2720-net-dsa-phy-coverity-scan.patch]
---
drivers/net/dsa/mt7530.c | 4 ++-
drivers/net/dsa/mt7531_phy.c | 56 +++++++++++++++++++-----------------
2 files changed, 32 insertions(+), 28 deletions(-)
1 files changed, 32 insertions(+), 28 deletions(-)
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index 290a2e77a..21fa3e300 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
@@ -2477,7 +2477,7 @@ static int
mt7531_cpu_port_config(struct dsa_switch *ds, int port)
{
struct mt7530_priv *priv = ds->priv;
- phy_interface_t interface;
+ phy_interface_t interface = PHY_INTERFACE_MODE_NA;
int speed;
switch (port) {
@@ -2497,6 +2497,8 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port)
priv->p6_interface = interface;
break;
};
+ if (interface == PHY_INTERFACE_MODE_NA)
+ dev_err(priv->dev, "invalid interface\n");
if (interface == PHY_INTERFACE_MODE_2500BASEX)
speed = SPEED_2500;
diff --git a/drivers/net/dsa/mt7531_phy.c b/drivers/net/dsa/mt7531_phy.c
index a5c1e7d54..aaa03c678 100644
--- a/drivers/net/dsa/mt7531_phy.c

View File

@@ -1,3 +1,15 @@
From 535fdc6dfce7def996a5188819ffc96231c36f98 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 2 Jan 2024 18:13:43 +0800
Subject: [PATCH] [networking][999-2738-an8801sb-gphy-support.patch]
---
drivers/net/phy/Kconfig | 5 +
drivers/net/phy/Makefile | 1 +
2 files changed, 6 insertions(+)
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index ccd3f3f..5dbfb17 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -345,6 +345,11 @@ config SFP
@@ -12,6 +24,8 @@
config AIROHA_EN8801SC_PHY
tristate "Drivers for Airoha EN8801S Gigabit PHYs for MediaTek SoC."
---help---
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index 1e8d67b..d39e54b 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -74,6 +74,7 @@ endif
@@ -22,64 +36,6 @@
obj-$(CONFIG_AIROHA_EN8801SC_PHY) += en8801sc.o
air_en8811h-y := air_en8811h_main.o air_en8811h_api.o
obj-$(CONFIG_AIROHA_EN8811H_PHY) += air_en8811h.o
--- a/drivers/net/phy/phylink.c
+++ b/drivers/net/phy/phylink.c
@@ -870,12 +870,17 @@
of_node_put(phy_node);
if (!phy_dev)
- return -ENODEV;
-
+ {
+ phylink_info(pl, "[phylink] reload phy-handle2. %s %d\n",__func__, __LINE__);
+ phy_node = of_parse_phandle(dn, "phy-handle2", 0);
+ phy_dev = of_phy_attach(pl->netdev, phy_node, flags, pl->link_interface);
+ if (!phy_dev)
+ return -ENODEV;
+ }
+
ret = phylink_bringup_phy(pl, phy_dev, pl->link_config.interface);
if (ret)
phy_detach(phy_dev);
-
return ret;
}
EXPORT_SYMBOL_GPL(phylink_of_phy_connect);
--- a/drivers/of/of_mdio.c
+++ b/drivers/of/of_mdio.c
@@ -226,7 +226,9 @@
return rc;
/* Loop over the child nodes and register a phy_device for each phy */
+ int an8801=0;
for_each_available_child_of_node(np, child) {
+ if(an8801==1)break;
addr = of_mdio_parse_addr(&mdio->dev, child);
if (addr < 0) {
scanphys = true;
@@ -234,7 +236,25 @@
}
if (of_mdiobus_child_is_phy(child))
+ {
+ if(addr==30)
+ {
+ int phy_id ;
+
+ phy_id = mdiobus_read(mdio, addr, MII_PHYSID1) << 16 ;
+ phy_id = phy_id + mdiobus_read(mdio, addr, MII_PHYSID2);
+ dev_info(&mdio->dev, "[of_mdio] %s %d addr:%d phy_id:0x%x \n",__func__, __LINE__, addr, phy_id);
+
+ if (phy_id==0 || phy_id==0x1a750000)
+ {
+ dev_info(&mdio->dev, "[of_mdio] %s %d continue \n",__func__, __LINE__);
+ continue;
+ }
+ else
+ an8801=1;
+ }
rc = of_mdiobus_register_phy(mdio, child, addr);
+ }
else
rc = of_mdiobus_register_device(mdio, child, addr);
--
2.18.0

View File

@@ -0,0 +1,397 @@
--- a/drivers/crypto/inside-secure/safexcel.c
+++ b/drivers/crypto/inside-secure/safexcel.c
@@ -1222,6 +1222,7 @@ static struct safexcel_alg_template *saf
&safexcel_alg_cfb_aes,
&safexcel_alg_ofb_aes,
&safexcel_alg_ctr_aes,
+ &safexcel_alg_basic_ctr_aes,
&safexcel_alg_md5,
&safexcel_alg_sha1,
&safexcel_alg_sha224,
--- a/drivers/crypto/inside-secure/safexcel.h
+++ b/drivers/crypto/inside-secure/safexcel.h
@@ -930,6 +930,7 @@ extern struct safexcel_alg_template safe
extern struct safexcel_alg_template safexcel_alg_cfb_aes;
extern struct safexcel_alg_template safexcel_alg_ofb_aes;
extern struct safexcel_alg_template safexcel_alg_ctr_aes;
+extern struct safexcel_alg_template safexcel_alg_basic_ctr_aes;
extern struct safexcel_alg_template safexcel_alg_md5;
extern struct safexcel_alg_template safexcel_alg_sha1;
extern struct safexcel_alg_template safexcel_alg_sha224;
--- a/drivers/crypto/inside-secure/safexcel_cipher.c
+++ b/drivers/crypto/inside-secure/safexcel_cipher.c
@@ -51,6 +51,8 @@ struct safexcel_cipher_ctx {
u8 xcm; /* 0=authenc, 1=GCM, 2 reserved for CCM */
u8 aadskip;
u8 blocksz;
+ bool basic_ctr;
+ u32 processed;
u32 ivmask;
u32 ctrinit;
@@ -79,7 +81,7 @@ struct safexcel_cipher_req {
static int safexcel_skcipher_iv(struct safexcel_cipher_ctx *ctx, u8 *iv,
struct safexcel_command_desc *cdesc)
{
- if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD) {
+ if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD && !(ctx->basic_ctr)) {
cdesc->control_data.options |= EIP197_OPTION_4_TOKEN_IV_CMD;
/* 32 bit nonce */
cdesc->control_data.token[0] = ctx->nonce;
@@ -513,8 +515,8 @@ static int safexcel_aead_setkey(struct c
memcpy(ctx->opad, &ostate.state, ctx->state_sz);
memzero_explicit(&keys, sizeof(keys));
- return 0;
+ return 0;
badkey:
memzero_explicit(&keys, sizeof(keys));
return err;
@@ -622,6 +624,43 @@ static int safexcel_context_control(stru
return 0;
}
+static int safexcel_queue_req(struct crypto_async_request *base,
+ struct safexcel_cipher_req *sreq,
+ enum safexcel_cipher_direction dir)
+{
+ struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
+ struct safexcel_crypto_priv *priv = ctx->priv;
+ int ret, ring;
+
+ sreq->needs_inv = false;
+ sreq->direction = dir;
+
+ if (ctx->base.ctxr) {
+ if (priv->flags & EIP197_TRC_CACHE && ctx->base.needs_inv) {
+ sreq->needs_inv = true;
+ ctx->base.needs_inv = false;
+ }
+ } else {
+ ctx->base.ring = safexcel_select_ring(priv);
+ ctx->base.ctxr = dma_pool_zalloc(priv->context_pool,
+ EIP197_GFP_FLAGS(*base),
+ &ctx->base.ctxr_dma);
+ if (!ctx->base.ctxr)
+ return -ENOMEM;
+ }
+
+ ring = ctx->base.ring;
+
+ spin_lock_bh(&priv->ring[ring].queue_lock);
+ ret = crypto_enqueue_request(&priv->ring[ring].queue, base);
+ spin_unlock_bh(&priv->ring[ring].queue_lock);
+
+ queue_work(priv->ring[ring].workqueue,
+ &priv->ring[ring].work_data.work);
+
+ return ret;
+}
+
static int safexcel_handle_req_result(struct safexcel_crypto_priv *priv, int ring,
struct crypto_async_request *async,
struct scatterlist *src,
@@ -635,6 +674,7 @@ static int safexcel_handle_req_result(st
struct safexcel_cipher_ctx *ctx = crypto_skcipher_ctx(skcipher);
struct safexcel_result_desc *rdesc;
int ndesc = 0;
+ int flag;
*ret = 0;
@@ -677,7 +717,13 @@ static int safexcel_handle_req_result(st
crypto_skcipher_ivsize(skcipher)));
}
- *should_complete = true;
+ if (ctx->basic_ctr && ctx->processed != cryptlen) {
+ *should_complete = false;
+ flag = safexcel_queue_req(async, sreq, sreq->direction);
+ } else {
+ *should_complete = true;
+ ctx->processed = 0;
+ }
return ndesc;
}
@@ -700,12 +746,16 @@ static int safexcel_send_req(struct cryp
unsigned int totlen;
unsigned int totlen_src = cryptlen + assoclen;
unsigned int totlen_dst = totlen_src;
+ unsigned int pass_byte = 0;
+ unsigned int pass;
struct safexcel_token *atoken;
int n_cdesc = 0, n_rdesc = 0;
int queued, i, ret = 0;
bool first = true;
- sreq->nr_src = sg_nents_for_len(src, totlen_src);
+ pass_byte = ctx->processed;
+ pass = pass_byte;
+ sreq->nr_src = sg_nents_for_len(src, totlen_src + pass_byte);
if (ctx->aead) {
/*
@@ -736,7 +786,7 @@ static int safexcel_send_req(struct cryp
crypto_skcipher_ivsize(skcipher)));
}
- sreq->nr_dst = sg_nents_for_len(dst, totlen_dst);
+ sreq->nr_dst = sg_nents_for_len(dst, totlen_dst + pass_byte);
/*
* Remember actual input length, source buffer length may be
@@ -798,14 +848,23 @@ static int safexcel_send_req(struct cryp
for_each_sg(src, sg, sreq->nr_src, i) {
int len = sg_dma_len(sg);
+ if (pass) {
+ if (pass >= len) {
+ pass -= len;
+ continue;
+ }
+ len = len - pass;
+ }
/* Do not overflow the request */
if (queued < len)
len = queued;
cdesc = safexcel_add_cdesc(priv, ring, !n_cdesc,
- !(queued - len),
- sg_dma_address(sg), len, totlen,
- ctx->base.ctxr_dma, &atoken);
+ !(queued - len),
+ sg_dma_address(sg) + pass, len,
+ totlen, ctx->base.ctxr_dma, &atoken);
+ pass = 0;
+
if (IS_ERR(cdesc)) {
/* No space left in the command descriptor ring */
ret = PTR_ERR(cdesc);
@@ -820,6 +879,7 @@ static int safexcel_send_req(struct cryp
if (!queued)
break;
}
+
skip_cdesc:
/* Add context control words and token to first command descriptor */
safexcel_context_control(ctx, base, sreq, first_cdesc);
@@ -831,11 +891,20 @@ skip_cdesc:
safexcel_skcipher_token(ctx, iv, first_cdesc, atoken,
cryptlen);
+ pass = pass_byte;
/* result descriptors */
for_each_sg(dst, sg, sreq->nr_dst, i) {
bool last = (i == sreq->nr_dst - 1);
u32 len = sg_dma_len(sg);
+ if (pass) {
+ if (pass >= len) {
+ pass -= len;
+ continue;
+ }
+ len -= pass;
+ }
+
/* only allow the part of the buffer we know we need */
if (len > totlen_dst)
len = totlen_dst;
@@ -855,9 +924,11 @@ skip_cdesc:
len - assoclen);
assoclen = 0;
} else {
+
rdesc = safexcel_add_rdesc(priv, ring, first, last,
- sg_dma_address(sg),
- len);
+ sg_dma_address(sg) + pass,
+ len);
+ pass = 0;
}
if (IS_ERR(rdesc)) {
/* No space left in the result descriptor ring */
@@ -892,6 +963,7 @@ skip_cdesc:
*commands = n_cdesc;
*results = n_rdesc;
+
return 0;
rdesc_rollback:
@@ -1033,6 +1105,26 @@ static int safexcel_cipher_send_inv(stru
return 0;
}
+static void accum_iv(u8 *iv, u32 blocks)
+{
+ u32 *counter;
+ int i;
+
+ for (i = 12; i >= 0; i = i - 4) {
+ counter = (u32 *) &iv[i];
+ if (be32_to_cpu(*counter) + blocks >= be32_to_cpu(*counter)) {
+ *counter = cpu_to_be32(be32_to_cpu(*counter) + blocks);
+ blocks = 0;
+ } else {
+ *counter = cpu_to_be32(be32_to_cpu(*counter) + blocks);
+ blocks = 1;
+ }
+
+ if (blocks == 0)
+ break;
+ }
+}
+
static int safexcel_skcipher_send(struct crypto_async_request *async, int ring,
int *commands, int *results)
{
@@ -1049,6 +1141,8 @@ static int safexcel_skcipher_send(struct
} else {
struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req);
u8 input_iv[AES_BLOCK_SIZE];
+ u32 blocks;
+ u32 *counter;
/*
* Save input IV in case of CBC decrypt mode
@@ -1056,9 +1150,29 @@ static int safexcel_skcipher_send(struct
*/
memcpy(input_iv, req->iv, crypto_skcipher_ivsize(skcipher));
- ret = safexcel_send_req(async, ring, sreq, req->src,
+ if (ctx->mode == CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD && ctx->basic_ctr) {
+ counter = (u32 *) &req->iv[12];
+ blocks = (req->cryptlen / ctx->blocksz) - (ctx->processed / 16);
+ if (req->cryptlen % ctx->blocksz)
+ blocks++;
+ if (be32_to_cpu(*counter) + blocks < be32_to_cpu(*counter)) {
+ blocks = 0 - be32_to_cpu(*counter);
+ ret = safexcel_send_req(async, ring, sreq, req->src,
+ req->dst, min(blocks * AES_BLOCK_SIZE, req->cryptlen), 0, 0, input_iv,
+ commands, results);
+ ctx->processed += min(blocks * AES_BLOCK_SIZE, req->cryptlen);
+ } else {
+ ret = safexcel_send_req(async, ring, sreq, req->src,
+ req->dst, req->cryptlen - ctx->processed,
+ 0, 0, input_iv, commands, results);
+ ctx->processed = req->cryptlen;
+ }
+ accum_iv(req->iv, blocks);
+ } else {
+ ret = safexcel_send_req(async, ring, sreq, req->src,
req->dst, req->cryptlen, 0, 0, input_iv,
commands, results);
+ }
}
sreq->rdescs = *results;
@@ -1152,43 +1266,6 @@ static int safexcel_aead_exit_inv(struct
return safexcel_cipher_exit_inv(tfm, &req->base, sreq, &result);
}
-static int safexcel_queue_req(struct crypto_async_request *base,
- struct safexcel_cipher_req *sreq,
- enum safexcel_cipher_direction dir)
-{
- struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(base->tfm);
- struct safexcel_crypto_priv *priv = ctx->priv;
- int ret, ring;
-
- sreq->needs_inv = false;
- sreq->direction = dir;
-
- if (ctx->base.ctxr) {
- if (priv->flags & EIP197_TRC_CACHE && ctx->base.needs_inv) {
- sreq->needs_inv = true;
- ctx->base.needs_inv = false;
- }
- } else {
- ctx->base.ring = safexcel_select_ring(priv);
- ctx->base.ctxr = dma_pool_zalloc(priv->context_pool,
- EIP197_GFP_FLAGS(*base),
- &ctx->base.ctxr_dma);
- if (!ctx->base.ctxr)
- return -ENOMEM;
- }
-
- ring = ctx->base.ring;
-
- spin_lock_bh(&priv->ring[ring].queue_lock);
- ret = crypto_enqueue_request(&priv->ring[ring].queue, base);
- spin_unlock_bh(&priv->ring[ring].queue_lock);
-
- queue_work(priv->ring[ring].workqueue,
- &priv->ring[ring].work_data.work);
-
- return ret;
-}
-
static int safexcel_encrypt(struct skcipher_request *req)
{
return safexcel_queue_req(&req->base, skcipher_request_ctx(req),
@@ -1216,6 +1293,8 @@ static int safexcel_skcipher_cra_init(st
ctx->base.send = safexcel_skcipher_send;
ctx->base.handle_result = safexcel_skcipher_handle_result;
ctx->ivmask = EIP197_OPTION_4_TOKEN_IV_CMD;
+ ctx->basic_ctr = false;
+ ctx->processed = 0;
ctx->ctrinit = 1;
return 0;
}
@@ -1496,6 +1575,44 @@ struct safexcel_alg_template safexcel_al
},
};
+static int safexcel_skcipher_basic_aes_ctr_cra_init(struct crypto_tfm *tfm)
+{
+ struct safexcel_cipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ safexcel_skcipher_cra_init(tfm);
+ ctx->alg = SAFEXCEL_AES;
+ ctx->blocksz = AES_BLOCK_SIZE;
+ ctx->mode = CONTEXT_CONTROL_CRYPTO_MODE_CTR_LOAD;
+ ctx->basic_ctr = true;
+ return 0;
+}
+
+struct safexcel_alg_template safexcel_alg_basic_ctr_aes = {
+ .type = SAFEXCEL_ALG_TYPE_SKCIPHER,
+ .algo_mask = SAFEXCEL_ALG_AES,
+ .alg.skcipher = {
+ .setkey = safexcel_skcipher_aes_setkey,
+ .encrypt = safexcel_encrypt,
+ .decrypt = safexcel_decrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ .base = {
+ .cra_name = "ctr(aes)",
+ .cra_driver_name = "safexcel-basic-ctr-aes",
+ .cra_priority = SAFEXCEL_CRA_PRIORITY,
+ .cra_flags = CRYPTO_ALG_ASYNC |
+ CRYPTO_ALG_KERN_DRIVER_ONLY,
+ .cra_blocksize = 1,
+ .cra_ctxsize = sizeof(struct safexcel_cipher_ctx),
+ .cra_alignmask = 0,
+ .cra_init = safexcel_skcipher_basic_aes_ctr_cra_init,
+ .cra_exit = safexcel_skcipher_cra_exit,
+ .cra_module = THIS_MODULE,
+ },
+ },
+};
+
static int safexcel_des_setkey(struct crypto_skcipher *ctfm, const u8 *key,
unsigned int len)
{
@@ -1724,6 +1841,9 @@ static int safexcel_aead_cra_init(struct
ctx->aead = true;
ctx->base.send = safexcel_aead_send;
ctx->base.handle_result = safexcel_aead_handle_result;
+ ctx->basic_ctr = false;
+ ctx->processed = 0;
+
return 0;
}

View File

@@ -0,0 +1,178 @@
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 3c2ea9f..e5a8b70 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -412,11 +412,25 @@ choice
endchoice
config AQUANTIA_PHY_FW_FILE
- string "FW File"
+ string "Default PHY FW File"
depends on AQUANTIA_PHY
default "Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld"
---help---
- Currently supports the Aquantia AQR113c
+ This is the default FW.
+
+config AQUANTIA_PHY_FW_FILE_AQR113C
+ string "AQR113C PHY FW File"
+ depends on AQUANTIA_PHY
+ default "Rhe-05.06-Candidate7-AQR_Mediatek_23B_StartOff_ID45623_VER36657.cld"
+ ---help---
+ This FW is for AQR113C
+
+config AQUANTIA_PHY_FW_FILE_CUX3410
+ string "CUX3410 PHY FW File"
+ depends on AQUANTIA_PHY
+ default "AQR-G4_v5.7.0-AQR_EVB_Generic_X3410_StdCfg_MDISwap_USX_ID46316_VER2148.cld"
+ ---help---
+ This FW is for CUX3410
config AQUANTIA_PHY_MIB
tristate "MIB Read Enable"
diff --git a/drivers/net/phy/aquantia.h b/drivers/net/phy/aquantia.h
index 03d6744..d7e6786 100644
--- a/drivers/net/phy/aquantia.h
+++ b/drivers/net/phy/aquantia.h
@@ -9,6 +9,16 @@
#include <linux/device.h>
#include <linux/phy.h>
+#define PHY_ID_AQ1202 0x03a1b445
+#define PHY_ID_AQ2104 0x03a1b460
+#define PHY_ID_AQR105 0x03a1b4a2
+#define PHY_ID_AQR106 0x03a1b4d0
+#define PHY_ID_AQR107 0x03a1b4e0
+#define PHY_ID_AQCS109 0x03a1b5c2
+#define PHY_ID_AQR405 0x03a1b4b0
+#define PHY_ID_AQR113C 0x31c31c12
+#define PHY_ID_CUX3410 0x31c31dd3
+
#define MDIO_AN_VEND_PROV_DOWNSHIFT_DFLT 4
#define PMAPMD_RSVD_VEND_PROV 0xe400
diff --git a/drivers/net/phy/aquantia_firmware.c b/drivers/net/phy/aquantia_firmware.c
index f37bee1..55a9a29 100644
--- a/drivers/net/phy/aquantia_firmware.c
+++ b/drivers/net/phy/aquantia_firmware.c
@@ -19,6 +19,8 @@
#endif
#define AQR_FIRMWARE CONFIG_AQUANTIA_PHY_FW_FILE
+#define AQR113C_FIRMWARE CONFIG_AQUANTIA_PHY_FW_FILE_AQR113C
+#define CUX3410_FIRMWARE CONFIG_AQUANTIA_PHY_FW_FILE_CUX3410
/* Vendor specific 1, MDIO_MMD_VEND1 */
#define VEND1_STD_CONTROL1 0x0000
@@ -923,6 +925,18 @@ int aqr_firmware_heartbeat_thread(void *data)
return ret;
}
+static char* aqr_firmware_name_get(u32 phy_id)
+{
+ switch (phy_id) {
+ case PHY_ID_AQR113C:
+ return AQR113C_FIRMWARE;
+ case PHY_ID_CUX3410:
+ return CUX3410_FIRMWARE;
+ default:
+ return AQR_FIRMWARE;
+ }
+}
+
static void aqr_firmware_download_cb(const struct firmware *fw, void *context)
{
struct phy_device **phydevs = context;
@@ -931,6 +945,8 @@ static void aqr_firmware_download_cb(const struct firmware *fw, void *context)
struct aqr107_priv *priv = phydevs[0]->priv;
int result[MAX_GANGLOAD_DEVICES];
int i, num_phydevs = 0, ret = 0;
+ u32 phy_id = phydevs[0]->drv->phy_id;
+ char *firmware_name = aqr_firmware_name_get(phy_id);
if (!fw)
return;
@@ -957,7 +973,7 @@ retry:
dev = &phydevs[i]->mdio.dev;
dev_err(dev, "failed to download firmware %s, ret: %d\n",
- AQR_FIRMWARE, ret);
+ firmware_name, ret);
goto retry;
}
}
@@ -1005,6 +1021,8 @@ static int aqr_firmware_download_single(struct phy_device *phydev, bool force_re
struct device *dev = &phydev->mdio.dev;
const struct firmware *fw;
int ret = 0;
+ u32 phy_id = phydev->drv->phy_id;
+ char *firmware_name = aqr_firmware_name_get(phy_id);
if (priv->fw_initialized == true && force_reload == false)
return 0;
@@ -1016,10 +1034,10 @@ static int aqr_firmware_download_single(struct phy_device *phydev, bool force_re
priv->fw_dl_mode = FW_DL_SINGLE;
priv->heartbeat = -1;
- ret = request_firmware(&fw, AQR_FIRMWARE, dev);
+ ret = request_firmware(&fw, firmware_name, dev);
if (ret) {
dev_err(dev, "failed to request firmware %s, ret: %d\n",
- AQR_FIRMWARE, ret);
+ firmware_name, ret);
}
aqr_firmware_download_cb(fw, priv->phydevs);
@@ -1032,6 +1050,8 @@ static int aqr_firmware_gandload_thread(void *data)
struct phy_device **phydevs = data;
struct device *dev = &phydevs[0]->mdio.dev;
int ret = 0;
+ u32 phy_id = phydevs[0]->drv->phy_id;
+ char *firmware_name = aqr_firmware_name_get(phy_id);
for (;;) {
if (kthread_should_stop())
@@ -1040,11 +1060,11 @@ static int aqr_firmware_gandload_thread(void *data)
/* either maximum gangload phy devices or timeout is reached */
if (gangload == MAX_GANGLOAD_DEVICES ||
time_after(jiffies, gangload_timeout)) {
- ret = request_firmware_nowait(THIS_MODULE, true, AQR_FIRMWARE, dev,
+ ret = request_firmware_nowait(THIS_MODULE, true, firmware_name, dev,
GFP_KERNEL, phydevs, aqr_firmware_download_cb);
if (ret) {
dev_err(dev, "failed to request firmware %s, ret: %d\n",
- AQR_FIRMWARE, ret);
+ firmware_name, ret);
}
break;
}
diff --git a/drivers/net/phy/aquantia_main.c b/drivers/net/phy/aquantia_main.c
index f445ef9..208fc7d 100644
--- a/drivers/net/phy/aquantia_main.c
+++ b/drivers/net/phy/aquantia_main.c
@@ -17,16 +17,6 @@
#include "aquantia.h"
-#define PHY_ID_AQ1202 0x03a1b445
-#define PHY_ID_AQ2104 0x03a1b460
-#define PHY_ID_AQR105 0x03a1b4a2
-#define PHY_ID_AQR106 0x03a1b4d0
-#define PHY_ID_AQR107 0x03a1b4e0
-#define PHY_ID_AQCS109 0x03a1b5c2
-#define PHY_ID_AQR405 0x03a1b4b0
-#define PHY_ID_AQR113C 0x31c31c12
-#define PHY_ID_CUX3410 0x31c31dd3
-
#define MDIO_PHYXS_VEND_IF_STATUS 0xe812
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_MASK GENMASK(7, 3)
#define MDIO_PHYXS_VEND_IF_STATUS_TYPE_KR 0
@@ -489,7 +479,7 @@ void aqr107_chip_info(struct phy_device *phydev)
build_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_FW_BUILD_ID, val);
prov_id = FIELD_GET(VEND1_GLOBAL_RSVD_STAT1_PROV_ID, val);
- phydev_dbg(phydev, "FW %u.%u, Build %u, Provisioning %u\n",
+ phydev_info(phydev, "FW %u.%u, Build %u, Provisioning %u\n",
fw_major, fw_minor, build_id, prov_id);
}

View File

@@ -0,0 +1,94 @@
From ae07baf1efdbd3705be90691b5ae606057b225b0 Mon Sep 17 00:00:00 2001
From: "neal.yen" <neal.yen@mediatek.com>
Date: Fri, 26 Jul 2024 15:05:19 +0800
Subject: [PATCH] 999-2742-drivers-net-dsa-mxl862xx
---
drivers/net/dsa/Kconfig | 2 ++
drivers/net/dsa/Makefile | 1 +
include/net/dsa.h | 4 ++++
net/dsa/Kconfig | 13 +++++++++++++
net/dsa/Makefile | 2 ++
6 files changed, 23 insertions(+)
diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig
index a15dd0d..13ef0f0 100644
--- a/drivers/net/dsa/Kconfig
+++ b/drivers/net/dsa/Kconfig
@@ -54,6 +54,8 @@ source "drivers/net/dsa/microchip/Kconfig"
source "drivers/net/dsa/mv88e6xxx/Kconfig"
+source "drivers/net/dsa/mxl862xx/Kconfig"
+
source "drivers/net/dsa/sja1105/Kconfig"
config NET_DSA_QCA8K
diff --git a/drivers/net/dsa/Makefile b/drivers/net/dsa/Makefile
index c36e793..263c052 100644
--- a/drivers/net/dsa/Makefile
+++ b/drivers/net/dsa/Makefile
@@ -23,3 +23,4 @@ obj-y += b53/
obj-y += microchip/
obj-y += mv88e6xxx/
obj-y += sja1105/
+obj-y += mxl862xx/
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 65cfa41..0c138e5 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -44,6 +44,8 @@ struct phylink_link_state;
#define DSA_TAG_PROTO_KSZ8795_VALUE 14
#define DSA_TAG_PROTO_RTL4_A_VALUE 17
#define DSA_TAG_PROTO_ARHT_VALUE 28
+#define DSA_TAG_PROTO_MXL862_VALUE 29
+#define DSA_TAG_PROTO_MXL862_8021Q_VALUE 30
enum dsa_tag_protocol {
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -63,6 +65,8 @@ enum dsa_tag_protocol {
DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE,
DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE,
DSA_TAG_PROTO_ARHT = DSA_TAG_PROTO_ARHT_VALUE,
+ DSA_TAG_PROTO_MXL862 = DSA_TAG_PROTO_MXL862_VALUE,
+ DSA_TAG_PROTO_MXL862_8021Q = DSA_TAG_PROTO_MXL862_8021Q_VALUE,
};
struct packet_type;
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig
index 5da7a23..b0b9df1 100644
--- a/net/dsa/Kconfig
+++ b/net/dsa/Kconfig
@@ -86,6 +86,19 @@ config NET_DSA_TAG_KSZ
Say Y if you want to enable support for tagging frames for the
Microchip 8795/9477/9893 families of switches.
+config NET_DSA_TAG_MXL862
+ tristate "Tag driver for MxL862xx switches"
+ help
+ Say Y or M if you want to enable support for tagging frames for the
+ Maxlinear MxL862xx switches.
+
+config NET_DSA_TAG_MXL862_8021Q
+ tristate "Tag driver for MxL862xx switches, based on VLAN tags"
+ help
+ Say Y or M if you want to enable support for tagging frames for the
+ Maxlinear MxL862xx switches. This tagging variant is based on 4-byte wide VLAN
+ tags
+
config NET_DSA_TAG_RTL4_A
tristate "Tag driver for Realtek 4 byte protocol A tags"
help
diff --git a/net/dsa/Makefile b/net/dsa/Makefile
index b58ac0f..692b70f 100644
--- a/net/dsa/Makefile
+++ b/net/dsa/Makefile
@@ -17,3 +17,5 @@ obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
obj-$(CONFIG_NET_DSA_TAG_SJA1105) += tag_sja1105.o
obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
obj-$(CONFIG_NET_DSA_TAG_AIROHA) += tag_arht.o
+obj-$(CONFIG_NET_DSA_TAG_MXL862) += tag_mxl862xx.o
+obj-$(CONFIG_NET_DSA_TAG_MXL862_8021Q) += tag_mxl862xx_8021q.o
--
2.18.0

View File

@@ -0,0 +1,71 @@
From 5feba07f7e9ccf9c9a3d862e321c84ac4fd089a9 Mon Sep 17 00:00:00 2001
From: "neal.yen" <neal.yen@mediatek.com>
Date: Thu, 26 Sep 2024 20:19:57 +0800
Subject: [PATCH] 999-2743-drivers-net-dsa-mxl862xx-kernel-compatible
---
drivers/net/dsa/mxl862xx/mxl862xx.c | 32 -----------------------------
1 file changed, 32 deletions(-)
diff --git a/drivers/net/dsa/mxl862xx/mxl862xx.c b/drivers/net/dsa/mxl862xx/mxl862xx.c
index 5cab346..cbf2fe4 100755
--- a/drivers/net/dsa/mxl862xx/mxl862xx.c
+++ b/drivers/net/dsa/mxl862xx/mxl862xx.c
@@ -1494,7 +1494,6 @@ static void mxl862xx_phylink_mac_link_down(struct dsa_switch *ds, int port,
}
}
-#if (KERNEL_VERSION(5, 6, 0) <= LINUX_VERSION_CODE)
static void mxl862xx_phylink_mac_link_up(struct dsa_switch *ds, int port,
unsigned int mode,
phy_interface_t interface,
@@ -1589,32 +1588,6 @@ static void mxl862xx_phylink_mac_link_up(struct dsa_switch *ds, int port,
return;
}
-#else
-static void mxl862xx_phylink_mac_link_up(struct dsa_switch *ds, int port,
- unsigned int mode,
- phy_interface_t interface,
- struct phy_device *phydev)
-{
- mxl862xx_port_link_cfg_t port_link_cfg = { 0 };
- int ret;
-
- if (dsa_is_cpu_port(ds, port))
- return;
-
- port_link_cfg.port_id = port + 1;
-
- port_link_cfg.link_force = true;
- port_link_cfg.link = MXL862XX_PORT_LINK_UP;
-
- ret = mxl862xx_port_link_cfg_set(&mxl_dev, &port_link_cfg);
- if (ret != MXL862XX_STATUS_OK) {
- dev_err(ds->dev,
- "%s: Port link configuration for port %d failed with %d\n",
- __func__, port, ret);
- return;
- }
-}
-#endif
#endif
static void mxl862xx_get_ethtool_stats(struct dsa_switch *ds, int port,
@@ -4398,13 +4371,8 @@ static int mxl862xx_change_tag_protocol(struct dsa_switch *ds,
}
#endif
-#if (KERNEL_VERSION(5, 6, 0) > LINUX_VERSION_CODE)
-static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds,
- int port)
-#else
static enum dsa_tag_protocol mxl862xx_get_tag_protocol(struct dsa_switch *ds,
int port, enum dsa_tag_protocol m)
-#endif
{
enum dsa_tag_protocol tag_proto;
--
2.45.2

View File

@@ -0,0 +1,79 @@
From 2b6996b2827db88d87ad28e0c28cbe7382eb375c Mon Sep 17 00:00:00 2001
From: "neal.yen" <neal.yen@mediatek.com>
Date: Mon, 12 Aug 2024 16:32:48 +0800
Subject: [PATCH] 999-2745-drivers-net-phy-mxl862xx-mxl-gpy
---
drivers/net/phy/mxl-gpy.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/drivers/net/phy/mxl-gpy.c b/drivers/net/phy/mxl-gpy.c
index 7304278..988eb77 100644
--- a/drivers/net/phy/mxl-gpy.c
+++ b/drivers/net/phy/mxl-gpy.c
@@ -14,6 +14,7 @@
/* PHY ID */
#define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
#define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
+#define PHY_ID_MXL862XX_MASK 0xFFFFFF00
#define PHY_ID_GPY2xx 0x67C9DC00
#define PHY_ID_GPY115B 0x67C9DF00
#define PHY_ID_GPY115C 0x67C9DF10
@@ -26,6 +27,7 @@
#define PHY_ID_GPY241B 0x67C9DE40
#define PHY_ID_GPY241BM 0x67C9DE80
#define PHY_ID_GPY245B 0x67C9DEC0
+#define PHY_ID_MXL862XX 0xC1335500
#define PHY_MIISTAT 0x18 /* MII state */
#define PHY_IMASK 0x19 /* interrupt mask */
@@ -504,6 +506,15 @@ static int gpy115_loopback(struct phy_device *phydev, bool enable)
return genphy_soft_reset(phydev);
}
+static int gpy_c45_pma_read_abilities(struct phy_device *phydev)
+{
+ phydev->c45_ids.devices_in_package |= MDIO_DEVS_AN;
+
+ genphy_c45_pma_read_abilities(phydev);
+
+ return 0;
+}
+
static struct phy_driver gpy_drivers[] = {
{
PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
@@ -713,6 +724,22 @@ static struct phy_driver gpy_drivers[] = {
.get_wol = gpy_get_wol,
.set_loopback = gpy_loopback,
},
+ {
+ .phy_id = PHY_ID_MXL862XX,
+ .phy_id_mask = PHY_ID_MXL862XX_MASK,
+ .name = "MaxLinear Ethernet MxL862XX",
+ .get_features = gpy_c45_pma_read_abilities,
+ .config_init = gpy_config_init,
+ .probe = gpy_probe,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .config_aneg = gpy_config_aneg,
+ .aneg_done = genphy_c45_aneg_done,
+ .read_status = gpy_read_status,
+ .config_intr = gpy_config_intr,
+ .handle_interrupt = gpy_handle_interrupt,
+ .set_loopback = gpy_loopback,
+ },
};
module_phy_driver(gpy_drivers);
@@ -729,6 +756,7 @@ static struct mdio_device_id __maybe_unused gpy_tbl[] = {
{PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
{PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
{PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
+ {PHY_ID_MXL862XX, PHY_ID_MXL862XX_MASK},
{ }
};
MODULE_DEVICE_TABLE(mdio, gpy_tbl);
--
2.45.2

View File

@@ -0,0 +1,60 @@
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -5076,4 +5076,5 @@ extern struct net_device *blackhole_netd
atomic_long_add((VAL), &(DEV)->stats.__##FIELD)
#define DEV_STATS_READ(DEV, FIELD) atomic_long_read(&(DEV)->stats.__##FIELD)
+extern int (*mtk_skb_headroom_copy)(struct sk_buff *new, struct sk_buff *old);
#endif /* _LINUX_NETDEVICE_H */
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -198,6 +198,9 @@ static DEFINE_READ_MOSTLY_HASHTABLE(napi
static DECLARE_RWSEM(devnet_rename_sem);
+int (*mtk_skb_headroom_copy)(struct sk_buff *new, struct sk_buff *old) = NULL;
+EXPORT_SYMBOL(mtk_skb_headroom_copy);
+
static inline void dev_base_seq_inc(struct net *net)
{
while (++net->dev_base_seq == 0)
@@ -3448,6 +3451,9 @@ static struct sk_buff *validate_xmit_skb
if (IS_ERR(segs)) {
goto out_kfree_skb;
} else if (segs) {
+ if (mtk_skb_headroom_copy)
+ mtk_skb_headroom_copy(segs, skb);
+
consume_skb(skb);
skb = segs;
}
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -705,7 +705,7 @@ struct sk_buff *ip_frag_next(struct sk_b
}
/* Allocate buffer */
- skb2 = alloc_skb(len + state->hlen + state->ll_rs, GFP_ATOMIC);
+ skb2 = alloc_skb(len + state->hlen + state->ll_rs + NET_SKB_PAD + NET_IP_ALIGN, GFP_ATOMIC);
if (!skb2)
return ERR_PTR(-ENOMEM);
@@ -714,7 +714,7 @@ struct sk_buff *ip_frag_next(struct sk_b
*/
ip_copy_metadata(skb2, skb);
- skb_reserve(skb2, state->ll_rs);
+ skb_reserve(skb2, state->ll_rs + NET_SKB_PAD + NET_IP_ALIGN);
skb_put(skb2, len + state->hlen);
skb_reset_network_header(skb2);
skb2->transport_header = skb2->network_header + state->hlen;
@@ -909,6 +909,9 @@ slow_path:
}
ip_frag_ipcb(skb, skb2, first_frag, &state);
+ if (mtk_skb_headroom_copy)
+ mtk_skb_headroom_copy(skb2, skb);
+
/*
* Put this fragment into the sending queue.
*/

View File

@@ -0,0 +1,59 @@
From 214c02d3738a8dee0c07cbf50aa0eb25eed7faa9 Mon Sep 17 00:00:00 2001
From: "chak-kei.lam" <chak-kei.lam@mediatek.com>
Date: Fri, 31 Jan 2025 15:15:43 +0800
Subject: [PATCH] net: macvlan: support hardware flow table offload
---
drivers/net/macvlan.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 90e8b56..2f578a1 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -33,6 +33,11 @@
#include <linux/netpoll.h>
#include <linux/phy.h>
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#endif
+
#define MACVLAN_HASH_BITS 8
#define MACVLAN_HASH_SIZE (1<<MACVLAN_HASH_BITS)
#define MACVLAN_BC_QUEUE_LEN 1000
@@ -1137,6 +1142,20 @@ static int macvlan_dev_get_iflink(const struct net_device *dev)
return vlan->lowerdev->ifindex;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int macvlan_dev_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *real_dev = macvlan_dev_real_dev(path->dev);
+
+ path->dev = real_dev;
+
+ if (real_dev->netdev_ops->ndo_flow_offload_check)
+ return real_dev->netdev_ops->ndo_flow_offload_check(path);
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct ethtool_ops macvlan_ethtool_ops = {
.get_link = ethtool_op_get_link,
.get_link_ksettings = macvlan_ethtool_get_link_ksettings,
@@ -1171,6 +1190,9 @@ static const struct net_device_ops macvlan_netdev_ops = {
.ndo_get_iflink = macvlan_dev_get_iflink,
.ndo_features_check = passthru_features_check,
.ndo_change_proto_down = dev_change_proto_down_generic,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = macvlan_dev_flow_offload_check,
+#endif
};
void macvlan_common_setup(struct net_device *dev)
--
2.45.2

View File

@@ -0,0 +1,12 @@
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -369,7 +369,8 @@ int phy_ethtool_ksettings_set(struct phy
return -EINVAL;
if (autoneg == AUTONEG_DISABLE &&
- ((speed != SPEED_1000 &&
+ ((speed != SPEED_2500 &&
+ speed != SPEED_1000 &&
speed != SPEED_100 &&
speed != SPEED_10) ||
(duplex != DUPLEX_HALF &&

View File

@@ -0,0 +1,110 @@
diff --git a/drivers/md/dm-verity-target.c b/drivers/md/dm-verity-target.c
index 711f101..d143fdc 100644
--- a/drivers/md/dm-verity-target.c
+++ b/drivers/md/dm-verity-target.c
@@ -278,6 +278,7 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
int r;
sector_t hash_block;
unsigned offset;
+ unsigned c;
verity_hash_at_level(v, block, level, &hash_block, &offset);
@@ -293,11 +294,23 @@ static int verity_verify_level(struct dm_verity *v, struct dm_verity_io *io,
goto release_ret_r;
}
- r = verity_hash(v, verity_io_hash_req(v, io),
- data, 1 << v->hash_dev_block_bits,
- verity_io_real_digest(v, io));
- if (unlikely(r < 0))
- goto release_ret_r;
+ for (c = 0; c < DM_VERITY_MAX_CORRUPTED_ERRS; c++) {
+ r = verity_hash(v, verity_io_hash_req(v, io),
+ data, 1 << v->hash_dev_block_bits,
+ verity_io_real_digest(v, io));
+
+ if (unlikely(r < 0))
+ goto release_ret_r;
+
+ if (likely(memcmp(verity_io_real_digest(v, io),
+ want_digest,
+ v->digest_size) == 0))
+ break;
+ }
+
+ if (c == DM_VERITY_MAX_CORRUPTED_ERRS)
+ DMINFO("redo meta hash failure over %d times",
+ DM_VERITY_MAX_CORRUPTED_ERRS);
if (likely(memcmp(verity_io_real_digest(v, io), want_digest,
v->digest_size) == 0))
@@ -399,6 +412,7 @@ static int verity_for_io_block(struct dm_verity *v, struct dm_verity_io *io,
bio_advance_iter(bio, iter, len);
todo -= len;
+
} while (todo);
return 0;
@@ -469,7 +483,9 @@ static int verity_verify_io(struct dm_verity_io *io)
bool is_zero;
struct dm_verity *v = io->v;
struct bvec_iter start;
+ struct bvec_iter keep;
unsigned b;
+ unsigned c;
struct crypto_wait wait;
for (b = 0; b < io->n_blocks; b++) {
@@ -502,19 +518,39 @@ static int verity_verify_io(struct dm_verity_io *io)
continue;
}
- r = verity_hash_init(v, req, &wait);
- if (unlikely(r < 0))
- return r;
-
start = io->iter;
- r = verity_for_io_block(v, io, &io->iter, &wait);
- if (unlikely(r < 0))
- return r;
- r = verity_hash_final(v, req, verity_io_real_digest(v, io),
- &wait);
- if (unlikely(r < 0))
- return r;
+ for (c = 0; c < DM_VERITY_MAX_CORRUPTED_ERRS; c++) {
+ keep = start;
+
+ r = verity_hash_init(v, req, &wait);
+ if (unlikely(r < 0))
+ return r;
+
+ if (c == 0)
+ r = verity_for_io_block(v, io, &io->iter,
+ &wait);
+ else
+ r = verity_for_io_block(v, io, &keep,
+ &wait);
+ if (unlikely(r < 0))
+ return r;
+
+ r = verity_hash_final(v, req,
+ verity_io_real_digest(v, io),
+ &wait);
+ if (unlikely(r < 0))
+ return r;
+
+ if (likely(memcmp(verity_io_real_digest(v, io),
+ verity_io_want_digest(v, io),
+ v->digest_size) == 0))
+ break;
+ }
+
+ if (c == DM_VERITY_MAX_CORRUPTED_ERRS)
+ DMINFO("redo data hash failure over %d times",
+ DM_VERITY_MAX_CORRUPTED_ERRS);
if (likely(memcmp(verity_io_real_digest(v, io),
verity_io_want_digest(v, io), v->digest_size) == 0)) {

View File

@@ -0,0 +1,165 @@
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -21,6 +21,7 @@
#include <linux/blk-mq.h>
#include <linux/mount.h>
#include <linux/dax.h>
+#include <linux/blkdev.h>
#define DM_MSG_PREFIX "table"
@@ -400,6 +401,132 @@ static int upgrade_mode(struct dm_dev_in
}
/*
+ * Note for patch conflicts/building failure when upgrading kernel:
+ * Most of the following code is copied from init/do_mounts.c
+ */
+struct uuidcmp {
+ const char *uuid;
+ int len;
+};
+
+/**
+ * match_dev_by_uuid - callback for finding a partition using its uuid
+ * @dev: device passed in by the caller
+ * @data: opaque pointer to the desired struct uuidcmp to match
+ *
+ * Returns 1 if the device matches, and 0 otherwise.
+ */
+static int match_dev_by_uuid(struct device *dev, const void *data)
+{
+ const struct uuidcmp *cmp = data;
+ struct hd_struct *part = dev_to_part(dev);
+
+ if (!part->info)
+ goto no_match;
+
+ if (strncasecmp(cmp->uuid, part->info->uuid, cmp->len))
+ goto no_match;
+
+ return 1;
+no_match:
+ return 0;
+}
+
+
+/**
+ * devt_from_partuuid - looks up the dev_t of a partition by its UUID
+ * @uuid_str: char array containing ascii UUID
+ *
+ * The function will return the first partition which contains a matching
+ * UUID value in its partition_meta_info struct. This does not search
+ * by filesystem UUIDs.
+ *
+ * If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be
+ * extracted and used as an offset from the partition identified by the UUID.
+ *
+ * Returns the matching dev_t on success or 0 on failure.
+ */
+static dev_t devt_from_partuuid(const char *uuid_str)
+{
+ dev_t res = 0;
+ struct uuidcmp cmp;
+ struct device *dev = NULL;
+ struct gendisk *disk;
+ struct hd_struct *part;
+ int offset = 0;
+ bool prompt_failure = false;
+ char *slash;
+
+ cmp.uuid = uuid_str;
+
+ slash = strchr(uuid_str, '/');
+ /* Check for optional partition number offset attributes. */
+ if (slash) {
+ char c = 0;
+ /* Explicitly fail on poor PARTUUID syntax. */
+ if (sscanf(slash + 1,
+ "PARTNROFF=%d%c", &offset, &c) != 1) {
+ prompt_failure = true;
+ goto done;
+ }
+ cmp.len = slash - uuid_str;
+ } else {
+ cmp.len = strlen(uuid_str);
+ }
+
+ if (!cmp.len) {
+ prompt_failure = true;
+ goto done;
+ }
+
+ dev = class_find_device(&block_class, NULL, &cmp,
+ &match_dev_by_uuid);
+ if (!dev)
+ goto done;
+
+ res = dev->devt;
+
+ /* Attempt to find the partition by offset. */
+ if (!offset)
+ goto no_offset;
+
+ res = 0;
+ disk = part_to_disk(dev_to_part(dev));
+ part = disk_get_part(disk, dev_to_part(dev)->partno + offset);
+ if (part) {
+ res = part_devt(part);
+ put_device(part_to_dev(part));
+ }
+
+no_offset:
+ put_device(dev);
+done:
+ if (prompt_failure) {
+ pr_err("DM: PARTUUID= is invalid.\n"
+ "Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
+ }
+ return res;
+}
+
+/**
+ * match_dev_by_label - callback for finding a partition using its label
+ * @dev: device passed in by the caller
+ * @data: opaque pointer to the label to match
+ *
+ * Returns 1 if the device matches, and 0 otherwise.
+ */
+static int match_dev_by_label(struct device *dev, const void *data)
+{
+ const char *label = data;
+ struct hd_struct *part = dev_to_part(dev);
+
+ if (part->info && !strcmp(label, part->info->volname))
+ return 1;
+
+ return 0;
+}
+
+/*
* Convert the path to a device
*/
dev_t dm_get_dev_t(const char *path)
@@ -407,6 +534,21 @@ dev_t dm_get_dev_t(const char *path)
dev_t dev;
struct block_device *bdev;
+ if (strncmp(path, "PARTUUID=", 9) == 0) {
+ return devt_from_partuuid(path + 9);
+ } else if (strncmp(path, "PARTLABEL=", 10) == 0) {
+ struct device *ddev;
+
+ ddev = class_find_device(&block_class, NULL, path + 10,
+ &match_dev_by_label);
+ if (!ddev)
+ return 0;
+
+ dev = ddev->devt;
+ put_device(ddev);
+ return dev;
+ }
+
bdev = lookup_bdev(path);
if (IS_ERR(bdev))
dev = name_to_dev_t(path);

View File

@@ -0,0 +1,9 @@
--- a/drivers/md/dm-init.c
+++ b/drivers/md/dm-init.c
@@ -299,5 +299,5 @@ out:
late_initcall(dm_init_init);
-module_param(create, charp, 0);
+module_param(create, charp, 0444);
MODULE_PARM_DESC(create, "Create a mapped device in early boot");

View File

@@ -1,507 +0,0 @@
From 2d5090dc6072979167593c8fee026341774efb53 Mon Sep 17 00:00:00 2001
From: mtk22468 <Xuzhu.Wang@mediatek.com>
Date: Mon, 18 Sep 2023 10:50:36 +0800
Subject: [PATCH] ovs add multicast to unicast support
---
net/openvswitch/actions.c | 30 ++++
net/openvswitch/datapath.c | 290 +++++++++++++++++++++++++++++++++++++
net/openvswitch/datapath.h | 40 +++++
net/openvswitch/vport.c | 8 +
net/openvswitch/vport.h | 26 ++++
5 files changed, 394 insertions(+)
diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c
index 9e8a5c4..82cd46e 100644
--- a/net/openvswitch/actions.c
+++ b/net/openvswitch/actions.c
@@ -919,6 +919,10 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
struct sw_flow_key *key)
{
struct vport *vport = ovs_vport_rcu(dp, out_port);
+ struct multicast_data_base *mdb;
+ struct multicast_table *table;
+ struct multicast_table_entry *entry;
+ struct sk_buff *skb_cpy;
if (likely(vport)) {
u16 mru = OVS_CB(skb)->mru;
@@ -933,6 +937,32 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port,
if (likely(!mru ||
(skb->len <= mru + vport->dev->hard_header_len))) {
+ if (is_multicast_addr(skb) && !is_igmp_mld(skb) && !is_icmpv6_ndp_rs_ra(skb)) {
+ mdb = vport->mdb;
+ spin_lock_bh(&mdb->tbl_lock);
+ list_for_each_entry(table, &mdb->list_head, mdb_node) {
+ if ((key->eth.type == htons(ETH_P_IP) &&
+ table->group_addr.u.ip4 == key->ipv4.addr.dst) ||
+ (key->eth.type == htons(ETH_P_IPV6) &&
+ ipv6_addr_equal(&table->group_addr.u.ip6, &key->ipv6.addr.dst))) {
+ list_for_each_entry(entry, &table->entry_list, entry_node) {
+ skb_cpy = skb_copy(skb, GFP_ATOMIC);
+ if (!skb_cpy) {
+ kfree_skb(skb);
+ pr_err("%s(): skb copy error\n", __func__);
+ spin_unlock_bh(&mdb->tbl_lock);
+ return;
+ }
+ memcpy(skb_cpy->data, entry->eth_addr, ETH_ALEN);
+ ovs_vport_send(vport, skb_cpy, ovs_key_mac_proto(key));
+ }
+ spin_unlock_bh(&mdb->tbl_lock);
+ kfree_skb(skb);
+ return;
+ }
+ }
+ spin_unlock_bh(&mdb->tbl_lock);
+ }
ovs_vport_send(vport, skb, ovs_key_mac_proto(key));
} else if (mru <= vport->dev->mtu) {
struct net *net = read_pnet(&dp->net);
diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c
index 4c537e7..0c8d344 100644
--- a/net/openvswitch/datapath.c
+++ b/net/openvswitch/datapath.c
@@ -11,6 +11,9 @@
#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
+#include <linux/igmp.h>
+#include <net/mld.h>
+#include <linux/icmpv6.h>
#include <linux/jhash.h>
#include <linux/delay.h>
#include <linux/time.h>
@@ -538,6 +541,271 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb,
return err;
}
+static int ovs_multicast_add_group(struct ip_addr *_group_addr,
+ const u8 *entry_addr,
+ struct vport *input_vport)
+{
+ struct multicast_data_base *mdb;
+ struct multicast_table *table;
+ struct multicast_table_entry *entry;
+ int err;
+
+ mdb = input_vport->mdb;
+ spin_lock_bh(&mdb->tbl_lock);
+ list_for_each_entry(table, &mdb->list_head, mdb_node) {
+ if (!memcmp(&table->group_addr.u, &_group_addr->u, sizeof(struct ip_addr))) {
+ list_for_each_entry(entry, &table->entry_list, entry_node) {
+ if (ether_addr_equal(entry->eth_addr, entry_addr))
+ goto out;
+ }
+
+ entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
+ if (!entry) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
+ list_add(&entry->entry_node, &table->entry_list);
+ goto out;
+ }
+ }
+
+ table = kzalloc(sizeof(struct multicast_table), GFP_ATOMIC);
+ if (!table) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ INIT_LIST_HEAD(&table->entry_list);
+ entry = kzalloc(sizeof(struct multicast_table_entry), GFP_ATOMIC);
+ if (!entry) {
+ kfree(table);
+ err = -ENOMEM;
+ goto err;
+ }
+
+ memcpy(entry->eth_addr, entry_addr, ETH_ALEN);
+ list_add(&entry->entry_node, &table->entry_list);
+
+ table->group_addr.u = _group_addr->u;
+ list_add(&table->mdb_node, &mdb->list_head);
+
+out:
+ err = 0;
+err:
+ spin_unlock_bh(&mdb->tbl_lock);
+ return err;
+}
+
+static int ovs_multicast_leave_group(struct ip_addr *_group_addr,
+ const u8 *entry_addr,
+ struct vport *input_vport)
+{
+ struct multicast_data_base *mdb;
+ struct multicast_table *table, *table_tmp;
+ struct multicast_table_entry *entry, *entry_tmp;
+ int err;
+
+ mdb = input_vport->mdb;
+ spin_lock_bh(&mdb->tbl_lock);
+ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
+ if (!memcmp(&table->group_addr.u, &_group_addr->u, sizeof(struct ip_addr))) {
+ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
+ if (ether_addr_equal(entry->eth_addr, entry_addr)) {
+ list_del(&entry->entry_node);
+ kfree(entry);
+
+ if (list_empty(&table->entry_list)) {
+ list_del(&table->mdb_node);
+ kfree(table);
+ }
+
+ goto out;
+ }
+ }
+ }
+ }
+
+out:
+ err = 0;
+ spin_unlock_bh(&mdb->tbl_lock);
+ return err;
+}
+
+static int ovs_multicast_ipv4_rcv(struct sk_buff *skb, struct vport *input_vport)
+{
+ struct ethhdr *eth_hdr;
+ const u8 *dl_src;
+ struct ip_addr group_addr = {0};
+ struct iphdr *ip_header;
+ struct igmphdr *igmp_header;
+ int i;
+ struct igmpv3_report *igmpv3_hdr;
+ u16 group_num;
+ struct igmpv3_grec *grec;
+ u8 group_type;
+ u8 aux_data_len;
+ u16 num_of_source;
+ int err;
+
+ err = ip_mc_check_igmp(skb);
+ if (err)
+ return 0;
+
+ eth_hdr = skb_eth_hdr(skb);
+ dl_src = eth_hdr->h_source;
+ ip_header = ip_hdr(skb);
+ igmp_header = igmp_hdr(skb);
+
+ switch (igmp_header->type) {
+ case IGMP_HOST_MEMBERSHIP_REPORT:
+ case IGMPV2_HOST_MEMBERSHIP_REPORT:
+ group_addr.u.ip4 = igmp_header->group;
+ if (ipv4_is_local_multicast(group_addr.u.ip4))
+ return 0;
+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
+ break;
+ case IGMP_HOST_LEAVE_MESSAGE:
+ group_addr.u.ip4 = igmp_header->group;
+ if (ipv4_is_local_multicast(group_addr.u.ip4))
+ return 0;
+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
+ break;
+ case IGMPV3_HOST_MEMBERSHIP_REPORT:
+ igmpv3_hdr = (struct igmpv3_report *)igmp_header;
+ group_num = ntohs(igmpv3_hdr->ngrec);
+ grec = igmpv3_hdr->grec;
+
+ for (i = 0; i < group_num; i++) {
+ group_type = grec->grec_type;
+ aux_data_len = grec->grec_auxwords;
+ num_of_source = ntohs(grec->grec_nsrcs);
+ group_addr.u.ip4 = grec->grec_mca;
+ if (ipv4_is_local_multicast(group_addr.u.ip4))
+ return 0;
+
+ if (group_type == IGMPV3_MODE_IS_EXCLUDE ||
+ group_type == IGMPV3_CHANGE_TO_EXCLUDE ||
+ group_type == IGMPV3_ALLOW_NEW_SOURCES)
+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
+
+ if (group_type == IGMPV3_MODE_IS_INCLUDE ||
+ group_type == IGMPV3_CHANGE_TO_INCLUDE ||
+ group_type == IGMPV3_BLOCK_OLD_SOURCES)
+ if (num_of_source == 0)
+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
+
+ grec = (struct igmpv3_grec *)((u8 *)grec + sizeof(struct igmpv3_grec)
+ + aux_data_len * sizeof(u32));
+ }
+ break;
+ case IGMP_HOST_MEMBERSHIP_QUERY:
+ break;
+ default:
+ pr_warning("%s(): error packet type 0x%x\n", __func__, igmp_header->type);
+ break;
+ }
+ return 0;
+}
+
+static int ovs_multicast_ipv6_rcv(struct sk_buff *skb, struct vport *input_vport)
+{
+ const u8 *dl_src;
+ struct mld_msg *mld_hdr;
+ struct ip_addr group_addr = {0};
+ struct icmp6hdr *icmpv6_hdr;
+ u16 group_num;
+ struct mld2_grec *grec;
+ u8 group_type;
+ u8 aux_data_len;
+ u16 num_of_source;
+ int i;
+ int err;
+
+ err = ipv6_mc_check_mld(skb);
+ if (err)
+ return err;
+
+ mld_hdr = (struct mld_msg *)skb_transport_header(skb);
+ dl_src = skb_eth_hdr(skb)->h_source;
+
+ switch (mld_hdr->mld_type) {
+ case ICMPV6_MGM_REPORT:
+ group_addr.u.ip6 = mld_hdr->mld_mca;
+ if (ipv6_addr_is_ll_all_nodes(&group_addr.u.ip6))
+ return 0;
+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
+ break;
+ case ICMPV6_MGM_REDUCTION:
+ group_addr.u.ip6 = mld_hdr->mld_mca;
+ if (ipv6_addr_is_ll_all_nodes(&group_addr.u.ip6))
+ return 0;
+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
+ break;
+ case ICMPV6_MLD2_REPORT:
+ icmpv6_hdr = icmp6_hdr(skb);
+ group_num = ntohs(icmpv6_hdr->icmp6_dataun.un_data16[1]);
+ grec = (struct mld2_grec *)(skb_transport_header(skb) + sizeof(struct icmp6hdr));
+
+ for (i = 0; i < group_num; i++) {
+ group_type = grec->grec_type;
+ aux_data_len = grec->grec_auxwords;
+ num_of_source = ntohs(grec->grec_nsrcs);
+ group_addr.u.ip6 = grec->grec_mca;
+ if (ipv6_addr_is_ll_all_nodes(&group_addr.u.ip6))
+ return 0;
+
+ if ((group_type == MLD2_MODE_IS_EXCLUDE ||
+ group_type == MLD2_CHANGE_TO_EXCLUDE ||
+ group_type == MLD2_ALLOW_NEW_SOURCES) &&
+ num_of_source == 0)
+ ovs_multicast_add_group(&group_addr, dl_src, input_vport);
+ else if ((group_type == MLD2_MODE_IS_INCLUDE ||
+ group_type == MLD2_CHANGE_TO_INCLUDE ||
+ group_type == MLD2_BLOCK_OLD_SOURCES) &&
+ num_of_source == 0)
+ ovs_multicast_leave_group(&group_addr, dl_src, input_vport);
+ else {
+ pr_info("%s(): group_type(%d), aux_data_len(%d),\
+ num_of_source(%d), group_addr(%pI6)\n",
+ __func__, group_type, aux_data_len,
+ num_of_source, &group_addr.u.ip6);
+ return 0;
+ }
+ grec = (struct mld2_grec *)((u8 *)grec + sizeof(struct mld2_grec)
+ + aux_data_len * sizeof(u32));
+ }
+ break;
+ case ICMPV6_MGM_QUERY:
+ break;
+ default:
+ pr_warning("%s(): error packet type 0x%x\n", __func__, mld_hdr->mld_type);
+ break;
+ }
+
+ return 0;
+}
+
+static int ovs_multicast_rcv(struct sk_buff *skb, struct vport *input_vport)
+{
+ int ret = 0;
+
+ if (!skb)
+ return -EINVAL;
+
+ switch (skb->protocol) {
+ case htons(ETH_P_IP):
+ ret = ovs_multicast_ipv4_rcv(skb, input_vport);
+ break;
+ case htons(ETH_P_IPV6):
+ ret = ovs_multicast_ipv6_rcv(skb, input_vport);
+ break;
+ }
+
+ return ret;
+}
+
static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
{
struct ovs_header *ovs_header = info->userhdr;
@@ -612,6 +880,9 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info)
OVS_CB(packet)->input_vport = input_vport;
sf_acts = rcu_dereference(flow->sf_acts);
+ if (is_multicast_addr(packet) && !is_icmpv6_ndp_rs_ra(packet))
+ ovs_multicast_rcv(packet, input_vport);
+
local_bh_disable();
err = ovs_execute_actions(dp, packet, sf_acts, &flow->key);
local_bh_enable();
@@ -2199,6 +2470,9 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
struct datapath *dp;
struct vport *vport;
unsigned int new_headroom;
+ struct multicast_data_base *mdb;
+ struct multicast_table *table, *table_tmp;
+ struct multicast_table_entry *entry, *entry_tmp;
int err;
reply = ovs_vport_cmd_alloc_info();
@@ -2226,6 +2500,22 @@ static int ovs_vport_cmd_del(struct sk_buff *skb, struct genl_info *info)
if (netdev_get_fwd_headroom(vport->dev) == dp->max_headroom)
update_headroom = true;
+ mdb = vport->mdb;
+ spin_lock_bh(&mdb->tbl_lock);
+ list_for_each_entry_safe(table, table_tmp, &mdb->list_head, mdb_node) {
+ list_for_each_entry_safe(entry, entry_tmp, &table->entry_list, entry_node) {
+ list_del(&entry->entry_node);
+ kfree(entry);
+
+ if (list_empty(&table->entry_list)) {
+ list_del(&table->mdb_node);
+ kfree(table);
+ }
+ }
+ }
+ spin_unlock_bh(&mdb->tbl_lock);
+ kfree(mdb);
+
netdev_reset_rx_headroom(vport->dev);
ovs_dp_detach_port(vport);
diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h
index 81e85dd..50596bc 100644
--- a/net/openvswitch/datapath.h
+++ b/net/openvswitch/datapath.h
@@ -215,6 +215,46 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex)
return dp;
}
+static inline bool is_multicast_addr(struct sk_buff *skb)
+{
+ struct ethhdr *eth_hdr;
+
+ if (!skb)
+ return 0;
+
+ eth_hdr = skb_eth_hdr(skb);
+
+ return (eth_hdr->h_dest[0] == 0x01 && skb->protocol == htons(ETH_P_IP)) ||
+ (eth_hdr->h_dest[0] == 0x33 && skb->protocol == htons(ETH_P_IPV6));
+}
+
+static inline bool is_igmp_mld(struct sk_buff *skb)
+{
+ struct ethhdr *eth_hdr;
+ int err = 0;
+
+ if (!skb)
+ return err;
+
+ eth_hdr = skb_eth_hdr(skb);
+
+ if (skb->protocol == htons(ETH_P_IP)) {
+ err = ip_hdr(skb)->protocol == IPPROTO_IGMP;
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ err = !ipv6_mc_check_mld(skb);
+ }
+
+ return err;
+}
+
+static inline bool is_icmpv6_ndp_rs_ra(struct sk_buff *skb)
+{
+ if (!skb)
+ return 0;
+
+ return ((icmp6_hdr(skb)->icmp6_type == NDISC_ROUTER_SOLICITATION) && (icmp6_hdr(skb)->icmp6_type == NDISC_ROUTER_ADVERTISEMENT));
+}
+
extern struct notifier_block ovs_dp_device_notifier;
extern struct genl_family dp_vport_genl_family;
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 19af0ef..77bc923 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -141,6 +141,14 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops,
return ERR_PTR(-EINVAL);
}
+ vport->mdb = kzalloc(sizeof(struct multicast_data_base), GFP_KERNEL);
+ if (!vport->mdb) {
+ kfree(vport);
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_LIST_HEAD(&vport->mdb->list_head);
+ spin_lock_init(&vport->mdb->tbl_lock);
+
return vport;
}
EXPORT_SYMBOL_GPL(ovs_vport_alloc);
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index 1eb7495..eb69d6c 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -55,6 +55,30 @@ struct vport_portids {
u32 ids[];
};
+struct ip_addr {
+ union {
+ __be32 ip4;
+ struct in6_addr ip6;
+ } u;
+};
+
+struct multicast_table_entry {
+ struct list_head entry_node;
+ u8 eth_addr[ETH_ALEN];
+};
+
+struct multicast_table {
+ struct list_head mdb_node;
+ struct list_head entry_list;
+ struct ip_addr group_addr;
+};
+
+struct multicast_data_base {
+ struct list_head list_head;
+ spinlock_t tbl_lock;
+};
+
+
/**
* struct vport - one port within a datapath
* @dev: Pointer to net_device.
@@ -79,6 +103,8 @@ struct vport {
struct list_head detach_list;
struct rcu_head rcu;
+
+ struct multicast_data_base *mdb;
};
/**
--
2.18.0

View File

@@ -1,181 +0,0 @@
From f99c7b63e766c2ff8851a8ba6ff77f3d8bfef0d5 Mon Sep 17 00:00:00 2001
From: Bo Jiao <Bo.Jiao@mediatek.com>
Date: Mon, 18 Sep 2023 10:55:08 +0800
Subject: [PATCH 02/24] dts netsys2 wed changes
---
.../boot/dts/mediatek/mt7981-spim-nor-rfb.dts | 8 -----
arch/arm64/boot/dts/mediatek/mt7981.dtsi | 21 ++++--------
arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 33 +++++++------------
arch/arm64/boot/dts/mediatek/mt7986b.dtsi | 33 +++++++------------
4 files changed, 28 insertions(+), 67 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts b/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
index 3fa55a0..f5c70a4 100755
--- a/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7981-spim-nor-rfb.dts
@@ -211,11 +211,3 @@
&xhci {
status = "okay";
};
-
-&wed {
- dy_txbm_enable = "true";
- dy_txbm_budget = <8>;
- txbm_init_sz = <8>;
- txbm_max_sz = <32>;
- status = "okay";
-};
diff --git a/arch/arm64/boot/dts/mediatek/mt7981.dtsi b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
index 91415e4..283421a 100644
--- a/arch/arm64/boot/dts/mediatek/mt7981.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7981.dtsi
@@ -90,22 +90,12 @@
#io-channel-cells = <1>;
};
- wed: wed@15010000 {
- compatible = "mediatek,wed";
- wed_num = <2>;
- /* add this property for wed get the pci slot number. */
- pci_slot_map = <0>, <1>;
- reg = <0 0x15010000 0 0x1000>,
- <0 0x15011000 0 0x1000>;
+ wed0: wed@15010000 {
+ compatible = "mediatek,mt7981-wed",
+ "syscon";
+ reg = <0 0x15010000 0 0x1000>;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- wdma: wdma@15104800 {
- compatible = "mediatek,wed-wdma";
- reg = <0 0x15104800 0 0x400>,
- <0 0x15104c00 0 0x400>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
};
ap2woccif: ap2woccif@151A5000 {
@@ -423,6 +413,7 @@
mediatek,ethsys = <&ethsys>;
mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
mediatek,infracfg = <&topmisc>;
+ mediatek,wed = <&wed0>;
#reset-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
index 2c7e171..3a4f279 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -58,32 +58,20 @@
};
};
- wed: wed@15010000 {
- compatible = "mediatek,wed";
- wed_num = <2>;
- /* add this property for wed get the pci slot number. */
- pci_slot_map = <0>, <1>;
- reg = <0 0x15010000 0 0x1000>,
- <0 0x15011000 0 0x1000>;
+ wed0: wed@15010000 {
+ compatible = "mediatek,mt7986-wed",
+ "syscon";
+ reg = <0 0x15010000 0 0x1000>;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
};
- wed2: wed2@15011000 {
- compatible = "mediatek,wed2";
- wed_num = <2>;
- reg = <0 0x15010000 0 0x1000>,
- <0 0x15011000 0 0x1000>;
+ wed1: wed@15011000 {
+ compatible = "mediatek,mt7986-wed",
+ "syscon";
+ reg = <0 0x15011000 0 0x1000>;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- wdma: wdma@15104800 {
- compatible = "mediatek,wed-wdma";
- reg = <0 0x15104800 0 0x400>,
- <0 0x15104c00 0 0x400>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
};
ap2woccif: ap2woccif@151A5000 {
@@ -494,6 +482,7 @@
<&topckgen CK_TOP_CB_SGM_325M>;
mediatek,ethsys = <&ethsys>;
mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+ mediatek,wed = <&wed0>, <&wed1>;
#reset-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
index 26f093b..ce884f0 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986b.dtsi
@@ -58,32 +58,20 @@
};
};
- wed: wed@15010000 {
- compatible = "mediatek,wed";
- wed_num = <2>;
- /* add this property for wed get the pci slot number. */
- pci_slot_map = <0>, <1>;
- reg = <0 0x15010000 0 0x1000>,
- <0 0x15011000 0 0x1000>;
+ wed0: wed@15010000 {
+ compatible = "mediatek,mt7986-wed",
+ "syscon";
+ reg = <0 0x15010000 0 0x1000>;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
+ interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>;
};
- wed2: wed2@15011000 {
- compatible = "mediatek,wed2";
- wed_num = <2>;
- reg = <0 0x15010000 0 0x1000>,
- <0 0x15011000 0 0x1000>;
+ wed1: wed@15011000 {
+ compatible = "mediatek,mt7986-wed",
+ "syscon";
+ reg = <0 0x15011000 0 0x1000>;
interrupt-parent = <&gic>;
- interrupts = <GIC_SPI 205 IRQ_TYPE_LEVEL_HIGH>,
- <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
- };
-
- wdma: wdma@15104800 {
- compatible = "mediatek,wed-wdma";
- reg = <0 0x15104800 0 0x400>,
- <0 0x15104c00 0 0x400>;
+ interrupts = <GIC_SPI 206 IRQ_TYPE_LEVEL_HIGH>;
};
ap2woccif: ap2woccif@151A5000 {
@@ -408,6 +396,7 @@
<&topckgen CK_TOP_CB_SGM_325M>;
mediatek,ethsys = <&ethsys>;
mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
+ mediatek,wed = <&wed0>, <&wed1>;
#reset-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
--
2.18.0

File diff suppressed because it is too large Load Diff

View File

@@ -1,354 +0,0 @@
From 07a3ac0ae724c4df67316e01b03432d8ee9f4229 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Mar 2024 17:56:01 +0800
Subject: [PATCH 04/24] ethernet update ppe from netsys1 to netsys2
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 19 ++++---
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 7 ++-
drivers/net/ethernet/mediatek/mtk_ppe.c | 29 +++++++++--
drivers/net/ethernet/mediatek/mtk_ppe.h | 51 +++++++++++++++++++
.../net/ethernet/mediatek/mtk_ppe_offload.c | 8 +++
drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 10 ++++
6 files changed, 112 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index ffaa515..9262227 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2447,16 +2447,20 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, netdev);
+#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
+ hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
+ reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
+ if (hash != MTK_RXD5_FOE_ENTRY_V2)
+ skb_set_hash(skb, jhash_1word(hash, 0), PKT_HASH_TYPE_L4);
+#else
hash = trxd.rxd4 & MTK_RXD4_FOE_ENTRY;
- if (hash != MTK_RXD4_FOE_ENTRY) {
- hash = jhash_1word(hash, 0);
- skb_set_hash(skb, hash, PKT_HASH_TYPE_L4);
- }
-
reason = FIELD_GET(MTK_RXD4_PPE_CPU_REASON, trxd.rxd4);
+ if (hash != MTK_RXD4_FOE_ENTRY)
+ skb_set_hash(skb, jhash_1word(hash, 0), PKT_HASH_TYPE_L4);
+#endif
+
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
- mtk_ppe_check_skb(eth->ppe, skb,
- trxd.rxd4 & MTK_RXD4_FOE_ENTRY);
+ mtk_ppe_check_skb(eth->ppe, skb, hash);
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
@@ -5957,6 +5961,7 @@ static const struct mtk_soc_data mt7986_data = {
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .offload_version = 2,
.rss_num = 4,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 41daeb2..910baaf 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -137,7 +137,7 @@
#define MTK_GDMA_UCS_EN BIT(20)
#define MTK_GDMA_STRP_CRC BIT(16)
#define MTK_GDMA_TO_PDMA 0x0
-#define MTK_GDMA_TO_PPE 0x4444
+#define MTK_GDMA_TO_PPE 0x3333
#define MTK_GDMA_DROP_ALL 0x7777
/* GDM Egress Control Register */
@@ -680,6 +680,11 @@
#define MTK_RXD4_SRC_PORT GENMASK(21, 19)
#define MTK_RXD4_ALG GENMASK(31, 22)
+/* QDMA descriptor rxd4 */
+#define MTK_RXD5_FOE_ENTRY_V2 GENMASK(14, 0)
+#define MTK_RXD5_PPE_CPU_REASON_V2 GENMASK(22, 18)
+#define MTK_RXD5_SRC_PORT_V2 GENMASK(29, 26)
+
/* QDMA descriptor rxd4 */
#define RX_DMA_L4_VALID BIT(24)
#define RX_DMA_L4_VALID_PDMA BIT(30) /* when PDMA is used */
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index eeaec1b..e195fb3 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -122,7 +122,7 @@ static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
hash = (hash >> 24) | ((hash & 0xffffff) << 8);
hash ^= hv1 ^ hv2 ^ hv3;
hash ^= hash >> 16;
- hash <<= 1;
+ hash <<= 2;
hash &= MTK_PPE_ENTRIES - 1;
return hash;
@@ -171,8 +171,12 @@ int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
MTK_FOE_IB1_BIND_CACHE;
entry->ib1 = val;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ val = FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0xf) |
+#else
val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0x1f) |
+#endif
FIELD_PREP(MTK_FOE_IB2_DEST_PORT, pse_port);
if (is_multicast_ether_addr(dest_mac))
@@ -359,12 +363,19 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
*ib2 &= ~MTK_FOE_IB2_PORT_MG;
*ib2 |= MTK_FOE_IB2_WDMA_WINFO;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq);
+
+ l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
+ FIELD_PREP(MTK_FOE_WINFO_BSS, bss);
+#else
if (wdma_idx)
*ib2 |= MTK_FOE_IB2_WDMA_DEVIDX;
l2->vlan2 = FIELD_PREP(MTK_FOE_VLAN2_WINFO_BSS, bss) |
FIELD_PREP(MTK_FOE_VLAN2_WINFO_WCID, wcid) |
FIELD_PREP(MTK_FOE_VLAN2_WINFO_RING, txq);
+#endif
return 0;
}
@@ -746,6 +757,9 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
MTK_PPE_TB_CFG_AGE_TCP |
MTK_PPE_TB_CFG_AGE_UDP |
MTK_PPE_TB_CFG_AGE_TCP_FIN |
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ MTK_PPE_TB_CFG_INFO_SEL |
+#endif
FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
MTK_PPE_SEARCH_MISS_ACTION_FORWARD_BUILD) |
FIELD_PREP(MTK_PPE_TB_CFG_KEEPALIVE,
@@ -762,15 +776,17 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
mtk_ppe_cache_enable(ppe, true);
- val = MTK_PPE_FLOW_CFG_IP4_TCP_FRAG |
- MTK_PPE_FLOW_CFG_IP4_UDP_FRAG |
+ val = MTK_PPE_MD_TOAP_BYP_CRSN0 |
+ MTK_PPE_MD_TOAP_BYP_CRSN1 |
+ MTK_PPE_MD_TOAP_BYP_CRSN2 |
MTK_PPE_FLOW_CFG_IP6_3T_ROUTE |
MTK_PPE_FLOW_CFG_IP6_5T_ROUTE |
MTK_PPE_FLOW_CFG_IP6_6RD |
MTK_PPE_FLOW_CFG_IP4_NAT |
MTK_PPE_FLOW_CFG_IP4_NAPT |
MTK_PPE_FLOW_CFG_IP4_DSLITE |
- MTK_PPE_FLOW_CFG_IP4_NAT_FRAG;
+ MTK_PPE_FLOW_CFG_IP4_NAT_FRAG |
+ MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY;
ppe_w32(ppe, MTK_PPE_FLOW_CFG, val);
val = FIELD_PREP(MTK_PPE_UNBIND_AGE_MIN_PACKETS, 1000) |
@@ -806,6 +822,11 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777);
+ ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
+#endif
+
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 1f5cf1c..7012351 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -8,7 +8,11 @@
#include <linux/bitfield.h>
#include <linux/rhashtable.h>
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_ETH_PPE_BASE 0x2000
+#else
#define MTK_ETH_PPE_BASE 0xc00
+#endif
#define MTK_PPE_ENTRIES_SHIFT 3
#define MTK_PPE_ENTRIES (1024 << MTK_PPE_ENTRIES_SHIFT)
@@ -16,6 +20,24 @@
#define MTK_PPE_WAIT_TIMEOUT_US 1000000
#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_FOE_IB1_UNBIND_SRC_PORT GENMASK(11, 8)
+#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(19, 12)
+#define MTK_FOE_IB1_UNBIND_PREBIND BIT(22)
+#define MTK_FOE_IB1_UNBIND_PACKET_TYPE GENMASK(27, 23)
+#define MTK_FOE_IB1_BIND_TIMESTAMP GENMASK(7, 0)
+#define MTK_FOE_IB1_BIND_SRC_PORT GENMASK(11, 8)
+#define MTK_FOE_IB1_BIND_MC BIT(12)
+#define MTK_FOE_IB1_BIND_KEEPALIVE BIT(13)
+#define MTK_FOE_IB1_BIND_VLAN_LAYER GENMASK(16, 14)
+#define MTK_FOE_IB1_BIND_PPPOE BIT(17)
+#define MTK_FOE_IB1_BIND_VLAN_TAG BIT(18)
+#define MTK_FOE_IB1_BIND_PKT_SAMPLE BIT(19)
+#define MTK_FOE_IB1_BIND_CACHE BIT(20)
+#define MTK_FOE_IB1_BIND_TUNNEL_DECAP BIT(21)
+#define MTK_FOE_IB1_BIND_TTL BIT(22)
+#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 23)
+#else
#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(23, 8)
#define MTK_FOE_IB1_UNBIND_PREBIND BIT(24)
@@ -30,6 +52,8 @@
#define MTK_FOE_IB1_BIND_TTL BIT(24)
#define MTK_FOE_IB1_PACKET_TYPE GENMASK(27, 25)
+#endif
+
#define MTK_FOE_IB1_STATE GENMASK(29, 28)
#define MTK_FOE_IB1_UDP BIT(30)
#define MTK_FOE_IB1_STATIC BIT(31)
@@ -44,24 +68,42 @@ enum {
MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
};
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_FOE_IB2_QID GENMASK(6, 0)
+#define MTK_FOE_IB2_PORT_MG BIT(7)
+#define MTK_FOE_IB2_PSE_QOS BIT(8)
+#define MTK_FOE_IB2_DEST_PORT GENMASK(12, 9)
+#define MTK_FOE_IB2_MULTICAST BIT(13)
+#define MTK_FOE_IB2_MIB_CNT BIT(15)
+#define MTK_FOE_IB2_RX_IDX GENMASK(18, 17)
+#define MTK_FOE_IB2_WDMA_WINFO BIT(19)
+#define MTK_FOE_IB2_PORT_AG GENMASK(23, 20)
+#else
#define MTK_FOE_IB2_QID GENMASK(3, 0)
#define MTK_FOE_IB2_PSE_QOS BIT(4)
#define MTK_FOE_IB2_DEST_PORT GENMASK(7, 5)
#define MTK_FOE_IB2_MULTICAST BIT(8)
#define MTK_FOE_IB2_WDMA_QID2 GENMASK(13, 12)
+#define MTK_FOE_IB2_MIB_CNT BIT(15)
#define MTK_FOE_IB2_WDMA_DEVIDX BIT(16)
#define MTK_FOE_IB2_WDMA_WINFO BIT(17)
#define MTK_FOE_IB2_PORT_MG GENMASK(17, 12)
#define MTK_FOE_IB2_PORT_AG GENMASK(23, 18)
+#endif
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_FOE_WINFO_BSS GENMASK(5, 0)
+#define MTK_FOE_WINFO_WCID GENMASK(15, 6)
+#else
#define MTK_FOE_VLAN2_WINFO_BSS GENMASK(5, 0)
#define MTK_FOE_VLAN2_WINFO_WCID GENMASK(13, 6)
#define MTK_FOE_VLAN2_WINFO_RING GENMASK(15, 14)
+#endif
enum {
MTK_FOE_STATE_INVALID,
@@ -83,6 +125,11 @@ struct mtk_foe_mac_info {
u16 pppoe_id;
u16 src_mac_lo;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ u16 minfo;
+ u16 winfo;
+#endif
};
/* software-only entry type */
@@ -200,7 +247,11 @@ struct mtk_foe_entry {
struct mtk_foe_ipv4_dslite dslite;
struct mtk_foe_ipv6 ipv6;
struct mtk_foe_ipv6_6rd ipv6_6rd;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ u32 data[23];
+#else
u32 data[19];
+#endif
};
};
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index 8a28572..77594f3 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -193,6 +193,14 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
info.wcid);
pse_port = PSE_PPE0_PORT;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ if (info.wdma_idx == 0)
+ pse_port = PSE_WDMA0_PORT;
+ else if (info.wdma_idx == 1)
+ pse_port = PSE_WDMA1_PORT;
+ else
+ return -EOPNOTSUPP;
+#endif
*wed_index = info.wdma_idx;
goto out;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
index 0c45ea0..d319f18 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
@@ -21,6 +21,9 @@
#define MTK_PPE_GLO_CFG_BUSY BIT(31)
#define MTK_PPE_FLOW_CFG 0x204
+#define MTK_PPE_MD_TOAP_BYP_CRSN0 BIT(1)
+#define MTK_PPE_MD_TOAP_BYP_CRSN1 BIT(2)
+#define MTK_PPE_MD_TOAP_BYP_CRSN2 BIT(3)
#define MTK_PPE_FLOW_CFG_IP4_TCP_FRAG BIT(6)
#define MTK_PPE_FLOW_CFG_IP4_UDP_FRAG BIT(7)
#define MTK_PPE_FLOW_CFG_IP6_3T_ROUTE BIT(8)
@@ -35,6 +38,8 @@
#define MTK_PPE_FLOW_CFG_IP4_HASH_FLOW_LABEL BIT(18)
#define MTK_PPE_FLOW_CFG_IP4_HASH_GRE_KEY BIT(19)
#define MTK_PPE_FLOW_CFG_IP6_HASH_GRE_KEY BIT(20)
+#define MTK_PPE_FLOW_CFG_IPV4_MAPE_EN BIT(21)
+#define MTK_PPE_FLOW_CFG_IPV4_MAPT_EN BIT(22)
#define MTK_PPE_IP_PROTO_CHK 0x208
#define MTK_PPE_IP_PROTO_CHK_IPV4 GENMASK(15, 0)
@@ -54,6 +59,7 @@
#define MTK_PPE_TB_CFG_HASH_MODE GENMASK(15, 14)
#define MTK_PPE_TB_CFG_SCAN_MODE GENMASK(17, 16)
#define MTK_PPE_TB_CFG_HASH_DEBUG GENMASK(19, 18)
+#define MTK_PPE_TB_CFG_INFO_SEL BIT(20)
enum {
MTK_PPE_SCAN_MODE_DISABLED,
@@ -111,6 +117,8 @@ enum {
#define MTK_PPE_DEFAULT_CPU_PORT 0x248
#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4))
+#define MTK_PPE_DEFAULT_CPU_PORT1 0x24C
+#define MTK_PPE_DEFAULT_CPU_PORT_MASK(_n) (GENMASK(2, 0) << ((_n) * 4))
#define MTK_PPE_MTU_DROP 0x308
@@ -141,4 +149,6 @@ enum {
#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
+#define MTK_PPE_SBW_CTRL 0x374
+
#endif
--
2.18.0

View File

@@ -1,463 +0,0 @@
From 01556d88ad11f0d096d2816b2a69999994e1740f Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Mar 2024 16:26:28 +0800
Subject: [PATCH 05/24] flow-offload-add-mkhnat-dual-ppe-new-v2
---
arch/arm64/boot/dts/mediatek/mt7986a.dtsi | 1 +
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 50 ++++++++++++++-----
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 14 ++++--
drivers/net/ethernet/mediatek/mtk_ppe.c | 5 +-
drivers/net/ethernet/mediatek/mtk_ppe.h | 7 ++-
.../net/ethernet/mediatek/mtk_ppe_debugfs.c | 27 +++++++---
.../net/ethernet/mediatek/mtk_ppe_offload.c | 48 ++++++++++++++----
include/linux/netdevice.h | 4 ++
8 files changed, 119 insertions(+), 37 deletions(-)
mode change 100644 => 100755 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
diff --git a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
index 3a4f279..d70151b 100644
--- a/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7986a.dtsi
@@ -483,6 +483,7 @@
mediatek,ethsys = <&ethsys>;
mediatek,sgmiisys = <&sgmiisys0>, <&sgmiisys1>;
mediatek,wed = <&wed0>, <&wed1>;
+ mtketh-ppe-num = <2>;
#reset-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 2fb67e0..7eeddb3 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2464,7 +2464,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
#endif
if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
- mtk_ppe_check_skb(eth->ppe, skb, hash);
+ mtk_ppe_check_skb(eth->ppe[0], skb, hash);
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
@@ -4112,8 +4112,12 @@ static int mtk_open(struct net_device *dev)
regmap_write(eth->sgmii->pcs[id].regmap,
SGMSYS_QPHY_PWR_STATE_CTRL, 0);
- if (eth->soc->offload_version && mtk_ppe_start(&eth->ppe) == 0)
- gdm_config = MTK_GDMA_TO_PPE;
+ if (eth->soc->offload_version) {
+ gdm_config = MTK_GDMA_TO_PPE0;
+
+ for (i = 0; i < eth->ppe_num; i++)
+ mtk_ppe_start(eth->ppe[i]);
+ }
mtk_gdm_config(eth, mac->id, gdm_config);
@@ -4202,8 +4206,10 @@ static int mtk_stop(struct net_device *dev)
mtk_dma_free(eth);
- if (eth->soc->offload_version)
- mtk_ppe_stop(eth->ppe);
+ if (eth->soc->offload_version) {
+ for (i = 0; i < eth->ppe_num; i++)
+ mtk_ppe_stop(eth->ppe[i]);
+ }
return 0;
}
@@ -5762,15 +5768,35 @@ static int mtk_probe(struct platform_device *pdev)
}
if (eth->soc->offload_version) {
- eth->ppe = mtk_ppe_init(eth, eth->base + MTK_ETH_PPE_BASE, 2);
- if (!eth->ppe) {
- err = -ENOMEM;
- goto err_free_dev;
+ unsigned int val;
+
+ err = of_property_read_u32_index(pdev->dev.of_node, "mtketh-ppe-num", 0, &val);
+ if (err < 0)
+ eth->ppe_num = 1;
+ else
+ eth->ppe_num = val;
+
+ if (eth->ppe_num > MTK_MAX_PPE_NUM) {
+ dev_warn(&pdev->dev, "%d is not a valid ppe num, please check mtketh-ppe-num in dts !", eth->ppe_num);
+ eth->ppe_num = MTK_MAX_PPE_NUM;
}
- err = mtk_eth_offload_init(eth);
- if (err)
- goto err_free_dev;
+ dev_info(&pdev->dev, "ppe num = %d\n", eth->ppe_num);
+
+ for (i = 0; i < eth->ppe_num; i++) {
+ eth->ppe[i] = mtk_ppe_init(eth,
+ eth->base + MTK_ETH_PPE_BASE + i * 0x400, 2, i);
+ if (!eth->ppe[i]) {
+ err = -ENOMEM;
+ goto err_free_dev;
+ }
+
+ err = mtk_eth_offload_init(eth, i);
+ if (err)
+ goto err_free_dev;
+ }
+
+ mtk_ppe_debugfs_init(eth);
}
for (i = 0; i < MTK_MAX_DEVS; i++) {
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 910baaf..3995608 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -137,7 +137,12 @@
#define MTK_GDMA_UCS_EN BIT(20)
#define MTK_GDMA_STRP_CRC BIT(16)
#define MTK_GDMA_TO_PDMA 0x0
-#define MTK_GDMA_TO_PPE 0x3333
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_GDMA_TO_PPE0 0x3333
+#define MTK_GDMA_TO_PPE1 0x4444
+#else
+#define MTK_GDMA_TO_PPE0 0x4444
+#endif
#define MTK_GDMA_DROP_ALL 0x7777
/* GDM Egress Control Register */
@@ -1936,7 +1941,8 @@ struct mtk_eth {
spinlock_t syscfg0_lock;
struct timer_list mtk_dma_monitor_timer;
- struct mtk_ppe *ppe;
+ u8 ppe_num;
+ struct mtk_ppe *ppe[MTK_MAX_PPE_NUM];
struct rhashtable flow_table;
};
@@ -2019,9 +2025,11 @@ int mtk_toprgu_init(struct mtk_eth *eth, struct device_node *r);
int mtk_dump_usxgmii(struct regmap *pmap, char *name, u32 offset, u32 range);
void mtk_usxgmii_link_poll(struct work_struct *work);
-int mtk_eth_offload_init(struct mtk_eth *eth);
+int mtk_eth_offload_init(struct mtk_eth *eth, int id);
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
+
+int mtk_ppe_debugfs_init(struct mtk_eth *eth);
#endif /* MTK_ETH_H */
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index e195fb3..c9ee505 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -696,7 +696,7 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
}
struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
- int version)
+ int version, int id)
{
struct device *dev = eth->dev;
struct mtk_foe_entry *foe;
@@ -715,6 +715,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->eth = eth;
ppe->dev = dev;
ppe->version = version;
+ ppe->id = id;
foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
&ppe->foe_phys, GFP_KERNEL);
@@ -723,8 +724,6 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->foe_table = foe;
- mtk_ppe_debugfs_init(ppe);
-
return ppe;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 7012351..86bbac8 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -9,8 +9,10 @@
#include <linux/rhashtable.h>
#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#define MTK_MAX_PPE_NUM 2
#define MTK_ETH_PPE_BASE 0x2000
#else
+#define MTK_MAX_PPE_NUM 1
#define MTK_ETH_PPE_BASE 0xc00
#endif
@@ -299,6 +301,7 @@ struct mtk_flow_entry {
};
};
u8 type;
+ s8 ppe_index;
s8 wed_index;
u16 hash;
union {
@@ -318,6 +321,7 @@ struct mtk_ppe {
struct device *dev;
void __iomem *base;
int version;
+ int id;
struct mtk_foe_entry *foe_table;
dma_addr_t foe_phys;
@@ -330,7 +334,7 @@ struct mtk_ppe {
void *acct_table;
};
-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version);
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int id);
int mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
@@ -381,6 +385,5 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
-int mtk_ppe_debugfs_init(struct mtk_ppe *ppe);
#endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
index a591ab1..f4ebe59 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
@@ -73,9 +73,8 @@ mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
}
static int
-mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
+mtk_ppe_debugfs_foe_show(struct seq_file *m, struct mtk_ppe *ppe, bool bind)
{
- struct mtk_ppe *ppe = m->private;
int i;
for (i = 0; i < MTK_PPE_ENTRIES; i++) {
@@ -122,6 +121,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
break;
}
+ seq_printf(m, " ppe=%d", ppe->id);
+
seq_printf(m, " orig=");
mtk_print_addr_info(m, &ai);
@@ -164,13 +165,25 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
static int
mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
{
- return mtk_ppe_debugfs_foe_show(m, private, false);
+ struct mtk_eth *eth = m->private;
+ int i;
+
+ for (i = 0; i < eth->ppe_num; i++)
+ mtk_ppe_debugfs_foe_show(m, eth->ppe[i], false);
+
+ return 0;
}
static int
mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
{
- return mtk_ppe_debugfs_foe_show(m, private, true);
+ struct mtk_eth *eth = m->private;
+ int i;
+
+ for (i = 0; i < eth->ppe_num; i++)
+ mtk_ppe_debugfs_foe_show(m, eth->ppe[i], true);
+
+ return 0;
}
static int
@@ -187,7 +200,7 @@ mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
inode->i_private);
}
-int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
+int mtk_ppe_debugfs_init(struct mtk_eth *eth)
{
static const struct file_operations fops_all = {
.open = mtk_ppe_debugfs_foe_open_all,
@@ -209,8 +222,8 @@ int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
if (!root)
return -ENOMEM;
- debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
- debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
+ debugfs_create_file("entries", S_IRUGO, root, eth, &fops_all);
+ debugfs_create_file("bind", S_IRUGO, root, eth, &fops_bind);
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
old mode 100644
new mode 100755
index 77594f3..f256607
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -229,9 +229,12 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
struct flow_action_entry *act;
struct mtk_flow_data data = {};
struct mtk_foe_entry foe;
- struct net_device *odev = NULL;
+ struct net_device *idev = NULL, *odev = NULL;
struct mtk_flow_entry *entry;
+ struct net_device_path_ctx ctx = {};
+ struct net_device_path path = {};
int offload_type = 0;
+ int ppe_index = 0;
int wed_index = -1;
u16 addr_type = 0;
u8 l4proto = 0;
@@ -245,6 +248,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
struct flow_match_meta match;
flow_rule_match_meta(rule, &match);
+ idev = __dev_get_by_index(&init_net, match.key->ingress_ifindex);
+
+ if (!idev)
+ pr_info("[%s] idev doesn't exist !\n", __func__);
} else {
return -EOPNOTSUPP;
}
@@ -347,6 +354,20 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (err)
return err;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ if (idev && idev->netdev_ops->ndo_fill_receive_path) {
+ ctx.dev = idev;
+ idev->netdev_ops->ndo_fill_receive_path(&ctx, &path);
+ ppe_index = path.mtk_wdma.wdma_idx;
+ if (ppe_index >= eth->ppe_num) {
+ if (printk_ratelimit())
+ pr_info("[%s] PPE%d doesn't exist, please check mtketh-ppe-num in dts !\n", __func__, ppe_index);
+
+ return -EINVAL;
+ }
+ }
+#endif
+
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_PORTS)) {
struct flow_match_ports ports;
@@ -440,9 +461,10 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
entry->cookie = f->cookie;
memcpy(&entry->data, &foe, sizeof(entry->data));
+ entry->ppe_index = ppe_index;
entry->wed_index = wed_index;
- if (mtk_foe_entry_commit(eth->ppe, entry) < 0)
+ if (mtk_foe_entry_commit(eth->ppe[ppe_index], entry) < 0)
goto free;
err = rhashtable_insert_fast(&eth->flow_table, &entry->node,
@@ -453,7 +475,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
return 0;
clear:
- mtk_foe_entry_clear(eth->ppe, entry);
+ mtk_foe_entry_clear(eth->ppe[ppe_index], entry);
free:
kfree(entry);
if (wed_index >= 0)
@@ -465,13 +487,15 @@ static int
mtk_flow_offload_destroy(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
+ int i;
entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
mtk_flow_ht_params);
if (!entry)
return -ENOENT;
- mtk_foe_entry_clear(eth->ppe, entry);
+ i = entry->ppe_index;
+ mtk_foe_entry_clear(eth->ppe[i], entry);
rhashtable_remove_fast(&eth->flow_table, &entry->node,
mtk_flow_ht_params);
if (entry->wed_index >= 0)
@@ -486,13 +510,15 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
u32 idle;
+ int i;
entry = rhashtable_lookup(&eth->flow_table, &f->cookie,
mtk_flow_ht_params);
if (!entry)
return -ENOENT;
- idle = mtk_foe_entry_idle_time(eth->ppe, entry);
+ i = entry->ppe_index;
+ idle = mtk_foe_entry_idle_time(eth->ppe[i], entry);
f->stats.lastused = jiffies - idle * HZ;
return 0;
@@ -543,10 +569,12 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
static LIST_HEAD(block_cb_list);
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
- int err = 0;
+ int i, err = 0;
- if (!eth->ppe || !eth->ppe->foe_table)
- return -EOPNOTSUPP;
+ for (i = 0; i < eth->ppe_num; i++) {
+ if (!eth->ppe[i] || !eth->ppe[i]->foe_table)
+ return -EOPNOTSUPP;
+ }
if (f->binder_type != FLOW_BLOCK_BINDER_TYPE_CLSACT_INGRESS)
return -EOPNOTSUPP;
@@ -603,9 +631,9 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
}
}
-int mtk_eth_offload_init(struct mtk_eth *eth)
+int mtk_eth_offload_init(struct mtk_eth *eth, int id)
{
- if (!eth->ppe || !eth->ppe->foe_table)
+ if (!eth->ppe[id] || !eth->ppe[id]->foe_table)
return 0;
return rhashtable_init(&eth->flow_table, &mtk_flow_ht_params);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5305384..b2abebe 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1316,6 +1316,8 @@ struct tlsdev_ops;
* rtnl_lock is not held.
* int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
* Get the forwarding path to reach the real device from the HW destination address
+ * int (*ndo_fill_receive_path)(struct net_device_path_ctx *ctx, struct net_device_path *path);
+ * Get the receiving path to reach the real device from the HW source address
*/
struct net_device_ops {
int (*ndo_init)(struct net_device *dev);
@@ -1515,6 +1517,8 @@ struct net_device_ops {
struct devlink_port * (*ndo_get_devlink_port)(struct net_device *dev);
int (*ndo_fill_forward_path)(struct net_device_path_ctx *ctx,
struct net_device_path *path);
+ int (*ndo_fill_receive_path)(struct net_device_path_ctx *ctx,
+ struct net_device_path *path);
};
/**
--
2.18.0

View File

@@ -1,73 +0,0 @@
From 7c68ae1b991064bc0904313c56b83d2f3e03ccd7 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Mon, 18 Sep 2023 11:03:33 +0800
Subject: [PATCH 07/24] add-wed-tx-wds-support-for-netsys2
---
drivers/net/ethernet/mediatek/mtk_wed.c | 6 ++++--
drivers/net/ethernet/mediatek/mtk_wed_regs.h | 1 +
include/linux/soc/mediatek/mtk_wed.h | 3 +++
3 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index 02e06a8..ea8b2db 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -813,7 +813,7 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
val |= BIT(0) | (BIT(1) * !!dev->hw->index);
regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
} else {
- mtk_wed_set_512_support(dev, true);
+ mtk_wed_set_512_support(dev, dev->wlan.wcid_512);
}
mtk_wed_dma_enable(dev);
@@ -869,9 +869,11 @@ mtk_wed_attach(struct mtk_wed_device *dev)
mtk_wed_hw_init_early(dev);
- if (hw->hifsys)
+ if (hw->version == 1)
regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
BIT(hw->index), 0);
+ else
+ dev->rev_id = wed_r32(dev, MTK_WED_REV_ID);
out:
mutex_unlock(&hw_lock);
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
index e66acda..e797e9d 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
@@ -26,6 +26,7 @@ struct mtk_wdma_desc {
#define MTK_WED_REV_ID 0x000
#define MTK_WED_REV_ID_MAJOR GENMASK(7, 0)
#endif
+#define MTK_WED_REV_ID_MINOR GENMASK(27, 16)
#define MTK_WED_RESET 0x008
#define MTK_WED_RESET_TX_BM BIT(0)
diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
index 4db70b0..00036f9 100644
--- a/include/linux/soc/mediatek/mtk_wed.h
+++ b/include/linux/soc/mediatek/mtk_wed.h
@@ -35,6 +35,7 @@ struct mtk_wed_device {
bool init_done, running;
int wdma_idx;
int irq;
+ u32 rev_id;
struct mtk_wed_ring tx_ring[MTK_WED_TX_QUEUES];
struct mtk_wed_ring txfree_ring;
@@ -68,6 +69,8 @@ struct mtk_wed_device {
u16 token_start;
unsigned int nbuf;
+ bool wcid_512;
+
u32 (*init_buf)(void *ptr, dma_addr_t phys, int token_id);
int (*offload_enable)(struct mtk_wed_device *wed);
void (*offload_disable)(struct mtk_wed_device *wed);
--
2.18.0

View File

@@ -1,860 +0,0 @@
From 7f1319357888271ea4aeeda81723b19a8f5ef2c0 Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Mon, 18 Sep 2023 11:05:45 +0800
Subject: [PATCH] add-wed-ser-support
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 +
drivers/net/ethernet/mediatek/mtk_wed.c | 391 ++++++++++++++-----
drivers/net/ethernet/mediatek/mtk_wed.h | 10 +
drivers/net/ethernet/mediatek/mtk_wed_regs.h | 9 +
include/linux/soc/mediatek/mtk_wed.h | 25 +-
5 files changed, 342 insertions(+), 101 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 268c9e7..a24b223 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -4619,6 +4619,9 @@ static void mtk_pending_work(struct work_struct *work)
for (i = 0; i < MTK_MAC_COUNT; i++) {
if (!eth->netdev[i])
continue;
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ mtk_wed_fe_reset();
+#else
if (mtk_reset_flag == MTK_FE_STOP_TRAFFIC) {
pr_info("send MTK_FE_STOP_TRAFFIC event\n");
call_netdevice_notifiers(MTK_FE_STOP_TRAFFIC,
@@ -4644,6 +4647,7 @@ static void mtk_pending_work(struct work_struct *work)
pr_warn("wait for MTK_FE_START_RESET\n");
}
rtnl_lock();
+#endif
break;
}
@@ -4682,6 +4686,9 @@ static void mtk_pending_work(struct work_struct *work)
for (i = 0; i < MTK_MAC_COUNT; i++) {
if (!eth->netdev[i])
continue;
+#ifdef CONFIG_NET_MEDIATEK_SOC_WED
+ mtk_wed_fe_reset_complete();
+#else
if (mtk_reset_flag == MTK_FE_STOP_TRAFFIC) {
pr_info("send MTK_FE_START_TRAFFIC event\n");
call_netdevice_notifiers(MTK_FE_START_TRAFFIC,
@@ -4691,6 +4698,7 @@ static void mtk_pending_work(struct work_struct *work)
call_netdevice_notifiers(MTK_FE_RESET_DONE,
eth->netdev[i]);
}
+#endif
call_netdevice_notifiers(MTK_FE_RESET_NAT_DONE,
eth->netdev[i]);
break;
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index ad9f3d5..b993f0e 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -13,8 +13,10 @@
#include <linux/debugfs.h>
#include <linux/iopoll.h>
#include <linux/soc/mediatek/mtk_wed.h>
+#include <net/rtnetlink.h>
#include "mtk_eth_soc.h"
+#include "mtk_eth_reset.h"
#include "mtk_wed_regs.h"
#include "mtk_wed.h"
#include "mtk_ppe.h"
@@ -80,10 +82,13 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_RX_DMA_EN);
ret = readx_poll_timeout(mtk_wdma_read_reset, dev, status,
- !(status & mask), 0, 1000)
+ !(status & mask), 0, 10000);
if (ret)
dev_err(dev->hw->dev, "rx reset failed \n");
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++) {
if (!dev->rx_wdma[i].desc)
continue;
@@ -91,6 +96,8 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
wdma_w32(dev,
MTK_WDMA_RING_RX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
}
+
+ return ret;
}
static void
@@ -101,16 +108,15 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
if (readx_poll_timeout(mtk_wdma_read_reset, dev, status,
- !(status & mask), 0, 1000))
+ !(status & mask), 0, 10000))
dev_err(dev->hw->dev, "tx reset failed \n");
- for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++) {
- if (!dev->tx_wdma[i].desc)
- continue;
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
+ wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+ for (i = 0; i < ARRAY_SIZE(dev->tx_wdma); i++)
wdma_w32(dev,
MTK_WDMA_RING_TX(i) + MTK_WED_RING_OFS_CPU_IDX, 0);
- }
}
static void
@@ -176,6 +182,59 @@ mtk_wed_wo_reset(struct mtk_wed_device *dev)
iounmap((void *)reg);
}
+void mtk_wed_fe_reset(void)
+{
+ int i;
+
+ mutex_lock(&hw_lock);
+
+ for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
+ struct mtk_wed_hw *hw = hw_list[i];
+ struct mtk_wed_device *dev;
+ int err;
+
+ if (!hw)
+ break;
+
+ dev = hw->wed_dev;
+ if (!dev || !dev->wlan.reset)
+ continue;
+
+ pr_info("%s: receive fe reset start event, trigger SER\n", __func__);
+
+ /* reset callback blocks until WLAN reset is completed */
+ err = dev->wlan.reset(dev);
+ if (err)
+ dev_err(dev->dev, "wlan reset failed: %d\n", err);
+ }
+
+ mutex_unlock(&hw_lock);
+}
+
+void mtk_wed_fe_reset_complete(void)
+{
+ int i;
+
+ mutex_lock(&hw_lock);
+
+ for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
+ struct mtk_wed_hw *hw = hw_list[i];
+ struct mtk_wed_device *dev;
+
+ if (!hw)
+ break;
+
+ dev = hw->wed_dev;
+ if (!dev || !dev->wlan.reset_complete)
+ continue;
+
+ pr_info("%s: receive fe reset done event, continue SER\n", __func__);
+ dev->wlan.reset_complete(dev);
+ }
+
+ mutex_unlock(&hw_lock);
+}
+
static struct mtk_wed_hw *
mtk_wed_assign(struct mtk_wed_device *dev)
{
@@ -473,8 +532,8 @@ mtk_wed_check_wfdma_rx_fill(struct mtk_wed_device *dev, int idx)
}
if (i == 3) {
- dev_err(dev->hw->dev, "mtk_wed%d: rx dma enable failed!\n",
- dev->hw->index);
+ dev_err(dev->hw->dev, "mtk_wed%d: rx(%d) dma enable failed!\n",
+ dev->hw->index, idx);
return;
}
@@ -522,16 +581,8 @@ mtk_wed_dma_disable(struct mtk_wed_device *dev)
static void
mtk_wed_stop(struct mtk_wed_device *dev)
{
- mtk_wed_dma_disable(dev);
-
mtk_wed_set_ext_int(dev, false);
- wed_clr(dev, MTK_WED_CTRL,
- MTK_WED_CTRL_WDMA_INT_AGENT_EN |
- MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
- MTK_WED_CTRL_WED_TX_BM_EN |
- MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
-
wed_w32(dev, MTK_WED_WPDMA_INT_TRIGGER, 0);
wed_w32(dev, MTK_WED_WDMA_INT_TRIGGER, 0);
wdma_w32(dev, MTK_WDMA_INT_MASK, 0);
@@ -543,39 +594,49 @@ mtk_wed_stop(struct mtk_wed_device *dev)
wed_w32(dev, MTK_WED_EXT_INT_MASK1, 0);
wed_w32(dev, MTK_WED_EXT_INT_MASK2, 0);
- wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
-
}
static void
-mtk_wed_detach(struct mtk_wed_device *dev)
+mtk_wed_deinit(struct mtk_wed_device *dev)
{
- struct device_node *wlan_node;
- struct mtk_wed_hw *hw = dev->hw;
+ mtk_wed_stop(dev);
+ mtk_wed_dma_disable(dev);
- mutex_lock(&hw_lock);
+ wed_clr(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_WDMA_INT_AGENT_EN |
+ MTK_WED_CTRL_WPDMA_INT_AGENT_EN |
+ MTK_WED_CTRL_WED_TX_BM_EN |
+ MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
- mtk_wed_stop(dev);
+ if (dev->hw->version == 1)
+ return;
- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+ wed_clr(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_RX_ROUTE_QM_EN |
+ MTK_WED_CTRL_WED_RX_BM_EN |
+ MTK_WED_CTRL_RX_RRO_QM_EN);
+}
- mtk_wed_reset(dev, MTK_WED_RESET_WED);
+static void
+__mtk_wed_detach(struct mtk_wed_device *dev)
+{
+ struct device_node *wlan_node;
+ struct mtk_wed_hw *hw = dev->hw;
- if (mtk_wed_get_rx_capa(dev)) {
- wdma_clr(dev, MTK_WDMA_GLO_CFG, MTK_WDMA_GLO_CFG_TX_DMA_EN);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
- }
+ mtk_wed_deinit(dev);
+ mtk_wdma_rx_reset(dev);
+ mtk_wed_reset(dev, MTK_WED_RESET_WED);
mtk_wed_free_tx_buffer(dev);
mtk_wed_free_tx_rings(dev);
if (mtk_wed_get_rx_capa(dev)) {
- mtk_wed_wo_reset(dev);
+ if(hw->wed_wo)
+ mtk_wed_wo_reset(dev);
mtk_wed_free_rx_rings(dev);
- mtk_wed_wo_exit(hw);
- mtk_wdma_rx_reset(dev);
+ if(hw->wed_wo)
+ mtk_wed_wo_exit(hw);
+ mtk_wdma_tx_reset(dev);
}
if (dev->wlan.bus_type == MTK_WED_BUS_PCIE) {
@@ -593,6 +654,13 @@ mtk_wed_detach(struct mtk_wed_device *dev)
module_put(THIS_MODULE);
hw->wed_dev = NULL;
+}
+
+static void
+mtk_wed_detach(struct mtk_wed_device *dev)
+{
+ mutex_lock(&hw_lock);
+ __mtk_wed_detach(dev);
mutex_unlock(&hw_lock);
}
@@ -665,7 +733,7 @@ mtk_wed_hw_init_early(struct mtk_wed_device *dev)
{
u32 mask, set;
- mtk_wed_stop(dev);
+ mtk_wed_deinit(dev);
mtk_wed_reset(dev, MTK_WED_RESET_WED);
mtk_wed_set_wpdma(dev);
@@ -715,7 +783,6 @@ mtk_wed_rro_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
ring->desc_size = sizeof(*ring->desc);
ring->size = size;
- memset(ring->desc, 0, size);
return 0;
}
@@ -938,44 +1005,140 @@ mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx)
}
static u32
-mtk_wed_check_busy(struct mtk_wed_device *dev)
+mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
{
- if (wed_r32(dev, MTK_WED_GLO_CFG) & MTK_WED_GLO_CFG_TX_DMA_BUSY)
- return true;
-
- if (wed_r32(dev, MTK_WED_WPDMA_GLO_CFG) &
- MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY)
- return true;
-
- if (wed_r32(dev, MTK_WED_CTRL) & MTK_WED_CTRL_WDMA_INT_AGENT_BUSY)
- return true;
-
- if (wed_r32(dev, MTK_WED_WDMA_GLO_CFG) &
- MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY)
- return true;
-
- if (wdma_r32(dev, MTK_WDMA_GLO_CFG) &
- MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY)
- return true;
-
- if (wed_r32(dev, MTK_WED_CTRL) &
- (MTK_WED_CTRL_WED_TX_BM_BUSY | MTK_WED_CTRL_WED_TX_FREE_AGENT_BUSY))
+ if (wed_r32(dev, reg) & mask)
return true;
return false;
}
static int
-mtk_wed_poll_busy(struct mtk_wed_device *dev)
+mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
{
- int sleep = 15000;
+ int sleep = 1000;
int timeout = 100 * sleep;
u32 val;
return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
- timeout, false, dev);
+ timeout, false, dev, reg, mask);
}
+static int
+mtk_wed_rx_reset(struct mtk_wed_device *dev)
+{
+ struct mtk_wed_wo *wo = dev->hw->wed_wo;
+ u8 val = WO_STATE_SER_RESET;
+ int i, ret;
+
+ ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
+ MTK_WED_WO_CMD_CHANGE_STATE, &val,
+ sizeof(val), true);
+
+ if (ret)
+ return ret;
+
+ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
+ ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+ MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
+ if (ret) {
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
+ mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
+ } else {
+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
+ MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
+ MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
+
+ wed_set(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+ MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE |
+ MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE);
+ wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
+ MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE |
+ MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE);
+
+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX, 0);
+ }
+
+ /* reset rro qm */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_RRO_QM_EN);
+ ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_RX_RRO_QM_BUSY);
+ if (ret) {
+ mtk_wed_reset(dev, MTK_WED_RESET_RX_RRO_QM);
+ } else {
+ wed_set(dev, MTK_WED_RROQM_RST_IDX,
+ MTK_WED_RROQM_RST_IDX_MIOD |
+ MTK_WED_RROQM_RST_IDX_FDBK);
+ wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
+ }
+
+ /* reset route qm */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
+ ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
+ if (ret) {
+ mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
+ } else {
+ wed_set(dev, MTK_WED_RTQM_GLO_CFG,
+ MTK_WED_RTQM_Q_RST);
+ }
+
+ /* reset tx wdma */
+ mtk_wdma_tx_reset(dev);
+
+ /* reset tx wdma drv */
+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
+ mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
+
+ /* reset wed rx dma */
+ ret = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
+ MTK_WED_GLO_CFG_RX_DMA_BUSY);
+ wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_RX_DMA_EN);
+ if (ret) {
+ mtk_wed_reset(dev, MTK_WED_RESET_WED_RX_DMA);
+ } else {
+ struct mtk_eth *eth = dev->hw->eth;
+
+ if(MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_V2))
+ wed_set(dev, MTK_WED_RESET_IDX,
+ MTK_WED_RESET_IDX_RX_V2);
+ else
+ wed_set(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_RX);
+ wed_w32(dev, MTK_WED_RESET_IDX, 0);
+ }
+
+ /* reset rx bm */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_BM_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_WED_RX_BM_BUSY);
+ mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
+
+ /* wo change to enable state */
+ val = WO_STATE_ENABLE;
+ ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
+ MTK_WED_WO_CMD_CHANGE_STATE, &val,
+ sizeof(val), true);
+
+ if (ret)
+ return ret;
+
+ /* wed_rx_ring_reset */
+ for (i = 0; i < ARRAY_SIZE(dev->rx_ring); i++) {
+ if (!dev->rx_ring[i].desc)
+ continue;
+
+ mtk_wed_ring_reset(&dev->rx_ring[i], MTK_WED_RX_RING_SIZE,
+ false);
+ }
+
+ mtk_wed_free_rx_buffer(dev);
+
+ return 0;
+}
+
+
static void
mtk_wed_reset_dma(struct mtk_wed_device *dev)
{
@@ -991,22 +1154,25 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
true);
}
- if (mtk_wed_poll_busy(dev))
- busy = mtk_wed_check_busy(dev);
+ /* 1.Reset WED Tx DMA */
+ wed_clr(dev, MTK_WED_GLO_CFG, MTK_WED_GLO_CFG_TX_DMA_EN);
+ busy = mtk_wed_poll_busy(dev, MTK_WED_GLO_CFG,
+ MTK_WED_GLO_CFG_TX_DMA_BUSY);
if (busy) {
mtk_wed_reset(dev, MTK_WED_RESET_WED_TX_DMA);
} else {
- wed_w32(dev, MTK_WED_RESET_IDX,
- MTK_WED_RESET_IDX_TX |
- MTK_WED_RESET_IDX_RX);
+ wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_IDX_TX);
wed_w32(dev, MTK_WED_RESET_IDX, 0);
}
- wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
- wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
+ /* 2. Reset WDMA Rx DMA/Driver_Engine */
+ busy = !!mtk_wdma_rx_reset(dev);
- mtk_wdma_rx_reset(dev);
+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+ if (!busy)
+ busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
+ MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
if (busy) {
mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
@@ -1023,6 +1189,9 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
MTK_WED_WDMA_GLO_CFG_RST_INIT_COMPLETE);
}
+ /* 3. Reset WED WPDMA Tx Driver Engine */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
+
for (i = 0; i < 100; i++) {
val = wed_r32(dev, MTK_WED_TX_BM_INTF);
if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
@@ -1030,8 +1199,21 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
}
mtk_wed_reset(dev, MTK_WED_RESET_TX_FREE_AGENT);
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_BM_EN);
mtk_wed_reset(dev, MTK_WED_RESET_TX_BM);
+ /* 4. Reset WED WPDMA Tx Driver Engine */
+ busy = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_BUSY);
+
+ wed_clr(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_TX_DRV_EN |
+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_EN);
+
+ if(!busy)
+ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_GLO_CFG,
+ MTK_WED_WPDMA_GLO_CFG_RX_DRV_BUSY);
+
if (busy) {
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
@@ -1043,6 +1225,16 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
wed_w32(dev, MTK_WED_WPDMA_RESET_IDX, 0);
}
+ dev->init_done = false;
+ if (dev->hw->version == 1)
+ return;
+
+ if (!busy) {
+ wed_w32(dev, MTK_WED_RESET_IDX, MTK_WED_RESET_WPDMA_IDX_RX);
+ wed_w32(dev, MTK_WED_RESET_IDX, 0);
+ }
+
+ mtk_wed_rx_reset(dev);
}
static int
@@ -1062,7 +1254,8 @@ mtk_wed_ring_alloc(struct mtk_wed_device *dev, struct mtk_wed_ring *ring,
}
static int
-mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
+ bool reset)
{
u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
struct mtk_wed_ring *wdma;
@@ -1071,8 +1264,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
return -EINVAL;
wdma = &dev->rx_wdma[idx];
- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE, desc_size,
- true))
+ if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
+ desc_size, true))
return -ENOMEM;
wdma_w32(dev, MTK_WDMA_RING_RX(idx) + MTK_WED_RING_OFS_BASE,
@@ -1090,7 +1283,8 @@ mtk_wed_wdma_rx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
}
static int
-mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
+mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size,
+ bool reset)
{
u32 desc_size = sizeof(struct mtk_wdma_desc) * dev->hw->version;
struct mtk_wed_ring *wdma;
@@ -1099,8 +1293,8 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
return -EINVAL;
wdma = &dev->tx_wdma[idx];
- if (mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
- desc_size, true))
+ if (!reset && mtk_wed_ring_alloc(dev, wdma, MTK_WED_WDMA_RING_SIZE,
+ desc_size, true))
return -ENOMEM;
wdma_w32(dev, MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_BASE,
@@ -1112,6 +1306,9 @@ mtk_wed_wdma_tx_ring_setup(struct mtk_wed_device *dev, int idx, int size)
wdma_w32(dev,
MTK_WDMA_RING_TX(idx) + MTK_WED_RING_OFS_DMA_IDX, 0);
+ if (reset)
+ mtk_wed_ring_reset(wdma, MTK_WED_WDMA_RING_SIZE, true);
+
if (!idx) {
wed_w32(dev, MTK_WED_WDMA_RING_TX + MTK_WED_RING_OFS_BASE,
wdma->desc_phys);
@@ -1267,9 +1464,12 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
{
int i;
+ if (mtk_wed_get_rx_capa(dev) && mtk_wed_rx_buffer_alloc(dev))
+ return;
+
for (i = 0; i < ARRAY_SIZE(dev->rx_wdma); i++)
if (!dev->rx_wdma[i].desc)
- mtk_wed_wdma_rx_ring_setup(dev, i, 16);
+ mtk_wed_wdma_rx_ring_setup(dev, i, 16, false);
mtk_wed_hw_init(dev);
@@ -1278,10 +1478,9 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask)
mtk_wed_set_ext_int(dev, true);
if (dev->hw->version == 1) {
- u32 val;
-
- val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
- FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID, dev->hw->index);
+ u32 val = dev->wlan.wpdma_phys | MTK_PCIE_MIRROR_MAP_EN |
+ FIELD_PREP(MTK_PCIE_MIRROR_MAP_WED_ID,
+ dev->hw->index);
val |= BIT(0) | (BIT(1) * !!dev->hw->index);
regmap_write(dev->hw->mirror, dev->hw->index * 4, val);
@@ -1353,10 +1552,6 @@ mtk_wed_attach(struct mtk_wed_device *dev)
goto out;
if (mtk_wed_get_rx_capa(dev)) {
- ret = mtk_wed_rx_buffer_alloc(dev);
- if (ret)
- goto out;
-
ret = mtk_wed_rro_alloc(dev);
if (ret)
goto out;
@@ -1364,6 +1559,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
mtk_wed_hw_init_early(dev);
+ init_completion(&dev->fe_reset_done);
+ init_completion(&dev->wlan_reset_done);
+ atomic_set(&dev->fe_reset, 0);
+
if (hw->version == 1) {
regmap_update_bits(hw->hifsys, HIFSYS_DMA_AG_MAP,
BIT(hw->index), 0);
@@ -1373,8 +1572,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
}
out:
- if (ret)
- mtk_wed_detach(dev);
+ if (ret) {
+ dev_err(dev->hw->dev, "failed to attach wed device\n");
+ __mtk_wed_detach(dev);
+ }
unlock:
mutex_unlock(&hw_lock);
@@ -1382,7 +1583,8 @@ mtk_wed_attach(struct mtk_wed_device *dev)
}
static int
-mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx,
+ void __iomem *regs, bool reset)
{
struct mtk_wed_ring *ring = &dev->tx_ring[idx];
@@ -1401,11 +1603,12 @@ mtk_wed_tx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
if (WARN_ON(idx >= ARRAY_SIZE(dev->tx_ring)))
return -EINVAL;
- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
- sizeof(*ring->desc), true))
+ if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_TX_RING_SIZE,
+ sizeof(*ring->desc), true))
return -ENOMEM;
- if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
+ if (mtk_wed_wdma_rx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE,
+ reset))
return -ENOMEM;
ring->reg_base = MTK_WED_RING_TX(idx);
@@ -1450,18 +1653,20 @@ mtk_wed_txfree_ring_setup(struct mtk_wed_device *dev, void __iomem *regs)
}
static int
-mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs)
+mtk_wed_rx_ring_setup(struct mtk_wed_device *dev, int idx, void __iomem *regs,
+ bool reset)
{
struct mtk_wed_ring *ring = &dev->rx_ring[idx];
if (WARN_ON(idx >= ARRAY_SIZE(dev->rx_ring)))
return -EINVAL;
- if (mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
- sizeof(*ring->desc), false))
+ if (!reset && mtk_wed_ring_alloc(dev, ring, MTK_WED_RX_RING_SIZE,
+ sizeof(*ring->desc), false))
return -ENOMEM;
- if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE))
+ if (mtk_wed_wdma_tx_ring_setup(dev, idx, MTK_WED_WDMA_RING_SIZE,
+ reset))
return -ENOMEM;
ring->reg_base = MTK_WED_RING_RX_DATA(idx);
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.h b/drivers/net/ethernet/mediatek/mtk_wed.h
index 1bfd96f..2ce1a5b 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed.h
@@ -160,6 +160,9 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
void mtk_wed_exit(void);
int mtk_wed_flow_add(int index);
void mtk_wed_flow_remove(int index);
+void mtk_wed_fe_reset(void);
+void mtk_wed_fe_reset_complete(void);
+
#else
static inline void
mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
@@ -178,6 +181,13 @@ static inline int mtk_wed_flow_add(int index)
static inline void mtk_wed_flow_remove(int index)
{
}
+static inline void mtk_wed_fe_reset(void)
+{
+}
+
+static inline void mtk_wed_fe_reset_complete(void)
+{
+}
#endif
#ifdef CONFIG_DEBUG_FS
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
index a79305f..645b8b1 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
@@ -32,11 +32,15 @@ struct mtk_wdma_desc {
#define MTK_WED_RESET 0x008
#define MTK_WED_RESET_TX_BM BIT(0)
+#define MTK_WED_RESET_RX_BM BIT(1)
#define MTK_WED_RESET_TX_FREE_AGENT BIT(4)
#define MTK_WED_RESET_WPDMA_TX_DRV BIT(8)
#define MTK_WED_RESET_WPDMA_RX_DRV BIT(9)
+#define MTK_WED_RESET_WPDMA_RX_D_DRV BIT(10)
#define MTK_WED_RESET_WPDMA_INT_AGENT BIT(11)
#define MTK_WED_RESET_WED_TX_DMA BIT(12)
+#define MTK_WED_RESET_WED_RX_DMA BIT(13)
+#define MTK_WED_RESET_WDMA_TX_DRV BIT(16)
#define MTK_WED_RESET_WDMA_RX_DRV BIT(17)
#define MTK_WED_RESET_WDMA_INT_AGENT BIT(19)
#define MTK_WED_RESET_RX_RRO_QM BIT(20)
@@ -174,6 +178,8 @@ struct mtk_wdma_desc {
#define MTK_WED_RESET_IDX 0x20c
#define MTK_WED_RESET_IDX_TX GENMASK(3, 0)
#define MTK_WED_RESET_IDX_RX GENMASK(17, 16)
+#define MTK_WED_RESET_IDX_RX_V2 GENMASK(7, 6)
+#define MTK_WED_RESET_WPDMA_IDX_RX GENMASK(31, 30)
#define MTK_WED_TX_MIB(_n) (0x2a0 + (_n) * 4)
#define MTK_WED_RX_MIB(_n) (0x2e0 + (_n) * 4)
@@ -287,6 +293,9 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_RX_D_GLO_CFG 0x75c
#define MTK_WED_WPDMA_RX_D_RX_DRV_EN BIT(0)
+#define MTK_WED_WPDMA_RX_D_RX_DRV_BUSY BIT(1)
+#define MTK_WED_WPDMA_RX_D_FSM_RETURN_IDLE BIT(3)
+#define MTK_WED_WPDMA_RX_D_RST_INIT_COMPLETE BIT(4)
#define MTK_WED_WPDMA_RX_D_INIT_PHASE_RXEN_SEL GENMASK(11, 7)
#define MTK_WED_WPDMA_RX_D_RXD_READ_LEN GENMASK(31, 24)
diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
index 658f392..6772ea8 100644
--- a/include/linux/soc/mediatek/mtk_wed.h
+++ b/include/linux/soc/mediatek/mtk_wed.h
@@ -151,16 +151,21 @@ struct mtk_wed_device {
void (*release_rx_buf)(struct mtk_wed_device *wed);
void (*update_wo_rx_stats)(struct mtk_wed_device *wed,
struct mtk_wed_wo_rx_stats *stats);
+ int (*reset)(struct mtk_wed_device *wed);
+ void (*reset_complete)(struct mtk_wed_device *wed);
} wlan;
+ struct completion fe_reset_done;
+ struct completion wlan_reset_done;
+ atomic_t fe_reset;
#endif
};
struct mtk_wed_ops {
int (*attach)(struct mtk_wed_device *dev);
int (*tx_ring_setup)(struct mtk_wed_device *dev, int ring,
- void __iomem *regs);
+ void __iomem *regs, bool reset);
int (*rx_ring_setup)(struct mtk_wed_device *dev, int ring,
- void __iomem *regs);
+ void __iomem *regs, bool reset);
int (*txfree_ring_setup)(struct mtk_wed_device *dev,
void __iomem *regs);
int (*msg_update)(struct mtk_wed_device *dev, int cmd_id,
@@ -216,8 +221,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
#define mtk_wed_device_active(_dev) !!(_dev)->ops
#define mtk_wed_device_detach(_dev) (_dev)->ops->detach(_dev)
#define mtk_wed_device_start(_dev, _mask) (_dev)->ops->start(_dev, _mask)
-#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) \
- (_dev)->ops->tx_ring_setup(_dev, _ring, _regs)
+#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) \
+ (_dev)->ops->tx_ring_setup(_dev, _ring, _regs, _reset)
#define mtk_wed_device_txfree_ring_setup(_dev, _regs) \
(_dev)->ops->txfree_ring_setup(_dev, _regs)
#define mtk_wed_device_reg_read(_dev, _reg) \
@@ -228,12 +233,14 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
(_dev)->ops->irq_get(_dev, _mask)
#define mtk_wed_device_irq_set_mask(_dev, _mask) \
(_dev)->ops->irq_set_mask(_dev, _mask)
-#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) \
- (_dev)->ops->rx_ring_setup(_dev, _ring, _regs)
+#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) \
+ (_dev)->ops->rx_ring_setup(_dev, _ring, _regs, reset)
#define mtk_wed_device_ppe_check(_dev, _skb, _reason, _hash) \
(_dev)->ops->ppe_check(_dev, _skb, _reason, _hash)
#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) \
(_dev)->ops->msg_update(_dev, _id, _msg, _len)
+#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
+#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
#else
static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
{
@@ -241,15 +248,17 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
}
#define mtk_wed_device_detach(_dev) do {} while (0)
#define mtk_wed_device_start(_dev, _mask) do {} while (0)
-#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs) -ENODEV
+#define mtk_wed_device_tx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
#define mtk_wed_device_txfree_ring_setup(_dev, _ring, _regs) -ENODEV
#define mtk_wed_device_reg_read(_dev, _reg) 0
#define mtk_wed_device_reg_write(_dev, _reg, _val) do {} while (0)
#define mtk_wed_device_irq_get(_dev, _mask) 0
#define mtk_wed_device_irq_set_mask(_dev, _mask) do {} while (0)
-#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs) -ENODEV
+#define mtk_wed_device_rx_ring_setup(_dev, _ring, _regs, _reset) -ENODEV
#define mtk_wed_device_ppe_check(_dev, _hash) do {} while (0)
#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
+#define mtk_wed_device_stop(_dev) do {} while (0)
+#define mtk_wed_device_dma_reset(_dev) do {} while (0)
#endif
#endif
--
2.18.0

View File

@@ -1,207 +0,0 @@
From 7feee53fdfd481fc2beb02739ccd0e87f1c96b7a Mon Sep 17 00:00:00 2001
From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Sep 2023 11:07:14 +0800
Subject: [PATCH 10/24] ethernet-update-ppe-backward-compatible-two-way-hash
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 ++++++++-
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
drivers/net/ethernet/mediatek/mtk_ppe.c | 24 ++++++++++++++-------
drivers/net/ethernet/mediatek/mtk_ppe.h | 5 +++--
4 files changed, 29 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index a24b223..e8837b6 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -5799,7 +5799,8 @@ static int mtk_probe(struct platform_device *pdev)
for (i = 0; i < eth->ppe_num; i++) {
eth->ppe[i] = mtk_ppe_init(eth,
- eth->base + MTK_ETH_PPE_BASE + i * 0x400, 2, i);
+ eth->base + MTK_ETH_PPE_BASE + i * 0x400,
+ 2, eth->soc->hash_way, i);
if (!eth->ppe[i]) {
err = -ENOMEM;
goto err_free_dev;
@@ -5913,6 +5914,7 @@ static const struct mtk_soc_data mt2701_data = {
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
.has_sram = false,
+ .hash_way = 2,
.offload_version = 2,
.rss_num = 0,
.txrx = {
@@ -5931,6 +5933,7 @@ static const struct mtk_soc_data mt7621_data = {
.required_clks = MT7621_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .hash_way = 2,
.offload_version = 2,
.rss_num = 0,
.txrx = {
@@ -5950,6 +5953,7 @@ static const struct mtk_soc_data mt7622_data = {
.required_clks = MT7622_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .hash_way = 2,
.offload_version = 2,
.rss_num = 0,
.txrx = {
@@ -5968,6 +5972,7 @@ static const struct mtk_soc_data mt7623_data = {
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
.has_sram = false,
+ .hash_way = 2,
.offload_version = 2,
.rss_num = 0,
.txrx = {
@@ -6005,6 +6010,7 @@ static const struct mtk_soc_data mt7986_data = {
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .hash_way = 4,
.offload_version = 2,
.rss_num = 4,
.txrx = {
@@ -6024,6 +6030,8 @@ static const struct mtk_soc_data mt7981_data = {
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .hash_way = 4,
+ .offload_version = 2,
.rss_num = 4,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 9099dea..b4f04e2 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1732,6 +1732,7 @@ struct mtk_soc_data {
u64 caps;
u64 required_clks;
bool required_pctl;
+ u8 hash_way;
u8 offload_version;
netdev_features_t hw_features;
bool has_sram;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index c9ee505..569bf34 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -88,7 +88,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
enable * MTK_PPE_CACHE_CTL_EN);
}
-static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
+static u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e)
{
u32 hv1, hv2, hv3;
u32 hash;
@@ -122,7 +122,7 @@ static u32 mtk_ppe_hash_entry(struct mtk_foe_entry *e)
hash = (hash >> 24) | ((hash & 0xffffff) << 8);
hash ^= hv1 ^ hv2 ^ hv3;
hash ^= hash >> 16;
- hash <<= 2;
+ hash <<= (ffs(ppe->way) - 1);
hash &= MTK_PPE_ENTRIES - 1;
return hash;
@@ -557,10 +557,10 @@ int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
if (type == MTK_PPE_PKT_TYPE_BRIDGE)
return mtk_foe_entry_commit_l2(ppe, entry);
- hash = mtk_ppe_hash_entry(&entry->data);
+ hash = mtk_ppe_hash_entry(ppe, &entry->data);
entry->hash = 0xffff;
spin_lock_bh(&ppe_lock);
- hlist_add_head(&entry->list, &ppe->foe_flow[hash / 4]);
+ hlist_add_head(&entry->list, &ppe->foe_flow[hash / ppe->way]);
spin_unlock_bh(&ppe_lock);
return 0;
@@ -584,7 +584,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
flow_info->l2_data.base_flow = entry;
flow_info->type = MTK_FLOW_TYPE_L2_SUBFLOW;
flow_info->hash = hash;
- hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / 4]);
+ hlist_add_head(&flow_info->list, &ppe->foe_flow[hash / ppe->way]);
hlist_add_head(&flow_info->l2_data.list, &entry->l2_flows);
hwe = &ppe->foe_table[hash];
@@ -608,7 +608,7 @@ mtk_foe_entry_commit_subflow(struct mtk_ppe *ppe, struct mtk_flow_entry *entry,
void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
{
- struct hlist_head *head = &ppe->foe_flow[hash / 4];
+ struct hlist_head *head = &ppe->foe_flow[hash / ppe->way];
struct mtk_foe_entry *hwe = &ppe->foe_table[hash];
struct mtk_flow_entry *entry;
struct mtk_foe_bridge key = {};
@@ -695,12 +695,12 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
return __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
}
-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
- int version, int id)
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int way, int id)
{
struct device *dev = eth->dev;
struct mtk_foe_entry *foe;
struct mtk_ppe *ppe;
+ struct hlist_head *flow;
ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL);
if (!ppe)
@@ -715,6 +715,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->eth = eth;
ppe->dev = dev;
ppe->version = version;
+ ppe->way = way;
ppe->id = id;
foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
@@ -724,6 +725,13 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base,
ppe->foe_table = foe;
+ flow = devm_kzalloc(dev, (MTK_PPE_ENTRIES / way) * sizeof(*flow),
+ GFP_KERNEL);
+ if (!flow)
+ return NULL;
+
+ ppe->foe_flow = flow;
+
return ppe;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 86bbac8..feb1a4a 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -322,19 +322,20 @@ struct mtk_ppe {
void __iomem *base;
int version;
int id;
+ int way;
struct mtk_foe_entry *foe_table;
dma_addr_t foe_phys;
u16 foe_check_time[MTK_PPE_ENTRIES];
- struct hlist_head foe_flow[MTK_PPE_ENTRIES / 2];
+ struct hlist_head *foe_flow;
struct rhashtable l2_flows;
void *acct_table;
};
-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int id);
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int way, int id);
int mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
--
2.18.0

View File

@@ -1,463 +0,0 @@
From 4eaba588e0c730d6188f5f1b667a55d1b9ca0fe6 Mon Sep 17 00:00:00 2001
From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Sep 2023 11:09:23 +0800
Subject: [PATCH 11/24] flow-offload-add-mtkhnat-flow-accounting
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 11 +-
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 1 +
drivers/net/ethernet/mediatek/mtk_ppe.c | 131 +++++++++++++++++-
drivers/net/ethernet/mediatek/mtk_ppe.h | 23 ++-
.../net/ethernet/mediatek/mtk_ppe_debugfs.c | 10 +-
.../net/ethernet/mediatek/mtk_ppe_offload.c | 7 +
drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 14 ++
net/netfilter/xt_FLOWOFFLOAD.c | 2 +-
8 files changed, 191 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index e8837b6..9cd306d 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -5800,7 +5800,8 @@ static int mtk_probe(struct platform_device *pdev)
for (i = 0; i < eth->ppe_num; i++) {
eth->ppe[i] = mtk_ppe_init(eth,
eth->base + MTK_ETH_PPE_BASE + i * 0x400,
- 2, eth->soc->hash_way, i);
+ 2, eth->soc->hash_way, i,
+ eth->soc->has_accounting);
if (!eth->ppe[i]) {
err = -ENOMEM;
goto err_free_dev;
@@ -5914,6 +5915,7 @@ static const struct mtk_soc_data mt2701_data = {
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
.has_sram = false,
+ .has_accounting = false,
.hash_way = 2,
.offload_version = 2,
.rss_num = 0,
@@ -5933,6 +5935,7 @@ static const struct mtk_soc_data mt7621_data = {
.required_clks = MT7621_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .has_accounting = false,
.hash_way = 2,
.offload_version = 2,
.rss_num = 0,
@@ -5953,6 +5956,7 @@ static const struct mtk_soc_data mt7622_data = {
.required_clks = MT7622_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .has_accounting = true,
.hash_way = 2,
.offload_version = 2,
.rss_num = 0,
@@ -5972,6 +5976,7 @@ static const struct mtk_soc_data mt7623_data = {
.required_clks = MT7623_CLKS_BITMAP,
.required_pctl = true,
.has_sram = false,
+ .has_accounting = false,
.hash_way = 2,
.offload_version = 2,
.rss_num = 0,
@@ -5992,6 +5997,7 @@ static const struct mtk_soc_data mt7629_data = {
.required_clks = MT7629_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .has_accounting = true,
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
@@ -6010,6 +6016,7 @@ static const struct mtk_soc_data mt7986_data = {
.required_clks = MT7986_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .has_accounting = true,
.hash_way = 4,
.offload_version = 2,
.rss_num = 4,
@@ -6030,6 +6037,7 @@ static const struct mtk_soc_data mt7981_data = {
.required_clks = MT7981_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .has_accounting = true,
.hash_way = 4,
.offload_version = 2,
.rss_num = 4,
@@ -6067,6 +6075,7 @@ static const struct mtk_soc_data rt5350_data = {
.required_clks = MT7628_CLKS_BITMAP,
.required_pctl = false,
.has_sram = false,
+ .has_accounting = false,
.rss_num = 0,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma),
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index b4f04e2..5f90765 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1736,6 +1736,7 @@ struct mtk_soc_data {
u8 offload_version;
netdev_features_t hw_features;
bool has_sram;
+ bool has_accounting;
struct {
u32 txd_size;
u32 rxd_size;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 569bf34..94e03b2 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -74,6 +74,46 @@ static int mtk_ppe_wait_busy(struct mtk_ppe *ppe)
return ret;
}
+static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
+{
+ int ret;
+ u32 val;
+
+ ret = readl_poll_timeout(ppe->base + MTK_PPE_MIB_SER_CR, val,
+ !(val & MTK_PPE_MIB_SER_CR_ST),
+ 20, MTK_PPE_WAIT_TIMEOUT_US);
+
+ if (ret)
+ dev_err(ppe->dev, "MIB table busy");
+
+ return ret;
+}
+
+int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
+{
+ u32 val, cnt_r0, cnt_r1, cnt_r2;
+ u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high;
+
+ val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST;
+ ppe_w32(ppe, MTK_PPE_MIB_SER_CR, val);
+
+ if (mtk_ppe_mib_wait_busy(ppe))
+ return -ETIMEDOUT;
+
+ cnt_r0 = readl(ppe->base + MTK_PPE_MIB_SER_R0);
+ cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
+ cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2);
+
+ byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
+ byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
+ pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
+ pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
+ *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
+ *packets = (pkt_cnt_high << 16) | pkt_cnt_low;
+
+ return 0;
+}
+
static void mtk_ppe_cache_clear(struct mtk_ppe *ppe)
{
ppe_set(ppe, MTK_PPE_CACHE_CTL, MTK_PPE_CACHE_CTL_CLEAR);
@@ -426,6 +466,18 @@ __mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
MTK_FOE_STATE_INVALID);
dma_wmb();
mtk_ppe_cache_clear(ppe);
+
+ if (ppe->accounting) {
+ struct mtk_foe_accounting *acct, *acct_updated;
+
+ acct = ppe->acct_table + entry->hash * sizeof(*acct);
+ acct->packets = 0;
+ acct->bytes = 0;
+
+ acct_updated = ppe->acct_updated_table + entry->hash * sizeof(*acct_updated);
+ acct_updated->packets = 0;
+ acct_updated->bytes = 0;
+ }
}
entry->hash = 0xffff;
@@ -528,6 +580,16 @@ __mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_foe_entry *entry,
wmb();
hwe->ib1 = entry->ib1;
+ if (ppe->accounting) {
+ int type;
+
+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
+ if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE)
+ hwe->ipv6.ib2 |= MTK_FOE_IB2_MIB_CNT;
+ else
+ hwe->ipv4.ib2 |= MTK_FOE_IB2_MIB_CNT;
+ }
+
dma_wmb();
mtk_ppe_cache_clear(ppe);
@@ -637,8 +699,6 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
}
if (found || !mtk_flow_entry_match(entry, hwe)) {
- if (entry->hash != 0xffff)
- entry->hash = 0xffff;
continue;
}
@@ -695,12 +755,44 @@ int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
return __mtk_foe_entry_idle_time(ppe, entry->data.ib1);
}
-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int way, int id)
+struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, struct mtk_foe_accounting *diff)
+{
+ struct mtk_foe_accounting *acct, *acct_updated;
+ int size = sizeof(struct mtk_foe_accounting);
+ u64 bytes, packets;
+
+ if (!ppe->accounting)
+ return NULL;
+
+ if (mtk_mib_entry_read(ppe, index, &bytes, &packets))
+ return NULL;
+
+ acct = ppe->acct_table + index * size;
+
+ acct->bytes += bytes;
+ acct->packets += packets;
+
+ if (diff) {
+ acct_updated = ppe->acct_updated_table + index * size;
+
+ diff->bytes = acct->bytes - acct_updated->bytes;
+ diff->packets = acct->packets - acct_updated->packets;
+ acct_updated->bytes += diff->bytes;
+ acct_updated->packets += diff->packets;
+ }
+
+ return acct;
+}
+
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int way, int id,
+ int accounting)
{
struct device *dev = eth->dev;
struct mtk_foe_entry *foe;
+ struct mtk_mib_entry *mib;
struct mtk_ppe *ppe;
struct hlist_head *flow;
+ struct mtk_foe_accounting *acct, *acct_updated;
ppe = devm_kzalloc(dev, sizeof(*ppe), GFP_KERNEL);
if (!ppe)
@@ -717,6 +809,7 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int versio
ppe->version = version;
ppe->way = way;
ppe->id = id;
+ ppe->accounting = accounting;
foe = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*foe),
&ppe->foe_phys, GFP_KERNEL);
@@ -732,6 +825,31 @@ struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int versio
ppe->foe_flow = flow;
+ if (accounting) {
+ mib = dmam_alloc_coherent(ppe->dev, MTK_PPE_ENTRIES * sizeof(*mib),
+ &ppe->mib_phys, GFP_KERNEL);
+ if (!foe)
+ return NULL;
+
+ memset(mib, 0, MTK_PPE_ENTRIES * sizeof(*mib));
+
+ ppe->mib_table = mib;
+
+ acct = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct),
+ GFP_KERNEL);
+ if (!acct)
+ return NULL;
+
+ ppe->acct_table = acct;
+
+ acct_updated = devm_kzalloc(dev, MTK_PPE_ENTRIES * sizeof(*acct_updated),
+ GFP_KERNEL);
+ if (!acct_updated)
+ return NULL;
+
+ ppe->acct_updated_table = acct_updated;
+ }
+
return ppe;
}
@@ -834,6 +952,13 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
#endif
+ if (ppe->accounting && ppe->mib_phys) {
+ ppe_w32(ppe, MTK_PPE_MIB_TB_BASE, ppe->mib_phys);
+ ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_EN, MTK_PPE_MIB_CFG_EN);
+ ppe_m32(ppe, MTK_PPE_MIB_CFG, MTK_PPE_MIB_CFG_RD_CLR, MTK_PPE_MIB_CFG_RD_CLR);
+ ppe_m32(ppe, MTK_PPE_MIB_CACHE_CTL, MTK_PPE_MIB_CACHE_CTL_EN, MTK_PPE_MIB_CACHE_CTL_EN);
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index feb1a4a..86288b0 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -316,6 +316,20 @@ struct mtk_flow_entry {
unsigned long cookie;
};
+struct mtk_mib_entry {
+ u32 byt_cnt_l;
+ u16 byt_cnt_h;
+ u32 pkt_cnt_l;
+ u8 pkt_cnt_h;
+ u8 _rsv0;
+ u32 _rsv1;
+} __packed;
+
+struct mtk_foe_accounting {
+ u64 bytes;
+ u64 packets;
+};
+
struct mtk_ppe {
struct mtk_eth *eth;
struct device *dev;
@@ -323,19 +337,25 @@ struct mtk_ppe {
int version;
int id;
int way;
+ int accounting;
struct mtk_foe_entry *foe_table;
dma_addr_t foe_phys;
+ struct mtk_mib_entry *mib_table;
+ dma_addr_t mib_phys;
+
u16 foe_check_time[MTK_PPE_ENTRIES];
struct hlist_head *foe_flow;
struct rhashtable l2_flows;
void *acct_table;
+ void *acct_updated_table;
};
-struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int way, int id);
+struct mtk_ppe *mtk_ppe_init(struct mtk_eth *eth, void __iomem *base, int version, int way, int id,
+ int accounting);
int mtk_ppe_start(struct mtk_ppe *ppe);
int mtk_ppe_stop(struct mtk_ppe *ppe);
@@ -386,5 +406,6 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
+struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, struct mtk_foe_accounting *diff);
#endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
index f4ebe59..d713e2e 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c
@@ -81,6 +81,7 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, struct mtk_ppe *ppe, bool bind)
struct mtk_foe_entry *entry = &ppe->foe_table[i];
struct mtk_foe_mac_info *l2;
struct mtk_flow_addr_info ai = {};
+ struct mtk_foe_accounting *acct;
unsigned char h_source[ETH_ALEN];
unsigned char h_dest[ETH_ALEN];
int type, state;
@@ -94,6 +95,8 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, struct mtk_ppe *ppe, bool bind)
if (bind && state != MTK_FOE_STATE_BIND)
continue;
+ acct = mtk_foe_entry_get_mib(ppe, i, NULL);
+
type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
seq_printf(m, "%05x %s %7s", i,
mtk_foe_entry_state_str(state),
@@ -154,9 +157,12 @@ mtk_ppe_debugfs_foe_show(struct seq_file *m, struct mtk_ppe *ppe, bool bind)
*((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
seq_printf(m, " eth=%pM->%pM etype=%04x"
- " vlan=%d,%d ib1=%08x ib2=%08x\n",
+ " vlan=%d,%d ib1=%08x ib2=%08x"
+ " packets=%lld bytes=%lld\n",
h_source, h_dest, ntohs(l2->etype),
- l2->vlan1, l2->vlan2, entry->ib1, ib2);
+ l2->vlan1, l2->vlan2, entry->ib1, ib2,
+ acct->packets, acct->bytes
+ );
}
return 0;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index f256607..b80f72d 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -509,6 +509,7 @@ static int
mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
{
struct mtk_flow_entry *entry;
+ struct mtk_foe_accounting diff;
u32 idle;
int i;
@@ -521,6 +522,12 @@ mtk_flow_offload_stats(struct mtk_eth *eth, struct flow_cls_offload *f)
idle = mtk_foe_entry_idle_time(eth->ppe[i], entry);
f->stats.lastused = jiffies - idle * HZ;
+ if (entry->hash != 0xFFFF) {
+ mtk_foe_entry_get_mib(eth->ppe[i], entry->hash, &diff);
+ f->stats.pkts += diff.packets;
+ f->stats.bytes += diff.bytes;
+ }
+
return 0;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
index d319f18..8d3ebe1 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
@@ -145,6 +145,20 @@ enum {
#define MTK_PPE_MIB_TB_BASE 0x338
+#define MTK_PPE_MIB_SER_CR 0x33C
+#define MTK_PPE_MIB_SER_CR_ST BIT(16)
+#define MTK_PPE_MIB_SER_CR_ADDR GENMASK(13, 0)
+
+#define MTK_PPE_MIB_SER_R0 0x340
+#define MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW GENMASK(31, 0)
+
+#define MTK_PPE_MIB_SER_R1 0x344
+#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW GENMASK(31, 16)
+#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH GENMASK(15, 0)
+
+#define MTK_PPE_MIB_SER_R2 0x348
+#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0)
+
#define MTK_PPE_MIB_CACHE_CTL 0x350
#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
#define MTK_PPE_MIB_CACHE_CTL_FLUSH BIT(2)
diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
index e4c7db9..aae37f5 100644
--- a/net/netfilter/xt_FLOWOFFLOAD.c
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -772,7 +772,7 @@ static int __init xt_flowoffload_tg_init(void)
if (ret)
goto cleanup;
- flowtable[1].ft.flags = NF_FLOWTABLE_HW_OFFLOAD;
+ flowtable[1].ft.flags = NF_FLOWTABLE_HW_OFFLOAD | NF_FLOWTABLE_COUNTER;
ret = xt_register_target(&offload_tg_reg);
if (ret)
--
2.18.0

View File

@@ -1,862 +0,0 @@
From 51573e91708521bdc47a9d6f771f2cbde11e5ed7 Mon Sep 17 00:00:00 2001
From: "chak-kei.lam" <chak-kei.lam@mediatek.com>
Date: Tue, 9 Apr 2024 15:05:24 +0800
Subject: [PATCH 12/24] flow-offload-add-mtkhnat-qdma-qos
---
drivers/net/ethernet/mediatek/Makefile | 2 +-
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 10 +
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 50 ++
drivers/net/ethernet/mediatek/mtk_ppe.c | 48 +-
drivers/net/ethernet/mediatek/mtk_ppe.h | 4 +
.../net/ethernet/mediatek/mtk_ppe_offload.c | 28 +-
.../net/ethernet/mediatek/mtk_qdma_debugfs.c | 448 ++++++++++++++++++
include/net/flow_offload.h | 1 +
net/netfilter/nf_flow_table_offload.c | 4 +-
9 files changed, 590 insertions(+), 5 deletions(-)
create mode 100644 drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
diff --git a/drivers/net/ethernet/mediatek/Makefile b/drivers/net/ethernet/mediatek/Makefile
index fdbb90f..c7d2296 100644
--- a/drivers/net/ethernet/mediatek/Makefile
+++ b/drivers/net/ethernet/mediatek/Makefile
@@ -5,7 +5,7 @@
obj-$(CONFIG_NET_MEDIATEK_SOC) += mtk_eth.o
mtk_eth-y := mtk_eth_soc.o mtk_sgmii.o mtk_usxgmii.o mtk_eth_path.o mtk_eth_dbg.o mtk_eth_reset.o \
- mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o
+ mtk_ppe.o mtk_ppe_debugfs.o mtk_ppe_offload.o mtk_qdma_debugfs.o
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed.o
ifdef CONFIG_DEBUG_FS
mtk_eth-$(CONFIG_NET_MEDIATEK_SOC_WED) += mtk_wed_debugfs.o
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 60672c6..8e3a276 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -5838,6 +5838,8 @@ static int mtk_probe(struct platform_device *pdev)
}
mtk_ppe_debugfs_init(eth);
+
+ mtk_qdma_debugfs_init(eth);
}
for (i = 0; i < MTK_MAX_DEVS; i++) {
@@ -5953,6 +5955,7 @@ static const struct mtk_soc_data mt2701_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
+ .qdma_tx_sch = 2,
},
};
@@ -5976,6 +5979,7 @@ static const struct mtk_soc_data mt7621_data = {
.rxd_size = sizeof(struct mtk_rx_dma),
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
+ .qdma_tx_sch = 2,
},
};
@@ -6000,6 +6004,7 @@ static const struct mtk_soc_data mt7622_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
+ .qdma_tx_sch = 2,
},
};
@@ -6023,6 +6028,7 @@ static const struct mtk_soc_data mt7623_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
+ .qdma_tx_sch = 2,
},
};
@@ -6069,6 +6075,7 @@ static const struct mtk_soc_data mt7986_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
+ .qdma_tx_sch = 4,
},
};
@@ -6093,6 +6100,7 @@ static const struct mtk_soc_data mt7981_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
+ .qdma_tx_sch = 4,
},
};
@@ -6117,6 +6125,7 @@ static const struct mtk_soc_data mt7988_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_V2,
.dma_max_len = MTK_TX_DMA_BUF_LEN_V2,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT_V2,
+ .qdma_tx_sch = 4,
},
};
@@ -6138,6 +6147,7 @@ static const struct mtk_soc_data rt5350_data = {
.rx_dma_l4_valid = RX_DMA_L4_VALID_PDMA,
.dma_max_len = MTK_TX_DMA_BUF_LEN,
.dma_len_offset = MTK_TX_DMA_BUF_SHIFT,
+ .qdma_tx_sch = 4,
},
};
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 52e4b85..7b3230e 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -495,6 +495,9 @@
#define FC_THRES_DROP_EN (7 << 16)
#define FC_THRES_MIN 0x4444
+/* QDMA TX Scheduler Rate Control Register */
+#define MTK_QDMA_TX_2SCH_BASE (QDMA_BASE + 0x214)
+
/* QDMA Interrupt Status Register */
#define MTK_QDMA_INT_STATUS (QDMA_BASE + 0x218)
#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
@@ -538,6 +541,11 @@
/* QDMA Interrupt Mask Register */
#define MTK_QDMA_HRED2 (QDMA_BASE + 0x244)
+/* QDMA TX Queue MIB Interface Register */
+#define MTK_QTX_MIB_IF (QDMA_BASE + 0x2bc)
+#define MTK_MIB_ON_QTX_CFG BIT(31)
+#define MTK_VQTX_MIB_EN BIT(28)
+
/* QDMA TX Forward CPU Pointer Register */
#define MTK_QTX_CTX_PTR (QDMA_BASE +0x300)
@@ -565,6 +573,14 @@
/* QDMA FQ Free Page Buffer Length Register */
#define MTK_QDMA_FQ_BLEN (QDMA_BASE +0x32c)
+/* QDMA TX Scheduler Rate Control Register */
+#define MTK_QDMA_TX_4SCH_BASE(x) (QDMA_BASE + 0x398 + (((x) >> 1) * 0x4))
+#define MTK_QDMA_TX_SCH_MASK GENMASK(15, 0)
+#define MTK_QDMA_TX_SCH_MAX_WFQ BIT(15)
+#define MTK_QDMA_TX_SCH_RATE_EN BIT(11)
+#define MTK_QDMA_TX_SCH_RATE_MAN GENMASK(10, 4)
+#define MTK_QDMA_TX_SCH_RATE_EXP GENMASK(3, 0)
+
/* WDMA Registers */
#define MTK_WDMA_CTX_PTR(x) (WDMA_BASE(x) + 0x8)
#define MTK_WDMA_DTX_PTR(x) (WDMA_BASE(x) + 0xC)
@@ -1753,6 +1769,7 @@ struct mtk_soc_data {
u32 rx_dma_l4_valid;
u32 dma_max_len;
u32 dma_len_offset;
+ u32 qdma_tx_sch;
} txrx;
};
@@ -1946,6 +1963,7 @@ struct mtk_eth {
spinlock_t syscfg0_lock;
struct timer_list mtk_dma_monitor_timer;
+ u8 qos_toggle;
u8 ppe_num;
struct mtk_ppe *ppe[MTK_MAX_PPE_NUM];
struct rhashtable flow_table;
@@ -2004,6 +2022,36 @@ extern const struct of_device_id of_mtk_match[];
extern u32 mtk_hwlro_stats_ebl;
extern u32 dbg_show_level;
+static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
+{
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ foe->ib1 |= FIELD_PREP(MTK_FOE_IB1_UNBIND_SRC_PORT, val);
+#endif
+}
+
+static inline u32 mtk_get_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe)
+{
+#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+ return FIELD_GET(MTK_FOE_IB1_UNBIND_SRC_PORT, foe->ib1);
+#else
+ return 0;
+#endif
+}
+
+static inline int
+mtk_ppe_check_pppq_path(struct mtk_eth *eth, struct mtk_foe_entry *foe, int dsa_port)
+{
+ u32 sp = mtk_get_ib1_sp(eth, foe);
+
+ if ((dsa_port >= 0 && dsa_port <= 4) ||
+ (dsa_port == 5 && (sp == PSE_WDMA0_PORT ||
+ sp == PSE_WDMA1_PORT ||
+ sp == PSE_WDMA2_PORT)))
+ return 1;
+
+ return 0;
+}
+
/* read the hardware status register */
void mtk_stats_update_mac(struct mtk_mac *mac);
@@ -2037,4 +2085,6 @@ void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
int mtk_ppe_debugfs_init(struct mtk_eth *eth);
+
+int mtk_qdma_debugfs_init(struct mtk_eth *eth);
#endif /* MTK_ETH_H */
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 7b92fff..f5dbfe9 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -139,7 +139,7 @@ static void mtk_ppe_cache_enable(struct mtk_ppe *ppe, bool enable)
enable * MTK_PPE_CACHE_CTL_EN);
}
-static u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e)
+u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e)
{
u32 hv1, hv2, hv3;
u32 hash;
@@ -431,12 +431,58 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
return 0;
}
+int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
+{
+ u32 *ib2 = mtk_foe_entry_ib2(entry);
+
+ *ib2 &= ~MTK_FOE_IB2_QID;
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, qid);
+ *ib2 |= MTK_FOE_IB2_PSE_QOS;
+
+ return 0;
+}
static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
{
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1) != MTK_FOE_STATE_BIND;
}
+bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data)
+{
+ int type, len;
+
+ if ((data->ib1 ^ entry->ib1) & MTK_FOE_IB1_UDP)
+ return false;
+
+ type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
+ if (type > MTK_PPE_PKT_TYPE_IPV4_DSLITE)
+ len = offsetof(struct mtk_foe_entry, ipv6._rsv);
+ else
+ len = offsetof(struct mtk_foe_entry, ipv4.ib2);
+
+ return !memcmp(&entry->data, &data->data, len - 4);
+}
+
+int mtk_foe_entry_set_sp(struct mtk_ppe *ppe, struct mtk_foe_entry *entry)
+{
+ struct mtk_foe_entry *hwe;
+ u32 hash, sp = 0;
+ int i;
+
+ hash = mtk_ppe_hash_entry(ppe, entry);
+ for (i = 0; i < ppe->way; i++) {
+ hwe = &ppe->foe_table[hash + i];
+ if (mtk_foe_entry_match(hwe, entry)) {
+ sp = mtk_get_ib1_sp(ppe->eth, hwe);
+ break;
+ }
+ }
+
+ mtk_set_ib1_sp(ppe->eth, entry, sp);
+
+ return 0;
+}
+
static bool
mtk_flow_entry_match(struct mtk_flow_entry *entry, struct mtk_foe_entry *data)
{
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index bc48bd9..5529d64 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -429,9 +429,13 @@ int mtk_foe_entry_set_vlan(struct mtk_foe_entry *entry, int vid);
int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int bss, int wcid);
+int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
+bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
+int mtk_foe_entry_set_sp(struct mtk_ppe *ppe, struct mtk_foe_entry *entry);
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
void mtk_foe_entry_clear(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
int mtk_foe_entry_idle_time(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
struct mtk_foe_accounting *mtk_foe_entry_get_mib(struct mtk_ppe *ppe, u32 index, struct mtk_foe_accounting *diff);
+u32 mtk_ppe_hash_entry(struct mtk_ppe *ppe, struct mtk_foe_entry *e);
#endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index f9cd2f9..f0c63da 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -9,6 +9,8 @@
#include <linux/ipv6.h>
#include <net/flow_offload.h>
#include <net/pkt_cls.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <net/netfilter/nf_flow_table.h>
#include <net/dsa.h>
#include "mtk_eth_soc.h"
#include "mtk_wed.h"
@@ -183,7 +185,7 @@ mtk_flow_get_dsa_port(struct net_device **dev)
static int
mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
- struct net_device *dev, const u8 *dest_mac,
+ struct net_device *dev, struct nf_conn *ct, const u8 *dest_mac,
int *wed_index)
{
struct mtk_wdma_info info = {};
@@ -209,6 +211,9 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
if (dsa_port >= 0)
mtk_foe_entry_set_dsa(foe, dsa_port);
+ if (eth->qos_toggle == 2 && mtk_ppe_check_pppq_path(eth, foe, dsa_port))
+ mtk_foe_entry_set_qid(foe, dsa_port & MTK_QDMA_TX_MASK);
+
if (dev == eth->netdev[0])
pse_port = PSE_GDM1_PORT;
else if (dev == eth->netdev[1])
@@ -219,6 +224,23 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
return -EOPNOTSUPP;
out:
+ if (eth->qos_toggle == 1 || (ct->mark & MTK_QDMA_TX_MASK) >= 6) {
+ u8 qos_ul_toggle;
+
+ if (eth->qos_toggle == 2)
+ qos_ul_toggle = ((ct->mark >> 16) & MTK_QDMA_TX_MASK) >= 6 ? 1 : 0;
+ else
+ qos_ul_toggle = ((ct->mark >> 16) & MTK_QDMA_TX_MASK) >= 1 ? 1 : 0;
+
+ if (qos_ul_toggle == 1) {
+ if (dev == eth->netdev[1])
+ mtk_foe_entry_set_qid(foe, (ct->mark >> 16) & MTK_QDMA_TX_MASK);
+ else
+ mtk_foe_entry_set_qid(foe, ct->mark & MTK_QDMA_TX_MASK);
+ } else
+ mtk_foe_entry_set_qid(foe, ct->mark & MTK_QDMA_TX_MASK);
+ }
+
mtk_foe_entry_set_pse_port(foe, pse_port);
return 0;
@@ -449,7 +471,9 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (data.pppoe.num == 1)
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
- err = mtk_flow_set_output_device(eth, &foe, odev, data.eth.h_dest,
+ mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
+
+ err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
&wed_index);
if (err)
return err;
diff --git a/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c b/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
new file mode 100644
index 0000000..c7af3eb
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_qdma_debugfs.c
@@ -0,0 +1,448 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (c) 2022 MediaTek Inc.
+ * Author: Henry Yen <henry.yen@mediatek.com>
+ * Bo-Cun Chen <bc-bocun.chen@mediatek.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include "mtk_eth_soc.h"
+
+#define MAX_PPPQ_PORT_NUM 6
+
+static struct mtk_eth *_eth;
+
+static void mtk_qdma_qos_shaper_ebl(struct mtk_eth *eth, u32 id, u32 enable)
+{
+ u32 val;
+
+ if (enable) {
+ if (id < MAX_PPPQ_PORT_NUM) {
+ val = MTK_QTX_SCH_MIN_RATE_EN | MTK_QTX_SCH_MAX_RATE_EN;
+ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
+ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 4) |
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 25) |
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 5) |
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 4);
+ } else {
+ val = MTK_QTX_SCH_MIN_RATE_EN;
+ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, 1) |
+ FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, 3) |
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, 0) |
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, 0) |
+ FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, 4);
+ }
+
+ writel(val, eth->base + MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+ } else {
+ writel(0, eth->base + MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+ }
+}
+
+static void mtk_qdma_qos_disable(struct mtk_eth *eth)
+{
+ u32 id, val;
+
+ for (id = 0; id < MAX_PPPQ_PORT_NUM; id++) {
+ mtk_qdma_qos_shaper_ebl(eth, id, 0);
+
+ writel(FIELD_PREP(MTK_QTX_CFG_HW_RESV_CNT_OFFSET, 4) |
+ FIELD_PREP(MTK_QTX_CFG_SW_RESV_CNT_OFFSET, 4),
+ eth->base + MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+ }
+
+ val = (MTK_QDMA_TX_SCH_MAX_WFQ) | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
+ for (id = 0; id < eth->soc->txrx.qdma_tx_sch; id += 2) {
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ writel(val, eth->base + MTK_QDMA_TX_4SCH_BASE(id));
+ else
+ writel(val, eth->base + MTK_QDMA_TX_2SCH_BASE);
+ }
+}
+
+static void mtk_qdma_qos_pppq_enable(struct mtk_eth *eth)
+{
+ u32 id, val;
+
+ for (id = 0; id < 2 * MAX_PPPQ_PORT_NUM; id++) {
+ mtk_qdma_qos_shaper_ebl(eth, id, 1);
+
+ writel(FIELD_PREP(MTK_QTX_CFG_HW_RESV_CNT_OFFSET, 4) |
+ FIELD_PREP(MTK_QTX_CFG_SW_RESV_CNT_OFFSET, 4),
+ eth->base + MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+ }
+
+ val = (MTK_QDMA_TX_SCH_MAX_WFQ) | (MTK_QDMA_TX_SCH_MAX_WFQ << 16);
+ for (id = 0; id < eth->soc->txrx.qdma_tx_sch; id+= 2) {
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ writel(val, eth->base + MTK_QDMA_TX_4SCH_BASE(id));
+ else
+ writel(val, eth->base + MTK_QDMA_TX_2SCH_BASE);
+ }
+}
+
+ static ssize_t mtk_qmda_debugfs_write_qos(struct file *file, const char __user *buffer,
+ size_t count, loff_t *data)
+{
+ struct seq_file *m = file->private_data;
+ struct mtk_eth *eth = m->private;
+ char buf[8];
+ int len = count;
+
+ if ((len > 8) || copy_from_user(buf, buffer, len))
+ return -EFAULT;
+
+ if (buf[0] == '0') {
+ pr_info("HQoS is going to be disabled !\n");
+ eth->qos_toggle = 0;
+ mtk_qdma_qos_disable(eth);
+ } else if (buf[0] == '1') {
+ pr_info("HQoS mode is going to be enabled !\n");
+ eth->qos_toggle = 1;
+ } else if (buf[0] == '2') {
+ pr_info("Per-port-per-queue mode is going to be enabled !\n");
+ pr_info("PPPQ use qid 0~11 (scheduler 0).\n");
+ eth->qos_toggle = 2;
+ mtk_qdma_qos_pppq_enable(eth);
+ }
+
+ return len;
+}
+
+static int mtk_qmda_debugfs_read_qos(struct seq_file *m, void *private)
+{
+ struct mtk_eth *eth = m->private;
+
+ if (eth->qos_toggle == 0)
+ pr_info("HQoS is disabled now!\n");
+ else if (eth->qos_toggle == 1)
+ pr_info("HQoS is enabled now!\n");
+ else if (eth->qos_toggle == 2)
+ pr_info("Per-port-per-queue mode is enabled!\n");
+
+ return 0;
+}
+
+static int mtk_qmda_debugfs_open_qos(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtk_qmda_debugfs_read_qos,
+ inode->i_private);
+}
+
+static ssize_t mtk_qmda_debugfs_read_qos_sched(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct mtk_eth *eth = _eth;
+ long id = (long)file->private_data;
+ char *buf;
+ unsigned int len = 0, buf_len = 1500;
+ int enable, scheduling, max_rate, exp, scheduler, i;
+ ssize_t ret_cnt;
+ u32 val;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ val = readl(eth->base + MTK_QDMA_TX_4SCH_BASE(id));
+ else
+ val = readl(eth->base + MTK_QDMA_TX_2SCH_BASE);
+
+ if (id & 0x1)
+ val >>= 16;
+
+ val &= MTK_QDMA_TX_SCH_MASK;
+ enable = FIELD_GET(MTK_QDMA_TX_SCH_RATE_EN, val);
+ scheduling = FIELD_GET(MTK_QDMA_TX_SCH_MAX_WFQ, val);
+ max_rate = FIELD_GET(MTK_QDMA_TX_SCH_RATE_MAN, val);
+ exp = FIELD_GET(MTK_QDMA_TX_SCH_RATE_EXP, val);
+ while (exp--)
+ max_rate *= 10;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "EN\tScheduling\tMAX\tQueue#\n%d\t%s%16d\t", enable,
+ (scheduling == 1) ? "WRR" : "SP", max_rate);
+
+ for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+ val = readl(eth->base + MTK_QDMA_PAGE) & ~MTK_QTX_CFG_PAGE;
+ val |= FIELD_PREP(MTK_QTX_CFG_PAGE, i / MTK_QTX_PER_PAGE);
+ writel(val, eth->base + MTK_QDMA_PAGE);
+
+ val = readl(eth->base + MTK_QTX_SCH(i % MTK_QTX_PER_PAGE));
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL_V2, val);
+ else
+ scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL, val);
+ if (id == scheduler)
+ len += scnprintf(buf + len, buf_len - len, "%d ", i);
+ }
+
+ len += scnprintf(buf + len, buf_len - len, "\n");
+ if (len > buf_len)
+ len = buf_len;
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+ return ret_cnt;
+}
+
+static ssize_t mtk_qmda_debugfs_write_qos_sched(struct file *file, const char __user *buf,
+ size_t length, loff_t *offset)
+{
+ struct mtk_eth *eth = _eth;
+ long id = (long)file->private_data;
+ char line[64] = {0}, scheduling[32];
+ int enable, rate, exp = 0, shift = 0;
+ size_t size;
+ u32 sch, val = 0;
+
+ if (length >= sizeof(line))
+ return -EINVAL;
+
+ if (copy_from_user(line, buf, length))
+ return -EFAULT;
+
+ if (sscanf(line, "%d %s %d", &enable, scheduling, &rate) != 3)
+ return -EFAULT;
+
+ while (rate > 127) {
+ rate /= 10;
+ exp++;
+ }
+
+ line[length] = '\0';
+
+ if (enable)
+ val |= FIELD_PREP(MTK_QDMA_TX_SCH_RATE_EN, 1);
+ if (strcmp(scheduling, "sp") != 0)
+ val |= FIELD_PREP(MTK_QDMA_TX_SCH_MAX_WFQ, 1);
+ val |= FIELD_PREP(MTK_QDMA_TX_SCH_RATE_MAN, rate);
+ val |= FIELD_PREP(MTK_QDMA_TX_SCH_RATE_EXP, exp);
+
+ if (id & 0x1)
+ shift = 16;
+
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ sch = readl(eth->base + MTK_QDMA_TX_4SCH_BASE(id));
+ else
+ sch = readl(eth->base + MTK_QDMA_TX_2SCH_BASE);
+
+ sch &= ~(MTK_QDMA_TX_SCH_MASK << shift);
+ sch |= val << shift;
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ writel(sch, eth->base + MTK_QDMA_TX_4SCH_BASE(id));
+ else
+ writel(sch, eth->base + MTK_QDMA_TX_2SCH_BASE);
+
+ size = strlen(line);
+ *offset += size;
+
+ return length;
+}
+
+static ssize_t mtk_qmda_debugfs_read_qos_queue(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct mtk_eth *eth = _eth;
+ long id = (long)file->private_data;
+ char *buf;
+ unsigned int len = 0, buf_len = 1500;
+ int min_rate_en, min_rate, min_rate_exp;
+ int max_rate_en, max_weight, max_rate, max_rate_exp;
+ u32 qtx_sch, qtx_cfg, scheduler, val;
+ ssize_t ret_cnt;
+
+ buf = kzalloc(buf_len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ val = readl(eth->base + MTK_QDMA_PAGE) & ~MTK_QTX_CFG_PAGE;
+ val |= FIELD_PREP(MTK_QTX_CFG_PAGE, id / MTK_QTX_PER_PAGE);
+ writel(val, eth->base + MTK_QDMA_PAGE);
+
+ qtx_cfg = readl(eth->base + MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+ qtx_sch = readl(eth->base + MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL_V2, qtx_sch);
+ else
+ scheduler = FIELD_GET(MTK_QTX_SCH_TX_SEL, qtx_sch);
+
+ min_rate_en = FIELD_GET(MTK_QTX_SCH_MIN_RATE_EN, qtx_sch);
+ min_rate = FIELD_GET(MTK_QTX_SCH_MIN_RATE_MAN, qtx_sch);
+ min_rate_exp = FIELD_GET(MTK_QTX_SCH_MIN_RATE_EXP, qtx_sch);
+ max_rate_en = FIELD_GET(MTK_QTX_SCH_MAX_RATE_EN, qtx_sch);
+ max_weight = FIELD_GET(MTK_QTX_SCH_MAX_RATE_WEIGHT, qtx_sch);
+ max_rate = FIELD_GET(MTK_QTX_SCH_MAX_RATE_MAN, qtx_sch);
+ max_rate_exp = FIELD_GET(MTK_QTX_SCH_MAX_RATE_EXP, qtx_sch);
+ while (min_rate_exp--)
+ min_rate *= 10;
+
+ while (max_rate_exp--)
+ max_rate *= 10;
+
+ len += scnprintf(buf + len, buf_len - len,
+ "scheduler: %d\nhw resv: %d\nsw resv: %d\n", scheduler,
+ (qtx_cfg >> 8) & 0xff, qtx_cfg & 0xff);
+
+ /* Switch to debug mode */
+ val = readl(eth->base + MTK_QTX_MIB_IF) & ~MTK_MIB_ON_QTX_CFG;
+ val |= MTK_MIB_ON_QTX_CFG;
+ writel(val, eth->base + MTK_QTX_MIB_IF);
+
+ val = readl(eth->base + MTK_QTX_MIB_IF) & ~MTK_VQTX_MIB_EN;
+ val |= MTK_VQTX_MIB_EN;
+ writel(val, eth->base + MTK_QTX_MIB_IF);
+
+ qtx_cfg = readl(eth->base + MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+ qtx_sch = readl(eth->base + MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+
+ len += scnprintf(buf + len, buf_len - len,
+ "packet count: %u\n", qtx_cfg);
+ len += scnprintf(buf + len, buf_len - len,
+ "packet drop: %u\n\n", qtx_sch);
+
+ /* Recover to normal mode */
+ val = readl(eth->base + MTK_QTX_MIB_IF);
+ val &= ~MTK_MIB_ON_QTX_CFG;
+ writel(val, eth->base + MTK_QTX_MIB_IF);
+
+ val = readl(eth->base + MTK_QTX_MIB_IF);
+ val &= ~MTK_VQTX_MIB_EN;
+ writel(val, eth->base + MTK_QTX_MIB_IF);
+
+ len += scnprintf(buf + len, buf_len - len,
+ " EN RATE WEIGHT\n");
+ len += scnprintf(buf + len, buf_len - len,
+ "----------------------------\n");
+ len += scnprintf(buf + len, buf_len - len,
+ "max%5d%9d%9d\n", max_rate_en, max_rate, max_weight);
+ len += scnprintf(buf + len, buf_len - len,
+ "min%5d%9d -\n", min_rate_en, min_rate);
+
+ if (len > buf_len)
+ len = buf_len;
+
+ ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+
+ kfree(buf);
+
+ return ret_cnt;
+}
+
+static ssize_t mtk_qmda_debugfs_write_qos_queue(struct file *file, const char __user *buf,
+ size_t length, loff_t *offset)
+{
+ struct mtk_eth *eth = _eth;
+ long id = (long)file->private_data;
+ char line[64] = {0};
+ int max_enable, max_rate, max_exp = 0;
+ int min_enable, min_rate, min_exp = 0;
+ int scheduler, weight, resv;
+ size_t size;
+ u32 val;
+
+ if (length >= sizeof(line))
+ return -EINVAL;
+
+ if (copy_from_user(line, buf, length))
+ return -EFAULT;
+
+ if (sscanf(line, "%d %d %d %d %d %d %d", &scheduler, &min_enable, &min_rate,
+ &max_enable, &max_rate, &weight, &resv) != 7)
+ return -EFAULT;
+
+ line[length] = '\0';
+
+ while (max_rate > 127) {
+ max_rate /= 10;
+ max_exp++;
+ }
+
+ while (min_rate > 127) {
+ min_rate /= 10;
+ min_exp++;
+ }
+
+ val = readl(eth->base + MTK_QDMA_PAGE) & ~MTK_QTX_CFG_PAGE;
+ val |= FIELD_PREP(MTK_QTX_CFG_PAGE, id / MTK_QTX_PER_PAGE);
+ writel(val, eth->base + MTK_QDMA_PAGE);
+
+ if (eth->soc->txrx.qdma_tx_sch == 4)
+ val = FIELD_PREP(MTK_QTX_SCH_TX_SEL_V2, scheduler);
+ else
+ val = FIELD_PREP(MTK_QTX_SCH_TX_SEL, scheduler);
+ if (min_enable)
+ val |= MTK_QTX_SCH_MIN_RATE_EN;
+ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_MAN, min_rate);
+ val |= FIELD_PREP(MTK_QTX_SCH_MIN_RATE_EXP, min_exp);
+ if (max_enable)
+ val |= MTK_QTX_SCH_MAX_RATE_EN;
+ val |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_WEIGHT, weight);
+ val |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_MAN, max_rate);
+ val |= FIELD_PREP(MTK_QTX_SCH_MAX_RATE_EXP, max_exp);
+ writel(val, eth->base + MTK_QTX_SCH(id % MTK_QTX_PER_PAGE));
+
+ val = readl(eth->base + MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+ val |= FIELD_PREP(MTK_QTX_CFG_HW_RESV_CNT_OFFSET, resv);
+ val |= FIELD_PREP(MTK_QTX_CFG_SW_RESV_CNT_OFFSET, resv);
+ writel(val, eth->base + MTK_QTX_CFG(id % MTK_QTX_PER_PAGE));
+
+ size = strlen(line);
+ *offset += size;
+
+ return length;
+}
+
+int mtk_qdma_debugfs_init(struct mtk_eth *eth)
+{
+ static const struct file_operations fops_qos = {
+ .open = mtk_qmda_debugfs_open_qos,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .write = mtk_qmda_debugfs_write_qos,
+ .release = single_release,
+ };
+
+ static const struct file_operations fops_qos_sched = {
+ .open = simple_open,
+ .read = mtk_qmda_debugfs_read_qos_sched,
+ .write = mtk_qmda_debugfs_write_qos_sched,
+ .llseek = default_llseek,
+ };
+
+ static const struct file_operations fops_qos_queue = {
+ .open = simple_open,
+ .read = mtk_qmda_debugfs_read_qos_queue,
+ .write = mtk_qmda_debugfs_write_qos_queue,
+ .llseek = default_llseek,
+ };
+
+ struct dentry *root;
+ long i;
+ char name[16];
+
+ _eth = eth;
+
+ root = debugfs_lookup("mtk_ppe", NULL);
+ if (!root)
+ return -ENOMEM;
+
+ debugfs_create_file("qos_toggle", S_IRUGO, root, eth, &fops_qos);
+
+ for (i = 0; i < eth->soc->txrx.qdma_tx_sch; i++) {
+ snprintf(name, sizeof(name), "qdma_sch%ld", i);
+ debugfs_create_file(name, S_IRUGO, root, (void *)i,
+ &fops_qos_sched);
+ }
+
+ for (i = 0; i < MTK_QDMA_TX_NUM; i++) {
+ snprintf(name, sizeof(name), "qdma_txq%ld", i);
+ debugfs_create_file(name, S_IRUGO, root, (void *)i,
+ &fops_qos_queue);
+ }
+
+ return 0;
+}
diff --git a/include/net/flow_offload.h b/include/net/flow_offload.h
index 59b8736..c4eb45c 100644
--- a/include/net/flow_offload.h
+++ b/include/net/flow_offload.h
@@ -365,6 +365,7 @@ struct flow_cls_offload {
struct flow_cls_common_offload common;
enum flow_cls_command command;
unsigned long cookie;
+ struct flow_offload *flow;
struct flow_rule *rule;
struct flow_stats stats;
u32 classid;
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index 50f2f2e..ba34572 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -810,11 +810,13 @@ static int nf_flow_offload_alloc(const struct flow_offload_work *offload,
}
static void nf_flow_offload_init(struct flow_cls_offload *cls_flow,
+ struct flow_offload *flow,
__be16 proto, int priority,
enum flow_cls_command cmd,
const struct flow_offload_tuple *tuple,
struct netlink_ext_ack *extack)
{
+ cls_flow->flow = flow;
cls_flow->common.protocol = proto;
cls_flow->common.prio = priority;
cls_flow->common.extack = extack;
@@ -836,7 +838,7 @@ static int nf_flow_offload_tuple(struct nf_flowtable *flowtable,
__be16 proto = ETH_P_ALL;
int err, i = 0;
- nf_flow_offload_init(&cls_flow, proto, priority, cmd,
+ nf_flow_offload_init(&cls_flow, flow, proto, priority, cmd,
&flow->tuplehash[dir].tuple, &extack);
if (cmd == FLOW_CLS_REPLACE)
cls_flow.rule = flow_rule->rule;
--
2.18.0

View File

@@ -1,75 +0,0 @@
From f3112e335a7f95aeb3d834962de813baadc1f620 Mon Sep 17 00:00:00 2001
From: Evelyn Tsai <evelyn.tsai@mediatek.com>
Date: Mon, 18 Sep 2023 11:11:41 +0800
Subject: [PATCH 13/24] flow-offload-ovs-support
---
net/openvswitch/vport-internal_dev.c | 46 ++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c
index 58a7b83..8475727 100644
--- a/net/openvswitch/vport-internal_dev.c
+++ b/net/openvswitch/vport-internal_dev.c
@@ -113,12 +113,58 @@ internal_get_stats(struct net_device *dev, struct rtnl_link_stats64 *stats)
}
}
+static int internal_dev_fill_forward_path(struct net_device_path_ctx *ctx, struct net_device_path *path)
+{
+ struct vport *vport;
+ int i;
+ struct table_instance *ti;
+ struct datapath *dp;
+ struct sw_flow_key *key;
+ struct sw_flow_actions *sf_acts;
+ struct nlattr *a;
+ int rem;
+
+ vport = ovs_internal_dev_get_vport(ctx->dev);
+ dp = vport->dp;
+ ti = rcu_dereference_ovsl(dp->table.ti);
+
+ for (i = 0; i < ti->n_buckets; i++) {
+ struct sw_flow *flow;
+ struct hlist_head *head = &ti->buckets[i];
+ struct hlist_node *n;
+
+ hlist_for_each_entry_safe(flow, n, head, flow_table.node[ti->node_ver]) {
+ key = &flow->key;
+
+ if((!memcmp(ctx->dev->dev_addr, key->eth.dst, ETH_ALEN)) && (!memcmp(ctx->daddr, key->eth.src, ETH_ALEN))){
+ sf_acts = rcu_dereference_ovsl(flow->sf_acts);
+ for (a = sf_acts->actions, rem = sf_acts->actions_len; rem > 0;
+ a = nla_next(a, &rem)) {
+ if(nla_type(a) == OVS_ACTION_ATTR_OUTPUT){
+ vport = ovs_vport_rcu(dp, key->phy.in_port);
+ goto out;
+ }
+ }
+ }
+ }
+ }
+
+out:
+
+ path->type = DEV_PATH_BRIDGE;
+ path->dev = ctx->dev;
+ ctx->dev = vport->dev;
+
+ return 0;
+}
+
static const struct net_device_ops internal_dev_netdev_ops = {
.ndo_open = internal_dev_open,
.ndo_stop = internal_dev_stop,
.ndo_start_xmit = internal_dev_xmit,
.ndo_set_mac_address = eth_mac_addr,
.ndo_get_stats64 = internal_get_stats,
+ .ndo_fill_forward_path = internal_dev_fill_forward_path,
};
static struct rtnl_link_ops internal_dev_link_ops __read_mostly = {
--
2.18.0

View File

@@ -1,335 +0,0 @@
From aaac91720ca1fd7679896286eac2b014e7150fca Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Mar 2024 16:35:07 +0800
Subject: [PATCH 15/24] ethernet-update-ppe-from-netsys2-to-netsys3
---
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 8 +++-
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 7 ++--
drivers/net/ethernet/mediatek/mtk_ppe.c | 35 ++++++++++++++---
drivers/net/ethernet/mediatek/mtk_ppe.h | 38 ++++++++++++++++---
.../net/ethernet/mediatek/mtk_ppe_offload.c | 6 ++-
drivers/net/ethernet/mediatek/mtk_ppe_regs.h | 7 ++++
6 files changed, 82 insertions(+), 19 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 952bf51..f477ff3 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2447,7 +2447,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
skb_checksum_none_assert(skb);
skb->protocol = eth_type_trans(skb, netdev);
-#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_RX_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
hash = trxd.rxd5 & MTK_RXD5_FOE_ENTRY_V2;
reason = FIELD_GET(MTK_RXD5_PPE_CPU_REASON_V2, trxd.rxd5);
if (hash != MTK_RXD5_FOE_ENTRY_V2) {
@@ -5798,7 +5798,8 @@ static int mtk_probe(struct platform_device *pdev)
for (i = 0; i < eth->ppe_num; i++) {
eth->ppe[i] = mtk_ppe_init(eth,
- eth->base + MTK_ETH_PPE_BASE + i * 0x400,
+ eth->base + MTK_ETH_PPE_BASE +
+ (i == 2 ? 0xC00 : i * 0x400),
2, eth->soc->hash_way, i,
eth->soc->has_accounting);
if (!eth->ppe[i]) {
@@ -6065,6 +6066,9 @@ static const struct mtk_soc_data mt7988_data = {
.required_clks = MT7988_CLKS_BITMAP,
.required_pctl = false,
.has_sram = true,
+ .has_accounting = true,
+ .hash_way = 4,
+ .offload_version = 2,
.rss_num = 4,
.txrx = {
.txd_size = sizeof(struct mtk_tx_dma_v2),
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 58547af..9c46ac1 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -137,9 +137,10 @@
#define MTK_GDMA_UCS_EN BIT(20)
#define MTK_GDMA_STRP_CRC BIT(16)
#define MTK_GDMA_TO_PDMA 0x0
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
#define MTK_GDMA_TO_PPE0 0x3333
#define MTK_GDMA_TO_PPE1 0x4444
+#define MTK_GDMA_TO_PPE2 0xcccc
#else
#define MTK_GDMA_TO_PPE0 0x4444
#endif
@@ -2018,14 +2019,14 @@ extern u32 dbg_show_level;
static inline void mtk_set_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe, u32 val)
{
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
foe->ib1 |= FIELD_PREP(MTK_FOE_IB1_UNBIND_SRC_PORT, val);
#endif
}
static inline u32 mtk_get_ib1_sp(struct mtk_eth *eth, struct mtk_foe_entry *foe)
{
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
return FIELD_GET(MTK_FOE_IB1_UNBIND_SRC_PORT, foe->ib1);
#else
return 0;
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 8388f65..184e29d 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -91,7 +91,7 @@ static int mtk_ppe_mib_wait_busy(struct mtk_ppe *ppe)
int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
{
- u32 val, cnt_r0, cnt_r1, cnt_r2;
+ u32 val, cnt_r0, cnt_r1, cnt_r2, cnt_r3;
u32 byte_cnt_low, byte_cnt_high, pkt_cnt_low, pkt_cnt_high;
val = FIELD_PREP(MTK_PPE_MIB_SER_CR_ADDR, index) | MTK_PPE_MIB_SER_CR_ST;
@@ -104,12 +104,23 @@ int mtk_mib_entry_read(struct mtk_ppe *ppe, u16 index, u64 *bytes, u64 *packets)
cnt_r1 = readl(ppe->base + MTK_PPE_MIB_SER_R1);
cnt_r2 = readl(ppe->base + MTK_PPE_MIB_SER_R2);
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ cnt_r3 = readl(ppe->base + MTK_PPE_MIB_SER_R3);
+
+ byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
+ byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH_V2, cnt_r1);
+ pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_LOW_V2, cnt_r2);
+ pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R3_PKT_CNT_HIGH, cnt_r3);
+ *bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
+ *packets = ((u64)pkt_cnt_high << 32) | pkt_cnt_low;
+#else
byte_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R0_BYTE_CNT_LOW, cnt_r0);
byte_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH, cnt_r1);
pkt_cnt_low = FIELD_GET(MTK_PPE_MIB_SER_R1_PKT_CNT_LOW, cnt_r1);
pkt_cnt_high = FIELD_GET(MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH, cnt_r2);
*bytes = ((u64)byte_cnt_high << 32) | byte_cnt_low;
*packets = (pkt_cnt_high << 16) | pkt_cnt_low;
+#endif
return 0;
}
@@ -211,7 +222,7 @@ int mtk_foe_entry_prepare(struct mtk_foe_entry *entry, int type, int l4proto,
MTK_FOE_IB1_BIND_CACHE;
entry->ib1 = val;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
val = FIELD_PREP(MTK_FOE_IB2_PORT_AG, 0xf) |
#else
val = FIELD_PREP(MTK_FOE_IB2_PORT_MG, 0x3f) |
@@ -403,7 +414,7 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
*ib2 &= ~MTK_FOE_IB2_PORT_MG;
*ib2 |= MTK_FOE_IB2_WDMA_WINFO;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
*ib2 |= FIELD_PREP(MTK_FOE_IB2_RX_IDX, txq);
l2->winfo = FIELD_PREP(MTK_FOE_WINFO_WCID, wcid) |
@@ -422,11 +433,16 @@ int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
{
+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(entry);
u32 *ib2 = mtk_foe_entry_ib2(entry);
*ib2 &= ~MTK_FOE_IB2_QID;
*ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, qid);
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ l2->tport_id = 1;
+#else
*ib2 |= MTK_FOE_IB2_PSE_QOS;
+#endif
return 0;
}
@@ -922,13 +938,16 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
mtk_ppe_init_foe_table(ppe);
ppe_w32(ppe, MTK_PPE_TB_BASE, ppe->foe_phys);
- val = MTK_PPE_TB_CFG_ENTRY_80B |
+ val =
+#if !defined(CONFIG_MEDIATEK_NETSYS_V3)
+ MTK_PPE_TB_CFG_ENTRY_80B |
+#endif
MTK_PPE_TB_CFG_AGE_NON_L4 |
MTK_PPE_TB_CFG_AGE_UNBIND |
MTK_PPE_TB_CFG_AGE_TCP |
MTK_PPE_TB_CFG_AGE_UDP |
MTK_PPE_TB_CFG_AGE_TCP_FIN |
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
MTK_PPE_TB_CFG_INFO_SEL |
#endif
FIELD_PREP(MTK_PPE_TB_CFG_SEARCH_MISS,
@@ -988,12 +1007,16 @@ int mtk_ppe_start(struct mtk_ppe *ppe)
MTK_PPE_GLO_CFG_IP4_L4_CS_DROP |
MTK_PPE_GLO_CFG_IP4_CS_DROP |
MTK_PPE_GLO_CFG_MCAST_TB_EN |
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ MTK_PPE_GLO_CFG_CS0_PIPE_EN |
+ MTK_PPE_GLO_CFG_SRH_CACHE_FIRST_EN |
+#endif
MTK_PPE_GLO_CFG_FLOW_DROP_UPDATE;
ppe_w32(ppe, MTK_PPE_GLO_CFG, val);
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT, 0);
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
ppe_w32(ppe, MTK_PPE_DEFAULT_CPU_PORT1, 0xcb777);
ppe_w32(ppe, MTK_PPE_SBW_CTRL, 0x7f);
#endif
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 5ab864f..5529d64 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -8,7 +8,10 @@
#include <linux/bitfield.h>
#include <linux/rhashtable.h>
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+#define MTK_MAX_PPE_NUM 3
+#define MTK_ETH_PPE_BASE 0x2000
+#elif defined(CONFIG_MEDIATEK_NETSYS_V2)
#define MTK_MAX_PPE_NUM 2
#define MTK_ETH_PPE_BASE 0x2000
#else
@@ -22,7 +25,7 @@
#define MTK_PPE_WAIT_TIMEOUT_US 1000000
#define MTK_FOE_IB1_UNBIND_TIMESTAMP GENMASK(7, 0)
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
#define MTK_FOE_IB1_UNBIND_SRC_PORT GENMASK(11, 8)
#define MTK_FOE_IB1_UNBIND_PACKETS GENMASK(19, 12)
#define MTK_FOE_IB1_UNBIND_PREBIND BIT(22)
@@ -70,7 +73,7 @@ enum {
MTK_PPE_PKT_TYPE_IPV6_6RD = 7,
};
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
#define MTK_FOE_IB2_QID GENMASK(6, 0)
#define MTK_FOE_IB2_PORT_MG BIT(7)
#define MTK_FOE_IB2_PSE_QOS BIT(8)
@@ -98,7 +101,18 @@ enum {
#define MTK_FOE_IB2_DSCP GENMASK(31, 24)
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+#define MTK_FOE_WINFO_WCID GENMASK(15, 0)
+#define MTK_FOE_WINFO_BSS GENMASK(23, 16)
+
+#define MTK_FOE_WINFO_PAO_USR_INFO GENMASK(15, 0)
+#define MTK_FOE_WINFO_PAO_TID GENMASK(19, 16)
+#define MTK_FOE_WINFO_PAO_IS_FIXEDRATE BIT(20)
+#define MTK_FOE_WINFO_PAO_IS_PRIOR BIT(21)
+#define MTK_FOE_WINFO_PAO_IS_SP BIT(22)
+#define MTK_FOE_WINFO_PAO_HF BIT(23)
+#define MTK_FOE_WINFO_PAO_AMSDU_EN BIT(24)
+#elif defined(CONFIG_MEDIATEK_NETSYS_V2)
#define MTK_FOE_WINFO_BSS GENMASK(5, 0)
#define MTK_FOE_WINFO_WCID GENMASK(15, 6)
#else
@@ -128,7 +142,17 @@ struct mtk_foe_mac_info {
u16 pppoe_id;
u16 src_mac_lo;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ u16 minfo;
+ u16 resv1;
+ u32 winfo;
+ u32 winfo_pao;
+ u16 cdrt_id:8;
+ u16 tops_entry:6;
+ u16 resv3:2;
+ u16 tport_id:4;
+ u16 resv4:12;
+#elif defined(CONFIG_MEDIATEK_NETSYS_V2)
u16 minfo;
u16 winfo;
#endif
@@ -249,7 +273,9 @@ struct mtk_foe_entry {
struct mtk_foe_ipv4_dslite dslite;
struct mtk_foe_ipv6 ipv6;
struct mtk_foe_ipv6_6rd ipv6_6rd;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ u32 data[31];
+#elif defined(CONFIG_MEDIATEK_NETSYS_V2)
u32 data[23];
#else
u32 data[19];
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index 3bc50a4..f0c63da 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -195,7 +195,7 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
mtk_foe_entry_set_wdma(foe, info.wdma_idx, info.queue, info.bss,
info.wcid);
pse_port = PSE_PPE0_PORT;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
if (info.wdma_idx == 0)
pse_port = PSE_WDMA0_PORT;
else if (info.wdma_idx == 1)
@@ -218,6 +218,8 @@ mtk_flow_set_output_device(struct mtk_eth *eth, struct mtk_foe_entry *foe,
pse_port = PSE_GDM1_PORT;
else if (dev == eth->netdev[1])
pse_port = PSE_GDM2_PORT;
+ else if (dev == eth->netdev[2])
+ pse_port = PSE_GDM3_PORT;
else
return -EOPNOTSUPP;
@@ -376,7 +378,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (err)
return err;
-#if defined(CONFIG_MEDIATEK_NETSYS_V2)
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
if (idev && idev->netdev_ops->ndo_fill_receive_path) {
ctx.dev = idev;
idev->netdev_ops->ndo_fill_receive_path(&ctx, &path);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
index 8d3ebe1..55b9b0c 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_regs.h
@@ -18,6 +18,8 @@
#define MTK_PPE_GLO_CFG_UDP_LITE_EN BIT(10)
#define MTK_PPE_GLO_CFG_UDP_LEN_DROP BIT(11)
#define MTK_PPE_GLO_CFG_MCAST_ENTRIES GNEMASK(13, 12)
+#define MTK_PPE_GLO_CFG_CS0_PIPE_EN BIT(29)
+#define MTK_PPE_GLO_CFG_SRH_CACHE_FIRST_EN BIT(30)
#define MTK_PPE_GLO_CFG_BUSY BIT(31)
#define MTK_PPE_FLOW_CFG 0x204
@@ -155,9 +157,14 @@ enum {
#define MTK_PPE_MIB_SER_R1 0x344
#define MTK_PPE_MIB_SER_R1_PKT_CNT_LOW GENMASK(31, 16)
#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH GENMASK(15, 0)
+#define MTK_PPE_MIB_SER_R1_BYTE_CNT_HIGH_V2 GENMASK(31, 0)
#define MTK_PPE_MIB_SER_R2 0x348
#define MTK_PPE_MIB_SER_R2_PKT_CNT_HIGH GENMASK(23, 0)
+#define MTK_PPE_MIB_SER_R2_PKT_CNT_LOW_V2 GENMASK(31, 0)
+
+#define MTK_PPE_MIB_SER_R3 0x34C
+#define MTK_PPE_MIB_SER_R3_PKT_CNT_HIGH GENMASK(31, 0)
#define MTK_PPE_MIB_CACHE_CTL 0x350
#define MTK_PPE_MIB_CACHE_CTL_EN BIT(0)
--
2.18.0

View File

@@ -1,165 +0,0 @@
From 743b10e8e2a17c904f27cf78d46aea64193fc41c Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Mon, 18 Sep 2023 11:16:18 +0800
Subject: [PATCH 16/24] mediatek-ethernet-add-wifi2wifi-offload-support
---
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 2 ++
.../net/ethernet/mediatek/mtk_ppe_offload.c | 35 +++++++++++++------
drivers/net/ethernet/mediatek/mtk_wed.c | 13 +++++++
include/linux/soc/mediatek/mtk_wed.h | 5 +++
4 files changed, 45 insertions(+), 10 deletions(-)
mode change 100755 => 100644 drivers/net/ethernet/mediatek/mtk_ppe_offload.c
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index f9dda59..88d2f46 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -2072,6 +2072,8 @@ void mtk_usxgmii_link_poll(struct work_struct *work);
int mtk_eth_offload_init(struct mtk_eth *eth, int id);
int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
+int mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f,
+ struct mtk_eth *eth);
void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
old mode 100755
new mode 100644
index f0c63da..c1cce76
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -563,10 +563,20 @@ static int
mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_priv)
{
struct flow_cls_offload *cls = type_data;
- struct net_device *dev = cb_priv;
- struct mtk_mac *mac = netdev_priv(dev);
- struct mtk_eth *eth = mac->hw;
- int err;
+ struct mtk_eth *eth = cb_priv;
+ struct net_device *dev = NULL;
+ int i, err;
+
+ for (i = 0; i < MTK_MAC_COUNT; i++) {
+ if (!eth->netdev[i])
+ continue;
+
+ dev = eth->netdev[i];
+ break;
+ }
+
+ if (!dev)
+ return -EOPNOTSUPP;
if (!tc_can_offload(dev))
return -EOPNOTSUPP;
@@ -594,16 +604,21 @@ mtk_eth_setup_tc_block_cb(enum tc_setup_type type, void *type_data, void *cb_pri
return err;
}
-static int
-mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
+int
+mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f,
+ struct mtk_eth *eth)
{
- struct mtk_mac *mac = netdev_priv(dev);
- struct mtk_eth *eth = mac->hw;
+ struct mtk_mac *mac;
static LIST_HEAD(block_cb_list);
struct flow_block_cb *block_cb;
flow_setup_cb_t *cb;
int i, err = 0;
+ if (!eth) {
+ mac = netdev_priv(dev);
+ eth = mac->hw;
+ }
+
for (i = 0; i < eth->ppe_num; i++) {
if (!eth->ppe[i] || !eth->ppe[i]->foe_table)
return -EOPNOTSUPP;
@@ -622,7 +637,7 @@ mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f)
flow_block_cb_incref(block_cb);
goto unlock;
}
- block_cb = flow_block_cb_alloc(cb, dev, dev, NULL);
+ block_cb = flow_block_cb_alloc(cb, dev, eth, NULL);
if (IS_ERR(block_cb)) {
err = PTR_ERR(block_cb);
goto unlock;
@@ -658,7 +673,7 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
switch (type) {
case TC_SETUP_BLOCK:
case TC_SETUP_FT:
- return mtk_eth_setup_tc_block(dev, type_data);
+ return mtk_eth_setup_tc_block(dev, type_data, NULL);
default:
return -EOPNOTSUPP;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index 5dd1182..68eedd3 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -1766,6 +1766,18 @@ void mtk_wed_flow_remove(int index)
mutex_unlock(&hw_lock);
}
+static int mtk_wed_eth_setup_tc(struct mtk_wed_device *wed, struct net_device *dev,
+ int type, void *type_data)
+{
+ switch (type) {
+ case TC_SETUP_BLOCK:
+ case TC_SETUP_FT:
+ return mtk_eth_setup_tc_block(dev, type_data, wed->hw->eth);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
void __iomem *wdma, phys_addr_t wdma_phy,
int index)
@@ -1785,6 +1797,7 @@ void mtk_wed_add_hw(struct device_node *np, struct mtk_eth *eth,
.irq_get = mtk_wed_irq_get,
.irq_set_mask = mtk_wed_irq_set_mask,
.detach = mtk_wed_detach,
+ .setup_tc = mtk_wed_eth_setup_tc,
.ppe_check = mtk_wed_ppe_check,
};
struct device_node *eth_np = eth->dev->of_node;
diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
index 6772ea8..470beb2 100644
--- a/include/linux/soc/mediatek/mtk_wed.h
+++ b/include/linux/soc/mediatek/mtk_wed.h
@@ -173,6 +173,8 @@ struct mtk_wed_ops {
void (*detach)(struct mtk_wed_device *dev);
void (*ppe_check)(struct mtk_wed_device *dev, struct sk_buff *skb,
u32 reason, u32 hash);
+ int (*setup_tc)(struct mtk_wed_device *wed, struct net_device *dev,
+ int type, void *type_data);
void (*stop)(struct mtk_wed_device *dev);
void (*start)(struct mtk_wed_device *dev, u32 irq_mask);
@@ -241,6 +243,8 @@ mtk_wed_get_rx_capa(struct mtk_wed_device *dev)
(_dev)->ops->msg_update(_dev, _id, _msg, _len)
#define mtk_wed_device_stop(_dev) (_dev)->ops->stop(_dev)
#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
+#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) \
+ (_dev)->ops->setup_tc(_dev, _ndev, _type, _data)
#else
static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
{
@@ -259,6 +263,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
#define mtk_wed_device_update_msg(_dev, _id, _msg, _len) -ENODEV
#define mtk_wed_device_stop(_dev) do {} while (0)
#define mtk_wed_device_dma_reset(_dev) do {} while (0)
+#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
#endif
#endif
--
2.18.0

View File

@@ -1,186 +0,0 @@
From 8c918e858df4b7cb12ea185acf23e83bae883cd2 Mon Sep 17 00:00:00 2001
From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Sep 2023 11:17:24 +0800
Subject: [PATCH 17/24] flow-offload-add-mtkhnat-dscp
---
drivers/net/ethernet/mediatek/mtk_ppe.c | 11 +++++++
drivers/net/ethernet/mediatek/mtk_ppe.h | 1 +
.../net/ethernet/mediatek/mtk_ppe_offload.c | 12 +++++++
include/net/netfilter/nf_flow_table.h | 2 ++
net/netfilter/nf_flow_table_offload.c | 7 +++-
net/netfilter/xt_FLOWOFFLOAD.c | 32 +++++++++++++++++++
6 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index 184e29d..0e9c0bd 100755
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -446,6 +446,17 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
return 0;
}
+
+int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
+{
+ u32 *ib2 = mtk_foe_entry_ib2(entry);
+
+ *ib2 &= ~MTK_FOE_IB2_DSCP;
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_DSCP, dscp);
+
+ return 0;
+}
+
static inline bool mtk_foe_entry_usable(struct mtk_foe_entry *entry)
{
return !(entry->ib1 & MTK_FOE_IB1_STATIC) &&
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.h b/drivers/net/ethernet/mediatek/mtk_ppe.h
index 5529d64..2a8b6ef 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.h
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.h
@@ -430,6 +430,7 @@ int mtk_foe_entry_set_pppoe(struct mtk_foe_entry *entry, int sid);
int mtk_foe_entry_set_wdma(struct mtk_foe_entry *entry, int wdma_idx, int txq,
int bss, int wcid);
int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid);
+int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp);
bool mtk_foe_entry_match(struct mtk_foe_entry *entry, struct mtk_foe_entry *data);
int mtk_foe_entry_set_sp(struct mtk_ppe *ppe, struct mtk_foe_entry *entry);
int mtk_foe_entry_commit(struct mtk_ppe *ppe, struct mtk_flow_entry *entry);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index c1cce76..95174b7 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -262,6 +262,7 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
int wed_index = -1;
u16 addr_type = 0;
u8 l4proto = 0;
+ u8 dscp = 0;
int err = 0;
int i;
@@ -298,6 +299,15 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
return -EOPNOTSUPP;
}
+ if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_IP)) {
+ struct flow_match_ip match;
+
+ flow_rule_match_ip(rule, &match);
+ dscp = match.key->tos;
+ } else {
+ return -EOPNOTSUPP;
+ }
+
switch (addr_type) {
case 0:
offload_type = MTK_PPE_PKT_TYPE_BRIDGE;
@@ -471,6 +481,8 @@ mtk_flow_offload_replace(struct mtk_eth *eth, struct flow_cls_offload *f)
if (data.pppoe.num == 1)
mtk_foe_entry_set_pppoe(&foe, data.pppoe.sid);
+ mtk_foe_entry_set_dscp(&foe, dscp);
+
mtk_foe_entry_set_sp(eth->ppe[ppe_index], &foe);
err = mtk_flow_set_output_device(eth, &foe, odev, f->flow->ct, data.eth.h_dest,
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 7374cb2..d5dd3fe 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -38,6 +38,7 @@ struct nf_flow_key {
};
struct flow_dissector_key_tcp tcp;
struct flow_dissector_key_ports tp;
+ struct flow_dissector_key_ip ip;
} __aligned(BITS_PER_LONG / 8); /* Ensure that we can do comparisons as longs. */
struct nf_flow_match {
@@ -147,6 +148,7 @@ struct flow_offload_tuple {
u8 h_dest[ETH_ALEN];
} out;
};
+ u8 tos;
};
struct flow_offload_tuple_rhash {
diff --git a/net/netfilter/nf_flow_table_offload.c b/net/netfilter/nf_flow_table_offload.c
index ba34572..b8b2fa6 100644
--- a/net/netfilter/nf_flow_table_offload.c
+++ b/net/netfilter/nf_flow_table_offload.c
@@ -104,6 +104,7 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IPV6_ADDRS, ipv6);
NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_TCP, tcp);
NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_PORTS, tp);
+ NF_FLOW_DISSECTOR(match, FLOW_DISSECTOR_KEY_IP, ip);
if (other_dst && other_dst->lwtstate) {
tun_info = lwt_tun_info(other_dst->lwtstate);
@@ -183,10 +184,14 @@ static int nf_flow_rule_match(struct nf_flow_match *match,
key->tp.dst = tuple->dst_port;
mask->tp.dst = 0xffff;
+ key->ip.tos = tuple->tos;
+ mask->ip.tos = 0xff;
+
match->dissector.used_keys |= BIT(FLOW_DISSECTOR_KEY_META) |
BIT(FLOW_DISSECTOR_KEY_CONTROL) |
BIT(FLOW_DISSECTOR_KEY_BASIC) |
- BIT(FLOW_DISSECTOR_KEY_PORTS);
+ BIT(FLOW_DISSECTOR_KEY_PORTS) |
+ BIT(FLOW_DISSECTOR_KEY_IP);
return 0;
}
diff --git a/net/netfilter/xt_FLOWOFFLOAD.c b/net/netfilter/xt_FLOWOFFLOAD.c
index aae37f5..5364a32 100644
--- a/net/netfilter/xt_FLOWOFFLOAD.c
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
@@ -49,6 +49,35 @@ static DEFINE_SPINLOCK(hooks_lock);
struct xt_flowoffload_table flowtable[2];
+static int
+xt_flowoffload_dscp_init(struct sk_buff *skb, struct flow_offload *flow,
+ enum ip_conntrack_dir dir)
+{
+ const struct flow_offload_tuple *flow_tuple = &flow->tuplehash[dir].tuple;
+ struct iphdr *iph;
+ struct ipv6hdr *ip6h;
+ u32 offset = 0;
+ u8 tos = 0;
+
+ switch (flow_tuple->l3proto) {
+ case NFPROTO_IPV4:
+ iph = (struct iphdr *)(skb_network_header(skb) + offset);
+ tos = iph->tos;
+ break;
+ case NFPROTO_IPV6:
+ ip6h = (struct ipv6hdr *)(skb_network_header(skb) + offset);
+ tos = ipv6_get_dsfield(ip6h);
+ break;
+ default:
+ return -1;
+ };
+
+ flow->tuplehash[dir].tuple.tos = tos;
+ flow->tuplehash[!dir].tuple.tos = tos;
+
+ return 0;
+}
+
static unsigned int
xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
const struct nf_hook_state *state)
@@ -623,6 +652,9 @@ flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
if (flow_offload_route_init(flow, &route) < 0)
goto err_flow_add;
+ if (xt_flowoffload_dscp_init(skb, flow, dir) < 0)
+ goto err_flow_add;
+
if (tcph) {
ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
--
2.18.0

View File

@@ -1,355 +0,0 @@
From 122cb2a2ae7ececd20412083b5bb9bfd6f9c8d26 Mon Sep 17 00:00:00 2001
From: Bc-bocun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Sep 2023 13:14:08 +0800
Subject: [PATCH 18/24] flow-offload-add-mtkhnat-netlink
---
include/net/netfilter/nf_flow_table.h | 1 +
include/uapi/linux/netfilter/nfnetlink.h | 3 +-
net/netfilter/Kconfig | 9 +
net/netfilter/Makefile | 1 +
net/netfilter/nf_flow_table_core.c | 23 +++
net/netfilter/nf_flow_table_netlink.c | 239 +++++++++++++++++++++++
6 files changed, 275 insertions(+), 1 deletion(-)
create mode 100644 net/netfilter/nf_flow_table_netlink.c
diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index d5dd3fe..f2bce73 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -279,6 +279,7 @@ int nf_flow_table_init(struct nf_flowtable *flow_table);
void nf_flow_table_free(struct nf_flowtable *flow_table);
void flow_offload_teardown(struct flow_offload *flow);
+void flow_offload_teardown_by_tuple(struct flow_offload_tuple *tuple);
int nf_flow_table_iterate(struct nf_flowtable *flow_table,
void (*iter)(struct flow_offload *flow, void *data),
diff --git a/include/uapi/linux/netfilter/nfnetlink.h b/include/uapi/linux/netfilter/nfnetlink.h
index 5bc960f..603d9c0 100644
--- a/include/uapi/linux/netfilter/nfnetlink.h
+++ b/include/uapi/linux/netfilter/nfnetlink.h
@@ -60,7 +60,8 @@ struct nfgenmsg {
#define NFNL_SUBSYS_CTHELPER 9
#define NFNL_SUBSYS_NFTABLES 10
#define NFNL_SUBSYS_NFT_COMPAT 11
-#define NFNL_SUBSYS_COUNT 12
+#define NFNL_SUBSYS_FLOWTABLE 12
+#define NFNL_SUBSYS_COUNT 13
/* Reserved control nfnetlink messages */
#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 5d690ab..8ec87aa 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -708,6 +708,15 @@ config NF_FLOW_TABLE
To compile it as a module, choose M here.
+config NF_FLOW_TABLE_NETLINK
+ tristate "Netfilter flow table netlink module"
+ depends on NETFILTER_INGRESS
+ depends on NF_CONNTRACK
+ help
+ This option adds the flow table core infrastructure.
+
+ To compile it as a module, choose M here.
+
config NETFILTER_XTABLES
tristate "Netfilter Xtables support (required for ip_tables)"
default m if NETFILTER_ADVANCED=n
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index d93a121..fa6ffb1 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -124,6 +124,7 @@ nf_flow_table-objs := nf_flow_table_core.o nf_flow_table_ip.o \
nf_flow_table_offload.o
obj-$(CONFIG_NF_FLOW_TABLE_INET) += nf_flow_table_inet.o
+obj-$(CONFIG_NF_FLOW_TABLE_NETLINK) += nf_flow_table_netlink.o
# generic X tables
obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index c3054af..fb06755 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -373,6 +373,29 @@ void flow_offload_teardown(struct flow_offload *flow)
}
EXPORT_SYMBOL_GPL(flow_offload_teardown);
+void flow_offload_teardown_by_tuple(struct flow_offload_tuple *tuple)
+{
+ struct net_device *netdev;
+ struct nf_flowtable *flowtable;
+ struct flow_offload_tuple_rhash *tuplehash;
+ struct flow_offload *flow;
+ int dir;
+
+ list_for_each_entry(flowtable, &flowtables, list) {
+ for_each_netdev(&init_net, netdev) {
+ tuple->iifidx = netdev->ifindex;
+ tuplehash = flow_offload_lookup(flowtable, tuple);
+ if (!tuplehash)
+ continue;
+
+ dir = tuplehash->tuple.dir;
+ flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
+ flow_offload_teardown(flow);
+ }
+ };
+}
+EXPORT_SYMBOL_GPL(flow_offload_teardown_by_tuple);
+
struct flow_offload_tuple_rhash *
flow_offload_lookup(struct nf_flowtable *flow_table,
struct flow_offload_tuple *tuple)
diff --git a/net/netfilter/nf_flow_table_netlink.c b/net/netfilter/nf_flow_table_netlink.c
new file mode 100644
index 0000000..f05f29e
--- /dev/null
+++ b/net/netfilter/nf_flow_table_netlink.c
@@ -0,0 +1,239 @@
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <linux/netlink.h>
+#include <net/netlink.h>
+#include <net/ip.h>
+#include <linux/netfilter/nfnetlink.h>
+#include <net/netfilter/nf_flow_table.h>
+
+enum ft_netlink_msg_types {
+ FT_MSG_DEL,
+ FT_MSG_ADD,
+ FT_MSG_FLUSH,
+ FT_MSG_MAX
+};
+
+enum ftattr_type {
+ FTA_UNSPEC,
+ FTA_TUPLE,
+ __FTA_MAX
+};
+#define FTA_MAX (__FTA_MAX - 1)
+
+enum ftattr_tuple {
+ FTA_TUPLE_UNSPEC,
+ FTA_TUPLE_IP,
+ FTA_TUPLE_PROTO,
+ FTA_TUPLE_ZONE,
+ __FTA_TUPLE_MAX
+};
+#define FTA_TUPLE_MAX (__FTA_TUPLE_MAX - 1)
+
+enum ftattr_ip {
+ FTA_IP_UNSPEC,
+ FTA_IP_V4_SRC,
+ FTA_IP_V4_DST,
+ __FTA_IP_MAX
+};
+#define FTA_IP_MAX (__FTA_IP_MAX - 1)
+
+enum ftattr_l4proto {
+ FTA_PROTO_UNSPEC,
+ FTA_PROTO_NUM,
+ FTA_PROTO_SPORT,
+ FTA_PROTO_DPORT,
+ __FTA_PROTO_MAX
+};
+#define FTA_PROTO_MAX (__FTA_PROTO_MAX - 1)
+
+static const struct nla_policy tuple_nla_policy[FTA_TUPLE_MAX + 1] = {
+ [FTA_TUPLE_IP] = { .type = NLA_NESTED },
+ [FTA_TUPLE_PROTO] = { .type = NLA_NESTED },
+ [FTA_TUPLE_ZONE] = { .type = NLA_U16 },
+};
+
+static const struct nla_policy ip_nla_policy[FTA_IP_MAX + 1] = {
+ [FTA_IP_V4_SRC] = { .type = NLA_U32 },
+ [FTA_IP_V4_DST] = { .type = NLA_U32 },
+};
+
+static const struct nla_policy l4proto_nla_policy[FTA_PROTO_MAX + 1] = {
+ [FTA_PROTO_NUM] = { .type = NLA_U8 },
+ [FTA_PROTO_SPORT] = {.type = NLA_U16},
+ [FTA_PROTO_DPORT] = {.type = NLA_U16},
+};
+
+static inline int ftnetlink_parse_tuple_ip(struct nlattr *attr,
+ struct flow_offload_tuple *tuple)
+{
+ struct nlattr *tb[FTA_IP_MAX+1];
+ int err;
+
+ err = nla_parse_nested_deprecated(tb, FTA_IP_MAX, attr, ip_nla_policy, NULL);
+
+ if (err < 0)
+ return err;
+
+ switch (tuple->l3proto) {
+ case NFPROTO_IPV4:
+ if (!tb[FTA_IP_V4_SRC] || !tb[FTA_IP_V4_DST])
+ return -EINVAL;
+
+ tuple->src_v4.s_addr = nla_get_in_addr(tb[FTA_IP_V4_SRC]);
+ tuple->dst_v4.s_addr = nla_get_in_addr(tb[FTA_IP_V4_DST]);
+ }
+
+ return err;
+}
+
+static inline int ftnetlink_parse_tuple_proto(struct nlattr *attr,
+ struct flow_offload_tuple *tuple)
+{
+ struct nlattr *tb[FTA_PROTO_MAX+1];
+ int err;
+
+ err = nla_parse_nested_deprecated(tb, FTA_PROTO_MAX, attr, l4proto_nla_policy, NULL);
+
+ if(err < 0)
+ return err;
+
+ if (!tb[FTA_PROTO_NUM] || !tb[FTA_PROTO_SPORT] || !tb[FTA_PROTO_DPORT])
+ return -EINVAL;
+
+ tuple->l4proto = nla_get_u8(tb[FTA_PROTO_NUM]);
+ tuple->src_port = nla_get_u16(tb[FTA_PROTO_SPORT]);
+ tuple->dst_port = nla_get_u16(tb[FTA_PROTO_DPORT]);
+
+ return err;
+}
+
+static int ftnetlink_parse_tuple(const struct nlattr * const cda[],
+ struct flow_offload_tuple *tuple,
+ int attrtype, int l3proto)
+{
+ struct nlattr *tb[FTA_TUPLE_MAX+1];
+ int err;
+
+ memset(tuple, 0, sizeof(*tuple));
+
+ err = nla_parse_nested_deprecated(tb, FTA_TUPLE_MAX, cda[attrtype], tuple_nla_policy, NULL);
+ if (err < 0)
+ return err;
+
+ if (!tb[FTA_TUPLE_IP])
+ return -EINVAL;
+
+ /* parse IP */
+ tuple->l3proto = l3proto;
+ err = ftnetlink_parse_tuple_ip(tb[FTA_TUPLE_IP], tuple);
+ if (err < 0)
+ return err;
+
+ /* parse proto */
+ if (!tb[FTA_TUPLE_PROTO])
+ return -EINVAL;
+ err = ftnetlink_parse_tuple_proto(tb[FTA_TUPLE_PROTO], tuple);
+
+ if (err >= 0)
+ printk("tuple info:sip=%pI4,dip=%pI4 proto=%d "
+ "sport=%d dport=%d\n",
+ &tuple->src_v4, &tuple->dst_v4, tuple->l4proto,
+ ntohs(tuple->src_port), ntohs(tuple->dst_port));
+
+ return err;
+}
+
+static int ftnetlink_del_nf_flow(struct net *net, struct sock *ftnl, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const cda[],
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = skb->dev;
+ struct flow_offload_tuple tuple;
+ int err = -1;
+ struct nfgenmsg *nfmsg = nlmsg_data(nlh);
+ u_int8_t u3 = nfmsg->nfgen_family;
+
+ /* parse tuple */
+ if(!cda[FTA_TUPLE])
+ return -EINVAL;
+
+ err = ftnetlink_parse_tuple(cda, &tuple, FTA_TUPLE, u3);
+ if (err < 0)
+ return err;
+
+ /* teardown the flow */
+ flow_offload_teardown_by_tuple(&tuple);
+
+ return 0;
+}
+
+static int ftnetlink_add_nf_flow(struct net *net, struct sock *ftnl, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const cda[],
+ struct netlink_ext_ack *extack)
+{
+ return 0;
+}
+
+static int ftnetlink_flush_table(struct net *net, struct sock *ftnl, struct sk_buff *skb,
+ const struct nlmsghdr *nlh,
+ const struct nlattr * const cda[],
+ struct netlink_ext_ack *extack)
+{
+ struct net_device *dev = skb->dev;
+
+ nf_flow_table_cleanup(dev);
+
+ return 0;
+}
+
+static const struct nla_policy ft_nla_policy[FTA_MAX + 1] = {
+ [FTA_TUPLE] = { .type = NLA_NESTED },
+};
+
+static const struct nfnl_callback flow_table_cb[FT_MSG_MAX] = {
+ [FT_MSG_DEL] = {
+ .call = ftnetlink_del_nf_flow,
+ .attr_count = FTA_MAX,
+ .policy = ft_nla_policy
+ },
+ [FT_MSG_ADD] = {
+ .call = ftnetlink_add_nf_flow,
+ .attr_count = FTA_MAX,
+ .policy = ft_nla_policy
+ },
+ [FT_MSG_FLUSH] = {
+ .call = ftnetlink_flush_table,
+ .attr_count = FTA_MAX,
+ .policy = ft_nla_policy
+ },
+};
+
+static const struct nfnetlink_subsystem ftnl_subsys = {
+ .name = "flowtable",
+ .subsys_id = NFNL_SUBSYS_FLOWTABLE,
+ .cb_count = FT_MSG_MAX,
+ .cb = flow_table_cb,
+};
+
+static int __init ftnetlink_init(void)
+{
+ int ret;
+
+ ret = nfnetlink_subsys_register(&ftnl_subsys);
+
+ return ret;
+}
+
+static void ftnetlink_exit(void)
+{
+ nfnetlink_subsys_unregister(&ftnl_subsys);
+}
+
+MODULE_LICENSE("GPL");
+module_init(ftnetlink_init);
+module_exit(ftnetlink_exit);
--
2.18.0

View File

@@ -1,697 +0,0 @@
From 67a20e07982e9c43d299679f75fd81638271fc63 Mon Sep 17 00:00:00 2001
From: mtk27745 <rex.lu@mediatek.com>
Date: Mon, 18 Sep 2023 13:22:44 +0800
Subject: [PATCH 2/6] mtk wed add wed3 ser support
---
drivers/net/ethernet/mediatek/mtk_wed.c | 339 ++++++++++++++++---
drivers/net/ethernet/mediatek/mtk_wed_regs.h | 68 +++-
include/linux/soc/mediatek/mtk_wed.h | 8 +-
3 files changed, 367 insertions(+), 48 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index 4b32a82..02c156a 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -110,24 +110,88 @@ mtk_wdma_read_reset(struct mtk_wed_device *dev)
return wdma_r32(dev, MTK_WDMA_GLO_CFG);
}
-static u32
-mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+static void
+mtk_wdma_v3_rx_reset(struct mtk_wed_device *dev)
{
- if (wed_r32(dev, reg) & mask)
- return true;
-
- return false;
-}
+ u32 status;
-static int
-mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-{
- int sleep = 1000;
- int timeout = 100 * sleep;
- u32 val;
+ if (!mtk_wed_is_v3_or_greater(dev->hw))
+ return;
- return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
- timeout, false, dev, reg, mask);
+ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
+ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_PREF_TX_CFG))
+ dev_err(dev->hw->dev, "rx reset failed\n");
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_PREF_RX_CFG))
+ dev_err(dev->hw->dev, "rx reset failed\n");
+
+ wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
+ wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_WRBK_TX_CFG))
+ dev_err(dev->hw->dev, "rx reset failed\n");
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_WRBK_RX_CFG))
+ dev_err(dev->hw->dev, "rx reset failed\n");
+
+ /* prefetch FIFO */
+ wdma_w32(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
+ MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
+ MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
+ wdma_clr(dev, MTK_WDMA_PREF_RX_FIFO_CFG,
+ MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR |
+ MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR);
+
+ /* core FIFO */
+ wdma_w32(dev, MTK_WDMA_XDMA_RX_FIFO_CFG,
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
+ wdma_clr(dev, MTK_WDMA_XDMA_RX_FIFO_CFG,
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR |
+ MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR);
+
+ /* writeback FIFO */
+ wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0),
+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
+ wdma_w32(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1),
+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
+
+ wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(0),
+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
+ wdma_clr(dev, MTK_WDMA_WRBK_RX_FIFO_CFG(1),
+ MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR);
+
+ /* prefetch ring status */
+ wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG,
+ MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
+ wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG,
+ MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR);
+
+ /* writeback ring status */
+ wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG,
+ MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
+ wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG,
+ MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR);
}
static int
@@ -142,6 +206,7 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
if (ret)
dev_err(dev->hw->dev, "rx reset failed \n");
+ mtk_wdma_v3_rx_reset(dev);
wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_RX);
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
@@ -156,6 +221,101 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev)
return ret;
}
+static u32
+mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+{
+ return !!(wed_r32(dev, reg) & mask);
+}
+
+static int
+mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
+{
+ int sleep = 15000;
+ int timeout = 100 * sleep;
+ u32 val;
+
+ return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
+ timeout, false, dev, reg, mask);
+}
+
+static void
+mtk_wdma_v3_tx_reset(struct mtk_wed_device *dev)
+{
+ u32 status;
+
+ if (!mtk_wed_is_v3_or_greater(dev->hw))
+ return;
+
+ wdma_clr(dev, MTK_WDMA_PREF_TX_CFG, MTK_WDMA_PREF_TX_CFG_PREF_EN);
+ wdma_clr(dev, MTK_WDMA_PREF_RX_CFG, MTK_WDMA_PREF_RX_CFG_PREF_EN);
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_PREF_TX_CFG_PREF_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_PREF_TX_CFG))
+ dev_err(dev->hw->dev, "tx reset failed\n");
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_PREF_RX_CFG_PREF_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_PREF_RX_CFG))
+ dev_err(dev->hw->dev, "tx reset failed\n");
+
+ wdma_clr(dev, MTK_WDMA_WRBK_TX_CFG, MTK_WDMA_WRBK_TX_CFG_WRBK_EN);
+ wdma_clr(dev, MTK_WDMA_WRBK_RX_CFG, MTK_WDMA_WRBK_RX_CFG_WRBK_EN);
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_WRBK_TX_CFG))
+ dev_err(dev->hw->dev, "tx reset failed\n");
+
+ if (read_poll_timeout(wdma_r32, status,
+ !(status & MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY),
+ 0, 10000, false, dev, MTK_WDMA_WRBK_RX_CFG))
+ dev_err(dev->hw->dev, "tx reset failed\n");
+
+ /* prefetch FIFO */
+ wdma_w32(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
+ MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
+ MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
+ wdma_clr(dev, MTK_WDMA_PREF_TX_FIFO_CFG,
+ MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR |
+ MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR);
+
+ /* core FIFO */
+ wdma_w32(dev, MTK_WDMA_XDMA_TX_FIFO_CFG,
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
+ wdma_clr(dev, MTK_WDMA_XDMA_TX_FIFO_CFG,
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR |
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR |
+ MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR);
+
+ /* writeback FIFO */
+ wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0),
+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
+ wdma_w32(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1),
+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
+
+ wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(0),
+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
+ wdma_clr(dev, MTK_WDMA_WRBK_TX_FIFO_CFG(1),
+ MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR);
+
+ /* prefetch ring status */
+ wdma_w32(dev, MTK_WDMA_PREF_SIDX_CFG,
+ MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
+ wdma_clr(dev, MTK_WDMA_PREF_SIDX_CFG,
+ MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR);
+
+ /* writeback ring status */
+ wdma_w32(dev, MTK_WDMA_WRBK_SIDX_CFG,
+ MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
+ wdma_clr(dev, MTK_WDMA_WRBK_SIDX_CFG,
+ MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR);
+}
+
static void
mtk_wdma_tx_reset(struct mtk_wed_device *dev)
{
@@ -167,6 +327,7 @@ mtk_wdma_tx_reset(struct mtk_wed_device *dev)
!(status & mask), 0, 10000))
dev_err(dev->hw->dev, "tx reset failed \n");
+ mtk_wdma_v3_tx_reset(dev);
wdma_w32(dev, MTK_WDMA_RESET_IDX, MTK_WDMA_RESET_IDX_TX);
wdma_w32(dev, MTK_WDMA_RESET_IDX, 0);
@@ -1389,25 +1550,6 @@ mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx)
}
}
-static u32
-mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-{
- if (wed_r32(dev, reg) & mask)
- return true;
-
- return false;
-}
-
-static int
-mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask)
-{
- int sleep = 1000;
- int timeout = 100 * sleep;
- u32 val;
-
- return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep,
- timeout, false, dev, reg, mask);
-}
static int
mtk_wed_rx_reset(struct mtk_wed_device *dev)
@@ -1423,13 +1565,32 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
if (ret)
return ret;
+ if (dev->wlan.hw_rro) {
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_IND_CMD_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_HW_STS,
+ MTK_WED_RX_IND_CMD_BUSY);
+ mtk_wed_reset(dev, MTK_WED_RESET_RRO_RX_TO_PG);
+ }
+
wed_clr(dev, MTK_WED_WPDMA_RX_D_GLO_CFG, MTK_WED_WPDMA_RX_D_RX_DRV_EN);
ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_GLO_CFG,
MTK_WED_WPDMA_RX_D_RX_DRV_BUSY);
+ if (!ret && mtk_wed_is_v3_or_greater(dev->hw))
+ ret = mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
+ MTK_WED_WPDMA_RX_D_PREF_BUSY);
if (ret) {
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_D_DRV);
} else {
+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
+ /*1.a. Disable Prefetch HW*/
+ wed_clr(dev, MTK_WED_WPDMA_RX_D_PREF_CFG, MTK_WED_WPDMA_RX_D_PREF_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_RX_D_PREF_CFG,
+ MTK_WED_WPDMA_RX_D_PREF_BUSY);
+ wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
+ MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL);
+ }
+
wed_w32(dev, MTK_WED_WPDMA_RX_D_RST_IDX,
MTK_WED_WPDMA_RX_D_RST_CRX_IDX |
MTK_WED_WPDMA_RX_D_RST_DRV_IDX);
@@ -1457,15 +1618,36 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
wed_w32(dev, MTK_WED_RROQM_RST_IDX, 0);
}
+ if (dev->wlan.hw_rro) {
+ /* Disable RRO MSDU Page Drv */
+ wed_clr(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_EN);
+
+ /* Disable RRO Data Drv */
+ wed_clr(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_EN);
+
+ /* RRO MSDU Page Drv Reset */
+ wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG, MTK_WED_RRO_MSDU_PG_DRV_CLR);
+ mtk_wed_poll_busy(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
+ MTK_WED_RRO_MSDU_PG_DRV_CLR);
+
+ /* RRO Data Drv Reset */
+ wed_w32(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_RX_D_DRV_CLR);
+ mtk_wed_poll_busy(dev, MTK_WED_RRO_RX_D_CFG(2),
+ MTK_WED_RRO_RX_D_DRV_CLR);
+ }
+
/* reset route qm */
wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_RX_ROUTE_QM_EN);
ret = mtk_wed_poll_busy(dev, MTK_WED_CTRL,
MTK_WED_CTRL_RX_ROUTE_QM_BUSY);
if (ret) {
mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
+ } else if (mtk_wed_is_v3_or_greater(dev->hw)) {
+ wed_set(dev, MTK_WED_RTQM_RST, BIT(0));
+ wed_clr(dev, MTK_WED_RTQM_RST, BIT(0));
+ mtk_wed_reset(dev, MTK_WED_RESET_RX_ROUTE_QM);
} else {
- wed_set(dev, MTK_WED_RTQM_GLO_CFG,
- MTK_WED_RTQM_Q_RST);
+ wed_set(dev, MTK_WED_RTQM_GLO_CFG, MTK_WED_RTQM_Q_RST);
}
/* reset tx wdma */
@@ -1473,8 +1655,12 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
/* reset tx wdma drv */
wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_TX_DRV_EN);
- mtk_wed_poll_busy(dev, MTK_WED_CTRL,
- MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
+ if (mtk_wed_is_v3_or_greater(dev->hw))
+ mtk_wed_poll_busy(dev, MTK_WED_WPDMA_STATUS,
+ MTK_WED_WPDMA_STATUS_TX_DRV);
+ else
+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_WDMA_INT_AGENT_BUSY);
mtk_wed_reset(dev, MTK_WED_RESET_WDMA_TX_DRV);
/* reset wed rx dma */
@@ -1495,6 +1681,14 @@ mtk_wed_rx_reset(struct mtk_wed_device *dev)
MTK_WED_CTRL_WED_RX_BM_BUSY);
mtk_wed_reset(dev, MTK_WED_RESET_RX_BM);
+ if (dev->wlan.hw_rro) {
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_RX_PG_BM_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_CTRL,
+ MTK_WED_CTRL_WED_RX_PG_BM_BUSY);
+ wed_set(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
+ wed_clr(dev, MTK_WED_RESET, MTK_WED_RESET_RX_PG_BM);
+ }
+
/* wo change to enable state */
val = WO_STATE_ENABLE;
ret = mtk_wed_mcu_send_msg(wo, MTK_WED_MODULE_ID_WO,
@@ -1549,16 +1743,55 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
/* 2. Reset WDMA Rx DMA/Driver_Engine */
busy = !!mtk_wdma_rx_reset(dev);
+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
+ val = MTK_WED_WDMA_GLO_CFG_RX_DIS_FSM_AUTO_IDLE |
+ wed_r32(dev, MTK_WED_WDMA_GLO_CFG);
+ val &= ~MTK_WED_WDMA_GLO_CFG_RX_DRV_EN;
+ wed_w32(dev, MTK_WED_WDMA_GLO_CFG, val);
+ } else {
+ wed_clr(dev, MTK_WED_WDMA_GLO_CFG,
+ MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
+ }
- wed_clr(dev, MTK_WED_WDMA_GLO_CFG, MTK_WED_WDMA_GLO_CFG_RX_DRV_EN);
if (!busy)
busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_GLO_CFG,
MTK_WED_WDMA_GLO_CFG_RX_DRV_BUSY);
+ if (!busy && mtk_wed_is_v3_or_greater(dev->hw))
+ busy = mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
+ MTK_WED_WDMA_RX_PREF_BUSY);
if (busy) {
mtk_wed_reset(dev, MTK_WED_RESET_WDMA_INT_AGENT);
mtk_wed_reset(dev, MTK_WED_RESET_WDMA_RX_DRV);
} else {
+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
+ /*1.a. Disable Prefetch HW*/
+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
+ MTK_WED_WDMA_RX_PREF_EN);
+ mtk_wed_poll_busy(dev, MTK_WED_WDMA_RX_PREF_CFG,
+ MTK_WED_WDMA_RX_PREF_BUSY);
+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
+ MTK_WED_WDMA_RX_PREF_DDONE2_EN);
+
+ /* reset prefetch index */
+ wed_set(dev, MTK_WED_WDMA_RX_PREF_CFG,
+ MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
+ MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
+
+ wed_clr(dev, MTK_WED_WDMA_RX_PREF_CFG,
+ MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR |
+ MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR);
+
+ /* reset prefetch FIFO */
+ wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG,
+ MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR |
+ MTK_WED_WDMA_RX_PREF_FIFO_RX1_CLR);
+ wed_w32(dev, MTK_WED_WDMA_RX_PREF_FIFO_CFG, 0);
+
+ /*2. Reset dma index*/
+ wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
+ MTK_WED_WDMA_RESET_IDX_RX_ALL);
+ }
wed_w32(dev, MTK_WED_WDMA_RESET_IDX,
MTK_WED_WDMA_RESET_IDX_RX | MTK_WED_WDMA_RESET_IDX_DRV);
wed_w32(dev, MTK_WED_WDMA_RESET_IDX, 0);
@@ -1574,8 +1807,13 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_WED_TX_FREE_AGENT_EN);
for (i = 0; i < 100; i++) {
- val = wed_r32(dev, MTK_WED_TX_BM_INTF);
- if (FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP, val) == 0x40)
+ if (mtk_wed_is_v1(dev->hw))
+ val = FIELD_GET(MTK_WED_TX_BM_INTF_TKFIFO_FDEP,
+ wed_r32(dev, MTK_WED_TX_BM_INTF));
+ else
+ val = FIELD_GET(MTK_WED_TX_TKID_INTF_TKFIFO_FDEP,
+ wed_r32(dev, MTK_WED_TX_TKID_INTF));
+ if (val == 0x40)
break;
}
@@ -1599,6 +1837,8 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_INT_AGENT);
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_TX_DRV);
mtk_wed_reset(dev, MTK_WED_RESET_WPDMA_RX_DRV);
+ if (mtk_wed_is_v3_or_greater(dev->hw))
+ wed_w32(dev, MTK_WED_RX1_CTRL2, 0);
} else {
wed_w32(dev, MTK_WED_WPDMA_RESET_IDX,
MTK_WED_WPDMA_RESET_IDX_TX |
@@ -1615,7 +1855,14 @@ mtk_wed_reset_dma(struct mtk_wed_device *dev)
wed_w32(dev, MTK_WED_RESET_IDX, 0);
}
- mtk_wed_rx_reset(dev);
+ if (mtk_wed_is_v3_or_greater(dev->hw)) {
+ /* reset amsdu engine */
+ wed_clr(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN);
+ mtk_wed_reset(dev, MTK_WED_RESET_TX_AMSDU);
+ }
+
+ if (mtk_wed_get_rx_capa(dev))
+ mtk_wed_rx_reset(dev);
}
static int
@@ -1932,7 +2179,7 @@ mtk_wed_dma_enable(struct mtk_wed_device *dev)
}
static void
-mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask)
+mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask, bool reset)
{
int i;
@@ -1942,6 +2189,12 @@ mtk_wed_start_hw_rro(struct mtk_wed_device *dev, u32 irq_mask)
if (!mtk_wed_get_rx_capa(dev) || !dev->wlan.hw_rro)
return;
+ if (reset) {
+ wed_set(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
+ MTK_WED_RRO_MSDU_PG_DRV_EN);
+ return;
+ }
+
wed_set(dev, MTK_WED_RRO_RX_D_CFG(2), MTK_WED_RRO_MSDU_PG_DRV_CLR);
wed_w32(dev, MTK_WED_RRO_MSDU_PG_RING2_CFG,
MTK_WED_RRO_MSDU_PG_DRV_CLR);
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_regs.h b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
index 0af264d..1ee0fe1 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_regs.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_regs.h
@@ -36,6 +36,8 @@ struct mtk_wdma_desc {
#define MTK_WED_RESET 0x008
#define MTK_WED_RESET_TX_BM BIT(0)
#define MTK_WED_RESET_RX_BM BIT(1)
+#define MTK_WED_RESET_RX_PG_BM BIT(2)
+#define MTK_WED_RESET_RRO_RX_TO_PG BIT(3)
#define MTK_WED_RESET_TX_FREE_AGENT BIT(4)
#define MTK_WED_RESET_WPDMA_TX_DRV BIT(8)
#define MTK_WED_RESET_WPDMA_RX_DRV BIT(9)
@@ -58,7 +60,7 @@ struct mtk_wdma_desc {
#define MTK_WED_CTRL_WDMA_INT_AGENT_BUSY BIT(3)
#define MTK_WED_CTRL_WED_RX_IND_CMD_EN BIT(5)
#define MTK_WED_CTRL_WED_RX_PG_BM_EN BIT(6)
-#define MTK_WED_CTRL_WED_RX_PG_BM_BUSU BIT(7)
+#define MTK_WED_CTRL_WED_RX_PG_BM_BUSY BIT(7)
#define MTK_WED_CTRL_WED_TX_BM_EN BIT(8)
#define MTK_WED_CTRL_WED_TX_BM_BUSY BIT(9)
#define MTK_WED_CTRL_WED_TX_FREE_AGENT_EN BIT(10)
@@ -117,6 +119,10 @@ struct mtk_wdma_desc {
#define MTK_WED_STATUS 0x060
#define MTK_WED_STATUS_TX GENMASK(15, 8)
+#define MTK_WED_WPDMA_STATUS 0x068
+#define MTK_WED_WPDMA_STATUS_TX_DRV GENMASK(15, 8)
+
+
#define MTK_WED_TX_BM_CTRL 0x080
#define MTK_WED_TX_BM_CTRL_VLD_GRP_NUM GENMASK(6, 0)
#define MTK_WED_TX_BM_CTRL_RSV_GRP_NUM GENMASK(22, 16)
@@ -154,6 +160,9 @@ struct mtk_wdma_desc {
#define MTK_WED_TX_TKID_CTRL_VLD_GRP_NUM_V3 GENMASK(7, 0)
#define MTK_WED_TX_TKID_CTRL_RSV_GRP_NUM_V3 GENMASK(23, 16)
+#define MTK_WED_TX_TKID_INTF 0x0dc
+#define MTK_WED_TX_TKID_INTF_TKFIFO_FDEP GENMASK(25, 16)
+
#define MTK_WED_TX_TKID_DYN_THR 0x0e0
#define MTK_WED_TX_TKID_DYN_THR_LO GENMASK(6, 0)
#define MTK_WED_TX_TKID_DYN_THR_HI GENMASK(22, 16)
@@ -205,6 +214,7 @@ struct mtk_wdma_desc {
#define MTK_WED_RING_RX_DATA(_n) (0x420 + (_n) * 0x10)
#define MTK_WED_SCR0 0x3c0
+#define MTK_WED_RX1_CTRL2 0x418
#define MTK_WED_WPDMA_INT_TRIGGER 0x504
#define MTK_WED_WPDMA_INT_TRIGGER_RX_DONE BIT(1)
#define MTK_WED_WPDMA_INT_TRIGGER_TX_DONE GENMASK(5, 4)
@@ -320,6 +330,7 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_RX_D_RST_IDX 0x760
#define MTK_WED_WPDMA_RX_D_RST_CRX_IDX GENMASK(17, 16)
+#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX_ALL BIT(20)
#define MTK_WED_WPDMA_RX_D_RST_DRV_IDX GENMASK(25, 24)
#define MTK_WED_WPDMA_RX_GLO_CFG 0x76c
@@ -336,6 +347,7 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_RX_D_PREF_CFG 0x7b4
#define MTK_WED_WPDMA_RX_D_PREF_EN BIT(0)
+#define MTK_WED_WPDMA_RX_D_PREF_BUSY BIT(1)
#define MTK_WED_WPDMA_RX_D_PREF_BURST_SIZE GENMASK(12, 8)
#define MTK_WED_WPDMA_RX_D_PREF_LOW_THRES GENMASK(21, 16)
@@ -357,11 +369,13 @@ struct mtk_wdma_desc {
#define MTK_WED_WDMA_RX_PREF_CFG 0x950
#define MTK_WED_WDMA_RX_PREF_EN BIT(0)
+#define MTK_WED_WDMA_RX_PREF_BUSY BIT(1)
#define MTK_WED_WDMA_RX_PREF_BURST_SIZE GENMASK(12, 8)
#define MTK_WED_WDMA_RX_PREF_LOW_THRES GENMASK(21, 16)
#define MTK_WED_WDMA_RX_PREF_RX0_SIDX_CLR BIT(24)
#define MTK_WED_WDMA_RX_PREF_RX1_SIDX_CLR BIT(25)
#define MTK_WED_WDMA_RX_PREF_DDONE2_EN BIT(26)
+#define MTK_WED_WDMA_RX_PREF_DDONE2_BUSY BIT(27)
#define MTK_WED_WDMA_RX_PREF_FIFO_CFG 0x95C
#define MTK_WED_WDMA_RX_PREF_FIFO_RX0_CLR BIT(0)
@@ -390,6 +404,7 @@ struct mtk_wdma_desc {
#define MTK_WED_WDMA_RESET_IDX 0xa08
#define MTK_WED_WDMA_RESET_IDX_RX GENMASK(17, 16)
+#define MTK_WED_WDMA_RESET_IDX_RX_ALL BIT(20)
#define MTK_WED_WDMA_RESET_IDX_DRV GENMASK(25, 24)
#define MTK_WED_WDMA_INT_CLR 0xa24
@@ -458,21 +473,66 @@ struct mtk_wdma_desc {
#define MTK_WDMA_INT_MASK_RX_DELAY BIT(30)
#define MTK_WDMA_INT_MASK_RX_COHERENT BIT(31)
+#define MTK_WDMA_XDMA_TX_FIFO_CFG 0x238
+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_PAR_FIFO_CLEAR BIT(0)
+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_CMD_FIFO_CLEAR BIT(4)
+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_DMAD_FIFO_CLEAR BIT(8)
+#define MTK_WDMA_XDMA_TX_FIFO_CFG_TX_ARR_FIFO_CLEAR BIT(12)
+
+#define MTK_WDMA_XDMA_RX_FIFO_CFG 0x23c
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_PAR_FIFO_CLEAR BIT(0)
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_CMD_FIFO_CLEAR BIT(4)
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_DMAD_FIFO_CLEAR BIT(8)
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_ARR_FIFO_CLEAR BIT(12)
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_LEN_FIFO_CLEAR BIT(15)
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_WID_FIFO_CLEAR BIT(18)
+#define MTK_WDMA_XDMA_RX_FIFO_CFG_RX_BID_FIFO_CLEAR BIT(21)
+
+
+
#define MTK_WDMA_INT_GRP1 0x250
#define MTK_WDMA_INT_GRP2 0x254
#define MTK_WDMA_PREF_TX_CFG 0x2d0
#define MTK_WDMA_PREF_TX_CFG_PREF_EN BIT(0)
+#define MTK_WDMA_PREF_TX_CFG_PREF_BUSY BIT(1)
#define MTK_WDMA_PREF_RX_CFG 0x2dc
#define MTK_WDMA_PREF_RX_CFG_PREF_EN BIT(0)
+#define MTK_WDMA_PREF_RX_CFG_PREF_BUSY BIT(1)
+
+#define MTK_WDMA_PREF_RX_FIFO_CFG 0x2e0
+#define MTK_WDMA_PREF_RX_FIFO_CFG_RING0_CLEAR BIT(0)
+#define MTK_WDMA_PREF_RX_FIFO_CFG_RING1_CLEAR BIT(16)
+
+#define MTK_WDMA_PREF_TX_FIFO_CFG 0x2d4
+#define MTK_WDMA_PREF_TX_FIFO_CFG_RING0_CLEAR BIT(0)
+#define MTK_WDMA_PREF_TX_FIFO_CFG_RING1_CLEAR BIT(16)
+
+#define MTK_WDMA_PREF_SIDX_CFG 0x2e4
+#define MTK_WDMA_PREF_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
+#define MTK_WDMA_PREF_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
#define MTK_WDMA_WRBK_TX_CFG 0x300
+#define MTK_WDMA_WRBK_TX_CFG_WRBK_BUSY BIT(0)
#define MTK_WDMA_WRBK_TX_CFG_WRBK_EN BIT(30)
+#define MTK_WDMA_WRBK_TX_FIFO_CFG(_n) (0x304 + (_n) * 0x4)
+#define MTK_WDMA_WRBK_TX_FIFO_CFG_RING_CLEAR BIT(0)
+
+
#define MTK_WDMA_WRBK_RX_CFG 0x344
+#define MTK_WDMA_WRBK_RX_CFG_WRBK_BUSY BIT(0)
#define MTK_WDMA_WRBK_RX_CFG_WRBK_EN BIT(30)
+#define MTK_WDMA_WRBK_RX_FIFO_CFG(_n) (0x348 + (_n) * 0x4)
+#define MTK_WDMA_WRBK_RX_FIFO_CFG_RING_CLEAR BIT(0)
+
+
+#define MTK_WDMA_WRBK_SIDX_CFG 0x388
+#define MTK_WDMA_WRBK_SIDX_CFG_TX_RING_CLEAR GENMASK(3, 0)
+#define MTK_WDMA_WRBK_SIDX_CFG_RX_RING_CLEAR GENMASK(5, 4)
+
#define MTK_PCIE_MIRROR_MAP(n) ((n) ? 0x4 : 0x0)
#define MTK_PCIE_MIRROR_MAP_EN BIT(0)
#define MTK_PCIE_MIRROR_MAP_WED_ID BIT(1)
@@ -486,6 +546,9 @@ struct mtk_wdma_desc {
#define MTK_WED_RTQM_Q_DBG_BYPASS BIT(5)
#define MTK_WED_RTQM_TXDMAD_FPORT GENMASK(23, 20)
+#define MTK_WED_RTQM_RST 0xb04
+
+
#define MTK_WED_RTQM_IGRS0_I2HW_DMAD_CNT 0xb1c
#define MTK_WED_RTQM_IGRS0_I2H_DMAD_CNT(_n) (0xb20 + (_n) * 0x4)
#define MTK_WED_RTQM_IGRS0_I2HW_PKT_CNT 0xb28
@@ -675,6 +738,9 @@ struct mtk_wdma_desc {
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_CLR BIT(17)
#define MTK_WED_WPDMA_INT_CTRL_RRO_PG2_DONE_TRIG GENMASK(22, 18)
+#define MTK_WED_RRO_RX_HW_STS 0xf00
+#define MTK_WED_RX_IND_CMD_BUSY GENMASK(31, 0)
+
#define MTK_WED_RX_IND_CMD_CNT0 0xf20
#define MTK_WED_RX_IND_CMD_DBG_CNT_EN BIT(31)
diff --git a/include/linux/soc/mediatek/mtk_wed.h b/include/linux/soc/mediatek/mtk_wed.h
index e81e41f..83a4b8b 100644
--- a/include/linux/soc/mediatek/mtk_wed.h
+++ b/include/linux/soc/mediatek/mtk_wed.h
@@ -222,7 +222,7 @@ struct mtk_wed_ops {
u32 (*irq_get)(struct mtk_wed_device *dev, u32 mask);
void (*irq_set_mask)(struct mtk_wed_device *dev, u32 mask);
- void (*start_hw_rro)(struct mtk_wed_device *dev, u32 irq_mask);
+ void (*start_hw_rro)(struct mtk_wed_device *dev, u32 irq_mask, bool reset);
void (*rro_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
void __iomem *regs);
void (*msdu_pg_rx_ring_setup)(struct mtk_wed_device *dev, int ring,
@@ -302,8 +302,8 @@ mtk_wed_is_amsdu_supported(struct mtk_wed_device *dev)
#define mtk_wed_device_dma_reset(_dev) (_dev)->ops->reset_dma(_dev)
#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) \
(_dev)->ops->setup_tc(_dev, _ndev, _type, _data)
-#define mtk_wed_device_start_hw_rro(_dev, _mask) \
- (_dev)->ops->start_hw_rro(_dev, _mask)
+#define mtk_wed_device_start_hw_rro(_dev, _mask, _reset) \
+ (_dev)->ops->start_hw_rro(_dev, _mask, _reset)
#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) \
(_dev)->ops->rro_rx_ring_setup(_dev, _ring, _regs)
#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) \
@@ -329,7 +329,7 @@ static inline bool mtk_wed_device_active(struct mtk_wed_device *dev)
#define mtk_wed_device_stop(_dev) do {} while (0)
#define mtk_wed_device_dma_reset(_dev) do {} while (0)
#define mtk_wed_device_setup_tc(_dev, _ndev, _type, _data) do {} while (0)
-#define mtk_wed_device_start_hw_rro(_dev, _mask) do {} while (0)
+#define mtk_wed_device_start_hw_rro(_dev, _mask, _reset) do {} while (0)
#define mtk_wed_device_rro_rx_ring_setup(_dev, _ring, _regs) -ENODEV
#define mtk_wed_device_msdu_pg_rx_ring_setup(_dev, _ring, _regs) -ENODEV
#define mtk_wed_device_ind_rx_ring_setup(_dev, _regs) -ENODEV
--
2.18.0

View File

@@ -1,140 +0,0 @@
From f83c601c7b525c0adedcf1f5e8041acd350c7e2d Mon Sep 17 00:00:00 2001
From: Sujuan Chen <sujuan.chen@mediatek.com>
Date: Mon, 18 Sep 2023 13:23:56 +0800
Subject: [PATCH] mtk: wed: add dma mask limitation and GFP_DMA32 for board >=
4GB dram
---
drivers/net/ethernet/mediatek/mtk_wed.c | 16 +++++++++++-----
drivers/net/ethernet/mediatek/mtk_wed_mcu.c | 4 ++--
drivers/net/ethernet/mediatek/mtk_wed_wo.c | 4 ++--
drivers/net/ethernet/mediatek/mtk_wed_wo.h | 1 +
4 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/drivers/net/ethernet/mediatek/mtk_wed.c b/drivers/net/ethernet/mediatek/mtk_wed.c
index 5eeb3ed..094bc94 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed.c
@@ -625,7 +625,7 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
void *buf;
int s;
- page = __dev_alloc_pages(GFP_KERNEL, 0);
+ page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
if (!page)
return -ENOMEM;
@@ -646,10 +646,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
for (s = 0; s < MTK_WED_BUF_PER_PAGE; s++) {
struct mtk_wdma_desc *desc = desc_ptr;
+ u32 ctrl;
desc->buf0 = cpu_to_le32(buf_phys);
if (!mtk_wed_is_v3_or_greater(dev->hw)) {
- u32 txd_size, ctrl;
+ u32 txd_size;
txd_size = dev->wlan.init_buf(buf, buf_phys,
token++);
@@ -663,11 +664,11 @@ mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev)
ctrl |= MTK_WDMA_DESC_CTRL_LAST_SEG0 |
FIELD_PREP(MTK_WDMA_DESC_CTRL_LEN1_V2,
MTK_WED_BUF_SIZE - txd_size);
- desc->ctrl = cpu_to_le32(ctrl);
desc->info = 0;
} else {
- desc->ctrl = cpu_to_le32(token << 16);
+ ctrl = token << 16 | TX_DMA_SDP1(buf_phys);
}
+ desc->ctrl = cpu_to_le32(ctrl);
desc_ptr += desc_size;
buf += MTK_WED_BUF_SIZE;
@@ -749,7 +750,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
void *buf;
int s;
- page = __dev_alloc_pages(GFP_KERNEL, 0);
+ page = __dev_alloc_pages(GFP_KERNEL | GFP_DMA32, 0);
if (!page)
return -ENOMEM;
@@ -769,6 +770,7 @@ mtk_wed_hwrro_buffer_alloc(struct mtk_wed_device *dev)
buf_phys = page_phys;
for (s = 0; s < MTK_WED_RX_PAGE_BUF_PER_PAGE; s++) {
desc->buf0 = cpu_to_le32(buf_phys);
+ desc->token = cpu_to_le32(RX_DMA_SDP1(buf_phys));
desc++;
buf += MTK_WED_PAGE_BUF_SIZE;
buf_phys += MTK_WED_PAGE_BUF_SIZE;
@@ -2457,6 +2459,10 @@ mtk_wed_attach(struct mtk_wed_device *dev)
dev->version = hw->version;
dev->hw->pci_base = mtk_wed_get_pci_base(dev);
+ ret = dma_set_mask_and_coherent(hw->dev, DMA_BIT_MASK(32));
+ if (ret)
+ return ret;
+
if (hw->eth->dma_dev == hw->eth->dev &&
of_dma_is_coherent(hw->eth->dev->of_node))
mtk_eth_set_dma_device(hw->eth, hw->dev);
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
index 18d1fb1..a88061c 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_mcu.c
@@ -145,7 +145,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
}req;
exp->log_size = EXCEPTION_LOG_SIZE;
- exp->log = kmalloc(exp->log_size, GFP_ATOMIC);
+ exp->log = page_frag_alloc(&wo->page, exp->log_size, GFP_ATOMIC | GFP_DMA32);
if (!exp->log)
return -ENOMEM;
@@ -165,7 +165,7 @@ int mtk_wed_exception_init(struct mtk_wed_wo *wo)
&req, sizeof(req), false);
free:
- kfree(exp->log);
+ skb_free_frag(exp->log);
return -ENOMEM;
}
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.c b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
index 54b7787..e991d20 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.c
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.c
@@ -88,7 +88,7 @@ woif_q_rx_fill(struct mtk_wed_wo *wo, struct wed_wo_queue *q, bool rx)
page = &q->rx_page;
while (q->queued < q->ndesc) {
- buf = page_frag_alloc(page, len, GFP_ATOMIC);
+ buf = page_frag_alloc(page, len, GFP_ATOMIC | GFP_DMA32);
if (!buf)
break;
@@ -555,7 +555,7 @@ void mtk_wed_wo_exit(struct mtk_wed_hw *hw)
if (wo->exp.log) {
dma_unmap_single(wo->hw->dev, wo->exp.phys, wo->exp.log_size, DMA_FROM_DEVICE);
- kfree(wo->exp.log);
+ skb_free_frag(wo->exp.log);
}
wo->hw = NULL;
diff --git a/drivers/net/ethernet/mediatek/mtk_wed_wo.h b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
index b24fef3..5afa6de 100644
--- a/drivers/net/ethernet/mediatek/mtk_wed_wo.h
+++ b/drivers/net/ethernet/mediatek/mtk_wed_wo.h
@@ -193,6 +193,7 @@ struct mtk_wed_wo {
const struct wed_wo_drv_ops *drv_ops;
const struct wed_wo_mcu_ops *mcu_ops;
const struct wed_wo_queue_ops *queue_ops;
+ struct page_frag_cache page;
struct net_device napi_dev;
spinlock_t rx_lock;
--
2.18.0

View File

@@ -1,124 +0,0 @@
From e917fdd9042787edd43e4070c3480baf0dfb8d33 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Mon, 18 Mar 2024 16:57:13 +0800
Subject: [PATCH 22/24]
999-3022-mediatek-ethernet-add-multiple-ppe-allocatiion.patch
---
arch/arm64/boot/dts/mediatek/mt7988.dtsi | 1 +
drivers/net/ethernet/mediatek/mtk_eth_soc.c | 22 ++++++++++++++++---
drivers/net/ethernet/mediatek/mtk_eth_soc.h | 3 +++
.../net/ethernet/mediatek/mtk_ppe_offload.c | 10 +++++++++
4 files changed, 33 insertions(+), 3 deletions(-)
diff --git a/arch/arm64/boot/dts/mediatek/mt7988.dtsi b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
index 4a1a446..57b27f8 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988.dtsi
+++ b/arch/arm64/boot/dts/mediatek/mt7988.dtsi
@@ -942,6 +942,7 @@
mediatek,infracfg = <&topmisc>;
mediatek,toprgu = <&watchdog>;
mediatek,hwver = <&hwver>;
+ mtketh-ppe-num = <3>;
#reset-cells = <1>;
#address-cells = <1>;
#size-cells = <0>;
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.c b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
index 291afdc..c0f4ade 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
@@ -2349,6 +2349,7 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
u8 *data, *new_data;
struct mtk_rx_dma_v2 *rxd, trxd;
int done = 0;
+ int i;
if (unlikely(!ring))
goto rx_done;
@@ -2463,8 +2464,10 @@ static int mtk_poll_rx(struct napi_struct *napi, int budget,
}
#endif
- if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED)
- mtk_ppe_check_skb(eth->ppe[0], skb, hash);
+ if (reason == MTK_PPE_CPU_REASON_HIT_UNBIND_RATE_REACHED) {
+ i = eth->mac[mac]->ppe_idx;
+ mtk_ppe_check_skb(eth->ppe[i], skb, hash);
+ }
if (netdev->features & NETIF_F_HW_VLAN_CTAG_RX) {
if (MTK_HAS_CAPS(eth->soc->caps, MTK_NETSYS_RX_V2)) {
@@ -4113,7 +4116,19 @@ static int mtk_open(struct net_device *dev)
SGMSYS_QPHY_PWR_STATE_CTRL, 0);
if (eth->soc->offload_version) {
- gdm_config = MTK_GDMA_TO_PPE0;
+#if defined(CONFIG_MEDIATEK_NETSYS_V2) || defined(CONFIG_MEDIATEK_NETSYS_V3)
+ if (eth->ppe_num >= 3 && mac->id == 2) {
+ mac->ppe_idx = 2;
+ gdm_config = MTK_GDMA_TO_PPE2;
+ } else if (eth->ppe_num >= 2 && mac->id == 1) {
+ mac->ppe_idx = 1;
+ gdm_config = MTK_GDMA_TO_PPE1;
+ } else
+#endif
+ {
+ mac->ppe_idx = 0;
+ gdm_config = MTK_GDMA_TO_PPE0;
+ }
for (i = 0; i < eth->ppe_num; i++)
mtk_ppe_start(eth->ppe[i]);
@@ -5129,6 +5144,7 @@ static const struct net_device_ops mtk_netdev_ops = {
.ndo_poll_controller = mtk_poll_controller,
#endif
.ndo_setup_tc = mtk_eth_setup_tc,
+ .ndo_fill_receive_path = mtk_eth_fill_receive_path,
};
static void mux_poll(struct work_struct *work)
diff --git a/drivers/net/ethernet/mediatek/mtk_eth_soc.h b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
index 8454361..d958aec 100644
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.h
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.h
@@ -1978,6 +1978,7 @@ struct mtk_mac {
phy_interface_t interface;
unsigned int mode;
unsigned int type;
+ unsigned int ppe_idx;
int speed;
struct device_node *of_node;
struct phylink *phylink;
@@ -2079,6 +2080,8 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
void *type_data);
int mtk_eth_setup_tc_block(struct net_device *dev, struct flow_block_offload *f,
struct mtk_eth *eth);
+int mtk_eth_fill_receive_path(struct net_device_path_ctx *ctx,
+ struct net_device_path *path);
void mtk_eth_set_dma_device(struct mtk_eth *eth, struct device *dma_dev);
u32 mtk_rss_indr_table(struct mtk_rss_params *rss_params, int index);
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
index 402f1e3..3bfbec8 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
@@ -828,6 +828,16 @@ int mtk_eth_setup_tc(struct net_device *dev, enum tc_setup_type type,
}
}
+int mtk_eth_fill_receive_path(struct net_device_path_ctx *ctx,
+ struct net_device_path *path)
+{
+ struct mtk_mac *mac = netdev_priv(ctx->dev);
+
+ path->mtk_wdma.wdma_idx = mac->ppe_idx;
+
+ return 0;
+}
+
int mtk_eth_offload_init(struct mtk_eth *eth, int id)
{
if (!eth->ppe[id] || !eth->ppe[id]->foe_table)
--
2.18.0

View File

@@ -1,58 +0,0 @@
From e8a6054c824c5c65abd501bfd7437a3d7c5f2751 Mon Sep 17 00:00:00 2001
From: Bo-Cun Chen <bc-bocun.chen@mediatek.com>
Date: Tue, 28 Nov 2023 13:25:03 +0800
Subject: [PATCH 23/24]
mtk-ppe-dispatch-short-packets-to-high-priority-TXQ-in-PPPQ
---
drivers/net/ethernet/mediatek/mtk_ppe.c | 27 +++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/drivers/net/ethernet/mediatek/mtk_ppe.c b/drivers/net/ethernet/mediatek/mtk_ppe.c
index ae0acd5..547b5a0 100644
--- a/drivers/net/ethernet/mediatek/mtk_ppe.c
+++ b/drivers/net/ethernet/mediatek/mtk_ppe.c
@@ -451,6 +451,31 @@ int mtk_foe_entry_set_qid(struct mtk_foe_entry *entry, int qid)
return 0;
}
+void mtk_foe_entry_adjust_qid(struct mtk_ppe *ppe, struct mtk_flow_entry *entry)
+{
+ struct mtk_foe_mac_info *l2 = mtk_foe_entry_l2(&entry->data);
+ u32 *ib2 = mtk_foe_entry_ib2(&entry->data);
+ u8 qid;
+
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+ if (l2->tport_id != 1)
+ return;
+#else
+ if (!(*ib2 & MTK_FOE_IB2_PSE_QOS))
+ return;
+#endif
+
+ qid = FIELD_GET(MTK_FOE_IB2_QID, *ib2);
+ /* To enhance performance in the unbalanced PHY rate test,
+ * dispatching short packets to the high priority TXQ.
+ */
+ if (ppe->eth->qos_toggle == 2 && qid < 6) {
+ qid += 6;
+ *ib2 &= ~MTK_FOE_IB2_QID;
+ *ib2 |= FIELD_PREP(MTK_FOE_IB2_QID, qid);
+ }
+}
+
int mtk_foe_entry_set_dscp(struct mtk_foe_entry *entry, int dscp)
{
u32 *ib2 = mtk_foe_entry_ib2(entry);
@@ -790,6 +815,9 @@ void __mtk_ppe_check_skb(struct mtk_ppe *ppe, struct sk_buff *skb, u16 hash)
continue;
}
+ if (skb && skb->len < 100)
+ mtk_foe_entry_adjust_qid(ppe, entry);
+
entry->hash = hash;
__mtk_foe_entry_commit(ppe, &entry->data, hash);
found = true;
--
2.18.0

View File

@@ -1,38 +0,0 @@
From b294202119468041b6f4b6651f968c9d2a0adcc2 Mon Sep 17 00:00:00 2001
From: Rex Lu <rex.lu@mediatek.com>
Date: Mon, 22 Jan 2024 13:50:29 +0800
Subject: [PATCH 24/24] dts 88d option type 2 support
Signed-off-by: Rex Lu <rex.lu@mediatek.com>
---
arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts | 1 +
arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts | 1 +
2 files changed, 2 insertions(+)
diff --git a/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
index 8ebcbaf..df15051 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988a-88d-10g-spim-nand.dts
@@ -572,6 +572,7 @@
mt7996@0,0 {
reg = <0x0000 0 0 0 0>;
device_type = "pci";
+ option_type = <2>;
mediatek,mtd-eeprom = <&factory 0x0>;
};
};
diff --git a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
index d4f96c8..c27ffa6 100644
--- a/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
+++ b/arch/arm64/boot/dts/mediatek/mt7988d-dsa-10g-spim-nand.dts
@@ -547,6 +547,7 @@
mt7996@0,0 {
reg = <0x0000 0 0 0 0>;
device_type = "pci";
+ option_type = <2>;
mediatek,mtd-eeprom = <&factory 0x0>;
};
};
--
2.18.0

View File

@@ -1,63 +0,0 @@
Index: linux-5.4.246/drivers/char/tpm/tpm_tis_spi.c
===================================================================
--- linux-5.4.246.orig/drivers/char/tpm/tpm_tis_spi.c
+++ linux-5.4.246/drivers/char/tpm/tpm_tis_spi.c
@@ -199,11 +199,35 @@ static const struct tpm_tis_phy_ops tpm_
.do_calibration = tpm_tis_spi_do_calibration,
};
+int reset_tpm(struct spi_device *dev)
+{
+ int error;
+ struct gpio_desc *reset_gpio;
+ reset_gpio = gpiod_get_optional(&dev->dev, "reset", GPIOD_OUT_LOW);
+ error = PTR_ERR_OR_ZERO(reset_gpio);
+
+ printk("Doing tpm reset!!");
+
+ if(error) {
+ printk("get tpm reset gpio fail!!!!!\n");
+ return error;
+ }
+
+ if(reset_gpio)
+ gpiod_set_consumer_name(reset_gpio, "TPM reset");
+
+ return 0;
+}
+
static int tpm_tis_spi_probe(struct spi_device *dev)
{
struct tpm_tis_spi_phy *phy;
int irq;
+ if(reset_tpm(dev)){
+ printk("!!!tpm reset fail!!\n");
+ }
+
phy = devm_kzalloc(&dev->dev, sizeof(struct tpm_tis_spi_phy),
GFP_KERNEL);
if (!phy)
Index: linux-5.4.246/drivers/spi/spi.c
===================================================================
--- linux-5.4.246.orig/drivers/spi/spi.c
+++ linux-5.4.246/drivers/spi/spi.c
@@ -1124,8 +1124,17 @@ int spi_do_calibration(struct spi_contro
bool hit;
/* Make sure we can start calibration */
+#if 1
+ if(!ctlr->cal_target || !ctlr->cal_rule) {
+ return 0;
+ } else if(!ctlr->append_caldata) {
+ pr_err("%s: calibration is enabled but no controller data.\n", __func__);
+ return -EINVAL;
+ }
+#else
if(!ctlr->cal_target || !ctlr->cal_rule || !ctlr->append_caldata)
return -EINVAL;
+#endif
datalen = ctlr->cal_rule->datalen;
addrlen = ctlr->cal_rule->addrlen;

View File

@@ -0,0 +1,24 @@
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -179,10 +179,21 @@ struct flow_offload {
struct rcu_head rcu_head;
};
+enum flow_offload_tnl {
+ FLOW_OFFLOAD_TNL_GRETAP,
+ FLOW_OFFLOAD_TNL_PPTP,
+ FLOW_OFFLOAD_TNL_L2TP_V2,
+ FLOW_OFFLOAD_TNL_L2TP_V3,
+ FLOW_OFFLOAD_TNL_VXLAN,
+ FLOW_OFFLOAD_NATT,
+ __FLOW_OFFLOAD_MAX,
+};
+
struct flow_offload_hw_path {
struct net_device *dev;
struct net_device *virt_dev;
u32 flags;
+ u32 tnl_type;
u8 eth_src[ETH_ALEN];
u8 eth_dest[ETH_ALEN];

View File

@@ -0,0 +1,410 @@
--- a/drivers/net/ethernet/mediatek/mtk_hnat/Makefile
+++ b/drivers/net/ethernet/mediatek/mtk_hnat/Makefile
@@ -1,7 +1,9 @@
ccflags-y=-Werror
obj-$(CONFIG_NET_MEDIATEK_HNAT) += mtkhnat.o
-mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o hnat_mcast.o
+mtkhnat-objs := hnat.o hnat_nf_hook.o hnat_debugfs.o hnat_mcast.o \
+ external/hnat_entry.o
+mtkhnat-$(CONFIG_MEDIATEK_NETSYS_V3) += external/v3/hnat_ipv4_hnapt.o
ifeq ($(CONFIG_NET_DSA_AN8855), y)
mtkhnat-y += hnat_stag.o
else
--- a/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
+++ b/drivers/net/ethernet/mediatek/mtk_hnat/hnat_debugfs.c
@@ -2919,6 +2919,7 @@ u32 hnat_get_ppe_hash(struct foe_entry *
return hash;
}
+EXPORT_SYMBOL(hnat_get_ppe_hash);
static u32 hnat_char2hex(const char c)
{
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_hnat/external/hnat_entry.c
@@ -0,0 +1,61 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2024 Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+#include <linux/bits.h>
+
+#include "../hnat.h"
+#include "hnat_entry.h"
+
+static inline int ppe_id_get_by_sport(u32 sp)
+{
+ if (CFG_PPE_NUM == 3) {
+ switch (sp) {
+ case NR_GMAC1_PORT:
+ return 0;
+ case NR_GMAC2_PORT:
+ return 1;
+ case NR_GMAC3_PORT:
+ return 2;
+ }
+ }
+
+ return 0;
+}
+
+void hnat_entry_add(struct foe_entry *foe)
+{
+ struct foe_entry *dst_foe;
+ u32 ppe_id;
+ int hash;
+ int i;
+
+ hash = hnat_get_ppe_hash(foe);
+ ppe_id = ppe_id_get_by_sport(foe->ipv4_hnapt.bfib1.sp);
+
+ /* collision policy: at most 4 entries with the same hash value */
+ for (i = 0; i < 4; i++) {
+ dst_foe = hnat_get_foe_entry(ppe_id,
+ ((hash + i) % hnat_priv->foe_etry_num));
+
+ if ((IS_ERR(dst_foe)))
+ return;
+
+ if (dst_foe->ipv4_hnapt.bfib1.state == BIND)
+ continue;
+
+ break;
+ }
+
+ /* We must ensure all info has been updated before set to hw */
+ wmb();
+ memcpy(dst_foe, foe, sizeof(*foe));
+}
+EXPORT_SYMBOL(hnat_entry_add);
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_hnat/external/hnat_entry.h
@@ -0,0 +1,45 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2024 Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+
+#ifndef _MTK_HNAT_EXTERNAL_HNAT_ENTRY_H_
+#define _MTK_HNAT_EXTERNAL_HNAT_ENTRY_H_
+
+#include <linux/debugfs.h>
+
+#include "../hnat.h"
+
+void hnat_entry_add(struct foe_entry *foe);
+
+/* necessary apis to access struct hnapt_ipv4_hnapt from external kernel module */
+int hnat_ipv4_hnapt_init(struct hnat_ipv4_hnapt *entry);
+int hnat_ipv4_hnapt_sp_set(struct hnat_ipv4_hnapt *entry, u32 val);
+int hnat_ipv4_hnapt_qid_set(struct hnat_ipv4_hnapt *entry, u32 val);
+int hnat_ipv4_hnapt_fp_set(struct hnat_ipv4_hnapt *entry, u32 val);
+int hnat_ipv4_hnapt_sip_set(struct hnat_ipv4_hnapt *entry, __be32 val);
+int hnat_ipv4_hnapt_dip_set(struct hnat_ipv4_hnapt *entry, __be32 val);
+int hnat_ipv4_hnapt_dport_set(struct hnat_ipv4_hnapt *entry, u16 val);
+int hnat_ipv4_hnapt_sport_set(struct hnat_ipv4_hnapt *entry, u16 val);
+int hnat_ipv4_hnapt_new_sip_set(struct hnat_ipv4_hnapt *entry, __be32 val);
+int hnat_ipv4_hnapt_new_dip_set(struct hnat_ipv4_hnapt *entry, __be32 val);
+int hnat_ipv4_hnapt_new_dport_set(struct hnat_ipv4_hnapt *entry, u16 val);
+int hnat_ipv4_hnapt_new_sport_set(struct hnat_ipv4_hnapt *entry, u16 val);
+int hnat_ipv4_hnapt_dmac_set(struct hnat_ipv4_hnapt *entry, u8 *mac);
+int hnat_ipv4_hnapt_smac_set(struct hnat_ipv4_hnapt *entry, u8 *mac);
+#if defined(CONFIG_MEDIATEK_NETSYS_V3)
+int hnat_ipv4_hnapt_cdrt_id_set(struct hnat_ipv4_hnapt *entry, u32 val);
+u32 hnat_ipv4_hnapt_tops_entry_get(struct hnat_ipv4_hnapt *entry);
+int hnat_ipv4_hnapt_tops_entry_set(struct hnat_ipv4_hnapt *entry, u32 val);
+u32 hnat_ipv4_hnapt_tport_id_get(struct hnat_ipv4_hnapt *entry);
+int hnat_ipv4_hnapt_tport_id_set(struct hnat_ipv4_hnapt *entry, u32 val);
+#endif /* (CONFIG_MEDIATEK_NETSYS_V3) */
+
+#endif /* _MTK_HNAT_EXTERNAL_HNAT_ENTRY_H_ */
--- /dev/null
+++ b/drivers/net/ethernet/mediatek/mtk_hnat/external/v3/hnat_ipv4_hnapt.c
@@ -0,0 +1,272 @@
+/* This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Copyright (C) 2024 Frank-zj Lin <frank-zj.lin@mediatek.com>
+ */
+#include <linux/bits.h>
+
+#include "../hnat_entry.h"
+
+/* Initialize with default values of a statically bind entry */
+static int hnat_bind_info_blk_init(struct hnat_bind_info_blk* blk)
+{
+ if (!blk)
+ return -EINVAL;
+
+ blk->pkt_type = IPV4_HNAPT;
+ blk->cah = 0x1;
+ blk->ttl = 0x1;
+ blk->state = 0x2; /* bind */
+ blk->sta = 0x1; /* static entry */
+
+ return 0;
+}
+
+/* PSE source port 0~15 */
+static int hnat_bind_info_blk_sp_set(struct hnat_bind_info_blk* blk, u32 val)
+{
+ u32 _val = val & GENMASK(3, 0);
+
+ if (!blk || _val != val)
+ return -EINVAL;
+
+ blk->sp = _val;
+
+ return 0;
+}
+
+/* Initialize with default values of a statically bind entry */
+static int hnat_info_blk2_init(struct hnat_info_blk2* blk)
+{
+ if (!blk)
+ return -EINVAL;
+
+ blk->mibf = 0x1;
+ blk->port_ag = 0xF;
+
+ return 0;
+}
+
+static int hnat_info_blk2_qid_set(struct hnat_info_blk2* blk, u32 val)
+{
+ u32 _val = val & GENMASK(6, 0);
+
+ if (!blk || _val != val)
+ return -EINVAL;
+
+ blk->qid = _val;
+
+ return 0;
+}
+
+/* PSE final port 0~15 */
+static int hnat_info_blk2_fp_set(struct hnat_info_blk2* blk, u32 val)
+{
+ u32 _val = val & GENMASK(3, 0);
+
+ if (!blk || _val != val)
+ return -EINVAL;
+
+ blk->dp = _val;
+
+ return 0;
+}
+
+int hnat_ipv4_hnapt_init(struct hnat_ipv4_hnapt *entry)
+{
+ if (!entry)
+ return -EINVAL;
+
+ hnat_bind_info_blk_init(&entry->bfib1);
+ hnat_info_blk2_init(&entry->iblk2);
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_init);
+
+int hnat_ipv4_hnapt_sp_set(struct hnat_ipv4_hnapt *entry, u32 val)
+{
+ return hnat_bind_info_blk_sp_set(&entry->bfib1, val);
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_sp_set);
+
+int hnat_ipv4_hnapt_qid_set(struct hnat_ipv4_hnapt *entry, u32 val)
+{
+ return hnat_info_blk2_qid_set(&entry->iblk2, val);
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_qid_set);
+
+int hnat_ipv4_hnapt_fp_set(struct hnat_ipv4_hnapt *entry, u32 val)
+{
+ return hnat_info_blk2_fp_set(&entry->iblk2, val);
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_fp_set);
+
+int hnat_ipv4_hnapt_sip_set(struct hnat_ipv4_hnapt *entry, __be32 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->sip = ntohl(val);
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_sip_set);
+
+int hnat_ipv4_hnapt_dip_set(struct hnat_ipv4_hnapt *entry, __be32 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->dip = ntohl(val);
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_dip_set);
+
+int hnat_ipv4_hnapt_dport_set(struct hnat_ipv4_hnapt *entry, u16 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->dport = val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_dport_set);
+
+int hnat_ipv4_hnapt_sport_set(struct hnat_ipv4_hnapt *entry, u16 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->sport = val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_sport_set);
+
+int hnat_ipv4_hnapt_new_sip_set(struct hnat_ipv4_hnapt *entry, __be32 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->new_sip = ntohl(val);
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_new_sip_set);
+
+int hnat_ipv4_hnapt_new_dip_set(struct hnat_ipv4_hnapt *entry, __be32 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->new_dip = ntohl(val);
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_new_dip_set);
+
+int hnat_ipv4_hnapt_new_dport_set(struct hnat_ipv4_hnapt *entry, u16 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->new_dport = val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_new_dport_set);
+
+int hnat_ipv4_hnapt_new_sport_set(struct hnat_ipv4_hnapt *entry, u16 val)
+{
+ if (!entry)
+ return -EINVAL;
+
+ entry->new_sport = val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_new_sport_set);
+
+int hnat_ipv4_hnapt_cdrt_id_set(struct hnat_ipv4_hnapt *entry, u32 val)
+{
+ u32 _val = val & GENMASK(7, 0);
+
+ if (!entry || _val != val)
+ return -EINVAL;
+
+ entry->cdrt_id = _val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_cdrt_id_set);
+
+u32 hnat_ipv4_hnapt_tops_entry_get(struct hnat_ipv4_hnapt *entry)
+{
+ return entry->tops_entry;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_tops_entry_get);
+
+int hnat_ipv4_hnapt_tops_entry_set(struct hnat_ipv4_hnapt *entry, u32 val)
+{
+ u32 _val = val & GENMASK(5, 0);
+
+ if (!entry || _val != val)
+ return -EINVAL;
+
+ entry->tops_entry = _val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_tops_entry_set);
+
+u32 hnat_ipv4_hnapt_tport_id_get(struct hnat_ipv4_hnapt *entry)
+{
+ return entry->tport_id;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_tport_id_get);
+
+int hnat_ipv4_hnapt_tport_id_set(struct hnat_ipv4_hnapt *entry, u32 val)
+{
+ u32 _val = val & GENMASK(3, 0);
+
+ if (!entry || _val != val)
+ return -EINVAL;
+
+ entry->tport_id = _val;
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_tport_id_set);
+
+int hnat_ipv4_hnapt_dmac_set(struct hnat_ipv4_hnapt *entry, u8 *mac)
+{
+ if (!entry || !mac)
+ return -EINVAL;
+
+ entry->dmac_hi = swab32(*((u32 *)mac));
+ entry->dmac_lo = swab16(*((u16 *)&mac[4]));
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_dmac_set);
+
+int hnat_ipv4_hnapt_smac_set(struct hnat_ipv4_hnapt *entry, u8 *mac)
+{
+ if (!entry || !mac)
+ return -EINVAL;
+
+ entry->smac_hi = swab32(*((u32 *)mac));
+ entry->smac_lo = swab16(*((u16 *)&mac[4]));
+
+ return 0;
+}
+EXPORT_SYMBOL(hnat_ipv4_hnapt_smac_set);

View File

@@ -0,0 +1,45 @@
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -39,6 +39,7 @@
#include <net/inet_ecn.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
+#include <net/netfilter/nf_flow_table.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
#include <net/gre.h>
@@ -901,6 +902,24 @@ static int ipgre_close(struct net_device
}
#endif
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int gre_dev_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct ip_tunnel *tunnel = netdev_priv(dev);
+
+ if (path->flags & BIT(DEV_PATH_TNL))
+ return -EEXIST;
+
+ path->flags |= BIT(DEV_PATH_TNL);
+ path->tnl_type = FLOW_OFFLOAD_TNL_GRETAP;
+ path->virt_dev = dev;
+ path->dev = tunnel->dev;
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct net_device_ops ipgre_netdev_ops = {
.ndo_init = ipgre_tunnel_init,
.ndo_uninit = ip_tunnel_uninit,
@@ -1264,6 +1283,9 @@ static const struct net_device_ops gre_t
.ndo_get_stats64 = ip_tunnel_get_stats64,
.ndo_get_iflink = ip_tunnel_get_iflink,
.ndo_fill_metadata_dst = gre_fill_metadata_dst,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = gre_dev_flow_offload_check,
+#endif
};
static int erspan_tunnel_init(struct net_device *dev)

View File

@@ -0,0 +1,65 @@
--- a/drivers/net/ppp/ppp_generic.c
+++ b/drivers/net/ppp/ppp_generic.c
@@ -296,6 +296,9 @@ static void unit_put(struct idr *p, int
static void *unit_find(struct idr *p, int n);
static void ppp_setup(struct net_device *dev);
+struct sock *ppp_netdev_get_sock(struct net_device *dev);
+EXPORT_SYMBOL(ppp_netdev_get_sock);
+
static const struct net_device_ops ppp_netdev_ops;
static struct class *ppp_class;
@@ -1660,6 +1663,40 @@ ppp_send_frame(struct ppp *ppp, struct s
++ppp->dev->stats.tx_errors;
}
+struct sock *ppp_netdev_get_sock(struct net_device *dev)
+{
+ struct list_head *list;
+ struct channel *pch;
+ struct ppp *ppp;
+ struct sock *sk;
+
+ if (!dev)
+ return ERR_PTR(-EINVAL);
+
+ ppp = netdev_priv(dev);
+
+ list = &ppp->channels;
+ if (list_empty(list))
+ /* nowhere to send the packet */
+ return ERR_PTR(-EINVAL);
+
+ if (ppp->flags & SC_MULTILINK)
+ /* not doing multilink: send it down the first channel */
+ return ERR_PTR(-EPERM);
+
+ list = list->next;
+ pch = list_entry(list, struct channel, clist);
+
+ spin_lock(&pch->downl);
+ if (pch->chan)
+ sk = (struct sock *)pch->chan->private;
+ else
+ sk = ERR_PTR(-EINVAL);
+ spin_unlock(&pch->downl);
+
+ return sk;
+}
+
/*
* Try to send the frame in xmit_pending.
* The caller should have the xmit path locked.
--- a/include/linux/ppp_channel.h
+++ b/include/linux/ppp_channel.h
@@ -75,6 +75,9 @@ extern int ppp_unit_number(struct ppp_ch
/* Get the device name associated with a channel, or NULL if none */
extern char *ppp_dev_name(struct ppp_channel *);
+/* Get the socket structure of a given ppp netdev */
+extern struct sock *ppp_netdev_get_sock(struct net_device *dev);
+
/*
* SMP locking notes:
* The channel code must ensure that when it calls ppp_unregister_channel,

View File

@@ -0,0 +1,45 @@
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -23,6 +23,7 @@
#include <net/rtnetlink.h>
#include <net/inet_ecn.h>
#include <net/net_namespace.h>
+#include <net/netfilter/nf_flow_table.h>
#include <net/netns/generic.h>
#include <net/tun_proto.h>
#include <net/vxlan.h>
@@ -2966,6 +2967,24 @@ static int vxlan_fill_metadata_dst(struc
return 0;
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int vxlan_flow_offload_check(struct flow_offload_hw_path *path)
+{
+ struct net_device *dev = path->dev;
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+
+ if (path->flags & BIT(DEV_PATH_TNL))
+ return -EEXIST;
+
+ path->flags |= BIT(DEV_PATH_TNL);
+ path->tnl_type = FLOW_OFFLOAD_TNL_VXLAN;
+ path->virt_dev = dev;
+ path->dev = vxlan->dev;
+
+ return 0;
+}
+#endif /* CONFIG_NF_FLOW_TABLE */
+
static const struct net_device_ops vxlan_netdev_ether_ops = {
.ndo_init = vxlan_init,
.ndo_uninit = vxlan_uninit,
@@ -2982,6 +3001,9 @@ static const struct net_device_ops vxlan
.ndo_fdb_dump = vxlan_fdb_dump,
.ndo_fdb_get = vxlan_fdb_get,
.ndo_fill_metadata_dst = vxlan_fill_metadata_dst,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .ndo_flow_offload_check = vxlan_flow_offload_check,
+#endif
.ndo_change_proto_down = dev_change_proto_down_generic,
};

View File

@@ -0,0 +1,23 @@
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -1068,6 +1068,10 @@ int l2tp_xmit_skb(struct l2tp_session *s
int udp_len;
int ret = NET_XMIT_SUCCESS;
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ skb_reset_inner_headers(skb);
+#endif
+
/* Check that there's enough headroom in the skb to insert IP,
* UDP and L2TP headers. If not enough, expand it to
* make room. Adjust truesize.
--- a/net/l2tp/l2tp_ppp.c
+++ b/net/l2tp/l2tp_ppp.c
@@ -356,6 +356,7 @@ static int l2tp_ppp_flow_offload_check(s
return -EINVAL;
path->flags |= BIT(DEV_PATH_TNL);
+ path->tnl_type = FLOW_OFFLOAD_TNL_L2TP_V2;
return 0;
}

View File

@@ -0,0 +1,100 @@
--- a/drivers/net/ppp/pptp.c
+++ b/drivers/net/ppp/pptp.c
@@ -33,6 +33,7 @@
#include <net/route.h>
#include <net/gre.h>
#include <net/pptp.h>
+#include <net/netfilter/nf_flow_table.h>
#include <linux/uaccess.h>
@@ -40,6 +41,9 @@
#define MAX_CALLID 65535
+int (*mtk_pptp_seq_next)(u16 call_id, u32 *val) = NULL;
+EXPORT_SYMBOL(mtk_pptp_seq_next);
+
static DECLARE_BITMAP(callid_bitmap, MAX_CALLID + 1);
static struct pppox_sock __rcu **callid_sock;
@@ -128,6 +132,26 @@ static void del_chan(struct pppox_sock *
spin_unlock(&chan_lock);
}
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+static int pptp_flow_offload_check(struct ppp_channel *chan,
+ struct flow_offload_hw_path *path)
+{
+ struct sock *sk = (struct sock *)chan->private;
+ struct pppox_sock *po = pppox_sk(sk);
+
+ if (path->flags & BIT(DEV_PATH_TNL))
+ return -EEXIST;
+
+ if (sk_pppox(po)->sk_state & PPPOX_DEAD)
+ return -EINVAL;
+
+ path->flags |= BIT(DEV_PATH_TNL);
+ path->tnl_type = FLOW_OFFLOAD_TNL_PPTP;
+
+ return 0;
+}
+#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
+
static int pptp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
{
struct sock *sk = (struct sock *) chan->private;
@@ -140,6 +164,7 @@ static int pptp_xmit(struct ppp_channel
int islcp;
int len;
unsigned char *data;
+ u32 seq_sent_hw;
__u32 seq_recv;
@@ -204,7 +229,14 @@ static int pptp_xmit(struct ppp_channel
hdr->gre_hd.protocol = GRE_PROTO_PPP;
hdr->call_id = htons(opt->dst_addr.call_id);
- hdr->seq = htonl(++opt->seq_sent);
+ if (mtk_pptp_seq_next && !mtk_pptp_seq_next(opt->dst_addr.call_id,
+ &seq_sent_hw)) {
+ opt->seq_sent = seq_sent_hw;
+ hdr->seq = htonl(opt->seq_sent);
+ } else {
+ hdr->seq = htonl(++opt->seq_sent);
+ }
+
if (opt->ack_sent != seq_recv) {
/* send ack with this message */
hdr->gre_hd.flags |= GRE_ACK;
@@ -598,6 +630,9 @@ static int pptp_ppp_ioctl(struct ppp_cha
static const struct ppp_channel_ops pptp_chan_ops = {
.start_xmit = pptp_xmit,
.ioctl = pptp_ppp_ioctl,
+#if IS_ENABLED(CONFIG_NF_FLOW_TABLE)
+ .flow_offload_check = pptp_flow_offload_check,
+#endif /* IS_ENABLED(CONFIG_NF_FLOW_TABLE) */
};
static struct proto pptp_sk_proto __read_mostly = {
--- a/include/net/pptp.h
+++ b/include/net/pptp.h
@@ -2,6 +2,8 @@
#ifndef _NET_PPTP_H
#define _NET_PPTP_H
+#include <net/gre.h>
+
#define PPP_LCP_ECHOREQ 0x09
#define PPP_LCP_ECHOREP 0x0A
#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP)
@@ -20,5 +22,7 @@ struct pptp_gre_header {
__be32 ack;
} __packed;
+/* symbol exported from linux kernel driver/net/ppp/pptp.c */
+extern int (*mtk_pptp_seq_next)(uint16_t call_id, uint32_t *val);
#endif

Some files were not shown because too many files have changed in this diff Show More