Commit 5d93cfcf authored by Sean Anderson's avatar Sean Anderson Committed by David S. Miller

net: dpaa: Convert to phylink

This converts DPAA to phylink. All macs are converted. This should work
with no device tree modifications (including those made in this series),
except for QSGMII (as noted previously).

The mEMAC configuration is one of the tricker areas. I have tried to
capture all the restrictions across the various models. Most of the time,
we assume that if the serdes supports a mode or the phy-interface-mode
specifies it, then we support it. The only place we can't do this is
(RG)MII, since there's no serdes. In that case, we rely on a (new)
devicetree property. There are also several cases where half-duplex is
broken. Unfortunately, only a single compatible is used for the MAC, so we
have to use the board compatible instead.

The 10GEC conversion is very straightforward, since it only supports XAUI.
There is generally nothing to configure.

The dTSEC conversion is broadly similar to mEMAC, but is simpler because we
don't support configuring the SerDes (though this can be easily added) and
we don't have multiple PCSs. From what I can tell, there's nothing
different in the driver or documentation between SGMII and 1000BASE-X
except for the advertising. Similarly, I couldn't find anything about
2500BASE-X. In both cases, I treat them like SGMII. These modes aren't used
by any in-tree boards. Similarly, despite being mentioned in the driver, I
couldn't find any documented SoCs which supported QSGMII.  I have left it
unimplemented for now.
Signed-off-by: default avatarSean Anderson <sean.anderson@seco.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a7c2a32e
......@@ -2,8 +2,8 @@
menuconfig FSL_DPAA_ETH
tristate "DPAA Ethernet"
depends on FSL_DPAA && FSL_FMAN
select PHYLIB
select FIXED_PHY
select PHYLINK
select PCS_LYNX
help
Data Path Acceleration Architecture Ethernet driver,
supporting the Freescale QorIQ chips.
......
......@@ -264,8 +264,19 @@ static int dpaa_netdev_init(struct net_device *net_dev,
net_dev->needed_headroom = priv->tx_headroom;
net_dev->watchdog_timeo = msecs_to_jiffies(tx_timeout);
mac_dev->net_dev = net_dev;
/* The rest of the config is filled in by the mac device already */
mac_dev->phylink_config.dev = &net_dev->dev;
mac_dev->phylink_config.type = PHYLINK_NETDEV;
mac_dev->update_speed = dpaa_eth_cgr_set_speed;
mac_dev->phylink = phylink_create(&mac_dev->phylink_config,
dev_fwnode(mac_dev->dev),
mac_dev->phy_if,
mac_dev->phylink_ops);
if (IS_ERR(mac_dev->phylink)) {
err = PTR_ERR(mac_dev->phylink);
dev_err_probe(dev, err, "Could not create phylink\n");
return err;
}
/* start without the RUNNING flag, phylib controls it later */
netif_carrier_off(net_dev);
......@@ -273,6 +284,7 @@ static int dpaa_netdev_init(struct net_device *net_dev,
err = register_netdev(net_dev);
if (err < 0) {
dev_err(dev, "register_netdev() = %d\n", err);
phylink_destroy(mac_dev->phylink);
return err;
}
......@@ -294,8 +306,7 @@ static int dpaa_stop(struct net_device *net_dev)
*/
msleep(200);
if (mac_dev->phy_dev)
phy_stop(mac_dev->phy_dev);
phylink_stop(mac_dev->phylink);
mac_dev->disable(mac_dev->fman_mac);
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++) {
......@@ -304,8 +315,7 @@ static int dpaa_stop(struct net_device *net_dev)
err = error;
}
if (net_dev->phydev)
phy_disconnect(net_dev->phydev);
phylink_disconnect_phy(mac_dev->phylink);
net_dev->phydev = NULL;
msleep(200);
......@@ -833,10 +843,10 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
/* Set different thresholds based on the configured MAC speed.
* This may turn suboptimal if the MAC is reconfigured at another
* speed, so MACs must call dpaa_eth_cgr_set_speed in their adjust_link
* speed, so MACs must call dpaa_eth_cgr_set_speed in their link_up
* callback.
*/
if (priv->mac_dev->if_support & SUPPORTED_10000baseT_Full)
if (priv->mac_dev->phylink_config.mac_capabilities & MAC_10000FD)
cs_th = DPAA_CS_THRESHOLD_10G;
else
cs_th = DPAA_CS_THRESHOLD_1G;
......@@ -865,7 +875,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv)
static void dpaa_eth_cgr_set_speed(struct mac_device *mac_dev, int speed)
{
struct net_device *net_dev = mac_dev->net_dev;
struct net_device *net_dev = to_net_dev(mac_dev->phylink_config.dev);
struct dpaa_priv *priv = netdev_priv(net_dev);
struct qm_mcc_initcgr opts = { };
u32 cs_th;
......@@ -2904,58 +2914,6 @@ static void dpaa_eth_napi_disable(struct dpaa_priv *priv)
}
}
static void dpaa_adjust_link(struct net_device *net_dev)
{
struct mac_device *mac_dev;
struct dpaa_priv *priv;
priv = netdev_priv(net_dev);
mac_dev = priv->mac_dev;
mac_dev->adjust_link(mac_dev);
}
/* The Aquantia PHYs are capable of performing rate adaptation */
#define PHY_VEND_AQUANTIA 0x03a1b400
#define PHY_VEND_AQUANTIA2 0x31c31c00
static int dpaa_phy_init(struct net_device *net_dev)
{
__ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
struct mac_device *mac_dev;
struct phy_device *phy_dev;
struct dpaa_priv *priv;
u32 phy_vendor;
priv = netdev_priv(net_dev);
mac_dev = priv->mac_dev;
phy_dev = of_phy_connect(net_dev, mac_dev->phy_node,
&dpaa_adjust_link, 0,
mac_dev->phy_if);
if (!phy_dev) {
netif_err(priv, ifup, net_dev, "init_phy() failed\n");
return -ENODEV;
}
phy_vendor = phy_dev->drv->phy_id & GENMASK(31, 10);
/* Unless the PHY is capable of rate adaptation */
if (mac_dev->phy_if != PHY_INTERFACE_MODE_XGMII ||
(phy_vendor != PHY_VEND_AQUANTIA &&
phy_vendor != PHY_VEND_AQUANTIA2)) {
/* remove any features not supported by the controller */
ethtool_convert_legacy_u32_to_link_mode(mask,
mac_dev->if_support);
linkmode_and(phy_dev->supported, phy_dev->supported, mask);
}
phy_support_asym_pause(phy_dev);
mac_dev->phy_dev = phy_dev;
net_dev->phydev = phy_dev;
return 0;
}
static int dpaa_open(struct net_device *net_dev)
{
struct mac_device *mac_dev;
......@@ -2966,7 +2924,8 @@ static int dpaa_open(struct net_device *net_dev)
mac_dev = priv->mac_dev;
dpaa_eth_napi_enable(priv);
err = dpaa_phy_init(net_dev);
err = phylink_of_phy_connect(mac_dev->phylink,
mac_dev->dev->of_node, 0);
if (err)
goto phy_init_failed;
......@@ -2981,7 +2940,7 @@ static int dpaa_open(struct net_device *net_dev)
netif_err(priv, ifup, net_dev, "mac_dev->enable() = %d\n", err);
goto mac_start_failed;
}
phy_start(priv->mac_dev->phy_dev);
phylink_start(mac_dev->phylink);
netif_tx_start_all_queues(net_dev);
......@@ -2990,6 +2949,7 @@ static int dpaa_open(struct net_device *net_dev)
mac_start_failed:
for (i = 0; i < ARRAY_SIZE(mac_dev->port); i++)
fman_port_disable(mac_dev->port[i]);
phylink_disconnect_phy(mac_dev->phylink);
phy_init_failed:
dpaa_eth_napi_disable(priv);
......@@ -3145,10 +3105,12 @@ static int dpaa_ts_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
static int dpaa_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd)
{
int ret = -EINVAL;
struct dpaa_priv *priv = netdev_priv(net_dev);
if (cmd == SIOCGMIIREG) {
if (net_dev->phydev)
return phy_mii_ioctl(net_dev->phydev, rq, cmd);
return phylink_mii_ioctl(priv->mac_dev->phylink, rq,
cmd);
}
if (cmd == SIOCSHWTSTAMP)
......@@ -3551,6 +3513,7 @@ static int dpaa_remove(struct platform_device *pdev)
dev_set_drvdata(dev, NULL);
unregister_netdev(net_dev);
phylink_destroy(priv->mac_dev->phylink);
err = dpaa_fq_free(dev, &priv->dpaa_fq_list);
......
......@@ -54,27 +54,19 @@ static char dpaa_stats_global[][ETH_GSTRING_LEN] = {
static int dpaa_get_link_ksettings(struct net_device *net_dev,
struct ethtool_link_ksettings *cmd)
{
if (!net_dev->phydev)
return 0;
phy_ethtool_ksettings_get(net_dev->phydev, cmd);
struct dpaa_priv *priv = netdev_priv(net_dev);
struct mac_device *mac_dev = priv->mac_dev;
return 0;
return phylink_ethtool_ksettings_get(mac_dev->phylink, cmd);
}
static int dpaa_set_link_ksettings(struct net_device *net_dev,
const struct ethtool_link_ksettings *cmd)
{
int err;
if (!net_dev->phydev)
return -ENODEV;
struct dpaa_priv *priv = netdev_priv(net_dev);
struct mac_device *mac_dev = priv->mac_dev;
err = phy_ethtool_ksettings_set(net_dev->phydev, cmd);
if (err < 0)
netdev_err(net_dev, "phy_ethtool_ksettings_set() = %d\n", err);
return err;
return phylink_ethtool_ksettings_set(mac_dev->phylink, cmd);
}
static void dpaa_get_drvinfo(struct net_device *net_dev,
......@@ -99,80 +91,28 @@ static void dpaa_set_msglevel(struct net_device *net_dev,
static int dpaa_nway_reset(struct net_device *net_dev)
{
int err;
if (!net_dev->phydev)
return -ENODEV;
err = 0;
if (net_dev->phydev->autoneg) {
err = phy_start_aneg(net_dev->phydev);
if (err < 0)
netdev_err(net_dev, "phy_start_aneg() = %d\n",
err);
}
struct dpaa_priv *priv = netdev_priv(net_dev);
struct mac_device *mac_dev = priv->mac_dev;
return err;
return phylink_ethtool_nway_reset(mac_dev->phylink);
}
static void dpaa_get_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *epause)
{
struct mac_device *mac_dev;
struct dpaa_priv *priv;
struct dpaa_priv *priv = netdev_priv(net_dev);
struct mac_device *mac_dev = priv->mac_dev;
priv = netdev_priv(net_dev);
mac_dev = priv->mac_dev;
if (!net_dev->phydev)
return;
epause->autoneg = mac_dev->autoneg_pause;
epause->rx_pause = mac_dev->rx_pause_active;
epause->tx_pause = mac_dev->tx_pause_active;
phylink_ethtool_get_pauseparam(mac_dev->phylink, epause);
}
static int dpaa_set_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *epause)
{
struct mac_device *mac_dev;
struct phy_device *phydev;
bool rx_pause, tx_pause;
struct dpaa_priv *priv;
int err;
priv = netdev_priv(net_dev);
mac_dev = priv->mac_dev;
phydev = net_dev->phydev;
if (!phydev) {
netdev_err(net_dev, "phy device not initialized\n");
return -ENODEV;
}
if (!phy_validate_pause(phydev, epause))
return -EINVAL;
/* The MAC should know how to handle PAUSE frame autonegotiation before
* adjust_link is triggered by a forced renegotiation of sym/asym PAUSE
* settings.
*/
mac_dev->autoneg_pause = !!epause->autoneg;
mac_dev->rx_pause_req = !!epause->rx_pause;
mac_dev->tx_pause_req = !!epause->tx_pause;
/* Determine the sym/asym advertised PAUSE capabilities from the desired
* rx/tx pause settings.
*/
phy_set_asym_pause(phydev, epause->rx_pause, epause->tx_pause);
fman_get_pause_cfg(mac_dev, &rx_pause, &tx_pause);
err = fman_set_mac_active_pause(mac_dev, rx_pause, tx_pause);
if (err < 0)
netdev_err(net_dev, "set_mac_active_pause() = %d\n", err);
struct dpaa_priv *priv = netdev_priv(net_dev);
struct mac_device *mac_dev = priv->mac_dev;
return err;
return phylink_ethtool_set_pauseparam(mac_dev->phylink, epause);
}
static int dpaa_get_sset_count(struct net_device *net_dev, int type)
......
......@@ -3,7 +3,6 @@ config FSL_FMAN
tristate "FMan support"
depends on FSL_SOC || ARCH_LAYERSCAPE || COMPILE_TEST
select GENERIC_ALLOCATOR
select PHYLIB
select PHYLINK
select PCS
select PCS_LYNX
......
......@@ -170,20 +170,10 @@ struct fman_mac_params {
* 0 - FM_MAX_NUM_OF_10G_MACS
*/
u8 mac_id;
/* Note that the speed should indicate the maximum rate that
* this MAC should support rather than the actual speed;
*/
u16 max_speed;
/* A handle to the FM object this port related to */
void *fm;
fman_mac_exception_cb *event_cb; /* MDIO Events Callback Routine */
fman_mac_exception_cb *exception_cb;/* Exception Callback Routine */
/* SGMII/QSGII interface with 1000BaseX auto-negotiation between MAC
* and phy or backplane; Note: 1000BaseX auto-negotiation relates only
* to interface between MAC and phy/backplane, SGMII phy can still
* synchronize with far-end phy at 10Mbps, 100Mbps or 1000Mbps
*/
bool basex_if;
};
struct eth_hash_t {
......
......@@ -13,6 +13,7 @@
#include <linux/bitrev.h>
#include <linux/io.h>
#include <linux/crc32.h>
#include <linux/netdevice.h>
/* Transmit Inter-Packet Gap Length Register (TX_IPG_LENGTH) */
#define TGEC_TX_IPG_LENGTH_MASK 0x000003ff
......@@ -243,10 +244,6 @@ static int init(struct tgec_regs __iomem *regs, struct tgec_cfg *cfg,
static int check_init_parameters(struct fman_mac *tgec)
{
if (tgec->max_speed < SPEED_10000) {
pr_err("10G MAC driver only support 10G speed\n");
return -EINVAL;
}
if (!tgec->exception_cb) {
pr_err("uninitialized exception_cb\n");
return -EINVAL;
......@@ -384,40 +381,13 @@ static void free_init_resources(struct fman_mac *tgec)
tgec->unicast_addr_hash = NULL;
}
static bool is_init_done(struct tgec_cfg *cfg)
{
/* Checks if tGEC driver parameters were initialized */
if (!cfg)
return true;
return false;
}
static int tgec_enable(struct fman_mac *tgec)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
iowrite32be(tmp, &regs->command_config);
return 0;
}
static void tgec_disable(struct fman_mac *tgec)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
WARN_ON_ONCE(!is_init_done(tgec->cfg));
tmp = ioread32be(&regs->command_config);
tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
iowrite32be(tmp, &regs->command_config);
}
static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val)
......@@ -425,9 +395,6 @@ static int tgec_set_promiscuous(struct fman_mac *tgec, bool new_val)
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (new_val)
tmp |= CMD_CFG_PROMIS_EN;
......@@ -444,9 +411,6 @@ static int tgec_set_tx_pause_frames(struct fman_mac *tgec,
{
struct tgec_regs __iomem *regs = tgec->regs;
if (!is_init_done(tgec->cfg))
return -EINVAL;
iowrite32be((u32)pause_time, &regs->pause_quant);
return 0;
......@@ -457,9 +421,6 @@ static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en)
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (!en)
tmp |= CMD_CFG_PAUSE_IGNORE;
......@@ -470,12 +431,53 @@ static int tgec_accept_rx_pause_frames(struct fman_mac *tgec, bool en)
return 0;
}
static void tgec_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
}
static void tgec_link_up(struct phylink_config *config, struct phy_device *phy,
unsigned int mode, phy_interface_t interface,
int speed, int duplex, bool tx_pause, bool rx_pause)
{
struct mac_device *mac_dev = fman_config_to_mac(config);
struct fman_mac *tgec = mac_dev->fman_mac;
struct tgec_regs __iomem *regs = tgec->regs;
u16 pause_time = tx_pause ? FSL_FM_PAUSE_TIME_ENABLE :
FSL_FM_PAUSE_TIME_DISABLE;
u32 tmp;
tgec_set_tx_pause_frames(tgec, 0, pause_time, 0);
tgec_accept_rx_pause_frames(tgec, rx_pause);
mac_dev->update_speed(mac_dev, speed);
tmp = ioread32be(&regs->command_config);
tmp |= CMD_CFG_RX_EN | CMD_CFG_TX_EN;
iowrite32be(tmp, &regs->command_config);
}
static void tgec_link_down(struct phylink_config *config, unsigned int mode,
phy_interface_t interface)
{
struct fman_mac *tgec = fman_config_to_mac(config)->fman_mac;
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
tmp = ioread32be(&regs->command_config);
tmp &= ~(CMD_CFG_RX_EN | CMD_CFG_TX_EN);
iowrite32be(tmp, &regs->command_config);
}
static const struct phylink_mac_ops tgec_mac_ops = {
.validate = phylink_generic_validate,
.mac_config = tgec_mac_config,
.mac_link_up = tgec_link_up,
.mac_link_down = tgec_link_down,
};
static int tgec_modify_mac_address(struct fman_mac *tgec,
const enet_addr_t *p_enet_addr)
{
if (!is_init_done(tgec->cfg))
return -EINVAL;
tgec->addr = ENET_ADDR_TO_UINT64(*p_enet_addr);
set_mac_address(tgec->regs, (const u8 *)(*p_enet_addr));
......@@ -490,9 +492,6 @@ static int tgec_add_hash_mac_address(struct fman_mac *tgec,
u32 crc = 0xFFFFFFFF, hash;
u64 addr;
if (!is_init_done(tgec->cfg))
return -EINVAL;
addr = ENET_ADDR_TO_UINT64(*eth_addr);
if (!(addr & GROUP_ADDRESS)) {
......@@ -525,9 +524,6 @@ static int tgec_set_allmulti(struct fman_mac *tgec, bool enable)
u32 entry;
struct tgec_regs __iomem *regs = tgec->regs;
if (!is_init_done(tgec->cfg))
return -EINVAL;
if (enable) {
for (entry = 0; entry < TGEC_HASH_TABLE_SIZE; entry++)
iowrite32be(entry | TGEC_HASH_MCAST_EN,
......@@ -548,9 +544,6 @@ static int tgec_set_tstamp(struct fman_mac *tgec, bool enable)
struct tgec_regs __iomem *regs = tgec->regs;
u32 tmp;
if (!is_init_done(tgec->cfg))
return -EINVAL;
tmp = ioread32be(&regs->command_config);
if (enable)
......@@ -572,9 +565,6 @@ static int tgec_del_hash_mac_address(struct fman_mac *tgec,
u32 crc = 0xFFFFFFFF, hash;
u64 addr;
if (!is_init_done(tgec->cfg))
return -EINVAL;
addr = ((*(u64 *)eth_addr) >> 16);
/* CRC calculation */
......@@ -601,22 +591,12 @@ static int tgec_del_hash_mac_address(struct fman_mac *tgec,
return 0;
}
static void tgec_adjust_link(struct mac_device *mac_dev)
{
struct phy_device *phy_dev = mac_dev->phy_dev;
mac_dev->update_speed(mac_dev, phy_dev->speed);
}
static int tgec_set_exception(struct fman_mac *tgec,
enum fman_mac_exceptions exception, bool enable)
{
struct tgec_regs __iomem *regs = tgec->regs;
u32 bit_mask = 0;
if (!is_init_done(tgec->cfg))
return -EINVAL;
bit_mask = get_exception_flag(exception);
if (bit_mask) {
if (enable)
......@@ -641,9 +621,6 @@ static int tgec_init(struct fman_mac *tgec)
enet_addr_t eth_addr;
int err;
if (is_init_done(tgec->cfg))
return -EINVAL;
if (DEFAULT_RESET_ON_INIT &&
(fman_reset_mac(tgec->fm, tgec->mac_id) != 0)) {
pr_err("Can't reset MAC!\n");
......@@ -753,7 +730,6 @@ static struct fman_mac *tgec_config(struct mac_device *mac_dev,
tgec->regs = mac_dev->vaddr;
tgec->addr = ENET_ADDR_TO_UINT64(mac_dev->addr);
tgec->max_speed = params->max_speed;
tgec->mac_id = params->mac_id;
tgec->exceptions = (TGEC_IMASK_MDIO_SCAN_EVENT |
TGEC_IMASK_REM_FAULT |
......@@ -788,17 +764,15 @@ int tgec_initialization(struct mac_device *mac_dev,
int err;
struct fman_mac *tgec;
mac_dev->phylink_ops = &tgec_mac_ops;
mac_dev->set_promisc = tgec_set_promiscuous;
mac_dev->change_addr = tgec_modify_mac_address;
mac_dev->add_hash_mac_addr = tgec_add_hash_mac_address;
mac_dev->remove_hash_mac_addr = tgec_del_hash_mac_address;
mac_dev->set_tx_pause = tgec_set_tx_pause_frames;
mac_dev->set_rx_pause = tgec_accept_rx_pause_frames;
mac_dev->set_exception = tgec_set_exception;
mac_dev->set_allmulti = tgec_set_allmulti;
mac_dev->set_tstamp = tgec_set_tstamp;
mac_dev->set_multi = fman_set_multi;
mac_dev->adjust_link = tgec_adjust_link;
mac_dev->enable = tgec_enable;
mac_dev->disable = tgec_disable;
......@@ -808,6 +782,19 @@ int tgec_initialization(struct mac_device *mac_dev,
goto _return;
}
/* The internal connection to the serdes is XGMII, but this isn't
* really correct for the phy mode (which is the external connection).
* However, this is how all older device trees say that they want
* XAUI, so just convert it for them.
*/
if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
mac_dev->phy_if = PHY_INTERFACE_MODE_XAUI;
__set_bit(PHY_INTERFACE_MODE_XAUI,
mac_dev->phylink_config.supported_interfaces);
mac_dev->phylink_config.mac_capabilities =
MAC_SYM_PAUSE | MAC_ASYM_PAUSE | MAC_10000FD;
tgec = mac_dev->fman_mac;
tgec->cfg->max_frame_length = fman_get_max_frm();
err = tgec_init(tgec);
......
......@@ -15,6 +15,7 @@
#include <linux/phy.h>
#include <linux/netdevice.h>
#include <linux/phy_fixed.h>
#include <linux/phylink.h>
#include <linux/etherdevice.h>
#include <linux/libfdt_env.h>
......@@ -93,130 +94,8 @@ int fman_set_multi(struct net_device *net_dev, struct mac_device *mac_dev)
return 0;
}
/**
* fman_set_mac_active_pause
* @mac_dev: A pointer to the MAC device
* @rx: Pause frame setting for RX
* @tx: Pause frame setting for TX
*
* Set the MAC RX/TX PAUSE frames settings
*
* Avoid redundant calls to FMD, if the MAC driver already contains the desired
* active PAUSE settings. Otherwise, the new active settings should be reflected
* in FMan.
*
* Return: 0 on success; Error code otherwise.
*/
int fman_set_mac_active_pause(struct mac_device *mac_dev, bool rx, bool tx)
{
struct fman_mac *fman_mac = mac_dev->fman_mac;
int err = 0;
if (rx != mac_dev->rx_pause_active) {
err = mac_dev->set_rx_pause(fman_mac, rx);
if (likely(err == 0))
mac_dev->rx_pause_active = rx;
}
if (tx != mac_dev->tx_pause_active) {
u16 pause_time = (tx ? FSL_FM_PAUSE_TIME_ENABLE :
FSL_FM_PAUSE_TIME_DISABLE);
err = mac_dev->set_tx_pause(fman_mac, 0, pause_time, 0);
if (likely(err == 0))
mac_dev->tx_pause_active = tx;
}
return err;
}
EXPORT_SYMBOL(fman_set_mac_active_pause);
/**
* fman_get_pause_cfg
* @mac_dev: A pointer to the MAC device
* @rx_pause: Return value for RX setting
* @tx_pause: Return value for TX setting
*
* Determine the MAC RX/TX PAUSE frames settings based on PHY
* autonegotiation or values set by eththool.
*
* Return: Pointer to FMan device.
*/
void fman_get_pause_cfg(struct mac_device *mac_dev, bool *rx_pause,
bool *tx_pause)
{
struct phy_device *phy_dev = mac_dev->phy_dev;
u16 lcl_adv, rmt_adv;
u8 flowctrl;
*rx_pause = *tx_pause = false;
if (!phy_dev->duplex)
return;
/* If PAUSE autonegotiation is disabled, the TX/RX PAUSE settings
* are those set by ethtool.
*/
if (!mac_dev->autoneg_pause) {
*rx_pause = mac_dev->rx_pause_req;
*tx_pause = mac_dev->tx_pause_req;
return;
}
/* Else if PAUSE autonegotiation is enabled, the TX/RX PAUSE
* settings depend on the result of the link negotiation.
*/
/* get local capabilities */
lcl_adv = linkmode_adv_to_lcl_adv_t(phy_dev->advertising);
/* get link partner capabilities */
rmt_adv = 0;
if (phy_dev->pause)
rmt_adv |= LPA_PAUSE_CAP;
if (phy_dev->asym_pause)
rmt_adv |= LPA_PAUSE_ASYM;
/* Calculate TX/RX settings based on local and peer advertised
* symmetric/asymmetric PAUSE capabilities.
*/
flowctrl = mii_resolve_flowctrl_fdx(lcl_adv, rmt_adv);
if (flowctrl & FLOW_CTRL_RX)
*rx_pause = true;
if (flowctrl & FLOW_CTRL_TX)
*tx_pause = true;
}
EXPORT_SYMBOL(fman_get_pause_cfg);
#define DTSEC_SUPPORTED \
(SUPPORTED_10baseT_Half \
| SUPPORTED_10baseT_Full \
| SUPPORTED_100baseT_Half \
| SUPPORTED_100baseT_Full \
| SUPPORTED_Autoneg \
| SUPPORTED_Pause \
| SUPPORTED_Asym_Pause \
| SUPPORTED_FIBRE \
| SUPPORTED_MII)
static DEFINE_MUTEX(eth_lock);
static const u16 phy2speed[] = {
[PHY_INTERFACE_MODE_MII] = SPEED_100,
[PHY_INTERFACE_MODE_GMII] = SPEED_1000,
[PHY_INTERFACE_MODE_SGMII] = SPEED_1000,
[PHY_INTERFACE_MODE_TBI] = SPEED_1000,
[PHY_INTERFACE_MODE_RMII] = SPEED_100,
[PHY_INTERFACE_MODE_RGMII] = SPEED_1000,
[PHY_INTERFACE_MODE_RGMII_ID] = SPEED_1000,
[PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000,
[PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000,
[PHY_INTERFACE_MODE_RTBI] = SPEED_1000,
[PHY_INTERFACE_MODE_QSGMII] = SPEED_1000,
[PHY_INTERFACE_MODE_XGMII] = SPEED_10000
};
static struct platform_device *dpaa_eth_add_device(int fman_id,
struct mac_device *mac_dev)
{
......@@ -296,6 +175,7 @@ static int mac_probe(struct platform_device *_of_dev)
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(_of_dev, mac_dev);
/* Save private information */
mac_dev->priv = priv;
......@@ -424,57 +304,21 @@ static int mac_probe(struct platform_device *_of_dev)
}
mac_dev->phy_if = phy_if;
priv->speed = phy2speed[mac_dev->phy_if];
params.max_speed = priv->speed;
mac_dev->if_support = DTSEC_SUPPORTED;
/* We don't support half-duplex in SGMII mode */
if (mac_dev->phy_if == PHY_INTERFACE_MODE_SGMII)
mac_dev->if_support &= ~(SUPPORTED_10baseT_Half |
SUPPORTED_100baseT_Half);
/* Gigabit support (no half-duplex) */
if (params.max_speed == 1000)
mac_dev->if_support |= SUPPORTED_1000baseT_Full;
/* The 10G interface only supports one mode */
if (mac_dev->phy_if == PHY_INTERFACE_MODE_XGMII)
mac_dev->if_support = SUPPORTED_10000baseT_Full;
/* Get the rest of the PHY information */
mac_dev->phy_node = of_parse_phandle(mac_node, "phy-handle", 0);
params.basex_if = false;
params.mac_id = priv->cell_index;
params.fm = (void *)priv->fman;
params.exception_cb = mac_exception;
params.event_cb = mac_exception;
err = init(mac_dev, mac_node, &params);
if (err < 0) {
dev_err(dev, "mac_dev->init() = %d\n", err);
of_node_put(mac_dev->phy_node);
return err;
}
/* pause frame autonegotiation enabled */
mac_dev->autoneg_pause = true;
/* By intializing the values to false, force FMD to enable PAUSE frames
* on RX and TX
*/
mac_dev->rx_pause_req = true;
mac_dev->tx_pause_req = true;
mac_dev->rx_pause_active = false;
mac_dev->tx_pause_active = false;
err = fman_set_mac_active_pause(mac_dev, true, true);
if (err < 0)
dev_err(dev, "fman_set_mac_active_pause() = %d\n", err);
return err;
if (!is_zero_ether_addr(mac_dev->addr))
dev_info(dev, "FMan MAC address: %pM\n", mac_dev->addr);
priv->eth_dev = dpaa_eth_add_device(fman_id, mac_dev);
if (IS_ERR(priv->eth_dev)) {
err = PTR_ERR(priv->eth_dev);
dev_err(dev, "failed to add Ethernet platform device for MAC %d\n",
priv->cell_index);
priv->eth_dev = NULL;
......
......@@ -9,6 +9,7 @@
#include <linux/device.h>
#include <linux/if_ether.h>
#include <linux/phy.h>
#include <linux/phylink.h>
#include <linux/list.h>
#include "fman_port.h"
......@@ -24,32 +25,22 @@ struct mac_device {
struct device *dev;
u8 addr[ETH_ALEN];
struct fman_port *port[2];
u32 if_support;
struct phy_device *phy_dev;
struct phylink *phylink;
struct phylink_config phylink_config;
phy_interface_t phy_if;
struct device_node *phy_node;
struct net_device *net_dev;
bool autoneg_pause;
bool rx_pause_req;
bool tx_pause_req;
bool rx_pause_active;
bool tx_pause_active;
bool promisc;
bool allmulti;
const struct phylink_mac_ops *phylink_ops;
int (*enable)(struct fman_mac *mac_dev);
void (*disable)(struct fman_mac *mac_dev);
void (*adjust_link)(struct mac_device *mac_dev);
int (*set_promisc)(struct fman_mac *mac_dev, bool enable);
int (*change_addr)(struct fman_mac *mac_dev, const enet_addr_t *enet_addr);
int (*set_allmulti)(struct fman_mac *mac_dev, bool enable);
int (*set_tstamp)(struct fman_mac *mac_dev, bool enable);
int (*set_multi)(struct net_device *net_dev,
struct mac_device *mac_dev);
int (*set_rx_pause)(struct fman_mac *mac_dev, bool en);
int (*set_tx_pause)(struct fman_mac *mac_dev, u8 priority,
u16 pause_time, u16 thresh_time);
int (*set_exception)(struct fman_mac *mac_dev,
enum fman_mac_exceptions exception, bool enable);
int (*add_hash_mac_addr)(struct fman_mac *mac_dev,
......@@ -63,6 +54,12 @@ struct mac_device {
struct mac_priv_s *priv;
};
static inline struct mac_device
*fman_config_to_mac(struct phylink_config *config)
{
return container_of(config, struct mac_device, phylink_config);
}
struct dpaa_eth_data {
struct mac_device *mac_dev;
int mac_hw_id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment