From: Stas Sergeev <stsp@list.ru>
To: Florian Fainelli <f.fainelli@gmail.com>
Cc: netdev <netdev@vger.kernel.org>,
Linux kernel <linux-kernel@vger.kernel.org>,
Stas Sergeev <stsp@users.sourceforge.net>,
Grant Likely <grant.likely@linaro.org>,
Rob Herring <robh+dt@kernel.org>,
"devicetree@vger.kernel.org" <devicetree@vger.kernel.org>,
Thomas Petazzoni <thomas.petazzoni@free-electrons.com>,
Andrew Lunn <andrew@lunn.ch>
Subject: Re: [PATCH 4/6] of: add API for changing parameters of fixed link
Date: Mon, 30 Mar 2015 17:39:13 +0300 [thread overview]
Message-ID: <55196011.7080502@list.ru> (raw)
In-Reply-To: <5515904A.1060600@gmail.com>
27.03.2015 20:15, Florian Fainelli пишет:
> I think your concerns are valid, but I don't think there is going to be
> any problem with the approach I suggested because there is a contract
> that the fixed PHYs and regular PHYs need to
Hello Florian.
As promised, today I tried to resurrect my first implementation
and do things as you suggested: install the link_update callback
for mvneta privately.
I feel SGMII setup is very common and deserves the separate API,
not the per-driver handling, but in any case, I'd like to show
the implementation first, then discuss.
Unfortunately, it didn't work quite right.
The problem is that mvneta calls phy_disconnect() on .ndo_stop
callback. After that, phy->attached_dev becomes NULL, and so the
link_update callback gets called with net_dev==NULL! And crashs.
Of course I can easily work around that, but IMHO its a bug -
the one that actually gets fixed by the patches I posted previously.
They were changing the callback to receive phy_device instead of
net_device, and so NULL will never be passed.
I am attaching the new patch so that you can take a look and decide.
If you still think its fine, even despite the NULL passing w/a, then
I'll mail it with the proper boilerplate. But if you agree that
passing NULL to link_update is a bug, then maybe you'll decide to
get the whole surgery thing. :)
-=-=-=-=-=-=-=-=-=# Don't remove this line #=-=-=-=-=-=-=-=-=-
When MDIO bus is unavailable (common setup for SGMII), the in-band
signaling must be used to correctly track link state.
This patch enables the in-band status delivery for links state changes, namely:
- link up/down
- link speed
- duplex full/half
fixed_phy link_update() callback is used to update status.
Note: SGMII setup is so common that I think it deserves a separate API
rather than the per-driver handling. There is an alternative implementation
that adds such API:
https://lkml.org/lkml/2015/3/27/346
CC: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
CC: Florian Fainelli <f.fainelli@gmail.com>
CC: netdev@vger.kernel.org
CC: linux-kernel@vger.kernel.org
Signed-off-by: Stas Sergeev <stsp@users.sourceforge.net>
---
drivers/net/ethernet/marvell/mvneta.c | 97 +++++++++++++++++++++++++++++----
1 file changed, 86 insertions(+), 11 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 96208f1..5b9cc0a 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -100,6 +100,8 @@
#define MVNETA_TXQ_CMD 0x2448
#define MVNETA_TXQ_DISABLE_SHIFT 8
#define MVNETA_TXQ_ENABLE_MASK 0x000000ff
+#define MVNETA_GMAC_CLOCK_DIVIDER 0x24f4
+#define MVNETA_GMAC_1MS_CLOCK_ENABLE BIT(31)
#define MVNETA_ACC_MODE 0x2500
#define MVNETA_CPU_MAP(cpu) (0x2540 + ((cpu) << 2))
#define MVNETA_CPU_RXQ_ACCESS_ALL_MASK 0x000000ff
@@ -122,6 +124,7 @@
#define MVNETA_TX_INTR_MASK_ALL (0xff << 0)
#define MVNETA_RX_INTR_MASK(nr_rxqs) (((1 << nr_rxqs) - 1) << 8)
#define MVNETA_RX_INTR_MASK_ALL (0xff << 8)
+#define MVNETA_MISCINTR_INTR_MASK BIT(31)
#define MVNETA_INTR_OLD_CAUSE 0x25a8
#define MVNETA_INTR_OLD_MASK 0x25ac
@@ -165,6 +168,7 @@
#define MVNETA_GMAC_MAX_RX_SIZE_MASK 0x7ffc
#define MVNETA_GMAC0_PORT_ENABLE BIT(0)
#define MVNETA_GMAC_CTRL_2 0x2c08
+#define MVNETA_GMAC2_INBAND_AN_ENABLE BIT(0)
#define MVNETA_GMAC2_PCS_ENABLE BIT(3)
#define MVNETA_GMAC2_PORT_RGMII BIT(4)
#define MVNETA_GMAC2_PORT_RESET BIT(6)
@@ -180,9 +184,11 @@
#define MVNETA_GMAC_AUTONEG_CONFIG 0x2c0c
#define MVNETA_GMAC_FORCE_LINK_DOWN BIT(0)
#define MVNETA_GMAC_FORCE_LINK_PASS BIT(1)
+#define MVNETA_GMAC_INBAND_AN_ENABLE BIT(2)
#define MVNETA_GMAC_CONFIG_MII_SPEED BIT(5)
#define MVNETA_GMAC_CONFIG_GMII_SPEED BIT(6)
#define MVNETA_GMAC_AN_SPEED_EN BIT(7)
+#define MVNETA_GMAC_AN_FLOW_CTRL_EN BIT(11)
#define MVNETA_GMAC_CONFIG_FULL_DUPLEX BIT(12)
#define MVNETA_GMAC_AN_DUPLEX_EN BIT(13)
#define MVNETA_MIB_COUNTERS_BASE 0x3080
@@ -304,6 +310,7 @@ struct mvneta_port {
unsigned int link;
unsigned int duplex;
unsigned int speed;
+ int inband_status;
};
/* The mvneta_tx_desc and mvneta_rx_desc structures describe the
@@ -994,6 +1001,20 @@ static void mvneta_defaults_set(struct mvneta_port *pp)
val &= ~MVNETA_PHY_POLLING_ENABLE;
mvreg_write(pp, MVNETA_UNIT_CONTROL, val);
+ if (pp->inband_status) {
+ val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
+ val &= ~(MVNETA_GMAC_FORCE_LINK_PASS |
+ MVNETA_GMAC_FORCE_LINK_DOWN |
+ MVNETA_GMAC_AN_FLOW_CTRL_EN);
+ val |= MVNETA_GMAC_INBAND_AN_ENABLE |
+ MVNETA_GMAC_AN_SPEED_EN |
+ MVNETA_GMAC_AN_DUPLEX_EN;
+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
+ val = mvreg_read(pp, MVNETA_GMAC_CLOCK_DIVIDER);
+ val |= MVNETA_GMAC_1MS_CLOCK_ENABLE;
+ mvreg_write(pp, MVNETA_GMAC_CLOCK_DIVIDER, val);
+ }
+
mvneta_set_ucast_table(pp, -1);
mvneta_set_special_mcast_table(pp, -1);
mvneta_set_other_mcast_table(pp, -1);
@@ -2043,6 +2064,29 @@ static irqreturn_t mvneta_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int mvneta_fixed_link_update(struct net_device *dev,
+ struct fixed_phy_status *status)
+{
+ struct mvneta_port *pp;
+ u32 gmac_stat;
+
+ if (!dev) {
+ /* we have a bug here */
+ return -EINVAL;
+ }
+ pp = netdev_priv(dev);
+ gmac_stat = mvreg_read(pp, MVNETA_GMAC_STATUS);
+ status->link = !!(gmac_stat & MVNETA_GMAC_LINK_UP);
+ if (gmac_stat & MVNETA_GMAC_SPEED_1000)
+ status->speed = SPEED_1000;
+ else if (gmac_stat & MVNETA_GMAC_SPEED_100)
+ status->speed = SPEED_100;
+ else
+ status->speed = SPEED_10;
+ status->duplex = !!(gmac_stat & MVNETA_GMAC_FULL_DUPLEX);
+ return 0;
+}
+
/* NAPI handler
* Bits 0 - 7 of the causeRxTx register indicate that are transmitted
* packets on the corresponding TXQ (Bit 0 is for TX queue 1).
@@ -2063,8 +2107,12 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
}
/* Read cause register */
- cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE) &
- (MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number));
+ cause_rx_tx = mvreg_read(pp, MVNETA_INTR_NEW_CAUSE);
+ if (cause_rx_tx & MVNETA_MISCINTR_INTR_MASK) {
+ /* since phylib uses polling, not much to do here...
+ * Any way to tell phylib to do the poll NOW? */
+ mvreg_write(pp, MVNETA_INTR_MISC_CAUSE, 0);
+ }
/* Release Tx descriptors */
if (cause_rx_tx & MVNETA_TX_INTR_MASK_ALL) {
@@ -2109,7 +2157,9 @@ static int mvneta_poll(struct napi_struct *napi, int budget)
napi_complete(napi);
local_irq_save(flags);
mvreg_write(pp, MVNETA_INTR_NEW_MASK,
- MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number));
+ MVNETA_RX_INTR_MASK(rxq_number) |
+ MVNETA_TX_INTR_MASK(txq_number) |
+ MVNETA_MISCINTR_INTR_MASK);
local_irq_restore(flags);
}
@@ -2373,7 +2423,13 @@ static void mvneta_start_dev(struct mvneta_port *pp)
/* Unmask interrupts */
mvreg_write(pp, MVNETA_INTR_NEW_MASK,
- MVNETA_RX_INTR_MASK(rxq_number) | MVNETA_TX_INTR_MASK(txq_number));
+ MVNETA_RX_INTR_MASK(rxq_number) |
+ MVNETA_TX_INTR_MASK(txq_number) |
+ MVNETA_MISCINTR_INTR_MASK);
+ mvreg_write(pp, MVNETA_INTR_MISC_MASK,
+ MVNETA_CAUSE_PHY_STATUS_CHANGE |
+ MVNETA_CAUSE_LINK_CHANGE |
+ MVNETA_CAUSE_PSC_SYNC_CHANGE);
phy_start(pp->phy_dev);
netif_tx_start_all_queues(pp->dev);
@@ -2523,9 +2579,7 @@ static void mvneta_adjust_link(struct net_device *ndev)
val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
val &= ~(MVNETA_GMAC_CONFIG_MII_SPEED |
MVNETA_GMAC_CONFIG_GMII_SPEED |
- MVNETA_GMAC_CONFIG_FULL_DUPLEX |
- MVNETA_GMAC_AN_SPEED_EN |
- MVNETA_GMAC_AN_DUPLEX_EN);
+ MVNETA_GMAC_CONFIG_FULL_DUPLEX);
if (phydev->duplex)
val |= MVNETA_GMAC_CONFIG_FULL_DUPLEX;
@@ -2554,12 +2608,24 @@ static void mvneta_adjust_link(struct net_device *ndev)
if (status_change) {
if (phydev->link) {
- u32 val = mvreg_read(pp, MVNETA_GMAC_AUTONEG_CONFIG);
- val |= (MVNETA_GMAC_FORCE_LINK_PASS |
- MVNETA_GMAC_FORCE_LINK_DOWN);
- mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
+ if (!pp->inband_status) {
+ u32 val = mvreg_read(pp,
+ MVNETA_GMAC_AUTONEG_CONFIG);
+ val &= ~MVNETA_GMAC_FORCE_LINK_DOWN;
+ val |= MVNETA_GMAC_FORCE_LINK_PASS;
+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
+ val);
+ }
mvneta_port_up(pp);
} else {
+ if (!pp->inband_status) {
+ u32 val = mvreg_read(pp,
+ MVNETA_GMAC_AUTONEG_CONFIG);
+ val &= ~MVNETA_GMAC_FORCE_LINK_PASS;
+ val |= MVNETA_GMAC_FORCE_LINK_DOWN;
+ mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG,
+ val);
+ }
mvneta_port_down(pp);
}
phy_print_status(phydev);
@@ -2910,6 +2976,9 @@ static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
return -EINVAL;
}
+ if (pp->inband_status)
+ ctrl |= MVNETA_GMAC2_INBAND_AN_ENABLE;
+
/* Cancel Port Reset */
ctrl &= ~MVNETA_GMAC2_PORT_RESET;
mvreg_write(pp, MVNETA_GMAC_CTRL_2, ctrl);
@@ -2934,6 +3003,7 @@ static int mvneta_probe(struct platform_device *pdev)
char hw_mac_addr[ETH_ALEN];
const char *mac_from;
int phy_mode;
+ int fixed_phy = 0;
int err;
/* Our multiqueue support is not complete, so for now, only
@@ -2956,6 +3026,7 @@ static int mvneta_probe(struct platform_device *pdev)
phy_node = of_parse_phandle(dn, "phy", 0);
if (!phy_node) {
+ struct phy_device *phy;
if (!of_phy_is_fixed_link(dn)) {
dev_err(&pdev->dev, "no PHY specified\n");
err = -ENODEV;
@@ -2967,11 +3038,14 @@ static int mvneta_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "cannot register fixed PHY\n");
goto err_free_irq;
}
+ fixed_phy = 1;
/* In the case of a fixed PHY, the DT node associated
* to the PHY is the Ethernet MAC DT node.
*/
phy_node = of_node_get(dn);
+ phy = of_phy_find_device(dn);
+ fixed_phy_set_link_update(phy, mvneta_fixed_link_update);
}
phy_mode = of_get_phy_mode(dn);
@@ -2990,6 +3064,7 @@ static int mvneta_probe(struct platform_device *pdev)
pp = netdev_priv(dev);
pp->phy_node = phy_node;
pp->phy_interface = phy_mode;
+ pp->inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) && fixed_phy;
pp->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(pp->clk)) {
--
1.7.9.5
next prev parent reply other threads:[~2015-03-30 14:39 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-03-27 13:28 [PATCH 0/6] mvneta: SGMII-based in-band link state signaling Stas Sergeev
2015-03-27 13:31 ` PATCH 1/6] fixed_phy: pass phy_device instead of net_device to link_update() function Stas Sergeev
2015-03-27 13:33 ` [PATCH 2/6] fixed_phy: add fixed_phy_unregister() Stas Sergeev
2015-03-27 13:34 ` [PATCH 1/6] fixed_phy: pass phy_device instead of net_device to link_update() function Stas Sergeev
2015-03-27 13:35 ` [PATCH 3/6] of_mdio: restructure of_phy_register_fixed_link() for further modifications Stas Sergeev
2015-03-27 13:37 ` [PATCH 4/6] of: add API for changing parameters of fixed link Stas Sergeev
[not found] ` <55155D35.1070703-cmBhpYW9OiY@public.gmane.org>
2015-03-27 15:41 ` Florian Fainelli
2015-03-27 15:41 ` Florian Fainelli
2015-03-27 16:07 ` Stas Sergeev
2015-03-27 16:21 ` Florian Fainelli
[not found] ` <CAGVrzcaLfQcTAx8OR=sE=7FLrp0gGvfX8_YfxK_CU+x26JHymw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2015-03-27 16:39 ` Stas Sergeev
2015-03-27 16:39 ` Stas Sergeev
2015-03-27 17:15 ` Florian Fainelli
2015-03-27 17:31 ` Stas Sergeev
2015-03-30 14:39 ` Stas Sergeev [this message]
2015-03-30 16:06 ` Florian Fainelli
2015-03-30 17:04 ` Stas Sergeev
2015-03-31 17:11 ` Stas Sergeev
2015-03-27 13:39 ` [PATCH 0/6] mvneta: SGMII-based in-band link state signaling Andrew Lunn
2015-03-27 13:52 ` Stas Sergeev
2015-03-27 13:59 ` Andrew Lunn
2015-03-27 14:20 ` Stas Sergeev
2015-03-27 15:44 ` Florian Fainelli
2015-03-27 13:39 ` [PATCH 5/6] mvneta: implement " Stas Sergeev
2015-07-08 16:30 ` [5/6] " Sebastien Rannou
2015-07-08 16:51 ` Stas Sergeev
2015-07-09 9:03 ` Sebastien Rannou
2015-07-09 9:19 ` Thomas Petazzoni
2015-07-09 10:11 ` Stas Sergeev
2015-03-27 13:40 ` [PATCH 6/6] mvneta: port marvell's official in-band status enabling procedure Stas Sergeev
-- strict thread matches above, loose matches on Subject: below --
2015-03-26 15:56 [PATCH 0/6] mvneta: SGMII-based in-band link status signaling Stas Sergeev
2015-03-26 15:58 ` [PATCH 1/6] restructure of_phy_register_fixed_link() for further modifications Stas Sergeev
2015-03-26 16:00 ` [PATCH 2/6] pass phy_device instead of net_device to fixed_phy link_update() function Stas Sergeev
2015-03-26 16:01 ` [PATCH 3/6] fixed_phy: add fixed_phy_unregister() Stas Sergeev
2015-03-26 16:02 ` [PATCH 4/6] of: add API for changing parameters of fixed link Stas Sergeev
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55196011.7080502@list.ru \
--to=stsp@list.ru \
--cc=andrew@lunn.ch \
--cc=devicetree@vger.kernel.org \
--cc=f.fainelli@gmail.com \
--cc=grant.likely@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=netdev@vger.kernel.org \
--cc=robh+dt@kernel.org \
--cc=stsp@users.sourceforge.net \
--cc=thomas.petazzoni@free-electrons.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.