Merge Official Source

Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
Tianling Shen
2024-02-12 12:54:22 +08:00
182 changed files with 20197 additions and 1698 deletions

View File

@@ -9,15 +9,15 @@ include $(TOPDIR)/rules.mk
PKG_NAME:=uboot-envtools
PKG_DISTNAME:=u-boot
PKG_VERSION:=2023.07.02
PKG_RELEASE:=3
PKG_VERSION:=2024.01
PKG_RELEASE:=2
PKG_SOURCE:=$(PKG_DISTNAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
https://ftp.denx.de/pub/u-boot \
https://mirror.cyberbits.eu/u-boot \
ftp://ftp.denx.de/pub/u-boot
PKG_HASH:=6b6a48581c14abb0f95bd87c1af4d740922406d7b801002a9f94727fdde021d5
PKG_HASH:=b99611f1ed237bf3541bdc8434b68c96a6e05967061f992443cb30aabebef5b3
PKG_SOURCE_SUBDIR:=$(PKG_DISTNAME)-$(PKG_VERSION)
PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_DISTNAME)-$(PKG_VERSION)

View File

@@ -10,8 +10,6 @@ This reverts upstream commit
tools/env/fw_env_main.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tools/env/fw_env_main.c b/tools/env/fw_env_main.c
index 0b201b9e62..1d193bd437 100644
--- a/tools/env/fw_env_main.c
+++ b/tools/env/fw_env_main.c
@@ -73,7 +73,7 @@ void usage_printenv(void)
@@ -32,7 +30,7 @@ index 0b201b9e62..1d193bd437 100644
" -s, --script batch mode to minimize writes\n"
"\n"
"Examples:\n"
@@ -206,7 +206,7 @@ int parse_setenv_args(int argc, char *argv[])
@@ -206,7 +206,7 @@ int parse_setenv_args(int argc, char *ar
int main(int argc, char *argv[])
{
@@ -41,4 +39,3 @@ index 0b201b9e62..1d193bd437 100644
int lockfd = -1;
int retval = EXIT_SUCCESS;
char *_cmdname;

View File

@@ -0,0 +1,75 @@
From 9e3003f79d168eac7ee65cd457e3904e2fb4eea8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
Date: Wed, 13 Dec 2023 13:13:54 +0100
Subject: [PATCH] fw_env: keep calling read() until whole flash block is read
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It's totally valid for read() to provide less bytes than requested
maximum. It may happen if there is no more data available yet or source
pushes data in small chunks.
This actually happens when trying to read env data from NVMEM device.
Kernel may provide NVMEM content in page size parts (like 4096 B).
This fixes warnings like:
Warning on /sys/bus/nvmem/devices/u-boot-env0/nvmem: Attempted to read 16384 bytes but got 4096
Warning on /sys/bus/nvmem/devices/u-boot-env0/nvmem: Attempted to read 12288 bytes but got 4096
Warning on /sys/bus/nvmem/devices/u-boot-env0/nvmem: Attempted to read 8192 bytes but got 4096
Since the main loop in flash_read_buf() is used to read blocks this
patch adds a new nested one.
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
tools/env/fw_env.c | 34 +++++++++++++++-------------------
1 file changed, 15 insertions(+), 19 deletions(-)
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -948,29 +948,25 @@ static int flash_read_buf(int dev, int f
*/
lseek(fd, blockstart + block_seek, SEEK_SET);
- rc = read(fd, buf + processed, readlen);
- if (rc == -1) {
- fprintf(stderr, "Read error on %s: %s\n",
- DEVNAME(dev), strerror(errno));
- return -1;
- }
+ while (readlen) {
+ rc = read(fd, buf + processed, readlen);
+ if (rc == -1) {
+ fprintf(stderr, "Read error on %s: %s\n",
+ DEVNAME(dev), strerror(errno));
+ return -1;
+ }
#ifdef DEBUG
- fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
- rc, (unsigned long long)blockstart + block_seek,
- DEVNAME(dev));
+ fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
+ rc, (unsigned long long)blockstart + block_seek,
+ DEVNAME(dev));
#endif
- processed += rc;
- if (rc != readlen) {
- fprintf(stderr,
- "Warning on %s: Attempted to read %zd bytes but got %d\n",
- DEVNAME(dev), readlen, rc);
+ processed += rc;
readlen -= rc;
- block_seek += rc;
- } else {
- blockstart += blocklen;
- readlen = min(blocklen, count - processed);
- block_seek = 0;
}
+
+ blockstart += blocklen;
+ readlen = min(blocklen, count - processed);
+ block_seek = 0;
}
return processed;

View File

@@ -0,0 +1,49 @@
From d73a6641868029b5cae53ed00c5766921c9d8b1f Mon Sep 17 00:00:00 2001
From: Anthony Loiseau <anthony.loiseau@allcircuits.com>
Date: Thu, 21 Dec 2023 23:44:38 +0100
Subject: [PATCH] fw_env: autodetect NAND erase size and env sectors
As already done for NOR chips, if device ESIZE and ENVSECTORS static
configurations are both zero, then autodetect them at runtime.
Cc: Joe Hershberger <joe.hershberger@ni.com>
cc: Stefan Agner <stefan@agner.ch>
cc: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
Signed-off-by: Anthony Loiseau <anthony.loiseau@allcircuits.com>
---
tools/env/README | 3 +++
tools/env/fw_env.c | 11 +++++++++--
2 files changed, 12 insertions(+), 2 deletions(-)
--- a/tools/env/README
+++ b/tools/env/README
@@ -58,6 +58,9 @@ DEVICEx_ENVSECTORS defines the number of
this environment instance. On NAND this is used to limit the range
within which bad blocks are skipped, on NOR it is not used.
+If DEVICEx_ESIZE and DEVICEx_ENVSECTORS are both zero, then a runtime
+detection is attempted for NOR and NAND mtd types.
+
To prevent losing changes to the environment and to prevent confusing the MTD
drivers, a lock file at /run/fw_printenv.lock is used to serialize access
to the environment.
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -1655,8 +1655,15 @@ static int check_device_config(int dev)
}
DEVTYPE(dev) = mtdinfo.type;
if (DEVESIZE(dev) == 0 && ENVSECTORS(dev) == 0 &&
- mtdinfo.type == MTD_NORFLASH)
- DEVESIZE(dev) = mtdinfo.erasesize;
+ mtdinfo.erasesize > 0) {
+ if (mtdinfo.type == MTD_NORFLASH)
+ DEVESIZE(dev) = mtdinfo.erasesize;
+ else if (mtdinfo.type == MTD_NANDFLASH) {
+ DEVESIZE(dev) = mtdinfo.erasesize;
+ ENVSECTORS(dev) =
+ mtdinfo.size / mtdinfo.erasesize;
+ }
+ }
if (DEVESIZE(dev) == 0)
/* Assume the erase size is the same as the env-size */
DEVESIZE(dev) = ENVSIZE(dev);

View File

@@ -1,7 +1,7 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=qca-ssdk
PKG_RELEASE:=4
PKG_RELEASE:=5
PKG_SOURCE_URL:=https://git.codelinaro.org/clo/qsdk/oss/lklm/qca-ssdk.git
PKG_SOURCE_PROTO:=git
@@ -46,13 +46,17 @@ MAKE_FLAGS+= \
SoC=$(CONFIG_TARGET_SUBTARGET) \
PTP_FEATURE=disable SWCONFIG_FEATURE=disable \
ISISC_ENABLE=disable IN_QCA803X_PHY=FALSE \
IN_QCA808X_PHY=FALSE \
IN_QCA808X_PHY=FALSE IN_MALIBU_PHY=FALSE \
$(LNX_CONFIG_OPTS)
ifeq ($(CONFIG_TARGET_SUBTARGET), "ipq807x")
MAKE_FLAGS+= CHIP_TYPE=HPPE
endif
ifeq ($(CONFIG_TARGET_SUBTARGET), "ipq60xx")
MAKE_FLAGS+= CHIP_TYPE=CPPE
endif
define Build/InstallDev
$(INSTALL_DIR) $(1)/usr/include/qca-ssdk
$(INSTALL_DIR) $(1)/usr/include/qca-ssdk/api

View File

@@ -1,65 +0,0 @@
From 1d37f4ee9b9588a62bfc87419c8a6d9ef989aa9c Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Tue, 7 Nov 2023 12:23:09 +0100
Subject: [PATCH 1/3] qca807x: add a LED quirk for Xiaomi AX9000
Xiaomi AX9000 has a single LED for each of 4 gigabit ethernet ports that
are connected to QCA8075, and that LED is connected to the 100M LED pin.
So, by default it will only work when in 10 or 100Mbit mode, this is quite
annoying and makes no sense(If they have connected it to the 1000Mbit LED
pin then it would have worked for 10/100 by default as well).
So, to solve this add a check for system compatible as we cant parse if
from DTS in any other way and set the 100M LED to blink on 1000Base-T
as well.
Signed-off-by: Robert Marko <robimarko@gmail.com>
---
include/hsl/phy/malibu_phy.h | 2 ++
src/hsl/phy/malibu_phy.c | 9 +++++++++
2 files changed, 11 insertions(+)
--- a/include/hsl/phy/malibu_phy.h
+++ b/include/hsl/phy/malibu_phy.h
@@ -94,6 +94,7 @@ extern "C"
#define MALIBU_DAC_CTRL_MASK 0x380
#define MALIBU_DAC_CTRL_VALUE 0x280
#define MALIBU_LED_1000_CTRL1_100_10_MASK 0x30
+#define MALIBU_LED_100_CTRL1_1000_MASK 0x40
#define MALIBU_PHY_EEE_ADV_100M 0x0002
#define MALIBU_PHY_EEE_ADV_1000M 0x0004
@@ -118,6 +119,7 @@ extern "C"
#define MALIBU_PHY_MMD7_EGRESS_COUNTER_HIGH 0x802d
#define MALIBU_PHY_MMD7_EGRESS_COUNTER_LOW 0x802e
#define MALIBU_PHY_MMD7_EGRESS_ERROR_COUNTER 0x802f
+#define MALIBU_PHY_MMD7_LED_100_CTRL1 0x8074
#define MALIBU_PHY_MMD7_LED_1000_CTRL1 0x8076
--- a/src/hsl/phy/malibu_phy.c
+++ b/src/hsl/phy/malibu_phy.c
@@ -15,6 +15,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <linux/of.h>
+
#include "sw.h"
#include "fal_port_ctrl.h"
#include "hsl_api.h"
@@ -1809,6 +1811,13 @@ malibu_phy_hw_init(a_uint32_t dev_id, a_
hsl_phy_modify_mmd(dev_id, phy_addr, A_FALSE, MALIBU_PHY_MMD7_NUM,
MALIBU_PHY_MMD7_LED_1000_CTRL1, MALIBU_LED_1000_CTRL1_100_10_MASK,
MALIBU_LED_1000_CTRL1_100_10_MASK);
+ if (of_machine_is_compatible("xiaomi,ax9000")) {
+ /* add 1000M link LED behavior for Xiaomi AX9000 */
+ hsl_phy_modify_mmd(dev_id, phy_addr, A_FALSE, MALIBU_PHY_MMD7_NUM,
+ MALIBU_PHY_MMD7_LED_100_CTRL1,
+ MALIBU_LED_100_CTRL1_1000_MASK,
+ MALIBU_LED_100_CTRL1_1000_MASK);
+ }
/*disable Extended next page*/
hsl_phy_modify_mii(dev_id, phy_addr, MALIBU_AUTONEG_ADVERT,
MALIBU_EXTENDED_NEXT_PAGE_EN, 0);

View File

@@ -1,29 +0,0 @@
From 957ee476ddec289973e0af07917da7bfee660af0 Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Tue, 7 Nov 2023 12:24:17 +0100
Subject: [PATCH 2/3] qca807x: add a LED quirk for Xiaomi AX3600
AX3600 requires the same LED quirk so that PHY LED-s will blink even
once Linux resets the PHY.
So, just check for its compatible.
Signed-off-by: Robert Marko <robimarko@gmail.com>
---
src/hsl/phy/malibu_phy.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/src/hsl/phy/malibu_phy.c
+++ b/src/hsl/phy/malibu_phy.c
@@ -1811,8 +1811,9 @@ malibu_phy_hw_init(a_uint32_t dev_id, a_
hsl_phy_modify_mmd(dev_id, phy_addr, A_FALSE, MALIBU_PHY_MMD7_NUM,
MALIBU_PHY_MMD7_LED_1000_CTRL1, MALIBU_LED_1000_CTRL1_100_10_MASK,
MALIBU_LED_1000_CTRL1_100_10_MASK);
- if (of_machine_is_compatible("xiaomi,ax9000")) {
- /* add 1000M link LED behavior for Xiaomi AX9000 */
+ if (of_machine_is_compatible("xiaomi,ax9000") ||
+ of_machine_is_compatible("xiaomi,ax3600")) {
+ /* add 1000M link LED behavior for Xiaomi boards */
hsl_phy_modify_mmd(dev_id, phy_addr, A_FALSE, MALIBU_PHY_MMD7_NUM,
MALIBU_PHY_MMD7_LED_100_CTRL1,
MALIBU_LED_100_CTRL1_1000_MASK,

View File

@@ -0,0 +1,25 @@
From e3763fd77e41b2f2495672c6a5898d69892fbf9f Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Wed, 15 Nov 2023 00:57:41 +0100
Subject: [PATCH] hsl_phy: add support for detection PSGMII PHY mode
Add support for detection of PSGMII PHY mode to correctly detect qca807x
PHY upstream driver.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
src/hsl/phy/hsl_phy.c | 3 +++
1 file changed, 3 insertions(+)
--- a/src/hsl/phy/hsl_phy.c
+++ b/src/hsl/phy/hsl_phy.c
@@ -1335,6 +1335,9 @@ hsl_port_phydev_interface_mode_status_ge
case PHY_INTERFACE_MODE_10GKR:
*interface_mode_status = PORT_10GBASE_R;
break;
+ case PHY_INTERFACE_MODE_PSGMII:
+ *interface_mode_status = PHY_PSGMII_BASET;
+ break;
case PHY_INTERFACE_MODE_QSGMII:
*interface_mode_status = PORT_QSGMII;
break;

View File

@@ -49,7 +49,7 @@ function __phy_is_fullmac(phyidx)
{
let data = nl80211.request(nl80211.const.NL80211_CMD_GET_WIPHY, 0, { wiphy: phyidx });
return !data.software_iftypes.ap_vlan;
return !data.software_iftypes.monitor;
}
function phy_is_fullmac(phy)

View File

@@ -12,7 +12,6 @@ config DROPBEAR_CURVE25519
config DROPBEAR_ECC
bool "Elliptic curve cryptography (ECC)"
default n
help
Enables basic support for elliptic curve cryptography (ECC)
in key exchange and public key authentication.
@@ -25,11 +24,10 @@ config DROPBEAR_ECC
Increases binary size by about 24 kB (MIPS).
If full ECC support is required, also select DROPBEAR_ECC_FULL.
Note: select DROPBEAR_ECC_FULL if full ECC support is required.
config DROPBEAR_ECC_FULL
bool "Elliptic curve cryptography (ECC), full support"
default n
depends on DROPBEAR_ECC
help
Enables full support for elliptic curve cryptography (ECC)
@@ -67,46 +65,62 @@ config DROPBEAR_CHACHA20POLY1305
Increases binary size by about 4 kB (MIPS).
config DROPBEAR_U2F
bool "U2F/FIDO support"
default y
help
This option itself doesn't enable any support for U2F/FIDO
but subordinate options do:
- DROPBEAR_ECDSA_SK - ecdsa-sk keys support
depends on DROPBEAR_ECC ("Elliptic curve cryptography (ECC)")
- DROPBEAR_ED25519_SK - ed25519-sk keys support
depends on DROPBEAR_ED25519 ("Ed25519 support")
config DROPBEAR_ECDSA_SK
bool "ECDSA-SK support"
default y
depends on DROPBEAR_U2F && DROPBEAR_ECC
help
This enables the following public key algorithm:
sk-ecdsa-sha2-nistp256@openssh.com
config DROPBEAR_ED25519_SK
bool "Ed25519-SK support"
default y
depends on DROPBEAR_U2F && DROPBEAR_ED25519
help
This enables the following public key algorithm:
sk-ssh-ed25519@openssh.com
config DROPBEAR_ZLIB
bool "Enable compression"
default n
help
Enables compression using shared zlib library.
Increases binary size by about 0.1 kB (MIPS) and requires additional 62 kB (MIPS)
for a shared zlib library.
Increases binary size by about 0.1 kB (MIPS) and requires
additional 62 kB (MIPS) for a shared zlib library.
config DROPBEAR_UTMP
bool "Utmp support"
default n
depends on BUSYBOX_CONFIG_FEATURE_UTMP
help
This enables dropbear utmp support, the file /var/run/utmp is used to
track who is currently logged in.
This enables dropbear utmp support, the file /var/run/utmp is
used to track who is currently logged in.
config DROPBEAR_PUTUTLINE
bool "Pututline support"
default n
depends on DROPBEAR_UTMP
help
Dropbear will use pututline() to write the utmp structure into the utmp file.
Dropbear will use pututline() to write the utmp structure into
the utmp file.
config DROPBEAR_DBCLIENT
bool "Build dropbear with dbclient"
default y
config DROPBEAR_DBCLIENT_AGENTFORWARD
bool "Enable agent forwarding in dbclient"
default y
depends on DROPBEAR_DBCLIENT
config DROPBEAR_SCP
bool "Build dropbear with scp"
default y
config DROPBEAR_ASKPASS
bool "Enable askpass helper support"
default n
depends on DROPBEAR_DBCLIENT
help
This enables support for ssh-askpass helper in dropbear client
@@ -114,8 +128,70 @@ config DROPBEAR_ASKPASS
Increases binary size by about 0.1 kB (MIPS).
config DROPBEAR_AGENTFORWARD
bool "Enable agent forwarding"
config DROPBEAR_DBCLIENT_AGENTFORWARD
bool "Enable agent forwarding in dbclient [LEGACY/SECURITY]"
default y
depends on DROPBEAR_DBCLIENT
help
Increases binary size by about 0.1 kB (MIPS).
Security notes:
SSH agent forwarding might cause security issues (locally and
on the jump machine).
Hovewer, it's enabled by default for compatibility with
previous OpenWrt/dropbear releases.
Consider DISABLING this option if you're building own OpenWrt
image.
Also see DROPBEAR_AGENTFORWARD (agent forwarding in dropbear
server itself).
config DROPBEAR_SCP
bool "Build dropbear with scp"
default y
config DROPBEAR_AGENTFORWARD
bool "Enable agent forwarding [LEGACY/SECURITY]"
default y
help
Increases binary size by about 0.1 kB (MIPS).
Security notes:
SSH agent forwarding might cause security issues (locally and
on the jump machine).
Hovewer, it's enabled by default for compatibility with
previous OpenWrt/dropbear releases.
Consider DISABLING this option if you're building own OpenWrt
image.
Also see DROPBEAR_DBCLIENT_AGENTFORWARD (agent forwarding in
dropbear client) if DROPBEAR_DBCLIENT is selected.
config DROPBEAR_MODERN_ONLY
bool "Use modern crypto only [BREAKS COMPATIBILITY]"
select DROPBEAR_ED25519
select DROPBEAR_CURVE25519
select DROPBEAR_CHACHA20POLY1305
help
This option enables:
- Chacha20-Poly1305
- Curve25519
- Ed25519
and disables:
- AES
- RSA
- SHA1
Reduces binary size by about 64 kB (MIPS) from default
configuration.
Consider enabling this option if you're building own OpenWrt
image and using modern SSH software everywhere.
endmenu

View File

@@ -8,14 +8,14 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=dropbear
PKG_VERSION:=2022.82
PKG_RELEASE:=5
PKG_VERSION:=2022.83
PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2
PKG_SOURCE_URL:= \
https://matt.ucc.asn.au/dropbear/releases/ \
https://dropbear.nl/mirror/releases/
PKG_HASH:=3a038d2bbc02bf28bbdd20c012091f741a3ec5cbe460691811d714876aad75d1
PKG_HASH:=bc5a121ffbc94b5171ad5ebe01be42746d50aa797c9549a4639894a16749443b
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE libtomcrypt/LICENSE libtommath/LICENSE
@@ -31,9 +31,11 @@ PKG_CONFIG_DEPENDS:= \
CONFIG_TARGET_INIT_PATH CONFIG_DROPBEAR_ECC CONFIG_DROPBEAR_ECC_FULL \
CONFIG_DROPBEAR_CURVE25519 CONFIG_DROPBEAR_ZLIB \
CONFIG_DROPBEAR_ED25519 CONFIG_DROPBEAR_CHACHA20POLY1305 \
CONFIG_DROPBEAR_U2F CONFIG_DROPBEAR_ECDSA_SK CONFIG_DROPBEAR_ED25519_SK \
CONFIG_DROPBEAR_UTMP CONFIG_DROPBEAR_PUTUTLINE \
CONFIG_DROPBEAR_DBCLIENT CONFIG_DROPBEAR_SCP CONFIG_DROPBEAR_ASKPASS \
CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD CONFIG_DROPBEAR_AGENTFORWARD
CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD CONFIG_DROPBEAR_AGENTFORWARD \
CONFIG_DROPBEAR_MODERN_ONLY
include $(INCLUDE_DIR)/package.mk
@@ -68,10 +70,11 @@ define Package/dropbear/description
endef
define Package/dropbear/conffiles
$(if $(CONFIG_DROPBEAR_ED25519),/etc/dropbear/dropbear_ed25519_host_key)
$(if $(CONFIG_DROPBEAR_ECC),/etc/dropbear/dropbear_ecdsa_host_key)
/etc/dropbear/dropbear_rsa_host_key
/etc/config/dropbear
/etc/dropbear/authorized_keys
/etc/dropbear/dropbear_ecdsa_host_key
/etc/dropbear/dropbear_ed25519_host_key
/etc/dropbear/dropbear_rsa_host_key
endef
define Package/dropbearconvert
@@ -99,79 +102,100 @@ CONFIGURE_ARGS += \
##############################################################################
#
# option|value - add option to localoptions.h
# !!option|value - replace option in sysoptions.h
# option,value - add option to localoptions.h
# !!option,value - replace option in sysoptions.h
#
##############################################################################
# adjust allowed shell list (if getusershell(3) is missing):
# - COMPAT_USER_SHELLS
# remove protocol idented software version number:
# - LOCAL_IDENT
# disable legacy/unsafe methods and unused functionality:
# - DROPBEAR_CLI_NETCAT
# - DROPBEAR_DSS
# - DO_MOTD
# - DROPBEAR_DH_GROUP14_SHA1
# - DROPBEAR_SHA1_HMAC
DB_OPT_COMMON = \
DEFAULT_PATH|"$(TARGET_INIT_PATH)" \
!!LOCAL_IDENT|"SSH-2.0-dropbear" \
DROPBEAR_CLI_NETCAT|0 \
DROPBEAR_DSS|0 \
DO_MOTD|0 \
!!LOCAL_IDENT,"SSH-2.0-dropbear" \
COMPAT_USER_SHELLS,"/bin/ash","/bin/sh" \
DEFAULT_PATH,"$(TARGET_INIT_PATH)" \
DEFAULT_ROOT_PATH,"$(TARGET_INIT_PATH)" \
DROPBEAR_DSS,0 \
DROPBEAR_CLI_NETCAT,0 \
DO_MOTD,0 \
DROPBEAR_DH_GROUP14_SHA1,0 \
DROPBEAR_SHA1_HMAC,0 \
##############################################################################
#
# option|config|enabled|disabled = add option to localoptions.h
# !!option|config|enabled|disabled = replace option in sysoptions.h
# option,config,enabled,disabled = add option to localoptions.h
# !!option,config,enabled,disabled = replace option in sysoptions.h
#
# option := (config) ? enabled : disabled
#
##############################################################################
DB_OPT_CONFIG = \
DROPBEAR_CURVE25519|CONFIG_DROPBEAR_CURVE25519|1|0 \
DROPBEAR_ED25519|CONFIG_DROPBEAR_ED25519|1|0 \
DROPBEAR_SK_ED25519|CONFIG_DROPBEAR_ED25519|1|0 \
DROPBEAR_CHACHA20POLY1305|CONFIG_DROPBEAR_CHACHA20POLY1305|1|0 \
DROPBEAR_ECDSA|CONFIG_DROPBEAR_ECC|1|0 \
DROPBEAR_SK_ECDSA|CONFIG_DROPBEAR_ECC|1|0 \
DROPBEAR_ECDH|CONFIG_DROPBEAR_ECC|1|0 \
!!DROPBEAR_ECC_384|CONFIG_DROPBEAR_ECC_FULL|1|0 \
!!DROPBEAR_ECC_521|CONFIG_DROPBEAR_ECC_FULL|1|0 \
DROPBEAR_CLI_ASKPASS_HELPER|CONFIG_DROPBEAR_ASKPASS|1|0 \
DROPBEAR_CLI_AGENTFWD|CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD|1|0 \
DROPBEAR_SVR_AGENTFWD|CONFIG_DROPBEAR_AGENTFORWARD|1|0 \
!!DROPBEAR_ECC_384,CONFIG_DROPBEAR_ECC_FULL,1,0 \
!!DROPBEAR_ECC_521,CONFIG_DROPBEAR_ECC_FULL,1,0 \
DROPBEAR_CURVE25519,CONFIG_DROPBEAR_CURVE25519,1,0 \
DROPBEAR_CHACHA20POLY1305,CONFIG_DROPBEAR_CHACHA20POLY1305,1,0 \
DROPBEAR_ED25519,CONFIG_DROPBEAR_ED25519,1,0 \
DROPBEAR_ECDSA,CONFIG_DROPBEAR_ECC,1,0 \
DROPBEAR_ECDH,CONFIG_DROPBEAR_ECC,1,0 \
DROPBEAR_SK_KEYS,CONFIG_DROPBEAR_U2F,1,0 \
DROPBEAR_SK_ECDSA,CONFIG_DROPBEAR_ECDSA_SK,1,0 \
DROPBEAR_SK_ED25519,CONFIG_DROPBEAR_ED25519_SK,1,0 \
DROPBEAR_CLI_ASKPASS_HELPER,CONFIG_DROPBEAR_ASKPASS,1,0 \
DROPBEAR_CLI_AGENTFWD,CONFIG_DROPBEAR_DBCLIENT_AGENTFORWARD,1,0 \
DROPBEAR_SVR_AGENTFWD,CONFIG_DROPBEAR_AGENTFORWARD,1,0 \
DROPBEAR_AES128,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
DROPBEAR_AES256,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
DROPBEAR_ENABLE_CTR_MODE,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
DROPBEAR_RSA,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
DROPBEAR_RSA_SHA1,CONFIG_DROPBEAR_MODERN_ONLY,0,1 \
TARGET_CFLAGS += -DARGTYPE=3
xsedx:=$(shell printf '\027')
db_opt_add =echo '\#define $(1) $(2)' >> $(PKG_BUILD_DIR)/localoptions.h
db_opt_replace =$(ESED) 's,^(\#define $(1)) .*$$$$,\1 $(2),g' $(PKG_BUILD_DIR)/sysoptions.h
db_opt_replace =$(ESED) '/^\#define $(1) .*$$$$/{h;:a;$$$$!n;/^\#.+$$$$/bb;/^$$$$/bb;H;ba;:b;x;s$(xsedx)^.+$$$$$(xsedx)\#define $(1) $(2)$(xsedx)p;x};p' -n $(PKG_BUILD_DIR)/sysoptions.h
define Build/Configure/dropbear_headers
$(strip $(foreach s,$(DB_OPT_COMMON), \
$(if $(filter !!%,$(word 1,$(subst |, ,$(s)))), \
$(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst |, ,$(s)))),$(word 2,$(subst |, ,$(s)))), \
$(call db_opt_add,$(word 1,$(subst |, ,$(s))),$(word 2,$(subst |, ,$(s)))) \
$(if $(filter !!%,$(word 1,$(subst $(comma),$(space),$(s)))), \
$(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst $(comma),$(space),$(s)))),$(subst $(space),$(comma),$(wordlist 2,$(words $(subst $(comma),$(space),$(s))),$(subst $(comma),$(space),$(s))))), \
$(call db_opt_add,$(word 1,$(subst $(comma),$(space),$(s))),$(subst $(space),$(comma),$(wordlist 2,$(words $(subst $(comma),$(space),$(s))),$(subst $(comma),$(space),$(s))))) \
) ; \
))
$(strip $(foreach s,$(DB_OPT_CONFIG), \
$(if $(filter !!%,$(word 1,$(subst |, ,$(s)))), \
$(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst |, ,$(s)))),$(if $($(word 2,$(subst |, ,$(s)))),$(word 3,$(subst |, ,$(s))),$(word 4,$(subst |, ,$(s))))), \
$(call db_opt_add,$(word 1,$(subst |, ,$(s))),$(if $($(word 2,$(subst |, ,$(s)))),$(word 3,$(subst |, ,$(s))),$(word 4,$(subst |, ,$(s))))) \
$(if $(filter !!%,$(word 1,$(subst $(comma),$(space),$(s)))), \
$(call db_opt_replace,$(patsubst !!%,%,$(word 1,$(subst $(comma),$(space),$(s)))),$(if $($(word 2,$(subst $(comma),$(space),$(s)))),$(word 3,$(subst $(comma),$(space),$(s))),$(word 4,$(subst $(comma),$(space),$(s))))), \
$(call db_opt_add,$(word 1,$(subst $(comma),$(space),$(s))),$(if $($(word 2,$(subst $(comma),$(space),$(s)))),$(word 3,$(subst $(comma),$(space),$(s))),$(word 4,$(subst $(comma),$(space),$(s))))) \
) ; \
))
endef
define Build/Configure
: > $(PKG_BUILD_DIR)/localoptions.h
define Build/Configure/dropbear_objects
grep -ERZl -e '($(subst $(space),|,$(strip $(sort $(patsubst !!%,%,$(foreach s,$(DB_OPT_COMMON) $(DB_OPT_CONFIG),$(word 1,$(subst $(comma),$(space),$(s)))))))))' \
$(PKG_BUILD_DIR)/ | sed -zE 's/^(.+)\.[^.]+$$$$/\1.o/' | sort -uV | xargs -0 -r rm -fv || :
endef
define Build/Configure
rm -f $(PKG_BUILD_DIR)/localoptions.h
$(Build/Configure/Default)
: > $(PKG_BUILD_DIR)/localoptions.h
$(Build/Configure/dropbear_headers)
# Enforce rebuild of svr-chansession.c
rm -f $(PKG_BUILD_DIR)/svr-chansession.o
# Enforce rebuild of files depending on configured options
$(Build/Configure/dropbear_objects)
# Rebuild them on config change
+$(MAKE) -C $(PKG_BUILD_DIR)/libtomcrypt clean
@@ -181,10 +205,12 @@ endef
define Build/Compile
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
IGNORE_SPEED=1 \
PROGRAMS="dropbear $(if $(CONFIG_DROPBEAR_DBCLIENT),dbclient,) dropbearkey $(if $(CONFIG_DROPBEAR_SCP),scp,)" \
MULTI=1 SCPPROGRESS=1
+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
$(TARGET_CONFIGURE_OPTS) \
IGNORE_SPEED=1 \
PROGRAMS="dropbearconvert"
endef
@@ -202,9 +228,7 @@ define Package/dropbear/install
$(INSTALL_DIR) $(1)/etc/dropbear
$(INSTALL_DIR) $(1)/lib/preinit
$(INSTALL_DATA) ./files/dropbear.failsafe $(1)/lib/preinit/99_10_failsafe_dropbear
$(if $(CONFIG_DROPBEAR_ED25519),touch $(1)/etc/dropbear/dropbear_ed25519_host_key)
$(if $(CONFIG_DROPBEAR_ECC),touch $(1)/etc/dropbear/dropbear_ecdsa_host_key)
touch $(1)/etc/dropbear/dropbear_rsa_host_key
$(foreach f,$(filter /etc/dropbear/%,$(Package/dropbear/conffiles)),$(if $(wildcard $(TOPDIR)/files/$(f)),chmod 0600 $(TOPDIR)/files/$(f) || :; ))
endef
define Package/dropbearconvert/install

View File

@@ -1,9 +1,61 @@
#!/bin/sh
_dropbear()
{
/usr/sbin/dropbear "$@" </dev/null >/dev/null 2>&1
}
_dropbearkey()
{
/usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
}
_ensurekey()
{
_dropbearkey -y -f "$1" && return
rm -f "$1"
_dropbearkey -f "$@" || {
rm -f "$1"
return 1
}
}
ktype_all='ed25519 ecdsa rsa'
failsafe_dropbear () {
dropbearkey -t rsa -s 1024 -f /tmp/dropbear_rsa_failsafe_host_key
dropbearkey -t ed25519 -f /tmp/dropbear_ed25519_failsafe_host_key
dropbear -r /tmp/dropbear_rsa_failsafe_host_key -r /tmp/dropbear_ed25519_failsafe_host_key <> /dev/null 2>&1
local kargs kcount ktype tkey
kargs=
kcount=0
for ktype in ${ktype_all} ; do
tkey="/tmp/dropbear_failsafe_${ktype}_host_key"
case "${ktype}" in
ed25519) _ensurekey "${tkey}" -t ed25519 ;;
ecdsa) _ensurekey "${tkey}" -t ecdsa -s 256 ;;
rsa) _ensurekey "${tkey}" -t rsa -s 1024 ;;
*)
echo "unknown key type: ${ktype}" >&2
continue
;;
esac
[ -s "${tkey}" ] || {
rm -f "${tkey}"
continue
}
chmod 0400 "${tkey}"
kargs="${kargs}${kargs:+ }-r ${tkey}"
kcount=$((kcount+1))
done
[ "${kcount}" != 0 ] || {
echo 'DROPBEAR IS BROKEN' >&2
return 1
}
_dropbear ${kargs}
}
boot_hook_add failsafe failsafe_dropbear

View File

@@ -12,28 +12,52 @@ PIDCOUNT=0
extra_command "killclients" "Kill ${NAME} processes except servers and yourself"
# most of time real_stat() will be failing
# due to missing "stat" binary (by default)
real_stat() { env stat -L "$@" 2>/dev/null ; }
dumb_stat() { ls -Ldln "$1" | tr -s '\t ' ' ' ; }
stat_perm() { real_stat -c '%A' "$1" || dumb_stat "$1" | cut -d ' ' -f 1 ; }
stat_owner() { real_stat -c '%u' "$1" || dumb_stat "$1" | cut -d ' ' -f 3 ; }
_dropbearkey()
{
/usr/bin/dropbearkey "$@" 0<&- 1>&- 2>&-
/usr/bin/dropbearkey "$@" </dev/null >/dev/null 2>&1
}
# $1 - host key file name
hk_verify()
# $1 - file name (host key or config)
file_verify()
{
[ -f "$1" ] || return 1
[ -s "$1" ] || return 2
_dropbearkey -y -f "$1" || return 3
# checking file ownership
[ "$(stat_owner "$1")" = "0" ] || {
chown 0 "$1"
[ "$(stat_owner "$1")" = "0" ] || return 2
}
# checking file permissions
[ "$(stat_perm "$1")" = "-rw-------" ] || {
chmod 0600 "$1"
[ "$(stat_perm "$1")" = "-rw-------" ] || return 3
}
# file is host key or not?
# if $2 is empty string - file is "host key"
# if $2 is non-empty string - file is "config"
[ -z "$2" ] || return 0
# checking file contents (finally)
[ -s "$1" ] || return 4
_dropbearkey -y -f "$1" || return 5
return 0
}
# $1 - hk_verify() return code
hk_errmsg()
# $1 - file_verify() return code
file_errmsg()
{
case "$1" in
0) ;;
1) echo "file does not exist" ;;
2) echo "file has zero length" ;;
3) echo "file is not valid host key or not supported" ;;
2) echo "file has wrong owner (must be owned by root)" ;;
3) echo "file has wrong permissions (must not have group/other write bit)" ;;
4) echo "file has zero length" ;;
5) echo "file is not valid host key or not supported" ;;
*) echo "unknown error" ;;
esac
}
@@ -43,73 +67,97 @@ hk_errmsg()
hk_config()
{
local x m
hk_verify "$2"; x=$?
case "$x" in
0) procd_append_param command -r "$2"
;;
*) m=$(hk_errmsg "$x")
logger -t "${NAME}" -p daemon.warn \
"option '$1', value '$2': $m, skipping"
;;
esac
file_verify "$2" ; x=$?
if [ "$x" = 0 ] ; then
procd_append_param command -r "$2"
return
fi
m=$(file_errmsg "$x")
logger -s -t "${NAME}" -p daemon.warn \
"Option '$1', skipping '$2': $m"
}
# $1 - host key file name
hk_config__keyfile()
{
hk_config 'keyfile' "$1"
}
hk_config__keyfile() { hk_config keyfile "$1" ; }
ktype_all='ed25519 ecdsa rsa'
hk_generate_as_needed()
{
local kdir kgen ktype tdir kcount tfile
kdir='/etc/dropbear'
local hk_cfg_dir kgen ktype kfile hk_tmp_dir
hk_cfg_dir='/etc/dropbear'
kgen=''
for ktype in ed25519 ecdsa rsa; do
hk_verify "${kdir}/dropbear_${ktype}_host_key" && continue
[ -d "${hk_cfg_dir}" ] || mkdir -p "${hk_cfg_dir}"
kgen="${kgen} ${ktype}"
kgen=
for ktype in ${ktype_all} ; do
kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
if file_verify "${kfile}" ; then continue ; fi
kgen="${kgen}${kgen:+ }${ktype}"
done
[ -z "${kgen}" ] && return
# all keys are sane?
[ -n "${kgen}" ] || return 0
tdir=$(mktemp -d); chmod 0700 "${tdir}"
hk_tmp_dir=$(mktemp -d)
# system in bad state?
[ -n "${hk_tmp_dir}" ] || return 1
kcount=0
for ktype in ${kgen}; do
tfile="${tdir}/dropbear_${ktype}_host_key"
chmod 0700 "${hk_tmp_dir}"
if ! _dropbearkey -t ${ktype} -f "${tfile}"; then
for ktype in ${kgen} ; do
kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
if ! _dropbearkey -t ${ktype} -f "${kfile}" ; then
# unsupported key type
rm -f "${tfile}"
rm -f "${kfile}"
continue
fi
kcount=$((kcount+1))
chmod 0600 "${kfile}"
done
if [ ${kcount} -ne 0 ]; then
mkdir -p "${kdir}"; chmod 0700 "${kdir}"; chown root "${kdir}"
mv -f "${tdir}/"* "${kdir}/"
kgen=
for ktype in ${ktype_all} ; do
kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
[ -s "${kfile}" ] || continue
kgen="${kgen}${kgen:+ }${ktype}"
done
if [ -n "${kgen}" ] ; then
for ktype in ${kgen} ; do
kfile="${hk_tmp_dir}/dropbear_${ktype}_host_key"
[ -s "${kfile}" ] || continue
mv -f "${kfile}" "${hk_cfg_dir}/"
done
fi
rm -rf "${tdir}"
rm -rf "${hk_tmp_dir}"
# cleanup empty files
for ktype in ${ktype_all} ; do
kfile="${hk_cfg_dir}/dropbear_${ktype}_host_key"
[ -s "${kfile}" ] || rm -f "${kfile}"
done
}
append_ports()
# $1 - list with whitespace-separated elements
normalize_list()
{
local ipaddrs="$1"
local port="$2"
printf '%s' "$1" | tr -s ' \r\n\t' ' ' | sed -E 's/^ //;s/ $//'
}
[ -z "$ipaddrs" ] && {
procd_append_param command -p "$port"
return
}
for addr in $ipaddrs; do
procd_append_param command -p "$addr:$port"
done
warn_multiple_interfaces()
{
logger -t "${NAME}" -p daemon.warn \
"Option '$1' should specify SINGLE interface but instead it lists interfaces: $2"
logger -t "${NAME}" -p daemon.warn \
"Consider creating per-interface instances instead!"
}
validate_section_dropbear()
@@ -117,6 +165,7 @@ validate_section_dropbear()
uci_load_validate dropbear dropbear "$1" "$2" \
'PasswordAuth:bool:1' \
'enable:bool:1' \
'DirectInterface:string' \
'Interface:string' \
'GatewayPorts:bool:0' \
'ForceCommand:string' \
@@ -129,59 +178,181 @@ validate_section_dropbear()
'SSHKeepAlive:uinteger:300' \
'IdleTimeout:uinteger:0' \
'MaxAuthTries:uinteger:3' \
'RecvWindowSize:uinteger:0' \
'RecvWindowSize:uinteger:262144' \
'mdns:bool:1'
}
dropbear_instance()
{
local ipaddrs
[ "$2" = 0 ] || {
echo "validation failed"
return 1
}
[ -n "${Interface}" ] && {
[ -n "${BOOT}" ] && return 0
[ "${enable}" = "1" ] || return 1
network_get_ipaddrs_all ipaddrs "${Interface}" || {
echo "interface ${Interface} has no physdev or physdev has no suitable ip"
return 1
}
}
local iface ndev ipaddrs
# 'DirectInterface' should specify single interface
# but end users may misinterpret this setting
DirectInterface=$(normalize_list "${DirectInterface}")
# 'Interface' should specify single interface
# but end users are often misinterpret this setting
Interface=$(normalize_list "${Interface}")
if [ -n "${Interface}" ] ; then
if [ -n "${DirectInterface}" ] ; then
logger -t "${NAME}" -p daemon.warn \
"Option 'DirectInterface' takes precedence over 'Interface'"
else
logger -t "${NAME}" -p daemon.info \
"Option 'Interface' binds to address(es) but not to interface"
logger -t "${NAME}" -p daemon.info \
"Consider using option 'DirectInterface' to bind directly to interface"
fi
fi
# handle 'DirectInterface'
iface=$(echo "${DirectInterface}" | awk '{print $1}')
case "${DirectInterface}" in
*\ *)
warn_multiple_interfaces DirectInterface "${DirectInterface}"
logger -t "${NAME}" -p daemon.warn \
"Using network interface '${iface}' for direct binding"
;;
esac
while [ -n "${iface}" ] ; do
# if network is available (even during boot) - proceed
if network_is_up "${iface}" ; then break ; fi
# skip during boot
[ -z "${BOOT}" ] || return 0
logger -t "${NAME}" -p daemon.crit \
"Network interface '${iface}' is not available!"
return 1
done
while [ -n "${iface}" ] ; do
# ${iface} is logical (higher level) interface name
# ${ndev} is 'real' interface name
# e.g.: if ${iface} is 'lan' (default LAN interface) then ${ndev} is 'br-lan'
network_get_device ndev "${iface}"
[ -z "${ndev}" ] || break
logger -t "${NAME}" -p daemon.crit \
"Missing network device for network interface '${iface}'!"
return 1
done
if [ -n "${iface}" ] ; then
logger -t "${NAME}" -p daemon.info \
"Using network interface '${iface}' (network device '${ndev}') for direct binding"
fi
# handle 'Interface'
while [ -z "${iface}" ] ; do
[ -n "${Interface}" ] || break
# skip during boot
[ -z "${BOOT}" ] || return 0
case "${Interface}" in
*\ *)
warn_multiple_interfaces Interface "${Interface}"
;;
esac
local c=0
# sysoptions.h
local DROPBEAR_MAX_PORTS=10
local a n if_ipaddrs
for n in ${Interface} ; do
[ -n "$n" ] || continue
if_ipaddrs=
network_get_ipaddrs_all if_ipaddrs "$n"
[ -n "${if_ipaddrs}" ] || {
logger -s -t "${NAME}" -p daemon.err \
"Network interface '$n' has no suitable IP address(es)!"
continue
}
[ $c -le ${DROPBEAR_MAX_PORTS} ] || {
logger -s -t "${NAME}" -p daemon.err \
"Network interface '$n' is NOT listened due to option limit exceed!"
continue
}
for a in ${if_ipaddrs} ; do
[ -n "$a" ] || continue
c=$((c+1))
if [ $c -le ${DROPBEAR_MAX_PORTS} ] ; then
ipaddrs="${ipaddrs} $a"
continue
fi
logger -t "${NAME}" -p daemon.err \
"Endpoint '$a:${Port}' on network interface '$n' is NOT listened due to option limit exceed!"
done
done
break
done
[ "${enable}" = "0" ] && return 1
PIDCOUNT="$(( ${PIDCOUNT} + 1))"
local pid_file="/var/run/${NAME}.${PIDCOUNT}.pid"
# Increase default receive window size to increase
# throughput on high latency links
if [ "${RecvWindowSize}" -eq "0" ]; then
RecvWindowSize="262144"
fi
procd_open_instance
procd_set_param command "$PROG" -F -P "$pid_file"
if [ -n "${iface}" ] ; then
# if ${iface} is non-empty then ${ndev} is non-empty too
procd_append_param command -l "${ndev}" -p "${Port}"
else
if [ -z "${ipaddrs}" ] ; then
procd_append_param command -p "${Port}"
else
local a
for a in ${ipaddrs} ; do
[ -n "$a" ] || continue
procd_append_param command -p "$a:${Port}"
done
fi
fi
[ "${PasswordAuth}" -eq 0 ] && procd_append_param command -s
[ "${GatewayPorts}" -eq 1 ] && procd_append_param command -a
[ -n "${ForceCommand}" ] && procd_append_param command -c "${ForceCommand}"
[ "${RootPasswordAuth}" -eq 0 ] && procd_append_param command -g
[ "${RootLogin}" -eq 0 ] && procd_append_param command -w
config_list_foreach "$1" 'keyfile' hk_config__keyfile
if [ -n "${rsakeyfile}" ]; then
logger -t ${NAME} -p daemon.warn \
"option 'rsakeyfile' is considered to be deprecated and" \
"will be removed in future releases, use 'keyfile' instead"
logger -s -t "${NAME}" -p daemon.crit \
"Option 'rsakeyfile' is considered to be DEPRECATED and will be REMOVED in future releases, use 'keyfile' list instead"
sed -i.before-upgrade -E -e 's/option(\s+)rsakeyfile/list keyfile/' \
"/etc/config/${NAME}"
logger -s -t "${NAME}" -p daemon.crit \
"Auto-transition 'option rsakeyfile' => 'list keyfile' in /etc/config/${NAME} is done, please verify your configuration"
hk_config 'rsakeyfile' "${rsakeyfile}"
fi
config_list_foreach "$1" "keyfile" hk_config__keyfile
[ -n "${BannerFile}" ] && procd_append_param command -b "${BannerFile}"
append_ports "${ipaddrs}" "${Port}"
[ "${IdleTimeout}" -ne 0 ] && procd_append_param command -I "${IdleTimeout}"
[ "${SSHKeepAlive}" -ne 0 ] && procd_append_param command -K "${SSHKeepAlive}"
[ "${MaxAuthTries}" -ne 0 ] && procd_append_param command -T "${MaxAuthTries}"
[ "${RecvWindowSize}" -gt 0 -a "${RecvWindowSize}" -le 1048576 ] && \
[ "${RecvWindowSize}" -gt 0 ] && {
# NB: OpenWrt increases receive window size to increase throughput on high latency links
# ref: validate_section_dropbear()
# default receive window size is 24576 (DEFAULT_RECV_WINDOW in default_options.h)
# sysoptions.h
local MAX_RECV_WINDOW=10485760
if [ "${RecvWindowSize}" -gt ${MAX_RECV_WINDOW} ] ; then
# separate logging is required because syslog misses dropbear's message
# Bad recv window '${RecvWindowSize}', using ${MAX_RECV_WINDOW}
# it's probably dropbear issue but we should handle this and notify user
logger -s -t "${NAME}" -p daemon.warn \
"Option 'RecvWindowSize' is too high (${RecvWindowSize}), limiting to ${MAX_RECV_WINDOW}"
RecvWindowSize=${MAX_RECV_WINDOW}
fi
procd_append_param command -W "${RecvWindowSize}"
}
[ "${mdns}" -ne 0 ] && procd_add_mdns "ssh" "tcp" "$Port" "daemon=dropbear"
procd_set_param respawn
procd_close_instance
@@ -189,10 +360,21 @@ dropbear_instance()
load_interfaces()
{
config_get interface "$1" Interface
local enable
config_get enable "$1" enable 1
[ "${enable}" = "1" ] || return 0
[ "${enable}" = "1" ] && interfaces=" ${interface} ${interfaces}"
local direct_iface iface
config_get direct_iface "$1" DirectInterface
direct_iface=$(normalize_list "${direct_iface}")
# 'DirectInterface' takes precedence over 'Interface'
if [ -n "${direct_iface}" ] ; then
iface=$(echo "${direct_iface}" | awk '{print $1}')
else
config_get iface "$1" Interface
iface=$(normalize_list "${iface}")
fi
interfaces="${interfaces} ${iface}"
}
boot()
@@ -204,6 +386,7 @@ boot()
start_service()
{
hk_generate_as_needed
file_verify /etc/dropbear/authorized_keys config
. /lib/functions.sh
. /lib/functions/network.sh
@@ -216,13 +399,14 @@ service_triggers()
{
local interfaces
procd_add_config_trigger "config.change" "dropbear" /etc/init.d/dropbear reload
procd_add_config_trigger "config.change" "${NAME}" /etc/init.d/dropbear reload
config_load "${NAME}"
config_foreach load_interfaces dropbear
config_foreach load_interfaces "${NAME}"
[ -n "${interfaces}" ] && {
for n in $interfaces ; do
local n
for n in $(printf '%s\n' ${interfaces} | sort -u) ; do
procd_add_interface_trigger "interface.*" $n /etc/init.d/dropbear reload
done
}

View File

@@ -0,0 +1,104 @@
From 36a03132634a17c667c0fac0a8e1519b3d1b71c6 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 28 Nov 2022 21:12:23 +0800
Subject: Add #if DROPBEAR_RSA guards
Fixes building with DROPBEAR_RSA disabled.
Closes #197
---
signkey.c | 8 +++++++-
signkey.h | 2 ++
sysoptions.h | 5 +----
3 files changed, 10 insertions(+), 5 deletions(-)
--- a/signkey.c
+++ b/signkey.c
@@ -120,6 +120,7 @@ enum signkey_type signkey_type_from_name
/* Special case for rsa-sha2-256. This could be generalised if more
signature names are added that aren't 1-1 with public key names */
const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) {
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (type == DROPBEAR_SIGNATURE_RSA_SHA256) {
if (namelen) {
@@ -136,11 +137,13 @@ const char* signature_name_from_type(enu
return SSH_SIGNKEY_RSA;
}
#endif
+#endif /* DROPBEAR_RSA */
return signkey_name_from_type((enum signkey_type)type, namelen);
}
/* Returns DROPBEAR_SIGNATURE_NONE if none match */
enum signature_type signature_type_from_name(const char* name, unsigned int namelen) {
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256)
&& memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) {
@@ -153,10 +156,11 @@ enum signature_type signature_type_from_
return DROPBEAR_SIGNATURE_RSA_SHA1;
}
#endif
+#endif /* DROPBEAR_RSA */
return (enum signature_type)signkey_type_from_name(name, namelen);
}
-/* Returns the signature type from a key type. Must not be called
+/* Returns the signature type from a key type. Must not be called
with RSA keytype */
enum signature_type signature_type_from_signkey(enum signkey_type keytype) {
#if DROPBEAR_RSA
@@ -167,6 +171,7 @@ enum signature_type signature_type_from_
}
enum signkey_type signkey_type_from_signature(enum signature_type sigtype) {
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA256
if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) {
return DROPBEAR_SIGNKEY_RSA;
@@ -177,6 +182,7 @@ enum signkey_type signkey_type_from_sign
return DROPBEAR_SIGNKEY_RSA;
}
#endif
+#endif /* DROPBEAR_RSA */
assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED);
return (enum signkey_type)sigtype;
}
--- a/signkey.h
+++ b/signkey.h
@@ -79,12 +79,14 @@ enum signature_type {
DROPBEAR_SIGNATURE_SK_ED25519 = DROPBEAR_SIGNKEY_SK_ED25519,
#endif
#endif
+#if DROPBEAR_RSA
#if DROPBEAR_RSA_SHA1
DROPBEAR_SIGNATURE_RSA_SHA1 = 100, /* ssh-rsa signature (sha1) */
#endif
#if DROPBEAR_RSA_SHA256
DROPBEAR_SIGNATURE_RSA_SHA256 = 101, /* rsa-sha2-256 signature. has a ssh-rsa key */
#endif
+#endif /* DROPBEAR_RSA */
DROPBEAR_SIGNATURE_NONE = DROPBEAR_SIGNKEY_NONE,
};
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -137,7 +137,7 @@
/* Debian doesn't define this in system headers */
#if !defined(LTM_DESC) && (DROPBEAR_ECC)
-#define LTM_DESC
+#define LTM_DESC
#endif
#define DROPBEAR_ECC_256 (DROPBEAR_ECC)
@@ -151,9 +151,6 @@
* signing operations slightly slower. */
#define DROPBEAR_RSA_BLINDING 1
-#ifndef DROPBEAR_RSA_SHA1
-#define DROPBEAR_RSA_SHA1 DROPBEAR_RSA
-#endif
#ifndef DROPBEAR_RSA_SHA256
#define DROPBEAR_RSA_SHA256 DROPBEAR_RSA
#endif

View File

@@ -1,134 +0,0 @@
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 8 Jun 2022 21:26:20 +0800
Subject: Fix MAX_UNAUTH_CLIENTS regression
Since re-exec change in 2022.82 Dropbear count
treat authenticated sessions towards the unauthenticated
session limit. This is fixed by passing the childpipe FD
through to the re-execed process.
---
runopts.h | 5 +++--
svr-main.c | 21 +++++++++++----------
svr-runopts.c | 15 ++++++++++++---
3 files changed, 26 insertions(+), 15 deletions(-)
--- a/runopts.h
+++ b/runopts.h
@@ -79,8 +79,9 @@ typedef struct svr_runopts {
char *addresses[DROPBEAR_MAX_PORTS];
int inetdmode;
- /* Hidden "-2" flag indicates it's re-executing itself */
- int reexec_child;
+ /* Hidden "-2 childpipe_fd" flag indicates it's re-executing itself,
+ stores the childpipe preauth file descriptor. Set to -1 otherwise. */
+ int reexec_childpipe;
/* Flags indicating whether to use ipv4 and ipv6 */
/* not used yet
--- a/svr-main.c
+++ b/svr-main.c
@@ -71,7 +71,7 @@ int main(int argc, char ** argv)
#endif
#if DROPBEAR_DO_REEXEC
- if (svr_opts.reexec_child) {
+ if (svr_opts.reexec_childpipe >= 0) {
#ifdef PR_SET_NAME
/* Fix the "Name:" in /proc/pid/status, otherwise it's
a FD number from fexecve.
@@ -102,7 +102,7 @@ static void main_inetd() {
seedrandom();
- if (!svr_opts.reexec_child) {
+ if (svr_opts.reexec_childpipe < 0) {
/* In case our inetd was lax in logging source addresses */
get_socket_address(0, NULL, NULL, &host, &port, 0);
dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port);
@@ -115,10 +115,8 @@ static void main_inetd() {
setsid();
}
- /* Start service program
- * -1 is a dummy childpipe, just something we can close() without
- * mattering. */
- svr_session(0, -1);
+ /* -1 for childpipe in the inetd case is discarded */
+ svr_session(0, svr_opts.reexec_childpipe);
/* notreached */
}
@@ -347,9 +345,10 @@ static void main_noinetd(int argc, char
if (execfd >= 0) {
#if DROPBEAR_DO_REEXEC
- /* Add "-2" to the args and re-execute ourself. */
- char **new_argv = m_malloc(sizeof(char*) * (argc+3));
- int pos0 = 0, new_argc = argc+1;
+ /* Add "-2 childpipe[1]" to the args and re-execute ourself. */
+ char **new_argv = m_malloc(sizeof(char*) * (argc+4));
+ char buf[10];
+ int pos0 = 0, new_argc = argc+2;
/* We need to specially handle "dropbearmulti dropbear". */
if (multipath) {
@@ -359,7 +358,9 @@ static void main_noinetd(int argc, char
}
memcpy(&new_argv[pos0], argv, sizeof(char*) * argc);
- new_argv[new_argc-1] = "-2";
+ new_argv[new_argc-2] = "-2";
+ snprintf(buf, sizeof(buf), "%d", childpipe[1]);
+ new_argv[new_argc-1] = buf;
new_argv[new_argc] = NULL;
if ((dup2(childsock, STDIN_FILENO) < 0)) {
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -138,6 +138,7 @@ void svr_getopts(int argc, char ** argv)
char* keepalive_arg = NULL;
char* idle_timeout_arg = NULL;
char* maxauthtries_arg = NULL;
+ char* reexec_fd_arg = NULL;
char* keyfile = NULL;
char c;
#if DROPBEAR_PLUGIN
@@ -175,6 +176,7 @@ void svr_getopts(int argc, char ** argv)
svr_opts.pubkey_plugin_options = NULL;
#endif
svr_opts.pass_on_env = 0;
+ svr_opts.reexec_childpipe = -1;
#ifndef DISABLE_ZLIB
opts.compress_mode = DROPBEAR_COMPRESS_DELAYED;
@@ -250,12 +252,12 @@ void svr_getopts(int argc, char ** argv)
#if DROPBEAR_DO_REEXEC && NON_INETD_MODE
/* For internal use by re-exec */
case '2':
- svr_opts.reexec_child = 1;
+ next = &reexec_fd_arg;
break;
#endif
case 'p':
- nextisport = 1;
- break;
+ nextisport = 1;
+ break;
case 'P':
next = &svr_opts.pidfile;
break;
@@ -426,6 +428,13 @@ void svr_getopts(int argc, char ** argv)
dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
}
+ if (reexec_fd_arg) {
+ if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
+ || svr_opts.reexec_childpipe < 0) {
+ dropbear_exit("Bad -2");
+ }
+ }
+
#if INETD_MODE
if (svr_opts.inetdmode && (
opts.usingsyslog == 0

View File

@@ -0,0 +1,198 @@
From ec2215726cffb976019d08ebf569edd2229e9dba Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Thu, 1 Dec 2022 11:34:43 +0800
Subject: Fix y2038 issues with time_t conversion
These changes were identified by building with and without
-D_TIME_BITS=64 -D_FILE_OFFSET_BITS=64
on 32-bit arm, logging warnings to files.
-Wconversion was added to CFLAGS in both builds.
Then a "diff -I Wconversion log1 log2" shows new warnings that appear
with the 64-bit time_t. There are a few false positives that have been
fixed for quietness.
struct logininfo and struct wtmp are still problematic, those will
need to be handled by libc.
---
common-session.c | 43 +++++++++++++++++++++++++++----------------
dbutil.c | 2 +-
loginrec.c | 2 ++
loginrec.h | 4 ++--
runopts.h | 4 ++--
svr-auth.c | 2 +-
6 files changed, 35 insertions(+), 22 deletions(-)
--- a/common-session.c
+++ b/common-session.c
@@ -519,15 +519,24 @@ static void send_msg_keepalive() {
ses.last_packet_time_idle = old_time_idle;
}
+/* Returns the difference in seconds, clamped to LONG_MAX */
+static long elapsed(time_t now, time_t prev) {
+ time_t del = now - prev;
+ if (del > LONG_MAX) {
+ return LONG_MAX;
+ }
+ return (long)del;
+}
+
/* Check all timeouts which are required. Currently these are the time for
* user authentication, and the automatic rekeying. */
static void checktimeouts() {
time_t now;
now = monotonic_now();
-
+
if (IS_DROPBEAR_SERVER && ses.connect_time != 0
- && now - ses.connect_time >= AUTH_TIMEOUT) {
+ && elapsed(now, ses.connect_time) >= AUTH_TIMEOUT) {
dropbear_close("Timeout before auth");
}
@@ -537,45 +546,47 @@ static void checktimeouts() {
}
if (!ses.kexstate.sentkexinit
- && (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT
+ && (elapsed(now, ses.kexstate.lastkextime) >= KEX_REKEY_TIMEOUT
|| ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
TRACE(("rekeying after timeout or max data reached"))
send_msg_kexinit();
}
-
+
if (opts.keepalive_secs > 0 && ses.authstate.authdone) {
/* Avoid sending keepalives prior to auth - those are
not valid pre-auth packet types */
/* Send keepalives if we've been idle */
- if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
+ if (elapsed(now, ses.last_packet_time_any_sent) >= opts.keepalive_secs) {
send_msg_keepalive();
}
/* Also send an explicit keepalive message to trigger a response
if the remote end hasn't sent us anything */
- if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
- && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
+ if (elapsed(now, ses.last_packet_time_keepalive_recv) >= opts.keepalive_secs
+ && elapsed(now, ses.last_packet_time_keepalive_sent) >= opts.keepalive_secs) {
send_msg_keepalive();
}
- if (now - ses.last_packet_time_keepalive_recv
+ if (elapsed(now, ses.last_packet_time_keepalive_recv)
>= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
dropbear_exit("Keepalive timeout");
}
}
- if (opts.idle_timeout_secs > 0
- && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
+ if (opts.idle_timeout_secs > 0
+ && elapsed(now, ses.last_packet_time_idle) >= opts.idle_timeout_secs) {
dropbear_close("Idle timeout");
}
}
-static void update_timeout(long limit, long now, long last_event, long * timeout) {
- TRACE2(("update_timeout limit %ld, now %ld, last %ld, timeout %ld",
- limit, now, last_event, *timeout))
+static void update_timeout(long limit, time_t now, time_t last_event, long * timeout) {
+ TRACE2(("update_timeout limit %ld, now %llu, last %llu, timeout %ld",
+ limit,
+ (unsigned long long)now,
+ (unsigned long long)last_event, *timeout))
if (last_event > 0 && limit > 0) {
- *timeout = MIN(*timeout, last_event+limit-now);
+ *timeout = MIN(*timeout, elapsed(now, last_event) + limit);
TRACE2(("new timeout %ld", *timeout))
}
}
@@ -584,7 +595,7 @@ static long select_timeout() {
/* determine the minimum timeout that might be required, so
as to avoid waking when unneccessary */
long timeout = KEX_REKEY_TIMEOUT;
- long now = monotonic_now();
+ time_t now = monotonic_now();
if (!ses.kexstate.sentkexinit) {
update_timeout(KEX_REKEY_TIMEOUT, now, ses.kexstate.lastkextime, &timeout);
@@ -596,7 +607,7 @@ static long select_timeout() {
}
if (ses.authstate.authdone) {
- update_timeout(opts.keepalive_secs, now,
+ update_timeout(opts.keepalive_secs, now,
MAX(ses.last_packet_time_keepalive_recv, ses.last_packet_time_keepalive_sent),
&timeout);
}
--- a/dbutil.c
+++ b/dbutil.c
@@ -724,7 +724,7 @@ void gettime_wrapper(struct timespec *no
/* Fallback for everything else - this will sometimes go backwards */
gettimeofday(&tv, NULL);
now->tv_sec = tv.tv_sec;
- now->tv_nsec = 1000*tv.tv_usec;
+ now->tv_nsec = 1000*(long)tv.tv_usec;
}
/* second-resolution monotonic timestamp */
--- a/loginrec.c
+++ b/loginrec.c
@@ -459,6 +459,7 @@ line_abbrevname(char *dst, const char *s
void
set_utmp_time(struct logininfo *li, struct utmp *ut)
{
+ /* struct utmp in glibc isn't y2038 safe yet */
# ifdef HAVE_STRUCT_UTMP_UT_TV
ut->ut_tv.tv_sec = li->tv_sec;
ut->ut_tv.tv_usec = li->tv_usec;
@@ -1272,6 +1273,7 @@ lastlog_construct(struct logininfo *li,
(void)line_stripname(last->ll_line, li->line, sizeof(last->ll_line));
strlcpy(last->ll_host, li->hostname,
MIN_SIZEOF(last->ll_host, li->hostname));
+ /* struct lastlog in glibc isn't y2038 safe yet */
last->ll_time = li->tv_sec;
}
--- a/loginrec.h
+++ b/loginrec.h
@@ -139,8 +139,8 @@ struct logininfo {
/* struct timeval (sys/time.h) isn't always available, if it isn't we'll
* use time_t's value as tv_sec and set tv_usec to 0
*/
- unsigned int tv_sec;
- unsigned int tv_usec;
+ time_t tv_sec;
+ suseconds_t tv_usec;
union login_netinfo hostaddr; /* caller's host address(es) */
}; /* struct logininfo */
--- a/runopts.h
+++ b/runopts.h
@@ -39,8 +39,8 @@ typedef struct runopts {
int listen_fwd_all;
#endif
unsigned int recv_window;
- time_t keepalive_secs; /* Time between sending keepalives. 0 is off */
- time_t idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
+ long keepalive_secs; /* Time between sending keepalives. 0 is off */
+ long idle_timeout_secs; /* Exit if no traffic is sent/received in this time */
int usingsyslog;
#ifndef DISABLE_ZLIB
--- a/svr-auth.c
+++ b/svr-auth.c
@@ -389,7 +389,7 @@ void send_msg_userauth_failure(int parti
Beware of integer overflow if increasing these values */
const unsigned int mindelay = 250000000;
const unsigned int vardelay = 100000000;
- unsigned int rand_delay;
+ suseconds_t rand_delay;
struct timespec delay;
gettime_wrapper(&delay);

View File

@@ -0,0 +1,25 @@
From c043efb47c3173072fa636ca0da0d19875d4511f Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 6 Dec 2022 22:34:11 +0800
Subject: Fix so DROPBEAR_DSS is only forced for fuzzing
Regression from 787391ea3b5af2acf5e3c83372510f0c79477ad7,
was missing fuzzing conditional
---
sysoptions.h | 2 ++
1 file changed, 2 insertions(+)
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -380,9 +380,11 @@
#endif
/* Fuzzing expects all key types to be enabled */
+#if DROPBEAR_FUZZ
#if defined(DROPBEAR_DSS)
#undef DROPBEAR_DSS
#endif
#define DROPBEAR_DSS 1
+#endif
/* no include guard for this file */

View File

@@ -0,0 +1,24 @@
From 860721558837441ab45019858e710a2625ffa46e Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 7 Dec 2022 13:04:10 +0800
Subject: Allow users's own gid in pty permission check
This allows non-root Dropbear to work even without devpts gid=5 mount
option on Linux.
---
sshpty.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
--- a/sshpty.c
+++ b/sshpty.c
@@ -380,7 +380,9 @@ pty_setowner(struct passwd *pw, const ch
tty_name, strerror(errno));
}
- if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
+ /* Allow either "tty" gid or user's own gid. On Linux with openpty()
+ * this varies depending on the devpts mount options */
+ if (st.st_uid != pw->pw_uid || !(st.st_gid == gid || st.st_gid == pw->pw_gid)) {
if (chown(tty_name, pw->pw_uid, gid) < 0) {
if (errno == EROFS &&
(st.st_uid == pw->pw_uid || st.st_uid == 0)) {

View File

@@ -0,0 +1,123 @@
From 01415ef8269e594a647f67ea0729ca8b590679de Mon Sep 17 00:00:00 2001
From: Francois Perrad <francois.perrad@gadz.org>
Date: Thu, 22 Dec 2022 10:19:54 +0100
Subject: const parameter mp_int
---
bignum.c | 2 +-
bignum.h | 2 +-
buffer.c | 2 +-
buffer.h | 2 +-
dbrandom.c | 2 +-
dbrandom.h | 2 +-
dbutil.c | 2 +-
dbutil.h | 2 +-
genrsa.c | 4 ++--
9 files changed, 10 insertions(+), 10 deletions(-)
--- a/bignum.c
+++ b/bignum.c
@@ -93,7 +93,7 @@ void bytes_to_mp(mp_int *mp, const unsig
/* hash the ssh representation of the mp_int mp */
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
- hash_state *hs, mp_int *mp) {
+ hash_state *hs, const mp_int *mp) {
buffer * buf;
buf = buf_new(512 + 20); /* max buffer is a 4096 bit key,
--- a/bignum.h
+++ b/bignum.h
@@ -33,6 +33,6 @@ void m_mp_alloc_init_multi(mp_int **mp,
void m_mp_free_multi(mp_int **mp, ...) ATTRIB_SENTINEL;
void bytes_to_mp(mp_int *mp, const unsigned char* bytes, unsigned int len);
void hash_process_mp(const struct ltc_hash_descriptor *hash_desc,
- hash_state *hs, mp_int *mp);
+ hash_state *hs, const mp_int *mp);
#endif /* DROPBEAR_BIGNUM_H_ */
--- a/buffer.c
+++ b/buffer.c
@@ -299,7 +299,7 @@ void buf_putbytes(buffer *buf, const uns
/* for our purposes we only need positive (or 0) numbers, so will
* fail if we get negative numbers */
-void buf_putmpint(buffer* buf, mp_int * mp) {
+void buf_putmpint(buffer* buf, const mp_int * mp) {
size_t written;
unsigned int len, pad = 0;
TRACE2(("enter buf_putmpint"))
--- a/buffer.h
+++ b/buffer.h
@@ -65,7 +65,7 @@ void buf_putint(buffer* buf, unsigned in
void buf_putstring(buffer* buf, const char* str, unsigned int len);
void buf_putbufstring(buffer *buf, const buffer* buf_str);
void buf_putbytes(buffer *buf, const unsigned char *bytes, unsigned int len);
-void buf_putmpint(buffer* buf, mp_int * mp);
+void buf_putmpint(buffer* buf, const mp_int * mp);
int buf_getmpint(buffer* buf, mp_int* mp);
unsigned int buf_getint(buffer* buf);
--- a/dbrandom.c
+++ b/dbrandom.c
@@ -347,7 +347,7 @@ void genrandom(unsigned char* buf, unsig
* rand must be an initialised *mp_int for the result.
* the result rand satisfies: 0 < rand < max
* */
-void gen_random_mpint(mp_int *max, mp_int *rand) {
+void gen_random_mpint(const mp_int *max, mp_int *rand) {
unsigned char *randbuf = NULL;
unsigned int len = 0;
--- a/dbrandom.h
+++ b/dbrandom.h
@@ -30,6 +30,6 @@
void seedrandom(void);
void genrandom(unsigned char* buf, unsigned int len);
void addrandom(const unsigned char * buf, unsigned int len);
-void gen_random_mpint(mp_int *max, mp_int *rand);
+void gen_random_mpint(const mp_int *max, mp_int *rand);
#endif /* DROPBEAR_RANDOM_H_ */
--- a/dbutil.c
+++ b/dbutil.c
@@ -442,7 +442,7 @@ void printhex(const char * label, const
}
}
-void printmpint(const char *label, mp_int *mp) {
+void printmpint(const char *label, const mp_int *mp) {
buffer *buf = buf_new(1000);
buf_putmpint(buf, mp);
fprintf(stderr, "%d bits ", mp_count_bits(mp));
--- a/dbutil.h
+++ b/dbutil.h
@@ -53,7 +53,7 @@ void dropbear_trace3(const char* format,
void dropbear_trace4(const char* format, ...) ATTRIB_PRINTF(1,2);
void dropbear_trace5(const char* format, ...) ATTRIB_PRINTF(1,2);
void printhex(const char * label, const unsigned char * buf, int len);
-void printmpint(const char *label, mp_int *mp);
+void printmpint(const char *label, const mp_int *mp);
void debug_start_net(void);
extern int debug_trace;
#endif
--- a/genrsa.c
+++ b/genrsa.c
@@ -34,7 +34,7 @@
#if DROPBEAR_RSA
static void getrsaprime(mp_int* prime, mp_int *primeminus,
- mp_int* rsa_e, unsigned int size_bytes);
+ const mp_int* rsa_e, unsigned int size_bytes);
/* mostly taken from libtomcrypt's rsa key generation routine */
dropbear_rsa_key * gen_rsa_priv_key(unsigned int size) {
@@ -89,7 +89,7 @@ dropbear_rsa_key * gen_rsa_priv_key(unsi
/* return a prime suitable for p or q */
static void getrsaprime(mp_int* prime, mp_int *primeminus,
- mp_int* rsa_e, unsigned int size_bytes) {
+ const mp_int* rsa_e, unsigned int size_bytes) {
unsigned char *buf;
int trials;

View File

@@ -0,0 +1,21 @@
From 39d955c49f31fc155e885447ee2be61c869d8c2d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 3 Jan 2023 22:05:14 +0800
Subject: Add missing break in switch
Has no effect on execution, the fallthrough does nothing
Closes #208
---
dropbearkey.c | 1 +
1 file changed, 1 insertion(+)
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -139,6 +139,7 @@ static void check_signkey_bits(enum sign
dropbear_exit("DSS keys have a fixed size of 1024 bits\n");
exit(EXIT_FAILURE);
}
+ break;
#endif
default:
(void)0; /* quiet, compiler. ecdsa handles checks itself */

View File

@@ -0,0 +1,29 @@
From 7a53c7f0f4b3eb23e002819553cb45558642c01d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Wed, 4 Jan 2023 20:32:23 +0800
Subject: Fix building only client or server
Regressed when -Wundef was added
Fixes #210
---
sysoptions.h | 8 ++++++++
1 file changed, 8 insertions(+)
--- a/sysoptions.h
+++ b/sysoptions.h
@@ -10,6 +10,14 @@
#define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION
#define PROGNAME "dropbear"
+#ifndef DROPBEAR_CLIENT
+#define DROPBEAR_CLIENT 0
+#endif
+
+#ifndef DROPBEAR_SERVER
+#define DROPBEAR_SERVER 0
+#endif
+
/* Spec recommends after one hour or 1 gigabyte of data. One hour
* is a bit too verbose, so we try 8 hours */
#ifndef KEX_REKEY_TIMEOUT

View File

@@ -0,0 +1,94 @@
From a113381c12a2da3c9b7bd594f47a1b2657bdfdf2 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 12 Feb 2023 22:44:32 +0800
Subject: Disable rsa signatures when no rsa hostkey
Otherwise Dropbear will offer RSA as a hostkey signature option, but the
session will exit with an assertion or NULL pointer dereference once
that algorithm is negotiated.
This likely regressed in 2020.79 when signature vs key type enums were
split, for rsa-sha256.
Fixes #219 on github
---
svr-runopts.c | 21 +++++++++++----------
1 file changed, 11 insertions(+), 10 deletions(-)
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -505,11 +505,11 @@ static void addportandaddress(const char
svr_opts.portcount++;
}
-static void disablekey(int type) {
+static void disablekey(enum signature_type type) {
int i;
TRACE(("Disabling key type %d", type))
for (i = 0; sigalgs[i].name != NULL; i++) {
- if (sigalgs[i].val == type) {
+ if ((int)sigalgs[i].val == (int)type) {
sigalgs[i].usable = 0;
break;
}
@@ -624,7 +624,8 @@ void load_all_hostkeys() {
#if DROPBEAR_RSA
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->rsakey) {
- disablekey(DROPBEAR_SIGNKEY_RSA);
+ disablekey(DROPBEAR_SIGNATURE_RSA_SHA256);
+ disablekey(DROPBEAR_SIGNATURE_RSA_SHA1);
} else {
any_keys = 1;
}
@@ -632,7 +633,7 @@ void load_all_hostkeys() {
#if DROPBEAR_DSS
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->dsskey) {
- disablekey(DROPBEAR_SIGNKEY_DSS);
+ disablekey(DROPBEAR_SIGNATURE_DSS);
} else {
any_keys = 1;
}
@@ -666,35 +667,35 @@ void load_all_hostkeys() {
#if DROPBEAR_ECC_256
if (!svr_opts.hostkey->ecckey256
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 256 )) {
- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP256);
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP256);
}
#endif
#if DROPBEAR_ECC_384
if (!svr_opts.hostkey->ecckey384
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 384 )) {
- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP384);
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP384);
}
#endif
#if DROPBEAR_ECC_521
if (!svr_opts.hostkey->ecckey521
&& (!svr_opts.delay_hostkey || loaded_any_ecdsa || ECDSA_DEFAULT_SIZE != 521 )) {
- disablekey(DROPBEAR_SIGNKEY_ECDSA_NISTP521);
+ disablekey(DROPBEAR_SIGNATURE_ECDSA_NISTP521);
}
#endif
#endif /* DROPBEAR_ECDSA */
#if DROPBEAR_ED25519
if (!svr_opts.delay_hostkey && !svr_opts.hostkey->ed25519key) {
- disablekey(DROPBEAR_SIGNKEY_ED25519);
+ disablekey(DROPBEAR_SIGNATURE_ED25519);
} else {
any_keys = 1;
}
#endif
#if DROPBEAR_SK_ECDSA
- disablekey(DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256);
+ disablekey(DROPBEAR_SIGNATURE_SK_ECDSA_NISTP256);
#endif
#if DROPBEAR_SK_ED25519
- disablekey(DROPBEAR_SIGNKEY_SK_ED25519);
+ disablekey(DROPBEAR_SIGNATURE_SK_ED25519);
#endif
if (!any_keys) {

View File

@@ -0,0 +1,27 @@
From 3292b8c6f1e5fcc405fa0f7a20e90a60f74037b2 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 12 Feb 2023 23:00:00 +0800
Subject: Use write() rather than fprintf() in segv handler
fprintf isn't guaranteed safe (though hasn't had any problems reported).
---
svr-main.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
--- a/svr-main.c
+++ b/svr-main.c
@@ -420,8 +420,12 @@ static void sigchld_handler(int UNUSED(u
/* catch any segvs */
static void sigsegv_handler(int UNUSED(unused)) {
- fprintf(stderr, "Aiee, segfault! You should probably report "
- "this as a bug to the developer\n");
+ int i;
+ const char *msg = "Aiee, segfault! You should probably report "
+ "this as a bug to the developer\n";
+ i = write(STDERR_FILENO, msg, strlen(msg));
+ /* ignore short writes */
+ (void)i;
_exit(EXIT_FAILURE);
}

View File

@@ -0,0 +1,39 @@
From 5040f21cb4ee6ade966e60c6d5a3c270d03de1f1 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 1 May 2023 22:05:43 +0800
Subject: Remove SO_LINGER
It could cause channels to take up to 5 seconds to close(), which would block
the entire process. On busy TCP forwarding sessions this would result in
channels seeming stuck and new connections not being accepted.
We don't need to monitor for flushing failures since we can't report errors, so
SO_LINGER wasn't useful.
Thanks to GektorUA for reporting and testing
Fixes #230
---
netio.c | 4 ----
1 file changed, 4 deletions(-)
--- a/netio.c
+++ b/netio.c
@@ -472,7 +472,6 @@ int dropbear_listen(const char* address,
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
unsigned int nsock;
- struct linger linger;
int val;
int sock;
uint16_t *allocated_lport_p = NULL;
@@ -551,9 +550,6 @@ int dropbear_listen(const char* address,
val = 1;
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
- linger.l_onoff = 1;
- linger.l_linger = 5;
- setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {

View File

@@ -0,0 +1,147 @@
From fb64db9eac3fdc6434f2dc7b5ea407fe5df76e6f Mon Sep 17 00:00:00 2001
From: Diederik De Coninck <diederik.deconinck_ext@softathome.com>
Date: Tue, 11 Apr 2023 15:38:04 +0200
Subject: Add option to bind to interface
---
netio.c | 13 +++++++++++--
netio.h | 2 +-
runopts.h | 1 +
svr-main.c | 2 +-
svr-runopts.c | 9 +++++++++
svr-tcpfwd.c | 1 +
tcp-accept.c | 2 +-
tcpfwd.h | 1 +
8 files changed, 26 insertions(+), 5 deletions(-)
--- a/netio.c
+++ b/netio.c
@@ -467,7 +467,7 @@ int get_sock_port(int sock) {
* failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/
int dropbear_listen(const char* address, const char* port,
- int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
+ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface) {
struct addrinfo hints, *res = NULL, *res0 = NULL;
int err;
@@ -497,7 +497,11 @@ int dropbear_listen(const char* address,
TRACE(("dropbear_listen: local loopback"))
} else {
if (address[0] == '\0') {
- TRACE(("dropbear_listen: all interfaces"))
+ if (interface) {
+ TRACE(("dropbear_listen: %s", interface))
+ } else {
+ TRACE(("dropbear_listen: all interfaces"))
+ }
address = NULL;
}
hints.ai_flags = AI_PASSIVE;
@@ -551,6 +555,11 @@ int dropbear_listen(const char* address,
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+ if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
+ dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
+ TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
+ }
+
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
int on = 1;
--- a/netio.h
+++ b/netio.h
@@ -19,7 +19,7 @@ void get_socket_address(int fd, char **l
void getaddrstring(struct sockaddr_storage* addr,
char **ret_host, char **ret_port, int host_lookup);
int dropbear_listen(const char* address, const char* port,
- int *socks, unsigned int sockcount, char **errstring, int *maxfd);
+ int *socks, unsigned int sockcount, char **errstring, int *maxfd, const char* interface);
struct dropbear_progress_connection;
--- a/runopts.h
+++ b/runopts.h
@@ -128,6 +128,7 @@ typedef struct svr_runopts {
char * pidfile;
char * forced_command;
+ char* interface;
#if DROPBEAR_PLUGIN
/* malloced */
--- a/svr-main.c
+++ b/svr-main.c
@@ -488,7 +488,7 @@ static size_t listensockets(int *socks,
nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &socks[sockpos],
sockcount - sockpos,
- &errstring, maxfd);
+ &errstring, maxfd, svr_opts.interface);
if (nsock < 0) {
dropbear_log(LOG_WARNING, "Failed listening on '%s': %s",
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -98,6 +98,8 @@ static void printhelp(const char * progn
" (default port is %s if none specified)\n"
"-P PidFile Create pid file PidFile\n"
" (default %s)\n"
+ "-l <interface>\n"
+ " interface to bind on\n"
#if INETD_MODE
"-i Start for inetd\n"
#endif
@@ -265,6 +267,9 @@ void svr_getopts(int argc, char ** argv)
case 'P':
next = &svr_opts.pidfile;
break;
+ case 'l':
+ next = &svr_opts.interface;
+ break;
#if DO_MOTD
/* motd is displayed by default, -m turns it off */
case 'm':
@@ -438,6 +443,10 @@ void svr_getopts(int argc, char ** argv)
dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command);
}
+ if (svr_opts.interface) {
+ dropbear_log(LOG_INFO, "Binding to interface '%s'", svr_opts.interface);
+ }
+
if (reexec_fd_arg) {
if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE
|| svr_opts.reexec_childpipe < 0) {
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -205,6 +205,7 @@ static int svr_remotetcpreq(int *allocat
tcpinfo->listenport = port;
tcpinfo->chantype = &svr_chan_tcpremote;
tcpinfo->tcp_type = forwarded;
+ tcpinfo->interface = svr_opts.interface;
tcpinfo->request_listenaddr = request_addr;
if (!opts.listen_fwd_all || (strcmp(request_addr, "localhost") == 0) ) {
--- a/tcp-accept.c
+++ b/tcp-accept.c
@@ -117,7 +117,7 @@ int listen_tcpfwd(struct TCPListener* tc
snprintf(portstring, sizeof(portstring), "%u", tcpinfo->listenport);
nsocks = dropbear_listen(tcpinfo->listenaddr, portstring, socks,
- DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
+ DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd, tcpinfo->interface);
if (nsocks < 0) {
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
m_free(errstring);
--- a/tcpfwd.h
+++ b/tcpfwd.h
@@ -42,6 +42,7 @@ struct TCPListener {
unsigned int listenport;
/* The address that the remote host asked to listen on */
char *request_listenaddr;
+ char* interface;
const struct ChanType *chantype;
enum {direct, forwarded} tcp_type;

View File

@@ -0,0 +1,50 @@
From 031d09b47912b2401f4934667c0b6f857ede61ee Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Tue, 18 Jul 2023 23:20:16 +0800
Subject: Add ifdef guards for SO_BINDTODEVICE
---
netio.c | 2 ++
svr-runopts.c | 4 ++++
2 files changed, 6 insertions(+)
--- a/netio.c
+++ b/netio.c
@@ -555,10 +555,12 @@ int dropbear_listen(const char* address,
/* set to reuse, quick timeout */
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+#ifdef SO_BINDTODEVICE
if(interface && setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, interface, strlen(interface)) < 0) {
dropbear_log(LOG_WARNING, "Couldn't set SO_BINDTODEVICE");
TRACE(("Failed setsockopt with errno failure, %d %s", errno, strerror(errno)))
}
+#endif
#if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY)
if (res->ai_family == AF_INET6) {
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -98,8 +98,10 @@ static void printhelp(const char * progn
" (default port is %s if none specified)\n"
"-P PidFile Create pid file PidFile\n"
" (default %s)\n"
+#ifdef SO_BINDTODEVICE
"-l <interface>\n"
" interface to bind on\n"
+#endif
#if INETD_MODE
"-i Start for inetd\n"
#endif
@@ -267,9 +269,11 @@ void svr_getopts(int argc, char ** argv)
case 'P':
next = &svr_opts.pidfile;
break;
+#ifdef SO_BINDTODEVICE
case 'l':
next = &svr_opts.interface;
break;
+#endif
#if DO_MOTD
/* motd is displayed by default, -m turns it off */
case 'm':

View File

@@ -0,0 +1,74 @@
From 62a06cd95f58060a59359f8769c3f35cd680d4fd Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sun, 23 Jul 2023 21:01:48 +0800
Subject: Make banner reading failure non-fatal
---
svr-runopts.c | 45 ++++++++++++++++++++++++++++-----------------
1 file changed, 28 insertions(+), 17 deletions(-)
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -38,6 +38,7 @@ static void printhelp(const char * progn
static void addportandaddress(const char* spec);
static void loadhostkey(const char *keyfile, int fatal_duplicate);
static void addhostkey(const char *keyfile);
+static void load_banner();
static void printhelp(const char * progname) {
@@ -382,23 +383,7 @@ void svr_getopts(int argc, char ** argv)
}
if (svr_opts.bannerfile) {
- struct stat buf;
- if (stat(svr_opts.bannerfile, &buf) != 0) {
- dropbear_exit("Error opening banner file '%s'",
- svr_opts.bannerfile);
- }
-
- if (buf.st_size > MAX_BANNER_SIZE) {
- dropbear_exit("Banner file too large, max is %d bytes",
- MAX_BANNER_SIZE);
- }
-
- svr_opts.banner = buf_new(buf.st_size);
- if (buf_readfile(svr_opts.banner, svr_opts.bannerfile)!=DROPBEAR_SUCCESS) {
- dropbear_exit("Error reading banner file '%s'",
- svr_opts.bannerfile);
- }
- buf_setpos(svr_opts.banner, 0);
+ load_banner();
}
#ifdef HAVE_GETGROUPLIST
@@ -715,3 +700,29 @@ void load_all_hostkeys() {
dropbear_exit("No hostkeys available. 'dropbear -R' may be useful or run dropbearkey.");
}
}
+
+static void load_banner() {
+ struct stat buf;
+ if (stat(svr_opts.bannerfile, &buf) != 0) {
+ dropbear_log(LOG_WARNING, "Error opening banner file '%s'",
+ svr_opts.bannerfile);
+ return;
+ }
+
+ if (buf.st_size > MAX_BANNER_SIZE) {
+ dropbear_log(LOG_WARNING, "Banner file too large, max is %d bytes",
+ MAX_BANNER_SIZE);
+ return;
+ }
+
+ svr_opts.banner = buf_new(buf.st_size);
+ if (buf_readfile(svr_opts.banner, svr_opts.bannerfile) != DROPBEAR_SUCCESS) {
+ dropbear_log(LOG_WARNING, "Error reading banner file '%s'",
+ svr_opts.bannerfile);
+ buf_free(svr_opts.banner);
+ svr_opts.banner = NULL;
+ return;
+ }
+ buf_setpos(svr_opts.banner, 0);
+
+}

View File

@@ -0,0 +1,60 @@
From ec26975d442163b66d1646a48e022bc8c2f1607a Mon Sep 17 00:00:00 2001
From: Sergey Ponomarev <stokito@gmail.com>
Date: Sun, 27 Aug 2023 00:07:05 +0300
Subject: dropbearkey.c Ignore unsupported command line options
To generate non interactively a key with OpenSSH the simplest command is:
ssh-keygen -t ed25519 -q -N '' -f ~/.ssh/id_ed25519
The command has two options -q quiet and -N passphrase which aren't supported by the dropbearkey.
To improve interoperability add explicit ignoring of the -q and -N with empty passphrase.
Also ignore the -v even if the DEBUG_TRACE is not set.
Signed-off-by: Sergey Ponomarev <stokito@gmail.com>
---
dropbearkey.c | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)
--- a/dropbearkey.c
+++ b/dropbearkey.c
@@ -159,6 +159,7 @@ int main(int argc, char ** argv) {
enum signkey_type keytype = DROPBEAR_SIGNKEY_NONE;
char * typetext = NULL;
char * sizetext = NULL;
+ char * passphrase = NULL;
unsigned int bits = 0, genbits;
int printpub = 0;
@@ -194,11 +195,16 @@ int main(int argc, char ** argv) {
printhelp(argv[0]);
exit(EXIT_SUCCESS);
break;
-#if DEBUG_TRACE
case 'v':
+#if DEBUG_TRACE
debug_trace = DROPBEAR_VERBOSE_LEVEL;
- break;
#endif
+ break;
+ case 'q':
+ break; /* quiet is default */
+ case 'N':
+ next = &passphrase;
+ break;
default:
fprintf(stderr, "Unknown argument %s\n", argv[i]);
printhelp(argv[0]);
@@ -266,6 +272,11 @@ int main(int argc, char ** argv) {
check_signkey_bits(keytype, bits);;
}
+ if (passphrase && *passphrase != '\0') {
+ fprintf(stderr, "Only empty passphrase is supported\n");
+ exit(EXIT_FAILURE);
+ }
+
genbits = signkey_generate_get_bits(keytype, bits);
fprintf(stderr, "Generating %u bit %s key, this may take a while...\n", genbits, typetext);
if (signkey_generate(keytype, bits, filename, 0) == DROPBEAR_FAILURE)

View File

@@ -0,0 +1,121 @@
From 3b576d95dcf791d7b945e75f639da8f89c1685a2 Mon Sep 17 00:00:00 2001
From: czurnieden <czurnieden@gmx.de>
Date: Tue, 9 May 2023 17:17:12 +0200
Subject: Fix possible integer overflow
---
libtommath/bn_mp_2expt.c | 4 ++++
libtommath/bn_mp_grow.c | 4 ++++
libtommath/bn_mp_init_size.c | 5 +++++
libtommath/bn_mp_mul_2d.c | 4 ++++
libtommath/bn_s_mp_mul_digs.c | 4 ++++
libtommath/bn_s_mp_mul_digs_fast.c | 4 ++++
libtommath/bn_s_mp_mul_high_digs.c | 4 ++++
libtommath/bn_s_mp_mul_high_digs_fast.c | 4 ++++
8 files changed, 33 insertions(+)
--- a/libtommath/bn_mp_2expt.c
+++ b/libtommath/bn_mp_2expt.c
@@ -12,6 +12,10 @@ mp_err mp_2expt(mp_int *a, int b)
{
mp_err err;
+ if (b < 0) {
+ return MP_VAL;
+ }
+
/* zero a as per default */
mp_zero(a);
--- a/libtommath/bn_mp_grow.c
+++ b/libtommath/bn_mp_grow.c
@@ -9,6 +9,10 @@ mp_err mp_grow(mp_int *a, int size)
int i;
mp_digit *tmp;
+ if (size < 0) {
+ return MP_VAL;
+ }
+
/* if the alloc size is smaller alloc more ram */
if (a->alloc < size) {
/* reallocate the array a->dp
--- a/libtommath/bn_mp_init_size.c
+++ b/libtommath/bn_mp_init_size.c
@@ -6,6 +6,11 @@
/* init an mp_init for a given size */
mp_err mp_init_size(mp_int *a, int size)
{
+
+ if (size < 0) {
+ return MP_VAL;
+ }
+
size = MP_MAX(MP_MIN_PREC, size);
/* alloc mem */
--- a/libtommath/bn_mp_mul_2d.c
+++ b/libtommath/bn_mp_mul_2d.c
@@ -9,6 +9,10 @@ mp_err mp_mul_2d(const mp_int *a, int b,
mp_digit d;
mp_err err;
+ if (b < 0) {
+ return MP_VAL;
+ }
+
/* copy */
if (a != c) {
if ((err = mp_copy(a, c)) != MP_OKAY) {
--- a/libtommath/bn_s_mp_mul_digs.c
+++ b/libtommath/bn_s_mp_mul_digs.c
@@ -16,6 +16,10 @@ mp_err s_mp_mul_digs(const mp_int *a, co
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* can we use the fast multiplier? */
if ((digs < MP_WARRAY) &&
(MP_MIN(a->used, b->used) < MP_MAXFAST)) {
--- a/libtommath/bn_s_mp_mul_digs_fast.c
+++ b/libtommath/bn_s_mp_mul_digs_fast.c
@@ -26,6 +26,10 @@ mp_err s_mp_mul_digs_fast(const mp_int *
mp_digit W[MP_WARRAY];
mp_word _W;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* grow the destination as required */
if (c->alloc < digs) {
if ((err = mp_grow(c, digs)) != MP_OKAY) {
--- a/libtommath/bn_s_mp_mul_high_digs.c
+++ b/libtommath/bn_s_mp_mul_high_digs.c
@@ -15,6 +15,10 @@ mp_err s_mp_mul_high_digs(const mp_int *
mp_word r;
mp_digit tmpx, *tmpt, *tmpy;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* can we use the fast multiplier? */
if (MP_HAS(S_MP_MUL_HIGH_DIGS_FAST)
&& ((a->used + b->used + 1) < MP_WARRAY)
--- a/libtommath/bn_s_mp_mul_high_digs_fast.c
+++ b/libtommath/bn_s_mp_mul_high_digs_fast.c
@@ -19,6 +19,10 @@ mp_err s_mp_mul_high_digs_fast(const mp_
mp_digit W[MP_WARRAY];
mp_word _W;
+ if (digs < 0) {
+ return MP_VAL;
+ }
+
/* grow the destination as required */
pa = a->used + b->used;
if (c->alloc < pa) {

View File

@@ -0,0 +1,35 @@
From 3cf8344769eda55e26eee53c1898b2c66544f188 Mon Sep 17 00:00:00 2001
From: Justin Chen <justin.chen@broadcom.com>
Date: Fri, 8 Sep 2023 11:35:18 -0700
Subject: src: svr-tcpfwd: Fix noremotetcp behavior
If noremotetcp is set, we should still reply with
send_msg_request_failed. This matches the behavior
of !DROPBEAR_SVR_REMOTETCPFWD.
We were seeing keepalive packets being ignored when
the "-k" option was used.
---
svr-tcpfwd.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -79,14 +79,14 @@ void recv_msg_global_request_remotetcp()
TRACE(("enter recv_msg_global_request_remotetcp"))
+ reqname = buf_getstring(ses.payload, &namelen);
+ wantreply = buf_getbool(ses.payload);
+
if (svr_opts.noremotetcp || !svr_pubkey_allows_tcpfwd()) {
TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"))
goto out;
}
- reqname = buf_getstring(ses.payload, &namelen);
- wantreply = buf_getbool(ses.payload);
-
if (namelen > MAX_NAME_LEN) {
TRACE(("name len is wrong: %d", namelen))
goto out;

View File

@@ -0,0 +1,32 @@
From e28ba1b9975eab48799aa3ed77d3cd91627d7b27 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Sat, 9 Dec 2023 23:10:41 +0800
Subject: Don't try to shutdown() a pty
shutdown() of a pty doesn't work (ENOTSOCK), so we should close
it instead.
This will ensure that PTY controlling terminals are closed when a
session exits, including when multiple sessions run over a single SSH
connection. In the normal case of a single session, the PTY controlling
terminal would be closed when the Dropbear server process exits anyway.
This possibly fixes #264 on github
It is possible that there could be subtle changes to PTY flushing
behaviour, though nothing caught by tests at present.
---
svr-chansession.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -910,7 +910,7 @@ static int ptycommand(struct Channel *ch
channel->readfd = chansess->master;
/* don't need to set stderr here */
ses.maxfd = MAX(ses.maxfd, chansess->master);
- channel->bidir_fd = 1;
+ channel->bidir_fd = 0;
setnonblocking(chansess->master);

View File

@@ -0,0 +1,33 @@
From 806586b585806cbe32013bcd3af3847278972060 Mon Sep 17 00:00:00 2001
From: Sergey Ponomarev <stokito@gmail.com>
Date: Sun, 10 Dec 2023 10:31:56 +0200
Subject: dropbearkey: add alias to ssh-keygen
The dropbearkey is partially compatible with ssh-keygen and can be used as an alias.
Closes: #263
---
dbmulti.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
--- a/dbmulti.c
+++ b/dbmulti.c
@@ -41,7 +41,8 @@ static int runprog(const char *multipath
}
#endif
#ifdef DBMULTI_dropbearkey
- if (strcmp(progname, "dropbearkey") == 0) {
+ if (strcmp(progname, "dropbearkey") == 0
+ || strcmp(progname, "ssh-keygen") == 0) {
return dropbearkey_main(argc, argv);
}
#endif
@@ -88,7 +89,7 @@ int main(int argc, char ** argv) {
"'dbclient' or 'ssh' - the Dropbear client\n"
#endif
#ifdef DBMULTI_dropbearkey
- "'dropbearkey' - the key generator\n"
+ "'dropbearkey' or 'ssh-keygen' - the key generator\n"
#endif
#ifdef DBMULTI_dropbearconvert
"'dropbearconvert' - the key converter\n"

View File

@@ -0,0 +1,34 @@
From 383cc8c97a9420aad9cf93d88e77ec636b183a9d Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 11 Dec 2023 23:18:09 +0800
Subject: Allow inetd with non-syslog
An inetd-alike should be able to distinguish stdout and stderr, so
it's a valid configuration.
Fixes #218 on github
---
svr-runopts.c | 12 ------------
1 file changed, 12 deletions(-)
--- a/svr-runopts.c
+++ b/svr-runopts.c
@@ -443,18 +443,6 @@ void svr_getopts(int argc, char ** argv)
}
}
-#if INETD_MODE
- if (svr_opts.inetdmode && (
- opts.usingsyslog == 0
-#if DEBUG_TRACE
- || debug_trace
-#endif
- )) {
- /* log output goes to stderr which would get sent over the inetd network socket */
- dropbear_exit("Dropbear inetd mode is incompatible with debug -v or non-syslog");
- }
-#endif
-
if (svr_opts.multiauthmethod && svr_opts.noauthpass) {
dropbear_exit("-t and -s are incompatible");
}

View File

@@ -0,0 +1,33 @@
From 9ac650401ffc2fb05c9328d26e76a5e7ae39152a Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 11 Dec 2023 23:31:22 +0800
Subject: Fix test for multiuser kernels
getuid() succeeds even on non-multiuser kernels. Instead
getgroups() is a valid test.
Fixes #214 on github
---
common-session.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
--- a/common-session.c
+++ b/common-session.c
@@ -71,10 +71,13 @@ void common_session_init(int sock_in, in
#if !DROPBEAR_SVR_MULTIUSER
/* A sanity check to prevent an accidental configuration option
leaving multiuser systems exposed */
- errno = 0;
- getuid();
- if (errno != ENOSYS) {
- dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
+ {
+ int ret;
+ errno = 0;
+ ret = getgroups(0, NULL);
+ if (!(ret == -1 && errno == ENOSYS)) {
+ dropbear_exit("Non-multiuser Dropbear requires a non-multiuser kernel");
+ }
}
#endif

View File

@@ -0,0 +1,216 @@
From 6e43be5c7b99dbee49dc72b6f989f29fdd7e9356 Mon Sep 17 00:00:00 2001
From: Matt Johnston <matt@ucc.asn.au>
Date: Mon, 20 Nov 2023 14:02:47 +0800
Subject: Implement Strict KEX mode
As specified by OpenSSH with kex-strict-c-v00@openssh.com and
kex-strict-s-v00@openssh.com.
---
cli-session.c | 11 +++++++++++
common-algo.c | 6 ++++++
common-kex.c | 26 +++++++++++++++++++++++++-
kex.h | 3 +++
process-packet.c | 34 +++++++++++++++++++---------------
ssh.h | 4 ++++
svr-session.c | 3 +++
7 files changed, 71 insertions(+), 16 deletions(-)
--- a/cli-session.c
+++ b/cli-session.c
@@ -46,6 +46,7 @@ static void cli_finished(void) ATTRIB_NO
static void recv_msg_service_accept(void);
static void cli_session_cleanup(void);
static void recv_msg_global_request_cli(void);
+static void cli_algos_initialise(void);
struct clientsession cli_ses; /* GLOBAL */
@@ -117,6 +118,7 @@ void cli_session(int sock_in, int sock_o
}
chaninitialise(cli_chantypes);
+ cli_algos_initialise();
/* Set up cli_ses vars */
cli_session_init(proxy_cmd_pid);
@@ -487,3 +489,12 @@ void cli_dropbear_log(int priority, cons
fflush(stderr);
}
+static void cli_algos_initialise(void) {
+ algo_type *algo;
+ for (algo = sshkex; algo->name; algo++) {
+ if (strcmp(algo->name, SSH_STRICT_KEX_S) == 0) {
+ algo->usable = 0;
+ }
+ }
+}
+
--- a/common-algo.c
+++ b/common-algo.c
@@ -308,6 +308,12 @@ algo_type sshkex[] = {
{SSH_EXT_INFO_C, 0, NULL, 1, NULL},
#endif
#endif
+#if DROPBEAR_CLIENT
+ {SSH_STRICT_KEX_C, 0, NULL, 1, NULL},
+#endif
+#if DROPBEAR_SERVER
+ {SSH_STRICT_KEX_S, 0, NULL, 1, NULL},
+#endif
{NULL, 0, NULL, 0, NULL}
};
--- a/common-kex.c
+++ b/common-kex.c
@@ -183,6 +183,10 @@ void send_msg_newkeys() {
gen_new_keys();
switch_keys();
+ if (ses.kexstate.strict_kex) {
+ ses.transseq = 0;
+ }
+
TRACE(("leave send_msg_newkeys"))
}
@@ -193,7 +197,11 @@ void recv_msg_newkeys() {
ses.kexstate.recvnewkeys = 1;
switch_keys();
-
+
+ if (ses.kexstate.strict_kex) {
+ ses.recvseq = 0;
+ }
+
TRACE(("leave recv_msg_newkeys"))
}
@@ -550,6 +558,10 @@ void recv_msg_kexinit() {
ses.kexstate.recvkexinit = 1;
+ if (ses.kexstate.strict_kex && !ses.kexstate.donefirstkex && ses.recvseq != 1) {
+ dropbear_exit("First packet wasn't kexinit");
+ }
+
TRACE(("leave recv_msg_kexinit"))
}
@@ -859,6 +871,18 @@ static void read_kex_algos() {
}
#endif
+ if (!ses.kexstate.donefirstkex) {
+ const char* strict_name;
+ if (IS_DROPBEAR_CLIENT) {
+ strict_name = SSH_STRICT_KEX_S;
+ } else {
+ strict_name = SSH_STRICT_KEX_C;
+ }
+ if (buf_has_algo(ses.payload, strict_name) == DROPBEAR_SUCCESS) {
+ ses.kexstate.strict_kex = 1;
+ }
+ }
+
algo = buf_match_algo(ses.payload, sshkex, kexguess2, &goodguess);
allgood &= goodguess;
if (algo == NULL || algo->data == NULL) {
--- a/kex.h
+++ b/kex.h
@@ -83,6 +83,9 @@ struct KEXState {
unsigned our_first_follows_matches : 1;
+ /* Boolean indicating that strict kex mode is in use */
+ unsigned int strict_kex;
+
time_t lastkextime; /* time of the last kex */
unsigned int datatrans; /* data transmitted since last kex */
unsigned int datarecv; /* data received since last kex */
--- a/process-packet.c
+++ b/process-packet.c
@@ -44,6 +44,7 @@ void process_packet() {
unsigned char type;
unsigned int i;
+ unsigned int first_strict_kex = ses.kexstate.strict_kex && !ses.kexstate.donefirstkex;
time_t now;
TRACE2(("enter process_packet"))
@@ -54,22 +55,24 @@ void process_packet() {
now = monotonic_now();
ses.last_packet_time_keepalive_recv = now;
- /* These packets we can receive at any time */
- switch(type) {
- case SSH_MSG_IGNORE:
- goto out;
- case SSH_MSG_DEBUG:
- goto out;
-
- case SSH_MSG_UNIMPLEMENTED:
- /* debugging XXX */
- TRACE(("SSH_MSG_UNIMPLEMENTED"))
- goto out;
-
- case SSH_MSG_DISCONNECT:
- /* TODO cleanup? */
- dropbear_close("Disconnect received");
+ if (type == SSH_MSG_DISCONNECT) {
+ /* Allowed at any time */
+ dropbear_close("Disconnect received");
+ }
+
+ /* These packets may be received at any time,
+ except during first kex with strict kex */
+ if (!first_strict_kex) {
+ switch(type) {
+ case SSH_MSG_IGNORE:
+ goto out;
+ case SSH_MSG_DEBUG:
+ goto out;
+ case SSH_MSG_UNIMPLEMENTED:
+ TRACE(("SSH_MSG_UNIMPLEMENTED"))
+ goto out;
+ }
}
/* Ignore these packet types so that keepalives don't interfere with
@@ -98,7 +101,8 @@ void process_packet() {
if (type >= 1 && type <= 49
&& type != SSH_MSG_SERVICE_REQUEST
&& type != SSH_MSG_SERVICE_ACCEPT
- && type != SSH_MSG_KEXINIT)
+ && type != SSH_MSG_KEXINIT
+ && !first_strict_kex)
{
TRACE(("unknown allowed packet during kexinit"))
recv_unimplemented();
--- a/ssh.h
+++ b/ssh.h
@@ -100,6 +100,10 @@
#define SSH_EXT_INFO_C "ext-info-c"
#define SSH_SERVER_SIG_ALGS "server-sig-algs"
+/* OpenSSH strict KEX feature */
+#define SSH_STRICT_KEX_S "kex-strict-s-v00@openssh.com"
+#define SSH_STRICT_KEX_C "kex-strict-c-v00@openssh.com"
+
/* service types */
#define SSH_SERVICE_USERAUTH "ssh-userauth"
#define SSH_SERVICE_USERAUTH_LEN 12
--- a/svr-session.c
+++ b/svr-session.c
@@ -370,6 +370,9 @@ static void svr_algos_initialise(void) {
algo->usable = 0;
}
#endif
+ if (strcmp(algo->name, SSH_STRICT_KEX_C) == 0) {
+ algo->usable = 0;
+ }
}
}

View File

@@ -1,6 +1,6 @@
--- a/svr-authpubkey.c
+++ b/svr-authpubkey.c
@@ -77,6 +77,13 @@ static void send_msg_userauth_pk_ok(cons
@@ -78,6 +78,13 @@ static void send_msg_userauth_pk_ok(cons
const unsigned char* keyblob, unsigned int keybloblen);
static int checkfileperm(char * filename);
@@ -14,7 +14,7 @@
/* process a pubkey auth request, sending success or failure message as
* appropriate */
void svr_auth_pubkey(int valid_user) {
@@ -439,14 +446,21 @@ static int checkpubkey(const char* keyal
@@ -462,14 +469,21 @@ static int checkpubkey(const char* keyal
if (checkpubkeyperms() == DROPBEAR_FAILURE) {
TRACE(("bad authorized_keys permissions, or file doesn't exist"))
} else {
@@ -44,7 +44,7 @@
authfile = fopen(filename, "r");
if (!authfile) {
@@ -520,27 +534,41 @@ static int checkpubkeyperms() {
@@ -543,27 +557,41 @@ static int checkpubkeyperms() {
goto out;
}

View File

@@ -1,8 +1,8 @@
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -325,6 +325,10 @@ void cli_getopts(int argc, char ** argv)
case 'b':
next = &bind_arg;
@@ -329,6 +329,10 @@ void cli_getopts(int argc, char ** argv)
case 'z':
opts.disable_ip_tos = 1;
break;
+ case 'x':
+ /* compatibility with openssh cli

View File

@@ -1,6 +1,6 @@
--- a/configure.ac
+++ b/configure.ac
@@ -74,53 +74,6 @@ AC_ARG_ENABLE(harden,
@@ -87,54 +87,6 @@ AC_ARG_ENABLE(harden,
if test "$hardenbuild" -eq 1; then
AC_MSG_NOTICE(Checking for available hardened build flags:)
@@ -11,15 +11,15 @@
-
- OLDLDFLAGS="$LDFLAGS"
- TESTFLAGS="-Wl,-pie"
- LDFLAGS="$LDFLAGS $TESTFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- LDFLAGS="$TESTFLAGS $LDFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [
- LDFLAGS="$OLDLDFLAGS"
- TESTFLAGS="-pie"
- LDFLAGS="$LDFLAGS $TESTFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- LDFLAGS="$TESTFLAGS $LDFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
- )
- ]
@@ -27,30 +27,31 @@
- # readonly elf relocation sections (relro)
- OLDLDFLAGS="$LDFLAGS"
- TESTFLAGS="-Wl,-z,now -Wl,-z,relro"
- LDFLAGS="$LDFLAGS $TESTFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- LDFLAGS="$TESTFLAGS $LDFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); LDFLAGS="$OLDLDFLAGS" ]
- )
- fi # non-static
- # stack protector. -strong is good but only in gcc 4.9 or later
- OLDCFLAGS="$CFLAGS"
- TESTFLAGS="-fstack-protector-strong"
- CFLAGS="$CFLAGS $TESTFLAGS"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- CFLAGS="$TESTFLAGS $CFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [
- CFLAGS="$OLDCFLAGS"
- TESTFLAGS="-fstack-protector --param=ssp-buffer-size=4"
- CFLAGS="$CFLAGS $TESTFLAGS"
- AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- CFLAGS="$TESTFLAGS $CFLAGS"
- AC_LINK_IFELSE([AC_LANG_PROGRAM([])],
- [AC_MSG_NOTICE([Setting $TESTFLAGS])],
- [AC_MSG_NOTICE([Not setting $TESTFLAGS]); CFLAGS="$OLDCFLAGS" ]
- )
- ]
- )
- # FORTIFY_SOURCE
- DB_TRYADDCFLAGS([-D_FORTIFY_SOURCE=2])
-
# Spectre v2 mitigations
DB_TRYADDCFLAGS([-mfunction-return=thunk])
DB_TRYADDCFLAGS([-mindirect-branch=thunk])

View File

@@ -1,48 +1,29 @@
--- a/libtomcrypt/makefile_include.mk
+++ b/libtomcrypt/makefile_include.mk
@@ -94,6 +94,13 @@ endif
--- a/configure.ac
+++ b/configure.ac
@@ -45,11 +45,8 @@ fi
# LTM_CFLAGS is given to ./configure by the user,
# DROPBEAR_LTM_CFLAGS is substituted in the LTM Makefile.in
DROPBEAR_LTM_CFLAGS="$LTM_CFLAGS"
-if test -z "$DROPBEAR_LTM_CFLAGS"; then
- DROPBEAR_LTM_CFLAGS="-O3 -funroll-loops -fomit-frame-pointer"
-fi
-AC_MSG_NOTICE(Setting LTM_CFLAGS to $DROPBEAR_LTM_CFLAGS)
-AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Default -O3 -funroll-loops -fomit-frame-pointer)
+AC_MSG_NOTICE(Setting LTM_CFLAGS to '$DROPBEAR_LTM_CFLAGS')
+AC_ARG_VAR(LTM_CFLAGS, CFLAGS for bundled libtommath. Defaults to empty string)
AC_SUBST(DROPBEAR_LTM_CFLAGS)
LTC_CFLAGS += -Wno-type-limits
AC_MSG_NOTICE([Checking if compiler '$CC' supports -Wno-pointer-sign])
--- a/libtomcrypt/src/headers/tomcrypt_dropbear.h
+++ b/libtomcrypt/src/headers/tomcrypt_dropbear.h
@@ -7,8 +7,10 @@
+ifdef OPENWRT_BUILD
+ ifeq (-Os,$(filter -Os,$(CFLAGS)))
+ LTC_CFLAGS += -DLTC_SMALL_CODE
+ endif
+else
+ ### ! OPENWRT_BUILD
+
ifdef LTC_DEBUG
$(info Debug build)
# compile for DEBUGGING (required for ccmalloc checking!!!)
@@ -121,6 +128,9 @@ endif
endif # COMPILE_SMALL
endif # COMPILE_DEBUG
/* Use small code where possible */
#if DROPBEAR_SMALL_CODE
+#ifndef LTC_SMALL_CODE
#define LTC_SMALL_CODE
#endif
+#endif
+ ### ! OPENWRT_BUILD
+endif
+
ifneq ($(findstring clang,$(CC)),)
LTC_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header -Wno-missing-field-initializers
--- a/libtommath/makefile_include.mk
+++ b/libtommath/makefile_include.mk
@@ -70,6 +70,9 @@ else
LTM_CFLAGS += -Wsystem-headers
endif
+ifndef OPENWRT_BUILD
+ ### ! OPENWRT_BUILD
+
ifdef COMPILE_DEBUG
#debug
LTM_CFLAGS += -g3
@@ -90,6 +93,9 @@ endif
endif # COMPILE_SIZE
+ ### ! OPENWRT_BUILD
+endif
+
ifneq ($(findstring clang,$(CC)),)
LTM_CFLAGS += -Wno-typedef-redefinition -Wno-tautological-compare -Wno-builtin-requires-header
endif
/* Fewer entries needed */
#define TAB_SIZE 5

View File

@@ -21,7 +21,7 @@ Signed-off-by: Petr Štetiar <ynezz@true.cz>
--- a/signkey.c
+++ b/signkey.c
@@ -646,8 +646,12 @@ int buf_verify(buffer * buf, sign_key *k
@@ -652,10 +652,18 @@ int buf_verify(buffer * buf, sign_key *k
sigtype = signature_type_from_name(type_name, type_name_len);
m_free(type_name);
@@ -29,10 +29,16 @@ Signed-off-by: Petr Štetiar <ynezz@true.cz>
- dropbear_exit("Non-matching signing type");
+ if (sigtype == DROPBEAR_SIGNATURE_NONE) {
+ dropbear_exit("No signature type");
+ }
+
+ if ((expect_sigtype != DROPBEAR_SIGNATURE_RSA_SHA256) && (expect_sigtype != sigtype)) {
+ dropbear_exit("Non-matching signing type");
}
+#if DROPBEAR_RSA
+#if DROPBEAR_RSA_SHA256
+ if ((expect_sigtype != DROPBEAR_SIGNATURE_RSA_SHA256) && (expect_sigtype != sigtype)) {
+ dropbear_exit("Non-matching signing type");
+ }
+#endif
+#endif
+
keytype = signkey_type_from_signature(sigtype);
#if DROPBEAR_DSS
if (keytype == DROPBEAR_SIGNKEY_DSS) {

View File

@@ -26,7 +26,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
return;
val = bcm_phy_read_shadow(phydev, BCM54XX_SHD_SCR3);
@@ -905,7 +906,7 @@ static struct phy_driver broadcom_driver
@@ -906,7 +907,7 @@ static struct phy_driver broadcom_driver
.link_change_notify = bcm54xx_link_change_notify,
}, {
.phy_id = PHY_ID_BCM54210E,
@@ -35,7 +35,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
.name = "Broadcom BCM54210E",
/* PHY_GBIT_FEATURES */
.get_sset_count = bcm_phy_get_sset_count,
@@ -919,6 +920,13 @@ static struct phy_driver broadcom_driver
@@ -920,6 +921,13 @@ static struct phy_driver broadcom_driver
.suspend = bcm54xx_suspend,
.resume = bcm54xx_resume,
}, {
@@ -49,7 +49,7 @@ Signed-off-by: Jonathan Bell <jonathan@raspberrypi.org>
.phy_id = PHY_ID_BCM5461,
.phy_id_mask = 0xfffffff0,
.name = "Broadcom BCM5461",
@@ -1155,7 +1163,8 @@ module_phy_driver(broadcom_drivers);
@@ -1156,7 +1164,8 @@ module_phy_driver(broadcom_drivers);
static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
{ PHY_ID_BCM5411, 0xfffffff0 },
{ PHY_ID_BCM5421, 0xfffffff0 },

View File

@@ -16,7 +16,7 @@ Signed-off-by: Jonathan Lemon <jonathan.lemon@gmail.com>
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -932,8 +932,14 @@ static struct phy_driver broadcom_driver
@@ -933,8 +933,14 @@ static struct phy_driver broadcom_driver
.phy_id_mask = 0xffffffff,
.name = "Broadcom BCM54213PE",
/* PHY_GBIT_FEATURES */

View File

@@ -0,0 +1,211 @@
From 385ef48f468696d6d172eb367656a3466fa0408d Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:05 +0100
Subject: [PATCH 02/10] net: phy: add support for scanning PHY in PHY packages
nodes
Add support for scanning PHY in PHY package nodes. PHY packages nodes
are just container for actual PHY on the MDIO bus.
Their PHY address defined in the PHY package node are absolute and
reflect the address on the MDIO bus.
mdio_bus.c and of_mdio.c is updated to now support and parse also
PHY package subnode by checking if the node name match
"ethernet-phy-package".
As PHY package reg is mandatory and each PHY in the PHY package must
have a reg, every invalid PHY Package node is ignored and will be
skipped by the autoscan fallback.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/mdio/of_mdio.c | 79 +++++++++++++++++++++++++++-----------
drivers/net/phy/mdio_bus.c | 44 +++++++++++++++++----
2 files changed, 92 insertions(+), 31 deletions(-)
--- a/drivers/net/mdio/of_mdio.c
+++ b/drivers/net/mdio/of_mdio.c
@@ -138,6 +138,53 @@ bool of_mdiobus_child_is_phy(struct devi
}
EXPORT_SYMBOL(of_mdiobus_child_is_phy);
+static int __of_mdiobus_parse_phys(struct mii_bus *mdio, struct device_node *np,
+ bool *scanphys)
+{
+ struct device_node *child;
+ int addr, rc = 0;
+
+ /* Loop over the child nodes and register a phy_device for each phy */
+ for_each_available_child_of_node(np, child) {
+ if (of_node_name_eq(child, "ethernet-phy-package")) {
+ /* Ignore invalid ethernet-phy-package node */
+ if (!of_find_property(child, "reg", NULL))
+ continue;
+
+ rc = __of_mdiobus_parse_phys(mdio, child, NULL);
+ if (rc && rc != -ENODEV)
+ goto exit;
+
+ continue;
+ }
+
+ addr = of_mdio_parse_addr(&mdio->dev, child);
+ if (addr < 0) {
+ /* Skip scanning for invalid ethernet-phy-package node */
+ if (scanphys)
+ *scanphys = true;
+ continue;
+ }
+
+ if (of_mdiobus_child_is_phy(child))
+ rc = of_mdiobus_register_phy(mdio, child, addr);
+ else
+ rc = of_mdiobus_register_device(mdio, child, addr);
+
+ if (rc == -ENODEV)
+ dev_err(&mdio->dev,
+ "MDIO device at address %d is missing.\n",
+ addr);
+ else if (rc)
+ goto exit;
+ }
+
+ return 0;
+exit:
+ of_node_put(child);
+ return rc;
+}
+
/**
* __of_mdiobus_register - Register mii_bus and create PHYs from the device tree
* @mdio: pointer to mii_bus structure
@@ -179,33 +226,18 @@ int __of_mdiobus_register(struct mii_bus
return rc;
/* Loop over the child nodes and register a phy_device for each phy */
- for_each_available_child_of_node(np, child) {
- addr = of_mdio_parse_addr(&mdio->dev, child);
- if (addr < 0) {
- scanphys = true;
- continue;
- }
-
- if (of_mdiobus_child_is_phy(child))
- rc = of_mdiobus_register_phy(mdio, child, addr);
- else
- rc = of_mdiobus_register_device(mdio, child, addr);
-
- if (rc == -ENODEV)
- dev_err(&mdio->dev,
- "MDIO device at address %d is missing.\n",
- addr);
- else if (rc)
- goto unregister;
- }
+ rc = __of_mdiobus_parse_phys(mdio, np, &scanphys);
+ if (rc)
+ goto unregister;
if (!scanphys)
return 0;
/* auto scan for PHYs with empty reg property */
for_each_available_child_of_node(np, child) {
- /* Skip PHYs with reg property set */
- if (of_find_property(child, "reg", NULL))
+ /* Skip PHYs with reg property set or ethernet-phy-package node */
+ if (of_find_property(child, "reg", NULL) ||
+ of_node_name_eq(child, "ethernet-phy-package"))
continue;
for (addr = 0; addr < PHY_MAX_ADDR; addr++) {
@@ -226,15 +258,16 @@ int __of_mdiobus_register(struct mii_bus
if (!rc)
break;
if (rc != -ENODEV)
- goto unregister;
+ goto put_unregister;
}
}
}
return 0;
-unregister:
+put_unregister:
of_node_put(child);
+unregister:
mdiobus_unregister(mdio);
return rc;
}
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -448,19 +448,34 @@ EXPORT_SYMBOL(of_mdio_find_bus);
* found, set the of_node pointer for the mdio device. This allows
* auto-probed phy devices to be supplied with information passed in
* via DT.
+ * If a PHY package is found, PHY is searched also there.
*/
-static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
- struct mdio_device *mdiodev)
+static int of_mdiobus_find_phy(struct device *dev, struct mdio_device *mdiodev,
+ struct device_node *np)
{
- struct device *dev = &mdiodev->dev;
struct device_node *child;
- if (dev->of_node || !bus->dev.of_node)
- return;
-
- for_each_available_child_of_node(bus->dev.of_node, child) {
+ for_each_available_child_of_node(np, child) {
int addr;
+ if (of_node_name_eq(child, "ethernet-phy-package")) {
+ /* Validate PHY package reg presence */
+ if (!of_find_property(child, "reg", NULL)) {
+ of_node_put(child);
+ return -EINVAL;
+ }
+
+ if (!of_mdiobus_find_phy(dev, mdiodev, child)) {
+ /* The refcount for the PHY package will be
+ * incremented later when PHY join the Package.
+ */
+ of_node_put(child);
+ return 0;
+ }
+
+ continue;
+ }
+
addr = of_mdio_parse_addr(dev, child);
if (addr < 0)
continue;
@@ -470,9 +485,22 @@ static void of_mdiobus_link_mdiodev(stru
/* The refcount on "child" is passed to the mdio
* device. Do _not_ use of_node_put(child) here.
*/
- return;
+ return 0;
}
}
+
+ return -ENODEV;
+}
+
+static void of_mdiobus_link_mdiodev(struct mii_bus *bus,
+ struct mdio_device *mdiodev)
+{
+ struct device *dev = &mdiodev->dev;
+
+ if (dev->of_node || !bus->dev.of_node)
+ return;
+
+ of_mdiobus_find_phy(dev, mdiodev, bus->dev.of_node);
}
#else /* !IS_ENABLED(CONFIG_OF_MDIO) */
static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio,

View File

@@ -0,0 +1,185 @@
From 471e8fd3afcef5a9f9089f0bd21965ad9ba35c91 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:06 +0100
Subject: [PATCH 03/10] net: phy: add devm/of_phy_package_join helper
Add devm/of_phy_package_join helper to join PHYs in a PHY package. These
are variant of the manual phy_package_join with the difference that
these will use DT nodes to derive the base_addr instead of manually
passing an hardcoded value.
An additional value is added in phy_package_shared, "np" to reference
the PHY package node pointer in specific PHY driver probe_once and
config_init_once functions to make use of additional specific properties
defined in the PHY package node in DT.
The np value is filled only with of_phy_package_join if a valid PHY
package node is found. A valid PHY package node must have the node name
set to "ethernet-phy-package".
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/phy_device.c | 96 ++++++++++++++++++++++++++++++++++++
include/linux/phy.h | 6 +++
2 files changed, 102 insertions(+)
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1650,6 +1650,7 @@ int phy_package_join(struct phy_device *
shared->priv_size = priv_size;
}
shared->base_addr = base_addr;
+ shared->np = NULL;
refcount_set(&shared->refcnt, 1);
bus->shared[base_addr] = shared;
} else {
@@ -1673,6 +1674,63 @@ err_unlock:
EXPORT_SYMBOL_GPL(phy_package_join);
/**
+ * of_phy_package_join - join a common PHY group in PHY package
+ * @phydev: target phy_device struct
+ * @priv_size: if non-zero allocate this amount of bytes for private data
+ *
+ * This is a variant of phy_package_join for PHY package defined in DT.
+ *
+ * The parent node of the @phydev is checked as a valid PHY package node
+ * structure (by matching the node name "ethernet-phy-package") and the
+ * base_addr for the PHY package is passed to phy_package_join.
+ *
+ * With this configuration the shared struct will also have the np value
+ * filled to use additional DT defined properties in PHY specific
+ * probe_once and config_init_once PHY package OPs.
+ *
+ * Returns < 0 on error, 0 on success. Esp. calling phy_package_join()
+ * with the same cookie but a different priv_size is an error. Or a parent
+ * node is not detected or is not valid or doesn't match the expected node
+ * name for PHY package.
+ */
+int of_phy_package_join(struct phy_device *phydev, size_t priv_size)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct device_node *package_node;
+ u32 base_addr;
+ int ret;
+
+ if (!node)
+ return -EINVAL;
+
+ package_node = of_get_parent(node);
+ if (!package_node)
+ return -EINVAL;
+
+ if (!of_node_name_eq(package_node, "ethernet-phy-package")) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ if (of_property_read_u32(package_node, "reg", &base_addr)) {
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ ret = phy_package_join(phydev, base_addr, priv_size);
+ if (ret)
+ goto exit;
+
+ phydev->shared->np = package_node;
+
+ return 0;
+exit:
+ of_node_put(package_node);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(of_phy_package_join);
+
+/**
* phy_package_leave - leave a common PHY group
* @phydev: target phy_device struct
*
@@ -1688,6 +1746,10 @@ void phy_package_leave(struct phy_device
if (!shared)
return;
+ /* Decrease the node refcount on leave if present */
+ if (shared->np)
+ of_node_put(shared->np);
+
if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
bus->shared[shared->base_addr] = NULL;
mutex_unlock(&bus->shared_lock);
@@ -1741,6 +1803,40 @@ int devm_phy_package_join(struct device
EXPORT_SYMBOL_GPL(devm_phy_package_join);
/**
+ * devm_of_phy_package_join - resource managed of_phy_package_join()
+ * @dev: device that is registering this PHY package
+ * @phydev: target phy_device struct
+ * @priv_size: if non-zero allocate this amount of bytes for private data
+ *
+ * Managed of_phy_package_join(). Shared storage fetched by this function,
+ * phy_package_leave() is automatically called on driver detach. See
+ * of_phy_package_join() for more information.
+ */
+int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
+ size_t priv_size)
+{
+ struct phy_device **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_phy_package_leave, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = of_phy_package_join(phydev, priv_size);
+
+ if (!ret) {
+ *ptr = phydev;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_package_join);
+
+/**
* phy_detach - detach a PHY device from its network device
* @phydev: target phy_device struct
*
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -321,6 +321,7 @@ struct mdio_bus_stats {
* struct phy_package_shared - Shared information in PHY packages
* @base_addr: Base PHY address of PHY package used to combine PHYs
* in one package and for offset calculation of phy_package_read/write
+ * @np: Pointer to the Device Node if PHY package defined in DT
* @refcnt: Number of PHYs connected to this shared data
* @flags: Initialization of PHY package
* @priv_size: Size of the shared private data @priv
@@ -332,6 +333,8 @@ struct mdio_bus_stats {
*/
struct phy_package_shared {
u8 base_addr;
+ /* With PHY package defined in DT this points to the PHY package node */
+ struct device_node *np;
refcount_t refcnt;
unsigned long flags;
size_t priv_size;
@@ -1765,9 +1768,12 @@ int phy_ethtool_set_link_ksettings(struc
const struct ethtool_link_ksettings *cmd);
int phy_ethtool_nway_reset(struct net_device *ndev);
int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size);
+int of_phy_package_join(struct phy_device *phydev, size_t priv_size);
void phy_package_leave(struct phy_device *phydev);
int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
int base_addr, size_t priv_size);
+int devm_of_phy_package_join(struct device *dev, struct phy_device *phydev,
+ size_t priv_size);
#if IS_ENABLED(CONFIG_PHYLIB)
int __init mdio_bus_init(void);

View File

@@ -0,0 +1,583 @@
From 737eb75a815f9c08dcbb6631db57f4f4b0540a5b Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:07 +0100
Subject: [PATCH 04/10] net: phy: qcom: move more function to shared library
Move more function to shared library in preparation for introduction of
new PHY Family qca807x that will make use of both functions from at803x
and qca808x as it's a transition PHY with some implementation of at803x
and some from the new qca808x.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/qcom/at803x.c | 35 -----
drivers/net/phy/qcom/qca808x.c | 205 ----------------------------
drivers/net/phy/qcom/qcom-phy-lib.c | 193 ++++++++++++++++++++++++++
drivers/net/phy/qcom/qcom.h | 51 +++++++
4 files changed, 244 insertions(+), 240 deletions(-)
--- a/drivers/net/phy/qcom/at803x.c
+++ b/drivers/net/phy/qcom/at803x.c
@@ -504,41 +504,6 @@ static void at803x_link_change_notify(st
}
}
-static int at803x_read_status(struct phy_device *phydev)
-{
- struct at803x_ss_mask ss_mask = { 0 };
- int err, old_link = phydev->link;
-
- /* Update the link, but return if there was an error */
- err = genphy_update_link(phydev);
- if (err)
- return err;
-
- /* why bother the PHY if nothing can have changed */
- if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
- return 0;
-
- phydev->speed = SPEED_UNKNOWN;
- phydev->duplex = DUPLEX_UNKNOWN;
- phydev->pause = 0;
- phydev->asym_pause = 0;
-
- err = genphy_read_lpa(phydev);
- if (err < 0)
- return err;
-
- ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
- ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
- err = at803x_read_specific_status(phydev, ss_mask);
- if (err < 0)
- return err;
-
- if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
- phy_resolve_aneg_pause(phydev);
-
- return 0;
-}
-
static int at803x_config_aneg(struct phy_device *phydev)
{
struct at803x_priv *priv = phydev->priv;
--- a/drivers/net/phy/qcom/qca808x.c
+++ b/drivers/net/phy/qcom/qca808x.c
@@ -2,7 +2,6 @@
#include <linux/phy.h>
#include <linux/module.h>
-#include <linux/ethtool_netlink.h>
#include "qcom.h"
@@ -63,55 +62,6 @@
#define QCA808X_DBG_AN_TEST 0xb
#define QCA808X_HIBERNATION_EN BIT(15)
-#define QCA808X_CDT_ENABLE_TEST BIT(15)
-#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
-#define QCA808X_CDT_STATUS BIT(11)
-#define QCA808X_CDT_LENGTH_UNIT BIT(10)
-
-#define QCA808X_MMD3_CDT_STATUS 0x8064
-#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
-#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
-#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
-#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
-#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
-#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
-
-#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
-#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
-#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
-#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
-
-#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
-#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
-#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
-#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
-#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
-
-#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
-#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
-#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
-#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
-
-/* NORMAL are MDI with type set to 0 */
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
- QCA808X_CDT_STATUS_STAT_MDI1)
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
- QCA808X_CDT_STATUS_STAT_MDI1)
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
- QCA808X_CDT_STATUS_STAT_MDI2)
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
- QCA808X_CDT_STATUS_STAT_MDI2)
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
- QCA808X_CDT_STATUS_STAT_MDI3)
-#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
- QCA808X_CDT_STATUS_STAT_MDI3)
-
-/* Added for reference of existence but should be handled by wait_for_completion already */
-#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
-
#define QCA808X_MMD7_LED_GLOBAL 0x8073
#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
@@ -406,86 +356,6 @@ static int qca808x_soft_reset(struct phy
return ret;
}
-static bool qca808x_cdt_fault_length_valid(int cdt_code)
-{
- switch (cdt_code) {
- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
- return true;
- default:
- return false;
- }
-}
-
-static int qca808x_cable_test_result_trans(int cdt_code)
-{
- switch (cdt_code) {
- case QCA808X_CDT_STATUS_STAT_NORMAL:
- return ETHTOOL_A_CABLE_RESULT_CODE_OK;
- case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
- return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
- case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
- return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
- case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
- return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
- case QCA808X_CDT_STATUS_STAT_FAIL:
- default:
- return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
- }
-}
-
-static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
- int result)
-{
- int val;
- u32 cdt_length_reg = 0;
-
- switch (pair) {
- case ETHTOOL_A_CABLE_PAIR_A:
- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
- break;
- case ETHTOOL_A_CABLE_PAIR_B:
- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
- break;
- case ETHTOOL_A_CABLE_PAIR_C:
- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
- break;
- case ETHTOOL_A_CABLE_PAIR_D:
- cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
- break;
- default:
- return -EINVAL;
- }
-
- val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
- if (val < 0)
- return val;
-
- if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
- else
- val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
-
- return at803x_cdt_fault_length(val);
-}
-
static int qca808x_cable_test_start(struct phy_device *phydev)
{
int ret;
@@ -526,81 +396,6 @@ static int qca808x_cable_test_start(stru
return 0;
}
-
-static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
- u16 status)
-{
- int length, result;
- u16 pair_code;
-
- switch (pair) {
- case ETHTOOL_A_CABLE_PAIR_A:
- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
- break;
- case ETHTOOL_A_CABLE_PAIR_B:
- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
- break;
- case ETHTOOL_A_CABLE_PAIR_C:
- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
- break;
- case ETHTOOL_A_CABLE_PAIR_D:
- pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
- break;
- default:
- return -EINVAL;
- }
-
- result = qca808x_cable_test_result_trans(pair_code);
- ethnl_cable_test_result(phydev, pair, result);
-
- if (qca808x_cdt_fault_length_valid(pair_code)) {
- length = qca808x_cdt_fault_length(phydev, pair, result);
- ethnl_cable_test_fault_length(phydev, pair, length);
- }
-
- return 0;
-}
-
-static int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
-{
- int ret, val;
-
- *finished = false;
-
- val = QCA808X_CDT_ENABLE_TEST |
- QCA808X_CDT_LENGTH_UNIT;
- ret = at803x_cdt_start(phydev, val);
- if (ret)
- return ret;
-
- ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
- if (ret)
- return ret;
-
- val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
- if (val < 0)
- return val;
-
- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
- if (ret)
- return ret;
-
- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
- if (ret)
- return ret;
-
- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
- if (ret)
- return ret;
-
- ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
- if (ret)
- return ret;
-
- *finished = true;
-
- return 0;
-}
static int qca808x_get_features(struct phy_device *phydev)
{
--- a/drivers/net/phy/qcom/qcom-phy-lib.c
+++ b/drivers/net/phy/qcom/qcom-phy-lib.c
@@ -5,6 +5,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool_netlink.h>
#include "qcom.h"
@@ -311,6 +312,42 @@ int at803x_prepare_config_aneg(struct ph
}
EXPORT_SYMBOL_GPL(at803x_prepare_config_aneg);
+int at803x_read_status(struct phy_device *phydev)
+{
+ struct at803x_ss_mask ss_mask = { 0 };
+ int err, old_link = phydev->link;
+
+ /* Update the link, but return if there was an error */
+ err = genphy_update_link(phydev);
+ if (err)
+ return err;
+
+ /* why bother the PHY if nothing can have changed */
+ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
+ return 0;
+
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ phydev->pause = 0;
+ phydev->asym_pause = 0;
+
+ err = genphy_read_lpa(phydev);
+ if (err < 0)
+ return err;
+
+ ss_mask.speed_mask = AT803X_SS_SPEED_MASK;
+ ss_mask.speed_shift = __bf_shf(AT803X_SS_SPEED_MASK);
+ err = at803x_read_specific_status(phydev, ss_mask);
+ if (err < 0)
+ return err;
+
+ if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
+ phy_resolve_aneg_pause(phydev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(at803x_read_status);
+
static int at803x_get_downshift(struct phy_device *phydev, u8 *d)
{
int val;
@@ -427,3 +464,159 @@ int at803x_cdt_wait_for_completion(struc
return ret < 0 ? ret : 0;
}
EXPORT_SYMBOL_GPL(at803x_cdt_wait_for_completion);
+
+static bool qca808x_cdt_fault_length_valid(int cdt_code)
+{
+ switch (cdt_code) {
+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static int qca808x_cable_test_result_trans(int cdt_code)
+{
+ switch (cdt_code) {
+ case QCA808X_CDT_STATUS_STAT_NORMAL:
+ return ETHTOOL_A_CABLE_RESULT_CODE_OK;
+ case QCA808X_CDT_STATUS_STAT_SAME_SHORT:
+ return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
+ case QCA808X_CDT_STATUS_STAT_SAME_OPEN:
+ return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
+ case QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
+ return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
+ case QCA808X_CDT_STATUS_STAT_FAIL:
+ default:
+ return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
+ }
+}
+
+static int qca808x_cdt_fault_length(struct phy_device *phydev, int pair,
+ int result)
+{
+ int val;
+ u32 cdt_length_reg = 0;
+
+ switch (pair) {
+ case ETHTOOL_A_CABLE_PAIR_A:
+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_A;
+ break;
+ case ETHTOOL_A_CABLE_PAIR_B:
+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_B;
+ break;
+ case ETHTOOL_A_CABLE_PAIR_C:
+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_C;
+ break;
+ case ETHTOOL_A_CABLE_PAIR_D:
+ cdt_length_reg = QCA808X_MMD3_CDT_DIAG_PAIR_D;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, cdt_length_reg);
+ if (val < 0)
+ return val;
+
+ if (result == ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT)
+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_SAME_SHORT, val);
+ else
+ val = FIELD_GET(QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT, val);
+
+ return at803x_cdt_fault_length(val);
+}
+
+static int qca808x_cable_test_get_pair_status(struct phy_device *phydev, u8 pair,
+ u16 status)
+{
+ int length, result;
+ u16 pair_code;
+
+ switch (pair) {
+ case ETHTOOL_A_CABLE_PAIR_A:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_A, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_B:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_B, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_C:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_C, status);
+ break;
+ case ETHTOOL_A_CABLE_PAIR_D:
+ pair_code = FIELD_GET(QCA808X_CDT_CODE_PAIR_D, status);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ result = qca808x_cable_test_result_trans(pair_code);
+ ethnl_cable_test_result(phydev, pair, result);
+
+ if (qca808x_cdt_fault_length_valid(pair_code)) {
+ length = qca808x_cdt_fault_length(phydev, pair, result);
+ ethnl_cable_test_fault_length(phydev, pair, length);
+ }
+
+ return 0;
+}
+
+int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished)
+{
+ int ret, val;
+
+ *finished = false;
+
+ val = QCA808X_CDT_ENABLE_TEST |
+ QCA808X_CDT_LENGTH_UNIT;
+ ret = at803x_cdt_start(phydev, val);
+ if (ret)
+ return ret;
+
+ ret = at803x_cdt_wait_for_completion(phydev, QCA808X_CDT_ENABLE_TEST);
+ if (ret)
+ return ret;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA808X_MMD3_CDT_STATUS);
+ if (val < 0)
+ return val;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_A, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_B, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_C, val);
+ if (ret)
+ return ret;
+
+ ret = qca808x_cable_test_get_pair_status(phydev, ETHTOOL_A_CABLE_PAIR_D, val);
+ if (ret)
+ return ret;
+
+ *finished = true;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status);
--- a/drivers/net/phy/qcom/qcom.h
+++ b/drivers/net/phy/qcom/qcom.h
@@ -54,6 +54,55 @@
#define AT803X_CDT_STATUS_STAT_MASK GENMASK(9, 8)
#define AT803X_CDT_STATUS_DELTA_TIME_MASK GENMASK(7, 0)
+#define QCA808X_CDT_ENABLE_TEST BIT(15)
+#define QCA808X_CDT_INTER_CHECK_DIS BIT(13)
+#define QCA808X_CDT_STATUS BIT(11)
+#define QCA808X_CDT_LENGTH_UNIT BIT(10)
+
+#define QCA808X_MMD3_CDT_STATUS 0x8064
+#define QCA808X_MMD3_CDT_DIAG_PAIR_A 0x8065
+#define QCA808X_MMD3_CDT_DIAG_PAIR_B 0x8066
+#define QCA808X_MMD3_CDT_DIAG_PAIR_C 0x8067
+#define QCA808X_MMD3_CDT_DIAG_PAIR_D 0x8068
+#define QCA808X_CDT_DIAG_LENGTH_SAME_SHORT GENMASK(15, 8)
+#define QCA808X_CDT_DIAG_LENGTH_CROSS_SHORT GENMASK(7, 0)
+
+#define QCA808X_CDT_CODE_PAIR_A GENMASK(15, 12)
+#define QCA808X_CDT_CODE_PAIR_B GENMASK(11, 8)
+#define QCA808X_CDT_CODE_PAIR_C GENMASK(7, 4)
+#define QCA808X_CDT_CODE_PAIR_D GENMASK(3, 0)
+
+#define QCA808X_CDT_STATUS_STAT_TYPE GENMASK(1, 0)
+#define QCA808X_CDT_STATUS_STAT_FAIL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 0)
+#define QCA808X_CDT_STATUS_STAT_NORMAL FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 1)
+#define QCA808X_CDT_STATUS_STAT_SAME_OPEN FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 2)
+#define QCA808X_CDT_STATUS_STAT_SAME_SHORT FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_TYPE, 3)
+
+#define QCA808X_CDT_STATUS_STAT_MDI GENMASK(3, 2)
+#define QCA808X_CDT_STATUS_STAT_MDI1 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 1)
+#define QCA808X_CDT_STATUS_STAT_MDI2 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 2)
+#define QCA808X_CDT_STATUS_STAT_MDI3 FIELD_PREP_CONST(QCA808X_CDT_STATUS_STAT_MDI, 3)
+
+/* NORMAL are MDI with type set to 0 */
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI1
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI1)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI1_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI1)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI2
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI2)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI2_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI2)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_NORMAL QCA808X_CDT_STATUS_STAT_MDI3
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_OPEN (QCA808X_CDT_STATUS_STAT_SAME_OPEN |\
+ QCA808X_CDT_STATUS_STAT_MDI3)
+#define QCA808X_CDT_STATUS_STAT_CROSS_SHORT_WITH_MDI3_SAME_SHORT (QCA808X_CDT_STATUS_STAT_SAME_SHORT |\
+ QCA808X_CDT_STATUS_STAT_MDI3)
+
+/* Added for reference of existence but should be handled by wait_for_completion already */
+#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
+
#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A
@@ -110,6 +159,7 @@ int at803x_read_specific_status(struct p
struct at803x_ss_mask ss_mask);
int at803x_config_mdix(struct phy_device *phydev, u8 ctrl);
int at803x_prepare_config_aneg(struct phy_device *phydev);
+int at803x_read_status(struct phy_device *phydev);
int at803x_get_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, void *data);
int at803x_set_tunable(struct phy_device *phydev,
@@ -118,3 +168,4 @@ int at803x_cdt_fault_length(int dt);
int at803x_cdt_start(struct phy_device *phydev, u32 cdt_start);
int at803x_cdt_wait_for_completion(struct phy_device *phydev,
u32 cdt_en);
+int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished);

View File

@@ -0,0 +1,100 @@
From 9b1d5e055508393561e26bd1720f4c2639b03b1a Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:09 +0100
Subject: [PATCH 06/10] net: phy: provide whether link has changed in
c37_read_status
Some PHY driver might require additional regs call after
genphy_c37_read_status() is called.
Expand genphy_c37_read_status to provide a bool wheather the link has
changed or not to permit PHY driver to skip additional regs call if
nothing has changed.
Every user of genphy_c37_read_status() is updated with the new
additional bool.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/broadcom.c | 3 ++-
drivers/net/phy/phy_device.c | 11 +++++++++--
drivers/net/phy/qcom/at803x.c | 3 ++-
include/linux/phy.h | 2 +-
4 files changed, 14 insertions(+), 5 deletions(-)
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -609,10 +609,11 @@ static int bcm54616s_config_aneg(struct
static int bcm54616s_read_status(struct phy_device *phydev)
{
struct bcm54616s_phy_priv *priv = phydev->priv;
+ bool changed;
int err;
if (priv->mode_1000bx_en)
- err = genphy_c37_read_status(phydev);
+ err = genphy_c37_read_status(phydev, &changed);
else
err = genphy_read_status(phydev);
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2551,12 +2551,15 @@ EXPORT_SYMBOL(genphy_read_status);
/**
* genphy_c37_read_status - check the link status and update current link state
* @phydev: target phy_device struct
+ * @changed: pointer where to store if link changed
*
* Description: Check the link, then figure out the current state
* by comparing what we advertise with what the link partner
* advertises. This function is for Clause 37 1000Base-X mode.
+ *
+ * If link has changed, @changed is set to true, false otherwise.
*/
-int genphy_c37_read_status(struct phy_device *phydev)
+int genphy_c37_read_status(struct phy_device *phydev, bool *changed)
{
int lpa, err, old_link = phydev->link;
@@ -2566,9 +2569,13 @@ int genphy_c37_read_status(struct phy_de
return err;
/* why bother the PHY if nothing can have changed */
- if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
+ if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link) {
+ *changed = false;
return 0;
+ }
+ /* Signal link has changed */
+ *changed = true;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
--- a/drivers/net/phy/qcom/at803x.c
+++ b/drivers/net/phy/qcom/at803x.c
@@ -912,9 +912,10 @@ static int at8031_config_intr(struct phy
static int at8031_read_status(struct phy_device *phydev)
{
struct at803x_priv *priv = phydev->priv;
+ bool changed;
if (priv->is_1000basex)
- return genphy_c37_read_status(phydev);
+ return genphy_c37_read_status(phydev, &changed);
return at803x_read_status(phydev);
}
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1660,7 +1660,7 @@ int genphy_write_mmd_unsupported(struct
/* Clause 37 */
int genphy_c37_config_aneg(struct phy_device *phydev);
-int genphy_c37_read_status(struct phy_device *phydev);
+int genphy_c37_read_status(struct phy_device *phydev, bool *changed);
/* Clause 45 PHY */
int genphy_c45_restart_aneg(struct phy_device *phydev);

View File

@@ -0,0 +1,668 @@
From d1cb613efbd3cd7d0c000167816beb3f248f5eb8 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Tue, 6 Feb 2024 18:31:10 +0100
Subject: [PATCH 07/10] net: phy: qcom: add support for QCA807x PHY Family
This adds driver for the Qualcomm QCA8072 and QCA8075 PHY-s.
They are 2 or 5 port IEEE 802.3 clause 22 compliant 10BASE-Te,
100BASE-TX and 1000BASE-T PHY-s.
They feature 2 SerDes, one for PSGMII or QSGMII connection with
MAC, while second one is SGMII for connection to MAC or fiber.
Both models have a combo port that supports 1000BASE-X and
100BASE-FX fiber.
PHY package can be configured in 3 mode following this table:
First Serdes mode Second Serdes mode
Option 1 PSGMII for copper Disabled
ports 0-4
Option 2 PSGMII for copper 1000BASE-X / 100BASE-FX
ports 0-4
Option 3 QSGMII for copper SGMII for
ports 0-3 copper port 4
Each PHY inside of QCA807x series has 4 digitally controlled
output only pins that natively drive LED-s.
But some vendors used these to driver generic LED-s controlled
by userspace, so lets enable registering each PHY as GPIO
controller and add driver for it.
These are commonly used in Qualcomm IPQ40xx, IPQ60xx and IPQ807x
boards.
Co-developed-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/qcom/Kconfig | 8 +
drivers/net/phy/qcom/Makefile | 1 +
drivers/net/phy/qcom/qca807x.c | 597 +++++++++++++++++++++++++++++++++
3 files changed, 606 insertions(+)
create mode 100644 drivers/net/phy/qcom/qca807x.c
--- a/drivers/net/phy/qcom/Kconfig
+++ b/drivers/net/phy/qcom/Kconfig
@@ -20,3 +20,11 @@ config QCA808X_PHY
select QCOM_NET_PHYLIB
help
Currently supports the QCA8081 model
+
+config QCA807X_PHY
+ tristate "Qualcomm QCA807x PHYs"
+ select QCOM_NET_PHYLIB
+ depends on OF_MDIO
+ help
+ Currently supports the Qualcomm QCA8072, QCA8075 and the PSGMII
+ control PHY.
--- a/drivers/net/phy/qcom/Makefile
+++ b/drivers/net/phy/qcom/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-ph
obj-$(CONFIG_AT803X_PHY) += at803x.o
obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
obj-$(CONFIG_QCA808X_PHY) += qca808x.o
+obj-$(CONFIG_QCA807X_PHY) += qca807x.o
--- /dev/null
+++ b/drivers/net/phy/qcom/qca807x.c
@@ -0,0 +1,597 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2023 Sartura Ltd.
+ *
+ * Author: Robert Marko <robert.marko@sartura.hr>
+ * Christian Marangi <ansuelsmth@gmail.com>
+ *
+ * Qualcomm QCA8072 and QCA8075 PHY driver
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy.h>
+#include <linux/bitfield.h>
+#include <linux/gpio/driver.h>
+#include <linux/sfp.h>
+
+#include "qcom.h"
+
+#define QCA807X_CHIP_CONFIGURATION 0x1f
+#define QCA807X_BT_BX_REG_SEL BIT(15)
+#define QCA807X_BT_BX_REG_SEL_FIBER 0
+#define QCA807X_BT_BX_REG_SEL_COPPER 1
+#define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0)
+#define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4
+#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3
+#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0
+
+#define QCA807X_MEDIA_SELECT_STATUS 0x1a
+#define QCA807X_MEDIA_DETECTED_COPPER BIT(5)
+#define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4)
+#define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3)
+
+#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e
+#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0)
+
+#define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a
+#define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0)
+/* List of tweaks enabled by this bit:
+ * - With both FULL amplitude and FULL bias current: bias current
+ * is set to half.
+ * - With only DSP amplitude: bias current is set to half and
+ * is set to 1/4 with cable < 10m.
+ * - With DSP bias current (included both DSP amplitude and
+ * DSP bias current): bias current is half the detected current
+ * with cable < 10m.
+ */
+#define QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK BIT(2)
+#define QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT BIT(1)
+#define QCA807X_CONTROL_DAC_DSP_AMPLITUDE BIT(0)
+
+#define QCA807X_MMD7_LED_100N_1 0x8074
+#define QCA807X_MMD7_LED_100N_2 0x8075
+#define QCA807X_MMD7_LED_1000N_1 0x8076
+#define QCA807X_MMD7_LED_1000N_2 0x8077
+
+#define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2))
+#define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2))
+
+#define QCA807X_GPIO_FORCE_EN BIT(15)
+#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
+
+#define QCA807X_FUNCTION_CONTROL 0x10
+#define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
+#define QCA807X_FC_MDI_CROSSOVER_AUTO 3
+#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1
+#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0
+
+/* PQSGMII Analog PHY specific */
+#define PQSGMII_CTRL_REG 0x0
+#define PQSGMII_ANALOG_SW_RESET BIT(6)
+#define PQSGMII_DRIVE_CONTROL_1 0xb
+#define PQSGMII_TX_DRIVER_MASK GENMASK(7, 4)
+#define PQSGMII_TX_DRIVER_140MV 0x0
+#define PQSGMII_TX_DRIVER_160MV 0x1
+#define PQSGMII_TX_DRIVER_180MV 0x2
+#define PQSGMII_TX_DRIVER_200MV 0x3
+#define PQSGMII_TX_DRIVER_220MV 0x4
+#define PQSGMII_TX_DRIVER_240MV 0x5
+#define PQSGMII_TX_DRIVER_260MV 0x6
+#define PQSGMII_TX_DRIVER_280MV 0x7
+#define PQSGMII_TX_DRIVER_300MV 0x8
+#define PQSGMII_TX_DRIVER_320MV 0x9
+#define PQSGMII_TX_DRIVER_400MV 0xa
+#define PQSGMII_TX_DRIVER_500MV 0xb
+#define PQSGMII_TX_DRIVER_600MV 0xc
+#define PQSGMII_MODE_CTRL 0x6d
+#define PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0)
+#define PQSGMII_MMD3_SERDES_CONTROL 0x805a
+
+#define PHY_ID_QCA8072 0x004dd0b2
+#define PHY_ID_QCA8075 0x004dd0b1
+
+#define QCA807X_COMBO_ADDR_OFFSET 4
+#define QCA807X_PQSGMII_ADDR_OFFSET 5
+#define SERDES_RESET_SLEEP 100
+
+enum qca807x_global_phy {
+ QCA807X_COMBO_ADDR = 4,
+ QCA807X_PQSGMII_ADDR = 5,
+};
+
+struct qca807x_shared_priv {
+ unsigned int package_mode;
+ u32 tx_drive_strength;
+};
+
+struct qca807x_gpio_priv {
+ struct phy_device *phy;
+};
+
+struct qca807x_priv {
+ bool dac_full_amplitude;
+ bool dac_full_bias_current;
+ bool dac_disable_bias_current_tweak;
+};
+
+static int qca807x_cable_test_start(struct phy_device *phydev)
+{
+ /* we do all the (time consuming) work later */
+ return 0;
+}
+
+#ifdef CONFIG_GPIOLIB
+static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
+ u16 reg;
+ int val;
+
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
+ val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
+
+ return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
+}
+
+static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
+ u16 reg;
+ int val;
+
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(offset);
+
+ val = phy_read_mmd(priv->phy, MDIO_MMD_AN, reg);
+ val &= ~QCA807X_GPIO_FORCE_MODE_MASK;
+ val |= QCA807X_GPIO_FORCE_EN;
+ val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value);
+
+ phy_write_mmd(priv->phy, MDIO_MMD_AN, reg, val);
+}
+
+static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ qca807x_gpio_set(gc, offset, value);
+
+ return 0;
+}
+
+static int qca807x_gpio(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct qca807x_gpio_priv *priv;
+ struct gpio_chip *gc;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->phy = phydev;
+
+ gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
+ if (!gc)
+ return -ENOMEM;
+
+ gc->label = dev_name(dev);
+ gc->base = -1;
+ gc->ngpio = 2;
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+ gc->can_sleep = true;
+ gc->get_direction = qca807x_gpio_get_direction;
+ gc->direction_output = qca807x_gpio_dir_out;
+ gc->get = qca807x_gpio_get;
+ gc->set = qca807x_gpio_set;
+
+ return devm_gpiochip_add_data(dev, gc, priv);
+}
+#endif
+
+static int qca807x_read_fiber_status(struct phy_device *phydev)
+{
+ bool changed;
+ int ss, err;
+
+ err = genphy_c37_read_status(phydev, &changed);
+ if (err || !changed)
+ return err;
+
+ /* Read the QCA807x PHY-Specific Status register fiber page,
+ * which indicates the speed and duplex that the PHY is actually
+ * using, irrespective of whether we are in autoneg mode or not.
+ */
+ ss = phy_read(phydev, AT803X_SPECIFIC_STATUS);
+ if (ss < 0)
+ return ss;
+
+ phydev->speed = SPEED_UNKNOWN;
+ phydev->duplex = DUPLEX_UNKNOWN;
+ if (ss & AT803X_SS_SPEED_DUPLEX_RESOLVED) {
+ switch (FIELD_GET(AT803X_SS_SPEED_MASK, ss)) {
+ case AT803X_SS_SPEED_100:
+ phydev->speed = SPEED_100;
+ break;
+ case AT803X_SS_SPEED_1000:
+ phydev->speed = SPEED_1000;
+ break;
+ }
+
+ if (ss & AT803X_SS_DUPLEX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+ }
+
+ return 0;
+}
+
+static int qca807x_read_status(struct phy_device *phydev)
+{
+ if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
+ switch (phydev->port) {
+ case PORT_FIBRE:
+ return qca807x_read_fiber_status(phydev);
+ case PORT_TP:
+ return at803x_read_status(phydev);
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return at803x_read_status(phydev);
+}
+
+static int qca807x_phy_package_probe_once(struct phy_device *phydev)
+{
+ struct phy_package_shared *shared = phydev->shared;
+ struct qca807x_shared_priv *priv = shared->priv;
+ unsigned int tx_drive_strength;
+ const char *package_mode_name;
+
+ /* Default to 600mw if not defined */
+ if (of_property_read_u32(shared->np, "qcom,tx-drive-strength-milliwatt",
+ &tx_drive_strength))
+ tx_drive_strength = 600;
+
+ switch (tx_drive_strength) {
+ case 140:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_140MV;
+ break;
+ case 160:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_160MV;
+ break;
+ case 180:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_180MV;
+ break;
+ case 200:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_200MV;
+ break;
+ case 220:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_220MV;
+ break;
+ case 240:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_240MV;
+ break;
+ case 260:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_260MV;
+ break;
+ case 280:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_280MV;
+ break;
+ case 300:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_300MV;
+ break;
+ case 320:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_320MV;
+ break;
+ case 400:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_400MV;
+ break;
+ case 500:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_500MV;
+ break;
+ case 600:
+ priv->tx_drive_strength = PQSGMII_TX_DRIVER_600MV;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ priv->package_mode = PHY_INTERFACE_MODE_NA;
+ if (!of_property_read_string(shared->np, "qcom,package-mode",
+ &package_mode_name)) {
+ if (!strcasecmp(package_mode_name,
+ phy_modes(PHY_INTERFACE_MODE_PSGMII)))
+ priv->package_mode = PHY_INTERFACE_MODE_PSGMII;
+ else if (!strcasecmp(package_mode_name,
+ phy_modes(PHY_INTERFACE_MODE_QSGMII)))
+ priv->package_mode = PHY_INTERFACE_MODE_QSGMII;
+ else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qca807x_phy_package_config_init_once(struct phy_device *phydev)
+{
+ struct phy_package_shared *shared = phydev->shared;
+ struct qca807x_shared_priv *priv = shared->priv;
+ int val, ret;
+
+ phy_lock_mdio_bus(phydev);
+
+ /* Set correct PHY package mode */
+ val = __phy_package_read(phydev, QCA807X_COMBO_ADDR,
+ QCA807X_CHIP_CONFIGURATION);
+ val &= ~QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK;
+ /* package_mode can be QSGMII or PSGMII and we validate
+ * this in probe_once.
+ * With package_mode to NA, we default to PSGMII.
+ */
+ switch (priv->package_mode) {
+ case PHY_INTERFACE_MODE_QSGMII:
+ val |= QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII;
+ break;
+ case PHY_INTERFACE_MODE_PSGMII:
+ default:
+ val |= QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER;
+ }
+ ret = __phy_package_write(phydev, QCA807X_COMBO_ADDR,
+ QCA807X_CHIP_CONFIGURATION, val);
+ if (ret)
+ goto exit;
+
+ /* After mode change Serdes reset is required */
+ val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
+ PQSGMII_CTRL_REG);
+ val &= ~PQSGMII_ANALOG_SW_RESET;
+ ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
+ PQSGMII_CTRL_REG, val);
+ if (ret)
+ goto exit;
+
+ msleep(SERDES_RESET_SLEEP);
+
+ val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
+ PQSGMII_CTRL_REG);
+ val |= PQSGMII_ANALOG_SW_RESET;
+ ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
+ PQSGMII_CTRL_REG, val);
+ if (ret)
+ goto exit;
+
+ /* Workaround to enable AZ transmitting ability */
+ val = __phy_package_read_mmd(phydev, QCA807X_PQSGMII_ADDR,
+ MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL);
+ val &= ~PQSGMII_MODE_CTRL_AZ_WORKAROUND_MASK;
+ ret = __phy_package_write_mmd(phydev, QCA807X_PQSGMII_ADDR,
+ MDIO_MMD_PMAPMD, PQSGMII_MODE_CTRL, val);
+ if (ret)
+ goto exit;
+
+ /* Set PQSGMII TX AMP strength */
+ val = __phy_package_read(phydev, QCA807X_PQSGMII_ADDR,
+ PQSGMII_DRIVE_CONTROL_1);
+ val &= ~PQSGMII_TX_DRIVER_MASK;
+ val |= FIELD_PREP(PQSGMII_TX_DRIVER_MASK, priv->tx_drive_strength);
+ ret = __phy_package_write(phydev, QCA807X_PQSGMII_ADDR,
+ PQSGMII_DRIVE_CONTROL_1, val);
+ if (ret)
+ goto exit;
+
+ /* Prevent PSGMII going into hibernation via PSGMII self test */
+ val = __phy_package_read_mmd(phydev, QCA807X_COMBO_ADDR,
+ MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL);
+ val &= ~BIT(1);
+ ret = __phy_package_write_mmd(phydev, QCA807X_COMBO_ADDR,
+ MDIO_MMD_PCS, PQSGMII_MMD3_SERDES_CONTROL, val);
+
+exit:
+ phy_unlock_mdio_bus(phydev);
+
+ return ret;
+}
+
+static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
+{
+ struct phy_device *phydev = upstream;
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
+ phy_interface_t iface;
+ int ret;
+ DECLARE_PHY_INTERFACE_MASK(interfaces);
+
+ sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
+ iface = sfp_select_interface(phydev->sfp_bus, support);
+
+ dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface));
+
+ switch (iface) {
+ case PHY_INTERFACE_MODE_1000BASEX:
+ case PHY_INTERFACE_MODE_100BASEX:
+ /* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
+ ret = phy_modify(phydev,
+ QCA807X_CHIP_CONFIGURATION,
+ QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
+ QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
+ /* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
+ ret = phy_set_bits_mmd(phydev,
+ MDIO_MMD_AN,
+ QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
+ QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN);
+ /* Select fiber page */
+ ret = phy_clear_bits(phydev,
+ QCA807X_CHIP_CONFIGURATION,
+ QCA807X_BT_BX_REG_SEL);
+
+ phydev->port = PORT_FIBRE;
+ break;
+ default:
+ dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n");
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static void qca807x_sfp_remove(void *upstream)
+{
+ struct phy_device *phydev = upstream;
+
+ /* Select copper page */
+ phy_set_bits(phydev,
+ QCA807X_CHIP_CONFIGURATION,
+ QCA807X_BT_BX_REG_SEL);
+
+ phydev->port = PORT_TP;
+}
+
+static const struct sfp_upstream_ops qca807x_sfp_ops = {
+ .attach = phy_sfp_attach,
+ .detach = phy_sfp_detach,
+ .module_insert = qca807x_sfp_insert,
+ .module_remove = qca807x_sfp_remove,
+};
+
+static int qca807x_probe(struct phy_device *phydev)
+{
+ struct device_node *node = phydev->mdio.dev.of_node;
+ struct qca807x_shared_priv *shared_priv;
+ struct device *dev = &phydev->mdio.dev;
+ struct phy_package_shared *shared;
+ struct qca807x_priv *priv;
+ int ret;
+
+ ret = devm_of_phy_package_join(dev, phydev, sizeof(*shared_priv));
+ if (ret)
+ return ret;
+
+ if (phy_package_probe_once(phydev)) {
+ ret = qca807x_phy_package_probe_once(phydev);
+ if (ret)
+ return ret;
+ }
+
+ shared = phydev->shared;
+ shared_priv = shared->priv;
+
+ /* Make sure PHY follow PHY package mode if enforced */
+ if (shared_priv->package_mode != PHY_INTERFACE_MODE_NA &&
+ phydev->interface != shared_priv->package_mode)
+ return -EINVAL;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->dac_full_amplitude = of_property_read_bool(node, "qcom,dac-full-amplitude");
+ priv->dac_full_bias_current = of_property_read_bool(node, "qcom,dac-full-bias-current");
+ priv->dac_disable_bias_current_tweak = of_property_read_bool(node,
+ "qcom,dac-disable-bias-current-tweak");
+
+ if (IS_ENABLED(CONFIG_GPIOLIB)) {
+ /* Do not register a GPIO controller unless flagged for it */
+ if (of_property_read_bool(node, "gpio-controller")) {
+ ret = qca807x_gpio(phydev);
+ if (ret)
+ return ret;
+ }
+ }
+
+ /* Attach SFP bus on combo port*/
+ if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
+ ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
+ if (ret)
+ return ret;
+ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
+ linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
+ }
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
+static int qca807x_config_init(struct phy_device *phydev)
+{
+ struct qca807x_priv *priv = phydev->priv;
+ u16 control_dac;
+ int ret;
+
+ if (phy_package_init_once(phydev)) {
+ ret = qca807x_phy_package_config_init_once(phydev);
+ if (ret)
+ return ret;
+ }
+
+ control_dac = phy_read_mmd(phydev, MDIO_MMD_AN,
+ QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH);
+ control_dac &= ~QCA807X_CONTROL_DAC_MASK;
+ if (!priv->dac_full_amplitude)
+ control_dac |= QCA807X_CONTROL_DAC_DSP_AMPLITUDE;
+ if (!priv->dac_full_amplitude)
+ control_dac |= QCA807X_CONTROL_DAC_DSP_BIAS_CURRENT;
+ if (!priv->dac_disable_bias_current_tweak)
+ control_dac |= QCA807X_CONTROL_DAC_BIAS_CURRENT_TWEAK;
+ return phy_write_mmd(phydev, MDIO_MMD_AN,
+ QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH,
+ control_dac);
+}
+
+static struct phy_driver qca807x_drivers[] = {
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_QCA8072),
+ .name = "Qualcomm QCA8072",
+ .flags = PHY_POLL_CABLE_TEST,
+ /* PHY_GBIT_FEATURES */
+ .probe = qca807x_probe,
+ .config_init = qca807x_config_init,
+ .read_status = qca807x_read_status,
+ .config_intr = at803x_config_intr,
+ .handle_interrupt = at803x_handle_interrupt,
+ .soft_reset = genphy_soft_reset,
+ .get_tunable = at803x_get_tunable,
+ .set_tunable = at803x_set_tunable,
+ .resume = genphy_resume,
+ .suspend = genphy_suspend,
+ .cable_test_start = qca807x_cable_test_start,
+ .cable_test_get_status = qca808x_cable_test_get_status,
+ },
+ {
+ PHY_ID_MATCH_EXACT(PHY_ID_QCA8075),
+ .name = "Qualcomm QCA8075",
+ .flags = PHY_POLL_CABLE_TEST,
+ /* PHY_GBIT_FEATURES */
+ .probe = qca807x_probe,
+ .config_init = qca807x_config_init,
+ .read_status = qca807x_read_status,
+ .config_intr = at803x_config_intr,
+ .handle_interrupt = at803x_handle_interrupt,
+ .soft_reset = genphy_soft_reset,
+ .get_tunable = at803x_get_tunable,
+ .set_tunable = at803x_set_tunable,
+ .resume = genphy_resume,
+ .suspend = genphy_suspend,
+ .cable_test_start = qca807x_cable_test_start,
+ .cable_test_get_status = qca808x_cable_test_get_status,
+ },
+};
+module_phy_driver(qca807x_drivers);
+
+static struct mdio_device_id __maybe_unused qca807x_tbl[] = {
+ { PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
+ { PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
+ { }
+};
+
+MODULE_AUTHOR("Robert Marko <robert.marko@sartura.hr>");
+MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>");
+MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver");
+MODULE_DEVICE_TABLE(mdio, qca807x_tbl);
+MODULE_LICENSE("GPL");

View File

@@ -0,0 +1,179 @@
From ee9d9807bee0e6af8ca2a4db6f0d1dc0e5b41f44 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:11 +0100
Subject: [PATCH 08/10] net: phy: qcom: move common qca808x LED define to
shared header
The LED implementation of qca808x and qca807x is the same but qca807x
supports also Fiber port and have different hw control bits for Fiber
port.
In preparation for qca807x introduction, move all the common define to
shared header.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/qcom/qca808x.c | 65 ----------------------------------
drivers/net/phy/qcom/qcom.h | 65 ++++++++++++++++++++++++++++++++++
2 files changed, 65 insertions(+), 65 deletions(-)
--- a/drivers/net/phy/qcom/qca808x.c
+++ b/drivers/net/phy/qcom/qca808x.c
@@ -62,29 +62,6 @@
#define QCA808X_DBG_AN_TEST 0xb
#define QCA808X_HIBERNATION_EN BIT(15)
-#define QCA808X_MMD7_LED_GLOBAL 0x8073
-#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
-#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
-/* Values are the same for both BLINK_1 and BLINK_2 */
-#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
-#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
-#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
-#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
-#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
-#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
-#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
-#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
-#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
-#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
-#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
-#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
-#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
-#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
-#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
-#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
-#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
-#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
-
#define QCA808X_MMD7_LED2_CTRL 0x8074
#define QCA808X_MMD7_LED2_FORCE_CTRL 0x8075
#define QCA808X_MMD7_LED1_CTRL 0x8076
@@ -92,51 +69,9 @@
#define QCA808X_MMD7_LED0_CTRL 0x8078
#define QCA808X_MMD7_LED_CTRL(x) (0x8078 - ((x) * 2))
-/* LED hw control pattern is the same for every LED */
-#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
-#define QCA808X_LED_SPEED2500_ON BIT(15)
-#define QCA808X_LED_SPEED2500_BLINK BIT(14)
-/* Follow blink trigger even if duplex or speed condition doesn't match */
-#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
-#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
-#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
-#define QCA808X_LED_TX_BLINK BIT(10)
-#define QCA808X_LED_RX_BLINK BIT(9)
-#define QCA808X_LED_TX_ON_10MS BIT(8)
-#define QCA808X_LED_RX_ON_10MS BIT(7)
-#define QCA808X_LED_SPEED1000_ON BIT(6)
-#define QCA808X_LED_SPEED100_ON BIT(5)
-#define QCA808X_LED_SPEED10_ON BIT(4)
-#define QCA808X_LED_COLLISION_BLINK BIT(3)
-#define QCA808X_LED_SPEED1000_BLINK BIT(2)
-#define QCA808X_LED_SPEED100_BLINK BIT(1)
-#define QCA808X_LED_SPEED10_BLINK BIT(0)
-
#define QCA808X_MMD7_LED0_FORCE_CTRL 0x8079
#define QCA808X_MMD7_LED_FORCE_CTRL(x) (0x8079 - ((x) * 2))
-/* LED force ctrl is the same for every LED
- * No documentation exist for this, not even internal one
- * with NDA as QCOM gives only info about configuring
- * hw control pattern rules and doesn't indicate any way
- * to force the LED to specific mode.
- * These define comes from reverse and testing and maybe
- * lack of some info or some info are not entirely correct.
- * For the basic LED control and hw control these finding
- * are enough to support LED control in all the required APIs.
- *
- * On doing some comparison with implementation with qca807x,
- * it was found that it's 1:1 equal to it and confirms all the
- * reverse done. It was also found further specification with the
- * force mode and the blink modes.
- */
-#define QCA808X_LED_FORCE_EN BIT(15)
-#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
-#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
-#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
-#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
-#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
-
#define QCA808X_MMD7_LED_POLARITY_CTRL 0x901a
/* QSDK sets by default 0x46 to this reg that sets BIT 6 for
* LED to active high. It's not clear what BIT 3 and BIT 4 does.
--- a/drivers/net/phy/qcom/qcom.h
+++ b/drivers/net/phy/qcom/qcom.h
@@ -103,6 +103,71 @@
/* Added for reference of existence but should be handled by wait_for_completion already */
#define QCA808X_CDT_STATUS_STAT_BUSY (BIT(1) | BIT(3))
+#define QCA808X_MMD7_LED_GLOBAL 0x8073
+#define QCA808X_LED_BLINK_1 GENMASK(11, 6)
+#define QCA808X_LED_BLINK_2 GENMASK(5, 0)
+/* Values are the same for both BLINK_1 and BLINK_2 */
+#define QCA808X_LED_BLINK_FREQ_MASK GENMASK(5, 3)
+#define QCA808X_LED_BLINK_FREQ_2HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x0)
+#define QCA808X_LED_BLINK_FREQ_4HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x1)
+#define QCA808X_LED_BLINK_FREQ_8HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x2)
+#define QCA808X_LED_BLINK_FREQ_16HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x3)
+#define QCA808X_LED_BLINK_FREQ_32HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x4)
+#define QCA808X_LED_BLINK_FREQ_64HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x5)
+#define QCA808X_LED_BLINK_FREQ_128HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x6)
+#define QCA808X_LED_BLINK_FREQ_256HZ FIELD_PREP(QCA808X_LED_BLINK_FREQ_MASK, 0x7)
+#define QCA808X_LED_BLINK_DUTY_MASK GENMASK(2, 0)
+#define QCA808X_LED_BLINK_DUTY_50_50 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x0)
+#define QCA808X_LED_BLINK_DUTY_75_25 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x1)
+#define QCA808X_LED_BLINK_DUTY_25_75 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x2)
+#define QCA808X_LED_BLINK_DUTY_33_67 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x3)
+#define QCA808X_LED_BLINK_DUTY_67_33 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x4)
+#define QCA808X_LED_BLINK_DUTY_17_83 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x5)
+#define QCA808X_LED_BLINK_DUTY_83_17 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x6)
+#define QCA808X_LED_BLINK_DUTY_8_92 FIELD_PREP(QCA808X_LED_BLINK_DUTY_MASK, 0x7)
+
+/* LED hw control pattern is the same for every LED */
+#define QCA808X_LED_PATTERN_MASK GENMASK(15, 0)
+#define QCA808X_LED_SPEED2500_ON BIT(15)
+#define QCA808X_LED_SPEED2500_BLINK BIT(14)
+/* Follow blink trigger even if duplex or speed condition doesn't match */
+#define QCA808X_LED_BLINK_CHECK_BYPASS BIT(13)
+#define QCA808X_LED_FULL_DUPLEX_ON BIT(12)
+#define QCA808X_LED_HALF_DUPLEX_ON BIT(11)
+#define QCA808X_LED_TX_BLINK BIT(10)
+#define QCA808X_LED_RX_BLINK BIT(9)
+#define QCA808X_LED_TX_ON_10MS BIT(8)
+#define QCA808X_LED_RX_ON_10MS BIT(7)
+#define QCA808X_LED_SPEED1000_ON BIT(6)
+#define QCA808X_LED_SPEED100_ON BIT(5)
+#define QCA808X_LED_SPEED10_ON BIT(4)
+#define QCA808X_LED_COLLISION_BLINK BIT(3)
+#define QCA808X_LED_SPEED1000_BLINK BIT(2)
+#define QCA808X_LED_SPEED100_BLINK BIT(1)
+#define QCA808X_LED_SPEED10_BLINK BIT(0)
+
+/* LED force ctrl is the same for every LED
+ * No documentation exist for this, not even internal one
+ * with NDA as QCOM gives only info about configuring
+ * hw control pattern rules and doesn't indicate any way
+ * to force the LED to specific mode.
+ * These define comes from reverse and testing and maybe
+ * lack of some info or some info are not entirely correct.
+ * For the basic LED control and hw control these finding
+ * are enough to support LED control in all the required APIs.
+ *
+ * On doing some comparison with implementation with qca807x,
+ * it was found that it's 1:1 equal to it and confirms all the
+ * reverse done. It was also found further specification with the
+ * force mode and the blink modes.
+ */
+#define QCA808X_LED_FORCE_EN BIT(15)
+#define QCA808X_LED_FORCE_MODE_MASK GENMASK(14, 13)
+#define QCA808X_LED_FORCE_BLINK_1 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x3)
+#define QCA808X_LED_FORCE_BLINK_2 FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x2)
+#define QCA808X_LED_FORCE_ON FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x1)
+#define QCA808X_LED_FORCE_OFF FIELD_PREP(QCA808X_LED_FORCE_MODE_MASK, 0x0)
+
#define AT803X_LOC_MAC_ADDR_0_15_OFFSET 0x804C
#define AT803X_LOC_MAC_ADDR_16_31_OFFSET 0x804B
#define AT803X_LOC_MAC_ADDR_32_47_OFFSET 0x804A

View File

@@ -0,0 +1,172 @@
From 47b930d0dd437af927145dba50a2e2ea1ba97c67 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:12 +0100
Subject: [PATCH 09/10] net: phy: qcom: generalize some qca808x LED functions
Generalize some qca808x LED functions in preparation for qca807x LED
support.
The LED implementation of qca808x and qca807x is the same but qca807x
supports also Fiber port and have different hw control bits for Fiber
port. To limit code duplication introduce micro functions that takes reg
instead of LED index to tweak all the supported LED modes.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/qcom/qca808x.c | 38 +++-----------------
drivers/net/phy/qcom/qcom-phy-lib.c | 54 +++++++++++++++++++++++++++++
drivers/net/phy/qcom/qcom.h | 7 ++++
3 files changed, 65 insertions(+), 34 deletions(-)
--- a/drivers/net/phy/qcom/qca808x.c
+++ b/drivers/net/phy/qcom/qca808x.c
@@ -437,9 +437,7 @@ static int qca808x_led_hw_control_enable
return -EINVAL;
reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-
- return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
- QCA808X_LED_FORCE_EN);
+ return qca808x_led_reg_hw_control_enable(phydev, reg);
}
static int qca808x_led_hw_is_supported(struct phy_device *phydev, u8 index,
@@ -480,16 +478,12 @@ static int qca808x_led_hw_control_set(st
static bool qca808x_led_hw_control_status(struct phy_device *phydev, u8 index)
{
u16 reg;
- int val;
if (index > 2)
return false;
reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-
- val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
-
- return !(val & QCA808X_LED_FORCE_EN);
+ return qca808x_led_reg_hw_control_status(phydev, reg);
}
static int qca808x_led_hw_control_get(struct phy_device *phydev, u8 index,
@@ -557,44 +551,20 @@ static int qca808x_led_brightness_set(st
}
reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-
- return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
- QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON :
- QCA808X_LED_FORCE_OFF));
+ return qca808x_led_reg_brightness_set(phydev, reg, value);
}
static int qca808x_led_blink_set(struct phy_device *phydev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off)
{
- int ret;
u16 reg;
if (index > 2)
return -EINVAL;
reg = QCA808X_MMD7_LED_FORCE_CTRL(index);
-
- /* Set blink to 50% off, 50% on at 4Hz by default */
- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
- QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
- QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
- if (ret)
- return ret;
-
- /* We use BLINK_1 for normal blinking */
- ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
- QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
- if (ret)
- return ret;
-
- /* We set blink to 4Hz, aka 250ms */
- *delay_on = 250 / 2;
- *delay_off = 250 / 2;
-
- return 0;
+ return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);
}
static int qca808x_led_polarity_set(struct phy_device *phydev, int index,
--- a/drivers/net/phy/qcom/qcom-phy-lib.c
+++ b/drivers/net/phy/qcom/qcom-phy-lib.c
@@ -620,3 +620,57 @@ int qca808x_cable_test_get_status(struct
return 0;
}
EXPORT_SYMBOL_GPL(qca808x_cable_test_get_status);
+
+int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg)
+{
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg,
+ QCA808X_LED_FORCE_EN);
+}
+EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_enable);
+
+bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg)
+{
+ int val;
+
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
+ return !(val & QCA808X_LED_FORCE_EN);
+}
+EXPORT_SYMBOL_GPL(qca808x_led_reg_hw_control_status);
+
+int qca808x_led_reg_brightness_set(struct phy_device *phydev,
+ u16 reg, enum led_brightness value)
+{
+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
+ QCA808X_LED_FORCE_EN | (value ? QCA808X_LED_FORCE_ON :
+ QCA808X_LED_FORCE_OFF));
+}
+EXPORT_SYMBOL_GPL(qca808x_led_reg_brightness_set);
+
+int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ int ret;
+
+ /* Set blink to 50% off, 50% on at 4Hz by default */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, QCA808X_MMD7_LED_GLOBAL,
+ QCA808X_LED_BLINK_FREQ_MASK | QCA808X_LED_BLINK_DUTY_MASK,
+ QCA808X_LED_BLINK_FREQ_4HZ | QCA808X_LED_BLINK_DUTY_50_50);
+ if (ret)
+ return ret;
+
+ /* We use BLINK_1 for normal blinking */
+ ret = phy_modify_mmd(phydev, MDIO_MMD_AN, reg,
+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_MODE_MASK,
+ QCA808X_LED_FORCE_EN | QCA808X_LED_FORCE_BLINK_1);
+ if (ret)
+ return ret;
+
+ /* We set blink to 4Hz, aka 250ms */
+ *delay_on = 250 / 2;
+ *delay_off = 250 / 2;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(qca808x_led_reg_blink_set);
--- a/drivers/net/phy/qcom/qcom.h
+++ b/drivers/net/phy/qcom/qcom.h
@@ -234,3 +234,10 @@ int at803x_cdt_start(struct phy_device *
int at803x_cdt_wait_for_completion(struct phy_device *phydev,
u32 cdt_en);
int qca808x_cable_test_get_status(struct phy_device *phydev, bool *finished);
+int qca808x_led_reg_hw_control_enable(struct phy_device *phydev, u16 reg);
+bool qca808x_led_reg_hw_control_status(struct phy_device *phydev, u16 reg);
+int qca808x_led_reg_brightness_set(struct phy_device *phydev,
+ u16 reg, enum led_brightness value);
+int qca808x_led_reg_blink_set(struct phy_device *phydev, u16 reg,
+ unsigned long *delay_on,
+ unsigned long *delay_off);

View File

@@ -0,0 +1,326 @@
From f508a226b517a6a8afd78a317de46bc83e3e3d51 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 6 Feb 2024 18:31:13 +0100
Subject: [PATCH 10/10] net: phy: qca807x: add support for configurable LED
QCA8072/5 have up to 2 LEDs attached for PHY.
LEDs can be configured to be ON/hw blink or be set to HW control.
Hw blink mode is set to blink at 4Hz or 250ms.
PHY can support both copper (TP) or fiber (FIBRE) kind and supports
different HW control modes based on the port type.
HW control modes supported for netdev trigger for copper ports are:
- LINK_10
- LINK_100
- LINK_1000
- TX
- RX
- FULL_DUPLEX
- HALF_DUPLEX
HW control modes supported for netdev trigger for fiber ports are:
- LINK_100
- LINK_1000
- TX
- RX
- FULL_DUPLEX
- HALF_DUPLEX
LED support conflicts with GPIO controller feature and must be disabled
if gpio-controller is used for the PHY.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---
drivers/net/phy/qcom/qca807x.c | 256 ++++++++++++++++++++++++++++++++-
1 file changed, 254 insertions(+), 2 deletions(-)
--- a/drivers/net/phy/qcom/qca807x.c
+++ b/drivers/net/phy/qcom/qca807x.c
@@ -57,8 +57,18 @@
#define QCA807X_MMD7_LED_CTRL(x) (0x8074 + ((x) * 2))
#define QCA807X_MMD7_LED_FORCE_CTRL(x) (0x8075 + ((x) * 2))
-#define QCA807X_GPIO_FORCE_EN BIT(15)
-#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
+/* LED hw control pattern for fiber port */
+#define QCA807X_LED_FIBER_PATTERN_MASK GENMASK(11, 1)
+#define QCA807X_LED_FIBER_TXACT_BLK_EN BIT(10)
+#define QCA807X_LED_FIBER_RXACT_BLK_EN BIT(9)
+#define QCA807X_LED_FIBER_FDX_ON_EN BIT(6)
+#define QCA807X_LED_FIBER_HDX_ON_EN BIT(5)
+#define QCA807X_LED_FIBER_1000BX_ON_EN BIT(2)
+#define QCA807X_LED_FIBER_100FX_ON_EN BIT(1)
+
+/* Some device repurpose the LED as GPIO out */
+#define QCA807X_GPIO_FORCE_EN QCA808X_LED_FORCE_EN
+#define QCA807X_GPIO_FORCE_MODE_MASK QCA808X_LED_FORCE_MODE_MASK
#define QCA807X_FUNCTION_CONTROL 0x10
#define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
@@ -121,6 +131,233 @@ static int qca807x_cable_test_start(stru
return 0;
}
+static int qca807x_led_parse_netdev(struct phy_device *phydev, unsigned long rules,
+ u16 *offload_trigger)
+{
+ /* Parsing specific to netdev trigger */
+ switch (phydev->port) {
+ case PORT_TP:
+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
+ *offload_trigger |= QCA808X_LED_TX_BLINK;
+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
+ *offload_trigger |= QCA808X_LED_RX_BLINK;
+ if (test_bit(TRIGGER_NETDEV_LINK_10, &rules))
+ *offload_trigger |= QCA808X_LED_SPEED10_ON;
+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ *offload_trigger |= QCA808X_LED_SPEED100_ON;
+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ *offload_trigger |= QCA808X_LED_SPEED1000_ON;
+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
+ *offload_trigger |= QCA808X_LED_HALF_DUPLEX_ON;
+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
+ *offload_trigger |= QCA808X_LED_FULL_DUPLEX_ON;
+ break;
+ case PORT_FIBRE:
+ if (test_bit(TRIGGER_NETDEV_TX, &rules))
+ *offload_trigger |= QCA807X_LED_FIBER_TXACT_BLK_EN;
+ if (test_bit(TRIGGER_NETDEV_RX, &rules))
+ *offload_trigger |= QCA807X_LED_FIBER_RXACT_BLK_EN;
+ if (test_bit(TRIGGER_NETDEV_LINK_100, &rules))
+ *offload_trigger |= QCA807X_LED_FIBER_100FX_ON_EN;
+ if (test_bit(TRIGGER_NETDEV_LINK_1000, &rules))
+ *offload_trigger |= QCA807X_LED_FIBER_1000BX_ON_EN;
+ if (test_bit(TRIGGER_NETDEV_HALF_DUPLEX, &rules))
+ *offload_trigger |= QCA807X_LED_FIBER_HDX_ON_EN;
+ if (test_bit(TRIGGER_NETDEV_FULL_DUPLEX, &rules))
+ *offload_trigger |= QCA807X_LED_FIBER_FDX_ON_EN;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (rules && !*offload_trigger)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static int qca807x_led_hw_control_enable(struct phy_device *phydev, u8 index)
+{
+ u16 reg;
+
+ if (index > 1)
+ return -EINVAL;
+
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ return qca808x_led_reg_hw_control_enable(phydev, reg);
+}
+
+static int qca807x_led_hw_is_supported(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ u16 offload_trigger = 0;
+
+ if (index > 1)
+ return -EINVAL;
+
+ return qca807x_led_parse_netdev(phydev, rules, &offload_trigger);
+}
+
+static int qca807x_led_hw_control_set(struct phy_device *phydev, u8 index,
+ unsigned long rules)
+{
+ u16 reg, mask, offload_trigger = 0;
+ int ret;
+
+ if (index > 1)
+ return -EINVAL;
+
+ ret = qca807x_led_parse_netdev(phydev, rules, &offload_trigger);
+ if (ret)
+ return ret;
+
+ ret = qca807x_led_hw_control_enable(phydev, index);
+ if (ret)
+ return ret;
+
+ switch (phydev->port) {
+ case PORT_TP:
+ reg = QCA807X_MMD7_LED_CTRL(index);
+ mask = QCA808X_LED_PATTERN_MASK;
+ break;
+ case PORT_FIBRE:
+ /* HW control pattern bits are in LED FORCE reg */
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ mask = QCA807X_LED_FIBER_PATTERN_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return phy_modify_mmd(phydev, MDIO_MMD_AN, reg, mask,
+ offload_trigger);
+}
+
+static bool qca807x_led_hw_control_status(struct phy_device *phydev, u8 index)
+{
+ u16 reg;
+
+ if (index > 1)
+ return false;
+
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ return qca808x_led_reg_hw_control_status(phydev, reg);
+}
+
+static int qca807x_led_hw_control_get(struct phy_device *phydev, u8 index,
+ unsigned long *rules)
+{
+ u16 reg;
+ int val;
+
+ if (index > 1)
+ return -EINVAL;
+
+ /* Check if we have hw control enabled */
+ if (qca807x_led_hw_control_status(phydev, index))
+ return -EINVAL;
+
+ /* Parsing specific to netdev trigger */
+ switch (phydev->port) {
+ case PORT_TP:
+ reg = QCA807X_MMD7_LED_CTRL(index);
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
+ if (val & QCA808X_LED_TX_BLINK)
+ set_bit(TRIGGER_NETDEV_TX, rules);
+ if (val & QCA808X_LED_RX_BLINK)
+ set_bit(TRIGGER_NETDEV_RX, rules);
+ if (val & QCA808X_LED_SPEED10_ON)
+ set_bit(TRIGGER_NETDEV_LINK_10, rules);
+ if (val & QCA808X_LED_SPEED100_ON)
+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
+ if (val & QCA808X_LED_SPEED1000_ON)
+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+ if (val & QCA808X_LED_HALF_DUPLEX_ON)
+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
+ if (val & QCA808X_LED_FULL_DUPLEX_ON)
+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
+ break;
+ case PORT_FIBRE:
+ /* HW control pattern bits are in LED FORCE reg */
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ val = phy_read_mmd(phydev, MDIO_MMD_AN, reg);
+ if (val & QCA807X_LED_FIBER_TXACT_BLK_EN)
+ set_bit(TRIGGER_NETDEV_TX, rules);
+ if (val & QCA807X_LED_FIBER_RXACT_BLK_EN)
+ set_bit(TRIGGER_NETDEV_RX, rules);
+ if (val & QCA807X_LED_FIBER_100FX_ON_EN)
+ set_bit(TRIGGER_NETDEV_LINK_100, rules);
+ if (val & QCA807X_LED_FIBER_1000BX_ON_EN)
+ set_bit(TRIGGER_NETDEV_LINK_1000, rules);
+ if (val & QCA807X_LED_FIBER_HDX_ON_EN)
+ set_bit(TRIGGER_NETDEV_HALF_DUPLEX, rules);
+ if (val & QCA807X_LED_FIBER_FDX_ON_EN)
+ set_bit(TRIGGER_NETDEV_FULL_DUPLEX, rules);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int qca807x_led_hw_control_reset(struct phy_device *phydev, u8 index)
+{
+ u16 reg, mask;
+
+ if (index > 1)
+ return -EINVAL;
+
+ switch (phydev->port) {
+ case PORT_TP:
+ reg = QCA807X_MMD7_LED_CTRL(index);
+ mask = QCA808X_LED_PATTERN_MASK;
+ break;
+ case PORT_FIBRE:
+ /* HW control pattern bits are in LED FORCE reg */
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ mask = QCA807X_LED_FIBER_PATTERN_MASK;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, reg, mask);
+}
+
+static int qca807x_led_brightness_set(struct phy_device *phydev,
+ u8 index, enum led_brightness value)
+{
+ u16 reg;
+ int ret;
+
+ if (index > 1)
+ return -EINVAL;
+
+ /* If we are setting off the LED reset any hw control rule */
+ if (!value) {
+ ret = qca807x_led_hw_control_reset(phydev, index);
+ if (ret)
+ return ret;
+ }
+
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ return qca808x_led_reg_brightness_set(phydev, reg, value);
+}
+
+static int qca807x_led_blink_set(struct phy_device *phydev, u8 index,
+ unsigned long *delay_on,
+ unsigned long *delay_off)
+{
+ u16 reg;
+
+ if (index > 1)
+ return -EINVAL;
+
+ reg = QCA807X_MMD7_LED_FORCE_CTRL(index);
+ return qca808x_led_reg_blink_set(phydev, reg, delay_on, delay_off);
+}
+
#ifdef CONFIG_GPIOLIB
static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
@@ -496,6 +733,16 @@ static int qca807x_probe(struct phy_devi
"qcom,dac-disable-bias-current-tweak");
if (IS_ENABLED(CONFIG_GPIOLIB)) {
+ /* Make sure we don't have mixed leds node and gpio-controller
+ * to prevent registering leds and having gpio-controller usage
+ * conflicting with them.
+ */
+ if (of_find_property(node, "leds", NULL) &&
+ of_find_property(node, "gpio-controller", NULL)) {
+ phydev_err(phydev, "Invalid property detected. LEDs and gpio-controller are mutually exclusive.");
+ return -EINVAL;
+ }
+
/* Do not register a GPIO controller unless flagged for it */
if (of_property_read_bool(node, "gpio-controller")) {
ret = qca807x_gpio(phydev);
@@ -580,6 +827,11 @@ static struct phy_driver qca807x_drivers
.suspend = genphy_suspend,
.cable_test_start = qca807x_cable_test_start,
.cable_test_get_status = qca808x_cable_test_get_status,
+ .led_brightness_set = qca807x_led_brightness_set,
+ .led_blink_set = qca807x_led_blink_set,
+ .led_hw_is_supported = qca807x_led_hw_is_supported,
+ .led_hw_control_set = qca807x_led_hw_control_set,
+ .led_hw_control_get = qca807x_led_hw_control_get,
},
};
module_phy_driver(qca807x_drivers);

View File

@@ -0,0 +1,92 @@
From 7edce370d87a23e8ed46af5b76a9fef1e341b67b Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Tue, 28 Nov 2023 14:59:28 +0100
Subject: [PATCH] net: phy: aquantia: drop wrong endianness conversion for addr
and CRC
On further testing on BE target with kernel test robot, it was notice
that the endianness conversion for addr and CRC in fw_load_memory was
wrong.
Drop the cpu_to_le32 conversion for addr load as it's not needed.
Use get_unaligned_le32 instead of get_unaligned for FW data word load to
correctly convert data in the correct order to follow system endian.
Also drop the cpu_to_be32 for CRC calculation as it's wrong and would
cause different CRC on BE system.
The loaded word is swapped internally and MAILBOX calculates the CRC on
the swapped word. To correctly calculate the CRC to be later matched
with the one from MAILBOX, use an u8 struct and swap the word there to
keep the same order on both LE and BE for crc_ccitt_false function.
Also add additional comments on how the CRC verification for the loaded
section works.
CRC is calculated as we load the section and verified with the MAILBOX
only after the entire section is loaded to skip additional slowdown by
loop the section data again.
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202311210414.sEJZjlcD-lkp@intel.com/
Fixes: e93984ebc1c8 ("net: phy: aquantia: add firmware load support")
Tested-by: Robert Marko <robimarko@gmail.com> # ipq8072 LE device
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Link: https://lore.kernel.org/r/20231128135928.9841-1-ansuelsmth@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
drivers/net/phy/aquantia/aquantia_firmware.c | 24 ++++++++++++--------
1 file changed, 14 insertions(+), 10 deletions(-)
--- a/drivers/net/phy/aquantia/aquantia_firmware.c
+++ b/drivers/net/phy/aquantia/aquantia_firmware.c
@@ -93,9 +93,6 @@ static int aqr_fw_load_memory(struct phy
u16 crc = 0, up_crc;
size_t pos;
- /* PHY expect addr in LE */
- addr = (__force u32)cpu_to_le32(addr);
-
phy_write_mmd(phydev, MDIO_MMD_VEND1,
VEND1_GLOBAL_MAILBOX_INTERFACE1,
VEND1_GLOBAL_MAILBOX_INTERFACE1_CRC_RESET);
@@ -110,10 +107,11 @@ static int aqr_fw_load_memory(struct phy
* If a firmware that is not word aligned is found, please report upstream.
*/
for (pos = 0; pos < len; pos += sizeof(u32)) {
+ u8 crc_data[4];
u32 word;
/* FW data is always stored in little-endian */
- word = get_unaligned((const u32 *)(data + pos));
+ word = get_unaligned_le32((const u32 *)(data + pos));
phy_write_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE5,
VEND1_GLOBAL_MAILBOX_INTERFACE5_MSW_DATA(word));
@@ -124,15 +122,21 @@ static int aqr_fw_load_memory(struct phy
VEND1_GLOBAL_MAILBOX_INTERFACE1_EXECUTE |
VEND1_GLOBAL_MAILBOX_INTERFACE1_WRITE);
- /* calculate CRC as we load data to the mailbox.
- * We convert word to big-endian as PHY is BE and mailbox will
- * return a BE CRC.
+ /* Word is swapped internally and MAILBOX CRC is calculated
+ * using big-endian order. Mimic what the PHY does to have a
+ * matching CRC...
*/
- word = (__force u32)cpu_to_be32(word);
- crc = crc_ccitt_false(crc, (u8 *)&word, sizeof(word));
- }
+ crc_data[0] = word >> 24;
+ crc_data[1] = word >> 16;
+ crc_data[2] = word >> 8;
+ crc_data[3] = word;
+ /* ...calculate CRC as we load data... */
+ crc = crc_ccitt_false(crc, crc_data, sizeof(crc_data));
+ }
+ /* ...gets CRC from MAILBOX after we have loaded the entire section... */
up_crc = phy_read_mmd(phydev, MDIO_MMD_VEND1, VEND1_GLOBAL_MAILBOX_INTERFACE2);
+ /* ...and make sure it does match our calculated CRC */
if (crc != up_crc) {
phydev_err(phydev, "CRC mismatch: calculated 0x%04x PHY 0x%04x\n",
crc, up_crc);

View File

@@ -56,7 +56,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
mutex_init(&dev->lock);
INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
@@ -2934,6 +2937,74 @@ static bool phy_drv_supports_irq(struct
@@ -3037,6 +3040,74 @@ static bool phy_drv_supports_irq(struct
return phydrv->config_intr && phydrv->handle_interrupt;
}
@@ -131,7 +131,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
/**
* fwnode_mdio_find_device - Given a fwnode, find the mdio_device
* @fwnode: pointer to the mdio_device's fwnode
@@ -3112,6 +3183,11 @@ static int phy_probe(struct device *dev)
@@ -3215,6 +3286,11 @@ static int phy_probe(struct device *dev)
/* Set the state to READY by default */
phydev->state = PHY_READY;
@@ -153,7 +153,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
#include <linux/linkmode.h>
#include <linux/netlink.h>
#include <linux/mdio.h>
@@ -603,6 +604,7 @@ struct macsec_ops;
@@ -606,6 +607,7 @@ struct macsec_ops;
* @phy_num_led_triggers: Number of triggers in @phy_led_triggers
* @led_link_trigger: LED trigger for link up/down
* @last_triggered: last LED trigger for link speed
@@ -161,7 +161,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
* @master_slave_set: User requested master/slave configuration
* @master_slave_get: Current master/slave advertisement
* @master_slave_state: Current master/slave configuration
@@ -695,6 +697,7 @@ struct phy_device {
@@ -698,6 +700,7 @@ struct phy_device {
struct phy_led_trigger *led_link_trigger;
#endif
@@ -169,7 +169,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
/*
* Interrupt number for this PHY
@@ -769,6 +772,19 @@ struct phy_tdr_config {
@@ -772,6 +775,19 @@ struct phy_tdr_config {
#define PHY_PAIR_ALL -1
/**

View File

@@ -20,7 +20,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2937,11 +2937,18 @@ static bool phy_drv_supports_irq(struct
@@ -3040,11 +3040,18 @@ static bool phy_drv_supports_irq(struct
return phydrv->config_intr && phydrv->handle_interrupt;
}
@@ -41,7 +41,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
}
static int of_phy_led(struct phy_device *phydev,
@@ -2958,12 +2965,14 @@ static int of_phy_led(struct phy_device
@@ -3061,12 +3068,14 @@ static int of_phy_led(struct phy_device
return -ENOMEM;
cdev = &phyled->led_cdev;
@@ -59,7 +59,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -775,15 +775,19 @@ struct phy_tdr_config {
@@ -778,15 +778,19 @@ struct phy_tdr_config {
* struct phy_led: An LED driven by the PHY
*
* @list: List of LEDs
@@ -79,7 +79,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
/**
* struct phy_driver - Driver structure for a particular PHY type
*
@@ -998,6 +1002,15 @@ struct phy_driver {
@@ -1001,6 +1005,15 @@ struct phy_driver {
int (*get_sqi)(struct phy_device *dev);
/** @get_sqi_max: Get the maximum signal quality indication */
int (*get_sqi_max)(struct phy_device *dev);

View File

@@ -18,7 +18,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2951,6 +2951,22 @@ static int phy_led_set_brightness(struct
@@ -3054,6 +3054,22 @@ static int phy_led_set_brightness(struct
return err;
}
@@ -41,7 +41,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static int of_phy_led(struct phy_device *phydev,
struct device_node *led)
{
@@ -2973,6 +2989,8 @@ static int of_phy_led(struct phy_device
@@ -3076,6 +3092,8 @@ static int of_phy_led(struct phy_device
if (phydev->drv->led_brightness_set)
cdev->brightness_set_blocking = phy_led_set_brightness;
@@ -52,7 +52,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1011,6 +1011,18 @@ struct phy_driver {
@@ -1014,6 +1014,18 @@ struct phy_driver {
*/
int (*led_brightness_set)(struct phy_device *dev,
u8 index, enum led_brightness value);

View File

@@ -53,7 +53,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs"
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3213,7 +3213,8 @@ static int phy_probe(struct device *dev)
@@ -3316,7 +3316,8 @@ static int phy_probe(struct device *dev)
/* Get the LEDs from the device tree, and instantiate standard
* LEDs for them.
*/

View File

@@ -18,7 +18,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2974,6 +2974,7 @@ static int of_phy_led(struct phy_device
@@ -3077,6 +3077,7 @@ static int of_phy_led(struct phy_device
struct led_init_data init_data = {};
struct led_classdev *cdev;
struct phy_led *phyled;
@@ -26,7 +26,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
int err;
phyled = devm_kzalloc(dev, sizeof(*phyled), GFP_KERNEL);
@@ -2983,10 +2984,13 @@ static int of_phy_led(struct phy_device
@@ -3086,10 +3087,13 @@ static int of_phy_led(struct phy_device
cdev = &phyled->led_cdev;
phyled->phydev = phydev;

View File

@@ -22,7 +22,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2967,6 +2967,15 @@ static int phy_led_blink_set(struct led_
@@ -3070,6 +3070,15 @@ static int phy_led_blink_set(struct led_
return err;
}
@@ -38,7 +38,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
static int of_phy_led(struct phy_device *phydev,
struct device_node *led)
{
@@ -3000,7 +3009,7 @@ static int of_phy_led(struct phy_device
@@ -3103,7 +3112,7 @@ static int of_phy_led(struct phy_device
init_data.fwnode = of_fwnode_handle(led);
init_data.devname_mandatory = true;
@@ -47,7 +47,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
if (err)
return err;
@@ -3029,6 +3038,7 @@ static int of_phy_leds(struct phy_device
@@ -3132,6 +3141,7 @@ static int of_phy_leds(struct phy_device
err = of_phy_led(phydev, led);
if (err) {
of_node_put(led);
@@ -55,7 +55,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
return err;
}
}
@@ -3234,6 +3244,9 @@ static int phy_remove(struct device *dev
@@ -3337,6 +3347,9 @@ static int phy_remove(struct device *dev
cancel_delayed_work_sync(&phydev->state_queue);

View File

@@ -23,7 +23,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -2967,6 +2967,61 @@ static int phy_led_blink_set(struct led_
@@ -3070,6 +3070,61 @@ static int phy_led_blink_set(struct led_
return err;
}
@@ -85,7 +85,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
static void phy_leds_unregister(struct phy_device *phydev)
{
struct phy_led *phyled;
@@ -3004,6 +3059,19 @@ static int of_phy_led(struct phy_device
@@ -3107,6 +3162,19 @@ static int of_phy_led(struct phy_device
cdev->brightness_set_blocking = phy_led_set_brightness;
if (phydev->drv->led_blink_set)
cdev->blink_set = phy_led_blink_set;
@@ -107,7 +107,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
init_data.fwnode = of_fwnode_handle(led);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -1023,6 +1023,39 @@ struct phy_driver {
@@ -1026,6 +1026,39 @@ struct phy_driver {
int (*led_blink_set)(struct phy_device *dev, u8 index,
unsigned long *delay_on,
unsigned long *delay_off);

View File

@@ -28,7 +28,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -3037,6 +3037,7 @@ static int of_phy_led(struct phy_device
@@ -3140,6 +3140,7 @@ static int of_phy_led(struct phy_device
struct device *dev = &phydev->mdio.dev;
struct led_init_data init_data = {};
struct led_classdev *cdev;
@@ -36,7 +36,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
struct phy_led *phyled;
u32 index;
int err;
@@ -3054,6 +3055,21 @@ static int of_phy_led(struct phy_device
@@ -3157,6 +3158,21 @@ static int of_phy_led(struct phy_device
if (index > U8_MAX)
return -EINVAL;
@@ -60,7 +60,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
cdev->brightness_set_blocking = phy_led_set_brightness;
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -788,6 +788,15 @@ struct phy_led {
@@ -791,6 +791,15 @@ struct phy_led {
#define to_phy_led(d) container_of(d, struct phy_led, led_cdev)
@@ -76,7 +76,7 @@ Signed-off-by: Jakub Kicinski <kuba@kernel.org>
/**
* struct phy_driver - Driver structure for a particular PHY type
*
@@ -1056,6 +1065,19 @@ struct phy_driver {
@@ -1059,6 +1068,19 @@ struct phy_driver {
int (*led_hw_control_get)(struct phy_device *dev, u8 index,
unsigned long *rules);

View File

@@ -1,6 +1,6 @@
From 9e2a0a8bd7a392b5af6bf2cfa0b07d96d1fb6719 Mon Sep 17 00:00:00 2001
From 12ce20e02e532f101b725d71c52a36c5cc8ad1e6 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Sun, 4 Feb 2024 00:32:04 +0100
Date: Sun, 4 Feb 2024 00:54:01 +0100
Subject: [PATCH] leds: trigger: netdev: Fix kernel panic on interface rename
trig notify
@@ -29,6 +29,9 @@ case) and correctly parse the new dev.
Fixes: d5e01266e7f5 ("leds: trigger: netdev: add additional specific link speed mode")
Cc: stable@vger.kernel.org
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://lore.kernel.org/r/20240203235413.1146-1-ansuelsmth@gmail.com
Signed-off-by: Lee Jones <lee@kernel.org>
---
drivers/leds/trigger/ledtrig-netdev.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

View File

@@ -5098,6 +5098,7 @@ CONFIG_PWRSEQ_SIMPLE=y
# CONFIG_QCA7000_SPI is not set
# CONFIG_QCA7000_UART is not set
# CONFIG_QCA83XX_PHY is not set
# CONFIG_QCA807X_PHY is not set
# CONFIG_QCA808X_PHY is not set
# CONFIG_QCOM_A7PLL is not set
# CONFIG_QCOM_BAM_DMUX is not set

View File

@@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -1756,6 +1756,9 @@ void phy_detach(struct phy_device *phyde
@@ -1852,6 +1852,9 @@ void phy_detach(struct phy_device *phyde
struct module *ndev_owner = NULL;
struct mii_bus *bus;
@@ -23,7 +23,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
sysfs_remove_link(&dev->dev.kobj, "phydev");
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -897,6 +897,12 @@ struct phy_driver {
@@ -900,6 +900,12 @@ struct phy_driver {
/** @handle_interrupt: Override default interrupt handling */
irqreturn_t (*handle_interrupt)(struct phy_device *phydev);

View File

@@ -1,844 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2020 Sartura Ltd.
*
* Author: Robert Marko <robert.marko@sartura.hr>
*
* Qualcomm QCA8072 and QCA8075 PHY driver
*/
#include <linux/version.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/bitfield.h>
#include <linux/ethtool_netlink.h>
#include <linux/gpio.h>
#include <linux/sfp.h>
#include <dt-bindings/net/qcom-qca807x.h>
#define PHY_ID_QCA8072 0x004dd0b2
#define PHY_ID_QCA8075 0x004dd0b1
#define PHY_ID_QCA807X_PSGMII 0x06820805
/* Downshift */
#define QCA807X_SMARTSPEED_EN BIT(5)
#define QCA807X_SMARTSPEED_RETRY_LIMIT_MASK GENMASK(4, 2)
#define QCA807X_SMARTSPEED_RETRY_LIMIT_DEFAULT 5
#define QCA807X_SMARTSPEED_RETRY_LIMIT_MIN 2
#define QCA807X_SMARTSPEED_RETRY_LIMIT_MAX 9
/* Cable diagnostic test (CDT) */
#define QCA807X_CDT 0x16
#define QCA807X_CDT_ENABLE BIT(15)
#define QCA807X_CDT_ENABLE_INTER_PAIR_SHORT BIT(13)
#define QCA807X_CDT_STATUS BIT(11)
#define QCA807X_CDT_MMD3_STATUS 0x8064
#define QCA807X_CDT_MDI0_STATUS_MASK GENMASK(15, 12)
#define QCA807X_CDT_MDI1_STATUS_MASK GENMASK(11, 8)
#define QCA807X_CDT_MDI2_STATUS_MASK GENMASK(7, 4)
#define QCA807X_CDT_MDI3_STATUS_MASK GENMASK(3, 0)
#define QCA807X_CDT_RESULTS_INVALID 0x0
#define QCA807X_CDT_RESULTS_OK 0x1
#define QCA807X_CDT_RESULTS_OPEN 0x2
#define QCA807X_CDT_RESULTS_SAME_SHORT 0x3
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK 0x4
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK 0x8
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK 0xc
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN 0x6
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN 0xa
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN 0xe
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT 0x7
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT 0xb
#define QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT 0xf
#define QCA807X_CDT_RESULTS_BUSY 0x9
#define QCA807X_CDT_MMD3_MDI0_LENGTH 0x8065
#define QCA807X_CDT_MMD3_MDI1_LENGTH 0x8066
#define QCA807X_CDT_MMD3_MDI2_LENGTH 0x8067
#define QCA807X_CDT_MMD3_MDI3_LENGTH 0x8068
#define QCA807X_CDT_SAME_SHORT_LENGTH_MASK GENMASK(15, 8)
#define QCA807X_CDT_CROSS_SHORT_LENGTH_MASK GENMASK(7, 0)
#define QCA807X_CHIP_CONFIGURATION 0x1f
#define QCA807X_BT_BX_REG_SEL BIT(15)
#define QCA807X_BT_BX_REG_SEL_FIBER 0
#define QCA807X_BT_BX_REG_SEL_COPPER 1
#define QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK GENMASK(3, 0)
#define QCA807X_CHIP_CONFIGURATION_MODE_QSGMII_SGMII 4
#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER 3
#define QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_ALL_COPPER 0
#define QCA807X_MEDIA_SELECT_STATUS 0x1a
#define QCA807X_MEDIA_DETECTED_COPPER BIT(5)
#define QCA807X_MEDIA_DETECTED_1000_BASE_X BIT(4)
#define QCA807X_MEDIA_DETECTED_100_BASE_FX BIT(3)
#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION 0x807e
#define QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN BIT(0)
#define QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH 0x801a
#define QCA807X_CONTROL_DAC_MASK GENMASK(2, 0)
#define QCA807X_MMD7_LED_100N_1 0x8074
#define QCA807X_MMD7_LED_100N_2 0x8075
#define QCA807X_MMD7_LED_1000N_1 0x8076
#define QCA807X_MMD7_LED_1000N_2 0x8077
#define QCA807X_LED_TXACT_BLK_EN_2 BIT(10)
#define QCA807X_LED_RXACT_BLK_EN_2 BIT(9)
#define QCA807X_LED_GT_ON_EN_2 BIT(6)
#define QCA807X_LED_HT_ON_EN_2 BIT(5)
#define QCA807X_LED_BT_ON_EN_2 BIT(4)
#define QCA807X_GPIO_FORCE_EN BIT(15)
#define QCA807X_GPIO_FORCE_MODE_MASK GENMASK(14, 13)
#define QCA807X_INTR_ENABLE 0x12
#define QCA807X_INTR_STATUS 0x13
#define QCA807X_INTR_ENABLE_AUTONEG_ERR BIT(15)
#define QCA807X_INTR_ENABLE_SPEED_CHANGED BIT(14)
#define QCA807X_INTR_ENABLE_DUPLEX_CHANGED BIT(13)
#define QCA807X_INTR_ENABLE_LINK_FAIL BIT(11)
#define QCA807X_INTR_ENABLE_LINK_SUCCESS BIT(10)
#define QCA807X_FUNCTION_CONTROL 0x10
#define QCA807X_FC_MDI_CROSSOVER_MODE_MASK GENMASK(6, 5)
#define QCA807X_FC_MDI_CROSSOVER_AUTO 3
#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX 1
#define QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI 0
#define QCA807X_PHY_SPECIFIC_STATUS 0x11
#define QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED BIT(11)
#define QCA807X_SS_SPEED_MASK GENMASK(15, 14)
#define QCA807X_SS_SPEED_1000 2
#define QCA807X_SS_SPEED_100 1
#define QCA807X_SS_SPEED_10 0
#define QCA807X_SS_DUPLEX BIT(13)
#define QCA807X_SS_MDIX BIT(6)
/* PSGMII PHY specific */
#define PSGMII_QSGMII_DRIVE_CONTROL_1 0xb
#define PSGMII_QSGMII_TX_DRIVER_MASK GENMASK(7, 4)
#define PSGMII_MODE_CTRL 0x6d
#define PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK BIT(0)
#define PSGMII_MMD3_SERDES_CONTROL 0x805a
struct qca807x_gpio_priv {
struct phy_device *phy;
};
static int qca807x_get_downshift(struct phy_device *phydev, u8 *data)
{
int val, cnt, enable;
val = phy_read(phydev, MII_NWAYTEST);
if (val < 0)
return val;
enable = FIELD_GET(QCA807X_SMARTSPEED_EN, val);
cnt = FIELD_GET(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, val) + 2;
*data = enable ? cnt : DOWNSHIFT_DEV_DISABLE;
return 0;
}
static int qca807x_set_downshift(struct phy_device *phydev, u8 cnt)
{
int ret, val;
if (cnt > QCA807X_SMARTSPEED_RETRY_LIMIT_MAX ||
(cnt < QCA807X_SMARTSPEED_RETRY_LIMIT_MIN && cnt != DOWNSHIFT_DEV_DISABLE))
return -EINVAL;
if (!cnt) {
ret = phy_clear_bits(phydev, MII_NWAYTEST, QCA807X_SMARTSPEED_EN);
} else {
val = QCA807X_SMARTSPEED_EN;
val |= FIELD_PREP(QCA807X_SMARTSPEED_RETRY_LIMIT_MASK, cnt - 2);
phy_modify(phydev, MII_NWAYTEST,
QCA807X_SMARTSPEED_EN |
QCA807X_SMARTSPEED_RETRY_LIMIT_MASK,
val);
}
ret = genphy_soft_reset(phydev);
return ret;
}
static int qca807x_get_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return qca807x_get_downshift(phydev, data);
default:
return -EOPNOTSUPP;
}
}
static int qca807x_set_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, const void *data)
{
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
return qca807x_set_downshift(phydev, *(const u8 *)data);
default:
return -EOPNOTSUPP;
}
}
static bool qca807x_distance_valid(int result)
{
switch (result) {
case QCA807X_CDT_RESULTS_OPEN:
case QCA807X_CDT_RESULTS_SAME_SHORT:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
return true;
}
return false;
}
static int qca807x_report_length(struct phy_device *phydev,
int pair, int result)
{
int length;
int ret;
ret = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA807X_CDT_MMD3_MDI0_LENGTH + pair);
if (ret < 0)
return ret;
switch (result) {
case ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT:
length = (FIELD_GET(QCA807X_CDT_SAME_SHORT_LENGTH_MASK, ret) * 800) / 10;
break;
case ETHTOOL_A_CABLE_RESULT_CODE_OPEN:
case ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT:
length = (FIELD_GET(QCA807X_CDT_CROSS_SHORT_LENGTH_MASK, ret) * 800) / 10;
break;
}
ethnl_cable_test_fault_length(phydev, pair, length);
return 0;
}
static int qca807x_cable_test_report_trans(int result)
{
switch (result) {
case QCA807X_CDT_RESULTS_OK:
return ETHTOOL_A_CABLE_RESULT_CODE_OK;
case QCA807X_CDT_RESULTS_OPEN:
return ETHTOOL_A_CABLE_RESULT_CODE_OPEN;
case QCA807X_CDT_RESULTS_SAME_SHORT:
return ETHTOOL_A_CABLE_RESULT_CODE_SAME_SHORT;
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OK:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OK:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OK:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_OPEN:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_OPEN:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_OPEN:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI1_SAME_SHORT:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI2_SAME_SHORT:
case QCA807X_CDT_RESULTS_CROSS_SHORT_WITH_MDI3_SAME_SHORT:
return ETHTOOL_A_CABLE_RESULT_CODE_CROSS_SHORT;
default:
return ETHTOOL_A_CABLE_RESULT_CODE_UNSPEC;
}
}
static int qca807x_cable_test_report(struct phy_device *phydev)
{
int pair0, pair1, pair2, pair3;
int ret;
ret = phy_read_mmd(phydev, MDIO_MMD_PCS, QCA807X_CDT_MMD3_STATUS);
if (ret < 0)
return ret;
pair0 = FIELD_GET(QCA807X_CDT_MDI0_STATUS_MASK, ret);
pair1 = FIELD_GET(QCA807X_CDT_MDI1_STATUS_MASK, ret);
pair2 = FIELD_GET(QCA807X_CDT_MDI2_STATUS_MASK, ret);
pair3 = FIELD_GET(QCA807X_CDT_MDI3_STATUS_MASK, ret);
ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_A,
qca807x_cable_test_report_trans(pair0));
ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_B,
qca807x_cable_test_report_trans(pair1));
ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_C,
qca807x_cable_test_report_trans(pair2));
ethnl_cable_test_result(phydev, ETHTOOL_A_CABLE_PAIR_D,
qca807x_cable_test_report_trans(pair3));
if (qca807x_distance_valid(pair0))
qca807x_report_length(phydev, 0, qca807x_cable_test_report_trans(pair0));
if (qca807x_distance_valid(pair1))
qca807x_report_length(phydev, 1, qca807x_cable_test_report_trans(pair1));
if (qca807x_distance_valid(pair2))
qca807x_report_length(phydev, 2, qca807x_cable_test_report_trans(pair2));
if (qca807x_distance_valid(pair3))
qca807x_report_length(phydev, 3, qca807x_cable_test_report_trans(pair3));
return 0;
}
static int qca807x_cable_test_get_status(struct phy_device *phydev,
bool *finished)
{
int val;
*finished = false;
val = phy_read(phydev, QCA807X_CDT);
if (!((val & QCA807X_CDT_ENABLE) && (val & QCA807X_CDT_STATUS))) {
*finished = true;
return qca807x_cable_test_report(phydev);
}
return 0;
}
static int qca807x_cable_test_start(struct phy_device *phydev)
{
int val, ret;
val = phy_read(phydev, QCA807X_CDT);
/* Enable inter-pair short check as well */
val &= ~QCA807X_CDT_ENABLE_INTER_PAIR_SHORT;
val |= QCA807X_CDT_ENABLE;
ret = phy_write(phydev, QCA807X_CDT, val);
return ret;
}
#ifdef CONFIG_GPIOLIB
static int qca807x_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
return GPIO_LINE_DIRECTION_OUT;
}
static int qca807x_gpio_get_reg(unsigned int offset)
{
return QCA807X_MMD7_LED_100N_2 + (offset % 2) * 2;
}
static int qca807x_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
int val;
val = phy_read_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset));
return FIELD_GET(QCA807X_GPIO_FORCE_MODE_MASK, val);
}
static void qca807x_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
struct qca807x_gpio_priv *priv = gpiochip_get_data(gc);
int val;
val = phy_read_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset));
val &= ~QCA807X_GPIO_FORCE_MODE_MASK;
val |= QCA807X_GPIO_FORCE_EN;
val |= FIELD_PREP(QCA807X_GPIO_FORCE_MODE_MASK, value);
phy_write_mmd(priv->phy, MDIO_MMD_AN, qca807x_gpio_get_reg(offset), val);
}
static int qca807x_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int value)
{
qca807x_gpio_set(gc, offset, value);
return 0;
}
static int qca807x_gpio(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
struct qca807x_gpio_priv *priv;
struct gpio_chip *gc;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->phy = phydev;
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
gc->label = dev_name(dev);
gc->base = -1;
gc->ngpio = 2;
gc->parent = dev;
gc->owner = THIS_MODULE;
gc->can_sleep = true;
gc->get_direction = qca807x_gpio_get_direction;
gc->direction_output = qca807x_gpio_dir_out;
gc->get = qca807x_gpio_get;
gc->set = qca807x_gpio_set;
return devm_gpiochip_add_data(dev, gc, priv);
}
#endif
static int qca807x_read_copper_status(struct phy_device *phydev)
{
int ss, err, old_link = phydev->link;
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
if (err)
return err;
/* why bother the PHY if nothing can have changed */
if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
return 0;
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
err = genphy_read_lpa(phydev);
if (err < 0)
return err;
/* Read the QCA807x PHY-Specific Status register copper page,
* which indicates the speed and duplex that the PHY is actually
* using, irrespective of whether we are in autoneg mode or not.
*/
ss = phy_read(phydev, QCA807X_PHY_SPECIFIC_STATUS);
if (ss < 0)
return ss;
if (ss & QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED) {
int sfc;
sfc = phy_read(phydev, QCA807X_FUNCTION_CONTROL);
if (sfc < 0)
return sfc;
switch (FIELD_GET(QCA807X_SS_SPEED_MASK, ss)) {
case QCA807X_SS_SPEED_10:
phydev->speed = SPEED_10;
break;
case QCA807X_SS_SPEED_100:
phydev->speed = SPEED_100;
break;
case QCA807X_SS_SPEED_1000:
phydev->speed = SPEED_1000;
break;
}
if (ss & QCA807X_SS_DUPLEX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
if (ss & QCA807X_SS_MDIX)
phydev->mdix = ETH_TP_MDI_X;
else
phydev->mdix = ETH_TP_MDI;
switch (FIELD_GET(QCA807X_FC_MDI_CROSSOVER_MODE_MASK, sfc)) {
case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDI:
phydev->mdix_ctrl = ETH_TP_MDI;
break;
case QCA807X_FC_MDI_CROSSOVER_MANUAL_MDIX:
phydev->mdix_ctrl = ETH_TP_MDI_X;
break;
case QCA807X_FC_MDI_CROSSOVER_AUTO:
phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
break;
}
}
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete)
phy_resolve_aneg_pause(phydev);
return 0;
}
static int qca807x_read_fiber_status(struct phy_device *phydev)
{
int ss, err, lpa, old_link = phydev->link;
/* Update the link, but return if there was an error */
err = genphy_update_link(phydev);
if (err)
return err;
/* why bother the PHY if nothing can have changed */
if (phydev->autoneg == AUTONEG_ENABLE && old_link && phydev->link)
return 0;
phydev->speed = SPEED_UNKNOWN;
phydev->duplex = DUPLEX_UNKNOWN;
phydev->pause = 0;
phydev->asym_pause = 0;
if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
lpa = phy_read(phydev, MII_LPA);
if (lpa < 0)
return lpa;
linkmode_mod_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
phydev->lp_advertising, lpa & LPA_LPACK);
linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
phydev->lp_advertising, lpa & LPA_1000XFULL);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT,
phydev->lp_advertising, lpa & LPA_1000XPAUSE);
linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
phydev->lp_advertising,
lpa & LPA_1000XPAUSE_ASYM);
phy_resolve_aneg_linkmode(phydev);
}
/* Read the QCA807x PHY-Specific Status register fiber page,
* which indicates the speed and duplex that the PHY is actually
* using, irrespective of whether we are in autoneg mode or not.
*/
ss = phy_read(phydev, QCA807X_PHY_SPECIFIC_STATUS);
if (ss < 0)
return ss;
if (ss & QCA807X_SS_SPEED_AND_DUPLEX_RESOLVED) {
switch (FIELD_GET(QCA807X_SS_SPEED_MASK, ss)) {
case QCA807X_SS_SPEED_100:
phydev->speed = SPEED_100;
break;
case QCA807X_SS_SPEED_1000:
phydev->speed = SPEED_1000;
break;
}
if (ss & QCA807X_SS_DUPLEX)
phydev->duplex = DUPLEX_FULL;
else
phydev->duplex = DUPLEX_HALF;
}
return 0;
}
static int qca807x_read_status(struct phy_device *phydev)
{
if (linkmode_test_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported)) {
switch (phydev->port) {
case PORT_FIBRE:
return qca807x_read_fiber_status(phydev);
case PORT_TP:
return qca807x_read_copper_status(phydev);
default:
return -EINVAL;
}
} else
return qca807x_read_copper_status(phydev);
}
static int qca807x_config_intr(struct phy_device *phydev)
{
int ret, val;
val = phy_read(phydev, QCA807X_INTR_ENABLE);
if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
/* Check for combo port as it has fewer interrupts */
if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
val |= QCA807X_INTR_ENABLE_SPEED_CHANGED;
val |= QCA807X_INTR_ENABLE_LINK_FAIL;
val |= QCA807X_INTR_ENABLE_LINK_SUCCESS;
} else {
val |= QCA807X_INTR_ENABLE_AUTONEG_ERR;
val |= QCA807X_INTR_ENABLE_SPEED_CHANGED;
val |= QCA807X_INTR_ENABLE_DUPLEX_CHANGED;
val |= QCA807X_INTR_ENABLE_LINK_FAIL;
val |= QCA807X_INTR_ENABLE_LINK_SUCCESS;
}
ret = phy_write(phydev, QCA807X_INTR_ENABLE, val);
} else {
ret = phy_write(phydev, QCA807X_INTR_ENABLE, 0);
}
return ret;
}
static irqreturn_t qca807x_handle_interrupt(struct phy_device *phydev)
{
int irq_status, int_enabled;
irq_status = phy_read(phydev, QCA807X_INTR_STATUS);
if (irq_status < 0) {
phy_error(phydev);
return IRQ_NONE;
}
/* Read the current enabled interrupts */
int_enabled = phy_read(phydev, QCA807X_INTR_ENABLE);
if (int_enabled < 0) {
phy_error(phydev);
return IRQ_NONE;
}
/* See if this was one of our enabled interrupts */
if (!(irq_status & int_enabled))
return IRQ_NONE;
phy_trigger_machine(phydev);
return IRQ_HANDLED;
}
static int qca807x_led_config(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
bool led_config = false;
int val;
val = phy_read_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_LED_1000N_1);
if (val < 0)
return val;
if (of_property_read_bool(node, "qcom,single-led-1000")) {
val |= QCA807X_LED_TXACT_BLK_EN_2;
val |= QCA807X_LED_RXACT_BLK_EN_2;
val |= QCA807X_LED_GT_ON_EN_2;
led_config = true;
}
if (of_property_read_bool(node, "qcom,single-led-100")) {
val |= QCA807X_LED_HT_ON_EN_2;
led_config = true;
}
if (of_property_read_bool(node, "qcom,single-led-10")) {
val |= QCA807X_LED_BT_ON_EN_2;
led_config = true;
}
if (led_config)
return phy_write_mmd(phydev, MDIO_MMD_AN, QCA807X_MMD7_LED_1000N_1, val);
else
return 0;
}
static int qca807x_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
{
struct phy_device *phydev = upstream;
__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
phy_interface_t iface;
int ret;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,1,0)
DECLARE_PHY_INTERFACE_MASK(interfaces);
sfp_parse_support(phydev->sfp_bus, id, support, interfaces);
#else
sfp_parse_support(phydev->sfp_bus, id, support);
#endif
iface = sfp_select_interface(phydev->sfp_bus, support);
dev_info(&phydev->mdio.dev, "%s SFP module inserted\n", phy_modes(iface));
switch (iface) {
case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_100BASEX:
/* Set PHY mode to PSGMII combo (1/4 copper + combo ports) mode */
ret = phy_modify(phydev,
QCA807X_CHIP_CONFIGURATION,
QCA807X_CHIP_CONFIGURATION_MODE_CFG_MASK,
QCA807X_CHIP_CONFIGURATION_MODE_PSGMII_FIBER);
/* Enable fiber mode autodection (1000Base-X or 100Base-FX) */
ret = phy_set_bits_mmd(phydev,
MDIO_MMD_AN,
QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION,
QCA807X_MMD7_FIBER_MODE_AUTO_DETECTION_EN);
/* Select fiber page */
ret = phy_clear_bits(phydev,
QCA807X_CHIP_CONFIGURATION,
QCA807X_BT_BX_REG_SEL);
phydev->port = PORT_FIBRE;
break;
default:
dev_err(&phydev->mdio.dev, "Incompatible SFP module inserted\n");
return -EINVAL;
}
return ret;
}
static void qca807x_sfp_remove(void *upstream)
{
struct phy_device *phydev = upstream;
/* Select copper page */
phy_set_bits(phydev,
QCA807X_CHIP_CONFIGURATION,
QCA807X_BT_BX_REG_SEL);
phydev->port = PORT_TP;
}
static const struct sfp_upstream_ops qca807x_sfp_ops = {
.attach = phy_sfp_attach,
.detach = phy_sfp_detach,
.module_insert = qca807x_sfp_insert,
.module_remove = qca807x_sfp_remove,
};
static int qca807x_config(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
int control_dac, ret = 0;
u32 of_control_dac;
/* Check for Combo port */
if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
int psgmii_serdes;
/* Prevent PSGMII going into hibernation via PSGMII self test */
psgmii_serdes = phy_read_mmd(phydev, MDIO_MMD_PCS, PSGMII_MMD3_SERDES_CONTROL);
psgmii_serdes &= ~BIT(1);
ret = phy_write_mmd(phydev, MDIO_MMD_PCS,
PSGMII_MMD3_SERDES_CONTROL,
psgmii_serdes);
}
if (!of_property_read_u32(node, "qcom,control-dac", &of_control_dac)) {
control_dac = phy_read_mmd(phydev, MDIO_MMD_AN,
QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH);
control_dac &= ~QCA807X_CONTROL_DAC_MASK;
control_dac |= FIELD_PREP(QCA807X_CONTROL_DAC_MASK, of_control_dac);
ret = phy_write_mmd(phydev, MDIO_MMD_AN,
QCA807X_MMD7_1000BASE_T_POWER_SAVE_PER_CABLE_LENGTH,
control_dac);
}
/* Optionally configure LED-s */
if (IS_ENABLED(CONFIG_GPIOLIB)) {
/* Check whether PHY-s pins are used as GPIO-s */
if (!of_property_read_bool(node, "gpio-controller"))
ret = qca807x_led_config(phydev);
} else {
ret = qca807x_led_config(phydev);
}
return ret;
}
static int qca807x_probe(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
int ret = 0;
if (IS_ENABLED(CONFIG_GPIOLIB)) {
/* Do not register a GPIO controller unless flagged for it */
if (of_property_read_bool(node, "gpio-controller"))
ret = qca807x_gpio(phydev);
}
/* Attach SFP bus on combo port*/
if (phy_read(phydev, QCA807X_CHIP_CONFIGURATION)) {
ret = phy_sfp_probe(phydev, &qca807x_sfp_ops);
linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->supported);
linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, phydev->advertising);
}
return ret;
}
static int qca807x_psgmii_config(struct phy_device *phydev)
{
struct device_node *node = phydev->mdio.dev.of_node;
int tx_amp, ret = 0;
u32 tx_driver_strength;
/* Workaround to enable AZ transmitting ability */
ret = phy_clear_bits_mmd(phydev,
MDIO_MMD_PMAPMD,
PSGMII_MODE_CTRL,
PSGMII_MODE_CTRL_AZ_WORKAROUND_MASK);
/* PSGMII/QSGMII TX amp set to DT defined value instead of default 600mV */
if (!of_property_read_u32(node, "qcom,tx-driver-strength", &tx_driver_strength)) {
tx_amp = phy_read(phydev, PSGMII_QSGMII_DRIVE_CONTROL_1);
tx_amp &= ~PSGMII_QSGMII_TX_DRIVER_MASK;
tx_amp |= FIELD_PREP(PSGMII_QSGMII_TX_DRIVER_MASK, tx_driver_strength);
ret = phy_write(phydev, PSGMII_QSGMII_DRIVE_CONTROL_1, tx_amp);
}
return ret;
}
static struct phy_driver qca807x_drivers[] = {
{
PHY_ID_MATCH_EXACT(PHY_ID_QCA8072),
.name = "Qualcomm QCA8072",
.flags = PHY_POLL_CABLE_TEST,
/* PHY_GBIT_FEATURES */
.probe = qca807x_probe,
.config_init = qca807x_config,
.read_status = qca807x_read_status,
.config_intr = qca807x_config_intr,
.handle_interrupt = qca807x_handle_interrupt,
.soft_reset = genphy_soft_reset,
.get_tunable = qca807x_get_tunable,
.set_tunable = qca807x_set_tunable,
.resume = genphy_resume,
.suspend = genphy_suspend,
.cable_test_start = qca807x_cable_test_start,
.cable_test_get_status = qca807x_cable_test_get_status,
},
{
PHY_ID_MATCH_EXACT(PHY_ID_QCA8075),
.name = "Qualcomm QCA8075",
.flags = PHY_POLL_CABLE_TEST,
/* PHY_GBIT_FEATURES */
.probe = qca807x_probe,
.config_init = qca807x_config,
.read_status = qca807x_read_status,
.config_intr = qca807x_config_intr,
.handle_interrupt = qca807x_handle_interrupt,
.soft_reset = genphy_soft_reset,
.get_tunable = qca807x_get_tunable,
.set_tunable = qca807x_set_tunable,
.resume = genphy_resume,
.suspend = genphy_suspend,
.cable_test_start = qca807x_cable_test_start,
.cable_test_get_status = qca807x_cable_test_get_status,
},
{
PHY_ID_MATCH_EXACT(PHY_ID_QCA807X_PSGMII),
.name = "Qualcomm QCA807x PSGMII",
.probe = qca807x_psgmii_config,
},
};
module_phy_driver(qca807x_drivers);
static struct mdio_device_id __maybe_unused qca807x_tbl[] = {
{ PHY_ID_MATCH_EXACT(PHY_ID_QCA8072) },
{ PHY_ID_MATCH_EXACT(PHY_ID_QCA8075) },
{ PHY_ID_MATCH_MODEL(PHY_ID_QCA807X_PSGMII) },
{ }
};
MODULE_AUTHOR("Robert Marko");
MODULE_DESCRIPTION("Qualcomm QCA807x PHY driver");
MODULE_DEVICE_TABLE(mdio, qca807x_tbl);
MODULE_LICENSE("GPL");

View File

@@ -1,61 +0,0 @@
From 96eb388c082bd0086b128d82def9daaab1617951 Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Thu, 1 Oct 2020 15:05:35 +0200
Subject: [PATCH] dt-bindings: net: add QCA807x PHY
Add DT bindings for Qualcomm QCA807x PHY series.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
include/dt-bindings/net/qcom-qca807x.h | 45 ++++++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 include/dt-bindings/net/qcom-qca807x.h
--- /dev/null
+++ b/include/dt-bindings/net/qcom-qca807x.h
@@ -0,0 +1,45 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Device Tree constants for the Qualcomm QCA807X PHYs
+ */
+
+#ifndef _DT_BINDINGS_QCOM_QCA807X_H
+#define _DT_BINDINGS_QCOM_QCA807X_H
+
+#define PSGMII_QSGMII_TX_DRIVER_140MV 0
+#define PSGMII_QSGMII_TX_DRIVER_160MV 1
+#define PSGMII_QSGMII_TX_DRIVER_180MV 2
+#define PSGMII_QSGMII_TX_DRIVER_200MV 3
+#define PSGMII_QSGMII_TX_DRIVER_220MV 4
+#define PSGMII_QSGMII_TX_DRIVER_240MV 5
+#define PSGMII_QSGMII_TX_DRIVER_260MV 6
+#define PSGMII_QSGMII_TX_DRIVER_280MV 7
+#define PSGMII_QSGMII_TX_DRIVER_300MV 8
+#define PSGMII_QSGMII_TX_DRIVER_320MV 9
+#define PSGMII_QSGMII_TX_DRIVER_400MV 10
+#define PSGMII_QSGMII_TX_DRIVER_500MV 11
+/* Default value */
+#define PSGMII_QSGMII_TX_DRIVER_600MV 12
+
+/* Full amplitude, full bias current */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_BIAS 0
+/* Amplitude follow DSP (amplitude is adjusted based on cable length), half bias current */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_HALF_BIAS 1
+/* Full amplitude, bias current follow DSP (bias current is adjusted based on cable length) */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_DSP_BIAS 2
+/* Both amplitude and bias current follow DSP */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_BIAS 3
+/* Full amplitude, half bias current */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_HALF_BIAS 4
+/* Amplitude follow DSP setting; 1/4 bias current when cable<10m,
+ * otherwise half bias current
+ */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS 5
+/* Full amplitude; same bias current setting with “010” and “011”,
+ * but half more bias is reduced when cable <10m
+ */
+#define QCA807X_CONTROL_DAC_FULL_VOLT_HALF_BIAS_SHORT 6
+/* Amplitude follow DSP; same bias current setting with “110”, default value */
+#define QCA807X_CONTROL_DAC_DSP_VOLT_HALF_BIAS_SHORT 7
+
+#endif

View File

@@ -0,0 +1,67 @@
From 5ac078c8fe18f3e8318547b8ed0ed782730c5039 Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Sat, 10 Feb 2024 22:28:27 +0100
Subject: [PATCH] ARM: dts: qcom: ipq4019: add QCA8075 PHY Package nodes
Add QCA8075 PHY Package nodes. The PHY nodes that were previously
defined never worked and actually never had a driver to correctly setup
these PHY. Now that we have a correct driver, correctly add the PHY
Package node and set the default value of 300mw for tx driver strength
following specification of ipq4019 SoC.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
---
arch/arm/boot/dts//qcom-ipq4019.dtsi | 35 +++++++++++++++---------
1 file changed, 22 insertions(+), 13 deletions(-)
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -725,24 +725,33 @@
reg = <0x90000 0x64>;
status = "disabled";
- ethphy0: ethernet-phy@0 {
+ ethernet-phy-package@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "qcom,qca8075-package";
reg = <0>;
- };
-
- ethphy1: ethernet-phy@1 {
- reg = <1>;
- };
- ethphy2: ethernet-phy@2 {
- reg = <2>;
- };
-
- ethphy3: ethernet-phy@3 {
- reg = <3>;
- };
+ qcom,tx-drive-strength-milliwatt = <300>;
- ethphy4: ethernet-phy@4 {
- reg = <4>;
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+
+ ethphy2: ethernet-phy@2 {
+ reg = <2>;
+ };
+
+ ethphy3: ethernet-phy@3 {
+ reg = <3>;
+ };
+
+ ethphy4: ethernet-phy@4 {
+ reg = <4>;
+ };
};
};

View File

@@ -1,49 +0,0 @@
From 876bb5b69c1e083be526c0ea261982d5eb78556f Mon Sep 17 00:00:00 2001
From: Robert Marko <robert.marko@sartura.hr>
Date: Fri, 9 Sep 2022 23:44:42 +0200
Subject: [PATCH] net: phy: Add Qualcom QCA807x driver
This adds driver for the Qualcomm QCA8072 and QCA8075 PHY-s.
They are 2 or 5 port IEEE 802.3 clause 22 compliant 10BASE-Te, 100BASE-TX and 1000BASE-T PHY-s.
They feature 2 SerDes, one for PSGMII or QSGMII connection with MAC, while second one is SGMII for connection to MAC or fiber.
Both models have a combo port that supports 1000BASE-X and 100BASE-FX fiber.
Each PHY inside of QCA807x series has 4 digitally controlled output only pins that natively drive LED-s.
But some vendors used these to driver generic LED-s controlled by userspace,
so lets enable registering each PHY as GPIO controller and add driver for it.
These are commonly used in Qualcomm IPQ40xx, IPQ60xx and IPQ807x boards.
Signed-off-by: Robert Marko <robert.marko@sartura.hr>
---
drivers/net/phy/Kconfig | 7 +++++++
drivers/net/phy/Makefile | 1 +
2 files changed, 8 insertions(+)
--- a/drivers/net/phy/qcom/Kconfig
+++ b/drivers/net/phy/qcom/Kconfig
@@ -15,6 +15,13 @@ config QCA83XX_PHY
help
Currently supports the internal QCA8337(Internal qca8k PHY) model
+config QCA807X_PHY
+ tristate "Qualcomm QCA807x PHYs"
+ depends on OF_MDIO
+ help
+ Currently supports the Qualcomm QCA8072, QCA8075 and the PSGMII
+ control PHY.
+
config QCA808X_PHY
tristate "Qualcomm QCA808x PHYs"
select QCOM_NET_PHYLIB
--- a/drivers/net/phy/qcom/Makefile
+++ b/drivers/net/phy/qcom/Makefile
@@ -2,4 +2,5 @@
obj-$(CONFIG_QCOM_NET_PHYLIB) += qcom-phy-lib.o
obj-$(CONFIG_AT803X_PHY) += at803x.o
obj-$(CONFIG_QCA83XX_PHY) += qca83xx.o
+obj-$(CONFIG_QCA807X_PHY) += qca807x.o
obj-$(CONFIG_QCA808X_PHY) += qca808x.o

View File

@@ -12,50 +12,14 @@ Signed-off-by: Robert Marko <robert.marko@sartura.hr>
--- a/arch/arm/boot/dts/qcom-ipq4019.dtsi
+++ b/arch/arm/boot/dts/qcom-ipq4019.dtsi
@@ -8,6 +8,7 @@
#include <dt-bindings/clock/qcom,gcc-ipq4019.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/net/qcom-qca807x.h>
/ {
#address-cells = <1>;
@@ -727,22 +728,38 @@
ethphy0: ethernet-phy@0 {
reg = <0>;
@@ -752,6 +752,10 @@
ethphy4: ethernet-phy@4 {
reg = <4>;
};
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy1: ethernet-phy@1 {
reg = <1>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy2: ethernet-phy@2 {
reg = <2>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy3: ethernet-phy@3 {
reg = <3>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
};
ethphy4: ethernet-phy@4 {
reg = <4>;
+
+ qcom,control-dac = <QCA807X_CONTROL_DAC_DSP_VOLT_QUARTER_BIAS>;
+ };
+
+ psgmiiphy: psgmii-phy@5 {
+ reg = <5>;
+
+ qcom,tx-driver-strength = <PSGMII_QSGMII_TX_DRIVER_300MV>;
+ psgmiiphy: psgmii-phy@5 {
+ reg = <5>;
+ };
};
};

View File

@@ -9,7 +9,8 @@ set_preinit_iface() {
ip link set eth1 up
ifname=eth1
;;
ubnt,unifi-6-lr)
ubnt,unifi-6-lr|\
zyxel,nwa50ax-pro)
ip link set eth0 up
ifname=eth0
;;

View File

@@ -6,7 +6,7 @@ BOARDNAME:=Qualcomm Atheros 802.11ax WiSoC-s
FEATURES:=squashfs ramdisk fpu nand rtc emmc
KERNELNAME:=Image dtbs
CPU_TYPE:=cortex-a53
SUBTARGETS:=ipq807x
SUBTARGETS:=ipq807x ipq60xx
KERNEL_PATCHVER:=6.1

View File

@@ -355,6 +355,7 @@ CONFIG_POWER_SUPPLY=y
CONFIG_PREEMPT_NONE_BUILD=y
CONFIG_PRINTK_TIME=y
CONFIG_PTP_1588_CLOCK_OPTIONAL=y
CONFIG_QCA807X_PHY=y
CONFIG_QCA808X_PHY=y
# CONFIG_QCM_DISPCC_2290 is not set
# CONFIG_QCM_GCC_2290 is not set

View File

@@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "ipq6018-cpr-regulator.dtsi"
&CPU0 {
cpu-supply = <&apc_vreg>;
};
&CPU1 {
cpu-supply = <&apc_vreg>;
};
&CPU2 {
cpu-supply = <&apc_vreg>;
};
&CPU3 {
cpu-supply = <&apc_vreg>;
};

View File

@@ -0,0 +1,124 @@
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
&soc {
apc_apm: apm@b111000 {
compatible = "qcom,ipq807x-apm";
reg = <0x0 0xb111000 0x0 0x1000>;
reg-names = "pm-apcc-glb";
qcom,apm-post-halt-delay = <0x2>;
qcom,apm-halt-clk-delay = <0x11>;
qcom,apm-resume-clk-delay = <0x10>;
qcom,apm-sel-switch-delay = <0x01>;
};
apc_cpr: cpr4-ctrl@b018000 {
compatible = "qcom,cpr4-ipq6018-apss-regulator";
reg = <0x0 0xb018000 0x0 0x4000>, <0x0 0xa4000 0x0 0x1000>, <0x0 0x0193d008 0x0 0x4>;
reg-names = "cpr_ctrl", "fuse_base", "cpr_tcsr_reg";
interrupts = <GIC_SPI 15 IRQ_TYPE_EDGE_RISING>;
interrupt-names = "cpr";
qcom,cpr-ctrl-name = "apc";
qcom,cpr-sensor-time = <1000>;
qcom,cpr-loop-time = <5000000>;
qcom,cpr-idle-cycles = <15>;
qcom,cpr-step-quot-init-min = <0>;
qcom,cpr-step-quot-init-max = <15>;
qcom,cpr-count-mode = <0>; /* All-at-once */
qcom,cpr-count-repeat = <1>;
qcom,cpr-down-error-step-limit = <1>;
qcom,cpr-up-error-step-limit = <1>;
qcom,apm-ctrl = <&apc_apm>;
qcom,apm-threshold-voltage = <850000>;
vdd-supply = <&ipq6018_s2>;
qcom,voltage-step = <12500>;
thread@0 {
qcom,cpr-thread-id = <0>;
qcom,cpr-consecutive-up = <2>;
qcom,cpr-consecutive-down = <2>;
qcom,cpr-up-threshold = <2>;
qcom,cpr-down-threshold = <2>;
apc_vreg: regulator {
regulator-name = "apc_corner";
regulator-min-microvolt = <1>;
regulator-max-microvolt = <6>;
qcom,cpr-fuse-corners = <4>;
qcom,cpr-fuse-combos = <8>;
qcom,cpr-corners = <6>;
qcom,cpr-speed-bins = <1>;
qcom,cpr-speed-bin-corners = <6>;
qcom,cpr-corner-fmax-map = <1 3 5 6>;
qcom,allow-voltage-interpolation;
qcom,allow-quotient-interpolation;
qcom,cpr-voltage-ceiling =
<725000 787500 862500
925000 987500 1062500>;
qcom,cpr-voltage-floor =
<587500 650000 712500
750000 787500 850000>;
qcom,corner-frequencies =
<864000000 1056000000 1320000000
1440000000 1608000000 1800000000>;
qcom,cpr-ro-sel =
/* Speed bin 0; CPR rev 0..7 */
< 0 0 0 0>,
< 7 7 7 7>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>;
qcom,cpr-open-loop-voltage-fuse-adjustment =
/* Speed bin 0; CPR rev 0..7 */
/* SVS Nominal Turbo Turbo_L1 */
< 0 0 0 0>,
< 0 0 15000 0>,
< 0 0 15000 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>;
qcom,cpr-closed-loop-voltage-fuse-adjustment =
/* Speed bin 0; CPR rev 0..7 */
< 0 0 0 0>,
< 13000 0 13000 13000>,
< 13000 0 13000 13000>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>,
< 0 0 0 0>;
qcom,cpr-ro-scaling-factor =
< 2000 1770 1900 1670 1930 1770 1910 1800
1870 1730 2000 1840 1800 2030 1700 1890 >,
< 2000 1770 1900 1670 1930 1770 1910 1800
1870 1730 2000 1840 1800 2030 1700 1890 >,
< 2000 1770 1900 1670 1930 1770 1910 1800
1870 1730 2000 1840 1800 2030 1700 1890 >,
< 2000 1770 1900 1670 1930 1770 1910 1800
1870 1730 2000 1840 1800 2030 1700 1890 >;
regulator-always-on;
};
};
};
};

View File

@@ -0,0 +1,507 @@
#include <dt-bindings/net/qcom-ipq-ess.h>
&soc {
bias_pll_cc_clk: bias-pll-cc-clk {
compatible = "fixed-clock";
clock-frequency = <300000000>;
clock-output-names = "bias_pll_cc_clk";
#clock-cells = <0>;
};
bias_pll_nss_noc_clk: bias-pll-nss-noc-clk {
compatible = "fixed-clock";
clock-frequency = <416500000>;
clock-output-names = "bias_pll_nss_noc_clk";
#clock-cells = <0>;
};
edma: edma@3ab00000 {
compatible = "qcom,edma";
reg = <0x0 0x3ab00000 0x0 0xabe00>;
reg-names = "edma-reg-base";
qcom,txdesc-ring-start = <23>;
qcom,txdesc-rings = <1>;
qcom,txcmpl-ring-start = <23>;
qcom,txcmpl-rings = <1>;
qcom,rxfill-ring-start = <7>;
qcom,rxfill-rings = <1>;
qcom,rxdesc-ring-start = <15>;
qcom,rxdesc-rings = <1>;
interrupts = <GIC_SPI 378 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 354 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>;
resets = <&gcc GCC_EDMA_HW_RESET>;
reset-names = "edma_rst";
status = "disabled";
};
ess_instance: ess-instance {
#address-cells = <1>;
#size-cells = <1>;
num_devices = <1>;
switch: ess-switch@3a000000 {
compatible = "qcom,ess-switch-ipq60xx";
reg = <0x3a000000 0x1000000>;
switch_access_mode = "local bus";
clocks = <&gcc GCC_CMN_12GPLL_AHB_CLK>,
<&gcc GCC_CMN_12GPLL_SYS_CLK>,
<&gcc GCC_UNIPHY0_AHB_CLK>,
<&gcc GCC_UNIPHY0_SYS_CLK>,
<&gcc GCC_UNIPHY1_AHB_CLK>,
<&gcc GCC_UNIPHY1_SYS_CLK>,
<&gcc GCC_PORT1_MAC_CLK>,
<&gcc GCC_PORT2_MAC_CLK>,
<&gcc GCC_PORT3_MAC_CLK>,
<&gcc GCC_PORT4_MAC_CLK>,
<&gcc GCC_PORT5_MAC_CLK>,
<&gcc GCC_NSS_PPE_CLK>,
<&gcc GCC_NSS_PPE_CFG_CLK>,
<&gcc GCC_NSSNOC_PPE_CLK>,
<&gcc GCC_NSSNOC_PPE_CFG_CLK>,
<&gcc GCC_NSS_EDMA_CLK>,
<&gcc GCC_NSS_EDMA_CFG_CLK>,
<&gcc GCC_NSS_PPE_IPE_CLK>,
<&gcc GCC_MDIO_AHB_CLK>,
<&gcc GCC_NSS_NOC_CLK>,
<&gcc GCC_NSSNOC_SNOC_CLK>,
<&gcc GCC_NSS_CRYPTO_CLK>,
<&gcc GCC_NSS_PTP_REF_CLK>,
<&gcc GCC_NSS_PORT1_RX_CLK>,
<&gcc GCC_NSS_PORT1_TX_CLK>,
<&gcc GCC_NSS_PORT2_RX_CLK>,
<&gcc GCC_NSS_PORT2_TX_CLK>,
<&gcc GCC_NSS_PORT3_RX_CLK>,
<&gcc GCC_NSS_PORT3_TX_CLK>,
<&gcc GCC_NSS_PORT4_RX_CLK>,
<&gcc GCC_NSS_PORT4_TX_CLK>,
<&gcc GCC_NSS_PORT5_RX_CLK>,
<&gcc GCC_NSS_PORT5_TX_CLK>,
<&gcc GCC_UNIPHY0_PORT1_RX_CLK>,
<&gcc GCC_UNIPHY0_PORT1_TX_CLK>,
<&gcc GCC_UNIPHY0_PORT2_RX_CLK>,
<&gcc GCC_UNIPHY0_PORT2_TX_CLK>,
<&gcc GCC_UNIPHY0_PORT3_RX_CLK>,
<&gcc GCC_UNIPHY0_PORT3_TX_CLK>,
<&gcc GCC_UNIPHY0_PORT4_RX_CLK>,
<&gcc GCC_UNIPHY0_PORT4_TX_CLK>,
<&gcc GCC_UNIPHY0_PORT5_RX_CLK>,
<&gcc GCC_UNIPHY0_PORT5_TX_CLK>,
<&gcc GCC_UNIPHY1_PORT5_RX_CLK>,
<&gcc GCC_UNIPHY1_PORT5_TX_CLK>,
<&gcc NSS_PORT5_RX_CLK_SRC>,
<&gcc NSS_PORT5_TX_CLK_SRC>,
<&gcc GCC_SNOC_NSSNOC_CLK>;
clock-names = "cmn_ahb_clk", "cmn_sys_clk",
"uniphy0_ahb_clk", "uniphy0_sys_clk",
"uniphy1_ahb_clk", "uniphy1_sys_clk",
"port1_mac_clk", "port2_mac_clk",
"port3_mac_clk", "port4_mac_clk",
"port5_mac_clk",
"nss_ppe_clk", "nss_ppe_cfg_clk",
"nssnoc_ppe_clk", "nssnoc_ppe_cfg_clk",
"nss_edma_clk", "nss_edma_cfg_clk",
"nss_ppe_ipe_clk",
"gcc_mdio_ahb_clk", "gcc_nss_noc_clk",
"gcc_nssnoc_snoc_clk",
"gcc_nss_crypto_clk",
"gcc_nss_ptp_ref_clk",
"nss_port1_rx_clk", "nss_port1_tx_clk",
"nss_port2_rx_clk", "nss_port2_tx_clk",
"nss_port3_rx_clk", "nss_port3_tx_clk",
"nss_port4_rx_clk", "nss_port4_tx_clk",
"nss_port5_rx_clk", "nss_port5_tx_clk",
"uniphy0_port1_rx_clk",
"uniphy0_port1_tx_clk",
"uniphy0_port2_rx_clk",
"uniphy0_port2_tx_clk",
"uniphy0_port3_rx_clk",
"uniphy0_port3_tx_clk",
"uniphy0_port4_rx_clk",
"uniphy0_port4_tx_clk",
"uniphy0_port5_rx_clk",
"uniphy0_port5_tx_clk",
"uniphy1_port5_rx_clk",
"uniphy1_port5_tx_clk",
"nss_port5_rx_clk_src",
"nss_port5_tx_clk_src",
"gcc_snoc_nssnoc_clk";
resets = <&gcc GCC_PPE_FULL_RESET>,
<&gcc GCC_UNIPHY0_SOFT_RESET>,
<&gcc GCC_UNIPHY0_XPCS_RESET>,
<&gcc GCC_UNIPHY1_SOFT_RESET>,
<&gcc GCC_UNIPHY1_XPCS_RESET>,
<&gcc GCC_NSSPORT1_RESET>,
<&gcc GCC_NSSPORT2_RESET>,
<&gcc GCC_NSSPORT3_RESET>,
<&gcc GCC_NSSPORT4_RESET>,
<&gcc GCC_NSSPORT5_RESET>,
<&gcc GCC_UNIPHY0_PORT1_ARES>,
<&gcc GCC_UNIPHY0_PORT2_ARES>,
<&gcc GCC_UNIPHY0_PORT3_ARES>,
<&gcc GCC_UNIPHY0_PORT4_ARES>,
<&gcc GCC_UNIPHY0_PORT5_ARES>,
<&gcc GCC_UNIPHY0_PORT_4_5_RESET>,
<&gcc GCC_UNIPHY0_PORT_4_RESET>;
reset-names = "ppe_rst", "uniphy0_soft_rst",
"uniphy0_xpcs_rst", "uniphy1_soft_rst",
"uniphy1_xpcs_rst", "nss_port1_rst",
"nss_port2_rst", "nss_port3_rst",
"nss_port4_rst", "nss_port5_rst",
"uniphy0_port1_dis",
"uniphy0_port2_dis",
"uniphy0_port3_dis",
"uniphy0_port4_dis",
"uniphy0_port5_dis",
"uniphy0_port_4_5_rst",
"uniphy0_port_4_rst";
mdio-bus = <&mdio>;
switch_cpu_bmp = <ESS_PORT0>; /* cpu port bitmap */
switch_inner_bmp = <(ESS_PORT6 | ESS_PORT7)>; /*inner port bitmap*/
switch_mac_mode = <MAC_MODE_DISABLED>; /* MAC mode for UNIPHY instance 0 */
switch_mac_mode1 = <MAC_MODE_DISABLED>; /* MAC mode for UNIPHY instance 1 */
switch_mac_mode2 = <MAC_MODE_DISABLED>; /* MAC mode for UNIPHY instance 2 */
status = "disabled";
bm_tick_mode = <0>; /* bm tick mode */
tm_tick_mode = <0>; /* tm tick mode */
port_scheduler_resource {
port@0 {
port_id = <0>;
ucast_queue = <0 143>;
mcast_queue = <256 271>;
l0sp = <0 35>;
l0cdrr = <0 47>;
l0edrr = <0 47>;
l1cdrr = <0 7>;
l1edrr = <0 7>;
};
port@1 {
port_id = <1>;
ucast_queue = <144 159>;
mcast_queue = <272 275>;
l0sp = <36 39>;
l0cdrr = <48 63>;
l0edrr = <48 63>;
l1cdrr = <8 11>;
l1edrr = <8 11>;
};
port@2 {
port_id = <2>;
ucast_queue = <160 175>;
mcast_queue = <276 279>;
l0sp = <40 43>;
l0cdrr = <64 79>;
l0edrr = <64 79>;
l1cdrr = <12 15>;
l1edrr = <12 15>;
};
port@3 {
port_id = <3>;
ucast_queue = <176 191>;
mcast_queue = <280 283>;
l0sp = <44 47>;
l0cdrr = <80 95>;
l0edrr = <80 95>;
l1cdrr = <16 19>;
l1edrr = <16 19>;
};
port@4 {
port_id = <4>;
ucast_queue = <192 207>;
mcast_queue = <284 287>;
l0sp = <48 51>;
l0cdrr = <96 111>;
l0edrr = <96 111>;
l1cdrr = <20 23>;
l1edrr = <20 23>;
};
port@5 {
port_id = <5>;
ucast_queue = <208 223>;
mcast_queue = <288 291>;
l0sp = <52 55>;
l0cdrr = <112 127>;
l0edrr = <112 127>;
l1cdrr = <24 27>;
l1edrr = <24 27>;
};
port@6 {
port_id = <6>;
ucast_queue = <224 239>;
mcast_queue = <292 295>;
l0sp = <56 59>;
l0cdrr = <128 143>;
l0edrr = <128 143>;
l1cdrr = <28 31>;
l1edrr = <28 31>;
};
port@7 {
port_id = <7>;
ucast_queue = <240 255>;
mcast_queue = <296 299>;
l0sp = <60 63>;
l0cdrr = <144 159>;
l0edrr = <144 159>;
l1cdrr = <32 35>;
l1edrr = <32 35>;
};
};
port_scheduler_config {
port@0 {
port_id = <0>;
l1scheduler {
group@0 {
sp = <0 1>; /*L0 SPs*/
/*cpri cdrr epri edrr*/
cfg = <0 0 0 0>;
};
};
l0scheduler {
group@0 {
/*unicast queues*/
ucast_queue = <0 4 8>;
/*multicast queues*/
mcast_queue = <256 260>;
/*sp cpricdrrepriedrr*/
cfg = <0 0 0 0 0>;
};
group@1 {
ucast_queue = <1 5 9>;
mcast_queue = <257 261>;
cfg = <0 1 1 1 1>;
};
group@2 {
ucast_queue = <2 6 10>;
mcast_queue = <258 262>;
cfg = <0 2 2 2 2>;
};
group@3 {
ucast_queue = <3 7 11>;
mcast_queue = <259 263>;
cfg = <0 3 3 3 3>;
};
};
};
port@1 {
port_id = <1>;
l1scheduler {
group@0 {
sp = <36>;
cfg = <0 8 0 8>;
};
group@1 {
sp = <37>;
cfg = <1 9 1 9>;
};
};
l0scheduler {
group@0 {
ucast_queue = <144>;
ucast_loop_pri = <16>;
mcast_queue = <272>;
mcast_loop_pri = <4>;
cfg = <36 0 48 0 48>;
};
};
};
port@2 {
port_id = <2>;
l1scheduler {
group@0 {
sp = <40>;
cfg = <0 12 0 12>;
};
group@1 {
sp = <41>;
cfg = <1 13 1 13>;
};
};
l0scheduler {
group@0 {
ucast_queue = <160>;
ucast_loop_pri = <16>;
mcast_queue = <276>;
mcast_loop_pri = <4>;
cfg = <40 0 64 0 64>;
};
};
};
port@3 {
port_id = <3>;
l1scheduler {
group@0 {
sp = <44>;
cfg = <0 16 0 16>;
};
group@1 {
sp = <45>;
cfg = <1 17 1 17>;
};
};
l0scheduler {
group@0 {
ucast_queue = <176>;
ucast_loop_pri = <16>;
mcast_queue = <280>;
mcast_loop_pri = <4>;
cfg = <44 0 80 0 80>;
};
};
};
port@4 {
port_id = <4>;
l1scheduler {
group@0 {
sp = <48>;
cfg = <0 20 0 20>;
};
group@1 {
sp = <49>;
cfg = <1 21 1 21>;
};
};
l0scheduler {
group@0 {
ucast_queue = <192>;
ucast_loop_pri = <16>;
mcast_queue = <284>;
mcast_loop_pri = <4>;
cfg = <48 0 96 0 96>;
};
};
};
port@5 {
port_id = <5>;
l1scheduler {
group@0 {
sp = <52>;
cfg = <0 24 0 24>;
};
group@1 {
sp = <53>;
cfg = <1 25 1 25>;
};
};
l0scheduler {
group@0 {
ucast_queue = <208>;
ucast_loop_pri = <16>;
mcast_queue = <288>;
mcast_loop_pri = <4>;
cfg = <52 0 112 0 112>;
};
};
};
port@6 {
port_id = <6>;
l1scheduler {
group@0 {
sp = <56>;
cfg = <0 28 0 28>;
};
group@1 {
sp = <57>;
cfg = <1 29 1 29>;
};
};
l0scheduler {
group@0 {
ucast_queue = <224>;
ucast_loop_pri = <16>;
mcast_queue = <292>;
mcast_loop_pri = <4>;
cfg = <56 0 128 0 128>;
};
};
};
port@7 {
port_id = <7>;
l1scheduler {
group@0 {
sp = <60>;
cfg = <0 32 0 32>;
};
group@1 {
sp = <61>;
cfg = <1 33 1 33>;
};
};
l0scheduler {
group@0 {
ucast_queue = <240>;
ucast_loop_pri = <16>;
mcast_queue = <296>;
cfg = <60 0 144 0 144>;
};
};
};
};
};
ess-uniphy@7a00000 {
compatible = "qcom,ess-uniphy";
reg = <0x7a00000 0x30000>;
uniphy_access_mode = "local bus";
};
};
dp1: dp1 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <1>;
reg = <0x0 0x3a001000 0x0 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
status = "disabled";
};
dp2: dp2 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <2>;
reg = <0x0 0x3a001200 0x0 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
status = "disabled";
};
dp3: dp3 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <3>;
reg = <0x0 0x3a001400 0x0 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
status = "disabled";
};
dp4: dp4 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <4>;
reg = <0x0 0x3a001600 0x0 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
status = "disabled";
};
dp5: dp5 {
device_type = "network";
compatible = "qcom,nss-dp";
qcom,id = <5>;
reg = <0x0 0x3a001800 0x0 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
status = "disabled";
};
};

View File

@@ -262,9 +262,16 @@
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
qca8075_4: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
};
};
};
@@ -288,7 +295,7 @@
&dp5 {
status = "okay";
phy-handle = <&qca8075>;
phy-handle = <&qca8075_4>;
label = "lan";
};

View File

@@ -4,6 +4,7 @@
/dts-v1/;
#include "ipq8071-ax3600.dtsi"
#include <dt-bindings/leds/common.h>
/ {
model = "Xiaomi AX3600";
@@ -71,3 +72,59 @@
&wifi {
qcom,ath11k-calibration-variant = "Xiaomi-AX3600";
};
&qca8075_1 {
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_WAN;
default-state = "keep";
};
};
};
&qca8075_2 {
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};
&qca8075_3 {
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};
&qca8075_4 {
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};

View File

@@ -213,24 +213,31 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_4: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
qca8075_4: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
};
};
};

View File

@@ -366,24 +366,33 @@
nvmem-cells = <&aqr1_fw>;
};
qca8075_16: ethernet-phy@16 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@16 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <16>;
};
qca8075_17: ethernet-phy@17 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <17>;
};
qcom,package-mode = "qsgmii";
qca8075_18: ethernet-phy@18 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <18>;
};
qca8075_16: ethernet-phy@16 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <16>;
};
qca8075_19: ethernet-phy@19 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <19>;
qca8075_17: ethernet-phy@17 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <17>;
};
qca8075_18: ethernet-phy@18 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <18>;
};
qca8075_19: ethernet-phy@19 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <19>;
};
};
};
@@ -448,24 +457,28 @@
&dp1 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_16>;
label = "lan4";
};
&dp2 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_17>;
label = "lan3";
};
&dp3 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_18>;
label = "lan2";
};
&dp4 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_19>;
label = "lan1";
};

View File

@@ -347,24 +347,81 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qcom,package-mode = "qsgmii";
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
leds {
#address-cells = <1>;
#size-cells = <0>;
led@0 {
reg = <0>;
color = <LED_COLOR_ID_GREEN>;
function = LED_FUNCTION_LAN;
default-state = "keep";
};
};
};
};
qca8081: ethernet-phy@24 {
@@ -426,6 +483,7 @@
&dp1 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_0>;
label = "lan4";
nvmem-cells = <&macaddr_dp1>;
@@ -434,6 +492,7 @@
&dp2 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_1>;
label = "lan3";
nvmem-cells = <&macaddr_dp2>;
@@ -442,6 +501,7 @@
&dp3 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_2>;
label = "lan2";
nvmem-cells = <&macaddr_dp3>;
@@ -450,6 +510,7 @@
&dp4 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_3>;
label = "lan1";
nvmem-cells = <&macaddr_dp4>;

View File

@@ -137,24 +137,33 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qcom,package-mode = "qsgmii";
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
};
qca8081: ethernet-phy@28 {
@@ -223,24 +232,28 @@
&dp1 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_0>;
label = "lan4";
};
&dp2 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_1>;
label = "lan3";
};
&dp3 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_2>;
label = "lan2";
};
&dp4 {
status = "okay";
phy-mode = "qsgmii";
phy-handle = <&qca8075_3>;
label = "lan1";
};

View File

@@ -161,24 +161,31 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 22 GPIO_ACTIVE_LOW>;
qca8075_1: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
};
qca8075_2: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
qca8075_3: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_4: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
};
aqr113c: ethernet-phy@5 {
@@ -236,25 +243,25 @@
/* Dummy LAN port */
&dp1 {
status = "disabled";
phy-handle = <&qca8075_1>;
phy-handle = <&qca8075_0>;
label = "lan4";
};
&dp2 {
status = "okay";
phy-handle = <&qca8075_2>;
phy-handle = <&qca8075_1>;
label = "lan3";
};
&dp3 {
status = "okay";
phy-handle = <&qca8075_3>;
phy-handle = <&qca8075_2>;
label = "lan2";
};
&dp4 {
status = "okay";
phy-handle = <&qca8075_4>;
phy-handle = <&qca8075_3>;
label = "lan1";
};

View File

@@ -357,19 +357,26 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
};
qca8081: ethernet-phy@28 {

View File

@@ -476,7 +476,7 @@
reg = <0x3a001000 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
phy-mode = "psgmii";
status = "disabled";
};
@@ -487,7 +487,7 @@
reg = <0x3a001200 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
phy-mode = "psgmii";
status = "disabled";
};
@@ -498,7 +498,7 @@
reg = <0x3a001400 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
phy-mode = "psgmii";
status = "disabled";
};
@@ -509,7 +509,7 @@
reg = <0x3a001600 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
phy-mode = "psgmii";
status = "disabled";
};
@@ -520,7 +520,7 @@
reg = <0x3a001800 0x200>;
qcom,mactype = <0>;
local-mac-address = [000000000000];
phy-mode = "sgmii";
phy-mode = "psgmii";
status = "disabled";
};

View File

@@ -271,27 +271,34 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075_1: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
};
qca8075_2: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_3: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_4: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
qca8081: ethernet-phy@4{
qca8081: ethernet-phy@28 {
compatible = "ethernet-phy-id004d.d101";
reg = <28>;
reset-deassert-us = <10000>;
@@ -358,7 +365,7 @@
&dp1 {
status = "okay";
phy-handle = <&qca8075_1>;
phy-handle = <&qca8075_0>;
label = "lan1";
nvmem-cells = <&macaddr_lan 0>;
nvmem-cell-names = "mac-address";
@@ -366,7 +373,7 @@
&dp2 {
status = "okay";
phy-handle = <&qca8075_2>;
phy-handle = <&qca8075_1>;
label = "lan2";
nvmem-cells = <&macaddr_lan 0>;
nvmem-cell-names = "mac-address";
@@ -374,7 +381,7 @@
&dp3 {
status = "okay";
phy-handle = <&qca8075_3>;
phy-handle = <&qca8075_2>;
label = "lan3";
nvmem-cells = <&macaddr_lan 0>;
nvmem-cell-names = "mac-address";
@@ -382,7 +389,7 @@
&dp4 {
status = "okay";
phy-handle = <&qca8075_4>;
phy-handle = <&qca8075_3>;
label = "lan4";
nvmem-cells = <&macaddr_lan 0>;
nvmem-cell-names = "mac-address";

View File

@@ -150,29 +150,37 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
reg = <0>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
compatible = "qcom,qca8075-package";
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
qca8075_1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
qca8075_4: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
qca8075_2: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <2>;
};
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
qca8075_4: ethernet-phy@4 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <4>;
};
};
aqr111b0: ethernet-phy@7 {

View File

@@ -194,9 +194,16 @@
pinctrl-names = "default";
reset-gpios = <&tlmm 37 GPIO_ACTIVE_LOW>;
qca8075: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
ethernet-phy-package@0 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0>;
qca8075_3: ethernet-phy@3 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <3>;
};
};
qca8081: ethernet-phy@28 {
@@ -209,7 +216,7 @@
&dp4 {
status = "okay";
phy-handle = <&qca8075>;
phy-handle = <&qca8075_3>;
label = "lan2";
};

View File

@@ -230,48 +230,41 @@
reg = <0x8>;
};
qca8075_1: ethernet-phy@18 {
compatible = "ethernet-phy-ieee802.3-c22";
ethernet-phy-package@17 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "qcom,qca8075-package";
reg = <0x18>;
};
qca8075_2: ethernet-phy@19 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x19>;
};
qcom,package-mode = "qsgmii";
qca8075_3: ethernet-phy@1a {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x1a>;
};
qca8075_1: ethernet-phy@19 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x19>;
};
qca8075_4: ethernet-phy@1b {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x1b>;
};
qca8075_2: ethernet-phy@1a {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x1a>;
};
qca8075_5: ethernet-phy@1c {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x1c>;
qca8075_3: ethernet-phy@1b {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0x1b>;
};
};
};
&switch {
status = "okay";
switch_lan_bmp = <(ESS_PORT1 | ESS_PORT2 | ESS_PORT3 | ESS_PORT4 | ESS_PORT5)>;
switch_wan_bmp = <ESS_PORT6>;
malibu_first_phy_addr = <0x18>;
switch_lan_bmp = <(ESS_PORT2 | ESS_PORT3 | ESS_PORT4 | ESS_PORT6)>;
switch_wan_bmp = <ESS_PORT5>;
switch_mac_mode = <MAC_MODE_QSGMII>;
switch_mac_mode1 = <MAC_MODE_USXGMII>;
switch_mac_mode2 = <MAC_MODE_USXGMII>;
qcom,port_phyinfo {
port@1 {
port_id = <1>;
phy_address = <0x18>;
};
port@2 {
port_id = <2>;
phy_address = <0x19>;
@@ -307,7 +300,8 @@
&dp2 {
status = "okay";
phy-handle = <&qca8075_2>;
phy-mode = "qsgmii";
phy-handle = <&qca8075_1>;
label = "lan4";
nvmem-cells = <&macaddr_appsblenv_ethaddr>;
nvmem-cell-names = "mac-address";
@@ -315,7 +309,8 @@
&dp3 {
status = "okay";
phy-handle = <&qca8075_3>;
phy-mode = "qsgmii";
phy-handle = <&qca8075_2>;
label = "lan3";
nvmem-cells = <&macaddr_appsblenv_ethaddr>;
nvmem-cell-names = "mac-address";
@@ -323,7 +318,8 @@
&dp4 {
status = "okay";
phy-handle = <&qca8075_4>;
phy-mode = "qsgmii";
phy-handle = <&qca8075_3>;
label = "lan2";
nvmem-cells = <&macaddr_appsblenv_ethaddr>;
nvmem-cell-names = "mac-address";

View File

@@ -12,6 +12,31 @@ define Device/Default
IMAGE/sysupgrade.bin/squashfs :=
endef
define Device/FitImage
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | libdeflate-gzip | fit gzip $$(KDIR)/image-$$(DEVICE_DTS).dtb
KERNEL_NAME := Image
endef
define Device/FitImageLzma
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
KERNEL_NAME := Image
endef
define Device/EmmcImage
IMAGES := factory.bin sysupgrade.bin
IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to 64k
IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-to 64k | sysupgrade-tar rootfs=$$$$@ | append-metadata
endef
define Device/UbiFit
KERNEL_IN_UBI := 1
IMAGES := factory.ubi sysupgrade.bin
IMAGE/factory.ubi := append-ubi
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
endef
include $(SUBTARGET).mk
$(eval $(call BuildImage))

View File

View File

@@ -1,28 +1,3 @@
define Device/FitImage
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | libdeflate-gzip | fit gzip $$(KDIR)/image-$$(DEVICE_DTS).dtb
KERNEL_NAME := Image
endef
define Device/FitImageLzma
KERNEL_SUFFIX := -uImage.itb
KERNEL = kernel-bin | lzma | fit lzma $$(KDIR)/image-$$(DEVICE_DTS).dtb
KERNEL_NAME := Image
endef
define Device/EmmcImage
IMAGES := factory.bin sysupgrade.bin
IMAGE/factory.bin := append-rootfs | pad-rootfs | pad-to 64k
IMAGE/sysupgrade.bin/squashfs := append-rootfs | pad-to 64k | sysupgrade-tar rootfs=$$$$@ | append-metadata
endef
define Device/UbiFit
KERNEL_IN_UBI := 1
IMAGES := factory.ubi sysupgrade.bin
IMAGE/factory.ubi := append-ubi
IMAGE/sysupgrade.bin := sysupgrade-tar | append-metadata
endef
define Build/wax6xx-netgear-tar
mkdir $@.tmp
mv $@ $@.tmp/nand-ipq807x-apps.img

View File

@@ -0,0 +1,11 @@
CONFIG_IPQ_GCC_6018=y
CONFIG_MTD_SPLIT_FIT_FW=y
CONFIG_PINCTRL_IPQ6018=y
CONFIG_QCOM_APM=y
# CONFIG_QCOM_CLK_SMD_RPM is not set
# CONFIG_QCOM_RPMPD is not set
CONFIG_QCOM_SMD_RPM=y
CONFIG_REGULATOR_CPR3=y
# CONFIG_REGULATOR_CPR3_NPU is not set
CONFIG_REGULATOR_CPR4_APSS=y
CONFIG_REGULATOR_QCOM_SMD_RPM=y

View File

@@ -0,0 +1,8 @@
SUBTARGET:=ipq60xx
FEATURES += source-only
BOARDNAME:=Qualcomm Atheros IPQ60xx
DEFAULT_PACKAGES += ath11k-firmware-ipq6018
define Target/Description
Build firmware images for Qualcomm Atheros IPQ60xx based boards.
endef

View File

@@ -33,13 +33,23 @@ netgear,wax630)
ucidef_set_led_netdev "lan2" "LAN2" "lan2:green" "lan2"
;;
redmi,ax6|\
redmi,ax6-stock|\
redmi,ax6-stock)
ucidef_set_led_netdev "wan" "WAN" "blue:network" "wan"
;;
xiaomi,ax3600|\
xiaomi,ax3600-stock)
ucidef_set_led_netdev "wan" "WAN" "blue:network" "wan" "link"
ucidef_set_led_netdev "wan-port-link" "WAN-PORT-LINK" "90000.mdio-1:01:green:wan" "wan" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "lan1-port-link" "LAN1-PORT-LINK" "90000.mdio-1:02:green:lan" "lan1" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "lan2-port-link" "LAN2-PORT-LINK" "90000.mdio-1:03:green:lan" "lan2" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "lan3-port-link" "LAN3-PORT-LINK" "90000.mdio-1:04:green:lan" "lan3" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "wan" "WAN" "blue:network" "wan"
;;
xiaomi,ax9000)
ucidef_set_led_netdev "wan-port-link" "WAN-PORT-LINK" "90000.mdio-1:18:green:wan" "wan" "tx rx link_10 link_100 link_1000 link_2500"
ucidef_set_led_netdev "lan1-port-link" "LAN1-PORT-LINK" "90000.mdio-1:03:green:lan" "lan1" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "lan2-port-link" "LAN2-PORT-LINK" "90000.mdio-1:02:green:lan" "lan2" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "lan3-port-link" "LAN3-PORT-LINK" "90000.mdio-1:01:green:lan" "lan3" "tx rx link_10 link_100 link_1000"
ucidef_set_led_netdev "lan4-port-link" "LAN4-PORT-LINK" "90000.mdio-1:00:green:lan" "lan4" "tx rx link_10 link_100 link_1000"
;;
qnap,301w)
ucidef_set_led_netdev "lan1" "LAN1" "green:lan1" "lan1"

View File

@@ -0,0 +1,27 @@
From 1e8a314a1b87eaba496fcc6dc0efef573b3c186d Mon Sep 17 00:00:00 2001
From: Christian Marangi <ansuelsmth@gmail.com>
Date: Mon, 17 Apr 2023 19:44:07 +0200
Subject: [PATCH] clk: qcom: gcc-ipq6018: drop redundant F define
The same exact F frequency table entry is defined in clk-rcg.h
Drop the redundant define to cleanup code.
Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230417174408.23722-1-ansuelsmth@gmail.com
---
drivers/clk/qcom/gcc-ipq6018.c | 2 --
1 file changed, 2 deletions(-)
--- a/drivers/clk/qcom/gcc-ipq6018.c
+++ b/drivers/clk/qcom/gcc-ipq6018.c
@@ -26,8 +26,6 @@
#include "clk-regmap-mux.h"
#include "reset.h"
-#define F(f, s, h, m, n) { (f), (s), (2 * (h) - 1), (m), (n) }
-
enum {
P_XO,
P_BIAS_PLL,

View File

@@ -0,0 +1,39 @@
From 91e7c87f0ec1d644afb65cf3a16ded874c9d4ab9 Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Fri, 26 May 2023 21:08:54 +0200
Subject: [PATCH] clk: qcom: gcc-ipq6018: update UBI32 PLL
Update the UBI32 alpha PLL config to the latest values from the downstream
QCA 5.4 kernel.
Signed-off-by: Robert Marko <robimarko@gmail.com>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230526190855.2941291-1-robimarko@gmail.com
---
drivers/clk/qcom/gcc-ipq6018.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
--- a/drivers/clk/qcom/gcc-ipq6018.c
+++ b/drivers/clk/qcom/gcc-ipq6018.c
@@ -4143,15 +4143,20 @@ static struct clk_branch gcc_dcc_clk = {
static const struct alpha_pll_config ubi32_pll_config = {
.l = 0x3e,
- .alpha = 0x57,
+ .alpha = 0x6667,
.config_ctl_val = 0x240d6aa8,
.config_ctl_hi_val = 0x3c2,
+ .config_ctl_val = 0x240d4828,
+ .config_ctl_hi_val = 0x6,
.main_output_mask = BIT(0),
.aux_output_mask = BIT(1),
.pre_div_val = 0x0,
.pre_div_mask = BIT(12),
.post_div_val = 0x0,
.post_div_mask = GENMASK(9, 8),
+ .alpha_en_mask = BIT(24),
+ .test_ctl_val = 0x1C0000C0,
+ .test_ctl_hi_val = 0x4000,
};
static const struct alpha_pll_config nss_crypto_pll_config = {

View File

@@ -0,0 +1,38 @@
From 3f2fbfe6e4f6f2bdd1da8ef5aceba3945c4ada57 Mon Sep 17 00:00:00 2001
From: Arnd Bergmann <arnd@arndb.de>
Date: Thu, 1 Jun 2023 23:34:12 +0200
Subject: [PATCH] clk: qcom: gcc-ipq6018: remove duplicate initializers
A recent change added new initializers for .config_ctl_val and
.config_ctl_hi_val but left the old values in place:
drivers/clk/qcom/gcc-ipq6018.c:4155:27: error: initialized field overwritten [-Werror=override-init]
4155 | .config_ctl_val = 0x240d4828,
| ^~~~~~~~~~
drivers/clk/qcom/gcc-ipq6018.c:4156:30: error: initialized field overwritten [-Werror=override-init]
4156 | .config_ctl_hi_val = 0x6,
| ^~~
Remove the unused ones now to avoid confusion.
Fixes: f4f0c8acee0e4 ("clk: qcom: gcc-ipq6018: update UBI32 PLL")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Reviewed-by: Robert Marko <robimarko@gmail.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230601213416.3373599-1-arnd@kernel.org
---
drivers/clk/qcom/gcc-ipq6018.c | 2 --
1 file changed, 2 deletions(-)
--- a/drivers/clk/qcom/gcc-ipq6018.c
+++ b/drivers/clk/qcom/gcc-ipq6018.c
@@ -4144,8 +4144,6 @@ static struct clk_branch gcc_dcc_clk = {
static const struct alpha_pll_config ubi32_pll_config = {
.l = 0x3e,
.alpha = 0x6667,
- .config_ctl_val = 0x240d6aa8,
- .config_ctl_hi_val = 0x3c2,
.config_ctl_val = 0x240d4828,
.config_ctl_hi_val = 0x6,
.main_output_mask = BIT(0),

View File

@@ -0,0 +1,102 @@
From 62a5df451ab911421da96655fcc4d1e269ff6e2f Mon Sep 17 00:00:00 2001
From: Mantas Pucka <mantas@8devices.com>
Date: Tue, 23 Jan 2024 18:09:20 +0200
Subject: [PATCH] phy: qcom-qmp-usb: fix serdes init sequence for IPQ6018
Commit 23fd679249df ("phy: qcom-qmp: add USB3 PHY support for IPQ6018")
noted that IPQ6018 init is identical to IPQ8074. Yet downstream uses
separate serdes init sequence for IPQ6018. Since already existing IPQ9574
serdes init sequence is identical, just reuse it and fix failing USB3 mode
in IPQ6018.
Fixes: 23fd679249df ("phy: qcom-qmp: add USB3 PHY support for IPQ6018")
Signed-off-by: Mantas Pucka <mantas@8devices.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/1706026160-17520-3-git-send-email-mantas@8devices.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
---
drivers/phy/qualcomm/phy-qcom-qmp-usb.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
--- a/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-usb.c
@@ -233,6 +233,43 @@ static const struct qmp_phy_init_tbl ipq
QMP_PHY_INIT_CFG(QPHY_V3_PCS_TXDEEMPH_M3P5DB_V0, 0x0f),
};
+static const struct qmp_phy_init_tbl ipq9574_usb3_serdes_tbl[] = {
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x1a),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CLK_SELECT, 0x30),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TRIM, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0b),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SVS_MODE_CLK_SEL, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_COM_HSCLK_SEL, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CMN_CONFIG, 0x06),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_IVCO, 0x0f),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SYS_CLK_CTRL, 0x06),
+ /* PLL and Loop filter settings */
+ QMP_PHY_INIT_CFG(QSERDES_COM_DEC_START_MODE0, 0x68),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START1_MODE0, 0xab),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START2_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x02),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CP_CTRL_MODE0, 0x09),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ QMP_PHY_INIT_CFG(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ QMP_PHY_INIT_CFG(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0xa0),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP1_MODE0, 0xaa),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP2_MODE0, 0x29),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_CORE_CLK_EN, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_LOCK_CMP_CFG, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_VCO_TUNE_MAP, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_BG_TIMER, 0x0a),
+ /* SSC settings */
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_EN_CENTER, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER1, 0x7d),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_PER2, 0x01),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER1, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_ADJ_PER2, 0x00),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE1, 0x0a),
+ QMP_PHY_INIT_CFG(QSERDES_COM_SSC_STEP_SIZE2, 0x05),
+};
+
static const struct qmp_phy_init_tbl msm8996_usb3_serdes_tbl[] = {
QMP_PHY_INIT_CFG(QSERDES_COM_SYSCLK_EN_SEL, 0x14),
QMP_PHY_INIT_CFG(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
@@ -1591,6 +1628,26 @@ static const char * const qmp_phy_vreg_l
"vdda-phy", "vdda-pll",
};
+static const struct qmp_phy_cfg ipq6018_usb3phy_cfg = {
+ .lanes = 1,
+
+ .serdes_tbl = ipq9574_usb3_serdes_tbl,
+ .serdes_tbl_num = ARRAY_SIZE(ipq9574_usb3_serdes_tbl),
+ .tx_tbl = msm8996_usb3_tx_tbl,
+ .tx_tbl_num = ARRAY_SIZE(msm8996_usb3_tx_tbl),
+ .rx_tbl = ipq8074_usb3_rx_tbl,
+ .rx_tbl_num = ARRAY_SIZE(ipq8074_usb3_rx_tbl),
+ .pcs_tbl = ipq8074_usb3_pcs_tbl,
+ .pcs_tbl_num = ARRAY_SIZE(ipq8074_usb3_pcs_tbl),
+ .clk_list = msm8996_phy_clk_l,
+ .num_clks = ARRAY_SIZE(msm8996_phy_clk_l),
+ .reset_list = msm8996_usb3phy_reset_l,
+ .num_resets = ARRAY_SIZE(msm8996_usb3phy_reset_l),
+ .vreg_list = qmp_phy_vreg_l,
+ .num_vregs = ARRAY_SIZE(qmp_phy_vreg_l),
+ .regs = qmp_v3_usb3phy_regs_layout,
+};
+
static const struct qmp_phy_cfg ipq8074_usb3phy_cfg = {
.lanes = 1,
@@ -2534,7 +2591,7 @@ static const struct of_device_id qmp_usb
.data = &msm8996_usb3phy_cfg,
}, {
.compatible = "qcom,ipq6018-qmp-usb3-phy",
- .data = &ipq8074_usb3phy_cfg,
+ .data = &ipq6018_usb3phy_cfg,
}, {
.compatible = "qcom,sc7180-qmp-usb3-phy",
.data = &sc7180_usb3phy_cfg,

View File

@@ -0,0 +1,50 @@
From fd712118aa1aa758da1fd1546b3f8a1b00e42cbc Mon Sep 17 00:00:00 2001
From: Mantas Pucka <mantas@8devices.com>
Date: Tue, 23 Jan 2024 11:26:09 +0200
Subject: [PATCH] clk: qcom: gcc-ipq6018: add qdss_at clock needed for wifi
operation
Without it system hangs upon wifi firmware load. It should be enabled by
remoteproc/wifi driver. Bindings already exist for it, so add it based
on vendor code.
Signed-off-by: Mantas Pucka <mantas@8devices.com>
Link: https://lore.kernel.org/r/1706001970-26032-1-git-send-email-mantas@8devices.com
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
---
drivers/clk/qcom/gcc-ipq6018.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
--- a/drivers/clk/qcom/gcc-ipq6018.c
+++ b/drivers/clk/qcom/gcc-ipq6018.c
@@ -3503,6 +3503,22 @@ static struct clk_branch gcc_prng_ahb_cl
},
};
+static struct clk_branch gcc_qdss_at_clk = {
+ .halt_reg = 0x29024,
+ .clkr = {
+ .enable_reg = 0x29024,
+ .enable_mask = BIT(0),
+ .hw.init = &(struct clk_init_data){
+ .name = "gcc_qdss_at_clk",
+ .parent_hws = (const struct clk_hw *[]){
+ &qdss_at_clk_src.clkr.hw },
+ .num_parents = 1,
+ .flags = CLK_SET_RATE_PARENT,
+ .ops = &clk_branch2_ops,
+ },
+ },
+};
+
static struct clk_branch gcc_qdss_dap_clk = {
.halt_reg = 0x29084,
.clkr = {
@@ -4341,6 +4357,7 @@ static struct clk_regmap *gcc_ipq6018_cl
[GCC_SYS_NOC_PCIE0_AXI_CLK] = &gcc_sys_noc_pcie0_axi_clk.clkr,
[GCC_PCIE0_PIPE_CLK] = &gcc_pcie0_pipe_clk.clkr,
[GCC_PRNG_AHB_CLK] = &gcc_prng_ahb_clk.clkr,
+ [GCC_QDSS_AT_CLK] = &gcc_qdss_at_clk.clkr,
[GCC_QDSS_DAP_CLK] = &gcc_qdss_dap_clk.clkr,
[GCC_QPIC_AHB_CLK] = &gcc_qpic_ahb_clk.clkr,
[GCC_QPIC_CLK] = &gcc_qpic_clk.clkr,

View File

@@ -0,0 +1,34 @@
From 546f0617a22a481f3ca1f7e058aea0c40517c64e Mon Sep 17 00:00:00 2001
From: Kathiravan T <quic_kathirav@quicinc.com>
Date: Fri, 26 May 2023 18:23:04 +0530
Subject: [PATCH] arm64: dts: qcom: ipq6018: add QFPROM node
IPQ6018 has efuse region to determine the various HW quirks. Lets
add the initial support and the individual fuses will be added as they
are required.
Signed-off-by: Kathiravan T <quic_kathirav@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20230526125305.19626-4-quic_kathirav@quicinc.com
---
arch/arm64/boot/dts/qcom/ipq6018.dtsi | 7 +++++++
1 file changed, 7 insertions(+)
--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
@@ -179,6 +179,13 @@
dma-ranges;
compatible = "simple-bus";
+ qfprom: efuse@a4000 {
+ compatible = "qcom,ipq6018-qfprom", "qcom,qfprom";
+ reg = <0x0 0x000a4000 0x0 0x2000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ };
+
prng: qrng@e1000 {
compatible = "qcom,prng-ee";
reg = <0x0 0x000e3000 0x0 0x1000>;

View File

@@ -0,0 +1,123 @@
From 47e161a7873b0891f4e01a69a839f6161d816ea8 Mon Sep 17 00:00:00 2001
From: Robert Marko <robimarko@gmail.com>
Date: Wed, 25 Oct 2023 14:57:57 +0530
Subject: [PATCH] cpufreq: qcom-nvmem: add support for IPQ6018
IPQ6018 SoC series comes in multiple SKU-s, and not all of them support
high frequency OPP points.
SoC itself does however have a single bit in QFPROM to indicate the CPU
speed-bin.
That bit is used to indicate frequency limit of 1.5GHz, but that alone is
not enough as IPQ6000 only goes up to 1.2GHz, but SMEM ID can be used to
limit it further.
IPQ6018 compatible is blacklisted from DT platdev as the cpufreq device
will get created by NVMEM CPUFreq driver.
Signed-off-by: Robert Marko <robimarko@gmail.com>
[ Viresh: Fixed rebase conflict. ]
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
---
drivers/cpufreq/cpufreq-dt-platdev.c | 1 +
drivers/cpufreq/qcom-cpufreq-nvmem.c | 58 ++++++++++++++++++++++++++++++++++++
2 files changed, 59 insertions(+)
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -163,6 +163,7 @@ static const struct of_device_id blockli
{ .compatible = "ti,dra7", },
{ .compatible = "ti,omap3", },
+ { .compatible = "qcom,ipq6018", },
{ .compatible = "qcom,ipq8064", },
{ .compatible = "qcom,ipq8074", },
{ .compatible = "qcom,apq8064", },
--- a/drivers/cpufreq/qcom-cpufreq-nvmem.c
+++ b/drivers/cpufreq/qcom-cpufreq-nvmem.c
@@ -36,6 +36,8 @@ enum ipq8074_versions {
IPQ8074_ACORN_VERSION,
};
+#define IPQ6000_VERSION BIT(2)
+
struct qcom_cpufreq_drv;
struct qcom_cpufreq_match_data {
@@ -209,6 +211,57 @@ len_error:
return ret;
}
+static int qcom_cpufreq_ipq6018_name_version(struct device *cpu_dev,
+ struct nvmem_cell *speedbin_nvmem,
+ char **pvs_name,
+ struct qcom_cpufreq_drv *drv)
+{
+ u32 msm_id;
+ int ret;
+ u8 *speedbin;
+ *pvs_name = NULL;
+
+ ret = qcom_smem_get_soc_id(&msm_id);
+ if (ret)
+ return ret;
+
+ speedbin = nvmem_cell_read(speedbin_nvmem, NULL);
+ if (IS_ERR(speedbin))
+ return PTR_ERR(speedbin);
+
+ switch (msm_id) {
+ case QCOM_ID_IPQ6005:
+ case QCOM_ID_IPQ6010:
+ case QCOM_ID_IPQ6018:
+ case QCOM_ID_IPQ6028:
+ /* Fuse Value Freq BIT to set
+ * ---------------------------------
+ * 2b0 No Limit BIT(0)
+ * 2b1 1.5 GHz BIT(1)
+ */
+ drv->versions = 1 << (unsigned int)(*speedbin);
+ break;
+ case QCOM_ID_IPQ6000:
+ /*
+ * IPQ6018 family only has one bit to advertise the CPU
+ * speed-bin, but that is not enough for IPQ6000 which
+ * is only rated up to 1.2GHz.
+ * So for IPQ6000 manually set BIT(2) based on SMEM ID.
+ */
+ drv->versions = IPQ6000_VERSION;
+ break;
+ default:
+ dev_err(cpu_dev,
+ "SoC ID %u is not part of IPQ6018 family, limiting to 1.2GHz!\n",
+ msm_id);
+ drv->versions = IPQ6000_VERSION;
+ break;
+ }
+
+ kfree(speedbin);
+ return 0;
+}
+
static int qcom_cpufreq_ipq8074_name_version(struct device *cpu_dev,
struct nvmem_cell *speedbin_nvmem,
char **pvs_name,
@@ -265,6 +318,10 @@ static const struct qcom_cpufreq_match_d
.get_version = qcom_cpufreq_ipq8074_name_version,
};
+static const struct qcom_cpufreq_match_data match_data_ipq6018 = {
+ .get_version = qcom_cpufreq_ipq6018_name_version,
+};
+
static int qcom_cpufreq_probe(struct platform_device *pdev)
{
struct qcom_cpufreq_drv *drv;
@@ -409,6 +466,7 @@ static const struct of_device_id qcom_cp
{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
{ .compatible = "qcom,qcs404", .data = &match_data_qcs404 },
+ { .compatible = "qcom,ipq6018", .data = &match_data_ipq6018 },
{ .compatible = "qcom,ipq8064", .data = &match_data_krait },
{ .compatible = "qcom,ipq8074", .data = &match_data_ipq8074 },
{ .compatible = "qcom,apq8064", .data = &match_data_krait },

View File

@@ -0,0 +1,32 @@
From a120815200adaf3ac28ccf3a1813c78b4be02cc4 Mon Sep 17 00:00:00 2001
From: Kathiravan Thirumoorthy <quic_kathirav@quicinc.com>
Date: Thu, 14 Sep 2023 12:29:59 +0530
Subject: [PATCH] arm64: dts: qcom: ipq6018: include the GPLL0 as clock
provider for mailbox
While the kernel is booting up, APSS PLL will be running at 800MHz with
GPLL0 as source. Once the cpufreq driver is available, APSS PLL will be
configured to the rate based on the opp table and the source also will
be changed to APSS_PLL_EARLY. So allow the mailbox to consume the GPLL0,
with this inclusion, CPU Freq correctly reports that CPU is running at
800MHz rather than 24MHz.
Signed-off-by: Kathiravan Thirumoorthy <quic_kathirav@quicinc.com>
Reviewed-by: Konrad Dybcio <konrad.dybcio@linaro.org>
---
arch/arm64/boot/dts/qcom/ipq6018.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
--- a/arch/arm64/boot/dts/qcom/ipq6018.dtsi
+++ b/arch/arm64/boot/dts/qcom/ipq6018.dtsi
@@ -504,8 +504,8 @@
compatible = "qcom,ipq6018-apcs-apps-global";
reg = <0x0 0x0b111000 0x0 0x1000>;
#clock-cells = <1>;
- clocks = <&a53pll>, <&xo>;
- clock-names = "pll", "xo";
+ clocks = <&a53pll>, <&xo>, <&gcc GPLL0>;
+ clock-names = "pll", "xo", "gpll0";
#mbox-cells = <1>;
};

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