mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 17:42:41 +00:00
kernel: update patches
Signed-off-by: Arif Alam <arif.alam@netexperience.com>
This commit is contained in:
@@ -119,6 +119,7 @@
|
||||
memory@40000000 {
|
||||
- reg = <0 0x40000000 0 0x20000000>;
|
||||
+ reg = <0 0x40000000 0 0x40000000>;
|
||||
device_type = "memory";
|
||||
};
|
||||
|
||||
reg_1p8v: regulator-1p8v {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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 = ¯onix_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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 },
|
||||
{},
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 },
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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/
|
||||
@@ -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)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
@@ -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);
|
||||
@@ -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 },
|
||||
{}
|
||||
};
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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 = {
|
||||
@@ -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 {
|
||||
@@ -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 = {
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
+}
|
||||
+
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
@@ -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
|
||||
|
||||
@@ -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 &&
|
||||
@@ -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)) {
|
||||
@@ -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);
|
||||
@@ -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");
|
||||
@@ -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
|
||||
|
||||
@@ -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 = <ðsys>;
|
||||
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 = <ðsys>;
|
||||
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 = <ðsys>;
|
||||
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
@@ -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
|
||||
|
||||
@@ -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 = <ðsys>;
|
||||
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(ð->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(ð->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(ð->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(ð->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(ð->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(ð->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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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];
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user