mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
net: freescale: ucc_geth: phylink conversion
ucc_geth is quite capable in terms of supported interfaces, and even includes an externally controlled PCS (well, TBI). Port that driver to phylink. Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
02d4a6498b
commit
53036aa8d0
|
|
@ -81,8 +81,7 @@ config UCC_GETH
|
||||||
tristate "Freescale QE Gigabit Ethernet"
|
tristate "Freescale QE Gigabit Ethernet"
|
||||||
depends on QUICC_ENGINE && PPC32
|
depends on QUICC_ENGINE && PPC32
|
||||||
select FSL_PQ_MDIO
|
select FSL_PQ_MDIO
|
||||||
select PHYLIB
|
select PHYLINK
|
||||||
select FIXED_PHY
|
|
||||||
help
|
help
|
||||||
This driver supports the Gigabit Ethernet mode of the QUICC Engine,
|
This driver supports the Gigabit Ethernet mode of the QUICC Engine,
|
||||||
which is available on some Freescale SOCs.
|
which is available on some Freescale SOCs.
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/mii.h>
|
#include <linux/mii.h>
|
||||||
#include <linux/phy.h>
|
#include <linux/phy.h>
|
||||||
#include <linux/phy_fixed.h>
|
#include <linux/phylink.h>
|
||||||
#include <linux/workqueue.h>
|
#include <linux/workqueue.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_address.h>
|
#include <linux/of_address.h>
|
||||||
|
|
@ -34,6 +34,7 @@
|
||||||
#include <linux/of_mdio.h>
|
#include <linux/of_mdio.h>
|
||||||
#include <linux/of_net.h>
|
#include <linux/of_net.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/rtnetlink.h>
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
#include <asm/irq.h>
|
#include <asm/irq.h>
|
||||||
|
|
@ -1265,84 +1266,6 @@ static bool phy_interface_mode_is_reduced(phy_interface_t interface)
|
||||||
interface == PHY_INTERFACE_MODE_RTBI;
|
interface == PHY_INTERFACE_MODE_RTBI;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int adjust_enet_interface(struct ucc_geth_private *ugeth)
|
|
||||||
{
|
|
||||||
struct ucc_geth_info *ug_info;
|
|
||||||
struct ucc_geth __iomem *ug_regs;
|
|
||||||
struct ucc_fast __iomem *uf_regs;
|
|
||||||
u32 upsmr, maccfg2;
|
|
||||||
u16 value;
|
|
||||||
|
|
||||||
ugeth_vdbg("%s: IN", __func__);
|
|
||||||
|
|
||||||
ug_info = ugeth->ug_info;
|
|
||||||
ug_regs = ugeth->ug_regs;
|
|
||||||
uf_regs = ugeth->uccf->uf_regs;
|
|
||||||
|
|
||||||
/* Set MACCFG2 */
|
|
||||||
maccfg2 = in_be32(&ug_regs->maccfg2);
|
|
||||||
|
|
||||||
/* Disable frame length check */
|
|
||||||
maccfg2 &= ~MACCFG2_LC;
|
|
||||||
maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
|
|
||||||
if ((ugeth->max_speed == SPEED_10) ||
|
|
||||||
(ugeth->max_speed == SPEED_100))
|
|
||||||
maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
|
|
||||||
else if (ugeth->max_speed == SPEED_1000)
|
|
||||||
maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
|
|
||||||
maccfg2 |= ug_info->padAndCrc;
|
|
||||||
out_be32(&ug_regs->maccfg2, maccfg2);
|
|
||||||
|
|
||||||
/* Set UPSMR */
|
|
||||||
upsmr = in_be32(&uf_regs->upsmr);
|
|
||||||
upsmr &= ~(UCC_GETH_UPSMR_RPM | UCC_GETH_UPSMR_R10M |
|
|
||||||
UCC_GETH_UPSMR_TBIM | UCC_GETH_UPSMR_RMM);
|
|
||||||
if (phy_interface_mode_is_reduced(ugeth->phy_interface)) {
|
|
||||||
if (ugeth->phy_interface != PHY_INTERFACE_MODE_RMII)
|
|
||||||
upsmr |= UCC_GETH_UPSMR_RPM;
|
|
||||||
switch (ugeth->max_speed) {
|
|
||||||
case SPEED_10:
|
|
||||||
upsmr |= UCC_GETH_UPSMR_R10M;
|
|
||||||
fallthrough;
|
|
||||||
case SPEED_100:
|
|
||||||
if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI)
|
|
||||||
upsmr |= UCC_GETH_UPSMR_RMM;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
|
|
||||||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
|
|
||||||
upsmr |= UCC_GETH_UPSMR_TBIM;
|
|
||||||
}
|
|
||||||
if (ugeth->phy_interface == PHY_INTERFACE_MODE_SGMII)
|
|
||||||
upsmr |= UCC_GETH_UPSMR_SGMM;
|
|
||||||
|
|
||||||
out_be32(&uf_regs->upsmr, upsmr);
|
|
||||||
|
|
||||||
/* Disable autonegotiation in tbi mode, because by default it
|
|
||||||
comes up in autonegotiation mode. */
|
|
||||||
/* Note that this depends on proper setting in utbipar register. */
|
|
||||||
if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) ||
|
|
||||||
(ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) {
|
|
||||||
struct ucc_geth_info *ug_info = ugeth->ug_info;
|
|
||||||
struct phy_device *tbiphy;
|
|
||||||
|
|
||||||
if (!ug_info->tbi_node)
|
|
||||||
pr_warn("TBI mode requires that the device tree specify a tbi-handle\n");
|
|
||||||
|
|
||||||
tbiphy = of_phy_find_device(ug_info->tbi_node);
|
|
||||||
if (!tbiphy)
|
|
||||||
pr_warn("Could not get TBI device\n");
|
|
||||||
|
|
||||||
value = phy_read(tbiphy, ENET_TBI_MII_CR);
|
|
||||||
value &= ~0x1000; /* Turn off autonegotiation */
|
|
||||||
phy_write(tbiphy, ENET_TBI_MII_CR, value);
|
|
||||||
|
|
||||||
put_device(&tbiphy->mdio.dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
|
static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth)
|
||||||
{
|
{
|
||||||
struct ucc_fast_private *uccf;
|
struct ucc_fast_private *uccf;
|
||||||
|
|
@ -1560,64 +1483,62 @@ static void uec_configure_serdes(struct net_device *dev)
|
||||||
put_device(&tbiphy->mdio.dev);
|
put_device(&tbiphy->mdio.dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ugeth_link_up(struct ucc_geth_private *ugeth,
|
static void ugeth_mac_link_up(struct phylink_config *config, struct phy_device *phy,
|
||||||
struct phy_device *phy,
|
unsigned int mode, phy_interface_t interface,
|
||||||
phy_interface_t interface, int speed, int duplex)
|
int speed, int duplex, bool tx_pause, bool rx_pause)
|
||||||
{
|
{
|
||||||
|
struct net_device *ndev = to_net_dev(config->dev);
|
||||||
|
struct ucc_geth_private *ugeth = netdev_priv(ndev);
|
||||||
|
struct ucc_geth_info *ug_info = ugeth->ug_info;
|
||||||
struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
|
struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
|
||||||
struct ucc_fast __iomem *uf_regs = ugeth->uccf->uf_regs;
|
struct ucc_fast __iomem *uf_regs = ugeth->uccf->uf_regs;
|
||||||
u32 tempval = in_be32(&ug_regs->maccfg2);
|
u32 old_maccfg2, maccfg2 = in_be32(&ug_regs->maccfg2);
|
||||||
u32 upsmr = in_be32(&uf_regs->upsmr);
|
u32 old_upsmr, upsmr = in_be32(&uf_regs->upsmr);
|
||||||
int new_state = 0;
|
|
||||||
|
|
||||||
/* Now we make sure that we can be in full duplex mode.
|
old_maccfg2 = maccfg2;
|
||||||
* If not, we operate in half-duplex mode.
|
old_upsmr = upsmr;
|
||||||
*/
|
|
||||||
if (duplex != ugeth->oldduplex) {
|
/* No length check */
|
||||||
new_state = 1;
|
maccfg2 &= ~MACCFG2_LC;
|
||||||
if (duplex == DUPLEX_HALF)
|
maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK;
|
||||||
tempval &= ~(MACCFG2_FDX);
|
upsmr &= ~(UCC_GETH_UPSMR_RPM | UCC_GETH_UPSMR_R10M |
|
||||||
else
|
UCC_GETH_UPSMR_TBIM | UCC_GETH_UPSMR_RMM);
|
||||||
tempval |= MACCFG2_FDX;
|
|
||||||
ugeth->oldduplex = duplex;
|
if (speed == SPEED_10 || speed == SPEED_100)
|
||||||
}
|
maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE;
|
||||||
|
else if (speed == SPEED_1000)
|
||||||
|
maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE;
|
||||||
|
|
||||||
|
maccfg2 |= ug_info->padAndCrc;
|
||||||
|
|
||||||
|
if (phy_interface_mode_is_reduced(interface)) {
|
||||||
|
|
||||||
|
if (interface != PHY_INTERFACE_MODE_RMII)
|
||||||
|
upsmr |= UCC_GETH_UPSMR_RPM;
|
||||||
|
|
||||||
if (speed != ugeth->oldspeed) {
|
|
||||||
new_state = 1;
|
|
||||||
switch (speed) {
|
switch (speed) {
|
||||||
case SPEED_1000:
|
|
||||||
tempval = ((tempval &
|
|
||||||
~(MACCFG2_INTERFACE_MODE_MASK)) |
|
|
||||||
MACCFG2_INTERFACE_MODE_BYTE);
|
|
||||||
break;
|
|
||||||
case SPEED_100:
|
|
||||||
case SPEED_10:
|
case SPEED_10:
|
||||||
tempval = ((tempval &
|
upsmr |= UCC_GETH_UPSMR_R10M;
|
||||||
~(MACCFG2_INTERFACE_MODE_MASK)) |
|
fallthrough;
|
||||||
MACCFG2_INTERFACE_MODE_NIBBLE);
|
case SPEED_100:
|
||||||
/* if reduced mode, re-set UPSMR.R10M */
|
if (interface != PHY_INTERFACE_MODE_RTBI)
|
||||||
if (phy_interface_mode_is_reduced(interface)) {
|
upsmr |= UCC_GETH_UPSMR_RMM;
|
||||||
if (speed == SPEED_10)
|
|
||||||
upsmr |= UCC_GETH_UPSMR_R10M;
|
|
||||||
else
|
|
||||||
upsmr &= ~UCC_GETH_UPSMR_R10M;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (netif_msg_link(ugeth))
|
|
||||||
pr_warn("%s: Speed (%d) is not 10/100/1000!",
|
|
||||||
netdev_name(ugeth->ndev), speed);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
ugeth->oldspeed = speed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ugeth->oldlink) {
|
if (interface == PHY_INTERFACE_MODE_TBI ||
|
||||||
new_state = 1;
|
interface == PHY_INTERFACE_MODE_RTBI)
|
||||||
ugeth->oldlink = 1;
|
upsmr |= UCC_GETH_UPSMR_TBIM;
|
||||||
}
|
|
||||||
|
|
||||||
if (new_state) {
|
if (interface == PHY_INTERFACE_MODE_SGMII)
|
||||||
|
upsmr |= UCC_GETH_UPSMR_SGMM;
|
||||||
|
|
||||||
|
if (duplex == DUPLEX_HALF)
|
||||||
|
maccfg2 &= ~(MACCFG2_FDX);
|
||||||
|
else
|
||||||
|
maccfg2 |= MACCFG2_FDX;
|
||||||
|
|
||||||
|
if (maccfg2 != old_maccfg2 || upsmr != old_upsmr) {
|
||||||
/*
|
/*
|
||||||
* To change the MAC configuration we need to disable
|
* To change the MAC configuration we need to disable
|
||||||
* the controller. To do so, we have to either grab
|
* the controller. To do so, we have to either grab
|
||||||
|
|
@ -1628,69 +1549,79 @@ static void ugeth_link_up(struct ucc_geth_private *ugeth,
|
||||||
ugeth_quiesce(ugeth);
|
ugeth_quiesce(ugeth);
|
||||||
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
|
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
|
||||||
|
|
||||||
out_be32(&ug_regs->maccfg2, tempval);
|
out_be32(&ug_regs->maccfg2, maccfg2);
|
||||||
out_be32(&uf_regs->upsmr, upsmr);
|
out_be32(&uf_regs->upsmr, upsmr);
|
||||||
|
|
||||||
ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
|
ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
|
||||||
ugeth_activate(ugeth);
|
ugeth_activate(ugeth);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (netif_msg_link(ugeth))
|
if (interface == PHY_INTERFACE_MODE_SGMII)
|
||||||
phy_print_status(phy);
|
uec_configure_serdes(ndev);
|
||||||
}
|
|
||||||
|
|
||||||
static void ugeth_link_down(struct ucc_geth_private *ugeth)
|
if (!phylink_autoneg_inband(mode)) {
|
||||||
{
|
ug_info->aufc = 0;
|
||||||
ugeth->oldlink = 0;
|
ug_info->receiveFlowControl = rx_pause;
|
||||||
ugeth->oldspeed = 0;
|
ug_info->transmitFlowControl = tx_pause;
|
||||||
ugeth->oldduplex = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called every time the controller might need to be made
|
init_flow_control_params(ug_info->aufc,
|
||||||
* aware of new link state. The PHY code conveys this
|
ug_info->receiveFlowControl,
|
||||||
* information through variables in the ugeth structure, and this
|
ug_info->transmitFlowControl,
|
||||||
* function converts those variables into the appropriate
|
ug_info->pausePeriod,
|
||||||
* register values, and can bring down the device if needed.
|
ug_info->extensionField,
|
||||||
*/
|
&ugeth->uccf->uf_regs->upsmr,
|
||||||
|
&ugeth->ug_regs->uempr,
|
||||||
static void adjust_link(struct net_device *dev)
|
&ugeth->ug_regs->maccfg1);
|
||||||
{
|
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(dev);
|
|
||||||
struct phy_device *phydev = dev->phydev;
|
|
||||||
|
|
||||||
if (phydev->link)
|
|
||||||
ugeth_link_up(ugeth, phydev, phydev->interface,
|
|
||||||
phydev->speed, phydev->duplex);
|
|
||||||
else
|
|
||||||
ugeth_link_down(ugeth);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Configure the PHY for dev.
|
|
||||||
* returns 0 if success. -1 if failure
|
|
||||||
*/
|
|
||||||
static int init_phy(struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct ucc_geth_private *priv = netdev_priv(dev);
|
|
||||||
struct ucc_geth_info *ug_info = priv->ug_info;
|
|
||||||
struct phy_device *phydev;
|
|
||||||
|
|
||||||
priv->oldlink = 0;
|
|
||||||
priv->oldspeed = 0;
|
|
||||||
priv->oldduplex = -1;
|
|
||||||
|
|
||||||
phydev = of_phy_connect(dev, ug_info->phy_node, &adjust_link, 0,
|
|
||||||
priv->phy_interface);
|
|
||||||
if (!phydev) {
|
|
||||||
dev_err(&dev->dev, "Could not attach to PHY\n");
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->phy_interface == PHY_INTERFACE_MODE_SGMII)
|
ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
|
||||||
uec_configure_serdes(dev);
|
}
|
||||||
|
|
||||||
phy_set_max_speed(phydev, priv->max_speed);
|
static void ugeth_mac_link_down(struct phylink_config *config,
|
||||||
|
unsigned int mode, phy_interface_t interface)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = to_net_dev(config->dev);
|
||||||
|
struct ucc_geth_private *ugeth = netdev_priv(ndev);
|
||||||
|
|
||||||
return 0;
|
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ugeth_mac_config(struct phylink_config *config, unsigned int mode,
|
||||||
|
const struct phylink_link_state *state)
|
||||||
|
{
|
||||||
|
struct net_device *ndev = to_net_dev(config->dev);
|
||||||
|
struct ucc_geth_private *ugeth = netdev_priv(ndev);
|
||||||
|
struct ucc_geth_info *ug_info = ugeth->ug_info;
|
||||||
|
u16 value;
|
||||||
|
|
||||||
|
if (state->interface == PHY_INTERFACE_MODE_TBI ||
|
||||||
|
state->interface == PHY_INTERFACE_MODE_RTBI) {
|
||||||
|
struct phy_device *tbiphy;
|
||||||
|
|
||||||
|
if (!ug_info->tbi_node)
|
||||||
|
pr_warn("TBI mode requires that the device tree specify a tbi-handle\n");
|
||||||
|
|
||||||
|
tbiphy = of_phy_find_device(ug_info->tbi_node);
|
||||||
|
if (!tbiphy)
|
||||||
|
pr_warn("Could not get TBI device\n");
|
||||||
|
|
||||||
|
value = phy_read(tbiphy, ENET_TBI_MII_CR);
|
||||||
|
value &= ~0x1000; /* Turn off autonegotiation */
|
||||||
|
phy_write(tbiphy, ENET_TBI_MII_CR, value);
|
||||||
|
|
||||||
|
put_device(&tbiphy->mdio.dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (phylink_autoneg_inband(mode)) {
|
||||||
|
ug_info->aufc = 1;
|
||||||
|
|
||||||
|
init_flow_control_params(ug_info->aufc, 1, 1,
|
||||||
|
ug_info->pausePeriod,
|
||||||
|
ug_info->extensionField,
|
||||||
|
&ugeth->uccf->uf_regs->upsmr,
|
||||||
|
&ugeth->ug_regs->uempr,
|
||||||
|
&ugeth->ug_regs->maccfg1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ugeth_dump_regs(struct ucc_geth_private *ugeth)
|
static void ugeth_dump_regs(struct ucc_geth_private *ugeth)
|
||||||
|
|
@ -1962,7 +1893,6 @@ static void ucc_geth_set_multi(struct net_device *dev)
|
||||||
static void ucc_geth_stop(struct ucc_geth_private *ugeth)
|
static void ucc_geth_stop(struct ucc_geth_private *ugeth)
|
||||||
{
|
{
|
||||||
struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
|
struct ucc_geth __iomem *ug_regs = ugeth->ug_regs;
|
||||||
struct phy_device *phydev = ugeth->ndev->phydev;
|
|
||||||
|
|
||||||
ugeth_vdbg("%s: IN", __func__);
|
ugeth_vdbg("%s: IN", __func__);
|
||||||
|
|
||||||
|
|
@ -1971,7 +1901,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth)
|
||||||
* Must be done before disabling the controller
|
* Must be done before disabling the controller
|
||||||
* or deadlock may happen.
|
* or deadlock may happen.
|
||||||
*/
|
*/
|
||||||
phy_stop(phydev);
|
phylink_stop(ugeth->phylink);
|
||||||
|
|
||||||
/* Disable the controller */
|
/* Disable the controller */
|
||||||
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
|
ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
|
||||||
|
|
@ -3213,12 +3143,6 @@ static int ucc_geth_init_mac(struct ucc_geth_private *ugeth)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = adjust_enet_interface(ugeth);
|
|
||||||
if (err) {
|
|
||||||
netif_err(ugeth, ifup, dev, "Cannot configure net device, aborting\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set MACSTNADDR1, MACSTNADDR2 */
|
/* Set MACSTNADDR1, MACSTNADDR2 */
|
||||||
/* For more details see the hardware spec. */
|
/* For more details see the hardware spec. */
|
||||||
init_mac_station_addr_regs(dev->dev_addr[0],
|
init_mac_station_addr_regs(dev->dev_addr[0],
|
||||||
|
|
@ -3230,12 +3154,6 @@ static int ucc_geth_init_mac(struct ucc_geth_private *ugeth)
|
||||||
&ugeth->ug_regs->macstnaddr1,
|
&ugeth->ug_regs->macstnaddr1,
|
||||||
&ugeth->ug_regs->macstnaddr2);
|
&ugeth->ug_regs->macstnaddr2);
|
||||||
|
|
||||||
err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
|
|
||||||
if (err) {
|
|
||||||
netif_err(ugeth, ifup, dev, "Cannot enable net device, aborting\n");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
err:
|
err:
|
||||||
ucc_geth_stop(ugeth);
|
ucc_geth_stop(ugeth);
|
||||||
|
|
@ -3258,10 +3176,10 @@ static int ucc_geth_open(struct net_device *dev)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = init_phy(dev);
|
err = phylink_of_phy_connect(ugeth->phylink, ugeth->dev->of_node, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
netif_err(ugeth, ifup, dev, "Cannot initialize PHY, aborting\n");
|
dev_err(&dev->dev, "Could not attach to PHY\n");
|
||||||
return err;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ucc_geth_init_mac(ugeth);
|
err = ucc_geth_init_mac(ugeth);
|
||||||
|
|
@ -3277,7 +3195,7 @@ static int ucc_geth_open(struct net_device *dev)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
phy_start(dev->phydev);
|
phylink_start(ugeth->phylink);
|
||||||
napi_enable(&ugeth->napi);
|
napi_enable(&ugeth->napi);
|
||||||
netdev_reset_queue(dev);
|
netdev_reset_queue(dev);
|
||||||
netif_start_queue(dev);
|
netif_start_queue(dev);
|
||||||
|
|
@ -3304,7 +3222,7 @@ static int ucc_geth_close(struct net_device *dev)
|
||||||
|
|
||||||
cancel_work_sync(&ugeth->timeout_work);
|
cancel_work_sync(&ugeth->timeout_work);
|
||||||
ucc_geth_stop(ugeth);
|
ucc_geth_stop(ugeth);
|
||||||
phy_disconnect(dev->phydev);
|
phylink_disconnect_phy(ugeth->phylink);
|
||||||
|
|
||||||
free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
|
free_irq(ugeth->ug_info->uf_info.irq, ugeth->ndev);
|
||||||
|
|
||||||
|
|
@ -3338,7 +3256,7 @@ static void ucc_geth_timeout_work(struct work_struct *work)
|
||||||
ucc_geth_stop(ugeth);
|
ucc_geth_stop(ugeth);
|
||||||
ucc_geth_init_mac(ugeth);
|
ucc_geth_init_mac(ugeth);
|
||||||
/* Must start PHY here */
|
/* Must start PHY here */
|
||||||
phy_start(dev->phydev);
|
phylink_start(ugeth->phylink);
|
||||||
netif_tx_start_all_queues(dev);
|
netif_tx_start_all_queues(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3363,6 +3281,7 @@ static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state)
|
||||||
{
|
{
|
||||||
struct net_device *ndev = platform_get_drvdata(ofdev);
|
struct net_device *ndev = platform_get_drvdata(ofdev);
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(ndev);
|
struct ucc_geth_private *ugeth = netdev_priv(ndev);
|
||||||
|
bool mac_wol = false;
|
||||||
|
|
||||||
if (!netif_running(ndev))
|
if (!netif_running(ndev))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -3380,10 +3299,13 @@ static int ucc_geth_suspend(struct platform_device *ofdev, pm_message_t state)
|
||||||
setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
|
setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
|
||||||
setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
|
setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
|
||||||
ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX);
|
ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX);
|
||||||
} else if (!ugeth->phy_wol_en) {
|
mac_wol = true;
|
||||||
phy_stop(ndev->phydev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rtnl_lock();
|
||||||
|
phylink_suspend(ugeth->phylink, mac_wol);
|
||||||
|
rtnl_unlock();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3417,12 +3339,9 @@ static int ucc_geth_resume(struct platform_device *ofdev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ugeth->oldlink = 0;
|
rtnl_lock();
|
||||||
ugeth->oldspeed = 0;
|
phylink_resume(ugeth->phylink);
|
||||||
ugeth->oldduplex = -1;
|
rtnl_unlock();
|
||||||
|
|
||||||
phy_stop(ndev->phydev);
|
|
||||||
phy_start(ndev->phydev);
|
|
||||||
|
|
||||||
napi_enable(&ugeth->napi);
|
napi_enable(&ugeth->napi);
|
||||||
netif_device_attach(ndev);
|
netif_device_attach(ndev);
|
||||||
|
|
@ -3437,13 +3356,12 @@ static int ucc_geth_resume(struct platform_device *ofdev)
|
||||||
|
|
||||||
static int ucc_geth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
static int ucc_geth_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
|
||||||
{
|
{
|
||||||
|
struct ucc_geth_private *ugeth = netdev_priv(dev);
|
||||||
|
|
||||||
if (!netif_running(dev))
|
if (!netif_running(dev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!dev->phydev)
|
return phylink_mii_ioctl(ugeth->phylink, rq, cmd);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return phy_mii_ioctl(dev->phydev, rq, cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct net_device_ops ucc_geth_netdev_ops = {
|
static const struct net_device_ops ucc_geth_netdev_ops = {
|
||||||
|
|
@ -3451,7 +3369,6 @@ static const struct net_device_ops ucc_geth_netdev_ops = {
|
||||||
.ndo_stop = ucc_geth_close,
|
.ndo_stop = ucc_geth_close,
|
||||||
.ndo_start_xmit = ucc_geth_start_xmit,
|
.ndo_start_xmit = ucc_geth_start_xmit,
|
||||||
.ndo_validate_addr = eth_validate_addr,
|
.ndo_validate_addr = eth_validate_addr,
|
||||||
.ndo_change_carrier = fixed_phy_change_carrier,
|
|
||||||
.ndo_set_mac_address = ucc_geth_set_mac_addr,
|
.ndo_set_mac_address = ucc_geth_set_mac_addr,
|
||||||
.ndo_set_rx_mode = ucc_geth_set_multi,
|
.ndo_set_rx_mode = ucc_geth_set_multi,
|
||||||
.ndo_tx_timeout = ucc_geth_timeout,
|
.ndo_tx_timeout = ucc_geth_timeout,
|
||||||
|
|
@ -3491,6 +3408,12 @@ static int ucc_geth_parse_clock(struct device_node *np, const char *which,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct phylink_mac_ops ugeth_mac_ops = {
|
||||||
|
.mac_link_up = ugeth_mac_link_up,
|
||||||
|
.mac_link_down = ugeth_mac_link_down,
|
||||||
|
.mac_config = ugeth_mac_config,
|
||||||
|
};
|
||||||
|
|
||||||
static int ucc_geth_probe(struct platform_device* ofdev)
|
static int ucc_geth_probe(struct platform_device* ofdev)
|
||||||
{
|
{
|
||||||
struct device *device = &ofdev->dev;
|
struct device *device = &ofdev->dev;
|
||||||
|
|
@ -3498,8 +3421,10 @@ static int ucc_geth_probe(struct platform_device* ofdev)
|
||||||
struct net_device *dev = NULL;
|
struct net_device *dev = NULL;
|
||||||
struct ucc_geth_private *ugeth = NULL;
|
struct ucc_geth_private *ugeth = NULL;
|
||||||
struct ucc_geth_info *ug_info;
|
struct ucc_geth_info *ug_info;
|
||||||
|
struct device_node *phy_node;
|
||||||
|
struct phylink *phylink;
|
||||||
struct resource res;
|
struct resource res;
|
||||||
int err, ucc_num, max_speed = 0;
|
int err, ucc_num;
|
||||||
const unsigned int *prop;
|
const unsigned int *prop;
|
||||||
phy_interface_t phy_interface;
|
phy_interface_t phy_interface;
|
||||||
|
|
||||||
|
|
@ -3537,57 +3462,35 @@ static int ucc_geth_probe(struct platform_device* ofdev)
|
||||||
ug_info->uf_info.regs = res.start;
|
ug_info->uf_info.regs = res.start;
|
||||||
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
|
ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
|
||||||
|
|
||||||
ug_info->phy_node = of_parse_phandle(np, "phy-handle", 0);
|
|
||||||
if (!ug_info->phy_node && of_phy_is_fixed_link(np)) {
|
|
||||||
/*
|
|
||||||
* In the case of a fixed PHY, the DT node associated
|
|
||||||
* to the PHY is the Ethernet MAC DT node.
|
|
||||||
*/
|
|
||||||
err = of_phy_register_fixed_link(np);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
ug_info->phy_node = of_node_get(np);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the TBI PHY node. If it's not there, we don't support SGMII */
|
/* Find the TBI PHY node. If it's not there, we don't support SGMII */
|
||||||
ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
|
ug_info->tbi_node = of_parse_phandle(np, "tbi-handle", 0);
|
||||||
|
|
||||||
prop = of_get_property(ug_info->phy_node, "interface", NULL);
|
phy_node = of_parse_phandle(np, "phy-handle", 0);
|
||||||
if (prop) {
|
if (phy_node) {
|
||||||
dev_err(&ofdev->dev,
|
prop = of_get_property(phy_node, "interface", NULL);
|
||||||
"Device-tree property 'interface' is no longer supported. Please use 'phy-connection-type' instead.");
|
if (prop) {
|
||||||
err = -EINVAL;
|
dev_err(&ofdev->dev,
|
||||||
goto err_deregister_fixed_link;
|
"Device-tree property 'interface' is no longer supported. Please use 'phy-connection-type' instead.");
|
||||||
|
of_node_put(phy_node);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto err_put_tbi;
|
||||||
|
}
|
||||||
|
of_node_put(phy_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = of_get_phy_mode(np, &phy_interface);
|
err = of_get_phy_mode(np, &phy_interface);
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&ofdev->dev, "Invalid phy-connection-type");
|
dev_err(&ofdev->dev, "Invalid phy-connection-type");
|
||||||
goto err_deregister_fixed_link;
|
goto err_put_tbi;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* get speed, or derive from PHY interface */
|
if (phy_interface == PHY_INTERFACE_MODE_GMII ||
|
||||||
if (max_speed == 0)
|
phy_interface_mode_is_rgmii(phy_interface) ||
|
||||||
switch (phy_interface) {
|
phy_interface == PHY_INTERFACE_MODE_TBI ||
|
||||||
case PHY_INTERFACE_MODE_GMII:
|
phy_interface == PHY_INTERFACE_MODE_RTBI ||
|
||||||
case PHY_INTERFACE_MODE_RGMII:
|
phy_interface == PHY_INTERFACE_MODE_SGMII) {
|
||||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
|
||||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
|
||||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
|
||||||
case PHY_INTERFACE_MODE_TBI:
|
|
||||||
case PHY_INTERFACE_MODE_RTBI:
|
|
||||||
case PHY_INTERFACE_MODE_SGMII:
|
|
||||||
max_speed = SPEED_1000;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
max_speed = SPEED_100;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (max_speed == SPEED_1000) {
|
|
||||||
unsigned int snums = qe_get_num_of_snums();
|
unsigned int snums = qe_get_num_of_snums();
|
||||||
|
|
||||||
/* configure muram FIFOs for gigabit operation */
|
|
||||||
ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
|
ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT;
|
||||||
ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
|
ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT;
|
||||||
ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT;
|
ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT;
|
||||||
|
|
@ -3616,7 +3519,7 @@ static int ucc_geth_probe(struct platform_device* ofdev)
|
||||||
dev = devm_alloc_etherdev(&ofdev->dev, sizeof(*ugeth));
|
dev = devm_alloc_etherdev(&ofdev->dev, sizeof(*ugeth));
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto err_deregister_fixed_link;
|
goto err_put_tbi;
|
||||||
}
|
}
|
||||||
|
|
||||||
ugeth = netdev_priv(dev);
|
ugeth = netdev_priv(dev);
|
||||||
|
|
@ -3643,23 +3546,50 @@ static int ucc_geth_probe(struct platform_device* ofdev)
|
||||||
dev->max_mtu = 1518;
|
dev->max_mtu = 1518;
|
||||||
|
|
||||||
ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
|
ugeth->msg_enable = netif_msg_init(debug.msg_enable, UGETH_MSG_DEFAULT);
|
||||||
ugeth->phy_interface = phy_interface;
|
|
||||||
ugeth->max_speed = max_speed;
|
|
||||||
|
|
||||||
/* Carrier starts down, phylib will bring it up */
|
ugeth->phylink_config.dev = &dev->dev;
|
||||||
netif_carrier_off(dev);
|
ugeth->phylink_config.type = PHYLINK_NETDEV;
|
||||||
|
|
||||||
|
ugeth->phylink_config.mac_capabilities =
|
||||||
|
MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000FD;
|
||||||
|
|
||||||
|
__set_bit(PHY_INTERFACE_MODE_MII,
|
||||||
|
ugeth->phylink_config.supported_interfaces);
|
||||||
|
__set_bit(PHY_INTERFACE_MODE_RMII,
|
||||||
|
ugeth->phylink_config.supported_interfaces);
|
||||||
|
__set_bit(PHY_INTERFACE_MODE_GMII,
|
||||||
|
ugeth->phylink_config.supported_interfaces);
|
||||||
|
phy_interface_set_rgmii(ugeth->phylink_config.supported_interfaces);
|
||||||
|
|
||||||
|
if (ug_info->tbi_node) {
|
||||||
|
__set_bit(PHY_INTERFACE_MODE_SGMII,
|
||||||
|
ugeth->phylink_config.supported_interfaces);
|
||||||
|
__set_bit(PHY_INTERFACE_MODE_TBI,
|
||||||
|
ugeth->phylink_config.supported_interfaces);
|
||||||
|
__set_bit(PHY_INTERFACE_MODE_RTBI,
|
||||||
|
ugeth->phylink_config.supported_interfaces);
|
||||||
|
}
|
||||||
|
|
||||||
|
phylink = phylink_create(&ugeth->phylink_config, dev_fwnode(&dev->dev),
|
||||||
|
phy_interface, &ugeth_mac_ops);
|
||||||
|
if (IS_ERR(phylink)) {
|
||||||
|
err = PTR_ERR(phylink);
|
||||||
|
goto err_put_tbi;
|
||||||
|
}
|
||||||
|
|
||||||
|
ugeth->phylink = phylink;
|
||||||
|
|
||||||
err = devm_register_netdev(&ofdev->dev, dev);
|
err = devm_register_netdev(&ofdev->dev, dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
if (netif_msg_probe(ugeth))
|
if (netif_msg_probe(ugeth))
|
||||||
pr_err("%s: Cannot register net device, aborting\n",
|
pr_err("%s: Cannot register net device, aborting\n",
|
||||||
dev->name);
|
dev->name);
|
||||||
goto err_deregister_fixed_link;
|
goto err_destroy_phylink;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = of_get_ethdev_address(np, dev);
|
err = of_get_ethdev_address(np, dev);
|
||||||
if (err == -EPROBE_DEFER)
|
if (err == -EPROBE_DEFER)
|
||||||
goto err_deregister_fixed_link;
|
goto err_destroy_phylink;
|
||||||
|
|
||||||
ugeth->ug_info = ug_info;
|
ugeth->ug_info = ug_info;
|
||||||
ugeth->dev = device;
|
ugeth->dev = device;
|
||||||
|
|
@ -3668,11 +3598,11 @@ static int ucc_geth_probe(struct platform_device* ofdev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_deregister_fixed_link:
|
err_destroy_phylink:
|
||||||
if (of_phy_is_fixed_link(np))
|
phylink_destroy(phylink);
|
||||||
of_phy_deregister_fixed_link(np);
|
err_put_tbi:
|
||||||
of_node_put(ug_info->tbi_node);
|
of_node_put(ug_info->tbi_node);
|
||||||
of_node_put(ug_info->phy_node);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3680,13 +3610,10 @@ static void ucc_geth_remove(struct platform_device* ofdev)
|
||||||
{
|
{
|
||||||
struct net_device *dev = platform_get_drvdata(ofdev);
|
struct net_device *dev = platform_get_drvdata(ofdev);
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(dev);
|
struct ucc_geth_private *ugeth = netdev_priv(dev);
|
||||||
struct device_node *np = ofdev->dev.of_node;
|
|
||||||
|
|
||||||
ucc_geth_memclean(ugeth);
|
ucc_geth_memclean(ugeth);
|
||||||
if (of_phy_is_fixed_link(np))
|
phylink_destroy(ugeth->phylink);
|
||||||
of_phy_deregister_fixed_link(np);
|
|
||||||
of_node_put(ugeth->ug_info->tbi_node);
|
of_node_put(ugeth->ug_info->tbi_node);
|
||||||
of_node_put(ugeth->ug_info->phy_node);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id ucc_geth_match[] = {
|
static const struct of_device_id ucc_geth_match[] = {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/phylink.h>
|
||||||
#include <linux/if_ether.h>
|
#include <linux/if_ether.h>
|
||||||
|
|
||||||
#include <soc/fsl/qe/immap_qe.h>
|
#include <soc/fsl/qe/immap_qe.h>
|
||||||
|
|
@ -1074,6 +1075,9 @@ struct ucc_geth_tad_params {
|
||||||
u16 vid;
|
u16 vid;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct phylink;
|
||||||
|
struct phylink_config;
|
||||||
|
|
||||||
/* GETH protocol initialization structure */
|
/* GETH protocol initialization structure */
|
||||||
struct ucc_geth_info {
|
struct ucc_geth_info {
|
||||||
struct ucc_fast_info uf_info;
|
struct ucc_fast_info uf_info;
|
||||||
|
|
@ -1124,7 +1128,6 @@ struct ucc_geth_info {
|
||||||
u32 eventRegMask;
|
u32 eventRegMask;
|
||||||
u16 pausePeriod;
|
u16 pausePeriod;
|
||||||
u16 extensionField;
|
u16 extensionField;
|
||||||
struct device_node *phy_node;
|
|
||||||
struct device_node *tbi_node;
|
struct device_node *tbi_node;
|
||||||
u8 weightfactor[NUM_TX_QUEUES];
|
u8 weightfactor[NUM_TX_QUEUES];
|
||||||
u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
|
u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
|
||||||
|
|
@ -1209,15 +1212,13 @@ struct ucc_geth_private {
|
||||||
u16 skb_dirtytx[NUM_TX_QUEUES];
|
u16 skb_dirtytx[NUM_TX_QUEUES];
|
||||||
|
|
||||||
struct ugeth_mii_info *mii_info;
|
struct ugeth_mii_info *mii_info;
|
||||||
phy_interface_t phy_interface;
|
|
||||||
int max_speed;
|
|
||||||
uint32_t msg_enable;
|
uint32_t msg_enable;
|
||||||
int oldspeed;
|
|
||||||
int oldduplex;
|
|
||||||
int oldlink;
|
|
||||||
u32 wol_en;
|
u32 wol_en;
|
||||||
u32 phy_wol_en;
|
u32 phy_wol_en;
|
||||||
|
|
||||||
|
struct phylink *phylink;
|
||||||
|
struct phylink_config phylink_config;
|
||||||
|
|
||||||
struct device_node *node;
|
struct device_node *node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -103,26 +103,18 @@ static const char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
|
||||||
static int
|
static int
|
||||||
uec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd)
|
uec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd)
|
||||||
{
|
{
|
||||||
struct phy_device *phydev = netdev->phydev;
|
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
||||||
|
|
||||||
if (!phydev)
|
return phylink_ethtool_ksettings_get(ugeth->phylink, cmd);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
phy_ethtool_ksettings_get(phydev, cmd);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
uec_set_ksettings(struct net_device *netdev,
|
uec_set_ksettings(struct net_device *netdev,
|
||||||
const struct ethtool_link_ksettings *cmd)
|
const struct ethtool_link_ksettings *cmd)
|
||||||
{
|
{
|
||||||
struct phy_device *phydev = netdev->phydev;
|
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
||||||
|
|
||||||
if (!phydev)
|
return phylink_ethtool_ksettings_set(ugeth->phylink, cmd);
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
return phy_ethtool_ksettings_set(phydev, cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -130,15 +122,8 @@ uec_get_pauseparam(struct net_device *netdev,
|
||||||
struct ethtool_pauseparam *pause)
|
struct ethtool_pauseparam *pause)
|
||||||
{
|
{
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
||||||
struct phy_device *phydev = netdev->phydev;
|
|
||||||
|
|
||||||
if (phydev)
|
return phylink_ethtool_get_pauseparam(ugeth->phylink, pause);
|
||||||
pause->autoneg = phydev->autoneg;
|
|
||||||
|
|
||||||
if (ugeth->ug_info->receiveFlowControl)
|
|
||||||
pause->rx_pause = 1;
|
|
||||||
if (ugeth->ug_info->transmitFlowControl)
|
|
||||||
pause->tx_pause = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
|
@ -146,31 +131,11 @@ uec_set_pauseparam(struct net_device *netdev,
|
||||||
struct ethtool_pauseparam *pause)
|
struct ethtool_pauseparam *pause)
|
||||||
{
|
{
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
||||||
struct phy_device *phydev = netdev->phydev;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
ugeth->ug_info->receiveFlowControl = pause->rx_pause;
|
ugeth->ug_info->receiveFlowControl = pause->rx_pause;
|
||||||
ugeth->ug_info->transmitFlowControl = pause->tx_pause;
|
ugeth->ug_info->transmitFlowControl = pause->tx_pause;
|
||||||
|
|
||||||
if (phydev && phydev->autoneg) {
|
return phylink_ethtool_set_pauseparam(ugeth->phylink, pause);
|
||||||
if (netif_running(netdev)) {
|
|
||||||
/* FIXME: automatically restart */
|
|
||||||
netdev_info(netdev, "Please re-open the interface\n");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct ucc_geth_info *ug_info = ugeth->ug_info;
|
|
||||||
|
|
||||||
ret = init_flow_control_params(ug_info->aufc,
|
|
||||||
ug_info->receiveFlowControl,
|
|
||||||
ug_info->transmitFlowControl,
|
|
||||||
ug_info->pausePeriod,
|
|
||||||
ug_info->extensionField,
|
|
||||||
&ugeth->uccf->uf_regs->upsmr,
|
|
||||||
&ugeth->ug_regs->uempr,
|
|
||||||
&ugeth->ug_regs->maccfg1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t
|
static uint32_t
|
||||||
|
|
@ -344,13 +309,8 @@ uec_get_drvinfo(struct net_device *netdev,
|
||||||
static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
||||||
struct phy_device *phydev = netdev->phydev;
|
|
||||||
|
|
||||||
wol->supported = 0;
|
phylink_ethtool_get_wol(ugeth->phylink, wol);
|
||||||
wol->wolopts = 0;
|
|
||||||
|
|
||||||
if (phydev)
|
|
||||||
phy_ethtool_get_wol(phydev, wol);
|
|
||||||
|
|
||||||
if (qe_alive_during_sleep())
|
if (qe_alive_during_sleep())
|
||||||
wol->supported |= WAKE_MAGIC;
|
wol->supported |= WAKE_MAGIC;
|
||||||
|
|
@ -361,19 +321,16 @@ static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
||||||
static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
|
||||||
{
|
{
|
||||||
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
struct ucc_geth_private *ugeth = netdev_priv(netdev);
|
||||||
struct phy_device *phydev = netdev->phydev;
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (phydev) {
|
ret = phylink_ethtool_set_wol(ugeth->phylink, wol);
|
||||||
ret = phy_ethtool_set_wol(phydev, wol);
|
if (ret == -EOPNOTSUPP) {
|
||||||
if (ret == -EOPNOTSUPP) {
|
ugeth->phy_wol_en = 0;
|
||||||
ugeth->phy_wol_en = 0;
|
} else if (ret) {
|
||||||
} else if (ret) {
|
return ret;
|
||||||
return ret;
|
} else {
|
||||||
} else {
|
ugeth->phy_wol_en = wol->wolopts;
|
||||||
ugeth->phy_wol_en = wol->wolopts;
|
goto out;
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the PHY isn't handling the WoL and the MAC is asked to more than
|
/* If the PHY isn't handling the WoL and the MAC is asked to more than
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user