mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-19 13:48:06 +00:00
generic: 5.10: replace pending 730-net-phy-at803x-fix... with upstream
Replace pending 730-net-phy-at803x-fix-feature-detection.patch with upstream version and move it to backport. Refresh other related patch while moving it. Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
This commit is contained in:
parent
7643d95bb3
commit
aa8ba5166e
@ -1,7 +1,7 @@
|
|||||||
From 97ca310aa18a93329ef5cd68c20de89761962f45 Mon Sep 17 00:00:00 2001
|
From b856150c8098f12996ee81c3ab2a65adbaeeb3ec Mon Sep 17 00:00:00 2001
|
||||||
From: David Bauer <mail@david-bauer.net>
|
From: David Bauer <mail@david-bauer.net>
|
||||||
Date: Sun, 13 Jun 2021 12:19:36 +0200
|
Date: Sun, 27 Jun 2021 12:16:07 +0200
|
||||||
Subject: [PATCH] net: phy: at803x: fix feature detection
|
Subject: [PATCH] net: phy: at803x: mask 1000 Base-X link mode
|
||||||
|
|
||||||
AR8031/AR8033 have different status registers for copper
|
AR8031/AR8033 have different status registers for copper
|
||||||
and fiber operation. However, the extended status register
|
and fiber operation. However, the extended status register
|
||||||
@ -14,14 +14,16 @@ Remove this mode from the supported link modes, as this driver
|
|||||||
currently only supports copper operation.
|
currently only supports copper operation.
|
||||||
|
|
||||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||||
|
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
---
|
---
|
||||||
drivers/net/phy/at803x.c | 30 +++++++++++++++++++++++++++++-
|
drivers/net/phy/at803x.c | 30 +++++++++++++++++++++++++++++-
|
||||||
1 file changed, 29 insertions(+), 1 deletion(-)
|
1 file changed, 29 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
--- a/drivers/net/phy/at803x.c
|
--- a/drivers/net/phy/at803x.c
|
||||||
+++ b/drivers/net/phy/at803x.c
|
+++ b/drivers/net/phy/at803x.c
|
||||||
@@ -1032,6 +1032,34 @@ static int at803x_set_tunable(struct phy
|
@@ -583,6 +583,34 @@ static void at803x_remove(struct phy_dev
|
||||||
}
|
regulator_disable(priv->vddio);
|
||||||
}
|
}
|
||||||
|
|
||||||
+static int at803x_get_features(struct phy_device *phydev)
|
+static int at803x_get_features(struct phy_device *phydev)
|
||||||
@ -52,10 +54,10 @@ Signed-off-by: David Bauer <mail@david-bauer.net>
|
|||||||
+ return 0;
|
+ return 0;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
static int at803x_cable_test_result_trans(u16 status)
|
static int at803x_clk_out_config(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
|
struct at803x_priv *priv = phydev->priv;
|
||||||
@@ -1364,7 +1392,7 @@ static struct phy_driver at803x_driver[]
|
@@ -1156,7 +1184,7 @@ static struct phy_driver at803x_driver[]
|
||||||
.resume = at803x_resume,
|
.resume = at803x_resume,
|
||||||
.read_page = at803x_read_page,
|
.read_page = at803x_read_page,
|
||||||
.write_page = at803x_write_page,
|
.write_page = at803x_write_page,
|
@ -170,7 +170,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
static int at803x_suspend(struct phy_device *phydev)
|
static int at803x_suspend(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
@@ -1102,6 +1191,34 @@ static int at803x_cable_test_start(struc
|
@@ -1130,6 +1219,34 @@ static int at803x_cable_test_start(struc
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,7 +205,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
static struct phy_driver at803x_driver[] = {
|
static struct phy_driver at803x_driver[] = {
|
||||||
{
|
{
|
||||||
/* Qualcomm Atheros AR8035 */
|
/* Qualcomm Atheros AR8035 */
|
||||||
@@ -1198,7 +1315,20 @@ static struct phy_driver at803x_driver[]
|
@@ -1226,7 +1343,20 @@ static struct phy_driver at803x_driver[]
|
||||||
.read_status = at803x_read_status,
|
.read_status = at803x_read_status,
|
||||||
.soft_reset = genphy_soft_reset,
|
.soft_reset = genphy_soft_reset,
|
||||||
.config_aneg = at803x_config_aneg,
|
.config_aneg = at803x_config_aneg,
|
||||||
|
@ -17,7 +17,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
--- a/drivers/net/phy/at803x.c
|
--- a/drivers/net/phy/at803x.c
|
||||||
+++ b/drivers/net/phy/at803x.c
|
+++ b/drivers/net/phy/at803x.c
|
||||||
@@ -1328,6 +1328,19 @@ static struct phy_driver at803x_driver[]
|
@@ -1356,6 +1356,19 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
@ -37,7 +37,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
}, };
|
}, };
|
||||||
|
|
||||||
module_phy_driver(at803x_driver);
|
module_phy_driver(at803x_driver);
|
||||||
@@ -1338,6 +1351,8 @@ static struct mdio_device_id __maybe_unu
|
@@ -1366,6 +1379,8 @@ static struct mdio_device_id __maybe_unu
|
||||||
{ PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
|
{ PHY_ID_MATCH_EXACT(ATH8032_PHY_ID) },
|
||||||
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
||||||
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
||||||
|
@ -26,7 +26,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
#define QCA8337_PHY_ID 0x004dd036
|
#define QCA8337_PHY_ID 0x004dd036
|
||||||
#define QCA8K_PHY_ID_MASK 0xffffffff
|
#define QCA8K_PHY_ID_MASK 0xffffffff
|
||||||
|
|
||||||
@@ -1329,10 +1330,23 @@ static struct phy_driver at803x_driver[]
|
@@ -1357,10 +1358,23 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
}, {
|
}, {
|
||||||
@ -53,7 +53,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
/* PHY_GBIT_FEATURES */
|
/* PHY_GBIT_FEATURES */
|
||||||
.probe = at803x_probe,
|
.probe = at803x_probe,
|
||||||
.flags = PHY_IS_INTERNAL,
|
.flags = PHY_IS_INTERNAL,
|
||||||
@@ -1352,7 +1366,8 @@ static struct mdio_device_id __maybe_unu
|
@@ -1380,7 +1394,8 @@ static struct mdio_device_id __maybe_unu
|
||||||
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
{ PHY_ID_MATCH_EXACT(ATH8035_PHY_ID) },
|
||||||
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
{ PHY_ID_MATCH_EXACT(ATH9331_PHY_ID) },
|
||||||
{ PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
|
{ PHY_ID_MATCH_EXACT(QCA8337_PHY_ID) },
|
||||||
|
@ -16,7 +16,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
--- a/drivers/net/phy/at803x.c
|
--- a/drivers/net/phy/at803x.c
|
||||||
+++ b/drivers/net/phy/at803x.c
|
+++ b/drivers/net/phy/at803x.c
|
||||||
@@ -1329,6 +1329,8 @@ static struct phy_driver at803x_driver[]
|
@@ -1357,6 +1357,8 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
@ -25,7 +25,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
}, {
|
}, {
|
||||||
/* QCA8327-A from switch QCA8327-AL1A */
|
/* QCA8327-A from switch QCA8327-AL1A */
|
||||||
.phy_id = QCA8327_A_PHY_ID,
|
.phy_id = QCA8327_A_PHY_ID,
|
||||||
@@ -1342,6 +1344,8 @@ static struct phy_driver at803x_driver[]
|
@@ -1370,6 +1372,8 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
@ -34,7 +34,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
}, {
|
}, {
|
||||||
/* QCA8327-B from switch QCA8327-BL1A */
|
/* QCA8327-B from switch QCA8327-BL1A */
|
||||||
.phy_id = QCA8327_B_PHY_ID,
|
.phy_id = QCA8327_B_PHY_ID,
|
||||||
@@ -1355,6 +1359,8 @@ static struct phy_driver at803x_driver[]
|
@@ -1383,6 +1387,8 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
|
@ -15,7 +15,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
--- a/drivers/net/phy/at803x.c
|
--- a/drivers/net/phy/at803x.c
|
||||||
+++ b/drivers/net/phy/at803x.c
|
+++ b/drivers/net/phy/at803x.c
|
||||||
@@ -1318,47 +1318,47 @@ static struct phy_driver at803x_driver[]
|
@@ -1346,47 +1346,47 @@ static struct phy_driver at803x_driver[]
|
||||||
.config_aneg = at803x_config_aneg,
|
.config_aneg = at803x_config_aneg,
|
||||||
}, {
|
}, {
|
||||||
/* QCA8337 */
|
/* QCA8337 */
|
||||||
|
@ -37,7 +37,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
#define AT803X_DEBUG_REG_1F 0x1F
|
#define AT803X_DEBUG_REG_1F 0x1F
|
||||||
#define AT803X_DEBUG_PLL_ON BIT(2)
|
#define AT803X_DEBUG_PLL_ON BIT(2)
|
||||||
@@ -1220,6 +1225,58 @@ static int qca83xx_config_init(struct ph
|
@@ -1248,6 +1253,58 @@ static int qca83xx_config_init(struct ph
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
static struct phy_driver at803x_driver[] = {
|
static struct phy_driver at803x_driver[] = {
|
||||||
{
|
{
|
||||||
/* Qualcomm Atheros AR8035 */
|
/* Qualcomm Atheros AR8035 */
|
||||||
@@ -1329,8 +1386,8 @@ static struct phy_driver at803x_driver[]
|
@@ -1357,8 +1414,8 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
@ -107,7 +107,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
}, {
|
}, {
|
||||||
/* QCA8327-A from switch QCA8327-AL1A */
|
/* QCA8327-A from switch QCA8327-AL1A */
|
||||||
.phy_id = QCA8327_A_PHY_ID,
|
.phy_id = QCA8327_A_PHY_ID,
|
||||||
@@ -1344,8 +1401,8 @@ static struct phy_driver at803x_driver[]
|
@@ -1372,8 +1429,8 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
@ -118,7 +118,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
}, {
|
}, {
|
||||||
/* QCA8327-B from switch QCA8327-BL1A */
|
/* QCA8327-B from switch QCA8327-BL1A */
|
||||||
.phy_id = QCA8327_B_PHY_ID,
|
.phy_id = QCA8327_B_PHY_ID,
|
||||||
@@ -1359,8 +1416,8 @@ static struct phy_driver at803x_driver[]
|
@@ -1387,8 +1444,8 @@ static struct phy_driver at803x_driver[]
|
||||||
.get_sset_count = at803x_get_sset_count,
|
.get_sset_count = at803x_get_sset_count,
|
||||||
.get_strings = at803x_get_strings,
|
.get_strings = at803x_get_strings,
|
||||||
.get_stats = at803x_get_stats,
|
.get_stats = at803x_get_stats,
|
||||||
|
@ -27,7 +27,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
|
#define AT803X_DEBUG_RX_CLK_DLY_EN BIT(15)
|
||||||
|
|
||||||
#define AT803X_DEBUG_REG_5 0x05
|
#define AT803X_DEBUG_REG_5 0x05
|
||||||
@@ -1222,9 +1224,37 @@ static int qca83xx_config_init(struct ph
|
@@ -1250,9 +1252,37 @@ static int qca83xx_config_init(struct ph
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
static int qca83xx_resume(struct phy_device *phydev)
|
static int qca83xx_resume(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
int ret, val;
|
int ret, val;
|
||||||
@@ -1379,6 +1409,7 @@ static struct phy_driver at803x_driver[]
|
@@ -1407,6 +1437,7 @@ static struct phy_driver at803x_driver[]
|
||||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||||
.name = "Qualcomm Atheros 8337 internal PHY",
|
.name = "Qualcomm Atheros 8337 internal PHY",
|
||||||
/* PHY_GBIT_FEATURES */
|
/* PHY_GBIT_FEATURES */
|
||||||
@ -73,7 +73,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
.probe = at803x_probe,
|
.probe = at803x_probe,
|
||||||
.flags = PHY_IS_INTERNAL,
|
.flags = PHY_IS_INTERNAL,
|
||||||
.config_init = qca83xx_config_init,
|
.config_init = qca83xx_config_init,
|
||||||
@@ -1394,6 +1425,7 @@ static struct phy_driver at803x_driver[]
|
@@ -1422,6 +1453,7 @@ static struct phy_driver at803x_driver[]
|
||||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||||
.name = "Qualcomm Atheros 8327-A internal PHY",
|
.name = "Qualcomm Atheros 8327-A internal PHY",
|
||||||
/* PHY_GBIT_FEATURES */
|
/* PHY_GBIT_FEATURES */
|
||||||
@ -81,7 +81,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
.probe = at803x_probe,
|
.probe = at803x_probe,
|
||||||
.flags = PHY_IS_INTERNAL,
|
.flags = PHY_IS_INTERNAL,
|
||||||
.config_init = qca83xx_config_init,
|
.config_init = qca83xx_config_init,
|
||||||
@@ -1409,6 +1441,7 @@ static struct phy_driver at803x_driver[]
|
@@ -1437,6 +1469,7 @@ static struct phy_driver at803x_driver[]
|
||||||
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
.phy_id_mask = QCA8K_PHY_ID_MASK,
|
||||||
.name = "Qualcomm Atheros 8327-B internal PHY",
|
.name = "Qualcomm Atheros 8327-B internal PHY",
|
||||||
/* PHY_GBIT_FEATURES */
|
/* PHY_GBIT_FEATURES */
|
||||||
|
@ -15,7 +15,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
|
|
||||||
--- a/drivers/net/phy/at803x.c
|
--- a/drivers/net/phy/at803x.c
|
||||||
+++ b/drivers/net/phy/at803x.c
|
+++ b/drivers/net/phy/at803x.c
|
||||||
@@ -1233,6 +1233,9 @@ static int qca83xx_config_init(struct ph
|
@@ -1261,6 +1261,9 @@ static int qca83xx_config_init(struct ph
|
||||||
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||||
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
|
AT803X_DEBUG_TX_CLK_DLY_EN, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1208,9 +1208,9 @@ static int qca83xx_config_init(struct ph
|
@@ -1236,9 +1236,9 @@ static int qca83xx_config_init(struct ph
|
||||||
switch (switch_revision) {
|
switch (switch_revision) {
|
||||||
case 1:
|
case 1:
|
||||||
/* For 100M waveform */
|
/* For 100M waveform */
|
||||||
@ -81,7 +81,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
@@ -1218,8 +1218,8 @@ static int qca83xx_config_init(struct ph
|
@@ -1246,8 +1246,8 @@ static int qca83xx_config_init(struct ph
|
||||||
fallthrough;
|
fallthrough;
|
||||||
case 4:
|
case 4:
|
||||||
phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
|
phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_AZ_DEBUG, 0x803f);
|
||||||
@ -92,7 +92,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
|
at803x_debug_reg_write(phydev, AT803X_DEBUG_REG_3C, 0x6000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1230,7 +1230,7 @@ static int qca83xx_config_init(struct ph
|
@@ -1258,7 +1258,7 @@ static int qca83xx_config_init(struct ph
|
||||||
*/
|
*/
|
||||||
if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
|
if (phydev->drv->phy_id == QCA8327_A_PHY_ID ||
|
||||||
phydev->drv->phy_id == QCA8327_B_PHY_ID)
|
phydev->drv->phy_id == QCA8327_B_PHY_ID)
|
||||||
@ -101,7 +101,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||||
|
|
||||||
/* Following original QCA sourcecode set port to prefer master */
|
/* Following original QCA sourcecode set port to prefer master */
|
||||||
@@ -1248,12 +1248,12 @@ static void qca83xx_link_change_notify(s
|
@@ -1276,12 +1276,12 @@ static void qca83xx_link_change_notify(s
|
||||||
/* Set DAC Amplitude adjustment to +6% for 100m on link running */
|
/* Set DAC Amplitude adjustment to +6% for 100m on link running */
|
||||||
if (phydev->state == PHY_RUNNING) {
|
if (phydev->state == PHY_RUNNING) {
|
||||||
if (phydev->speed == SPEED_100)
|
if (phydev->speed == SPEED_100)
|
||||||
@ -116,7 +116,7 @@ Signed-off-by: David S. Miller <davem@davemloft.net>
|
|||||||
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
QCA8327_DEBUG_MANU_CTRL_EN, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1300,7 +1300,7 @@ static int qca83xx_suspend(struct phy_de
|
@@ -1328,7 +1328,7 @@ static int qca83xx_suspend(struct phy_de
|
||||||
phy_modify(phydev, MII_BMCR, mask, 0);
|
phy_modify(phydev, MII_BMCR, mask, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user