aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch
diff options
context:
space:
mode:
authorHauke Mehrtens <hauke@hauke-m.de>2020-02-23 13:20:11 +0100
committerKoen Vandeputte <koen.vandeputte@ncentric.com>2020-02-28 17:50:45 +0100
commitc16517d26de30c90dabce1e456615fd7fbdce07c (patch)
treee7371ee12a3c413a064885b634ee4c975ad7f96a /target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch
parent955634b473284847e3c8281a6ac85655329d8b06 (diff)
downloadupstream-c16517d26de30c90dabce1e456615fd7fbdce07c.tar.gz
upstream-c16517d26de30c90dabce1e456615fd7fbdce07c.tar.bz2
upstream-c16517d26de30c90dabce1e456615fd7fbdce07c.zip
kernel: copy kernel 4.19 code to 5.4
No changes were done to the patches while coping them. Currently they do not apply on top of kernel 5.4. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
Diffstat (limited to 'target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch')
-rw-r--r--target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch225
1 files changed, 225 insertions, 0 deletions
diff --git a/target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch b/target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch
new file mode 100644
index 0000000000..163d8072e6
--- /dev/null
+++ b/target/linux/generic/backport-5.4/744-v5.5-net-sfp-soft-status-and-control-support.patch
@@ -0,0 +1,225 @@
+From 40e0b3b15f7da92e6b065292b14af7b9bfb1c6e0 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@armlinux.org.uk>
+Date: Fri, 13 Sep 2019 23:00:35 +0100
+Subject: [PATCH 642/660] net: sfp: soft status and control support
+
+Add support for the soft status and control register, which allows
+TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set. We
+make use of this when the board does not support GPIOs for these
+signals.
+
+Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
+---
+ drivers/net/phy/sfp.c | 110 ++++++++++++++++++++++++++++++++++--------
+ include/linux/sfp.h | 4 ++
+ 2 files changed, 94 insertions(+), 20 deletions(-)
+
+--- a/drivers/net/phy/sfp.c
++++ b/drivers/net/phy/sfp.c
+@@ -199,7 +199,10 @@ struct sfp {
+ struct gpio_desc *gpio[GPIO_MAX];
+ int gpio_irq[GPIO_MAX];
+
++ bool need_poll;
++
+ struct mutex st_mutex; /* Protects state */
++ unsigned int state_soft_mask;
+ unsigned int state;
+ struct delayed_work poll;
+ struct delayed_work timeout;
+@@ -393,24 +396,90 @@ static int sfp_i2c_configure(struct sfp
+ }
+
+ /* Interface */
+-static unsigned int sfp_get_state(struct sfp *sfp)
++static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
+ {
+- return sfp->get_state(sfp);
++ return sfp->read(sfp, a2, addr, buf, len);
+ }
+
+-static void sfp_set_state(struct sfp *sfp, unsigned int state)
++static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
+ {
+- sfp->set_state(sfp, state);
++ return sfp->write(sfp, a2, addr, buf, len);
+ }
+
+-static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
++static unsigned int sfp_soft_get_state(struct sfp *sfp)
+ {
+- return sfp->read(sfp, a2, addr, buf, len);
++ unsigned int state = 0;
++ u8 status;
++
++ if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
++ sizeof(status)) {
++ if (status & SFP_STATUS_RX_LOS)
++ state |= SFP_F_LOS;
++ if (status & SFP_STATUS_TX_FAULT)
++ state |= SFP_F_TX_FAULT;
++ }
++
++ return state & sfp->state_soft_mask;
+ }
+
+-static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
++static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
+ {
+- return sfp->write(sfp, a2, addr, buf, len);
++ u8 status;
++
++ if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
++ sizeof(status)) {
++ if (state & SFP_F_TX_DISABLE)
++ status |= SFP_STATUS_TX_DISABLE_FORCE;
++ else
++ status &= ~SFP_STATUS_TX_DISABLE_FORCE;
++
++ sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status));
++ }
++}
++
++static void sfp_soft_start_poll(struct sfp *sfp)
++{
++ const struct sfp_eeprom_id *id = &sfp->id;
++
++ sfp->state_soft_mask = 0;
++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE &&
++ !sfp->gpio[GPIO_TX_DISABLE])
++ sfp->state_soft_mask |= SFP_F_TX_DISABLE;
++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT &&
++ !sfp->gpio[GPIO_TX_FAULT])
++ sfp->state_soft_mask |= SFP_F_TX_FAULT;
++ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS &&
++ !sfp->gpio[GPIO_LOS])
++ sfp->state_soft_mask |= SFP_F_LOS;
++
++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
++ !sfp->need_poll)
++ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
++}
++
++static void sfp_soft_stop_poll(struct sfp *sfp)
++{
++ sfp->state_soft_mask = 0;
++}
++
++static unsigned int sfp_get_state(struct sfp *sfp)
++{
++ unsigned int state = sfp->get_state(sfp);
++
++ if (state & SFP_F_PRESENT &&
++ sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT))
++ state |= sfp_soft_get_state(sfp);
++
++ return state;
++}
++
++static void sfp_set_state(struct sfp *sfp, unsigned int state)
++{
++ sfp->set_state(sfp, state);
++
++ if (state & SFP_F_PRESENT &&
++ sfp->state_soft_mask & SFP_F_TX_DISABLE)
++ sfp_soft_set_state(sfp, state);
+ }
+
+ static unsigned int sfp_check(void *buf, size_t len)
+@@ -1342,11 +1411,6 @@ static void sfp_sm_fault(struct sfp *sfp
+ }
+ }
+
+-static void sfp_sm_mod_init(struct sfp *sfp)
+-{
+- sfp_module_tx_enable(sfp);
+-}
+-
+ static void sfp_sm_probe_for_phy(struct sfp *sfp)
+ {
+ /* Setting the serdes link mode is guesswork: there's no
+@@ -1509,7 +1573,7 @@ static int sfp_sm_mod_probe(struct sfp *
+ (int)sizeof(id.ext.datecode), id.ext.datecode);
+
+ /* Check whether we support this module */
+- if (!sfp->type->module_supported(&sfp->id)) {
++ if (!sfp->type->module_supported(&id)) {
+ dev_err(sfp->dev,
+ "module is not supported - phys id 0x%02x 0x%02x\n",
+ sfp->id.base.phys_id, sfp->id.base.phys_ext_id);
+@@ -1699,6 +1763,7 @@ static void sfp_sm_main(struct sfp *sfp,
+ if (sfp->mod_phy)
+ sfp_sm_phy_detach(sfp);
+ sfp_module_tx_disable(sfp);
++ sfp_soft_stop_poll(sfp);
+ sfp_sm_next(sfp, SFP_S_DOWN, 0);
+ return;
+ }
+@@ -1710,7 +1775,10 @@ static void sfp_sm_main(struct sfp *sfp,
+ sfp->sm_dev_state != SFP_DEV_UP)
+ break;
+
+- sfp_sm_mod_init(sfp);
++ if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE))
++ sfp_soft_start_poll(sfp);
++
++ sfp_module_tx_enable(sfp);
+
+ /* Initialise the fault clearance retries */
+ sfp->sm_retries = 5;
+@@ -1966,7 +2034,10 @@ static void sfp_poll(struct work_struct
+ struct sfp *sfp = container_of(work, struct sfp, poll.work);
+
+ sfp_check_state(sfp);
+- mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
++
++ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
++ sfp->need_poll)
++ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+ }
+
+ static struct sfp *sfp_alloc(struct device *dev)
+@@ -2010,7 +2081,6 @@ static int sfp_probe(struct platform_dev
+ {
+ const struct sff_data *sff;
+ struct sfp *sfp;
+- bool poll = false;
+ int err, i;
+
+ sfp = sfp_alloc(&pdev->dev);
+@@ -2100,7 +2170,7 @@ static int sfp_probe(struct platform_dev
+
+ sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
+ if (!sfp->gpio_irq[i]) {
+- poll = true;
++ sfp->need_poll = true;
+ continue;
+ }
+
+@@ -2112,11 +2182,11 @@ static int sfp_probe(struct platform_dev
+ dev_name(sfp->dev), sfp);
+ if (err) {
+ sfp->gpio_irq[i] = 0;
+- poll = true;
++ sfp->need_poll = true;
+ }
+ }
+
+- if (poll)
++ if (sfp->need_poll)
+ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
+
+ /* We could have an issue in cases no Tx disable pin is available or
+--- a/include/linux/sfp.h
++++ b/include/linux/sfp.h
+@@ -428,6 +428,10 @@ enum {
+ SFP_TEC_CUR = 0x6c,
+
+ SFP_STATUS = 0x6e,
++ SFP_STATUS_TX_DISABLE = BIT(7),
++ SFP_STATUS_TX_DISABLE_FORCE = BIT(6),
++ SFP_STATUS_TX_FAULT = BIT(2),
++ SFP_STATUS_RX_LOS = BIT(1),
+ SFP_ALARM0 = 0x70,
+ SFP_ALARM0_TEMP_HIGH = BIT(7),
+ SFP_ALARM0_TEMP_LOW = BIT(6),