mirror of
https://github.com/Ysurac/openmptcprouter.git
synced 2025-03-09 15:40:20 +00:00
Fix kernel 6.10 patches
This commit is contained in:
parent
f023e9c6e5
commit
a9809a6010
47 changed files with 0 additions and 9856 deletions
|
@ -1,97 +0,0 @@
|
|||
From a7ae4ed0a3951c45d4a59ee575951b64ae4a23fb Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Tue, 7 May 2024 12:22:15 +0200
|
||||
Subject: [PATCH] kernel: fix tools build breakage on macos with x86
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
--- a/tools/scripts/Makefile.include
|
||||
+++ b/tools/scripts/Makefile.include
|
||||
@@ -72,8 +72,6 @@ $(call allow-override,CXX,$(CROSS_COMPIL
|
||||
$(call allow-override,STRIP,$(CROSS_COMPILE)strip)
|
||||
endif
|
||||
|
||||
-CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
|
||||
-
|
||||
ifneq ($(LLVM),)
|
||||
HOSTAR ?= $(LLVM_PREFIX)llvm-ar$(LLVM_SUFFIX)
|
||||
HOSTCC ?= $(LLVM_PREFIX)clang$(LLVM_SUFFIX)
|
||||
@@ -84,6 +82,9 @@ HOSTCC ?= gcc
|
||||
HOSTLD ?= ld
|
||||
endif
|
||||
|
||||
+CC_NO_CLANG := $(shell $(CC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
|
||||
+HOSTCC_NO_CLANG := $(shell $(HOSTCC) -dM -E -x c /dev/null | grep -Fq "__clang__"; echo $$?)
|
||||
+
|
||||
# Some tools require Clang, LLC and/or LLVM utils
|
||||
CLANG ?= clang
|
||||
LLC ?= llc
|
||||
@@ -92,8 +93,9 @@ LLVM_OBJCOPY ?= llvm-objcopy
|
||||
LLVM_STRIP ?= llvm-strip
|
||||
|
||||
ifeq ($(CC_NO_CLANG), 1)
|
||||
-EXTRA_WARNINGS += -Wstrict-aliasing=3
|
||||
-
|
||||
+ ifeq ($(HOSTCC_NO_CLANG), 1)
|
||||
+ EXTRA_WARNINGS += -Wstrict-aliasing=3
|
||||
+ endif
|
||||
else ifneq ($(CROSS_COMPILE),)
|
||||
# Allow userspace to override CLANG_CROSS_FLAGS to specify their own
|
||||
# sysroots and flags or to avoid the GCC call in pure Clang builds.
|
||||
--- a/tools/include/linux/types.h
|
||||
+++ b/tools/include/linux/types.h
|
||||
@@ -56,6 +56,7 @@ typedef __s8 s8;
|
||||
#define __user
|
||||
#endif
|
||||
#define __must_check
|
||||
+#undef __cold
|
||||
#define __cold
|
||||
|
||||
typedef __u16 __bitwise __le16;
|
||||
--- a/tools/objtool/include/objtool/objtool.h
|
||||
+++ b/tools/objtool/include/objtool/objtool.h
|
||||
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <objtool/elf.h>
|
||||
|
||||
+#undef __weak
|
||||
#define __weak __attribute__((weak))
|
||||
|
||||
struct pv_state {
|
||||
--- a/tools/include/asm-generic/bitops/fls.h
|
||||
+++ b/tools/include/asm-generic/bitops/fls.h
|
||||
@@ -2,6 +2,8 @@
|
||||
#ifndef _ASM_GENERIC_BITOPS_FLS_H_
|
||||
#define _ASM_GENERIC_BITOPS_FLS_H_
|
||||
|
||||
+#include <string.h>
|
||||
+
|
||||
/**
|
||||
* fls - find last (most-significant) bit set
|
||||
* @x: the word to search
|
||||
@@ -10,6 +12,7 @@
|
||||
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
|
||||
*/
|
||||
|
||||
+#define fls __linux_fls
|
||||
static __always_inline int fls(unsigned int x)
|
||||
{
|
||||
int r = 32;
|
||||
--- a/tools/lib/string.c
|
||||
+++ b/tools/lib/string.c
|
||||
@@ -96,6 +96,7 @@ int strtobool(const char *s, bool *res)
|
||||
* If libc has strlcpy() then that version will override this
|
||||
* implementation:
|
||||
*/
|
||||
+#ifndef __APPLE__
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wignored-attributes"
|
||||
@@ -114,6 +115,7 @@ size_t __weak strlcpy(char *dest, const
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
+#endif
|
||||
|
||||
/**
|
||||
* skip_spaces - Removes leading whitespace from @str.
|
|
@ -1,24 +0,0 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 7 Nov 2022 23:48:24 +0100
|
||||
Subject: [PATCH] mtd: support OpenWrt's MTD_ROOTFS_ROOT_DEV
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This allows setting ROOT_DEV to MTD partition named "rootfs".
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/mtd/mtdcore.c
|
||||
+++ b/drivers/mtd/mtdcore.c
|
||||
@@ -801,7 +801,8 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
|
||||
mutex_unlock(&mtd_table_mutex);
|
||||
|
||||
- if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs")) {
|
||||
+ if (of_property_read_bool(mtd_get_of_node(mtd), "linux,rootfs") ||
|
||||
+ (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && !strcmp(mtd->name, "rootfs") && ROOT_DEV == 0)) {
|
||||
if (IS_BUILTIN(CONFIG_MTD)) {
|
||||
pr_info("mtd: setting mtd%d (%s) as root device\n", mtd->index, mtd->name);
|
||||
ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
|
|
@ -1,131 +0,0 @@
|
|||
From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:24:23 +0200
|
||||
Subject: net: swconfig: adds openwrt switch layer
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 83 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/phy/Makefile | 15 +++++++++
|
||||
include/uapi/linux/Kbuild | 1 +
|
||||
3 files changed, 99 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -66,6 +66,80 @@ config SFP
|
||||
depends on HWMON || HWMON=n
|
||||
select MDIO_I2C
|
||||
|
||||
+comment "Switch configuration API + drivers"
|
||||
+
|
||||
+config SWCONFIG
|
||||
+ tristate "Switch configuration API"
|
||||
+ help
|
||||
+ Switch configuration API using netlink. This allows
|
||||
+ you to configure the VLAN features of certain switches.
|
||||
+
|
||||
+config SWCONFIG_LEDS
|
||||
+ bool "Switch LED trigger support"
|
||||
+ depends on (SWCONFIG && LEDS_TRIGGERS)
|
||||
+
|
||||
+config ADM6996_PHY
|
||||
+ tristate "Driver for ADM6996 switches"
|
||||
+ select SWCONFIG
|
||||
+ help
|
||||
+ Currently supports the ADM6996FC and ADM6996M switches.
|
||||
+ Support for FC is very limited.
|
||||
+
|
||||
+config AR8216_PHY
|
||||
+ tristate "Driver for Atheros AR8216/8327 switches"
|
||||
+ select SWCONFIG
|
||||
+ select ETHERNET_PACKET_MANGLE
|
||||
+
|
||||
+config AR8216_PHY_LEDS
|
||||
+ bool "Atheros AR8216 switch LED support"
|
||||
+ depends on (AR8216_PHY && LEDS_CLASS)
|
||||
+
|
||||
+source "drivers/net/phy/b53/Kconfig"
|
||||
+
|
||||
+config IP17XX_PHY
|
||||
+ tristate "Driver for IC+ IP17xx switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config PSB6970_PHY
|
||||
+ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8306_PHY
|
||||
+ tristate "Driver for Realtek RTL8306S switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8366_SMI
|
||||
+ tristate "Driver for the RTL8366 SMI interface"
|
||||
+ depends on GPIOLIB
|
||||
+ help
|
||||
+ This module implements the SMI interface protocol which is used
|
||||
+ by some RTL8366 ethernet switch devices via the generic GPIO API.
|
||||
+
|
||||
+if RTL8366_SMI
|
||||
+
|
||||
+config RTL8366_SMI_DEBUG_FS
|
||||
+ bool "RTL8366 SMI interface debugfs support"
|
||||
+ depends on DEBUG_FS
|
||||
+ default n
|
||||
+
|
||||
+config RTL8366S_PHY
|
||||
+ tristate "Driver for the Realtek RTL8366S switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8366RB_PHY
|
||||
+ tristate "Driver for the Realtek RTL8366RB switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8367_PHY
|
||||
+ tristate "Driver for the Realtek RTL8367R/M switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8367B_PHY
|
||||
+ tristate "Driver fot the Realtek RTL8367R-VB switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+endif # RTL8366_SMI
|
||||
+
|
||||
comment "MII PHY device drivers"
|
||||
|
||||
config AIR_EN8811H_PHY
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -26,6 +26,21 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_
|
||||
obj-$(CONFIG_PHYLINK) += phylink.o
|
||||
obj-$(CONFIG_PHYLIB) += libphy.o
|
||||
|
||||
+obj-$(CONFIG_SWCONFIG) += swconfig.o
|
||||
+obj-$(CONFIG_ADM6996_PHY) += adm6996.o
|
||||
+obj-$(CONFIG_AR8216_PHY) += ar8xxx.o
|
||||
+ar8xxx-y += ar8216.o
|
||||
+ar8xxx-y += ar8327.o
|
||||
+obj-$(CONFIG_SWCONFIG_B53) += b53/
|
||||
+obj-$(CONFIG_IP17XX_PHY) += ip17xx.o
|
||||
+obj-$(CONFIG_PSB6970_PHY) += psb6970.o
|
||||
+obj-$(CONFIG_RTL8306_PHY) += rtl8306.o
|
||||
+obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o
|
||||
+obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o
|
||||
+obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o
|
||||
+obj-$(CONFIG_RTL8367_PHY) += rtl8367.o
|
||||
+obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o
|
||||
+
|
||||
obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += mii_timestamper.o
|
||||
|
||||
obj-$(CONFIG_SFP) += sfp.o
|
||||
--- a/include/linux/platform_data/b53.h
|
||||
+++ b/include/linux/platform_data/b53.h
|
||||
@@ -29,6 +29,9 @@ struct b53_platform_data {
|
||||
u32 chip_id;
|
||||
u16 enabled_ports;
|
||||
|
||||
+ /* allow to specify an ethX alias */
|
||||
+ const char *alias;
|
||||
+
|
||||
/* only used by MMAP'd driver */
|
||||
unsigned big_endian:1;
|
||||
void __iomem *regs;
|
|
@ -1,167 +0,0 @@
|
|||
From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:25:00 +0200
|
||||
Subject: net: add packet mangeling
|
||||
|
||||
ar8216 switches have a hardware bug, which renders normal 802.1q support
|
||||
unusable. Packet mangling is required to fix up the vlan for incoming
|
||||
packets.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/netdevice.h | 11 +++++++++++
|
||||
include/linux/skbuff.h | 14 ++++----------
|
||||
net/Kconfig | 6 ++++++
|
||||
net/core/dev.c | 20 +++++++++++++++-----
|
||||
net/core/skbuff.c | 17 +++++++++++++++++
|
||||
net/ethernet/eth.c | 6 ++++++
|
||||
6 files changed, 59 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1758,6 +1758,7 @@ enum netdev_priv_flags {
|
||||
IFF_TX_SKB_NO_LINEAR = BIT_ULL(31),
|
||||
IFF_CHANGE_PROTO_DOWN = BIT_ULL(32),
|
||||
IFF_SEE_ALL_HWTSTAMP_REQUESTS = BIT_ULL(33),
|
||||
+ IFF_NO_IP_ALIGN = BIT_ULL(34),
|
||||
};
|
||||
|
||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||
@@ -1791,6 +1792,7 @@ enum netdev_priv_flags {
|
||||
#define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
|
||||
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
|
||||
#define IFF_TX_SKB_NO_LINEAR IFF_TX_SKB_NO_LINEAR
|
||||
+#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN
|
||||
|
||||
/* Specifies the type of the struct net_device::ml_priv pointer */
|
||||
enum netdev_ml_priv_type {
|
||||
@@ -2183,6 +2185,11 @@ struct net_device {
|
||||
const struct tlsdev_ops *tlsdev_ops;
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
|
||||
+ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
|
||||
+#endif
|
||||
+
|
||||
const struct header_ops *header_ops;
|
||||
|
||||
unsigned char operstate;
|
||||
@@ -2256,6 +2263,10 @@ struct net_device {
|
||||
struct mctp_dev __rcu *mctp_ptr;
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ void *phy_ptr; /* PHY device specific data */
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Cache lines mostly used on receive path (including eth_type_trans())
|
||||
*/
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -3095,6 +3095,10 @@ static inline int pskb_trim(struct sk_bu
|
||||
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
|
||||
}
|
||||
|
||||
+extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
+ unsigned int length, gfp_t gfp);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
|
||||
* @skb: buffer to alter
|
||||
@@ -3260,16 +3264,6 @@ static inline struct sk_buff *dev_alloc_
|
||||
}
|
||||
|
||||
|
||||
-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
- unsigned int length, gfp_t gfp)
|
||||
-{
|
||||
- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
|
||||
-
|
||||
- if (NET_IP_ALIGN && skb)
|
||||
- skb_reserve(skb, NET_IP_ALIGN);
|
||||
- return skb;
|
||||
-}
|
||||
-
|
||||
static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
unsigned int length)
|
||||
{
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -26,6 +26,12 @@ menuconfig NET
|
||||
|
||||
if NET
|
||||
|
||||
+config ETHERNET_PACKET_MANGLE
|
||||
+ bool
|
||||
+ help
|
||||
+ This option can be selected by phy drivers that need to mangle
|
||||
+ packets going in or out of an ethernet device.
|
||||
+
|
||||
config WANT_COMPAT_NETLINK_MESSAGES
|
||||
bool
|
||||
help
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -3597,6 +3597,11 @@ static int xmit_one(struct sk_buff *skb,
|
||||
if (dev_nit_active(dev))
|
||||
dev_queue_xmit_nit(skb, dev);
|
||||
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ if (dev->eth_mangle_tx && !(skb = dev->eth_mangle_tx(dev, skb)))
|
||||
+ return NETDEV_TX_OK;
|
||||
+#endif
|
||||
+
|
||||
len = skb->len;
|
||||
trace_net_dev_start_xmit(skb, dev);
|
||||
rc = netdev_start_xmit(skb, dev, txq, more);
|
||||
--- a/net/core/skbuff.c
|
||||
+++ b/net/core/skbuff.c
|
||||
@@ -62,6 +62,7 @@
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/mpls.h>
|
||||
#include <linux/kcov.h>
|
||||
+#include <linux/if.h>
|
||||
|
||||
#include <net/protocol.h>
|
||||
#include <net/dst.h>
|
||||
@@ -844,6 +845,22 @@ skb_fail:
|
||||
}
|
||||
EXPORT_SYMBOL(__napi_alloc_skb);
|
||||
|
||||
+struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
+ unsigned int length, gfp_t gfp)
|
||||
+{
|
||||
+ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
|
||||
+
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
|
||||
+ return skb;
|
||||
+#endif
|
||||
+
|
||||
+ if (NET_IP_ALIGN && skb)
|
||||
+ skb_reserve(skb, NET_IP_ALIGN);
|
||||
+ return skb;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
|
||||
+
|
||||
void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
|
||||
int size, unsigned int truesize)
|
||||
{
|
||||
--- a/net/ethernet/eth.c
|
||||
+++ b/net/ethernet/eth.c
|
||||
@@ -159,6 +159,12 @@ __be16 eth_type_trans(struct sk_buff *sk
|
||||
const struct ethhdr *eth;
|
||||
|
||||
skb->dev = dev;
|
||||
+
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ if (dev->eth_mangle_rx)
|
||||
+ dev->eth_mangle_rx(dev, skb);
|
||||
+#endif
|
||||
+
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
eth = (struct ethhdr *)skb->data;
|
|
@ -1,105 +0,0 @@
|
|||
From 94b90966095f3fa625897e8f53d215882f6e19b3 Mon Sep 17 00:00:00 2001
|
||||
From: David Bauer <mail@david-bauer.net>
|
||||
Date: Sat, 11 Mar 2023 17:00:01 +0100
|
||||
Subject: [PATCH] mxl-gpy: control LED reg from DT
|
||||
|
||||
Add dynamic configuration for the LED control registers on MXL PHYs.
|
||||
|
||||
This patch has been tested with MaxLinear GPY211C. It is unlikely to be
|
||||
accepted upstream, as upstream plans on integrating their own framework
|
||||
for handling these LEDs.
|
||||
|
||||
For the time being, use this hack to configure PHY driven device-LEDs to
|
||||
show the correct state.
|
||||
|
||||
A possible alternative might be to expose the LEDs using the kernel LED
|
||||
framework and bind it to the netdevice. This might also be upstreamable,
|
||||
although it is a considerable extra amount of work.
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
---
|
||||
drivers/net/phy/mxl-gpy.c | 37 ++++++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 36 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/mxl-gpy.c
|
||||
+++ b/drivers/net/phy/mxl-gpy.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/mutex.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/polynomial.h>
|
||||
#include <linux/property.h>
|
||||
@@ -38,6 +39,7 @@
|
||||
#define PHY_MIISTAT 0x18 /* MII state */
|
||||
#define PHY_IMASK 0x19 /* interrupt mask */
|
||||
#define PHY_ISTAT 0x1A /* interrupt status */
|
||||
+#define PHY_LED 0x1B /* LED control */
|
||||
#define PHY_FWV 0x1E /* firmware version */
|
||||
|
||||
#define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
|
||||
@@ -61,10 +63,15 @@
|
||||
PHY_IMASK_ADSC | \
|
||||
PHY_IMASK_ANC)
|
||||
|
||||
+#define PHY_LED_NUM_LEDS 4
|
||||
+
|
||||
#define PHY_FWV_REL_MASK BIT(15)
|
||||
#define PHY_FWV_MAJOR_MASK GENMASK(11, 8)
|
||||
#define PHY_FWV_MINOR_MASK GENMASK(7, 0)
|
||||
|
||||
+/* LED */
|
||||
+#define VSPEC1_LED(x) (0x1 + x)
|
||||
+
|
||||
#define PHY_PMA_MGBT_POLARITY 0x82
|
||||
#define PHY_MDI_MDI_X_MASK GENMASK(1, 0)
|
||||
#define PHY_MDI_MDI_X_NORMAL 0x3
|
||||
@@ -260,6 +267,35 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int gpy_led_write(struct phy_device *phydev)
|
||||
+{
|
||||
+ struct device_node *node = phydev->mdio.dev.of_node;
|
||||
+ u32 led_regs[PHY_LED_NUM_LEDS];
|
||||
+ int i, ret;
|
||||
+ u16 val = 0xff00;
|
||||
+
|
||||
+ if (!IS_ENABLED(CONFIG_OF_MDIO))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (of_property_read_u32_array(node, "mxl,led-config", led_regs, PHY_LED_NUM_LEDS))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (of_property_read_bool(node, "mxl,led-drive-vdd"))
|
||||
+ val &= 0x0fff;
|
||||
+
|
||||
+ /* Enable LED function handling on all ports*/
|
||||
+ phy_write(phydev, PHY_LED, val);
|
||||
+
|
||||
+ /* Write LED register values */
|
||||
+ for (i = 0; i < PHY_LED_NUM_LEDS; i++) {
|
||||
+ ret = phy_write_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_LED(i), (u16)led_regs[i]);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int gpy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
@@ -271,7 +307,10 @@ static int gpy_config_init(struct phy_de
|
||||
|
||||
/* Clear all pending interrupts */
|
||||
ret = phy_read(phydev, PHY_ISTAT);
|
||||
- return ret < 0 ? ret : 0;
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ return gpy_led_write(phydev);
|
||||
}
|
||||
|
||||
static int gpy_probe(struct phy_device *phydev)
|
|
@ -1,63 +0,0 @@
|
|||
From 7cc39a6bedbd85f3ff7e16845f310e4ce8d9833f Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 6 Sep 2022 00:31:19 +0100
|
||||
Subject: [PATCH] net: sfp: add quirk for ATS SFP-GE-T 1000Base-TX module
|
||||
To: netdev@vger.kernel.org,
|
||||
linux-kernel@vger.kernel.org,
|
||||
Russell King <linux@armlinux.org.uk>,
|
||||
Andrew Lunn <andrew@lunn.ch>,
|
||||
Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Cc: David S. Miller <davem@davemloft.net>,
|
||||
Eric Dumazet <edumazet@google.com>,
|
||||
Jakub Kicinski <kuba@kernel.org>,
|
||||
Paolo Abeni <pabeni@redhat.com>,
|
||||
Josef Schlehofer <pepe.schlehofer@gmail.com>
|
||||
|
||||
This copper module comes with broken TX_FAULT indicator which must be
|
||||
ignored for it to work. Implement ignoring TX_FAULT state bit also
|
||||
during reset/insertion and mute the warning telling the user that the
|
||||
module indicates TX_FAULT.
|
||||
|
||||
Co-authored-by: Josef Schlehofer <pepe.schlehofer@gmail.com>
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 14 +++++++++++---
|
||||
1 file changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -471,6 +471,9 @@ static const struct sfp_quirk sfp_quirks
|
||||
// FS 2.5G Base-T
|
||||
SFP_QUIRK_M("FS", "SFP-2.5G-T", sfp_quirk_oem_2_5g),
|
||||
|
||||
+ // OEM SFP-GE-T is 1000Base-T module
|
||||
+ SFP_QUIRK_F("OEM", "SFP-GE-T", sfp_fixup_ignore_tx_fault),
|
||||
+
|
||||
// Lantech 8330-262D-E can operate at 2500base-X, but incorrectly report
|
||||
// 2500MBd NRZ in their EEPROM
|
||||
SFP_QUIRK_M("Lantech", "8330-262D-E", sfp_quirk_2500basex),
|
||||
@@ -2587,7 +2590,8 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
* or t_start_up, so assume there is a fault.
|
||||
*/
|
||||
sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
|
||||
- sfp->sm_fault_retries == N_FAULT_INIT);
|
||||
+ !sfp->tx_fault_ignore &&
|
||||
+ (sfp->sm_fault_retries == N_FAULT_INIT));
|
||||
} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
|
||||
init_done:
|
||||
/* Create mdiobus and start trying for PHY */
|
||||
@@ -2841,10 +2845,12 @@ static void sfp_check_state(struct sfp *
|
||||
mutex_lock(&sfp->st_mutex);
|
||||
state = sfp_get_state(sfp);
|
||||
changed = state ^ sfp->state;
|
||||
- if (sfp->tx_fault_ignore)
|
||||
+ if (sfp->tx_fault_ignore) {
|
||||
changed &= SFP_F_PRESENT | SFP_F_LOS;
|
||||
- else
|
||||
+ state &= ~SFP_F_TX_FAULT;
|
||||
+ } else {
|
||||
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
|
||||
+ }
|
||||
|
||||
for (i = 0; i < GPIO_MAX; i++)
|
||||
if (changed & BIT(i))
|
|
@ -1,173 +0,0 @@
|
|||
From cc809a441d8f2924f785eb863dfa6aef47a25b0b Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <blogic@openwrt.org>
|
||||
Date: Tue, 12 Aug 2014 20:49:27 +0200
|
||||
Subject: [PATCH 30/36] GPIO: add named gpio exports
|
||||
|
||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||
--- a/drivers/gpio/gpiolib-of.c
|
||||
+++ b/drivers/gpio/gpiolib-of.c
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/gpio/machine.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/platform_device.h>
|
||||
|
||||
#include "gpiolib.h"
|
||||
#include "gpiolib-of.h"
|
||||
@@ -1111,3 +1113,74 @@ void of_gpiochip_remove(struct gpio_chip
|
||||
{
|
||||
of_node_put(dev_of_node(&chip->gpiodev->dev));
|
||||
}
|
||||
+
|
||||
+#ifdef CONFIG_GPIO_SYSFS
|
||||
+
|
||||
+static struct of_device_id gpio_export_ids[] = {
|
||||
+ { .compatible = "gpio-export" },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+
|
||||
+static int of_gpio_export_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *np = pdev->dev.of_node;
|
||||
+ struct device_node *cnp;
|
||||
+ u32 val;
|
||||
+ int nb = 0;
|
||||
+
|
||||
+ for_each_child_of_node(np, cnp) {
|
||||
+ const char *name = NULL;
|
||||
+ int gpio;
|
||||
+ bool dmc;
|
||||
+ int max_gpio = 1;
|
||||
+ int i;
|
||||
+
|
||||
+ of_property_read_string(cnp, "gpio-export,name", &name);
|
||||
+
|
||||
+ if (!name)
|
||||
+ max_gpio = of_gpio_named_count(cnp, "gpios");
|
||||
+
|
||||
+ for (i = 0; i < max_gpio; i++) {
|
||||
+ struct gpio_desc *desc;
|
||||
+ unsigned flags = 0;
|
||||
+ enum of_gpio_flags of_flags;
|
||||
+
|
||||
+ desc = of_get_named_gpiod_flags(cnp, "gpios", i, &of_flags);
|
||||
+ if (IS_ERR(desc))
|
||||
+ return PTR_ERR(desc);
|
||||
+ gpio = desc_to_gpio(desc);
|
||||
+
|
||||
+ if (of_flags & OF_GPIO_ACTIVE_LOW)
|
||||
+ flags |= GPIOF_ACTIVE_LOW;
|
||||
+
|
||||
+ if (!of_property_read_u32(cnp, "gpio-export,output", &val))
|
||||
+ flags |= val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
|
||||
+ else
|
||||
+ flags |= GPIOF_IN;
|
||||
+
|
||||
+ if (devm_gpio_request_one(&pdev->dev, gpio, flags, name ? name : of_node_full_name(np)))
|
||||
+ continue;
|
||||
+
|
||||
+ dmc = of_property_read_bool(cnp, "gpio-export,direction_may_change");
|
||||
+ gpio_export_with_name(gpio_to_desc(gpio), dmc, name);
|
||||
+ nb++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ dev_info(&pdev->dev, "%d gpio(s) exported\n", nb);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct platform_driver gpio_export_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "gpio-export",
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .of_match_table = of_match_ptr(gpio_export_ids),
|
||||
+ },
|
||||
+ .probe = of_gpio_export_probe,
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(gpio_export_driver);
|
||||
+
|
||||
+#endif
|
||||
--- a/include/linux/gpio/consumer.h
|
||||
+++ b/include/linux/gpio/consumer.h
|
||||
@@ -644,7 +644,10 @@ static inline struct gpio_desc *acpi_get
|
||||
|
||||
#if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS)
|
||||
|
||||
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name);
|
||||
int gpiod_export(struct gpio_desc *desc, bool direction_may_change);
|
||||
+int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change,
|
||||
+ const char *name);
|
||||
int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc);
|
||||
void gpiod_unexport(struct gpio_desc *desc);
|
||||
@@ -653,11 +656,25 @@ void gpiod_unexport(struct gpio_desc *de
|
||||
|
||||
#include <asm/errno.h>
|
||||
|
||||
+static inline int __gpiod_export(struct gpio_desc *desc,
|
||||
+ bool direction_may_change,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
+
|
||||
static inline int gpiod_export(struct gpio_desc *desc,
|
||||
bool direction_may_change)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
+
|
||||
+static inline int gpio_export_with_name(struct gpio_desc *desc,
|
||||
+ bool direction_may_change,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ return -ENOSYS;
|
||||
+}
|
||||
|
||||
static inline int gpiod_export_link(struct device *dev, const char *name,
|
||||
struct gpio_desc *desc)
|
||||
--- a/drivers/gpio/gpiolib-sysfs.c
|
||||
+++ b/drivers/gpio/gpiolib-sysfs.c
|
||||
@@ -557,7 +557,7 @@ static struct class gpio_class = {
|
||||
*
|
||||
* Returns zero on success, else an error.
|
||||
*/
|
||||
-int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
+int __gpiod_export(struct gpio_desc *desc, bool direction_may_change, const char *name)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
struct gpio_device *gdev;
|
||||
@@ -619,6 +619,8 @@ int gpiod_export(struct gpio_desc *desc,
|
||||
offset = gpio_chip_hwgpio(desc);
|
||||
if (chip->names && chip->names[offset])
|
||||
ioname = chip->names[offset];
|
||||
+ if (name)
|
||||
+ ioname = name;
|
||||
|
||||
dev = device_create_with_groups(&gpio_class, &gdev->dev,
|
||||
MKDEV(0, 0), data, gpio_groups,
|
||||
@@ -640,8 +642,21 @@ err_unlock:
|
||||
gpiod_dbg(desc, "%s: status %d\n", __func__, status);
|
||||
return status;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(__gpiod_export);
|
||||
+
|
||||
+int gpiod_export(struct gpio_desc *desc, bool direction_may_change)
|
||||
+{
|
||||
+ return __gpiod_export(desc, direction_may_change, NULL);
|
||||
+}
|
||||
EXPORT_SYMBOL_GPL(gpiod_export);
|
||||
|
||||
+int gpio_export_with_name(struct gpio_desc *desc, bool direction_may_change,
|
||||
+ const char *name)
|
||||
+{
|
||||
+ return __gpiod_export(desc, direction_may_change, name);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(gpio_export_with_name);
|
||||
+
|
||||
static int match_export(struct device *dev, const void *desc)
|
||||
{
|
||||
struct gpiod_data *data = dev_get_drvdata(dev);
|
|
@ -1,187 +0,0 @@
|
|||
From e4d708702e6c98f2111e33201a264d6788564cb2 Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Fri, 12 May 2023 11:08:43 +0200
|
||||
Subject: [PATCH] ssb_sprom: add generic kernel support for Broadcom Fallback SPROMs
|
||||
|
||||
---
|
||||
drivers/bcma/Kconfig | 4 ++++
|
||||
drivers/bcma/Makefile | 1 +
|
||||
drivers/bcma/bcma_private.h | 4 ++++
|
||||
drivers/bcma/main.c | 8 ++++++++
|
||||
drivers/bcma/sprom.c | 23 ++++++++++++++---------
|
||||
drivers/ssb/Kconfig | 5 +++++
|
||||
drivers/ssb/Makefile | 1 +
|
||||
drivers/ssb/main.c | 8 ++++++++
|
||||
drivers/ssb/sprom.c | 12 +++++++++++-
|
||||
drivers/ssb/ssb_private.h | 4 ++++
|
||||
10 files changed, 60 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -18,6 +18,10 @@ config BCMA_BLOCKIO
|
||||
bool
|
||||
default y
|
||||
|
||||
+config BCMA_FALLBACK_SPROM
|
||||
+ bool
|
||||
+ default y
|
||||
+
|
||||
config BCMA_HOST_PCI_POSSIBLE
|
||||
bool
|
||||
depends on PCI = y
|
||||
--- a/drivers/bcma/Makefile
|
||||
+++ b/drivers/bcma/Makefile
|
||||
@@ -11,6 +11,7 @@ bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE)
|
||||
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_GPIO) += driver_gpio.o
|
||||
+bcma-$(CONFIG_BCMA_FALLBACK_SPROM) += fallback-sprom.o
|
||||
bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
|
||||
bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o
|
||||
obj-$(CONFIG_BCMA) += bcma.o
|
||||
--- a/drivers/bcma/bcma_private.h
|
||||
+++ b/drivers/bcma/bcma_private.h
|
||||
@@ -38,6 +38,10 @@ int bcma_bus_resume(struct bcma_bus *bus
|
||||
void bcma_detect_chip(struct bcma_bus *bus);
|
||||
int bcma_bus_scan(struct bcma_bus *bus);
|
||||
|
||||
+/* fallback-sprom.c */
|
||||
+int __init bcma_fbs_register(void);
|
||||
+int bcma_get_fallback_sprom(struct bcma_bus *dev, struct ssb_sprom *out);
|
||||
+
|
||||
/* sprom.c */
|
||||
int bcma_sprom_get(struct bcma_bus *bus);
|
||||
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -671,6 +671,14 @@ static int __init bcma_modinit(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
+#ifdef CONFIG_BCMA_FALLBACK_SPROM
|
||||
+ err = bcma_fbs_register();
|
||||
+ if (err) {
|
||||
+ pr_err("Fallback SPROM initialization failed\n");
|
||||
+ err = 0;
|
||||
+ }
|
||||
+#endif /* CONFIG_BCMA_FALLBACK_SPROM */
|
||||
+
|
||||
err = bcma_init_bus_register();
|
||||
if (err)
|
||||
return err;
|
||||
--- a/drivers/bcma/sprom.c
|
||||
+++ b/drivers/bcma/sprom.c
|
||||
@@ -51,21 +51,26 @@ static int bcma_fill_sprom_with_fallback
|
||||
{
|
||||
int err;
|
||||
|
||||
- if (!get_fallback_sprom) {
|
||||
+ if (get_fallback_sprom)
|
||||
+ err = get_fallback_sprom(bus, out);
|
||||
+
|
||||
+#ifdef CONFIG_BCMA_FALLBACK_SPROM
|
||||
+ if (!get_fallback_sprom || err)
|
||||
+ err = bcma_get_fallback_sprom(bus, out);
|
||||
+#else
|
||||
+ if (!get_fallback_sprom)
|
||||
err = -ENOENT;
|
||||
- goto fail;
|
||||
- }
|
||||
+#endif /* CONFIG_BCMA_FALLBACK_SPROM */
|
||||
|
||||
- err = get_fallback_sprom(bus, out);
|
||||
- if (err)
|
||||
- goto fail;
|
||||
+ if (err) {
|
||||
+ bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
|
||||
+ return err;
|
||||
+ }
|
||||
|
||||
bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
|
||||
bus->sprom.revision);
|
||||
+
|
||||
return 0;
|
||||
-fail:
|
||||
- bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
|
||||
- return err;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
--- a/drivers/ssb/Kconfig
|
||||
+++ b/drivers/ssb/Kconfig
|
||||
@@ -25,6 +25,11 @@ if SSB
|
||||
config SSB_SPROM
|
||||
bool
|
||||
|
||||
+config SSB_FALLBACK_SPROM
|
||||
+ bool
|
||||
+ depends on SSB_PCIHOST
|
||||
+ default y
|
||||
+
|
||||
# Support for Block-I/O. SELECT this from the driver that needs it.
|
||||
config SSB_BLOCKIO
|
||||
bool
|
||||
--- a/drivers/ssb/Makefile
|
||||
+++ b/drivers/ssb/Makefile
|
||||
@@ -2,6 +2,7 @@
|
||||
# core
|
||||
ssb-y += main.o scan.o
|
||||
ssb-$(CONFIG_SSB_EMBEDDED) += embedded.o
|
||||
+ssb-$(CONFIG_SSB_FALLBACK_SPROM) += fallback-sprom.o
|
||||
ssb-$(CONFIG_SSB_SPROM) += sprom.o
|
||||
|
||||
# host support
|
||||
--- a/drivers/ssb/main.c
|
||||
+++ b/drivers/ssb/main.c
|
||||
@@ -1287,6 +1287,14 @@ static int __init ssb_modinit(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
+#ifdef CONFIG_SSB_FALLBACK_SPROM
|
||||
+ err = ssb_fbs_register();
|
||||
+ if (err) {
|
||||
+ pr_err("Fallback SPROM initialization failed\n");
|
||||
+ err = 0;
|
||||
+ }
|
||||
+#endif /* CONFIG_SSB_FALLBACK_SPROM */
|
||||
+
|
||||
/* See the comment at the ssb_is_early_boot definition */
|
||||
ssb_is_early_boot = 0;
|
||||
err = bus_register(&ssb_bustype);
|
||||
--- a/drivers/ssb/sprom.c
|
||||
+++ b/drivers/ssb/sprom.c
|
||||
@@ -180,10 +180,20 @@ int ssb_arch_register_fallback_sprom(int
|
||||
|
||||
int ssb_fill_sprom_with_fallback(struct ssb_bus *bus, struct ssb_sprom *out)
|
||||
{
|
||||
+ int err;
|
||||
+
|
||||
+ if (get_fallback_sprom)
|
||||
+ err = get_fallback_sprom(bus, out);
|
||||
+
|
||||
+#ifdef CONFIG_SSB_FALLBACK_SPROM
|
||||
+ if (!get_fallback_sprom || err)
|
||||
+ err = ssb_get_fallback_sprom(bus, out);
|
||||
+#else
|
||||
if (!get_fallback_sprom)
|
||||
return -ENOENT;
|
||||
+#endif /* CONFIG_SSB_FALLBACK_SPROM */
|
||||
|
||||
- return get_fallback_sprom(bus, out);
|
||||
+ return err;
|
||||
}
|
||||
|
||||
/* https://bcm-v4.sipsolutions.net/802.11/IsSpromAvailable */
|
||||
--- a/drivers/ssb/ssb_private.h
|
||||
+++ b/drivers/ssb/ssb_private.h
|
||||
@@ -143,6 +143,10 @@ extern int ssb_bus_scan(struct ssb_bus *
|
||||
extern void ssb_iounmap(struct ssb_bus *ssb);
|
||||
|
||||
|
||||
+/* fallback-sprom.c */
|
||||
+int __init ssb_fbs_register(void);
|
||||
+int ssb_get_fallback_sprom(struct ssb_bus *dev, struct ssb_sprom *out);
|
||||
+
|
||||
/* sprom.c */
|
||||
extern
|
||||
ssize_t ssb_attr_sprom_show(struct ssb_bus *bus, char *buf,
|
|
@ -1,419 +0,0 @@
|
|||
From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 8 Jul 2017 08:20:09 +0200
|
||||
Subject: debloat: procfs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
fs/locks.c | 2 ++
|
||||
fs/proc/Kconfig | 5 +++++
|
||||
fs/proc/consoles.c | 3 +++
|
||||
fs/proc/proc_tty.c | 11 ++++++++++-
|
||||
include/net/snmp.h | 18 +++++++++++++++++-
|
||||
ipc/msg.c | 3 +++
|
||||
ipc/sem.c | 2 ++
|
||||
ipc/shm.c | 2 ++
|
||||
ipc/util.c | 3 +++
|
||||
kernel/exec_domain.c | 2 ++
|
||||
kernel/irq/proc.c | 9 +++++++++
|
||||
kernel/time/timer_list.c | 2 ++
|
||||
mm/vmalloc.c | 2 ++
|
||||
mm/vmstat.c | 8 +++++---
|
||||
net/8021q/vlanproc.c | 6 ++++++
|
||||
net/core/net-procfs.c | 18 ++++++++++++------
|
||||
net/core/sock.c | 2 ++
|
||||
net/ipv4/fib_trie.c | 18 ++++++++++++------
|
||||
net/ipv4/proc.c | 3 +++
|
||||
net/ipv4/route.c | 3 +++
|
||||
20 files changed, 105 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/fs/locks.c
|
||||
+++ b/fs/locks.c
|
||||
@@ -2897,6 +2897,8 @@ static const struct seq_operations locks
|
||||
|
||||
static int __init proc_locks_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
proc_create_seq_private("locks", 0, NULL, &locks_seq_operations,
|
||||
sizeof(struct locks_iterator), NULL);
|
||||
return 0;
|
||||
--- a/fs/proc/Kconfig
|
||||
+++ b/fs/proc/Kconfig
|
||||
@@ -101,6 +101,11 @@ config PROC_CHILDREN
|
||||
Say Y if you are running any user-space software which takes benefit from
|
||||
this interface. For example, rkt is such a piece of software.
|
||||
|
||||
+config PROC_STRIPPED
|
||||
+ default n
|
||||
+ depends on EXPERT
|
||||
+ bool "Strip non-essential /proc functionality to reduce code size"
|
||||
+
|
||||
config PROC_PID_ARCH_STATUS
|
||||
def_bool n
|
||||
depends on PROC_FS
|
||||
--- a/fs/proc/consoles.c
|
||||
+++ b/fs/proc/consoles.c
|
||||
@@ -107,6 +107,9 @@ static const struct seq_operations conso
|
||||
|
||||
static int __init proc_consoles_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
proc_create_seq("consoles", 0, NULL, &consoles_op);
|
||||
return 0;
|
||||
}
|
||||
--- a/fs/proc/proc_tty.c
|
||||
+++ b/fs/proc/proc_tty.c
|
||||
@@ -131,7 +131,10 @@ static const struct seq_operations tty_d
|
||||
void proc_tty_register_driver(struct tty_driver *driver)
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
-
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
if (!driver->driver_name || driver->proc_entry ||
|
||||
!driver->ops->proc_show)
|
||||
return;
|
||||
@@ -148,6 +151,9 @@ void proc_tty_unregister_driver(struct t
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
ent = driver->proc_entry;
|
||||
if (!ent)
|
||||
return;
|
||||
@@ -162,6 +168,9 @@ void proc_tty_unregister_driver(struct t
|
||||
*/
|
||||
void __init proc_tty_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
if (!proc_mkdir("tty", NULL))
|
||||
return;
|
||||
proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */
|
||||
--- a/include/net/snmp.h
|
||||
+++ b/include/net/snmp.h
|
||||
@@ -124,6 +124,21 @@ struct linux_tls_mib {
|
||||
#define DECLARE_SNMP_STAT(type, name) \
|
||||
extern __typeof__(type) __percpu *name
|
||||
|
||||
+#ifdef CONFIG_PROC_STRIPPED
|
||||
+#define __SNMP_STATS_DUMMY(mib) \
|
||||
+ do { (void) mib->mibs[0]; } while(0)
|
||||
+
|
||||
+#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+
|
||||
+#else
|
||||
+
|
||||
#define __SNMP_INC_STATS(mib, field) \
|
||||
__this_cpu_inc(mib->mibs[field])
|
||||
|
||||
@@ -154,8 +169,9 @@ struct linux_tls_mib {
|
||||
__this_cpu_add(ptr[basefield##OCTETS], addend); \
|
||||
} while (0)
|
||||
|
||||
+#endif
|
||||
|
||||
-#if BITS_PER_LONG==32
|
||||
+#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
|
||||
|
||||
#define __SNMP_ADD_STATS64(mib, field, addend) \
|
||||
do { \
|
||||
--- a/ipc/msg.c
|
||||
+++ b/ipc/msg.c
|
||||
@@ -1370,6 +1370,9 @@ void __init msg_init(void)
|
||||
{
|
||||
msg_init_ns(&init_ipc_ns);
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
ipc_init_proc_interface("sysvipc/msg",
|
||||
" key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
|
||||
IPC_MSG_IDS, sysvipc_msg_proc_show);
|
||||
--- a/ipc/sem.c
|
||||
+++ b/ipc/sem.c
|
||||
@@ -268,6 +268,8 @@ void sem_exit_ns(struct ipc_namespace *n
|
||||
void __init sem_init(void)
|
||||
{
|
||||
sem_init_ns(&init_ipc_ns);
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
ipc_init_proc_interface("sysvipc/sem",
|
||||
" key semid perms nsems uid gid cuid cgid otime ctime\n",
|
||||
IPC_SEM_IDS, sysvipc_sem_proc_show);
|
||||
--- a/ipc/shm.c
|
||||
+++ b/ipc/shm.c
|
||||
@@ -154,6 +154,8 @@ pure_initcall(ipc_ns_init);
|
||||
|
||||
void __init shm_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
ipc_init_proc_interface("sysvipc/shm",
|
||||
#if BITS_PER_LONG <= 32
|
||||
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
|
||||
--- a/ipc/util.c
|
||||
+++ b/ipc/util.c
|
||||
@@ -141,6 +141,9 @@ void __init ipc_init_proc_interface(cons
|
||||
struct proc_dir_entry *pde;
|
||||
struct ipc_proc_iface *iface;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
iface = kmalloc(sizeof(*iface), GFP_KERNEL);
|
||||
if (!iface)
|
||||
return;
|
||||
--- a/kernel/exec_domain.c
|
||||
+++ b/kernel/exec_domain.c
|
||||
@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct
|
||||
|
||||
static int __init proc_execdomains_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
proc_create_single("execdomains", 0, NULL, execdomains_proc_show);
|
||||
return 0;
|
||||
}
|
||||
--- a/kernel/irq/proc.c
|
||||
+++ b/kernel/irq/proc.c
|
||||
@@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq,
|
||||
void __maybe_unused *irqp = (void *)(unsigned long) irq;
|
||||
char name [MAX_NAMELEN];
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
|
||||
+ return;
|
||||
+
|
||||
if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
|
||||
return;
|
||||
|
||||
@@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir
|
||||
{
|
||||
char name [MAX_NAMELEN];
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
|
||||
+ return;
|
||||
+
|
||||
if (!root_irq_dir || !desc->dir)
|
||||
return;
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -432,6 +438,9 @@ void init_irq_proc(void)
|
||||
unsigned int irq;
|
||||
struct irq_desc *desc;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
|
||||
+ return;
|
||||
+
|
||||
/* create /proc/irq */
|
||||
root_irq_dir = proc_mkdir("irq", NULL);
|
||||
if (!root_irq_dir)
|
||||
--- a/kernel/time/timer_list.c
|
||||
+++ b/kernel/time/timer_list.c
|
||||
@@ -350,6 +350,8 @@ static int __init init_timer_list_procfs
|
||||
{
|
||||
struct proc_dir_entry *pe;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops,
|
||||
sizeof(struct timer_list_iter), NULL);
|
||||
if (!pe)
|
||||
--- a/mm/vmalloc.c
|
||||
+++ b/mm/vmalloc.c
|
||||
@@ -4439,6 +4439,8 @@ static const struct seq_operations vmall
|
||||
|
||||
static int __init proc_vmalloc_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
if (IS_ENABLED(CONFIG_NUMA))
|
||||
proc_create_seq_private("vmallocinfo", 0400, NULL,
|
||||
&vmalloc_op,
|
||||
--- a/mm/vmstat.c
|
||||
+++ b/mm/vmstat.c
|
||||
@@ -2135,10 +2135,12 @@ void __init init_mm_internals(void)
|
||||
start_shepherd_timer();
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
- proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
|
||||
- proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
|
||||
+ proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
|
||||
+ proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
|
||||
+ proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
|
||||
+ }
|
||||
proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
|
||||
- proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
|
||||
#endif
|
||||
}
|
||||
|
||||
--- a/net/8021q/vlanproc.c
|
||||
+++ b/net/8021q/vlanproc.c
|
||||
@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net)
|
||||
{
|
||||
struct vlan_net *vn = net_generic(net, vlan_net_id);
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
if (vn->proc_vlan_conf)
|
||||
remove_proc_entry(name_conf, vn->proc_vlan_dir);
|
||||
|
||||
@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net
|
||||
{
|
||||
struct vlan_net *vn = net_generic(net, vlan_net_id);
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
|
||||
if (!vn->proc_vlan_dir)
|
||||
goto err;
|
||||
--- a/net/core/net-procfs.c
|
||||
+++ b/net/core/net-procfs.c
|
||||
@@ -327,10 +327,12 @@ static int __net_init dev_proc_net_init(
|
||||
if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops,
|
||||
sizeof(struct seq_net_private)))
|
||||
goto out;
|
||||
- if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_seq("softnet_stat", 0444, net->proc_net,
|
||||
&softnet_seq_ops))
|
||||
goto out_dev;
|
||||
- if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
|
||||
sizeof(struct seq_net_private)))
|
||||
goto out_softnet;
|
||||
|
||||
@@ -340,9 +342,11 @@ static int __net_init dev_proc_net_init(
|
||||
out:
|
||||
return rc;
|
||||
out_ptype:
|
||||
- remove_proc_entry("ptype", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("ptype", net->proc_net);
|
||||
out_softnet:
|
||||
- remove_proc_entry("softnet_stat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("softnet_stat", net->proc_net);
|
||||
out_dev:
|
||||
remove_proc_entry("dev", net->proc_net);
|
||||
goto out;
|
||||
@@ -352,8 +356,10 @@ static void __net_exit dev_proc_net_exit
|
||||
{
|
||||
wext_proc_exit(net);
|
||||
|
||||
- remove_proc_entry("ptype", net->proc_net);
|
||||
- remove_proc_entry("softnet_stat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
|
||||
+ remove_proc_entry("ptype", net->proc_net);
|
||||
+ remove_proc_entry("softnet_stat", net->proc_net);
|
||||
+ }
|
||||
remove_proc_entry("dev", net->proc_net);
|
||||
}
|
||||
|
||||
--- a/net/core/sock.c
|
||||
+++ b/net/core/sock.c
|
||||
@@ -4145,6 +4145,8 @@ static __net_initdata struct pernet_oper
|
||||
|
||||
static int __init proto_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
return register_pernet_subsys(&proto_net_ops);
|
||||
}
|
||||
|
||||
--- a/net/ipv4/fib_trie.c
|
||||
+++ b/net/ipv4/fib_trie.c
|
||||
@@ -3036,11 +3036,13 @@ static const struct seq_operations fib_r
|
||||
|
||||
int __net_init fib_proc_init(struct net *net)
|
||||
{
|
||||
- if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
|
||||
sizeof(struct fib_trie_iter)))
|
||||
goto out1;
|
||||
|
||||
- if (!proc_create_net_single("fib_triestat", 0444, net->proc_net,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_net_single("fib_triestat", 0444, net->proc_net,
|
||||
fib_triestat_seq_show, NULL))
|
||||
goto out2;
|
||||
|
||||
@@ -3051,17 +3053,21 @@ int __net_init fib_proc_init(struct net
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
- remove_proc_entry("fib_triestat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("fib_triestat", net->proc_net);
|
||||
out2:
|
||||
- remove_proc_entry("fib_trie", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("fib_trie", net->proc_net);
|
||||
out1:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void __net_exit fib_proc_exit(struct net *net)
|
||||
{
|
||||
- remove_proc_entry("fib_trie", net->proc_net);
|
||||
- remove_proc_entry("fib_triestat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
|
||||
+ remove_proc_entry("fib_trie", net->proc_net);
|
||||
+ remove_proc_entry("fib_triestat", net->proc_net);
|
||||
+ }
|
||||
remove_proc_entry("route", net->proc_net);
|
||||
}
|
||||
|
||||
--- a/net/ipv4/proc.c
|
||||
+++ b/net/ipv4/proc.c
|
||||
@@ -557,5 +557,8 @@ static __net_initdata struct pernet_oper
|
||||
|
||||
int __init ip_misc_proc_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
return register_pernet_subsys(&ip_proc_ops);
|
||||
}
|
||||
--- a/net/ipv4/route.c
|
||||
+++ b/net/ipv4/route.c
|
||||
@@ -380,6 +380,9 @@ static struct pernet_operations ip_rt_pr
|
||||
|
||||
static int __init ip_rt_proc_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
return register_pernet_subsys(&ip_rt_proc_ops);
|
||||
}
|
||||
|
||||
--- a/net/ipv4/inet_timewait_sock.c
|
||||
+++ b/net/ipv4/inet_timewait_sock.c
|
||||
@@ -266,7 +266,7 @@ void __inet_twsk_schedule(struct inet_ti
|
||||
*/
|
||||
|
||||
if (!rearm) {
|
||||
- bool kill = timeo <= 4*HZ;
|
||||
+ bool __maybe_unused kill = timeo <= 4*HZ;
|
||||
|
||||
__NET_INC_STATS(twsk_net(tw), kill ? LINUX_MIB_TIMEWAITKILLED :
|
||||
LINUX_MIB_TIMEWAITED);
|
|
@ -1,32 +0,0 @@
|
|||
From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 16 Jul 2017 16:56:10 +0200
|
||||
Subject: lib: add uevent_next_seqnum()
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/kobject.h | 5 +++++
|
||||
lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
--- a/lib/kobject_uevent.c
|
||||
+++ b/lib/kobject_uevent.c
|
||||
@@ -179,6 +179,18 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
+u64 uevent_next_seqnum(void)
|
||||
+{
|
||||
+ u64 seq;
|
||||
+
|
||||
+ mutex_lock(&uevent_sock_mutex);
|
||||
+ seq = ++uevent_seqnum;
|
||||
+ mutex_unlock(&uevent_sock_mutex);
|
||||
+
|
||||
+ return seq;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(uevent_next_seqnum);
|
||||
+
|
||||
/**
|
||||
* kobject_synth_uevent - send synthetic uevent with arguments
|
||||
*
|
|
@ -1,76 +0,0 @@
|
|||
From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 16 Jul 2017 16:56:10 +0200
|
||||
Subject: lib: add uevent_next_seqnum()
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/kobject.h | 5 +++++
|
||||
lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
--- a/include/linux/kobject.h
|
||||
+++ b/include/linux/kobject.h
|
||||
@@ -32,6 +32,8 @@
|
||||
#define UEVENT_NUM_ENVP 64 /* number of env pointers */
|
||||
#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
|
||||
|
||||
+struct sk_buff;
|
||||
+
|
||||
#ifdef CONFIG_UEVENT_HELPER
|
||||
/* path to the userspace helper executed on an event */
|
||||
extern char uevent_helper[];
|
||||
@@ -219,4 +221,7 @@ int kobject_synth_uevent(struct kobject
|
||||
__printf(2, 3)
|
||||
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
|
||||
|
||||
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
|
||||
+ gfp_t allocation);
|
||||
+
|
||||
#endif /* _KOBJECT_H_ */
|
||||
--- a/lib/kobject_uevent.c
|
||||
+++ b/lib/kobject_uevent.c
|
||||
@@ -691,6 +691,43 @@ int add_uevent_var(struct kobj_uevent_en
|
||||
EXPORT_SYMBOL_GPL(add_uevent_var);
|
||||
|
||||
#if defined(CONFIG_NET)
|
||||
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
|
||||
+ gfp_t allocation)
|
||||
+{
|
||||
+ struct uevent_sock *ue_sk;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ /* send netlink message */
|
||||
+ mutex_lock(&uevent_sock_mutex);
|
||||
+ list_for_each_entry(ue_sk, &uevent_sock_list, list) {
|
||||
+ struct sock *uevent_sock = ue_sk->sk;
|
||||
+ struct sk_buff *skb2;
|
||||
+
|
||||
+ skb2 = skb_clone(skb, allocation);
|
||||
+ if (!skb2)
|
||||
+ break;
|
||||
+
|
||||
+ err = netlink_broadcast(uevent_sock, skb2, pid, group,
|
||||
+ allocation);
|
||||
+ if (err)
|
||||
+ break;
|
||||
+ }
|
||||
+ mutex_unlock(&uevent_sock_mutex);
|
||||
+
|
||||
+ kfree_skb(skb);
|
||||
+ return err;
|
||||
+}
|
||||
+#else
|
||||
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
|
||||
+ gfp_t allocation)
|
||||
+{
|
||||
+ kfree_skb(skb);
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+EXPORT_SYMBOL_GPL(broadcast_uevent);
|
||||
+
|
||||
+#if defined(CONFIG_NET)
|
||||
static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
|
@ -1,30 +0,0 @@
|
|||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 19 Jul 2022 06:17:48 +0200
|
||||
Subject: [PATCH] Revert "Revert "Revert "driver core: Set fw_devlink=on by
|
||||
default"""
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This reverts commit ea718c699055c8566eb64432388a04974c43b2ea.
|
||||
|
||||
With of_platform_populate() called for MTD partitions that commit breaks
|
||||
probing devices which reference MTD in device tree.
|
||||
|
||||
Link: https://lore.kernel.org/all/696cb2da-20b9-b3dd-46d9-de4bf91a1506@gmail.com/T/#u
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
drivers/base/core.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/base/core.c
|
||||
+++ b/drivers/base/core.c
|
||||
@@ -1657,7 +1657,7 @@ static void device_links_purge(struct de
|
||||
#define FW_DEVLINK_FLAGS_RPM (FW_DEVLINK_FLAGS_ON | \
|
||||
DL_FLAG_PM_RUNTIME)
|
||||
|
||||
-static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_ON;
|
||||
+static u32 fw_devlink_flags = FW_DEVLINK_FLAGS_PERMISSIVE;
|
||||
static int __init fw_devlink_setup(char *arg)
|
||||
{
|
||||
if (!arg)
|
File diff suppressed because it is too large
Load diff
|
@ -1,427 +0,0 @@
|
|||
From f1dfe037fdf0c300f38bab0bb8f256d4195d45e8 Mon Sep 17 00:00:00 2001
|
||||
From: Geliang Tang <geliang.tang@suse.com>
|
||||
Date: Tue, 19 Dec 2023 13:27:59 +0100
|
||||
Subject: [PATCH] mptcp: add sched_data helpers
|
||||
|
||||
Add a new helper mptcp_sched_data_set_contexts() to set the subflow
|
||||
pointers array in struct mptcp_sched_data. Add a new helper
|
||||
mptcp_subflow_ctx_by_pos() to get the given pos subflow from the
|
||||
contexts array in struct mptcp_sched_data. They will be invoked by
|
||||
the BPF schedulers to export the subflow pointers to the BPF contexts.
|
||||
|
||||
Signed-off-by: Geliang Tang <geliang.tang@suse.com>
|
||||
Reviewed-by: Mat Martineau <martineau@kernel.org>
|
||||
---
|
||||
net/mptcp/bpf.c | 14 ++++++++++++++
|
||||
net/mptcp/protocol.h | 2 ++
|
||||
net/mptcp/sched.c | 22 ++++++++++++++++++++++
|
||||
3 files changed, 38 insertions(+)
|
||||
|
||||
diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
|
||||
index 8a16672b94e23..c3d62535eb0cf 100644
|
||||
--- a/net/mptcp/bpf.c
|
||||
+++ b/net/mptcp/bpf.c
|
||||
@@ -29,6 +29,20 @@ static const struct btf_kfunc_id_set bpf_mptcp_fmodret_set = {
|
||||
.set = &bpf_mptcp_fmodret_ids,
|
||||
};
|
||||
|
||||
+__diag_push();
|
||||
+__diag_ignore_all("-Wmissing-prototypes",
|
||||
+ "kfuncs which will be used in BPF programs");
|
||||
+
|
||||
+__bpf_kfunc struct mptcp_subflow_context *
|
||||
+bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos)
|
||||
+{
|
||||
+ if (pos >= MPTCP_SUBFLOWS_MAX)
|
||||
+ return NULL;
|
||||
+ return data->contexts[pos];
|
||||
+}
|
||||
+
|
||||
+__diag_pop();
|
||||
+
|
||||
static int __init bpf_mptcp_kfunc_init(void)
|
||||
{
|
||||
return register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
|
||||
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
|
||||
index 3517f2d24a226..7cf5d2de74419 100644
|
||||
--- a/net/mptcp/protocol.h
|
||||
+++ b/net/mptcp/protocol.h
|
||||
@@ -636,6 +636,8 @@ void __mptcp_subflow_send_ack(struct sock *ssk);
|
||||
void mptcp_subflow_reset(struct sock *ssk);
|
||||
void mptcp_subflow_queue_clean(struct sock *sk, struct sock *ssk);
|
||||
void mptcp_sock_graft(struct sock *sk, struct socket *parent);
|
||||
+struct mptcp_subflow_context *
|
||||
+bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos);
|
||||
struct sock *__mptcp_nmpc_sk(struct mptcp_sock *msk);
|
||||
bool __mptcp_close(struct sock *sk, long timeout);
|
||||
void mptcp_cancel_work(struct sock *sk);
|
||||
diff --git a/net/mptcp/sched.c b/net/mptcp/sched.c
|
||||
index 4ab0693c069c0..a7e1c10b19848 100644
|
||||
--- a/net/mptcp/sched.c
|
||||
+++ b/net/mptcp/sched.c
|
||||
@@ -121,6 +121,26 @@ void mptcp_subflow_set_scheduled(struct mptcp_subflow_context *subflow,
|
||||
WRITE_ONCE(subflow->scheduled, scheduled);
|
||||
}
|
||||
|
||||
+static void mptcp_sched_data_set_contexts(const struct mptcp_sock *msk,
|
||||
+ struct mptcp_sched_data *data)
|
||||
+{
|
||||
+ struct mptcp_subflow_context *subflow;
|
||||
+ int i = 0;
|
||||
+
|
||||
+ mptcp_for_each_subflow(msk, subflow) {
|
||||
+ if (i == MPTCP_SUBFLOWS_MAX) {
|
||||
+ pr_warn_once("too many subflows");
|
||||
+ break;
|
||||
+ }
|
||||
+ mptcp_subflow_set_scheduled(subflow, false);
|
||||
+ data->contexts[i++] = subflow;
|
||||
+ }
|
||||
+ data->subflows = i;
|
||||
+
|
||||
+ for (; i < MPTCP_SUBFLOWS_MAX; i++)
|
||||
+ data->contexts[i] = NULL;
|
||||
+}
|
||||
+
|
||||
int mptcp_sched_get_send(struct mptcp_sock *msk)
|
||||
{
|
||||
struct mptcp_subflow_context *subflow;
|
||||
@@ -147,6 +167,7 @@ int mptcp_sched_get_send(struct mptcp_sock *msk)
|
||||
data.reinject = false;
|
||||
if (msk->sched == &mptcp_sched_default || !msk->sched)
|
||||
return mptcp_sched_default_get_subflow(msk, &data);
|
||||
+ mptcp_sched_data_set_contexts(msk, &data);
|
||||
return msk->sched->get_subflow(msk, &data);
|
||||
}
|
||||
|
||||
@@ -169,5 +190,6 @@ int mptcp_sched_get_retrans(struct mptcp_sock *msk)
|
||||
data.reinject = true;
|
||||
if (msk->sched == &mptcp_sched_default || !msk->sched)
|
||||
return mptcp_sched_default_get_subflow(msk, &data);
|
||||
+ mptcp_sched_data_set_contexts(msk, &data);
|
||||
return msk->sched->get_subflow(msk, &data);
|
||||
}
|
||||
From 229208a99e76be925541e898fd9a272984b5958c Mon Sep 17 00:00:00 2001
|
||||
From: Geliang Tang <geliang.tang@suse.com>
|
||||
Date: Tue, 19 Dec 2023 13:28:00 +0100
|
||||
Subject: [PATCH] bpf: Add bpf_mptcp_sched_ops
|
||||
|
||||
This patch implements a new struct bpf_struct_ops: bpf_mptcp_sched_ops.
|
||||
Register and unregister the bpf scheduler in .reg and .unreg.
|
||||
|
||||
Add write access for the scheduled flag of struct mptcp_subflow_context
|
||||
in .btf_struct_access.
|
||||
|
||||
This MPTCP BPF scheduler implementation is similar to BPF TCP CC. And
|
||||
net/ipv4/bpf_tcp_ca.c is a frame of reference for this patch.
|
||||
|
||||
Acked-by: Paolo Abeni <pabeni@redhat.com>
|
||||
Reviewed-by: Mat Martineau <martineau@kernel.org>
|
||||
Co-developed-by: Matthieu Baerts <matttbe@kernel.org>
|
||||
Signed-off-by: Matthieu Baerts <matttbe@kernel.org>
|
||||
Signed-off-by: Geliang Tang <geliang.tang@suse.com>
|
||||
---
|
||||
kernel/bpf/bpf_struct_ops_types.h | 4 +
|
||||
net/mptcp/bpf.c | 146 ++++++++++++++++++++++++++++++
|
||||
2 files changed, 150 insertions(+)
|
||||
|
||||
diff --git a/kernel/bpf/bpf_struct_ops_types.h b/kernel/bpf/bpf_struct_ops_types.h
|
||||
index 5678a9ddf8178..5a6b0c0d8d3db 100644
|
||||
--- a/kernel/bpf/bpf_struct_ops_types.h
|
||||
+++ b/kernel/bpf/bpf_struct_ops_types.h
|
||||
@@ -8,5 +8,9 @@ BPF_STRUCT_OPS_TYPE(bpf_dummy_ops)
|
||||
#ifdef CONFIG_INET
|
||||
#include <net/tcp.h>
|
||||
BPF_STRUCT_OPS_TYPE(tcp_congestion_ops)
|
||||
+#ifdef CONFIG_MPTCP
|
||||
+#include <net/mptcp.h>
|
||||
+BPF_STRUCT_OPS_TYPE(mptcp_sched_ops)
|
||||
+#endif
|
||||
#endif
|
||||
#endif
|
||||
diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
|
||||
index c3d62535eb0cf..dfcaaf0e07dd5 100644
|
||||
--- a/net/mptcp/bpf.c
|
||||
+++ b/net/mptcp/bpf.c
|
||||
@@ -10,8 +10,153 @@
|
||||
#define pr_fmt(fmt) "MPTCP: " fmt
|
||||
|
||||
#include <linux/bpf.h>
|
||||
+#include <linux/bpf_verifier.h>
|
||||
+#include <linux/btf.h>
|
||||
+#include <linux/btf_ids.h>
|
||||
+#include <net/bpf_sk_storage.h>
|
||||
#include "protocol.h"
|
||||
|
||||
+#ifdef CONFIG_BPF_JIT
|
||||
+extern struct bpf_struct_ops bpf_mptcp_sched_ops;
|
||||
+static const struct btf_type *mptcp_sock_type, *mptcp_subflow_type __read_mostly;
|
||||
+static u32 mptcp_sock_id, mptcp_subflow_id;
|
||||
+
|
||||
+static const struct bpf_func_proto *
|
||||
+bpf_mptcp_sched_get_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog)
|
||||
+{
|
||||
+ switch (func_id) {
|
||||
+ case BPF_FUNC_sk_storage_get:
|
||||
+ return &bpf_sk_storage_get_proto;
|
||||
+ case BPF_FUNC_sk_storage_delete:
|
||||
+ return &bpf_sk_storage_delete_proto;
|
||||
+ case BPF_FUNC_skc_to_tcp6_sock:
|
||||
+ return &bpf_skc_to_tcp6_sock_proto;
|
||||
+ case BPF_FUNC_skc_to_tcp_sock:
|
||||
+ return &bpf_skc_to_tcp_sock_proto;
|
||||
+ default:
|
||||
+ return bpf_base_func_proto(func_id);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int bpf_mptcp_sched_btf_struct_access(struct bpf_verifier_log *log,
|
||||
+ const struct bpf_reg_state *reg,
|
||||
+ int off, int size)
|
||||
+{
|
||||
+ const struct btf_type *t;
|
||||
+ size_t end;
|
||||
+
|
||||
+ t = btf_type_by_id(reg->btf, reg->btf_id);
|
||||
+ if (t != mptcp_sock_type && t != mptcp_subflow_type) {
|
||||
+ bpf_log(log, "only access to mptcp sock or subflow is supported\n");
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+
|
||||
+ switch (off) {
|
||||
+ case offsetof(struct mptcp_sock, snd_burst):
|
||||
+ end = offsetofend(struct mptcp_sock, snd_burst);
|
||||
+ break;
|
||||
+ case offsetof(struct mptcp_subflow_context, scheduled):
|
||||
+ end = offsetofend(struct mptcp_subflow_context, scheduled);
|
||||
+ break;
|
||||
+ case offsetof(struct mptcp_subflow_context, avg_pacing_rate):
|
||||
+ end = offsetofend(struct mptcp_subflow_context, avg_pacing_rate);
|
||||
+ break;
|
||||
+ default:
|
||||
+ bpf_log(log, "no write support to %s at off %d\n",
|
||||
+ t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context", off);
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+
|
||||
+ if (off + size > end) {
|
||||
+ bpf_log(log, "access beyond %s at off %u size %u ended at %zu",
|
||||
+ t == mptcp_sock_type ? "mptcp_sock" : "mptcp_subflow_context",
|
||||
+ off, size, end);
|
||||
+ return -EACCES;
|
||||
+ }
|
||||
+
|
||||
+ return NOT_INIT;
|
||||
+}
|
||||
+
|
||||
+static const struct bpf_verifier_ops bpf_mptcp_sched_verifier_ops = {
|
||||
+ .get_func_proto = bpf_mptcp_sched_get_func_proto,
|
||||
+ .is_valid_access = bpf_tracing_btf_ctx_access,
|
||||
+ .btf_struct_access = bpf_mptcp_sched_btf_struct_access,
|
||||
+};
|
||||
+
|
||||
+static int bpf_mptcp_sched_reg(void *kdata)
|
||||
+{
|
||||
+ return mptcp_register_scheduler(kdata);
|
||||
+}
|
||||
+
|
||||
+static void bpf_mptcp_sched_unreg(void *kdata)
|
||||
+{
|
||||
+ mptcp_unregister_scheduler(kdata);
|
||||
+}
|
||||
+
|
||||
+static int bpf_mptcp_sched_check_member(const struct btf_type *t,
|
||||
+ const struct btf_member *member,
|
||||
+ const struct bpf_prog *prog)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bpf_mptcp_sched_init_member(const struct btf_type *t,
|
||||
+ const struct btf_member *member,
|
||||
+ void *kdata, const void *udata)
|
||||
+{
|
||||
+ const struct mptcp_sched_ops *usched;
|
||||
+ struct mptcp_sched_ops *sched;
|
||||
+ u32 moff;
|
||||
+
|
||||
+ usched = (const struct mptcp_sched_ops *)udata;
|
||||
+ sched = (struct mptcp_sched_ops *)kdata;
|
||||
+
|
||||
+ moff = __btf_member_bit_offset(t, member) / 8;
|
||||
+ switch (moff) {
|
||||
+ case offsetof(struct mptcp_sched_ops, name):
|
||||
+ if (bpf_obj_name_cpy(sched->name, usched->name,
|
||||
+ sizeof(sched->name)) <= 0)
|
||||
+ return -EINVAL;
|
||||
+ if (mptcp_sched_find(usched->name))
|
||||
+ return -EEXIST;
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int bpf_mptcp_sched_init(struct btf *btf)
|
||||
+{
|
||||
+ s32 type_id;
|
||||
+
|
||||
+ type_id = btf_find_by_name_kind(btf, "mptcp_sock",
|
||||
+ BTF_KIND_STRUCT);
|
||||
+ if (type_id < 0)
|
||||
+ return -EINVAL;
|
||||
+ mptcp_sock_id = type_id;
|
||||
+ mptcp_sock_type = btf_type_by_id(btf, mptcp_sock_id);
|
||||
+
|
||||
+ type_id = btf_find_by_name_kind(btf, "mptcp_subflow_context",
|
||||
+ BTF_KIND_STRUCT);
|
||||
+ if (type_id < 0)
|
||||
+ return -EINVAL;
|
||||
+ mptcp_subflow_id = type_id;
|
||||
+ mptcp_subflow_type = btf_type_by_id(btf, mptcp_subflow_id);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+struct bpf_struct_ops bpf_mptcp_sched_ops = {
|
||||
+ .verifier_ops = &bpf_mptcp_sched_verifier_ops,
|
||||
+ .reg = bpf_mptcp_sched_reg,
|
||||
+ .unreg = bpf_mptcp_sched_unreg,
|
||||
+ .check_member = bpf_mptcp_sched_check_member,
|
||||
+ .init_member = bpf_mptcp_sched_init_member,
|
||||
+ .init = bpf_mptcp_sched_init,
|
||||
+ .name = "mptcp_sched_ops",
|
||||
+};
|
||||
+#endif /* CONFIG_BPF_JIT */
|
||||
+
|
||||
struct mptcp_sock *bpf_mptcp_sock_from_subflow(struct sock *sk)
|
||||
{
|
||||
if (sk && sk_fullsock(sk) && sk->sk_protocol == IPPROTO_TCP && sk_is_mptcp(sk))
|
||||
From c128adc086aa390e8dba43bcad604fe223e50bf4 Mon Sep 17 00:00:00 2001
|
||||
From: Geliang Tang <geliang.tang@suse.com>
|
||||
Date: Tue, 19 Dec 2023 13:28:01 +0100
|
||||
Subject: [PATCH] bpf: Add bpf_mptcp_sched_kfunc_set
|
||||
|
||||
This patch adds a new struct btf_kfunc_id_set for MPTCP scheduler. Add
|
||||
mptcp_subflow_set_scheduled() and mptcp_sched_data_set_contexts() helpers
|
||||
into this id_set, and register it in bpf_mptcp_kfunc_init() to make sure
|
||||
these helpers can be accessed from the BPF context.
|
||||
|
||||
Reviewed-by: Mat Martineau <martineau@kernel.org>
|
||||
Signed-off-by: Geliang Tang <geliang.tang@suse.com>
|
||||
---
|
||||
net/mptcp/bpf.c | 16 +++++++++++++++-
|
||||
1 file changed, 15 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
|
||||
index dfcaaf0e07dd..aec9515888f7 100644
|
||||
--- a/net/mptcp/bpf.c
|
||||
+++ b/net/mptcp/bpf.c
|
||||
@@ -189,8 +189,22 @@ bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int p
|
||||
|
||||
__diag_pop();
|
||||
|
||||
+BTF_SET8_START(bpf_mptcp_sched_kfunc_ids)
|
||||
+BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
|
||||
+BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
|
||||
+BTF_SET8_END(bpf_mptcp_sched_kfunc_ids)
|
||||
+
|
||||
+static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .set = &bpf_mptcp_sched_kfunc_ids,
|
||||
+};
|
||||
+
|
||||
static int __init bpf_mptcp_kfunc_init(void)
|
||||
{
|
||||
- return register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = register_btf_fmodret_id_set(&bpf_mptcp_fmodret_set);
|
||||
+ return ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS,
|
||||
+ &bpf_mptcp_sched_kfunc_set);
|
||||
}
|
||||
late_initcall(bpf_mptcp_kfunc_init);
|
||||
From f322294a8f32ddf7e40021d94c19665c302dbd79 Mon Sep 17 00:00:00 2001
|
||||
From: Geliang Tang <geliang.tang@suse.com>
|
||||
Date: Tue, 19 Dec 2023 13:28:12 +0100
|
||||
Subject: [PATCH] bpf: Export more bpf_burst related functions
|
||||
|
||||
sk_stream_memory_free() and tcp_rtx_and_write_queues_empty() are needed
|
||||
to export into the BPF context for bpf_burst scheduler. But these two
|
||||
functions are inline ones. So this patch added two wrappers for them,
|
||||
and export the wrappers in the BPF context.
|
||||
|
||||
Add more bpf_burst related functions into bpf_mptcp_sched_kfunc_set to make
|
||||
sure these helpers can be accessed from the BPF context.
|
||||
|
||||
Signed-off-by: Geliang Tang <geliang.tang@suse.com>
|
||||
Reviewed-by: Mat Martineau <martineau@kernel.org>
|
||||
---
|
||||
net/mptcp/bpf.c | 11 +++++++++++
|
||||
net/mptcp/protocol.c | 4 ++--
|
||||
net/mptcp/protocol.h | 3 +++
|
||||
3 files changed, 16 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/net/mptcp/bpf.c b/net/mptcp/bpf.c
|
||||
index aec9515888f7..007c2034db65 100644
|
||||
--- a/net/mptcp/bpf.c
|
||||
+++ b/net/mptcp/bpf.c
|
||||
@@ -187,11 +187,22 @@ bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int p
|
||||
return data->contexts[pos];
|
||||
}
|
||||
|
||||
+__bpf_kfunc bool bpf_mptcp_subflow_queues_empty(struct sock *sk)
|
||||
+{
|
||||
+ return tcp_rtx_queue_empty(sk);
|
||||
+}
|
||||
+
|
||||
__diag_pop();
|
||||
|
||||
BTF_SET8_START(bpf_mptcp_sched_kfunc_ids)
|
||||
BTF_ID_FLAGS(func, mptcp_subflow_set_scheduled)
|
||||
BTF_ID_FLAGS(func, bpf_mptcp_subflow_ctx_by_pos)
|
||||
+BTF_ID_FLAGS(func, mptcp_subflow_active)
|
||||
+BTF_ID_FLAGS(func, mptcp_set_timeout)
|
||||
+BTF_ID_FLAGS(func, mptcp_wnd_end)
|
||||
+BTF_ID_FLAGS(func, tcp_stream_memory_free)
|
||||
+BTF_ID_FLAGS(func, bpf_mptcp_subflow_queues_empty)
|
||||
+BTF_ID_FLAGS(func, mptcp_pm_subflow_chk_stale)
|
||||
BTF_SET8_END(bpf_mptcp_sched_kfunc_ids)
|
||||
|
||||
static const struct btf_kfunc_id_set bpf_mptcp_sched_kfunc_set = {
|
||||
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
|
||||
index 8bfd266f2754..c12bf17691d7 100644
|
||||
--- a/net/mptcp/protocol.c
|
||||
+++ b/net/mptcp/protocol.c
|
||||
@@ -50,7 +50,7 @@ DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions);
|
||||
static struct net_device mptcp_napi_dev;
|
||||
|
||||
/* Returns end sequence number of the receiver's advertised window */
|
||||
-static u64 mptcp_wnd_end(const struct mptcp_sock *msk)
|
||||
+u64 mptcp_wnd_end(const struct mptcp_sock *msk)
|
||||
{
|
||||
return READ_ONCE(msk->wnd_end);
|
||||
}
|
||||
@@ -485,7 +485,7 @@ static long mptcp_timeout_from_subflow(const struct mptcp_subflow_context *subfl
|
||||
inet_csk(ssk)->icsk_timeout - jiffies : 0;
|
||||
}
|
||||
|
||||
-static void mptcp_set_timeout(struct sock *sk)
|
||||
+void mptcp_set_timeout(struct sock *sk)
|
||||
{
|
||||
struct mptcp_subflow_context *subflow;
|
||||
long tout = 0;
|
||||
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
|
||||
index 7cf5d2de7441..f7b9c1b995df 100644
|
||||
--- a/net/mptcp/protocol.h
|
||||
+++ b/net/mptcp/protocol.h
|
||||
@@ -636,6 +636,9 @@ void __mptcp_subflow_send_ack(struct sock *ssk);
|
||||
void mptcp_subflow_reset(struct sock *ssk);
|
||||
void mptcp_subflow_queue_clean(struct sock *sk, struct sock *ssk);
|
||||
void mptcp_sock_graft(struct sock *sk, struct socket *parent);
|
||||
+u64 mptcp_wnd_end(const struct mptcp_sock *msk);
|
||||
+void mptcp_set_timeout(struct sock *sk);
|
||||
+bool bpf_mptcp_subflow_queues_empty(struct sock *sk);
|
||||
struct mptcp_subflow_context *
|
||||
bpf_mptcp_subflow_ctx_by_pos(const struct mptcp_sched_data *data, unsigned int pos);
|
||||
struct sock *__mptcp_nmpc_sk(struct mptcp_sock *msk);
|
|
@ -1,71 +0,0 @@
|
|||
From: Daniel González Cabanelas <dgcbueu@gmail.com>
|
||||
Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source
|
||||
|
||||
Currently there is no use for the interrupts on the rs5c372 RTC and the
|
||||
wakealarm isn't enabled. There are some devices like NASes which use this
|
||||
RTC to wake up from the power off state when the INTR pin is activated by
|
||||
the alarm clock.
|
||||
|
||||
Enable the alarm and let to be used as a wakeup source.
|
||||
|
||||
Tested on a Buffalo LS421DE NAS.
|
||||
|
||||
Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
|
||||
---
|
||||
drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
--- a/drivers/rtc/rtc-rs5c372.c
|
||||
+++ b/drivers/rtc/rtc-rs5c372.c
|
||||
@@ -832,6 +832,7 @@ static int rs5c372_probe(struct i2c_clie
|
||||
int err = 0;
|
||||
int smbus_mode = 0;
|
||||
struct rs5c372 *rs5c372;
|
||||
+ bool rs5c372_can_wakeup_device = false;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
@@ -868,6 +869,12 @@ static int rs5c372_probe(struct i2c_clie
|
||||
rs5c372->type = id->driver_data;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+ if(of_property_read_bool(client->dev.of_node,
|
||||
+ "wakeup-source"))
|
||||
+ rs5c372_can_wakeup_device = true;
|
||||
+#endif
|
||||
+
|
||||
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
|
||||
rs5c372->regs = &rs5c372->buf[1];
|
||||
rs5c372->smbus = smbus_mode;
|
||||
@@ -901,6 +908,8 @@ static int rs5c372_probe(struct i2c_clie
|
||||
goto exit;
|
||||
}
|
||||
|
||||
+ rs5c372->has_irq = 1;
|
||||
+
|
||||
/* if the oscillator lost power and no other software (like
|
||||
* the bootloader) set it up, do it here.
|
||||
*
|
||||
@@ -927,6 +936,10 @@ static int rs5c372_probe(struct i2c_clie
|
||||
);
|
||||
|
||||
/* REVISIT use client->irq to register alarm irq ... */
|
||||
+ if (rs5c372_can_wakeup_device) {
|
||||
+ device_init_wakeup(&client->dev, true);
|
||||
+ }
|
||||
+
|
||||
rs5c372->rtc = devm_rtc_device_register(&client->dev,
|
||||
rs5c372_driver.driver.name,
|
||||
&rs5c372_rtc_ops, THIS_MODULE);
|
||||
@@ -940,6 +953,10 @@ static int rs5c372_probe(struct i2c_clie
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
+ /* the rs5c372 alarm only supports a minute accuracy */
|
||||
+ set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rs5c372->rtc->features);
|
||||
+ clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rs5c372->rtc->features);
|
||||
+
|
||||
return 0;
|
||||
|
||||
exit:
|
|
@ -1,31 +0,0 @@
|
|||
From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
|
||||
Date: Sat, 28 Mar 2020 12:11:50 +0100
|
||||
Subject: [PATCH] generic: platform/mikrotik build bits (5.4)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This patch adds platform/mikrotik kernel build bits
|
||||
|
||||
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
|
||||
---
|
||||
drivers/platform/Kconfig | 2 ++
|
||||
drivers/platform/Makefile | 1 +
|
||||
2 files changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/platform/Kconfig
|
||||
+++ b/drivers/platform/Kconfig
|
||||
@@ -14,3 +14,5 @@ source "drivers/platform/olpc/Kconfig"
|
||||
source "drivers/platform/surface/Kconfig"
|
||||
|
||||
source "drivers/platform/x86/Kconfig"
|
||||
+
|
||||
+source "drivers/platform/mikrotik/Kconfig"
|
||||
--- a/drivers/platform/Makefile
|
||||
+++ b/drivers/platform/Makefile
|
||||
@@ -11,3 +11,4 @@ obj-$(CONFIG_OLPC_EC) += olpc/
|
||||
obj-$(CONFIG_GOLDFISH) += goldfish/
|
||||
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
|
||||
obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
|
||||
+obj-$(CONFIG_MIKROTIK) += mikrotik/
|
|
@ -1,370 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to
|
||||
|
||||
lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/Makefile | 5 +
|
||||
arch/mips/include/asm/module.h | 5 +
|
||||
arch/mips/kernel/module.c | 279 ++++++++++++++++++++++++++++++++++++++++-
|
||||
3 files changed, 284 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -97,8 +97,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||
cflags-y += -msoft-float -Wa,-msoft-float
|
||||
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||
+ifdef CONFIG_64BIT
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||
+else
|
||||
+ ifdef CONFIG_DYNAMIC_FTRACE
|
||||
+ KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
+ KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||
+ else
|
||||
+ KBUILD_AFLAGS_MODULE += -mno-long-calls
|
||||
+ KBUILD_CFLAGS_MODULE += -mno-long-calls
|
||||
+ endif
|
||||
+endif
|
||||
|
||||
ifeq ($(CONFIG_RELOCATABLE),y)
|
||||
LDFLAGS_vmlinux += --emit-relocs
|
||||
--- a/arch/mips/include/asm/module.h
|
||||
+++ b/arch/mips/include/asm/module.h
|
||||
@@ -12,6 +12,11 @@ struct mod_arch_specific {
|
||||
const struct exception_table_entry *dbe_start;
|
||||
const struct exception_table_entry *dbe_end;
|
||||
struct mips_hi16 *r_mips_hi16_list;
|
||||
+
|
||||
+ void *phys_plt_tbl;
|
||||
+ void *virt_plt_tbl;
|
||||
+ unsigned int phys_plt_offset;
|
||||
+ unsigned int virt_plt_offset;
|
||||
};
|
||||
|
||||
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
|
||||
--- a/arch/mips/kernel/module.c
|
||||
+++ b/arch/mips/kernel/module.c
|
||||
@@ -32,23 +32,261 @@ struct mips_hi16 {
|
||||
static LIST_HEAD(dbe_list);
|
||||
static DEFINE_SPINLOCK(dbe_lock);
|
||||
|
||||
-#ifdef MODULE_START
|
||||
+/*
|
||||
+ * Get the potential max trampolines size required of the init and
|
||||
+ * non-init sections. Only used if we cannot find enough contiguous
|
||||
+ * physically mapped memory to put the module into.
|
||||
+ */
|
||||
+static unsigned int
|
||||
+get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
||||
+ const char *secstrings, unsigned int symindex, bool is_init)
|
||||
+{
|
||||
+ unsigned long ret = 0;
|
||||
+ unsigned int i, j;
|
||||
+ Elf_Sym *syms;
|
||||
+
|
||||
+ /* Everything marked ALLOC (this includes the exported symbols) */
|
||||
+ for (i = 1; i < hdr->e_shnum; ++i) {
|
||||
+ unsigned int info = sechdrs[i].sh_info;
|
||||
+
|
||||
+ if (sechdrs[i].sh_type != SHT_REL
|
||||
+ && sechdrs[i].sh_type != SHT_RELA)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Not a valid relocation section? */
|
||||
+ if (info >= hdr->e_shnum)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Don't bother with non-allocated sections */
|
||||
+ if (!(sechdrs[info].sh_flags & SHF_ALLOC))
|
||||
+ continue;
|
||||
+
|
||||
+ /* If it's called *.init*, and we're not init, we're
|
||||
+ not interested */
|
||||
+ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
|
||||
+ != is_init)
|
||||
+ continue;
|
||||
+
|
||||
+ syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
|
||||
+ if (sechdrs[i].sh_type == SHT_REL) {
|
||||
+ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
|
||||
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
|
||||
+
|
||||
+ for (j = 0; j < size; ++j) {
|
||||
+ Elf_Sym *sym;
|
||||
+
|
||||
+ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
|
||||
+ continue;
|
||||
+
|
||||
+ sym = syms + ELF_MIPS_R_SYM(rel[j]);
|
||||
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
|
||||
+ continue;
|
||||
+
|
||||
+ ret += 4 * sizeof(int);
|
||||
+ }
|
||||
+ } else {
|
||||
+ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
|
||||
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
|
||||
+
|
||||
+ for (j = 0; j < size; ++j) {
|
||||
+ Elf_Sym *sym;
|
||||
+
|
||||
+ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
|
||||
+ continue;
|
||||
+
|
||||
+ sym = syms + ELF_MIPS_R_SYM(rela[j]);
|
||||
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
|
||||
+ continue;
|
||||
+
|
||||
+ ret += 4 * sizeof(int);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#ifndef MODULE_START
|
||||
+static void *alloc_phys(unsigned long size)
|
||||
+{
|
||||
+ unsigned order;
|
||||
+ struct page *page;
|
||||
+ struct page *p;
|
||||
+
|
||||
+ size = PAGE_ALIGN(size);
|
||||
+ order = get_order(size);
|
||||
+
|
||||
+ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
|
||||
+ __GFP_THISNODE, order);
|
||||
+ if (!page)
|
||||
+ return NULL;
|
||||
+
|
||||
+ split_page(page, order);
|
||||
+
|
||||
+ /* mark all pages except for the last one */
|
||||
+ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
|
||||
+ set_bit(PG_owner_priv_1, &p->flags);
|
||||
+
|
||||
+ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
|
||||
+ __free_page(p);
|
||||
+
|
||||
+ return page_address(page);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static void free_phys(void *ptr)
|
||||
+{
|
||||
+ struct page *page;
|
||||
+ bool free;
|
||||
+
|
||||
+ page = virt_to_page(ptr);
|
||||
+ do {
|
||||
+ free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
|
||||
+ __free_page(page);
|
||||
+ page++;
|
||||
+ } while (free);
|
||||
+}
|
||||
+
|
||||
+
|
||||
void *module_alloc(unsigned long size)
|
||||
{
|
||||
+#ifdef MODULE_START
|
||||
return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
|
||||
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
|
||||
__builtin_return_address(0));
|
||||
+#else
|
||||
+ void *ptr;
|
||||
+
|
||||
+ if (size == 0)
|
||||
+ return NULL;
|
||||
+
|
||||
+ ptr = alloc_phys(size);
|
||||
+
|
||||
+ /* If we failed to allocate physically contiguous memory,
|
||||
+ * fall back to regular vmalloc. The module loader code will
|
||||
+ * create jump tables to handle long jumps */
|
||||
+ if (!ptr)
|
||||
+ return vmalloc(size);
|
||||
+
|
||||
+ return ptr;
|
||||
+#endif
|
||||
}
|
||||
+
|
||||
+static inline bool is_phys_addr(void *ptr)
|
||||
+{
|
||||
+#ifdef CONFIG_64BIT
|
||||
+ return (KSEGX((unsigned long)ptr) == CKSEG0);
|
||||
+#else
|
||||
+ return (KSEGX(ptr) == KSEG0);
|
||||
#endif
|
||||
+}
|
||||
+
|
||||
+/* Free memory returned from module_alloc */
|
||||
+void module_memfree(void *module_region)
|
||||
+{
|
||||
+ if (is_phys_addr(module_region))
|
||||
+ free_phys(module_region);
|
||||
+ else
|
||||
+ vfree(module_region);
|
||||
+}
|
||||
+
|
||||
+static void *__module_alloc(int size, bool phys)
|
||||
+{
|
||||
+ void *ptr;
|
||||
+
|
||||
+ if (phys)
|
||||
+ ptr = kmalloc(size, GFP_KERNEL);
|
||||
+ else
|
||||
+ ptr = vmalloc(size);
|
||||
+ return ptr;
|
||||
+}
|
||||
+
|
||||
+static void __module_free(void *ptr)
|
||||
+{
|
||||
+ if (is_phys_addr(ptr))
|
||||
+ kfree(ptr);
|
||||
+ else
|
||||
+ vfree(ptr);
|
||||
+}
|
||||
+
|
||||
+int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
+ char *secstrings, struct module *mod)
|
||||
+{
|
||||
+ unsigned int symindex = 0;
|
||||
+ unsigned int core_size, init_size;
|
||||
+ int i;
|
||||
+
|
||||
+ mod->arch.phys_plt_offset = 0;
|
||||
+ mod->arch.virt_plt_offset = 0;
|
||||
+ mod->arch.phys_plt_tbl = NULL;
|
||||
+ mod->arch.virt_plt_tbl = NULL;
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_64BIT))
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 1; i < hdr->e_shnum; i++)
|
||||
+ if (sechdrs[i].sh_type == SHT_SYMTAB)
|
||||
+ symindex = i;
|
||||
+
|
||||
+ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
|
||||
+ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
|
||||
+
|
||||
+ if ((core_size + init_size) == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
|
||||
+ if (!mod->arch.phys_plt_tbl)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
|
||||
+ if (!mod->arch.virt_plt_tbl) {
|
||||
+ __module_free(mod->arch.phys_plt_tbl);
|
||||
+ mod->arch.phys_plt_tbl = NULL;
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
static void apply_r_mips_32(u32 *location, u32 base, Elf_Addr v)
|
||||
{
|
||||
*location = base + v;
|
||||
}
|
||||
|
||||
+static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
|
||||
+ void *start, Elf_Addr v)
|
||||
+{
|
||||
+ unsigned *tramp = start + *plt_offset;
|
||||
+ *plt_offset += 4 * sizeof(int);
|
||||
+
|
||||
+ /* adjust carry for addiu */
|
||||
+ if (v & 0x00008000)
|
||||
+ v += 0x10000;
|
||||
+
|
||||
+ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */
|
||||
+ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */
|
||||
+ tramp[2] = 0x03200008; /* jr t9 */
|
||||
+ tramp[3] = 0x00000000; /* nop */
|
||||
+
|
||||
+ return (Elf_Addr) tramp;
|
||||
+}
|
||||
+
|
||||
+static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
|
||||
+{
|
||||
+ if (is_phys_addr(location))
|
||||
+ return add_plt_entry_to(&me->arch.phys_plt_offset,
|
||||
+ me->arch.phys_plt_tbl, v);
|
||||
+ else
|
||||
+ return add_plt_entry_to(&me->arch.virt_plt_offset,
|
||||
+ me->arch.virt_plt_tbl, v);
|
||||
+
|
||||
+}
|
||||
+
|
||||
static int apply_r_mips_26(struct module *me, u32 *location, u32 base,
|
||||
Elf_Addr v)
|
||||
{
|
||||
+ u32 ofs = base & 0x03ffffff;
|
||||
+
|
||||
if (v % 4) {
|
||||
pr_err("module %s: dangerous R_MIPS_26 relocation\n",
|
||||
me->name);
|
||||
@@ -56,13 +294,17 @@ static int apply_r_mips_26(struct module
|
||||
}
|
||||
|
||||
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
|
||||
- pr_err("module %s: relocation overflow\n",
|
||||
- me->name);
|
||||
- return -ENOEXEC;
|
||||
+ v = add_plt_entry(me, location, v + (ofs << 2));
|
||||
+ if (!v) {
|
||||
+ pr_err("module %s: relocation overflow\n",
|
||||
+ me->name);
|
||||
+ return -ENOEXEC;
|
||||
+ }
|
||||
+ ofs = 0;
|
||||
}
|
||||
|
||||
*location = (*location & ~0x03ffffff) |
|
||||
- ((base + (v >> 2)) & 0x03ffffff);
|
||||
+ ((ofs + (v >> 2)) & 0x03ffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -442,9 +684,36 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||
list_add(&me->arch.dbe_list, &dbe_list);
|
||||
spin_unlock_irq(&dbe_lock);
|
||||
}
|
||||
+
|
||||
+ /* Get rid of the fixup trampoline if we're running the module
|
||||
+ * from physically mapped address space */
|
||||
+ if (me->arch.phys_plt_offset == 0) {
|
||||
+ __module_free(me->arch.phys_plt_tbl);
|
||||
+ me->arch.phys_plt_tbl = NULL;
|
||||
+ }
|
||||
+ if (me->arch.virt_plt_offset == 0) {
|
||||
+ __module_free(me->arch.virt_plt_tbl);
|
||||
+ me->arch.virt_plt_tbl = NULL;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
+void module_arch_freeing_init(struct module *mod)
|
||||
+{
|
||||
+ if (mod->state == MODULE_STATE_LIVE)
|
||||
+ return;
|
||||
+
|
||||
+ if (mod->arch.phys_plt_tbl) {
|
||||
+ __module_free(mod->arch.phys_plt_tbl);
|
||||
+ mod->arch.phys_plt_tbl = NULL;
|
||||
+ }
|
||||
+ if (mod->arch.virt_plt_tbl) {
|
||||
+ __module_free(mod->arch.virt_plt_tbl);
|
||||
+ mod->arch.virt_plt_tbl = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void module_arch_cleanup(struct module *mod)
|
||||
{
|
||||
spin_lock_irq(&dbe_lock);
|
|
@ -1,245 +0,0 @@
|
|||
From acacdac272927ae1d96e0bca51eb82899671eaea Mon Sep 17 00:00:00 2001
|
||||
From: John Thomson <git@johnthomson.fastmail.com.au>
|
||||
Date: Fri, 25 Dec 2020 18:50:08 +1000
|
||||
Subject: [PATCH] mtd: spi-nor: write support for minor aligned partitions
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Do not prevent writing to mtd partitions where a partition boundary sits
|
||||
on a minor erasesize boundary.
|
||||
This addresses a FIXME that has been present since the start of the
|
||||
linux git history:
|
||||
/* Doesn't start on a boundary of major erase size */
|
||||
/* FIXME: Let it be writable if it is on a boundary of
|
||||
* _minor_ erase size though */
|
||||
|
||||
Allow a uniform erase region spi-nor device to be configured
|
||||
to use the non-uniform erase regions code path for an erase with:
|
||||
CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE=y
|
||||
|
||||
On supporting hardware (SECT_4K: majority of current SPI-NOR device)
|
||||
provide the facility for an erase to use the least number
|
||||
of SPI-NOR operations, as well as access to 4K erase without
|
||||
requiring CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
|
||||
|
||||
Introduce erasesize_minor to the mtd struct,
|
||||
the smallest erasesize supported by the device
|
||||
|
||||
On existing devices, this is useful where write support is wanted
|
||||
for data on a 4K partition, such as some u-boot-env partitions,
|
||||
or RouterBoot soft_config, while still netting the performance
|
||||
benefits of using 64K sectors
|
||||
|
||||
Performance:
|
||||
time mtd erase firmware
|
||||
OpenWrt 5.10 ramips MT7621 w25q128jv 0xfc0000 partition length
|
||||
|
||||
Without this patch
|
||||
MTD_SPI_NOR_USE_4K_SECTORS=y |n
|
||||
real 2m 11.66s |0m 50.86s
|
||||
user 0m 0.00s |0m 0.00s
|
||||
sys 1m 56.20s |0m 50.80s
|
||||
|
||||
With this patch
|
||||
MTD_SPI_NOR_USE_VARIABLE_ERASE=n|y |4K_SECTORS=y
|
||||
real 0m 51.68s |0m 50.85s |2m 12.89s
|
||||
user 0m 0.00s |0m 0.00s |0m 0.01s
|
||||
sys 0m 46.94s |0m 50.38s |2m 12.46s
|
||||
|
||||
Signed-off-by: John Thomson <git@johnthomson.fastmail.com.au>
|
||||
Signed-off-by: Thibaut VARÈNE <hacks+kernel@slashdirt.org>
|
||||
|
||||
---
|
||||
|
||||
checkpatch does not like the printk(KERN_WARNING
|
||||
these should be changed separately beforehand?
|
||||
|
||||
Changes v1 -> v2:
|
||||
Added mtdcore sysfs for erasesize_minor
|
||||
Removed finding minor erasesize for variable erase regions device,
|
||||
as untested and no responses regarding it.
|
||||
Moved IF_ENABLED for SPINOR variable erase to guard setting
|
||||
erasesize_minor in spi-nor/core.c
|
||||
Removed setting erasesize to minor where partition boundaries require
|
||||
minor erase to be writable
|
||||
Simplified minor boundary check by relying on minor being a factor of
|
||||
major
|
||||
|
||||
Changes RFC -> v1:
|
||||
Fix uninitialized variable smatch warning
|
||||
Reported-by: kernel test robot <lkp@intel.com>
|
||||
Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
|
||||
---
|
||||
drivers/mtd/mtdcore.c | 10 ++++++++++
|
||||
drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++----------
|
||||
drivers/mtd/spi-nor/Kconfig | 10 ++++++++++
|
||||
drivers/mtd/spi-nor/core.c | 11 +++++++++--
|
||||
include/linux/mtd/mtd.h | 2 ++
|
||||
5 files changed, 56 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/mtdcore.c
|
||||
+++ b/drivers/mtd/mtdcore.c
|
||||
@@ -198,6 +198,15 @@ static ssize_t mtd_erasesize_show(struct
|
||||
}
|
||||
MTD_DEVICE_ATTR_RO(erasesize);
|
||||
|
||||
+static ssize_t mtd_erasesize_minor_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct mtd_info *mtd = dev_get_drvdata(dev);
|
||||
+
|
||||
+ return sysfs_emit(buf, "%lu\n", (unsigned long)mtd->erasesize_minor);
|
||||
+}
|
||||
+MTD_DEVICE_ATTR_RO(erasesize_minor);
|
||||
+
|
||||
static ssize_t mtd_writesize_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -343,6 +352,7 @@ static struct attribute *mtd_attrs[] = {
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_size.attr,
|
||||
&dev_attr_erasesize.attr,
|
||||
+ &dev_attr_erasesize_minor.attr,
|
||||
&dev_attr_writesize.attr,
|
||||
&dev_attr_subpagesize.attr,
|
||||
&dev_attr_oobsize.attr,
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -47,6 +47,7 @@ static struct mtd_info *allocate_partiti
|
||||
struct mtd_info *master = mtd_get_master(parent);
|
||||
int wr_alignment = (parent->flags & MTD_NO_ERASE) ?
|
||||
master->writesize : master->erasesize;
|
||||
+ int wr_alignment_minor = 0;
|
||||
u64 parent_size = mtd_is_partition(parent) ?
|
||||
parent->part.size : parent->size;
|
||||
struct mtd_info *child;
|
||||
@@ -171,6 +172,7 @@ static struct mtd_info *allocate_partiti
|
||||
} else {
|
||||
/* Single erase size */
|
||||
child->erasesize = master->erasesize;
|
||||
+ child->erasesize_minor = master->erasesize_minor;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -178,26 +180,39 @@ static struct mtd_info *allocate_partiti
|
||||
* exposes several regions with different erasesize. Adjust
|
||||
* wr_alignment accordingly.
|
||||
*/
|
||||
- if (!(child->flags & MTD_NO_ERASE))
|
||||
+ if (!(child->flags & MTD_NO_ERASE)) {
|
||||
wr_alignment = child->erasesize;
|
||||
+ wr_alignment_minor = child->erasesize_minor;
|
||||
+ }
|
||||
|
||||
tmp = mtd_get_master_ofs(child, 0);
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((child->flags & MTD_WRITEABLE) && remainder) {
|
||||
- /* Doesn't start on a boundary of major erase size */
|
||||
- /* FIXME: Let it be writable if it is on a boundary of
|
||||
- * _minor_ erase size though */
|
||||
- child->flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
|
||||
- part->name);
|
||||
+ if (wr_alignment_minor) {
|
||||
+ /* rely on minor being a factor of major erasesize */
|
||||
+ tmp = remainder;
|
||||
+ remainder = do_div(tmp, wr_alignment_minor);
|
||||
+ }
|
||||
+ if (remainder) {
|
||||
+ child->flags &= ~MTD_WRITEABLE;
|
||||
+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase/write block boundary -- force read-only\n",
|
||||
+ part->name);
|
||||
+ }
|
||||
}
|
||||
|
||||
tmp = mtd_get_master_ofs(child, 0) + child->part.size;
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((child->flags & MTD_WRITEABLE) && remainder) {
|
||||
- child->flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
|
||||
- part->name);
|
||||
+ if (wr_alignment_minor) {
|
||||
+ tmp = remainder;
|
||||
+ remainder = do_div(tmp, wr_alignment_minor);
|
||||
+ }
|
||||
+
|
||||
+ if (remainder) {
|
||||
+ child->flags &= ~MTD_WRITEABLE;
|
||||
+ printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
|
||||
+ part->name);
|
||||
+ }
|
||||
}
|
||||
|
||||
child->size = child->part.size;
|
||||
--- a/drivers/mtd/spi-nor/Kconfig
|
||||
+++ b/drivers/mtd/spi-nor/Kconfig
|
||||
@@ -10,6 +10,16 @@ menuconfig MTD_SPI_NOR
|
||||
|
||||
if MTD_SPI_NOR
|
||||
|
||||
+config MTD_SPI_NOR_USE_VARIABLE_ERASE
|
||||
+ bool "Disable uniform_erase to allow use of all hardware supported erasesizes"
|
||||
+ depends on !MTD_SPI_NOR_USE_4K_SECTORS
|
||||
+ default n
|
||||
+ help
|
||||
+ Allow mixed use of all hardware supported erasesizes,
|
||||
+ by forcing spi_nor to use the multiple eraseregions code path.
|
||||
+ For example: A 68K erase will use one 64K erase, and one 4K erase
|
||||
+ on supporting hardware.
|
||||
+
|
||||
config MTD_SPI_NOR_USE_4K_SECTORS
|
||||
bool "Use small 4096 B erase sectors"
|
||||
default y
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -1150,6 +1150,8 @@ static u8 spi_nor_convert_3to4_erase(u8
|
||||
|
||||
static bool spi_nor_has_uniform_erase(const struct spi_nor *nor)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE))
|
||||
+ return false;
|
||||
return !!nor->params->erase_map.uniform_erase_type;
|
||||
}
|
||||
|
||||
@@ -2582,6 +2584,7 @@ static int spi_nor_select_erase(struct s
|
||||
{
|
||||
struct spi_nor_erase_map *map = &nor->params->erase_map;
|
||||
const struct spi_nor_erase_type *erase = NULL;
|
||||
+ const struct spi_nor_erase_type *erase_minor = NULL;
|
||||
struct mtd_info *mtd = &nor->mtd;
|
||||
u32 wanted_size = nor->info->sector_size;
|
||||
int i;
|
||||
@@ -2614,8 +2617,9 @@ static int spi_nor_select_erase(struct s
|
||||
*/
|
||||
for (i = SNOR_ERASE_TYPE_MAX - 1; i >= 0; i--) {
|
||||
if (map->erase_type[i].size) {
|
||||
- erase = &map->erase_type[i];
|
||||
- break;
|
||||
+ if (!erase)
|
||||
+ erase = &map->erase_type[i];
|
||||
+ erase_minor = &map->erase_type[i];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2623,6 +2627,9 @@ static int spi_nor_select_erase(struct s
|
||||
return -EINVAL;
|
||||
|
||||
mtd->erasesize = erase->size;
|
||||
+ if (IS_ENABLED(CONFIG_MTD_SPI_NOR_USE_VARIABLE_ERASE) &&
|
||||
+ erase_minor && erase_minor->size < erase->size)
|
||||
+ mtd->erasesize_minor = erase_minor->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -245,6 +245,8 @@ struct mtd_info {
|
||||
* information below if they desire
|
||||
*/
|
||||
uint32_t erasesize;
|
||||
+ /* "Minor" (smallest) erase size supported by the whole device */
|
||||
+ uint32_t erasesize_minor;
|
||||
/* Minimal writable flash unit size. In case of NOR flash it is 1 (even
|
||||
* though individual bits can be cleared), in case of NAND flash it is
|
||||
* one NAND page (or half, or one-fourths of it), in case of ECC-ed NOR
|
|
@ -1,74 +0,0 @@
|
|||
From 7f4c9c534aabe1315669e076d3fe0af0fd374cda Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Thu, 30 May 2024 03:13:19 +0100
|
||||
Subject: [PATCH 2/9] block: partitions: populate fwnode
|
||||
|
||||
Let block partitions to be represented by a firmware node and hence
|
||||
allow them to being referenced e.g. for use with blk-nvmem.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
block/partitions/core.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 41 insertions(+)
|
||||
|
||||
--- a/block/partitions/core.c
|
||||
+++ b/block/partitions/core.c
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/raid/detect.h>
|
||||
+#include <linux/property.h>
|
||||
+
|
||||
#include "check.h"
|
||||
|
||||
static int (*const check_part[])(struct parsed_partitions *) = {
|
||||
@@ -292,6 +294,40 @@ static ssize_t whole_disk_show(struct de
|
||||
}
|
||||
static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
|
||||
|
||||
+static struct fwnode_handle *find_partition_fwnode(struct block_device *bdev)
|
||||
+{
|
||||
+ struct fwnode_handle *fw_parts, *fw_part;
|
||||
+ struct device *ddev = disk_to_dev(bdev->bd_disk);
|
||||
+ const char *partname, *uuid;
|
||||
+ u32 partno;
|
||||
+
|
||||
+ fw_parts = device_get_named_child_node(ddev, "partitions");
|
||||
+ if (!fw_parts)
|
||||
+ return NULL;
|
||||
+
|
||||
+ fwnode_for_each_child_node(fw_parts, fw_part) {
|
||||
+ if (!fwnode_property_read_string(fw_part, "uuid", &uuid) &&
|
||||
+ (!bdev->bd_meta_info || strncmp(uuid,
|
||||
+ bdev->bd_meta_info->uuid,
|
||||
+ PARTITION_META_INFO_UUIDLTH)))
|
||||
+ continue;
|
||||
+
|
||||
+ if (!fwnode_property_read_string(fw_part, "partname", &partname) &&
|
||||
+ (!bdev->bd_meta_info || strncmp(partname,
|
||||
+ bdev->bd_meta_info->volname,
|
||||
+ PARTITION_META_INFO_VOLNAMELTH)))
|
||||
+ continue;
|
||||
+
|
||||
+ if (!fwnode_property_read_u32(fw_part, "partno", &partno) &&
|
||||
+ bdev->bd_partno != partno)
|
||||
+ continue;
|
||||
+
|
||||
+ return fw_part;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Must be called either with open_mutex held, before a disk can be opened or
|
||||
* after all disk users are gone.
|
||||
@@ -374,6 +410,8 @@ static struct block_device *add_partitio
|
||||
goto out_put;
|
||||
}
|
||||
|
||||
+ device_set_node(pdev, find_partition_fwnode(bdev));
|
||||
+
|
||||
/* delay uevent until 'holders' subdir is created */
|
||||
dev_set_uevent_suppress(pdev, 1);
|
||||
err = device_add(pdev);
|
|
@ -1,19 +0,0 @@
|
|||
From: Piotr Dymacz <pepe2k@gmail.com>
|
||||
Subject: kernel/mtd: add support for EON EN25Q128
|
||||
|
||||
Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/eon.c
|
||||
+++ b/drivers/mtd/spi-nor/eon.c
|
||||
@@ -17,6 +17,8 @@ static const struct flash_info eon_nor_p
|
||||
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128) },
|
||||
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
+ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256)
|
||||
+ NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
|
||||
{ "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32)
|
|
@ -1,21 +0,0 @@
|
|||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Subject: kernel/mtd: add support for EON EN25QX128A
|
||||
|
||||
Add support for EON EN25QX128A with no flags as it does
|
||||
support SFDP parsing.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/eon.c
|
||||
+++ b/drivers/mtd/spi-nor/eon.c
|
||||
@@ -19,6 +19,7 @@ static const struct flash_info eon_nor_p
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
+ { "en25qx128a", INFO(0x1c7118, 0, 64 * 1024, 256) },
|
||||
{ "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ) },
|
||||
{ "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32)
|
|
@ -1,23 +0,0 @@
|
|||
From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001
|
||||
From: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
Date: Mon, 6 Jan 2020 13:07:56 +0100
|
||||
Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05
|
||||
|
||||
Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/gigadevice.c
|
||||
+++ b/drivers/mtd/spi-nor/gigadevice.c
|
||||
@@ -34,6 +34,10 @@ static const struct spi_nor_fixups gd25q
|
||||
};
|
||||
|
||||
static const struct flash_info gigadevice_nor_parts[] = {
|
||||
+ { "gd25q05", INFO(0xc84010, 0, 64 * 1024, 1)
|
||||
+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
+ SPI_NOR_QUAD_READ) },
|
||||
{ "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32)
|
||||
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
|
@ -1,23 +0,0 @@
|
|||
From f8943df3beb0d3f9754bb35320c3a378727175a8 Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Thu, 14 Jul 2022 08:38:07 +0200
|
||||
Subject: [PATCH] spi-nor/gigadevic: add gd25q512
|
||||
|
||||
---
|
||||
drivers/mtd/spi-nor/gigadevice.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/gigadevice.c
|
||||
+++ b/drivers/mtd/spi-nor/gigadevice.c
|
||||
@@ -71,6 +71,11 @@ static const struct flash_info gigadevic
|
||||
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
|
||||
FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
|
||||
.fixups = &gd25q256_fixups },
|
||||
+ { "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024)
|
||||
+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB)
|
||||
+ FIXUP_FLAGS(SPI_NOR_4B_OPCODES)
|
||||
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
+ SPI_NOR_QUAD_READ) },
|
||||
};
|
||||
|
||||
const struct spi_nor_manufacturer spi_nor_gigadevice = {
|
|
@ -1,24 +0,0 @@
|
|||
From 87363cc0e522de3294ea6ae10fb468d2a8d6fb2f Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Wed, 13 Jul 2022 12:17:21 +0200
|
||||
Subject: [PATCH] spi-nor/esmt.c: add esmt f25l16pa
|
||||
|
||||
This fixes support for Dongwon T&I DW02-412H which uses F25L16PA(2S)
|
||||
flash.
|
||||
|
||||
---
|
||||
drivers/mtd/spi-nor/esmt.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/esmt.c
|
||||
+++ b/drivers/mtd/spi-nor/esmt.c
|
||||
@@ -10,6 +10,9 @@
|
||||
|
||||
static const struct flash_info esmt_nor_parts[] = {
|
||||
/* ESMT */
|
||||
+ { "f25l16pa-2s", INFO(0x8c2115, 0, 64 * 1024, 32)
|
||||
+ FLAGS(SPI_NOR_HAS_LOCK)
|
||||
+ NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64)
|
||||
FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_SWP_IS_VOLATILE)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
|
@ -1,25 +0,0 @@
|
|||
From f6b33d850f7f12555df2fa0e3349b33427bf5890 Mon Sep 17 00:00:00 2001
|
||||
From: OpenWrt community <openwrt-devel@lists.openwrt.org>
|
||||
Date: Wed, 13 Jul 2022 12:19:01 +0200
|
||||
Subject: [PATCH] spi-nor/xmc.c: add xm25qh128c
|
||||
|
||||
The XMC XM25QH128C is a 16MB SPI NOR chip. The patch is verified on
|
||||
Ruijie RG-EW3200GX PRO.
|
||||
Datasheet available at https://www.xmcwh.com/uploads/435/XM25QH128C.pdf
|
||||
|
||||
---
|
||||
drivers/mtd/spi-nor/xmc.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/xmc.c
|
||||
+++ b/drivers/mtd/spi-nor/xmc.c
|
||||
@@ -16,6 +16,9 @@ static const struct flash_info xmc_nor_p
|
||||
{ "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ) },
|
||||
+ { "XM25QH128C", INFO(0x204018, 0, 64 * 1024, 256)
|
||||
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
+ SPI_NOR_QUAD_READ) },
|
||||
};
|
||||
|
||||
const struct spi_nor_manufacturer spi_nor_xmc = {
|
|
@ -1,170 +0,0 @@
|
|||
From f32085fc0b87049491b07e198d924d738a1a2834 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Danzberger <daniel@dd-wrt.com>
|
||||
Date: Wed, 3 Aug 2022 17:31:03 +0200
|
||||
Subject: [PATCH] mtd: spinand: Add support for Etron EM73D044VCx
|
||||
|
||||
Airoha is a new ARM platform based on Cortex-A53 which has recently been
|
||||
merged into linux-next.
|
||||
|
||||
Due to BootROM limitations on this platform, the Cortex-A53 can't run in
|
||||
Aarch64 mode and code must be compiled for 32-Bit ARM.
|
||||
|
||||
This support is based mostly on those linux-next commits backported
|
||||
for kernel 5.15.
|
||||
|
||||
Patches:
|
||||
1 - platform support = linux-next
|
||||
2 - clock driver = linux-next
|
||||
3 - gpio driver = linux-next
|
||||
4 - linux,usable-memory-range dts support = linux-next
|
||||
5 - mtd spinand driver
|
||||
6 - spi driver
|
||||
7 - pci driver (kconfig only, uses mediatek PCI) = linux-next
|
||||
|
||||
Still missing:
|
||||
- Ethernet driver
|
||||
- Sysupgrade support
|
||||
|
||||
A.t.m there exists one subtarget EN7523 with only one evaluation
|
||||
board.
|
||||
|
||||
The initramfs can be run with the following commands from u-boot:
|
||||
-
|
||||
u-boot> setenv bootfile \
|
||||
openwrt-airoha-airoha_en7523-evb-initramfs-kernel.bin
|
||||
u-boot> tftpboot
|
||||
u-boot> bootm 0x81800000
|
||||
-
|
||||
|
||||
Submitted-by: Daniel Danzberger <daniel@dd-wrt.com>
|
||||
|
||||
--- a/drivers/mtd/nand/spi/Makefile
|
||||
+++ b/drivers/mtd/nand/spi/Makefile
|
||||
@@ -1,4 +1,4 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
-spinand-objs := core.o alliancememory.o ato.o esmt.o gigadevice.o macronix.o
|
||||
-spinand-objs += micron.o paragon.o toshiba.o winbond.o xtx.o
|
||||
+spinand-objs := core.o alliancememory.o ato.o esmt.o etron.o gigadevice.o
|
||||
+spinand-objs += macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
--- a/drivers/mtd/nand/spi/core.c
|
||||
+++ b/drivers/mtd/nand/spi/core.c
|
||||
@@ -940,6 +940,7 @@ static const struct spinand_manufacturer
|
||||
&alliancememory_spinand_manufacturer,
|
||||
&ato_spinand_manufacturer,
|
||||
&esmt_c8_spinand_manufacturer,
|
||||
+ &etron_spinand_manufacturer,
|
||||
&gigadevice_spinand_manufacturer,
|
||||
¯onix_spinand_manufacturer,
|
||||
µn_spinand_manufacturer,
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/nand/spi/etron.c
|
||||
@@ -0,0 +1,98 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mtd/spinand.h>
|
||||
+
|
||||
+#define SPINAND_MFR_ETRON 0xd5
|
||||
+
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
+
|
||||
+static int etron_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *oobregion)
|
||||
+{
|
||||
+ if (section)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ oobregion->offset = 72;
|
||||
+ oobregion->length = 56;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int etron_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *oobregion)
|
||||
+{
|
||||
+ if (section)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ oobregion->offset = 1;
|
||||
+ oobregion->length = 71;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int etron_ecc_get_status(struct spinand_device *spinand, u8 status)
|
||||
+{
|
||||
+ switch (status & STATUS_ECC_MASK) {
|
||||
+ case STATUS_ECC_NO_BITFLIPS:
|
||||
+ return 0;
|
||||
+
|
||||
+ case STATUS_ECC_HAS_BITFLIPS:
|
||||
+ /* Between 1-7 bitflips were corrected */
|
||||
+ return 7;
|
||||
+
|
||||
+ case STATUS_ECC_MASK:
|
||||
+ /* Maximum bitflips were corrected */
|
||||
+ return 8;
|
||||
+
|
||||
+ case STATUS_ECC_UNCOR_ERROR:
|
||||
+ return -EBADMSG;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static const struct mtd_ooblayout_ops etron_ooblayout = {
|
||||
+ .ecc = etron_ooblayout_ecc,
|
||||
+ .free = etron_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
+static const struct spinand_info etron_spinand_table[] = {
|
||||
+ SPINAND_INFO("EM73D044VCx",
|
||||
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_ADDR, 0x1f),
|
||||
+ // bpc, pagesize, oobsize, pagesperblock, bperlun, maxbadplun, ppl, lpt, #t
|
||||
+ 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(&etron_ooblayout, etron_ecc_get_status)),
|
||||
+};
|
||||
+
|
||||
+static const struct spinand_manufacturer_ops etron_spinand_manuf_ops = {
|
||||
+};
|
||||
+
|
||||
+const struct spinand_manufacturer etron_spinand_manufacturer = {
|
||||
+ .id = SPINAND_MFR_ETRON,
|
||||
+ .name = "Etron",
|
||||
+ .chips = etron_spinand_table,
|
||||
+ .nchips = ARRAY_SIZE(etron_spinand_table),
|
||||
+ .ops = &etron_spinand_manuf_ops,
|
||||
+};
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -263,6 +263,7 @@ struct spinand_manufacturer {
|
||||
extern const struct spinand_manufacturer alliancememory_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer ato_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer esmt_c8_spinand_manufacturer;
|
||||
+extern const struct spinand_manufacturer etron_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
|
@ -1,23 +0,0 @@
|
|||
From: Joe Mullally <jwmullally@gmail.com>
|
||||
Subject: mtd/spi-nor/xmc: add support for XMC XM25QH64C
|
||||
|
||||
The XMC XM25QH64C is a 8MB SPI NOR chip. The patch is verified on TL-WPA8631P v3.
|
||||
Datasheet available at https://www.xmcwh.com/uploads/442/XM25QH64C.pdf
|
||||
|
||||
Signed-off-by: Joe Mullally <jwmullally@gmail.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/xmc.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/xmc.c
|
||||
+++ b/drivers/mtd/spi-nor/xmc.c
|
||||
@@ -13,6 +13,9 @@ static const struct flash_info xmc_nor_p
|
||||
{ "XM25QH64A", INFO(0x207017, 0, 64 * 1024, 128)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ) },
|
||||
+ { "XM25QH64C", INFO(0x204017, 0, 64 * 1024, 128)
|
||||
+ NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
+ SPI_NOR_QUAD_READ) },
|
||||
{ "XM25QH128A", INFO(0x207018, 0, 64 * 1024, 256)
|
||||
NO_SFDP_FLAGS(SECT_4K | SPI_NOR_DUAL_READ |
|
||||
SPI_NOR_QUAD_READ) },
|
|
@ -1,32 +0,0 @@
|
|||
From 8bf2ce6ea4ee840b70f55a27f80e1cd308051b13 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Hainke <vincent@systemli.org>
|
||||
Date: Mon, 27 Dec 2021 00:38:13 +0100
|
||||
Subject: [PATCH 1/2] mtd: spi-nor: locking support for MX25L6405D
|
||||
|
||||
Macronix MX25L6405D supports locking with four block-protection bits.
|
||||
Currently, the driver only sets three bits. If the bootloader does not
|
||||
sustain the flash chip in an unlocked state, the flash might be
|
||||
non-writeable. Add the corresponding flag to enable locking support with
|
||||
four bits in the status register.
|
||||
|
||||
Tested on Nanostation M2 XM.
|
||||
|
||||
Similar to commit 7ea40b54e83b ("mtd: spi-nor: enable locking support for
|
||||
MX25L12805D")
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
Signed-off-by: Nick Hainke <vincent@systemli.org>
|
||||
---
|
||||
drivers/mtd/spi-nor/macronix.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/macronix.c
|
||||
+++ b/drivers/mtd/spi-nor/macronix.c
|
||||
@@ -48,6 +48,7 @@ static const struct flash_info macronix_
|
||||
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128)
|
||||
+ FLAGS(SPI_NOR_HAS_LOCK | SPI_NOR_4BIT_BP)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
||||
{ "mx25u2033e", INFO(0xc22532, 0, 64 * 1024, 4)
|
||||
NO_SFDP_FLAGS(SECT_4K) },
|
|
@ -1,578 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Tue, 23 Apr 2024 11:23:03 +0200
|
||||
Subject: [PATCH] net: add TCP fraglist GRO support
|
||||
|
||||
When forwarding TCP after GRO, software segmentation is very expensive,
|
||||
especially when the checksum needs to be recalculated.
|
||||
One case where that's currently unavoidable is when routing packets over
|
||||
PPPoE. Performance improves significantly when using fraglist GRO
|
||||
implemented in the same way as for UDP.
|
||||
|
||||
Here's a measurement of running 2 TCP streams through a MediaTek MT7622
|
||||
device (2-core Cortex-A53), which runs NAT with flow offload enabled from
|
||||
one ethernet port to PPPoE on another ethernet port + cake qdisc set to
|
||||
1Gbps.
|
||||
|
||||
rx-gro-list off: 630 Mbit/s, CPU 35% idle
|
||||
rx-gro-list on: 770 Mbit/s, CPU 40% idle
|
||||
|
||||
Signe-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/gro.h
|
||||
+++ b/include/net/gro.h
|
||||
@@ -439,6 +439,7 @@ static inline __wsum ip6_gro_compute_pse
|
||||
}
|
||||
|
||||
int skb_gro_receive(struct sk_buff *p, struct sk_buff *skb);
|
||||
+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb);
|
||||
|
||||
/* Pass the currently batched GRO_NORMAL SKBs up to the stack. */
|
||||
static inline void gro_normal_list(struct napi_struct *napi)
|
||||
--- a/include/net/tcp.h
|
||||
+++ b/include/net/tcp.h
|
||||
@@ -2083,7 +2083,10 @@ void tcp_v4_destroy_sock(struct sock *sk
|
||||
|
||||
struct sk_buff *tcp_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features);
|
||||
-struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb);
|
||||
+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb);
|
||||
+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th);
|
||||
+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
|
||||
+ struct tcphdr *th);
|
||||
INDIRECT_CALLABLE_DECLARE(int tcp4_gro_complete(struct sk_buff *skb, int thoff));
|
||||
INDIRECT_CALLABLE_DECLARE(struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb));
|
||||
INDIRECT_CALLABLE_DECLARE(int tcp6_gro_complete(struct sk_buff *skb, int thoff));
|
||||
--- a/net/core/gro.c
|
||||
+++ b/net/core/gro.c
|
||||
@@ -233,6 +233,33 @@ done:
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
|
||||
+{
|
||||
+ if (unlikely(p->len + skb->len >= 65536))
|
||||
+ return -E2BIG;
|
||||
+
|
||||
+ if (NAPI_GRO_CB(p)->last == p)
|
||||
+ skb_shinfo(p)->frag_list = skb;
|
||||
+ else
|
||||
+ NAPI_GRO_CB(p)->last->next = skb;
|
||||
+
|
||||
+ skb_pull(skb, skb_gro_offset(skb));
|
||||
+
|
||||
+ NAPI_GRO_CB(p)->last = skb;
|
||||
+ NAPI_GRO_CB(p)->count++;
|
||||
+ p->data_len += skb->len;
|
||||
+
|
||||
+ /* sk ownership - if any - completely transferred to the aggregated packet */
|
||||
+ skb->destructor = NULL;
|
||||
+ skb->sk = NULL;
|
||||
+ p->truesize += skb->truesize;
|
||||
+ p->len += skb->len;
|
||||
+
|
||||
+ NAPI_GRO_CB(skb)->same_flow = 1;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
|
||||
static void napi_gro_complete(struct napi_struct *napi, struct sk_buff *skb)
|
||||
{
|
||||
--- a/net/ipv4/tcp_offload.c
|
||||
+++ b/net/ipv4/tcp_offload.c
|
||||
@@ -28,6 +28,70 @@ static void tcp_gso_tstamp(struct sk_buf
|
||||
}
|
||||
}
|
||||
|
||||
+static void __tcpv4_gso_segment_csum(struct sk_buff *seg,
|
||||
+ __be32 *oldip, __be32 newip,
|
||||
+ __be16 *oldport, __be16 newport)
|
||||
+{
|
||||
+ struct tcphdr *th;
|
||||
+ struct iphdr *iph;
|
||||
+
|
||||
+ if (*oldip == newip && *oldport == newport)
|
||||
+ return;
|
||||
+
|
||||
+ th = tcp_hdr(seg);
|
||||
+ iph = ip_hdr(seg);
|
||||
+
|
||||
+ inet_proto_csum_replace4(&th->check, seg, *oldip, newip, true);
|
||||
+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
|
||||
+ *oldport = newport;
|
||||
+
|
||||
+ csum_replace4(&iph->check, *oldip, newip);
|
||||
+ *oldip = newip;
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *__tcpv4_gso_segment_list_csum(struct sk_buff *segs)
|
||||
+{
|
||||
+ const struct tcphdr *th;
|
||||
+ const struct iphdr *iph;
|
||||
+ struct sk_buff *seg;
|
||||
+ struct tcphdr *th2;
|
||||
+ struct iphdr *iph2;
|
||||
+
|
||||
+ seg = segs;
|
||||
+ th = tcp_hdr(seg);
|
||||
+ iph = ip_hdr(seg);
|
||||
+ th2 = tcp_hdr(seg->next);
|
||||
+ iph2 = ip_hdr(seg->next);
|
||||
+
|
||||
+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
|
||||
+ iph->daddr == iph2->daddr && iph->saddr == iph2->saddr)
|
||||
+ return segs;
|
||||
+
|
||||
+ while ((seg = seg->next)) {
|
||||
+ th2 = tcp_hdr(seg);
|
||||
+ iph2 = ip_hdr(seg);
|
||||
+
|
||||
+ __tcpv4_gso_segment_csum(seg,
|
||||
+ &iph2->saddr, iph->saddr,
|
||||
+ &th2->source, th->source);
|
||||
+ __tcpv4_gso_segment_csum(seg,
|
||||
+ &iph2->daddr, iph->daddr,
|
||||
+ &th2->dest, th->dest);
|
||||
+ }
|
||||
+
|
||||
+ return segs;
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *__tcp4_gso_segment_list(struct sk_buff *skb,
|
||||
+ netdev_features_t features)
|
||||
+{
|
||||
+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
|
||||
+ if (IS_ERR(skb))
|
||||
+ return skb;
|
||||
+
|
||||
+ return __tcpv4_gso_segment_list_csum(skb);
|
||||
+}
|
||||
+
|
||||
static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
@@ -37,6 +101,9 @@ static struct sk_buff *tcp4_gso_segment(
|
||||
if (!pskb_may_pull(skb, sizeof(struct tcphdr)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
|
||||
+ return __tcp4_gso_segment_list(skb, features);
|
||||
+
|
||||
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
struct tcphdr *th = tcp_hdr(skb);
|
||||
@@ -178,61 +245,76 @@ out:
|
||||
return segs;
|
||||
}
|
||||
|
||||
-struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||
+struct sk_buff *tcp_gro_lookup(struct list_head *head, struct tcphdr *th)
|
||||
{
|
||||
- struct sk_buff *pp = NULL;
|
||||
+ struct tcphdr *th2;
|
||||
struct sk_buff *p;
|
||||
+
|
||||
+ list_for_each_entry(p, head, list) {
|
||||
+ if (!NAPI_GRO_CB(p)->same_flow)
|
||||
+ continue;
|
||||
+
|
||||
+ th2 = tcp_hdr(p);
|
||||
+ if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
|
||||
+ NAPI_GRO_CB(p)->same_flow = 0;
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ return p;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+struct tcphdr *tcp_gro_pull_header(struct sk_buff *skb)
|
||||
+{
|
||||
+ unsigned int thlen, hlen, off;
|
||||
struct tcphdr *th;
|
||||
- struct tcphdr *th2;
|
||||
- unsigned int len;
|
||||
- unsigned int thlen;
|
||||
- __be32 flags;
|
||||
- unsigned int mss = 1;
|
||||
- unsigned int hlen;
|
||||
- unsigned int off;
|
||||
- int flush = 1;
|
||||
- int i;
|
||||
|
||||
off = skb_gro_offset(skb);
|
||||
hlen = off + sizeof(*th);
|
||||
th = skb_gro_header(skb, hlen, off);
|
||||
if (unlikely(!th))
|
||||
- goto out;
|
||||
+ return NULL;
|
||||
|
||||
thlen = th->doff * 4;
|
||||
if (thlen < sizeof(*th))
|
||||
- goto out;
|
||||
+ return NULL;
|
||||
|
||||
hlen = off + thlen;
|
||||
if (skb_gro_header_hard(skb, hlen)) {
|
||||
th = skb_gro_header_slow(skb, hlen, off);
|
||||
if (unlikely(!th))
|
||||
- goto out;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
skb_gro_pull(skb, thlen);
|
||||
|
||||
- len = skb_gro_len(skb);
|
||||
- flags = tcp_flag_word(th);
|
||||
-
|
||||
- list_for_each_entry(p, head, list) {
|
||||
- if (!NAPI_GRO_CB(p)->same_flow)
|
||||
- continue;
|
||||
+ return th;
|
||||
+}
|
||||
|
||||
- th2 = tcp_hdr(p);
|
||||
+struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb,
|
||||
+ struct tcphdr *th)
|
||||
+{
|
||||
+ unsigned int thlen = th->doff * 4;
|
||||
+ struct sk_buff *pp = NULL;
|
||||
+ struct sk_buff *p;
|
||||
+ struct tcphdr *th2;
|
||||
+ unsigned int len;
|
||||
+ __be32 flags;
|
||||
+ unsigned int mss = 1;
|
||||
+ int flush = 1;
|
||||
+ int i;
|
||||
|
||||
- if (*(u32 *)&th->source ^ *(u32 *)&th2->source) {
|
||||
- NAPI_GRO_CB(p)->same_flow = 0;
|
||||
- continue;
|
||||
- }
|
||||
+ len = skb_gro_len(skb);
|
||||
+ flags = tcp_flag_word(th);
|
||||
|
||||
- goto found;
|
||||
- }
|
||||
- p = NULL;
|
||||
- goto out_check_final;
|
||||
+ p = tcp_gro_lookup(head, th);
|
||||
+ if (!p)
|
||||
+ goto out_check_final;
|
||||
|
||||
-found:
|
||||
/* Include the IP ID check below from the inner most IP hdr */
|
||||
+ th2 = tcp_hdr(p);
|
||||
flush = NAPI_GRO_CB(p)->flush;
|
||||
flush |= (__force int)(flags & TCP_FLAG_CWR);
|
||||
flush |= (__force int)((flags ^ tcp_flag_word(th2)) &
|
||||
@@ -269,6 +351,19 @@ found:
|
||||
flush |= p->decrypted ^ skb->decrypted;
|
||||
#endif
|
||||
|
||||
+ if (unlikely(NAPI_GRO_CB(p)->is_flist)) {
|
||||
+ flush |= (__force int)(flags ^ tcp_flag_word(th2));
|
||||
+ flush |= skb->ip_summed != p->ip_summed;
|
||||
+ flush |= skb->csum_level != p->csum_level;
|
||||
+ flush |= !pskb_may_pull(skb, skb_gro_offset(skb));
|
||||
+ flush |= NAPI_GRO_CB(p)->count >= 64;
|
||||
+
|
||||
+ if (flush || skb_gro_receive_list(p, skb))
|
||||
+ mss = 1;
|
||||
+
|
||||
+ goto out_check_final;
|
||||
+ }
|
||||
+
|
||||
if (flush || skb_gro_receive(p, skb)) {
|
||||
mss = 1;
|
||||
goto out_check_final;
|
||||
@@ -290,7 +385,6 @@ out_check_final:
|
||||
if (p && (!NAPI_GRO_CB(skb)->same_flow || flush))
|
||||
pp = p;
|
||||
|
||||
-out:
|
||||
NAPI_GRO_CB(skb)->flush |= (flush != 0);
|
||||
|
||||
return pp;
|
||||
@@ -314,18 +408,58 @@ void tcp_gro_complete(struct sk_buff *sk
|
||||
}
|
||||
EXPORT_SYMBOL(tcp_gro_complete);
|
||||
|
||||
+static void tcp4_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
|
||||
+ struct tcphdr *th)
|
||||
+{
|
||||
+ const struct iphdr *iph;
|
||||
+ struct sk_buff *p;
|
||||
+ struct sock *sk;
|
||||
+ struct net *net;
|
||||
+ int iif, sdif;
|
||||
+
|
||||
+ if (!(skb->dev->features & NETIF_F_GRO_FRAGLIST))
|
||||
+ return;
|
||||
+
|
||||
+ p = tcp_gro_lookup(head, th);
|
||||
+ if (p) {
|
||||
+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ inet_get_iif_sdif(skb, &iif, &sdif);
|
||||
+ iph = skb_gro_network_header(skb);
|
||||
+ net = dev_net(skb->dev);
|
||||
+ sk = __inet_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
|
||||
+ iph->saddr, th->source,
|
||||
+ iph->daddr, ntohs(th->dest),
|
||||
+ iif, sdif);
|
||||
+ NAPI_GRO_CB(skb)->is_flist = !sk;
|
||||
+ if (sk)
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||
{
|
||||
+ struct tcphdr *th;
|
||||
+
|
||||
/* Don't bother verifying checksum if we're going to flush anyway. */
|
||||
if (!NAPI_GRO_CB(skb)->flush &&
|
||||
skb_gro_checksum_validate(skb, IPPROTO_TCP,
|
||||
- inet_gro_compute_pseudo)) {
|
||||
- NAPI_GRO_CB(skb)->flush = 1;
|
||||
- return NULL;
|
||||
- }
|
||||
+ inet_gro_compute_pseudo))
|
||||
+ goto flush;
|
||||
+
|
||||
+ th = tcp_gro_pull_header(skb);
|
||||
+ if (!th)
|
||||
+ goto flush;
|
||||
|
||||
- return tcp_gro_receive(head, skb);
|
||||
+ tcp4_check_fraglist_gro(head, skb, th);
|
||||
+
|
||||
+ return tcp_gro_receive(head, skb, th);
|
||||
+
|
||||
+flush:
|
||||
+ NAPI_GRO_CB(skb)->flush = 1;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
INDIRECT_CALLABLE_SCOPE int tcp4_gro_complete(struct sk_buff *skb, int thoff)
|
||||
@@ -333,6 +467,15 @@ INDIRECT_CALLABLE_SCOPE int tcp4_gro_com
|
||||
const struct iphdr *iph = ip_hdr(skb);
|
||||
struct tcphdr *th = tcp_hdr(skb);
|
||||
|
||||
+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
|
||||
+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV4;
|
||||
+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
|
||||
+
|
||||
+ __skb_incr_checksum_unnecessary(skb);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr,
|
||||
iph->daddr, 0);
|
||||
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4;
|
||||
--- a/net/ipv4/udp_offload.c
|
||||
+++ b/net/ipv4/udp_offload.c
|
||||
@@ -433,33 +433,6 @@ out:
|
||||
return segs;
|
||||
}
|
||||
|
||||
-static int skb_gro_receive_list(struct sk_buff *p, struct sk_buff *skb)
|
||||
-{
|
||||
- if (unlikely(p->len + skb->len >= 65536))
|
||||
- return -E2BIG;
|
||||
-
|
||||
- if (NAPI_GRO_CB(p)->last == p)
|
||||
- skb_shinfo(p)->frag_list = skb;
|
||||
- else
|
||||
- NAPI_GRO_CB(p)->last->next = skb;
|
||||
-
|
||||
- skb_pull(skb, skb_gro_offset(skb));
|
||||
-
|
||||
- NAPI_GRO_CB(p)->last = skb;
|
||||
- NAPI_GRO_CB(p)->count++;
|
||||
- p->data_len += skb->len;
|
||||
-
|
||||
- /* sk ownership - if any - completely transferred to the aggregated packet */
|
||||
- skb->destructor = NULL;
|
||||
- skb->sk = NULL;
|
||||
- p->truesize += skb->truesize;
|
||||
- p->len += skb->len;
|
||||
-
|
||||
- NAPI_GRO_CB(skb)->same_flow = 1;
|
||||
-
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
|
||||
#define UDP_GRO_CNT_MAX 64
|
||||
static struct sk_buff *udp_gro_receive_segment(struct list_head *head,
|
||||
--- a/net/ipv6/tcpv6_offload.c
|
||||
+++ b/net/ipv6/tcpv6_offload.c
|
||||
@@ -7,24 +7,67 @@
|
||||
*/
|
||||
#include <linux/indirect_call_wrapper.h>
|
||||
#include <linux/skbuff.h>
|
||||
+#include <net/inet6_hashtables.h>
|
||||
#include <net/gro.h>
|
||||
#include <net/protocol.h>
|
||||
#include <net/tcp.h>
|
||||
#include <net/ip6_checksum.h>
|
||||
#include "ip6_offload.h"
|
||||
|
||||
+static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,
|
||||
+ struct tcphdr *th)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_IPV6)
|
||||
+ const struct ipv6hdr *hdr;
|
||||
+ struct sk_buff *p;
|
||||
+ struct sock *sk;
|
||||
+ struct net *net;
|
||||
+ int iif, sdif;
|
||||
+
|
||||
+ if (!(skb->dev->features & NETIF_F_GRO_FRAGLIST))
|
||||
+ return;
|
||||
+
|
||||
+ p = tcp_gro_lookup(head, th);
|
||||
+ if (p) {
|
||||
+ NAPI_GRO_CB(skb)->is_flist = NAPI_GRO_CB(p)->is_flist;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ inet6_get_iif_sdif(skb, &iif, &sdif);
|
||||
+ hdr = skb_gro_network_header(skb);
|
||||
+ net = dev_net(skb->dev);
|
||||
+ sk = __inet6_lookup_established(net, net->ipv4.tcp_death_row.hashinfo,
|
||||
+ &hdr->saddr, th->source,
|
||||
+ &hdr->daddr, ntohs(th->dest),
|
||||
+ iif, sdif);
|
||||
+ NAPI_GRO_CB(skb)->is_flist = !sk;
|
||||
+ if (sk)
|
||||
+ sock_put(sk);
|
||||
+#endif /* IS_ENABLED(CONFIG_IPV6) */
|
||||
+}
|
||||
+
|
||||
INDIRECT_CALLABLE_SCOPE
|
||||
struct sk_buff *tcp6_gro_receive(struct list_head *head, struct sk_buff *skb)
|
||||
{
|
||||
+ struct tcphdr *th;
|
||||
+
|
||||
/* Don't bother verifying checksum if we're going to flush anyway. */
|
||||
if (!NAPI_GRO_CB(skb)->flush &&
|
||||
skb_gro_checksum_validate(skb, IPPROTO_TCP,
|
||||
- ip6_gro_compute_pseudo)) {
|
||||
- NAPI_GRO_CB(skb)->flush = 1;
|
||||
- return NULL;
|
||||
- }
|
||||
+ ip6_gro_compute_pseudo))
|
||||
+ goto flush;
|
||||
|
||||
- return tcp_gro_receive(head, skb);
|
||||
+ th = tcp_gro_pull_header(skb);
|
||||
+ if (!th)
|
||||
+ goto flush;
|
||||
+
|
||||
+ tcp6_check_fraglist_gro(head, skb, th);
|
||||
+
|
||||
+ return tcp_gro_receive(head, skb, th);
|
||||
+
|
||||
+flush:
|
||||
+ NAPI_GRO_CB(skb)->flush = 1;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
INDIRECT_CALLABLE_SCOPE int tcp6_gro_complete(struct sk_buff *skb, int thoff)
|
||||
@@ -32,6 +75,15 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
|
||||
const struct ipv6hdr *iph = ipv6_hdr(skb);
|
||||
struct tcphdr *th = tcp_hdr(skb);
|
||||
|
||||
+ if (unlikely(NAPI_GRO_CB(skb)->is_flist)) {
|
||||
+ skb_shinfo(skb)->gso_type |= SKB_GSO_FRAGLIST | SKB_GSO_TCPV6;
|
||||
+ skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count;
|
||||
+
|
||||
+ __skb_incr_checksum_unnecessary(skb);
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr,
|
||||
&iph->daddr, 0);
|
||||
skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6;
|
||||
@@ -40,6 +92,61 @@ INDIRECT_CALLABLE_SCOPE int tcp6_gro_com
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void __tcpv6_gso_segment_csum(struct sk_buff *seg,
|
||||
+ __be16 *oldport, __be16 newport)
|
||||
+{
|
||||
+ struct tcphdr *th;
|
||||
+
|
||||
+ if (*oldport == newport)
|
||||
+ return;
|
||||
+
|
||||
+ th = tcp_hdr(seg);
|
||||
+ inet_proto_csum_replace2(&th->check, seg, *oldport, newport, false);
|
||||
+ *oldport = newport;
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *__tcpv6_gso_segment_list_csum(struct sk_buff *segs)
|
||||
+{
|
||||
+ const struct tcphdr *th;
|
||||
+ const struct ipv6hdr *iph;
|
||||
+ struct sk_buff *seg;
|
||||
+ struct tcphdr *th2;
|
||||
+ struct ipv6hdr *iph2;
|
||||
+
|
||||
+ seg = segs;
|
||||
+ th = tcp_hdr(seg);
|
||||
+ iph = ipv6_hdr(seg);
|
||||
+ th2 = tcp_hdr(seg->next);
|
||||
+ iph2 = ipv6_hdr(seg->next);
|
||||
+
|
||||
+ if (!(*(const u32 *)&th->source ^ *(const u32 *)&th2->source) &&
|
||||
+ ipv6_addr_equal(&iph->saddr, &iph2->saddr) &&
|
||||
+ ipv6_addr_equal(&iph->daddr, &iph2->daddr))
|
||||
+ return segs;
|
||||
+
|
||||
+ while ((seg = seg->next)) {
|
||||
+ th2 = tcp_hdr(seg);
|
||||
+ iph2 = ipv6_hdr(seg);
|
||||
+
|
||||
+ iph2->saddr = iph->saddr;
|
||||
+ iph2->daddr = iph->daddr;
|
||||
+ __tcpv6_gso_segment_csum(seg, &th2->source, th->source);
|
||||
+ __tcpv6_gso_segment_csum(seg, &th2->dest, th->dest);
|
||||
+ }
|
||||
+
|
||||
+ return segs;
|
||||
+}
|
||||
+
|
||||
+static struct sk_buff *__tcp6_gso_segment_list(struct sk_buff *skb,
|
||||
+ netdev_features_t features)
|
||||
+{
|
||||
+ skb = skb_segment_list(skb, features, skb_mac_header_len(skb));
|
||||
+ if (IS_ERR(skb))
|
||||
+ return skb;
|
||||
+
|
||||
+ return __tcpv6_gso_segment_list_csum(skb);
|
||||
+}
|
||||
+
|
||||
static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb,
|
||||
netdev_features_t features)
|
||||
{
|
||||
@@ -51,6 +158,9 @@ static struct sk_buff *tcp6_gso_segment(
|
||||
if (!pskb_may_pull(skb, sizeof(*th)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
+ if (skb_shinfo(skb)->gso_type & SKB_GSO_FRAGLIST)
|
||||
+ return __tcp6_gso_segment_list(skb, features);
|
||||
+
|
||||
if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) {
|
||||
const struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
||||
struct tcphdr *th = tcp_hdr(skb);
|
|
@ -1,21 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 21 Mar 2022 20:39:59 +0100
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: enable threaded NAPI
|
||||
|
||||
This can improve performance under load by ensuring that NAPI processing is
|
||||
not pinned on CPU 0.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_eth_soc.c
|
||||
@@ -4994,6 +4994,8 @@ static int mtk_probe(struct platform_dev
|
||||
* for NAPI to work
|
||||
*/
|
||||
init_dummy_netdev(ð->dummy_dev);
|
||||
+ eth->dummy_dev.threaded = 1;
|
||||
+ strcpy(eth->dummy_dev.name, "mtk_eth");
|
||||
netif_napi_add(ð->dummy_dev, ð->tx_napi, mtk_napi_tx);
|
||||
netif_napi_add(ð->dummy_dev, ð->rx_napi, mtk_napi_rx);
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 14 Feb 2024 15:24:41 +0100
|
||||
Subject: [PATCH] netfilter: nf_tables: fix bidirectional offload regression
|
||||
|
||||
Commit 8f84780b84d6 ("netfilter: flowtable: allow unidirectional rules")
|
||||
made unidirectional flow offload possible, while completely ignoring (and
|
||||
breaking) bidirectional flow offload for nftables.
|
||||
Add the missing flag that was left out as an exercise for the reader :)
|
||||
|
||||
Cc: Vlad Buslov <vladbu@nvidia.com>
|
||||
Fixes: 8f84780b84d6 ("netfilter: flowtable: allow unidirectional rules")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/netfilter/nft_flow_offload.c
|
||||
+++ b/net/netfilter/nft_flow_offload.c
|
||||
@@ -361,6 +361,7 @@ static void nft_flow_offload_eval(const
|
||||
ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
|
||||
}
|
||||
|
||||
+ __set_bit(NF_FLOW_HW_BIDIRECTIONAL, &flow->flags);
|
||||
ret = flow_offload_add(flowtable, flow);
|
||||
if (ret < 0)
|
||||
goto err_flow_add;
|
|
@ -1,158 +0,0 @@
|
|||
From b2d6ebf2f92f8695c83fa6979f4ab579c588df76 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Tue, 20 Jun 2023 07:57:38 +0200
|
||||
Subject: [PATCH 4/4] net: dsa: qca8k: add support for port_change_master
|
||||
|
||||
Add support for port_change_master to permit assigning an alternative
|
||||
CPU port if the switch have both CPU port connected or create a LAG on
|
||||
both CPU port and assign the LAG as DSA master.
|
||||
|
||||
On port change master request, we check if the master is a LAG.
|
||||
With LAG we compose the cpu_port_mask with the CPU port in the LAG, if
|
||||
master is a simple dsa_port, we derive the index.
|
||||
|
||||
Finally we apply the new cpu_port_mask to the LOOKUP MEMBER to permit
|
||||
the port to receive packet by the new CPU port setup for the port and we
|
||||
refresh the CPU ports LOOKUP MEMBER configuration to reflect the new
|
||||
user port state.
|
||||
|
||||
port_lag_join/leave is updated to refresh the user ports if we detect
|
||||
that the LAG is a DSA master and we have user port using it as a master.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/dsa/qca/qca8k-8xxx.c | 116 ++++++++++++++++++++++++++++++-
|
||||
1 file changed, 114 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
|
||||
@@ -1738,6 +1738,117 @@ qca8k_get_tag_protocol(struct dsa_switch
|
||||
return DSA_TAG_PROTO_QCA;
|
||||
}
|
||||
|
||||
+static int qca8k_port_change_master(struct dsa_switch *ds, int port,
|
||||
+ struct net_device *master,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct dsa_switch_tree *dst = ds->dst;
|
||||
+ struct qca8k_priv *priv = ds->priv;
|
||||
+ u8 cpu_port_mask = 0;
|
||||
+ struct dsa_port *dp;
|
||||
+ u32 val;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* With LAG of CPU port, compose the mask for port LOOKUP MEMBER */
|
||||
+ if (netif_is_lag_master(master)) {
|
||||
+ struct dsa_lag *lag;
|
||||
+ int id;
|
||||
+
|
||||
+ id = dsa_lag_id(dst, master);
|
||||
+ lag = dsa_lag_by_id(dst, id);
|
||||
+
|
||||
+ dsa_lag_foreach_port(dp, dst, lag)
|
||||
+ if (dsa_port_is_cpu(dp))
|
||||
+ cpu_port_mask |= BIT(dp->index);
|
||||
+ } else {
|
||||
+ dp = master->dsa_ptr;
|
||||
+ cpu_port_mask |= BIT(dp->index);
|
||||
+ }
|
||||
+
|
||||
+ /* Connect port to new cpu port */
|
||||
+ ret = regmap_read(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port), &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Reset connected CPU port in port LOOKUP MEMBER */
|
||||
+ val &= ~dsa_cpu_ports(ds);
|
||||
+ /* Assign the new CPU port in port LOOKUP MEMBER */
|
||||
+ val |= cpu_port_mask;
|
||||
+
|
||||
+ ret = regmap_update_bits(priv->regmap, QCA8K_PORT_LOOKUP_CTRL(port),
|
||||
+ QCA8K_PORT_LOOKUP_MEMBER,
|
||||
+ val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Refresh CPU port LOOKUP MEMBER with new port */
|
||||
+ dsa_tree_for_each_cpu_port(dp, ds->dst) {
|
||||
+ u32 reg = QCA8K_PORT_LOOKUP_CTRL(dp->index);
|
||||
+
|
||||
+ /* If CPU port in mask assign port, else remove port */
|
||||
+ if (BIT(dp->index) & cpu_port_mask)
|
||||
+ ret = regmap_set_bits(priv->regmap, reg, BIT(port));
|
||||
+ else
|
||||
+ ret = regmap_clear_bits(priv->regmap, reg, BIT(port));
|
||||
+
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qca8k_port_lag_refresh_user_ports(struct dsa_switch *ds,
|
||||
+ struct dsa_lag lag)
|
||||
+{
|
||||
+ struct net_device *lag_dev = lag.dev;
|
||||
+ struct dsa_port *dp;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Ignore if LAG is not a DSA master */
|
||||
+ if (!netif_is_lag_master(lag_dev))
|
||||
+ return 0;
|
||||
+
|
||||
+ dsa_switch_for_each_user_port(dp, ds) {
|
||||
+ /* Skip if assigned master is not the LAG */
|
||||
+ if (dsa_port_to_master(dp) != lag_dev)
|
||||
+ continue;
|
||||
+
|
||||
+ ret = qca8k_port_change_master(ds, dp->index,
|
||||
+ lag_dev, NULL);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int qca8xxx_port_lag_join(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_lag lag,
|
||||
+ struct netdev_lag_upper_info *info,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_port_lag_join(ds, port, lag, info, extack);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return qca8k_port_lag_refresh_user_ports(ds, lag);
|
||||
+}
|
||||
+
|
||||
+static int qca8xxx_port_lag_leave(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_lag lag)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = qca8k_port_lag_leave(ds, port, lag);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return qca8k_port_lag_refresh_user_ports(ds, lag);
|
||||
+}
|
||||
+
|
||||
static void
|
||||
qca8k_master_change(struct dsa_switch *ds, const struct net_device *master,
|
||||
bool operational)
|
||||
@@ -2024,8 +2135,9 @@ static const struct dsa_switch_ops qca8k
|
||||
.phylink_mac_link_down = qca8k_phylink_mac_link_down,
|
||||
.phylink_mac_link_up = qca8k_phylink_mac_link_up,
|
||||
.get_phy_flags = qca8k_get_phy_flags,
|
||||
- .port_lag_join = qca8k_port_lag_join,
|
||||
- .port_lag_leave = qca8k_port_lag_leave,
|
||||
+ .port_lag_join = qca8xxx_port_lag_join,
|
||||
+ .port_lag_leave = qca8xxx_port_lag_leave,
|
||||
+ .port_change_master = qca8k_port_change_master,
|
||||
.master_state_change = qca8k_master_change,
|
||||
.connect_tag_protocol = qca8k_connect_tag_protocol,
|
||||
};
|
|
@ -1,61 +0,0 @@
|
|||
From 312753d0aadba0f58841ae513b80fdbabc887523 Mon Sep 17 00:00:00 2001
|
||||
From: Chukun Pan <amadeus@jmu.edu.cn>
|
||||
Date: Wed, 8 Feb 2023 16:32:18 +0800
|
||||
Subject: [PATCH] net: phy: realtek: support switching between SGMII and
|
||||
2500BASE-X for RTL822x series
|
||||
|
||||
After commit ace6aba ("net: phy: realtek: rtl8221: allow to configure
|
||||
SERDES mode"), the rtl8221 phy can work in SGMII and 2500base-x modes
|
||||
respectively. So add interface automatic switching for rtl8221 phy to
|
||||
match various wire speeds.
|
||||
|
||||
Signed-off-by: Chukun Pan <amadeus@jmu.edu.cn>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 26 ++++++++++++++++++++++++--
|
||||
1 file changed, 24 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -714,6 +714,25 @@ static int rtl822x_config_aneg(struct ph
|
||||
return __genphy_config_aneg(phydev, ret);
|
||||
}
|
||||
|
||||
+static void rtl822x_update_interface(struct phy_device *phydev)
|
||||
+{
|
||||
+ /* Automatically switch SERDES interface between
|
||||
+ * SGMII and 2500-BaseX according to speed.
|
||||
+ */
|
||||
+ switch (phydev->speed) {
|
||||
+ case SPEED_2500:
|
||||
+ phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
|
||||
+ break;
|
||||
+ case SPEED_1000:
|
||||
+ case SPEED_100:
|
||||
+ case SPEED_10:
|
||||
+ phydev->interface = PHY_INTERFACE_MODE_SGMII;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int rtl822x_read_status(struct phy_device *phydev)
|
||||
{
|
||||
int ret;
|
||||
@@ -732,11 +751,14 @@ static int rtl822x_read_status(struct ph
|
||||
phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
|
||||
}
|
||||
|
||||
- ret = genphy_read_status(phydev);
|
||||
+ ret = rtlgen_read_status(phydev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- return rtlgen_get_speed(phydev);
|
||||
+ if (phydev->is_c45 && phydev->link)
|
||||
+ rtl822x_update_interface(phydev);
|
||||
+
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
|
|
@ -1,60 +0,0 @@
|
|||
From 92c8b9d558160d94b981dd8a2b9c47657627ffdc Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sat, 22 Apr 2023 01:23:08 +0100
|
||||
Subject: [PATCH 2/3] net: phy: realtek: use inline functions for 10GbE
|
||||
advertisement
|
||||
|
||||
Use existing generic inline functions to encode local advertisement
|
||||
of 10GbE link modes as well as to decode link-partner advertisement.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 22 +++++-----------------
|
||||
1 file changed, 5 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -69,10 +69,6 @@
|
||||
#define RTL_SUPPORTS_5000FULL BIT(14)
|
||||
#define RTL_SUPPORTS_2500FULL BIT(13)
|
||||
#define RTL_SUPPORTS_10000FULL BIT(0)
|
||||
-#define RTL_ADV_2500FULL BIT(7)
|
||||
-#define RTL_LPADV_10000FULL BIT(11)
|
||||
-#define RTL_LPADV_5000FULL BIT(6)
|
||||
-#define RTL_LPADV_2500FULL BIT(5)
|
||||
|
||||
#define RTL9000A_GINMR 0x14
|
||||
#define RTL9000A_GINMR_LINK_STATUS BIT(4)
|
||||
@@ -699,14 +695,11 @@ static int rtl822x_config_aneg(struct ph
|
||||
int ret = 0;
|
||||
|
||||
if (phydev->autoneg == AUTONEG_ENABLE) {
|
||||
- u16 adv2500 = 0;
|
||||
-
|
||||
- if (linkmode_test_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
- phydev->advertising))
|
||||
- adv2500 = RTL_ADV_2500FULL;
|
||||
-
|
||||
ret = phy_modify_paged_changed(phydev, 0xa5d, 0x12,
|
||||
- RTL_ADV_2500FULL, adv2500);
|
||||
+ MDIO_AN_10GBT_CTRL_ADV10G |
|
||||
+ MDIO_AN_10GBT_CTRL_ADV5G |
|
||||
+ MDIO_AN_10GBT_CTRL_ADV2_5G,
|
||||
+ linkmode_adv_to_mii_10gbt_adv_t(phydev->advertising));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
@@ -743,12 +736,7 @@ static int rtl822x_read_status(struct ph
|
||||
if (lpadv < 0)
|
||||
return lpadv;
|
||||
|
||||
- linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
|
||||
- phydev->lp_advertising, lpadv & RTL_LPADV_10000FULL);
|
||||
- linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
|
||||
- phydev->lp_advertising, lpadv & RTL_LPADV_5000FULL);
|
||||
- linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
|
||||
- phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
|
||||
+ mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
|
||||
}
|
||||
|
||||
ret = rtlgen_read_status(phydev);
|
|
@ -1,28 +0,0 @@
|
|||
From 929bb4d3cfbc7878326c0771a01a636d49c54b40 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sat, 22 Apr 2023 01:25:39 +0100
|
||||
Subject: [PATCH 3/3] net: phy: realtek: check validity of 10GbE link-partner
|
||||
advertisement
|
||||
|
||||
Only use link-partner advertisement bits for 10GbE modes if they are
|
||||
actually valid. Check LOCALOK and REMOTEOK bits and clear 10GbE modes
|
||||
unless both of them are set.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -736,6 +736,10 @@ static int rtl822x_read_status(struct ph
|
||||
if (lpadv < 0)
|
||||
return lpadv;
|
||||
|
||||
+ if (!(lpadv & MDIO_AN_10GBT_STAT_REMOK) ||
|
||||
+ !(lpadv & MDIO_AN_10GBT_STAT_LOCOK))
|
||||
+ lpadv = 0;
|
||||
+
|
||||
mii_10gbt_stat_mod_linkmode_lpa_t(phydev->lp_advertising, lpadv);
|
||||
}
|
||||
|
|
@ -1,84 +0,0 @@
|
|||
From 9155098547fb1172d4fa536f3f6bc9d42f59d08c Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sat, 22 Apr 2023 03:26:01 +0100
|
||||
Subject: [PATCH] net: phy: realtek: setup ALDPS on RTL822x
|
||||
|
||||
Setup Link Down Power Saving Mode according the DTS property
|
||||
just like for RTL821x 1GE PHYs.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -63,6 +63,10 @@
|
||||
#define RTL8221B_SERDES_OPTION_MODE_2500BASEX 2
|
||||
#define RTL8221B_SERDES_OPTION_MODE_HISGMII 3
|
||||
|
||||
+#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)
|
||||
|
||||
@@ -778,6 +782,25 @@ static int rtl8226_match_phy_device(stru
|
||||
rtlgen_supports_2_5gbps(phydev);
|
||||
}
|
||||
|
||||
+static int rtl822x_probe(struct phy_device *phydev)
|
||||
+{
|
||||
+ struct device *dev = &phydev->mdio.dev;
|
||||
+ int val;
|
||||
+
|
||||
+ val = phy_read_mmd(phydev, RTL8221B_MMD_SERDES_CTRL, 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, RTL8221B_MMD_SERDES_CTRL, RTL8221B_PHYCR1, val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int rtlgen_resume(struct phy_device *phydev)
|
||||
{
|
||||
int ret = genphy_resume(phydev);
|
||||
@@ -1091,6 +1114,7 @@ static struct phy_driver realtek_drvs[]
|
||||
.name = "RTL8226-CG 2.5Gbps PHY",
|
||||
.get_features = rtl822x_get_features,
|
||||
.config_aneg = rtl822x_config_aneg,
|
||||
+ .probe = rtl822x_probe,
|
||||
.read_status = rtl822x_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = rtlgen_resume,
|
||||
@@ -1102,6 +1126,7 @@ static struct phy_driver realtek_drvs[]
|
||||
.name = "RTL8226B-CG_RTL8221B-CG 2.5Gbps PHY",
|
||||
.get_features = rtl822x_get_features,
|
||||
.config_aneg = rtl822x_config_aneg,
|
||||
+ .probe = rtl822x_probe,
|
||||
.read_status = rtl822x_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = rtlgen_resume,
|
||||
@@ -1114,6 +1139,7 @@ static struct phy_driver realtek_drvs[]
|
||||
.get_features = rtl822x_get_features,
|
||||
.config_init = rtl8221b_config_init,
|
||||
.config_aneg = rtl822x_config_aneg,
|
||||
+ .probe = rtl822x_probe,
|
||||
.read_status = rtl822x_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = rtlgen_resume,
|
||||
@@ -1126,6 +1152,7 @@ static struct phy_driver realtek_drvs[]
|
||||
.get_features = rtl822x_get_features,
|
||||
.config_aneg = rtl822x_config_aneg,
|
||||
.config_init = rtl8221b_config_init,
|
||||
+ .probe = rtl822x_probe,
|
||||
.read_status = rtl822x_read_status,
|
||||
.suspend = genphy_suspend,
|
||||
.resume = rtlgen_resume,
|
|
@ -1,71 +0,0 @@
|
|||
From 0de82310d2b32e78ff79d42c08b1122a6ede3778 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Sun, 30 Apr 2023 00:15:41 +0100
|
||||
Subject: [PATCH] net: phy: realtek: detect early version of RTL8221B
|
||||
|
||||
Early versions (?) of the RTL8221B PHY cannot be identified in a regular
|
||||
Clause-45 bus scan as the PHY doesn't report the implemented MMDs
|
||||
correctly but returns 0 instead.
|
||||
Implement custom identify function using the PKGID instead of iterating
|
||||
over the implemented MMDs.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -81,6 +81,7 @@
|
||||
|
||||
#define RTL_GENERIC_PHYID 0x001cc800
|
||||
#define RTL_8211FVD_PHYID 0x001cc878
|
||||
+#define RTL_8221B_VB_CG_PHYID 0x001cc849
|
||||
|
||||
MODULE_DESCRIPTION("Realtek PHY driver");
|
||||
MODULE_AUTHOR("Johnson Leung");
|
||||
@@ -782,6 +783,38 @@ static int rtl8226_match_phy_device(stru
|
||||
rtlgen_supports_2_5gbps(phydev);
|
||||
}
|
||||
|
||||
+static int rtl8221b_vb_cg_match_phy_device(struct phy_device *phydev)
|
||||
+{
|
||||
+ int val;
|
||||
+ u32 id;
|
||||
+
|
||||
+ if (phydev->mdio.bus->read_c45) {
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID1);
|
||||
+ if (val < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ id = val << 16;
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PKGID2);
|
||||
+ if (val < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ id |= val;
|
||||
+ } else {
|
||||
+ val = phy_read(phydev, MII_PHYSID1);
|
||||
+ if (val < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ id = val << 16;
|
||||
+ val = phy_read(phydev, MII_PHYSID2);
|
||||
+ if (val < 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ id |= val;
|
||||
+ }
|
||||
+
|
||||
+ return (id == RTL_8221B_VB_CG_PHYID);
|
||||
+}
|
||||
+
|
||||
static int rtl822x_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct device *dev = &phydev->mdio.dev;
|
||||
@@ -1134,7 +1167,7 @@ static struct phy_driver realtek_drvs[]
|
||||
.write_page = rtl821x_write_page,
|
||||
.soft_reset = genphy_soft_reset,
|
||||
}, {
|
||||
- PHY_ID_MATCH_EXACT(0x001cc849),
|
||||
+ .match_phy_device = rtl8221b_vb_cg_match_phy_device,
|
||||
.name = "RTL8221B-VB-CG 2.5Gbps PHY",
|
||||
.get_features = rtl822x_get_features,
|
||||
.config_init = rtl8221b_config_init,
|
|
@ -1,498 +0,0 @@
|
|||
From patchwork Thu Feb 1 21:53:06 2024
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
|
||||
X-Patchwork-Id: 13541843
|
||||
Date: Thu, 1 Feb 2024 21:53:06 +0000
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
To: Bc-bocun Chen <bc-bocun.chen@mediatek.com>,
|
||||
Chunfeng Yun <chunfeng.yun@mediatek.com>,
|
||||
Vinod Koul <vkoul@kernel.org>,
|
||||
Kishon Vijay Abraham I <kishon@kernel.org>,
|
||||
Rob Herring <robh@kernel.org>,
|
||||
Krzysztof Kozlowski <krzysztof.kozlowski+dt@linaro.org>,
|
||||
Conor Dooley <conor+dt@kernel.org>,
|
||||
Daniel Golle <daniel@makrotopia.org>,
|
||||
Qingfang Deng <dqfext@gmail.com>,
|
||||
SkyLake Huang <SkyLake.Huang@mediatek.com>,
|
||||
Matthias Brugger <matthias.bgg@gmail.com>,
|
||||
AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>,
|
||||
Philipp Zabel <p.zabel@pengutronix.de>,
|
||||
linux-arm-kernel@lists.infradead.org,
|
||||
linux-mediatek@lists.infradead.org, linux-phy@lists.infradead.org,
|
||||
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
|
||||
netdev@vger.kernel.org
|
||||
Subject: [PATCH 2/2] phy: add driver for MediaTek XFI T-PHY
|
||||
Message-ID:
|
||||
<dd6b40ea1f7f8459a9a2cfe7fa60c1108332ade6.1706823233.git.daniel@makrotopia.org>
|
||||
References:
|
||||
<702afb0c1246d95c90b22e57105304028bdd3083.1706823233.git.daniel@makrotopia.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Disposition: inline
|
||||
In-Reply-To:
|
||||
<702afb0c1246d95c90b22e57105304028bdd3083.1706823233.git.daniel@makrotopia.org>
|
||||
List-Id: Linux Phy Mailing list <linux-phy.lists.infradead.org>
|
||||
|
||||
Add driver for MediaTek's XFI T-PHY, 10 Gigabit/s Ethernet SerDes PHY
|
||||
which can be found in the MT7988 SoC.
|
||||
|
||||
The PHY can operates only in PHY_MODE_ETHERNET, the submode is one of
|
||||
PHY_INTERFACE_MODE_* corresponding to the supported modes:
|
||||
|
||||
* USXGMII \
|
||||
* 10GBase-R }- USXGMII PCS - XGDM \
|
||||
* 5GBase-R / \
|
||||
}- Ethernet MAC
|
||||
* 2500Base-X \ /
|
||||
* 1000Base-X }- LynxI PCS - GDM /
|
||||
* Cisco SGMII (MAC side) /
|
||||
|
||||
In order to work-around a performance issue present on the first of
|
||||
two XFI T-PHYs present in MT7988, special tuning is applied which can be
|
||||
selected by adding the 'mediatek,usxgmii-performance-errata' property to
|
||||
the device tree node.
|
||||
|
||||
There is no documentation for most registers used for the
|
||||
analog/tuning part, however, most of the registers have been partially
|
||||
reverse-engineered from MediaTek's SDK implementation (an opaque
|
||||
sequence of 32-bit register writes) and descriptions for all relevant
|
||||
digital registers and bits such as resets and muxes have been supplied
|
||||
by MediaTek.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
MAINTAINERS | 1 +
|
||||
drivers/phy/mediatek/Kconfig | 12 +
|
||||
drivers/phy/mediatek/Makefile | 1 +
|
||||
drivers/phy/mediatek/phy-mtk-xfi-tphy.c | 392 ++++++++++++++++++++++++
|
||||
4 files changed, 406 insertions(+)
|
||||
create mode 100644 drivers/phy/mediatek/phy-mtk-xfi-tphy.c
|
||||
|
||||
--- a/drivers/phy/mediatek/Kconfig
|
||||
+++ b/drivers/phy/mediatek/Kconfig
|
||||
@@ -13,6 +13,18 @@ config PHY_MTK_PCIE
|
||||
callback for PCIe GEN3 port, it supports software efuse
|
||||
initialization.
|
||||
|
||||
+config PHY_MTK_XFI_TPHY
|
||||
+ tristate "MediaTek XFI T-PHY Driver"
|
||||
+ depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
+ depends on OF && OF_ADDRESS
|
||||
+ depends on HAS_IOMEM
|
||||
+ select GENERIC_PHY
|
||||
+ help
|
||||
+ Say 'Y' here to add support for MediaTek XFI T-PHY driver.
|
||||
+ The driver provides access to the Ethernet SerDes T-PHY supporting
|
||||
+ 1GE and 2.5GE modes via the LynxI PCS, and 5GE and 10GE modes
|
||||
+ via the USXGMII PCS found in MediaTek SoCs with 10G Ethernet.
|
||||
+
|
||||
config PHY_MTK_TPHY
|
||||
tristate "MediaTek T-PHY Driver"
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
--- a/drivers/phy/mediatek/Makefile
|
||||
+++ b/drivers/phy/mediatek/Makefile
|
||||
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_MTK_PCIE) += phy-mtk-p
|
||||
obj-$(CONFIG_PHY_MTK_TPHY) += phy-mtk-tphy.o
|
||||
obj-$(CONFIG_PHY_MTK_UFS) += phy-mtk-ufs.o
|
||||
obj-$(CONFIG_PHY_MTK_XSPHY) += phy-mtk-xsphy.o
|
||||
+obj-$(CONFIG_PHY_MTK_XFI_TPHY) += phy-mtk-xfi-tphy.o
|
||||
|
||||
phy-mtk-hdmi-drv-y := phy-mtk-hdmi.o
|
||||
phy-mtk-hdmi-drv-y += phy-mtk-hdmi-mt2701.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/phy/mediatek/phy-mtk-xfi-tphy.c
|
||||
@@ -0,0 +1,393 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
+/* MediaTek 10GE SerDes PHY driver
|
||||
+ *
|
||||
+ * Copyright (c) 2024 Daniel Golle <daniel@makrotopia.org>
|
||||
+ * Bc-bocun Chen <bc-bocun.chen@mediatek.com>
|
||||
+ * based on mtk_usxgmii.c found in MediaTek's SDK released under GPL-2.0
|
||||
+ * Copyright (c) 2022 MediaTek Inc.
|
||||
+ * Author: Henry Yen <henry.yen@mediatek.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/platform_device.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/io.h>
|
||||
+#include <linux/clk.h>
|
||||
+#include <linux/reset.h>
|
||||
+#include <linux/phy.h>
|
||||
+#include <linux/phy/phy.h>
|
||||
+
|
||||
+#define MTK_XFI_TPHY_NUM_CLOCKS 2
|
||||
+
|
||||
+#define REG_DIG_GLB_70 0x0070
|
||||
+#define XTP_PCS_RX_EQ_IN_PROGRESS(x) FIELD_PREP(GENMASK(25, 24), (x))
|
||||
+#define XTP_PCS_MODE_MASK GENMASK(17, 16)
|
||||
+#define XTP_PCS_MODE(x) FIELD_PREP(GENMASK(17, 16), (x))
|
||||
+#define XTP_PCS_RST_B BIT(15)
|
||||
+#define XTP_FRC_PCS_RST_B BIT(14)
|
||||
+#define XTP_PCS_PWD_SYNC_MASK GENMASK(13, 12)
|
||||
+#define XTP_PCS_PWD_SYNC(x) FIELD_PREP(XTP_PCS_PWD_SYNC_MASK, (x))
|
||||
+#define XTP_PCS_PWD_ASYNC_MASK GENMASK(11, 10)
|
||||
+#define XTP_PCS_PWD_ASYNC(x) FIELD_PREP(XTP_PCS_PWD_ASYNC_MASK, (x))
|
||||
+#define XTP_FRC_PCS_PWD_ASYNC BIT(8)
|
||||
+#define XTP_PCS_UPDT BIT(4)
|
||||
+#define XTP_PCS_IN_FR_RG BIT(0)
|
||||
+
|
||||
+#define REG_DIG_GLB_F4 0x00f4
|
||||
+#define XFI_DPHY_PCS_SEL BIT(0)
|
||||
+#define XFI_DPHY_PCS_SEL_SGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 1)
|
||||
+#define XFI_DPHY_PCS_SEL_USXGMII FIELD_PREP(XFI_DPHY_PCS_SEL, 0)
|
||||
+#define XFI_DPHY_AD_SGDT_FRC_EN BIT(5)
|
||||
+
|
||||
+#define REG_DIG_LN_TRX_40 0x3040
|
||||
+#define XTP_LN_FRC_TX_DATA_EN BIT(29)
|
||||
+#define XTP_LN_TX_DATA_EN BIT(28)
|
||||
+
|
||||
+#define REG_DIG_LN_TRX_B0 0x30b0
|
||||
+#define XTP_LN_FRC_TX_MACCK_EN BIT(5)
|
||||
+#define XTP_LN_TX_MACCK_EN BIT(4)
|
||||
+
|
||||
+#define REG_ANA_GLB_D0 0x90d0
|
||||
+#define XTP_GLB_USXGMII_SEL_MASK GENMASK(3, 1)
|
||||
+#define XTP_GLB_USXGMII_SEL(x) FIELD_PREP(GENMASK(3, 1), (x))
|
||||
+#define XTP_GLB_USXGMII_EN BIT(0)
|
||||
+
|
||||
+struct mtk_xfi_tphy {
|
||||
+ void __iomem *base;
|
||||
+ struct device *dev;
|
||||
+ struct reset_control *reset;
|
||||
+ struct clk_bulk_data clocks[MTK_XFI_TPHY_NUM_CLOCKS];
|
||||
+ bool da_war;
|
||||
+};
|
||||
+
|
||||
+static void mtk_xfi_tphy_write(struct mtk_xfi_tphy *xfi_tphy, u16 reg,
|
||||
+ u32 value)
|
||||
+{
|
||||
+ iowrite32(value, xfi_tphy->base + reg);
|
||||
+}
|
||||
+
|
||||
+static void mtk_xfi_tphy_rmw(struct mtk_xfi_tphy *xfi_tphy, u16 reg,
|
||||
+ u32 clr, u32 set)
|
||||
+{
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = ioread32(xfi_tphy->base + reg);
|
||||
+ val &= ~clr;
|
||||
+ val |= set;
|
||||
+ iowrite32(val, xfi_tphy->base + reg);
|
||||
+}
|
||||
+
|
||||
+static void mtk_xfi_tphy_set(struct mtk_xfi_tphy *xfi_tphy, u16 reg,
|
||||
+ u32 set)
|
||||
+{
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, reg, 0, set);
|
||||
+}
|
||||
+
|
||||
+static void mtk_xfi_tphy_clear(struct mtk_xfi_tphy *xfi_tphy, u16 reg,
|
||||
+ u32 clr)
|
||||
+{
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, reg, clr, 0);
|
||||
+}
|
||||
+
|
||||
+static void mtk_xfi_tphy_setup(struct mtk_xfi_tphy *xfi_tphy,
|
||||
+ phy_interface_t interface)
|
||||
+{
|
||||
+ bool is_2p5g = (interface == PHY_INTERFACE_MODE_2500BASEX);
|
||||
+ bool is_1g = (interface == PHY_INTERFACE_MODE_1000BASEX ||
|
||||
+ interface == PHY_INTERFACE_MODE_SGMII);
|
||||
+ bool is_10g = (interface == PHY_INTERFACE_MODE_10GBASER ||
|
||||
+ interface == PHY_INTERFACE_MODE_USXGMII);
|
||||
+ bool is_5g = (interface == PHY_INTERFACE_MODE_5GBASER);
|
||||
+ bool is_xgmii = (is_10g || is_5g);
|
||||
+
|
||||
+ dev_dbg(xfi_tphy->dev, "setting up for mode %s\n", phy_modes(interface));
|
||||
+
|
||||
+ /* Setup PLL setting */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x9024, 0x100000, is_10g ? 0x0 : 0x100000);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x2020, 0x202000, is_5g ? 0x202000 : 0x0);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x2030, 0x500, is_1g ? 0x0 : 0x500);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x2034, 0xa00, is_1g ? 0x0 : 0xa00);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x2040, 0x340000, is_1g ? 0x200000 :
|
||||
+ 0x140000);
|
||||
+
|
||||
+ /* Setup RXFE BW setting */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x50f0, 0xc10, is_1g ? 0x410 :
|
||||
+ is_5g ? 0x800 : 0x400);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x50e0, 0x4000, is_5g ? 0x0 : 0x4000);
|
||||
+
|
||||
+ /* Setup RX CDR setting */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x506c, 0x30000, is_5g ? 0x0 : 0x30000);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x5070, 0x670000, is_5g ? 0x620000 : 0x50000);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x5074, 0x180000, is_5g ? 0x180000 : 0x0);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x5078, 0xf000400, is_5g ? 0x8000000 :
|
||||
+ 0x7000400);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x507c, 0x5000500, is_5g ? 0x4000400 :
|
||||
+ 0x1000100);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x5080, 0x1410, is_1g ? 0x400 :
|
||||
+ is_5g ? 0x1010 : 0x0);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x5084, 0x30300, is_1g ? 0x30300 :
|
||||
+ is_5g ? 0x30100 :
|
||||
+ 0x100);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x5088, 0x60200, is_1g ? 0x20200 :
|
||||
+ is_5g ? 0x40000 :
|
||||
+ 0x20000);
|
||||
+
|
||||
+ /* Setting RXFE adaptation range setting */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x50e4, 0xc0000, is_5g ? 0x0 : 0xc0000);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x50e8, 0x40000, is_5g ? 0x0 : 0x40000);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x50ec, 0xa00, is_1g ? 0x200 : 0x800);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x50a8, 0xee0000, is_5g ? 0x800000 :
|
||||
+ 0x6e0000);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x6004, 0x190000, is_5g ? 0x0 : 0x190000);
|
||||
+ if (is_10g)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x01423342);
|
||||
+ else if (is_5g)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x00a132a1);
|
||||
+ else if (is_2p5g)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x009c329c);
|
||||
+ else
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x00f8, 0x00fa32fa);
|
||||
+
|
||||
+ /* Force SGDT_OUT off and select PCS */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, REG_DIG_GLB_F4,
|
||||
+ XFI_DPHY_AD_SGDT_FRC_EN | XFI_DPHY_PCS_SEL,
|
||||
+ XFI_DPHY_AD_SGDT_FRC_EN |
|
||||
+ (is_xgmii ? XFI_DPHY_PCS_SEL_USXGMII :
|
||||
+ XFI_DPHY_PCS_SEL_SGMII));
|
||||
+
|
||||
+
|
||||
+ /* Force GLB_CKDET_OUT */
|
||||
+ mtk_xfi_tphy_set(xfi_tphy, 0x0030, 0xc00);
|
||||
+
|
||||
+ /* Force AEQ on */
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, REG_DIG_GLB_70,
|
||||
+ XTP_PCS_RX_EQ_IN_PROGRESS(2) |
|
||||
+ XTP_PCS_PWD_SYNC(2) |
|
||||
+ XTP_PCS_PWD_ASYNC(2));
|
||||
+
|
||||
+ usleep_range(1, 5);
|
||||
+ writel(XTP_LN_FRC_TX_DATA_EN, xfi_tphy->base + REG_DIG_LN_TRX_40);
|
||||
+
|
||||
+ /* Setup TX DA default value */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x30b0, 0x30, 0x20);
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3028, 0x00008a01);
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x302c, 0x0000a884);
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3024, 0x00083002);
|
||||
+
|
||||
+ /* Setup RG default value */
|
||||
+ if (is_xgmii) {
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3010, 0x00022220);
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x5064, 0x0f020a01);
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x50b4, 0x06100600);
|
||||
+ if (interface == PHY_INTERFACE_MODE_USXGMII)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3048, 0x40704000);
|
||||
+ else
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3048, 0x47684100);
|
||||
+ } else {
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3010, 0x00011110);
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3048, 0x40704000);
|
||||
+ }
|
||||
+
|
||||
+ if (is_1g)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x3064, 0x0000c000);
|
||||
+
|
||||
+ /* Setup RX EQ initial value */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x3050, 0xa8000000,
|
||||
+ (interface != PHY_INTERFACE_MODE_10GBASER) ?
|
||||
+ 0xa8000000 : 0x0);
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0x3054, 0xaa,
|
||||
+ (interface != PHY_INTERFACE_MODE_10GBASER) ?
|
||||
+ 0xaa : 0x0);
|
||||
+
|
||||
+ if (is_xgmii)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x306c, 0x00000f00);
|
||||
+ else if (is_2p5g)
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x306c, 0x22000f00);
|
||||
+ else
|
||||
+ mtk_xfi_tphy_write(xfi_tphy, 0x306c, 0x20200f00);
|
||||
+
|
||||
+ if (interface == PHY_INTERFACE_MODE_10GBASER && xfi_tphy->da_war)
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0xa008, 0x10000, 0x10000);
|
||||
+
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, 0xa060, 0x50000, is_xgmii ? 0x40000 :
|
||||
+ 0x50000);
|
||||
+
|
||||
+ /* Setup PHYA speed */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, REG_ANA_GLB_D0,
|
||||
+ XTP_GLB_USXGMII_SEL_MASK | XTP_GLB_USXGMII_EN,
|
||||
+ is_10g ? XTP_GLB_USXGMII_SEL(0) :
|
||||
+ is_5g ? XTP_GLB_USXGMII_SEL(1) :
|
||||
+ is_2p5g ? XTP_GLB_USXGMII_SEL(2) :
|
||||
+ XTP_GLB_USXGMII_SEL(3));
|
||||
+ mtk_xfi_tphy_set(xfi_tphy, REG_ANA_GLB_D0, XTP_GLB_USXGMII_EN);
|
||||
+
|
||||
+ /* Release reset */
|
||||
+ mtk_xfi_tphy_set(xfi_tphy, REG_DIG_GLB_70,
|
||||
+ XTP_PCS_RST_B | XTP_FRC_PCS_RST_B);
|
||||
+ usleep_range(150, 500);
|
||||
+
|
||||
+ /* Switch to P0 */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, REG_DIG_GLB_70,
|
||||
+ XTP_PCS_PWD_SYNC_MASK |
|
||||
+ XTP_PCS_PWD_ASYNC_MASK,
|
||||
+ XTP_FRC_PCS_PWD_ASYNC |
|
||||
+ XTP_PCS_UPDT | XTP_PCS_IN_FR_RG);
|
||||
+ usleep_range(1, 5);
|
||||
+
|
||||
+ mtk_xfi_tphy_clear(xfi_tphy, REG_DIG_GLB_70, XTP_PCS_UPDT);
|
||||
+ usleep_range(15, 50);
|
||||
+
|
||||
+ if (is_xgmii) {
|
||||
+ /* Switch to Gen3 */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, REG_DIG_GLB_70,
|
||||
+ XTP_PCS_MODE_MASK | XTP_PCS_UPDT,
|
||||
+ XTP_PCS_MODE(2) | XTP_PCS_UPDT);
|
||||
+ } else {
|
||||
+ /* Switch to Gen2 */
|
||||
+ mtk_xfi_tphy_rmw(xfi_tphy, REG_DIG_GLB_70,
|
||||
+ XTP_PCS_MODE_MASK | XTP_PCS_UPDT,
|
||||
+ XTP_PCS_MODE(1) | XTP_PCS_UPDT);
|
||||
+ }
|
||||
+ usleep_range(1, 5);
|
||||
+
|
||||
+ mtk_xfi_tphy_clear(xfi_tphy, REG_DIG_GLB_70, XTP_PCS_UPDT);
|
||||
+
|
||||
+ usleep_range(100, 500);
|
||||
+
|
||||
+ /* Enable MAC CK */
|
||||
+ mtk_xfi_tphy_set(xfi_tphy, REG_DIG_LN_TRX_B0, XTP_LN_TX_MACCK_EN);
|
||||
+ mtk_xfi_tphy_clear(xfi_tphy, REG_DIG_GLB_F4, XFI_DPHY_AD_SGDT_FRC_EN);
|
||||
+
|
||||
+ /* Enable TX data */
|
||||
+ mtk_xfi_tphy_set(xfi_tphy, REG_DIG_LN_TRX_40,
|
||||
+ XTP_LN_FRC_TX_DATA_EN | XTP_LN_TX_DATA_EN);
|
||||
+ usleep_range(400, 1000);
|
||||
+}
|
||||
+
|
||||
+static int mtk_xfi_tphy_set_mode(struct phy *phy, enum phy_mode mode, int
|
||||
+ submode)
|
||||
+{
|
||||
+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
|
||||
+
|
||||
+ if (mode != PHY_MODE_ETHERNET)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ switch (submode) {
|
||||
+ case PHY_INTERFACE_MODE_1000BASEX:
|
||||
+ case PHY_INTERFACE_MODE_2500BASEX:
|
||||
+ case PHY_INTERFACE_MODE_SGMII:
|
||||
+ case PHY_INTERFACE_MODE_5GBASER:
|
||||
+ case PHY_INTERFACE_MODE_10GBASER:
|
||||
+ case PHY_INTERFACE_MODE_USXGMII:
|
||||
+ mtk_xfi_tphy_setup(xfi_tphy, submode);
|
||||
+ return 0;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int mtk_xfi_tphy_reset(struct phy *phy)
|
||||
+{
|
||||
+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
|
||||
+
|
||||
+ reset_control_assert(xfi_tphy->reset);
|
||||
+ usleep_range(100, 500);
|
||||
+ reset_control_deassert(xfi_tphy->reset);
|
||||
+ usleep_range(1, 10);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mtk_xfi_tphy_power_on(struct phy *phy)
|
||||
+{
|
||||
+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
|
||||
+
|
||||
+ return clk_bulk_prepare_enable(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks);
|
||||
+}
|
||||
+
|
||||
+static int mtk_xfi_tphy_power_off(struct phy *phy)
|
||||
+{
|
||||
+ struct mtk_xfi_tphy *xfi_tphy = phy_get_drvdata(phy);
|
||||
+
|
||||
+ clk_bulk_disable_unprepare(MTK_XFI_TPHY_NUM_CLOCKS, xfi_tphy->clocks);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct phy_ops mtk_xfi_tphy_ops = {
|
||||
+ .power_on = mtk_xfi_tphy_power_on,
|
||||
+ .power_off = mtk_xfi_tphy_power_off,
|
||||
+ .set_mode = mtk_xfi_tphy_set_mode,
|
||||
+ .reset = mtk_xfi_tphy_reset,
|
||||
+ .owner = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static int mtk_xfi_tphy_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *np = pdev->dev.of_node;
|
||||
+ struct phy_provider *phy_provider;
|
||||
+ struct mtk_xfi_tphy *xfi_tphy;
|
||||
+ struct phy *phy;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ xfi_tphy = devm_kzalloc(&pdev->dev, sizeof(*xfi_tphy), GFP_KERNEL);
|
||||
+ if (!xfi_tphy)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ xfi_tphy->base = devm_of_iomap(&pdev->dev, np, 0, NULL);
|
||||
+ if (!xfi_tphy->base)
|
||||
+ return -EIO;
|
||||
+
|
||||
+ xfi_tphy->dev = &pdev->dev;
|
||||
+
|
||||
+ xfi_tphy->clocks[0].id = "topxtal";
|
||||
+ xfi_tphy->clocks[0].clk = devm_clk_get(&pdev->dev, xfi_tphy->clocks[0].id);
|
||||
+ if (IS_ERR(xfi_tphy->clocks[0].clk))
|
||||
+ return PTR_ERR(xfi_tphy->clocks[0].clk);
|
||||
+
|
||||
+ xfi_tphy->clocks[1].id = "xfipll";
|
||||
+ xfi_tphy->clocks[1].clk = devm_clk_get(&pdev->dev, xfi_tphy->clocks[1].id);
|
||||
+ if (IS_ERR(xfi_tphy->clocks[1].clk))
|
||||
+ return PTR_ERR(xfi_tphy->clocks[1].clk);
|
||||
+
|
||||
+ xfi_tphy->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
|
||||
+ if (IS_ERR(xfi_tphy->reset))
|
||||
+ return PTR_ERR(xfi_tphy->reset);
|
||||
+
|
||||
+ xfi_tphy->da_war = of_property_read_bool(np,
|
||||
+ "mediatek,usxgmii-performance-errata");
|
||||
+
|
||||
+ phy = devm_phy_create(&pdev->dev, NULL, &mtk_xfi_tphy_ops);
|
||||
+ if (IS_ERR(phy))
|
||||
+ return PTR_ERR(phy);
|
||||
+
|
||||
+ phy_set_drvdata(phy, xfi_tphy);
|
||||
+
|
||||
+ phy_provider = devm_of_phy_provider_register(&pdev->dev,
|
||||
+ of_phy_simple_xlate);
|
||||
+
|
||||
+ return PTR_ERR_OR_ZERO(phy_provider);
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id mtk_xfi_tphy_match[] = {
|
||||
+ { .compatible = "mediatek,mt7988-xfi-tphy", },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, mtk_xfi_tphy_match);
|
||||
+
|
||||
+static struct platform_driver mtk_xfi_tphy_driver = {
|
||||
+ .probe = mtk_xfi_tphy_probe,
|
||||
+ .driver = {
|
||||
+ .name = "mtk-xfi-tphy",
|
||||
+ .of_match_table = mtk_xfi_tphy_match,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(mtk_xfi_tphy_driver);
|
||||
+
|
||||
+MODULE_DESCRIPTION("MediaTek XFI T-PHY driver");
|
||||
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
||||
+MODULE_AUTHOR("Bc-bocun Chen <bc-bocun.chen@mediatek.com>");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -1,371 +0,0 @@
|
|||
From 4b1a2716299c0e96a698044aebf3f80513509ae7 Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Tue, 12 Dec 2023 03:47:18 +0000
|
||||
Subject: [PATCH 3/5] net: pcs: pcs-mtk-lynxi: add platform driver for MT7988
|
||||
|
||||
Introduce a proper platform MFD driver for the LynxI (H)SGMII PCS which
|
||||
is going to initially be used for the MT7988 SoC.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/pcs/pcs-mtk-lynxi.c | 227 ++++++++++++++++++++++++++++--
|
||||
include/linux/pcs/pcs-mtk-lynxi.h | 11 ++
|
||||
2 files changed, 227 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/pcs/pcs-mtk-lynxi.c
|
||||
+++ b/drivers/net/pcs/pcs-mtk-lynxi.c
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2018-2019 MediaTek Inc.
|
||||
-/* A library for MediaTek SGMII circuit
|
||||
+/* A library and platform driver for the MediaTek LynxI SGMII circuit
|
||||
*
|
||||
* Author: Sean Wang <sean.wang@mediatek.com>
|
||||
* Author: Alexander Couzens <lynxis@fe80.eu>
|
||||
@@ -8,11 +8,17 @@
|
||||
*
|
||||
*/
|
||||
|
||||
+#include <linux/clk.h>
|
||||
#include <linux/mdio.h>
|
||||
+#include <linux/mfd/syscon.h>
|
||||
+#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
+#include <linux/of_platform.h>
|
||||
#include <linux/pcs/pcs-mtk-lynxi.h>
|
||||
#include <linux/phylink.h>
|
||||
+#include <linux/platform_device.h>
|
||||
#include <linux/regmap.h>
|
||||
+#include <linux/reset.h>
|
||||
|
||||
/* SGMII subsystem config registers */
|
||||
/* BMCR (low 16) BMSR (high 16) */
|
||||
@@ -65,6 +71,8 @@
|
||||
#define SGMII_PN_SWAP_MASK GENMASK(1, 0)
|
||||
#define SGMII_PN_SWAP_TX_RX (BIT(0) | BIT(1))
|
||||
|
||||
+#define MTK_NETSYS_V3_AMA_RGC3 0x128
|
||||
+
|
||||
/* struct mtk_pcs_lynxi - This structure holds each sgmii regmap andassociated
|
||||
* data
|
||||
* @regmap: The register map pointing at the range used to setup
|
||||
@@ -74,15 +82,29 @@
|
||||
* @interface: Currently configured interface mode
|
||||
* @pcs: Phylink PCS structure
|
||||
* @flags: Flags indicating hardware properties
|
||||
+ * @rstc: Reset controller
|
||||
+ * @sgmii_sel: SGMII Register Clock
|
||||
+ * @sgmii_rx: SGMII RX Clock
|
||||
+ * @sgmii_tx: SGMII TX Clock
|
||||
+ * @node: List node
|
||||
*/
|
||||
struct mtk_pcs_lynxi {
|
||||
struct regmap *regmap;
|
||||
+ struct device *dev;
|
||||
u32 ana_rgc3;
|
||||
phy_interface_t interface;
|
||||
struct phylink_pcs pcs;
|
||||
u32 flags;
|
||||
+ struct reset_control *rstc;
|
||||
+ struct clk *sgmii_sel;
|
||||
+ struct clk *sgmii_rx;
|
||||
+ struct clk *sgmii_tx;
|
||||
+ struct list_head node;
|
||||
};
|
||||
|
||||
+static LIST_HEAD(mtk_pcs_lynxi_instances);
|
||||
+static DEFINE_MUTEX(instance_mutex);
|
||||
+
|
||||
static struct mtk_pcs_lynxi *pcs_to_mtk_pcs_lynxi(struct phylink_pcs *pcs)
|
||||
{
|
||||
return container_of(pcs, struct mtk_pcs_lynxi, pcs);
|
||||
@@ -102,6 +124,17 @@ static void mtk_pcs_lynxi_get_state(stru
|
||||
FIELD_GET(SGMII_LPA, adv));
|
||||
}
|
||||
|
||||
+static void mtk_sgmii_reset(struct mtk_pcs_lynxi *mpcs)
|
||||
+{
|
||||
+ if (!mpcs->rstc)
|
||||
+ return;
|
||||
+
|
||||
+ reset_control_assert(mpcs->rstc);
|
||||
+ udelay(100);
|
||||
+ reset_control_deassert(mpcs->rstc);
|
||||
+ mdelay(1);
|
||||
+}
|
||||
+
|
||||
static int mtk_pcs_lynxi_config(struct phylink_pcs *pcs, unsigned int neg_mode,
|
||||
phy_interface_t interface,
|
||||
const unsigned long *advertising,
|
||||
@@ -147,6 +180,7 @@ static int mtk_pcs_lynxi_config(struct p
|
||||
SGMII_PHYA_PWD);
|
||||
|
||||
/* Reset SGMII PCS state */
|
||||
+ mtk_sgmii_reset(mpcs);
|
||||
regmap_set_bits(mpcs->regmap, SGMSYS_RESERVED_0,
|
||||
SGMII_SW_RESET);
|
||||
|
||||
@@ -233,10 +267,29 @@ static void mtk_pcs_lynxi_link_up(struct
|
||||
}
|
||||
}
|
||||
|
||||
+static int mtk_pcs_lynxi_enable(struct phylink_pcs *pcs)
|
||||
+{
|
||||
+ struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
|
||||
+
|
||||
+ if (mpcs->sgmii_tx && mpcs->sgmii_rx) {
|
||||
+ clk_prepare_enable(mpcs->sgmii_rx);
|
||||
+ clk_prepare_enable(mpcs->sgmii_tx);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static void mtk_pcs_lynxi_disable(struct phylink_pcs *pcs)
|
||||
{
|
||||
struct mtk_pcs_lynxi *mpcs = pcs_to_mtk_pcs_lynxi(pcs);
|
||||
|
||||
+ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
|
||||
+
|
||||
+ if (mpcs->sgmii_tx && mpcs->sgmii_rx) {
|
||||
+ clk_disable_unprepare(mpcs->sgmii_tx);
|
||||
+ clk_disable_unprepare(mpcs->sgmii_rx);
|
||||
+ }
|
||||
+
|
||||
mpcs->interface = PHY_INTERFACE_MODE_NA;
|
||||
}
|
||||
|
||||
@@ -246,11 +299,12 @@ static const struct phylink_pcs_ops mtk_
|
||||
.pcs_an_restart = mtk_pcs_lynxi_restart_an,
|
||||
.pcs_link_up = mtk_pcs_lynxi_link_up,
|
||||
.pcs_disable = mtk_pcs_lynxi_disable,
|
||||
+ .pcs_enable = mtk_pcs_lynxi_enable,
|
||||
};
|
||||
|
||||
-struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
|
||||
- struct regmap *regmap, u32 ana_rgc3,
|
||||
- u32 flags)
|
||||
+static struct phylink_pcs *mtk_pcs_lynxi_init(struct device *dev, struct regmap *regmap,
|
||||
+ u32 ana_rgc3, u32 flags,
|
||||
+ struct mtk_pcs_lynxi *prealloc)
|
||||
{
|
||||
struct mtk_pcs_lynxi *mpcs;
|
||||
u32 id, ver;
|
||||
@@ -258,29 +312,33 @@ struct phylink_pcs *mtk_pcs_lynxi_create
|
||||
|
||||
ret = regmap_read(regmap, SGMSYS_PCS_DEVICE_ID, &id);
|
||||
if (ret < 0)
|
||||
- return NULL;
|
||||
+ return ERR_PTR(ret);
|
||||
|
||||
if (id != SGMII_LYNXI_DEV_ID) {
|
||||
dev_err(dev, "unknown PCS device id %08x\n", id);
|
||||
- return NULL;
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
ret = regmap_read(regmap, SGMSYS_PCS_SCRATCH, &ver);
|
||||
if (ret < 0)
|
||||
- return NULL;
|
||||
+ return ERR_PTR(ret);
|
||||
|
||||
ver = FIELD_GET(SGMII_DEV_VERSION, ver);
|
||||
if (ver != 0x1) {
|
||||
dev_err(dev, "unknown PCS device version %04x\n", ver);
|
||||
- return NULL;
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
}
|
||||
|
||||
dev_dbg(dev, "MediaTek LynxI SGMII PCS (id 0x%08x, ver 0x%04x)\n", id,
|
||||
ver);
|
||||
|
||||
- mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
|
||||
- if (!mpcs)
|
||||
- return NULL;
|
||||
+ if (prealloc) {
|
||||
+ mpcs = prealloc;
|
||||
+ } else {
|
||||
+ mpcs = kzalloc(sizeof(*mpcs), GFP_KERNEL);
|
||||
+ if (!mpcs)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+ };
|
||||
|
||||
mpcs->ana_rgc3 = ana_rgc3;
|
||||
mpcs->regmap = regmap;
|
||||
@@ -291,6 +349,13 @@ struct phylink_pcs *mtk_pcs_lynxi_create
|
||||
mpcs->interface = PHY_INTERFACE_MODE_NA;
|
||||
|
||||
return &mpcs->pcs;
|
||||
+};
|
||||
+
|
||||
+struct phylink_pcs *mtk_pcs_lynxi_create(struct device *dev,
|
||||
+ struct regmap *regmap, u32 ana_rgc3,
|
||||
+ u32 flags)
|
||||
+{
|
||||
+ return mtk_pcs_lynxi_init(dev, regmap, ana_rgc3, flags, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_pcs_lynxi_create);
|
||||
|
||||
@@ -303,4 +368,144 @@ void mtk_pcs_lynxi_destroy(struct phylin
|
||||
}
|
||||
EXPORT_SYMBOL(mtk_pcs_lynxi_destroy);
|
||||
|
||||
+static int mtk_pcs_lynxi_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct device_node *np = dev->of_node;
|
||||
+ struct mtk_pcs_lynxi *mpcs;
|
||||
+ struct phylink_pcs *pcs;
|
||||
+ struct regmap *regmap;
|
||||
+ u32 flags = 0;
|
||||
+
|
||||
+ mpcs = devm_kzalloc(dev, sizeof(*mpcs), GFP_KERNEL);
|
||||
+ if (!mpcs)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mpcs->dev = dev;
|
||||
+ regmap = syscon_node_to_regmap(np->parent);
|
||||
+ if (IS_ERR(regmap))
|
||||
+ return PTR_ERR(regmap);
|
||||
+
|
||||
+ if (of_property_read_bool(np->parent, "mediatek,pnswap"))
|
||||
+ flags |= MTK_SGMII_FLAG_PN_SWAP;
|
||||
+
|
||||
+ mpcs->rstc = of_reset_control_get_shared(np->parent, NULL);
|
||||
+ if (IS_ERR(mpcs->rstc))
|
||||
+ return PTR_ERR(mpcs->rstc);
|
||||
+
|
||||
+ reset_control_deassert(mpcs->rstc);
|
||||
+ mpcs->sgmii_sel = devm_clk_get_enabled(dev, "sgmii_sel");
|
||||
+ if (IS_ERR(mpcs->sgmii_sel))
|
||||
+ return PTR_ERR(mpcs->sgmii_sel);
|
||||
+
|
||||
+ mpcs->sgmii_rx = devm_clk_get(dev, "sgmii_rx");
|
||||
+ if (IS_ERR(mpcs->sgmii_rx))
|
||||
+ return PTR_ERR(mpcs->sgmii_rx);
|
||||
+
|
||||
+ mpcs->sgmii_tx = devm_clk_get(dev, "sgmii_tx");
|
||||
+ if (IS_ERR(mpcs->sgmii_tx))
|
||||
+ return PTR_ERR(mpcs->sgmii_tx);
|
||||
+
|
||||
+ pcs = mtk_pcs_lynxi_init(dev, regmap, (uintptr_t)of_device_get_match_data(dev),
|
||||
+ flags, mpcs);
|
||||
+ if (IS_ERR(pcs))
|
||||
+ return PTR_ERR(pcs);
|
||||
+
|
||||
+ regmap_set_bits(mpcs->regmap, SGMSYS_QPHY_PWR_STATE_CTRL, SGMII_PHYA_PWD);
|
||||
+
|
||||
+ platform_set_drvdata(pdev, mpcs);
|
||||
+
|
||||
+ mutex_lock(&instance_mutex);
|
||||
+ list_add_tail(&mpcs->node, &mtk_pcs_lynxi_instances);
|
||||
+ mutex_unlock(&instance_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int mtk_pcs_lynxi_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct mtk_pcs_lynxi *cur, *tmp;
|
||||
+
|
||||
+ mutex_lock(&instance_mutex);
|
||||
+ list_for_each_entry_safe(cur, tmp, &mtk_pcs_lynxi_instances, node)
|
||||
+ if (cur->dev == dev) {
|
||||
+ list_del(&cur->node);
|
||||
+ kfree(cur);
|
||||
+ break;
|
||||
+ }
|
||||
+ mutex_unlock(&instance_mutex);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id mtk_pcs_lynxi_of_match[] = {
|
||||
+ { .compatible = "mediatek,mt7988-sgmii", .data = (void *)MTK_NETSYS_V3_AMA_RGC3 },
|
||||
+ { /* sentinel */ },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, mtk_pcs_lynxi_of_match);
|
||||
+
|
||||
+struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np)
|
||||
+{
|
||||
+ struct platform_device *pdev;
|
||||
+ struct mtk_pcs_lynxi *mpcs;
|
||||
+
|
||||
+ if (!np)
|
||||
+ return NULL;
|
||||
+
|
||||
+ if (!of_device_is_available(np))
|
||||
+ return ERR_PTR(-ENODEV);
|
||||
+
|
||||
+ if (!of_match_node(mtk_pcs_lynxi_of_match, np))
|
||||
+ return ERR_PTR(-EINVAL);
|
||||
+
|
||||
+ pdev = of_find_device_by_node(np);
|
||||
+ if (!pdev || !platform_get_drvdata(pdev)) {
|
||||
+ if (pdev)
|
||||
+ put_device(&pdev->dev);
|
||||
+ return ERR_PTR(-EPROBE_DEFER);
|
||||
+ }
|
||||
+
|
||||
+ mpcs = platform_get_drvdata(pdev);
|
||||
+ device_link_add(dev, mpcs->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
|
||||
+
|
||||
+ return &mpcs->pcs;
|
||||
+}
|
||||
+EXPORT_SYMBOL(mtk_pcs_lynxi_get);
|
||||
+
|
||||
+void mtk_pcs_lynxi_put(struct phylink_pcs *pcs)
|
||||
+{
|
||||
+ struct mtk_pcs_lynxi *cur, *mpcs = NULL;
|
||||
+
|
||||
+ if (!pcs)
|
||||
+ return;
|
||||
+
|
||||
+ mutex_lock(&instance_mutex);
|
||||
+ list_for_each_entry(cur, &mtk_pcs_lynxi_instances, node)
|
||||
+ if (pcs == &cur->pcs) {
|
||||
+ mpcs = cur;
|
||||
+ break;
|
||||
+ }
|
||||
+ mutex_unlock(&instance_mutex);
|
||||
+
|
||||
+ if (WARN_ON(!mpcs))
|
||||
+ return;
|
||||
+
|
||||
+ put_device(mpcs->dev);
|
||||
+}
|
||||
+EXPORT_SYMBOL(mtk_pcs_lynxi_put);
|
||||
+
|
||||
+static struct platform_driver mtk_pcs_lynxi_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "mtk-pcs-lynxi",
|
||||
+ .suppress_bind_attrs = true,
|
||||
+ .of_match_table = mtk_pcs_lynxi_of_match,
|
||||
+ },
|
||||
+ .probe = mtk_pcs_lynxi_probe,
|
||||
+ .remove = mtk_pcs_lynxi_remove,
|
||||
+};
|
||||
+module_platform_driver(mtk_pcs_lynxi_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Daniel Golle <daniel@makrotopia.org>");
|
||||
+MODULE_DESCRIPTION("MediaTek LynxI HSGMII PCS");
|
||||
MODULE_LICENSE("GPL");
|
||||
--- a/include/linux/pcs/pcs-mtk-lynxi.h
|
||||
+++ b/include/linux/pcs/pcs-mtk-lynxi.h
|
||||
@@ -10,4 +10,15 @@ struct phylink_pcs *mtk_pcs_lynxi_create
|
||||
struct regmap *regmap,
|
||||
u32 ana_rgc3, u32 flags);
|
||||
void mtk_pcs_lynxi_destroy(struct phylink_pcs *pcs);
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_PCS_MTK_LYNXI)
|
||||
+struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np);
|
||||
+void mtk_pcs_lynxi_put(struct phylink_pcs *pcs);
|
||||
+#else
|
||||
+static inline struct phylink_pcs *mtk_pcs_lynxi_get(struct device *dev, struct device_node *np)
|
||||
+{
|
||||
+ return NULL;
|
||||
+}
|
||||
+static inline void mtk_pcs_lynxi_put(struct phylink_pcs *pcs) { }
|
||||
+#endif /* IS_ENABLED(CONFIG_PCS_MTK_LYNXI) */
|
||||
#endif
|
|
@ -1,75 +0,0 @@
|
|||
From d7943c31d57c11e1a517aa3ce2006fca44866870 Mon Sep 17 00:00:00 2001
|
||||
From: Jianhui Zhao <zhaojh329@gmail.com>
|
||||
Date: Sun, 24 Sep 2023 22:15:00 +0800
|
||||
Subject: [PATCH] net: phy: realtek: add interrupt support for RTL8221B
|
||||
|
||||
This commit introduces interrupt support for RTL8221B.
|
||||
|
||||
Signed-off-by: Jianhui Zhao <zhaojh329@gmail.com>
|
||||
---
|
||||
drivers/net/phy/realtek.c | 47 +++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 47 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/realtek.c
|
||||
+++ b/drivers/net/phy/realtek.c
|
||||
@@ -1010,6 +1010,51 @@ static int rtl8221b_config_init(struct p
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int rtl8221b_ack_interrupt(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ err = phy_read_mmd(phydev, RTL8221B_MMD_PHY_CTRL, 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, RTL8221B_MMD_PHY_CTRL, 0xa4d2, 0x7ff);
|
||||
+ } else {
|
||||
+ err = phy_write_mmd(phydev, RTL8221B_MMD_PHY_CTRL, 0xa4d2, 0x0);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ err = rtl8221b_ack_interrupt(phydev);
|
||||
+ }
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static irqreturn_t rtl8221b_handle_interrupt(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ err = rtl8221b_ack_interrupt(phydev);
|
||||
+ if (err) {
|
||||
+ phy_error(phydev);
|
||||
+ return IRQ_NONE;
|
||||
+ }
|
||||
+
|
||||
+ phy_trigger_machine(phydev);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
static struct phy_driver realtek_drvs[] = {
|
||||
{
|
||||
PHY_ID_MATCH_EXACT(0x00008201),
|
||||
@@ -1172,6 +1217,8 @@ static struct phy_driver realtek_drvs[]
|
||||
.get_features = rtl822x_get_features,
|
||||
.config_init = rtl8221b_config_init,
|
||||
.config_aneg = rtl822x_config_aneg,
|
||||
+ .config_intr = rtl8221b_config_intr,
|
||||
+ .handle_interrupt = rtl8221b_handle_interrupt,
|
||||
.probe = rtl822x_probe,
|
||||
.read_status = rtl822x_read_status,
|
||||
.suspend = genphy_suspend,
|
|
@ -1,368 +0,0 @@
|
|||
From c6a1759365fc35463138a7d9e335ee53f384b8df Mon Sep 17 00:00:00 2001
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Date: Fri, 10 May 2024 02:53:52 +0100
|
||||
Subject: [PATCH] net: phy: aquantia: add support for PHY LEDs
|
||||
|
||||
Aquantia Ethernet PHYs got 3 LED output pins which are typically used
|
||||
to indicate link status and activity.
|
||||
Add a minimal LED controller driver supporting the most common uses
|
||||
with the 'netdev' trigger as well as software-driven forced control of
|
||||
the LEDs.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/net/phy/aquantia/Makefile | 3 +
|
||||
drivers/net/phy/aquantia/aquantia.h | 84 +++++++++++++
|
||||
drivers/net/phy/aquantia/aquantia_leds.c | 152 +++++++++++++++++++++++
|
||||
drivers/net/phy/aquantia/aquantia_main.c | 127 +++++++++++++------
|
||||
4 files changed, 329 insertions(+), 37 deletions(-)
|
||||
create mode 100644 drivers/net/phy/aquantia/aquantia_leds.c
|
||||
|
||||
--- a/drivers/net/phy/aquantia/Makefile
|
||||
+++ b/drivers/net/phy/aquantia/Makefile
|
||||
@@ -3,4 +3,7 @@ aquantia-objs += aquantia_main.o aquan
|
||||
ifdef CONFIG_HWMON
|
||||
aquantia-objs += aquantia_hwmon.o
|
||||
endif
|
||||
+ifdef CONFIG_PHYLIB_LEDS
|
||||
+aquantia-objs += aquantia_leds.o
|
||||
+endif
|
||||
obj-$(CONFIG_AQUANTIA_PHY) += aquantia.o
|
||||
--- a/drivers/net/phy/aquantia/aquantia.h
|
||||
+++ b/drivers/net/phy/aquantia/aquantia.h
|
||||
@@ -62,6 +62,26 @@
|
||||
#define VEND1_THERMAL_PROV_LOW_TEMP_FAIL 0xc422
|
||||
#define VEND1_THERMAL_PROV_HIGH_TEMP_WARN 0xc423
|
||||
#define VEND1_THERMAL_PROV_LOW_TEMP_WARN 0xc424
|
||||
+
|
||||
+#define AQR_NUM_LEDS 3
|
||||
+
|
||||
+#define VEND1_GLOBAL_LED_PROV 0xc430
|
||||
+#define AQR_LED_PROV(x) (VEND1_GLOBAL_LED_PROV + x)
|
||||
+#define VEND1_GLOBAL_LED_PROV_ACT_STRETCH GENMASK(0, 1)
|
||||
+#define VEND1_GLOBAL_LED_PROV_TX_ACT BIT(2)
|
||||
+#define VEND1_GLOBAL_LED_PROV_RX_ACT BIT(3)
|
||||
+#define VEND1_GLOBAL_LED_PROV_LINK_MASK (GENMASK(15, 14) | GENMASK(8, 5))
|
||||
+#define VEND1_GLOBAL_LED_PROV_LINK100 BIT(5)
|
||||
+#define VEND1_GLOBAL_LED_PROV_LINK1000 BIT(6)
|
||||
+#define VEND1_GLOBAL_LED_PROV_LINK10000 BIT(7)
|
||||
+#define VEND1_GLOBAL_LED_PROV_FORCE_ON BIT(8)
|
||||
+#define VEND1_GLOBAL_LED_PROV_LINK2500 BIT(14)
|
||||
+#define VEND1_GLOBAL_LED_PROV_LINK5000 BIT(15)
|
||||
+
|
||||
+#define VEND1_GLOBAL_LED_DRIVE 0xc438
|
||||
+#define VEND1_GLOBAL_LED_DRIVE_VDD BIT(1)
|
||||
+#define AQR_LED_DRIVE(x) (VEND1_GLOBAL_LED_DRIVE + x)
|
||||
+
|
||||
#define VEND1_THERMAL_STAT1 0xc820
|
||||
#define VEND1_THERMAL_STAT2 0xc821
|
||||
#define VEND1_THERMAL_STAT2_VALID BIT(0)
|
||||
@@ -115,3 +135,23 @@ static inline int aqr_hwmon_probe(struct
|
||||
#endif
|
||||
|
||||
int aqr_firmware_load(struct phy_device *phydev);
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+int aqr_phy_led_blink_set(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long *delay_on,
|
||||
+ unsigned long *delay_off);
|
||||
+
|
||||
+int aqr_phy_led_brightness_set(struct phy_device *phydev,
|
||||
+ u8 index, enum led_brightness value);
|
||||
+
|
||||
+int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long rules);
|
||||
+
|
||||
+int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long *rules);
|
||||
+
|
||||
+int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long rules);
|
||||
+
|
||||
+int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes);
|
||||
+#endif
|
||||
--- /dev/null
|
||||
+++ b/drivers/net/phy/aquantia/aquantia_leds.c
|
||||
@@ -0,0 +1,140 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/* LED driver for Aquantia PHY
|
||||
+ *
|
||||
+ * Author: Daniel Golle <daniel@makrotopia.org>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/phy.h>
|
||||
+
|
||||
+#include "aquantia.h"
|
||||
+
|
||||
+int aqr_phy_led_brightness_set(struct phy_device *phydev,
|
||||
+ u8 index, enum led_brightness value)
|
||||
+{
|
||||
+ if (index > 2)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index), VEND1_GLOBAL_LED_PROV_LINK_MASK |
|
||||
+ VEND1_GLOBAL_LED_PROV_FORCE_ON |
|
||||
+ VEND1_GLOBAL_LED_PROV_RX_ACT |
|
||||
+ VEND1_GLOBAL_LED_PROV_TX_ACT,
|
||||
+ value ? VEND1_GLOBAL_LED_PROV_FORCE_ON : 0);
|
||||
+}
|
||||
+
|
||||
+static const unsigned long supported_triggers = (BIT(TRIGGER_NETDEV_LINK) |
|
||||
+ BIT(TRIGGER_NETDEV_LINK_100) |
|
||||
+ BIT(TRIGGER_NETDEV_LINK_1000) |
|
||||
+ BIT(TRIGGER_NETDEV_LINK_2500) |
|
||||
+ BIT(TRIGGER_NETDEV_LINK_5000) |
|
||||
+ BIT(TRIGGER_NETDEV_LINK_10000) |
|
||||
+ BIT(TRIGGER_NETDEV_RX) |
|
||||
+ BIT(TRIGGER_NETDEV_TX));
|
||||
+
|
||||
+int aqr_phy_led_hw_is_supported(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long rules)
|
||||
+{
|
||||
+ if (index >= AQR_NUM_LEDS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ /* All combinations of the supported triggers are allowed */
|
||||
+ if (rules & ~supported_triggers)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int aqr_phy_led_hw_control_get(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long *rules)
|
||||
+{
|
||||
+ int val;
|
||||
+
|
||||
+ if (index >= AQR_NUM_LEDS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ val = phy_read_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index));
|
||||
+ if (val < 0)
|
||||
+ return val;
|
||||
+
|
||||
+ *rules = 0;
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_LINK100)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_LINK_100);
|
||||
+
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_LINK1000)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_LINK_1000);
|
||||
+
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_LINK2500)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_LINK_2500);
|
||||
+
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_LINK5000)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_LINK_5000);
|
||||
+
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_LINK10000)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_LINK_10000);
|
||||
+
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_RX_ACT)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_RX);
|
||||
+
|
||||
+ if (val & VEND1_GLOBAL_LED_PROV_TX_ACT)
|
||||
+ *rules |= BIT(TRIGGER_NETDEV_TX);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int aqr_phy_led_hw_control_set(struct phy_device *phydev, u8 index,
|
||||
+ unsigned long rules)
|
||||
+{
|
||||
+ u16 val = 0;
|
||||
+
|
||||
+ if (index >= AQR_NUM_LEDS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_100) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_LINK100;
|
||||
+
|
||||
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_LINK1000;
|
||||
+
|
||||
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_2500) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_LINK2500;
|
||||
+
|
||||
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_5000) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_LINK5000;
|
||||
+
|
||||
+ if (rules & (BIT(TRIGGER_NETDEV_LINK_10000) | BIT(TRIGGER_NETDEV_LINK)))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_LINK10000;
|
||||
+
|
||||
+ if (rules & BIT(TRIGGER_NETDEV_RX))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_RX_ACT;
|
||||
+
|
||||
+ if (rules & BIT(TRIGGER_NETDEV_TX))
|
||||
+ val |= VEND1_GLOBAL_LED_PROV_TX_ACT;
|
||||
+
|
||||
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_PROV(index),
|
||||
+ VEND1_GLOBAL_LED_PROV_LINK_MASK |
|
||||
+ VEND1_GLOBAL_LED_PROV_FORCE_ON |
|
||||
+ VEND1_GLOBAL_LED_PROV_RX_ACT |
|
||||
+ VEND1_GLOBAL_LED_PROV_TX_ACT, val);
|
||||
+}
|
||||
+
|
||||
+int aqr_phy_led_polarity_set(struct phy_device *phydev, int index, unsigned long modes)
|
||||
+{
|
||||
+ bool active_low = false;
|
||||
+ u32 mode;
|
||||
+
|
||||
+ if (index >= AQR_NUM_LEDS)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ for_each_set_bit(mode, &modes, __PHY_LED_MODES_NUM) {
|
||||
+ switch (mode) {
|
||||
+ case PHY_LED_ACTIVE_LOW:
|
||||
+ active_low = true;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return phy_modify_mmd(phydev, MDIO_MMD_VEND1, AQR_LED_DRIVE(index),
|
||||
+ VEND1_GLOBAL_LED_DRIVE_VDD,
|
||||
+ active_low ? VEND1_GLOBAL_LED_DRIVE_VDD : 0);
|
||||
+}
|
||||
--- a/drivers/net/phy/aquantia/aquantia_main.c
|
||||
+++ b/drivers/net/phy/aquantia/aquantia_main.c
|
||||
@@ -740,6 +740,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQCS109),
|
||||
@@ -759,6 +766,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR111),
|
||||
@@ -778,6 +792,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR111B0),
|
||||
@@ -797,6 +818,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR405),
|
||||
@@ -823,6 +851,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR412),
|
||||
@@ -841,6 +876,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR113),
|
||||
@@ -860,6 +902,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR113C),
|
||||
@@ -879,6 +928,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR114C),
|
||||
@@ -898,6 +954,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
{
|
||||
PHY_ID_MATCH_MODEL(PHY_ID_AQR813),
|
||||
@@ -917,6 +980,13 @@ static struct phy_driver aqr_driver[] =
|
||||
.get_strings = aqr107_get_strings,
|
||||
.get_stats = aqr107_get_stats,
|
||||
.link_change_notify = aqr107_link_change_notify,
|
||||
+#if IS_ENABLED(CONFIG_PHYLIB_LEDS)
|
||||
+ .led_brightness_set = aqr_phy_led_brightness_set,
|
||||
+ .led_hw_is_supported = aqr_phy_led_hw_is_supported,
|
||||
+ .led_hw_control_set = aqr_phy_led_hw_control_set,
|
||||
+ .led_hw_control_get = aqr_phy_led_hw_control_get,
|
||||
+ .led_polarity_set = aqr_phy_led_polarity_set,
|
||||
+#endif
|
||||
},
|
||||
};
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: debloat: disable common USB quirks
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/usb/host/pci-quirks.c | 16 ++++++++++++++++
|
||||
drivers/usb/host/pci-quirks.h | 18 +++++++++++++++++-
|
||||
include/linux/usb/hcd.h | 7 +++++++
|
||||
3 files changed, 40 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/usb/host/pci-quirks.c
|
||||
+++ b/drivers/usb/host/pci-quirks.c
|
||||
@@ -128,6 +128,8 @@ struct amd_chipset_type {
|
||||
u8 rev;
|
||||
};
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
+
|
||||
static struct amd_chipset_info {
|
||||
struct pci_dev *nb_dev;
|
||||
struct pci_dev *smbus_dev;
|
||||
@@ -631,6 +633,10 @@ bool usb_amd_pt_check_port(struct device
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
|
||||
|
||||
+#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
|
||||
+
|
||||
/*
|
||||
* Make sure the controller is completely inactive, unable to
|
||||
* generate interrupts or do DMA.
|
||||
@@ -710,8 +716,17 @@ reset_needed:
|
||||
uhci_reset_hc(pdev, base);
|
||||
return 1;
|
||||
}
|
||||
+#else
|
||||
+int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
+
|
||||
static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
|
||||
{
|
||||
u16 cmd;
|
||||
@@ -1283,3 +1298,4 @@ static void quirk_usb_early_handoff(stru
|
||||
}
|
||||
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
|
||||
+#endif
|
||||
--- a/drivers/usb/host/pci-quirks.h
|
||||
+++ b/drivers/usb/host/pci-quirks.h
|
||||
@@ -5,6 +5,9 @@
|
||||
#ifdef CONFIG_USB_PCI
|
||||
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
+#endif /* CONFIG_USB_PCI */
|
||||
+
|
||||
+#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
|
||||
int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
|
||||
bool usb_amd_hang_symptom_quirk(void);
|
||||
bool usb_amd_prefetch_quirk(void);
|
||||
@@ -19,6 +22,18 @@ void sb800_prefetch(struct device *dev,
|
||||
bool usb_amd_pt_check_port(struct device *device, int port);
|
||||
#else
|
||||
struct pci_dev;
|
||||
+static inline int usb_amd_quirk_pll_check(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static inline bool usb_amd_hang_symptom_quirk(void)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+static inline bool usb_amd_prefetch_quirk(void)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
static inline void usb_amd_quirk_pll_disable(void) {}
|
||||
static inline void usb_amd_quirk_pll_enable(void) {}
|
||||
static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
|
||||
@@ -29,6 +44,11 @@ static inline bool usb_amd_pt_check_port
|
||||
{
|
||||
return false;
|
||||
}
|
||||
+static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
+static inline bool usb_xhci_needs_pci_reset(struct pci_dev *pdev)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
#endif /* CONFIG_USB_PCI */
|
||||
|
||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||
--- a/include/linux/usb/hcd.h
|
||||
+++ b/include/linux/usb/hcd.h
|
||||
@@ -485,7 +485,14 @@ extern int usb_hcd_pci_probe(struct pci_
|
||||
extern void usb_hcd_pci_remove(struct pci_dev *dev);
|
||||
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
|
||||
+#else
|
||||
+static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
|
||||
#endif /* CONFIG_USB_PCI */
|
|
@ -1,26 +0,0 @@
|
|||
From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001
|
||||
From: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
Date: Sun, 18 Feb 2018 17:08:04 +0100
|
||||
Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio
|
||||
|
||||
In devices, where fdt is used, is impossible to apply platform data
|
||||
without proper fdt node.
|
||||
|
||||
This patch allow to use platform data in devices with fdt.
|
||||
|
||||
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
---
|
||||
drivers/w1/masters/w1-gpio.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/w1/masters/w1-gpio.c
|
||||
+++ b/drivers/w1/masters/w1-gpio.c
|
||||
@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform
|
||||
enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
|
||||
int err;
|
||||
|
||||
- if (of_have_populated_dt()) {
|
||||
+ if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) {
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
|
@ -1,37 +0,0 @@
|
|||
From 38eb5b3370c29515d2ce92adac2d6eba96f276f5 Mon Sep 17 00:00:00 2001
|
||||
From: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
Date: Wed, 20 Mar 2024 15:32:18 +0900
|
||||
Subject: [PATCH v2 1/2] dt-bindings: leds: add LED_FUNCTION_MOBILE for mobile
|
||||
network
|
||||
|
||||
Add LED_FUNCTION_MOBILE for LEDs that indicate status of mobile network
|
||||
connection. This is useful to distinguish those LEDs from LEDs that
|
||||
indicates status of wired "wan" connection.
|
||||
|
||||
example (on stock fw):
|
||||
|
||||
IIJ SA-W2 has "Mobile" LEDs that indicate status (no signal, too low,
|
||||
low, good) of mobile network connection via dongle connected to USB
|
||||
port.
|
||||
|
||||
- no signal: (none, turned off)
|
||||
- too low: green:mobile & red:mobile (amber, blink)
|
||||
- low: green:mobile & red:mobile (amber, turned on)
|
||||
- good: green:mobile (turned on)
|
||||
|
||||
Suggested-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
---
|
||||
include/dt-bindings/leds/common.h | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/include/dt-bindings/leds/common.h
|
||||
+++ b/include/dt-bindings/leds/common.h
|
||||
@@ -90,6 +90,7 @@
|
||||
#define LED_FUNCTION_INDICATOR "indicator"
|
||||
#define LED_FUNCTION_LAN "lan"
|
||||
#define LED_FUNCTION_MAIL "mail"
|
||||
+#define LED_FUNCTION_MOBILE "mobile"
|
||||
#define LED_FUNCTION_MTD "mtd"
|
||||
#define LED_FUNCTION_PANIC "panic"
|
||||
#define LED_FUNCTION_PROGRAMMING "programming"
|
|
@ -1,37 +0,0 @@
|
|||
From e22afe910afcfb51b6ba6a0ae776939959727f54 Mon Sep 17 00:00:00 2001
|
||||
From: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
Date: Wed, 20 Mar 2024 15:59:06 +0900
|
||||
Subject: [PATCH v2 2/2] dt-bindings: leds: add LED_FUNCTION_SPEED_* for link
|
||||
speed on LAN/WAN
|
||||
|
||||
Add LED_FUNCTION_SPEED_LAN and LED_FUNCTION_SPEED_WAN for LEDs that
|
||||
indicate link speed of ethernet ports on LAN/WAN. This is useful to
|
||||
distinguish those LEDs from LEDs that indicate link status (up/down).
|
||||
|
||||
example:
|
||||
|
||||
Fortinet FortiGate 30E/50E have LEDs that indicate link speed on each
|
||||
of the ethernet ports in addition to LEDs that indicate link status
|
||||
(up/down).
|
||||
|
||||
- 1000 Mbps: green:speed-(lan|wan)-N
|
||||
- 100 Mbps: amber:speed-(lan|wan)-N
|
||||
- 10 Mbps: (none, turned off)
|
||||
|
||||
Reviewed-by: Rob Herring <robh@kernel.org>
|
||||
Signed-off-by: INAGAKI Hiroshi <musashino.open@gmail.com>
|
||||
---
|
||||
include/dt-bindings/leds/common.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/include/dt-bindings/leds/common.h
|
||||
+++ b/include/dt-bindings/leds/common.h
|
||||
@@ -96,6 +96,8 @@
|
||||
#define LED_FUNCTION_PROGRAMMING "programming"
|
||||
#define LED_FUNCTION_RX "rx"
|
||||
#define LED_FUNCTION_SD "sd"
|
||||
+#define LED_FUNCTION_SPEED_LAN "speed-lan"
|
||||
+#define LED_FUNCTION_SPEED_WAN "speed-wan"
|
||||
#define LED_FUNCTION_STANDBY "standby"
|
||||
#define LED_FUNCTION_TORCH "torch"
|
||||
#define LED_FUNCTION_TX "tx"
|
|
@ -1,51 +0,0 @@
|
|||
From a7a94ca21ac0f347f683d33c72b4aab57ce5eec3 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Eckert <fe@dev.tdt.de>
|
||||
Date: Mon, 20 Nov 2023 11:13:20 +0100
|
||||
Subject: [PATCH] tools/thermal/tmon: Fix compilation warning for wrong format
|
||||
|
||||
The following warnings are shown during compilation:
|
||||
|
||||
tui.c: In function 'show_cooling_device':
|
||||
tui.c:216:40: warning: format '%d' expects argument of type 'int', but
|
||||
argument 7 has type 'long unsigned int' [-Wformat=]
|
||||
216 | "%02d %12.12s%6d %6d",
|
||||
| ~~^
|
||||
| |
|
||||
| int
|
||||
| %6ld
|
||||
......
|
||||
219 | ptdata.cdi[j].cur_state,
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| long unsigned int
|
||||
tui.c:216:44: warning: format '%d' expects argument of type 'int', but
|
||||
argument 8 has type 'long unsigned int' [-Wformat=]
|
||||
216 | "%02d %12.12s%6d %6d",
|
||||
| ~~^
|
||||
| |
|
||||
| int
|
||||
| %6ld
|
||||
......
|
||||
220 | ptdata.cdi[j].max_state);
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~
|
||||
| |
|
||||
| long unsigned int
|
||||
|
||||
To fix this, the correct string format must be used for printing.
|
||||
|
||||
Signed-off-by: Florian Eckert <fe@dev.tdt.de>
|
||||
---
|
||||
tools/thermal/tmon/tui.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/tools/thermal/tmon/tui.c
|
||||
+++ b/tools/thermal/tmon/tui.c
|
||||
@@ -213,7 +213,7 @@ void show_cooling_device(void)
|
||||
* cooling device instances. skip unused idr.
|
||||
*/
|
||||
mvwprintw(cooling_device_window, j + 2, 1,
|
||||
- "%02d %12.12s%6d %6d",
|
||||
+ "%02d %12.12s%6lu %6lu",
|
||||
ptdata.cdi[j].instance,
|
||||
ptdata.cdi[j].type,
|
||||
ptdata.cdi[j].cur_state,
|
|
@ -1,100 +0,0 @@
|
|||
From 6e6fff51ae5e54092611d174fa45fa78c237a415 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Marangi <ansuelsmth@gmail.com>
|
||||
Date: Tue, 21 May 2024 20:01:46 +0200
|
||||
Subject: [PATCH] net: phy: move LED polarity to phy_init_hw
|
||||
|
||||
Some PHY reset the polarity on reset and this cause the LED to
|
||||
malfunction as LED polarity is configured only when LED is
|
||||
registered.
|
||||
|
||||
To better handle this, move the LED polarity configuration in
|
||||
phy_init_hw to reconfigure it after PHY reset.
|
||||
|
||||
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 53 +++++++++++++++++++++++++-----------
|
||||
1 file changed, 37 insertions(+), 16 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1223,6 +1223,37 @@ static int phy_poll_reset(struct phy_dev
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int of_phy_led_init(struct phy_device *phydev)
|
||||
+{
|
||||
+ struct phy_led *phyled;
|
||||
+
|
||||
+ list_for_each_entry(phyled, &phydev->leds, list) {
|
||||
+ struct led_classdev *cdev = &phyled->led_cdev;
|
||||
+ struct device_node *np = cdev->dev->of_node;
|
||||
+ unsigned long modes = 0;
|
||||
+ int err;
|
||||
+
|
||||
+ if (of_property_read_bool(np, "active-low"))
|
||||
+ set_bit(PHY_LED_ACTIVE_LOW, &modes);
|
||||
+ if (of_property_read_bool(np, "inactive-high-impedance"))
|
||||
+ set_bit(PHY_LED_INACTIVE_HIGH_IMPEDANCE, &modes);
|
||||
+
|
||||
+ if (!modes)
|
||||
+ continue;
|
||||
+
|
||||
+ /* 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, phyled->index,
|
||||
+ modes);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int phy_init_hw(struct phy_device *phydev)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -1259,6 +1290,12 @@ int phy_init_hw(struct phy_device *phyde
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PHYLIB_LEDS)) {
|
||||
+ ret = of_phy_led_init(phydev);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(phy_init_hw);
|
||||
@@ -3204,7 +3241,6 @@ static int of_phy_led(struct phy_device
|
||||
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;
|
||||
@@ -3222,21 +3258,6 @@ static int of_phy_led(struct phy_device
|
||||
if (index > U8_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
- 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 (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;
|
Loading…
Add table
Add a link
Reference in a new issue