Merge Official Source
Signed-off-by: Tianling Shen <cnsztl@immortalwrt.org>
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
@@ -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,
|
||||
@@ -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;
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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 */
|
||||
@@ -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)) {
|
||||
@@ -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;
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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':
|
||||
@@ -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);
|
||||
+
|
||||
+}
|
||||
@@ -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)
|
||||
@@ -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) {
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(-)
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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>;
|
||||
+ };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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
|
||||
@@ -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>;
|
||||
+ };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
;;
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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))
|
||||
|
||||
0
target/linux/qualcommax/image/ipq60xx.mk
Normal file
0
target/linux/qualcommax/image/ipq60xx.mk
Normal 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
|
||||
|
||||
11
target/linux/qualcommax/ipq60xx/config-default
Normal file
11
target/linux/qualcommax/ipq60xx/config-default
Normal 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
|
||||
8
target/linux/qualcommax/ipq60xx/target.mk
Normal file
8
target/linux/qualcommax/ipq60xx/target.mk
Normal 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
|
||||
@@ -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"
|
||||
|
||||
@@ -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,
|
||||
@@ -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 = {
|
||||
@@ -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),
|
||||
@@ -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,
|
||||
@@ -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,
|
||||
@@ -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>;
|
||||
@@ -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
|
||||
+ * ---------------------------------
|
||||
+ * 2’b0 No Limit BIT(0)
|
||||
+ * 2’b1 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 },
|
||||
@@ -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
Reference in New Issue
Block a user