aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/ibm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/ibm')
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_ethtool.c51
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c5
-rw-r--r--drivers/net/ethernet/ibm/emac/Kconfig1
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c324
-rw-r--r--drivers/net/ethernet/ibm/emac/core.h4
-rw-r--r--drivers/net/ethernet/ibm/emac/mal.c18
-rw-r--r--drivers/net/ethernet/ibm/ibmveth.c32
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.c179
-rw-r--r--drivers/net/ethernet/ibm/ibmvnic.h5
9 files changed, 463 insertions, 156 deletions
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
index 85a3866459cf..4f58d338d739 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_ethtool.c
@@ -31,9 +31,11 @@
#include "ehea.h"
#include "ehea_phyp.h"
-static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int ehea_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
struct ehea_port *port = netdev_priv(dev);
+ u32 supported, advertising;
u32 speed;
int ret;
@@ -60,68 +62,75 @@ static int ehea_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
speed = -1;
break; /* BUG */
}
- cmd->duplex = port->full_duplex == 1 ?
+ cmd->base.duplex = port->full_duplex == 1 ?
DUPLEX_FULL : DUPLEX_HALF;
} else {
speed = SPEED_UNKNOWN;
- cmd->duplex = DUPLEX_UNKNOWN;
+ cmd->base.duplex = DUPLEX_UNKNOWN;
}
- ethtool_cmd_speed_set(cmd, speed);
+ cmd->base.speed = speed;
- if (cmd->speed == SPEED_10000) {
- cmd->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
- cmd->advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
- cmd->port = PORT_FIBRE;
+ if (cmd->base.speed == SPEED_10000) {
+ supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
+ advertising = (ADVERTISED_10000baseT_Full | ADVERTISED_FIBRE);
+ cmd->base.port = PORT_FIBRE;
} else {
- cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full
+ supported = (SUPPORTED_1000baseT_Full | SUPPORTED_100baseT_Full
| SUPPORTED_100baseT_Half | SUPPORTED_10baseT_Full
| SUPPORTED_10baseT_Half | SUPPORTED_Autoneg
| SUPPORTED_TP);
- cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg
+ advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg
| ADVERTISED_TP);
- cmd->port = PORT_TP;
+ cmd->base.port = PORT_TP;
}
- cmd->autoneg = port->autoneg == 1 ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+ cmd->base.autoneg = port->autoneg == 1 ?
+ AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
return 0;
}
-static int ehea_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int ehea_set_link_ksettings(struct net_device *dev,
+ const struct ethtool_link_ksettings *cmd)
{
struct ehea_port *port = netdev_priv(dev);
int ret = 0;
u32 sp;
- if (cmd->autoneg == AUTONEG_ENABLE) {
+ if (cmd->base.autoneg == AUTONEG_ENABLE) {
sp = EHEA_SPEED_AUTONEG;
goto doit;
}
- switch (cmd->speed) {
+ switch (cmd->base.speed) {
case SPEED_10:
- if (cmd->duplex == DUPLEX_FULL)
+ if (cmd->base.duplex == DUPLEX_FULL)
sp = H_SPEED_10M_F;
else
sp = H_SPEED_10M_H;
break;
case SPEED_100:
- if (cmd->duplex == DUPLEX_FULL)
+ if (cmd->base.duplex == DUPLEX_FULL)
sp = H_SPEED_100M_F;
else
sp = H_SPEED_100M_H;
break;
case SPEED_1000:
- if (cmd->duplex == DUPLEX_FULL)
+ if (cmd->base.duplex == DUPLEX_FULL)
sp = H_SPEED_1G_F;
else
ret = -EINVAL;
break;
case SPEED_10000:
- if (cmd->duplex == DUPLEX_FULL)
+ if (cmd->base.duplex == DUPLEX_FULL)
sp = H_SPEED_10G_F;
else
ret = -EINVAL;
@@ -264,7 +273,6 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
}
static const struct ethtool_ops ehea_ethtool_ops = {
- .get_settings = ehea_get_settings,
.get_drvinfo = ehea_get_drvinfo,
.get_msglevel = ehea_get_msglevel,
.set_msglevel = ehea_set_msglevel,
@@ -272,8 +280,9 @@ static const struct ethtool_ops ehea_ethtool_ops = {
.get_strings = ehea_get_strings,
.get_sset_count = ehea_get_sset_count,
.get_ethtool_stats = ehea_get_ethtool_stats,
- .set_settings = ehea_set_settings,
.nway_reset = ehea_nway_reset, /* Restart autonegotiation */
+ .get_link_ksettings = ehea_get_link_ksettings,
+ .set_link_ksettings = ehea_set_link_ksettings,
};
void ehea_set_ethtool_ops(struct net_device *netdev)
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 702446a93697..1e53d7a82675 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -328,8 +328,8 @@ out:
spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
}
-static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev,
- struct rtnl_link_stats64 *stats)
+static void ehea_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
{
struct ehea_port *port = netdev_priv(dev);
u64 rx_packets = 0, tx_packets = 0, rx_bytes = 0, tx_bytes = 0;
@@ -352,7 +352,6 @@ static struct rtnl_link_stats64 *ehea_get_stats64(struct net_device *dev,
stats->multicast = port->stats.multicast;
stats->rx_errors = port->stats.rx_errors;
- return stats;
}
static void ehea_update_stats(struct work_struct *work)
diff --git a/drivers/net/ethernet/ibm/emac/Kconfig b/drivers/net/ethernet/ibm/emac/Kconfig
index 3f44a30e0615..90d49191beb3 100644
--- a/drivers/net/ethernet/ibm/emac/Kconfig
+++ b/drivers/net/ethernet/ibm/emac/Kconfig
@@ -2,6 +2,7 @@ config IBM_EMAC
tristate "IBM EMAC Ethernet support"
depends on PPC_DCR
select CRC32
+ select PHYLIB
help
This driver supports the IBM EMAC family of Ethernet controllers
typically found on 4xx embedded PowerPC chips, but also on the
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 5909615c27f7..275c2e2349ad 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -42,6 +42,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_net.h>
+#include <linux/of_mdio.h>
#include <linux/slab.h>
#include <asm/processor.h>
@@ -1991,69 +1992,79 @@ static struct mal_commac_ops emac_commac_sg_ops = {
};
/* Ethtool support */
-static int emac_ethtool_get_settings(struct net_device *ndev,
- struct ethtool_cmd *cmd)
+static int emac_ethtool_get_link_ksettings(struct net_device *ndev,
+ struct ethtool_link_ksettings *cmd)
{
struct emac_instance *dev = netdev_priv(ndev);
+ u32 supported, advertising;
- cmd->supported = dev->phy.features;
- cmd->port = PORT_MII;
- cmd->phy_address = dev->phy.address;
- cmd->transceiver =
- dev->phy.address >= 0 ? XCVR_EXTERNAL : XCVR_INTERNAL;
+ supported = dev->phy.features;
+ cmd->base.port = PORT_MII;
+ cmd->base.phy_address = dev->phy.address;
mutex_lock(&dev->link_lock);
- cmd->advertising = dev->phy.advertising;
- cmd->autoneg = dev->phy.autoneg;
- cmd->speed = dev->phy.speed;
- cmd->duplex = dev->phy.duplex;
+ advertising = dev->phy.advertising;
+ cmd->base.autoneg = dev->phy.autoneg;
+ cmd->base.speed = dev->phy.speed;
+ cmd->base.duplex = dev->phy.duplex;
mutex_unlock(&dev->link_lock);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
return 0;
}
-static int emac_ethtool_set_settings(struct net_device *ndev,
- struct ethtool_cmd *cmd)
+static int
+emac_ethtool_set_link_ksettings(struct net_device *ndev,
+ const struct ethtool_link_ksettings *cmd)
{
struct emac_instance *dev = netdev_priv(ndev);
u32 f = dev->phy.features;
+ u32 advertising;
+
+ ethtool_convert_link_mode_to_legacy_u32(&advertising,
+ cmd->link_modes.advertising);
DBG(dev, "set_settings(%d, %d, %d, 0x%08x)" NL,
- cmd->autoneg, cmd->speed, cmd->duplex, cmd->advertising);
+ cmd->base.autoneg, cmd->base.speed, cmd->base.duplex, advertising);
/* Basic sanity checks */
if (dev->phy.address < 0)
return -EOPNOTSUPP;
- if (cmd->autoneg != AUTONEG_ENABLE && cmd->autoneg != AUTONEG_DISABLE)
+ if (cmd->base.autoneg != AUTONEG_ENABLE &&
+ cmd->base.autoneg != AUTONEG_DISABLE)
return -EINVAL;
- if (cmd->autoneg == AUTONEG_ENABLE && cmd->advertising == 0)
+ if (cmd->base.autoneg == AUTONEG_ENABLE && advertising == 0)
return -EINVAL;
- if (cmd->duplex != DUPLEX_HALF && cmd->duplex != DUPLEX_FULL)
+ if (cmd->base.duplex != DUPLEX_HALF && cmd->base.duplex != DUPLEX_FULL)
return -EINVAL;
- if (cmd->autoneg == AUTONEG_DISABLE) {
- switch (cmd->speed) {
+ if (cmd->base.autoneg == AUTONEG_DISABLE) {
+ switch (cmd->base.speed) {
case SPEED_10:
- if (cmd->duplex == DUPLEX_HALF &&
+ if (cmd->base.duplex == DUPLEX_HALF &&
!(f & SUPPORTED_10baseT_Half))
return -EINVAL;
- if (cmd->duplex == DUPLEX_FULL &&
+ if (cmd->base.duplex == DUPLEX_FULL &&
!(f & SUPPORTED_10baseT_Full))
return -EINVAL;
break;
case SPEED_100:
- if (cmd->duplex == DUPLEX_HALF &&
+ if (cmd->base.duplex == DUPLEX_HALF &&
!(f & SUPPORTED_100baseT_Half))
return -EINVAL;
- if (cmd->duplex == DUPLEX_FULL &&
+ if (cmd->base.duplex == DUPLEX_FULL &&
!(f & SUPPORTED_100baseT_Full))
return -EINVAL;
break;
case SPEED_1000:
- if (cmd->duplex == DUPLEX_HALF &&
+ if (cmd->base.duplex == DUPLEX_HALF &&
!(f & SUPPORTED_1000baseT_Half))
return -EINVAL;
- if (cmd->duplex == DUPLEX_FULL &&
+ if (cmd->base.duplex == DUPLEX_FULL &&
!(f & SUPPORTED_1000baseT_Full))
return -EINVAL;
break;
@@ -2062,8 +2073,8 @@ static int emac_ethtool_set_settings(struct net_device *ndev,
}
mutex_lock(&dev->link_lock);
- dev->phy.def->ops->setup_forced(&dev->phy, cmd->speed,
- cmd->duplex);
+ dev->phy.def->ops->setup_forced(&dev->phy, cmd->base.speed,
+ cmd->base.duplex);
mutex_unlock(&dev->link_lock);
} else {
@@ -2072,7 +2083,7 @@ static int emac_ethtool_set_settings(struct net_device *ndev,
mutex_lock(&dev->link_lock);
dev->phy.def->ops->setup_aneg(&dev->phy,
- (cmd->advertising & f) |
+ (advertising & f) |
(dev->phy.advertising &
(ADVERTISED_Pause |
ADVERTISED_Asym_Pause)));
@@ -2234,8 +2245,6 @@ static void emac_ethtool_get_drvinfo(struct net_device *ndev,
}
static const struct ethtool_ops emac_ethtool_ops = {
- .get_settings = emac_ethtool_get_settings,
- .set_settings = emac_ethtool_set_settings,
.get_drvinfo = emac_ethtool_get_drvinfo,
.get_regs_len = emac_ethtool_get_regs_len,
@@ -2251,6 +2260,8 @@ static const struct ethtool_ops emac_ethtool_ops = {
.get_ethtool_stats = emac_ethtool_get_ethtool_stats,
.get_link = ethtool_op_get_link,
+ .get_link_ksettings = emac_ethtool_get_link_ksettings,
+ .set_link_ksettings = emac_ethtool_set_link_ksettings,
};
static int emac_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -2410,6 +2421,219 @@ static int emac_read_uint_prop(struct device_node *np, const char *name,
return 0;
}
+static void emac_adjust_link(struct net_device *ndev)
+{
+ struct emac_instance *dev = netdev_priv(ndev);
+ struct phy_device *phy = dev->phy_dev;
+
+ dev->phy.autoneg = phy->autoneg;
+ dev->phy.speed = phy->speed;
+ dev->phy.duplex = phy->duplex;
+ dev->phy.pause = phy->pause;
+ dev->phy.asym_pause = phy->asym_pause;
+ dev->phy.advertising = phy->advertising;
+}
+
+static int emac_mii_bus_read(struct mii_bus *bus, int addr, int regnum)
+{
+ int ret = emac_mdio_read(bus->priv, addr, regnum);
+ /* This is a workaround for powered down ports/phys.
+ * In the wild, this was seen on the Cisco Meraki MX60(W).
+ * This hardware disables ports as part of the handoff
+ * procedure. Accessing the ports will lead to errors
+ * (-ETIMEDOUT, -EREMOTEIO) that do more harm than good.
+ */
+ return ret < 0 ? 0xffff : ret;
+}
+
+static int emac_mii_bus_write(struct mii_bus *bus, int addr,
+ int regnum, u16 val)
+{
+ emac_mdio_write(bus->priv, addr, regnum, val);
+ return 0;
+}
+
+static int emac_mii_bus_reset(struct mii_bus *bus)
+{
+ struct emac_instance *dev = netdev_priv(bus->priv);
+
+ return emac_reset(dev);
+}
+
+static int emac_mdio_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+ struct net_device *ndev = phy->dev;
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ dev->phy.autoneg = AUTONEG_ENABLE;
+ dev->phy.speed = SPEED_1000;
+ dev->phy.duplex = DUPLEX_FULL;
+ dev->phy.advertising = advertise;
+ phy->autoneg = AUTONEG_ENABLE;
+ phy->speed = dev->phy.speed;
+ phy->duplex = dev->phy.duplex;
+ phy->advertising = advertise;
+ return phy_start_aneg(dev->phy_dev);
+}
+
+static int emac_mdio_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+ struct net_device *ndev = phy->dev;
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ dev->phy.autoneg = AUTONEG_DISABLE;
+ dev->phy.speed = speed;
+ dev->phy.duplex = fd;
+ phy->autoneg = AUTONEG_DISABLE;
+ phy->speed = speed;
+ phy->duplex = fd;
+ return phy_start_aneg(dev->phy_dev);
+}
+
+static int emac_mdio_poll_link(struct mii_phy *phy)
+{
+ struct net_device *ndev = phy->dev;
+ struct emac_instance *dev = netdev_priv(ndev);
+ int res;
+
+ res = phy_read_status(dev->phy_dev);
+ if (res) {
+ dev_err(&dev->ofdev->dev, "link update failed (%d).", res);
+ return ethtool_op_get_link(ndev);
+ }
+
+ return dev->phy_dev->link;
+}
+
+static int emac_mdio_read_link(struct mii_phy *phy)
+{
+ struct net_device *ndev = phy->dev;
+ struct emac_instance *dev = netdev_priv(ndev);
+ int res;
+
+ res = phy_read_status(dev->phy_dev);
+ if (res)
+ return res;
+
+ dev->phy.speed = phy->speed;
+ dev->phy.duplex = phy->duplex;
+ dev->phy.pause = phy->pause;
+ dev->phy.asym_pause = phy->asym_pause;
+ return 0;
+}
+
+static int emac_mdio_init_phy(struct mii_phy *phy)
+{
+ struct net_device *ndev = phy->dev;
+ struct emac_instance *dev = netdev_priv(ndev);
+
+ phy_start(dev->phy_dev);
+ dev->phy.autoneg = phy->autoneg;
+ dev->phy.speed = phy->speed;
+ dev->phy.duplex = phy->duplex;
+ dev->phy.advertising = phy->advertising;
+ dev->phy.pause = phy->pause;
+ dev->phy.asym_pause = phy->asym_pause;
+
+ return phy_init_hw(dev->phy_dev);
+}
+
+static const struct mii_phy_ops emac_dt_mdio_phy_ops = {
+ .init = emac_mdio_init_phy,
+ .setup_aneg = emac_mdio_setup_aneg,
+ .setup_forced = emac_mdio_setup_forced,
+ .poll_link = emac_mdio_poll_link,
+ .read_link = emac_mdio_read_link,
+};
+
+static int emac_dt_mdio_probe(struct emac_instance *dev)
+{
+ struct device_node *mii_np;
+ int res;
+
+ mii_np = of_get_child_by_name(dev->ofdev->dev.of_node, "mdio");
+ if (!mii_np) {
+ dev_err(&dev->ofdev->dev, "no mdio definition found.");
+ return -ENODEV;
+ }
+
+ if (!of_device_is_available(mii_np)) {
+ res = -ENODEV;
+ goto put_node;
+ }
+
+ dev->mii_bus = devm_mdiobus_alloc(&dev->ofdev->dev);
+ if (!dev->mii_bus) {
+ res = -ENOMEM;
+ goto put_node;
+ }
+
+ dev->mii_bus->priv = dev->ndev;
+ dev->mii_bus->parent = dev->ndev->dev.parent;
+ dev->mii_bus->name = "emac_mdio";
+ dev->mii_bus->read = &emac_mii_bus_read;
+ dev->mii_bus->write = &emac_mii_bus_write;
+ dev->mii_bus->reset = &emac_mii_bus_reset;
+ snprintf(dev->mii_bus->id, MII_BUS_ID_SIZE, "%s", dev->ofdev->name);
+ res = of_mdiobus_register(dev->mii_bus, mii_np);
+ if (res) {
+ dev_err(&dev->ofdev->dev, "cannot register MDIO bus %s (%d)",
+ dev->mii_bus->name, res);
+ }
+
+ put_node:
+ of_node_put(mii_np);
+ return res;
+}
+
+static int emac_dt_phy_connect(struct emac_instance *dev,
+ struct device_node *phy_handle)
+{
+ int res;
+
+ dev->phy.def = devm_kzalloc(&dev->ofdev->dev, sizeof(*dev->phy.def),
+ GFP_KERNEL);
+ if (!dev->phy.def)
+ return -ENOMEM;
+
+ dev->phy_dev = of_phy_connect(dev->ndev, phy_handle, &emac_adjust_link,
+ 0, dev->phy_mode);
+ if (!dev->phy_dev) {
+ dev_err(&dev->ofdev->dev, "failed to connect to PHY.\n");
+ return -ENODEV;
+ }
+
+ dev->phy.def->phy_id = dev->phy_dev->drv->phy_id;
+ dev->phy.def->phy_id_mask = dev->phy_dev->drv->phy_id_mask;
+ dev->phy.def->name = dev->phy_dev->drv->name;
+ dev->phy.def->ops = &emac_dt_mdio_phy_ops;
+ dev->phy.features = dev->phy_dev->supported;
+ dev->phy.address = dev->phy_dev->mdio.addr;
+ dev->phy.mode = dev->phy_dev->interface;
+ return 0;
+}
+
+static int emac_dt_phy_probe(struct emac_instance *dev)
+{
+ struct device_node *np = dev->ofdev->dev.of_node;
+ struct device_node *phy_handle;
+ int res = 0;
+
+ phy_handle = of_parse_phandle(np, "phy-handle", 0);
+
+ if (phy_handle) {
+ res = emac_dt_mdio_probe(dev);
+ if (!res) {
+ res = emac_dt_phy_connect(dev, phy_handle);
+ if (res)
+ mdiobus_unregister(dev->mii_bus);
+ }
+ }
+
+ of_node_put(phy_handle);
+ return res;
+}
+
static int emac_init_phy(struct emac_instance *dev)
{
struct device_node *np = dev->ofdev->dev.of_node;
@@ -2420,15 +2644,12 @@ static int emac_init_phy(struct emac_instance *dev)
dev->phy.dev = ndev;
dev->phy.mode = dev->phy_mode;
- /* PHY-less configuration.
- * XXX I probably should move these settings to the dev tree
- */
- if (dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) {
+ /* PHY-less configuration. */
+ if ((dev->phy_address == 0xffffffff && dev->phy_map == 0xffffffff) ||
+ of_phy_is_fixed_link(np)) {
emac_reset(dev);
- /* PHY-less configuration.
- * XXX I probably should move these settings to the dev tree
- */
+ /* PHY-less configuration. */
dev->phy.address = -1;
dev->phy.features = SUPPORTED_MII;
if (emac_phy_supports_gige(dev->phy_mode))
@@ -2437,6 +2658,16 @@ static int emac_init_phy(struct emac_instance *dev)
dev->phy.features |= SUPPORTED_100baseT_Full;
dev->phy.pause = 1;
+ if (of_phy_is_fixed_link(np)) {
+ int res = emac_dt_mdio_probe(dev);
+
+ if (!res) {
+ res = of_phy_register_fixed_link(np);
+ if (res)
+ mdiobus_unregister(dev->mii_bus);
+ }
+ return res;
+ }
return 0;
}
@@ -2480,6 +2711,18 @@ static int emac_init_phy(struct emac_instance *dev)
emac_configure(dev);
+ if (emac_has_feature(dev, EMAC_FTR_HAS_RGMII)) {
+ int res = emac_dt_phy_probe(dev);
+
+ mutex_unlock(&emac_phy_map_lock);
+ if (!res)
+ goto init_phy;
+
+ dev_err(&dev->ofdev->dev, "failed to attach dt phy (%d).\n",
+ res);
+ return res;
+ }
+
if (dev->phy_address != 0xffffffff)
phy_map = ~(1 << dev->phy_address);
@@ -2507,6 +2750,7 @@ static int emac_init_phy(struct emac_instance *dev)
return -ENXIO;
}
+ init_phy:
/* Init PHY */
if (dev->phy.def->ops->init)
dev->phy.def->ops->init(&dev->phy);
@@ -2978,6 +3222,12 @@ static int emac_remove(struct platform_device *ofdev)
if (emac_has_feature(dev, EMAC_FTR_HAS_ZMII))
zmii_detach(dev->zmii_dev, dev->zmii_port);
+ if (dev->phy_dev)
+ phy_disconnect(dev->phy_dev);
+
+ if (dev->mii_bus)
+ mdiobus_unregister(dev->mii_bus);
+
busy_phy_map &= ~(1 << dev->phy.address);
DBG(dev, "busy_phy_map now %#x" NL, busy_phy_map);
diff --git a/drivers/net/ethernet/ibm/emac/core.h b/drivers/net/ethernet/ibm/emac/core.h
index 93ae11494810..0710a6685489 100644
--- a/drivers/net/ethernet/ibm/emac/core.h
+++ b/drivers/net/ethernet/ibm/emac/core.h
@@ -199,6 +199,10 @@ struct emac_instance {
struct emac_instance *mdio_instance;
struct mutex mdio_lock;
+ /* Device-tree based phy configuration */
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+
/* ZMII infos if any */
u32 zmii_ph;
u32 zmii_port;
diff --git a/drivers/net/ethernet/ibm/emac/mal.c b/drivers/net/ethernet/ibm/emac/mal.c
index aaf6fec566b5..cd3227b088b7 100644
--- a/drivers/net/ethernet/ibm/emac/mal.c
+++ b/drivers/net/ethernet/ibm/emac/mal.c
@@ -421,20 +421,20 @@ static int mal_poll(struct napi_struct *napi, int budget)
int n;
if (unlikely(test_bit(MAL_COMMAC_POLL_DISABLED, &mc->flags)))
continue;
- n = mc->ops->poll_rx(mc->dev, budget);
+ n = mc->ops->poll_rx(mc->dev, budget - received);
if (n) {
received += n;
- budget -= n;
- if (budget <= 0)
- goto more_work; // XXX What if this is the last one ?
+ if (received >= budget)
+ return budget;
}
}
- /* We need to disable IRQs to protect from RXDE IRQ here */
- spin_lock_irqsave(&mal->lock, flags);
- __napi_complete(napi);
- mal_enable_eob_irq(mal);
- spin_unlock_irqrestore(&mal->lock, flags);
+ if (napi_complete_done(napi, received)) {
+ /* We need to disable IRQs to protect from RXDE IRQ here */
+ spin_lock_irqsave(&mal->lock, flags);
+ mal_enable_eob_irq(mal);
+ spin_unlock_irqrestore(&mal->lock, flags);
+ }
/* Check for "rotting" packet(s) */
list_for_each(l, &mal->poll_list) {
diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c
index 309f5c66083c..72ab7b6bf20b 100644
--- a/drivers/net/ethernet/ibm/ibmveth.c
+++ b/drivers/net/ethernet/ibm/ibmveth.c
@@ -729,20 +729,26 @@ static int ibmveth_close(struct net_device *netdev)
return 0;
}
-static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+static int netdev_get_link_ksettings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
{
- cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+ u32 supported, advertising;
+
+ supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
SUPPORTED_FIBRE);
- cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
+ advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
ADVERTISED_FIBRE);
- ethtool_cmd_speed_set(cmd, SPEED_1000);
- cmd->duplex = DUPLEX_FULL;
- cmd->port = PORT_FIBRE;
- cmd->phy_address = 0;
- cmd->transceiver = XCVR_INTERNAL;
- cmd->autoneg = AUTONEG_ENABLE;
- cmd->maxtxpkt = 0;
- cmd->maxrxpkt = 1;
+ cmd->base.speed = SPEED_1000;
+ cmd->base.duplex = DUPLEX_FULL;
+ cmd->base.port = PORT_FIBRE;
+ cmd->base.phy_address = 0;
+ cmd->base.autoneg = AUTONEG_ENABLE;
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
return 0;
}
@@ -978,11 +984,11 @@ static void ibmveth_get_ethtool_stats(struct net_device *dev,
static const struct ethtool_ops netdev_ethtool_ops = {
.get_drvinfo = netdev_get_drvinfo,
- .get_settings = netdev_get_settings,
.get_link = ethtool_op_get_link,
.get_strings = ibmveth_get_strings,
.get_sset_count = ibmveth_get_sset_count,
.get_ethtool_stats = ibmveth_get_ethtool_stats,
+ .get_link_ksettings = netdev_get_link_ksettings,
};
static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
@@ -1320,7 +1326,7 @@ restart_poll:
ibmveth_replenish_task(adapter);
if (frames_processed < budget) {
- napi_complete(napi);
+ napi_complete_done(napi, frames_processed);
/* We think we are done - reenable interrupts,
* then check once more to make sure we are done.
diff --git a/drivers/net/ethernet/ibm/ibmvnic.c b/drivers/net/ethernet/ibm/ibmvnic.c
index c12596676bbb..9198e6bd5160 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.c
+++ b/drivers/net/ethernet/ibm/ibmvnic.c
@@ -189,9 +189,10 @@ static int alloc_long_term_buff(struct ibmvnic_adapter *adapter,
}
ltb->map_id = adapter->map_id;
adapter->map_id++;
+
+ init_completion(&adapter->fw_done);
send_request_map(adapter, ltb->addr,
ltb->size, ltb->map_id);
- init_completion(&adapter->fw_done);
wait_for_completion(&adapter->fw_done);
return 0;
}
@@ -505,7 +506,7 @@ rx_pool_alloc_failed:
adapter->rx_pool = NULL;
rx_pool_arr_alloc_failed:
for (i = 0; i < adapter->req_rx_queues; i++)
- napi_enable(&adapter->napi[i]);
+ napi_disable(&adapter->napi[i]);
alloc_napi_failed:
return -ENOMEM;
}
@@ -987,7 +988,7 @@ restart_poll:
if (frames_processed < budget) {
enable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]);
- napi_complete(napi);
+ napi_complete_done(napi, frames_processed);
if (pending_scrq(adapter, adapter->rx_scrq[scrq_num]) &&
napi_reschedule(napi)) {
disable_scrq_irq(adapter, adapter->rx_scrq[scrq_num]);
@@ -1025,21 +1026,26 @@ static const struct net_device_ops ibmvnic_netdev_ops = {
/* ethtool functions */
-static int ibmvnic_get_settings(struct net_device *netdev,
- struct ethtool_cmd *cmd)
+static int ibmvnic_get_link_ksettings(struct net_device *netdev,
+ struct ethtool_link_ksettings *cmd)
{
- cmd->supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
+ u32 supported, advertising;
+
+ supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
SUPPORTED_FIBRE);
- cmd->advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
+ advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
ADVERTISED_FIBRE);
- ethtool_cmd_speed_set(cmd, SPEED_1000);
- cmd->duplex = DUPLEX_FULL;
- cmd->port = PORT_FIBRE;
- cmd->phy_address = 0;
- cmd->transceiver = XCVR_INTERNAL;
- cmd->autoneg = AUTONEG_ENABLE;
- cmd->maxtxpkt = 0;
- cmd->maxrxpkt = 1;
+ cmd->base.speed = SPEED_1000;
+ cmd->base.duplex = DUPLEX_FULL;
+ cmd->base.port = PORT_FIBRE;
+ cmd->base.phy_address = 0;
+ cmd->base.autoneg = AUTONEG_ENABLE;
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
+ advertising);
+
return 0;
}
@@ -1121,10 +1127,10 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
crq.request_statistics.ioba = cpu_to_be32(adapter->stats_token);
crq.request_statistics.len =
cpu_to_be32(sizeof(struct ibmvnic_statistics));
- ibmvnic_send_crq(adapter, &crq);
/* Wait for data to be written */
init_completion(&adapter->stats_done);
+ ibmvnic_send_crq(adapter, &crq);
wait_for_completion(&adapter->stats_done);
for (i = 0; i < ARRAY_SIZE(ibmvnic_stats); i++)
@@ -1132,7 +1138,6 @@ static void ibmvnic_get_ethtool_stats(struct net_device *dev,
}
static const struct ethtool_ops ibmvnic_ethtool_ops = {
- .get_settings = ibmvnic_get_settings,
.get_drvinfo = ibmvnic_get_drvinfo,
.get_msglevel = ibmvnic_get_msglevel,
.set_msglevel = ibmvnic_set_msglevel,
@@ -1141,6 +1146,7 @@ static const struct ethtool_ops ibmvnic_ethtool_ops = {
.get_strings = ibmvnic_get_strings,
.get_sset_count = ibmvnic_get_sset_count,
.get_ethtool_stats = ibmvnic_get_ethtool_stats,
+ .get_link_ksettings = ibmvnic_get_link_ksettings,
};
/* Routines for managing CRQs/sCRQs */
@@ -1254,8 +1260,6 @@ static void release_sub_crqs(struct ibmvnic_adapter *adapter)
}
adapter->rx_scrq = NULL;
}
-
- adapter->requested_caps = 0;
}
static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *adapter)
@@ -1277,8 +1281,6 @@ static void release_sub_crqs_no_irqs(struct ibmvnic_adapter *adapter)
adapter->rx_scrq[i]);
adapter->rx_scrq = NULL;
}
-
- adapter->requested_caps = 0;
}
static int disable_scrq_irq(struct ibmvnic_adapter *adapter,
@@ -1496,7 +1498,7 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
adapter->req_rx_queues = adapter->opt_rx_comp_queues;
adapter->req_rx_add_queues = adapter->max_rx_add_queues;
- adapter->req_mtu = adapter->max_mtu;
+ adapter->req_mtu = adapter->netdev->mtu + ETH_HLEN;
}
total_queues = adapter->req_tx_queues + adapter->req_rx_queues;
@@ -1566,30 +1568,36 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
crq.request_capability.capability = cpu_to_be16(REQ_TX_QUEUES);
crq.request_capability.number = cpu_to_be64(adapter->req_tx_queues);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability = cpu_to_be16(REQ_RX_QUEUES);
crq.request_capability.number = cpu_to_be64(adapter->req_rx_queues);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability = cpu_to_be16(REQ_RX_ADD_QUEUES);
crq.request_capability.number = cpu_to_be64(adapter->req_rx_add_queues);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability =
cpu_to_be16(REQ_TX_ENTRIES_PER_SUBCRQ);
crq.request_capability.number =
cpu_to_be64(adapter->req_tx_entries_per_subcrq);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability =
cpu_to_be16(REQ_RX_ADD_ENTRIES_PER_SUBCRQ);
crq.request_capability.number =
cpu_to_be64(adapter->req_rx_add_entries_per_subcrq);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.request_capability.capability = cpu_to_be16(REQ_MTU);
crq.request_capability.number = cpu_to_be64(adapter->req_mtu);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
if (adapter->netdev->flags & IFF_PROMISC) {
@@ -1597,12 +1605,14 @@ static void init_sub_crqs(struct ibmvnic_adapter *adapter, int retry)
crq.request_capability.capability =
cpu_to_be16(PROMISC_REQUESTED);
crq.request_capability.number = cpu_to_be64(1);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
}
} else {
crq.request_capability.capability =
cpu_to_be16(PROMISC_REQUESTED);
crq.request_capability.number = cpu_to_be64(0);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
}
@@ -1954,112 +1964,112 @@ static void send_cap_queries(struct ibmvnic_adapter *adapter)
{
union ibmvnic_crq crq;
- atomic_set(&adapter->running_cap_queries, 0);
+ atomic_set(&adapter->running_cap_crqs, 0);
memset(&crq, 0, sizeof(crq));
crq.query_capability.first = IBMVNIC_CRQ_CMD;
crq.query_capability.cmd = QUERY_CAPABILITY;
crq.query_capability.capability = cpu_to_be16(MIN_TX_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MIN_RX_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MIN_RX_ADD_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MAX_TX_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MAX_RX_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MAX_RX_ADD_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(MIN_TX_ENTRIES_PER_SUBCRQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(MIN_RX_ADD_ENTRIES_PER_SUBCRQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(MAX_TX_ENTRIES_PER_SUBCRQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(MAX_RX_ADD_ENTRIES_PER_SUBCRQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(TCP_IP_OFFLOAD);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(PROMISC_SUPPORTED);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MIN_MTU);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MAX_MTU);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MAX_MULTICAST_FILTERS);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(VLAN_HEADER_INSERTION);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(MAX_TX_SG_ENTRIES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(RX_SG_SUPPORTED);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(OPT_TX_COMP_SUB_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(OPT_RX_COMP_QUEUES);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(OPT_RX_BUFADD_Q_PER_RX_COMP_Q);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(OPT_TX_ENTRIES_PER_SUBCRQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability =
cpu_to_be16(OPT_RXBA_ENTRIES_PER_SUBCRQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
crq.query_capability.capability = cpu_to_be16(TX_RX_DESC_REQ);
- atomic_inc(&adapter->running_cap_queries);
+ atomic_inc(&adapter->running_cap_crqs);
ibmvnic_send_crq(adapter, &crq);
}
@@ -2185,12 +2195,12 @@ static void handle_error_info_rsp(union ibmvnic_crq *crq,
if (!found) {
dev_err(dev, "Couldn't find error id %x\n",
- crq->request_error_rsp.error_id);
+ be32_to_cpu(crq->request_error_rsp.error_id));
return;
}
dev_err(dev, "Detailed info for error id %x:",
- crq->request_error_rsp.error_id);
+ be32_to_cpu(crq->request_error_rsp.error_id));
for (i = 0; i < error_buff->len; i++) {
pr_cont("%02x", (int)error_buff->buff[i]);
@@ -2269,8 +2279,8 @@ static void handle_error_indication(union ibmvnic_crq *crq,
dev_err(dev, "Firmware reports %serror id %x, cause %d\n",
crq->error_indication.
flags & IBMVNIC_FATAL_ERROR ? "FATAL " : "",
- crq->error_indication.error_id,
- crq->error_indication.error_cause);
+ be32_to_cpu(crq->error_indication.error_id),
+ be16_to_cpu(crq->error_indication.error_cause));
error_buff = kmalloc(sizeof(*error_buff), GFP_ATOMIC);
if (!error_buff)
@@ -2347,6 +2357,7 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
u64 *req_value;
char *name;
+ atomic_dec(&adapter->running_cap_crqs);
switch (be16_to_cpu(crq->request_capability_rsp.capability)) {
case REQ_TX_QUEUES:
req_value = &adapter->req_tx_queues;
@@ -2388,10 +2399,10 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
case PARTIALSUCCESS:
dev_info(dev, "req=%lld, rsp=%ld in %s queue, retrying.\n",
*req_value,
- (long int)be32_to_cpu(crq->request_capability_rsp.
+ (long int)be64_to_cpu(crq->request_capability_rsp.
number), name);
release_sub_crqs_no_irqs(adapter);
- *req_value = be32_to_cpu(crq->request_capability_rsp.number);
+ *req_value = be64_to_cpu(crq->request_capability_rsp.number);
init_sub_crqs(adapter, 1);
return;
default:
@@ -2401,12 +2412,13 @@ static void handle_request_cap_rsp(union ibmvnic_crq *crq,
}
/* Done receiving requested capabilities, query IP offload support */
- if (++adapter->requested_caps == 7) {
+ if (atomic_read(&adapter->running_cap_crqs) == 0) {
union ibmvnic_crq newcrq;
int buf_sz = sizeof(struct ibmvnic_query_ip_offload_buffer);
struct ibmvnic_query_ip_offload_buffer *ip_offload_buf =
&adapter->ip_offload_buf;
+ adapter->wait_capability = false;
adapter->ip_offload_tok = dma_map_single(dev, ip_offload_buf,
buf_sz,
DMA_FROM_DEVICE);
@@ -2542,9 +2554,9 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
struct device *dev = &adapter->vdev->dev;
long rc;
- atomic_dec(&adapter->running_cap_queries);
+ atomic_dec(&adapter->running_cap_crqs);
netdev_dbg(netdev, "Outstanding queries: %d\n",
- atomic_read(&adapter->running_cap_queries));
+ atomic_read(&adapter->running_cap_crqs));
rc = crq->query_capability.rc.code;
if (rc) {
dev_err(dev, "Error %ld in QUERY_CAP_RSP\n", rc);
@@ -2626,12 +2638,12 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
break;
case MIN_MTU:
adapter->min_mtu = be64_to_cpu(crq->query_capability.number);
- netdev->min_mtu = adapter->min_mtu;
+ netdev->min_mtu = adapter->min_mtu - ETH_HLEN;
netdev_dbg(netdev, "min_mtu = %lld\n", adapter->min_mtu);
break;
case MAX_MTU:
adapter->max_mtu = be64_to_cpu(crq->query_capability.number);
- netdev->max_mtu = adapter->max_mtu;
+ netdev->max_mtu = adapter->max_mtu - ETH_HLEN;
netdev_dbg(netdev, "max_mtu = %lld\n", adapter->max_mtu);
break;
case MAX_MULTICAST_FILTERS:
@@ -2702,9 +2714,11 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
}
out:
- if (atomic_read(&adapter->running_cap_queries) == 0)
+ if (atomic_read(&adapter->running_cap_crqs) == 0) {
+ adapter->wait_capability = false;
init_sub_crqs(adapter, 0);
/* We're done querying the capabilities, initialize sub-crqs */
+ }
}
static void handle_control_ras_rsp(union ibmvnic_crq *crq,
@@ -2799,9 +2813,9 @@ static ssize_t trace_read(struct file *file, char __user *user_buf, size_t len,
crq.collect_fw_trace.correlator = adapter->ras_comps[num].correlator;
crq.collect_fw_trace.ioba = cpu_to_be32(trace_tok);
crq.collect_fw_trace.len = adapter->ras_comps[num].trace_buff_size;
- ibmvnic_send_crq(adapter, &crq);
init_completion(&adapter->fw_done);
+ ibmvnic_send_crq(adapter, &crq);
wait_for_completion(&adapter->fw_done);
if (*ppos + len > be32_to_cpu(adapter->ras_comps[num].trace_buff_size))
@@ -3414,6 +3428,18 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
static irqreturn_t ibmvnic_interrupt(int irq, void *instance)
{
struct ibmvnic_adapter *adapter = instance;
+ unsigned long flags;
+
+ spin_lock_irqsave(&adapter->crq.lock, flags);
+ vio_disable_interrupts(adapter->vdev);
+ tasklet_schedule(&adapter->tasklet);
+ spin_unlock_irqrestore(&adapter->crq.lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void ibmvnic_tasklet(void *data)
+{
+ struct ibmvnic_adapter *adapter = data;
struct ibmvnic_crq_queue *queue = &adapter->crq;
struct vio_dev *vdev = adapter->vdev;
union ibmvnic_crq *crq;
@@ -3435,11 +3461,19 @@ static irqreturn_t ibmvnic_interrupt(int irq, void *instance)
ibmvnic_handle_crq(crq, adapter);
crq->generic.first = 0;
} else {
- done = true;
+ /* remain in tasklet until all
+ * capabilities responses are received
+ */
+ if (!adapter->wait_capability)
+ done = true;
}
}
+ /* if capabilities CRQ's were sent in this tasklet, the following
+ * tasklet must wait until all responses are received
+ */
+ if (atomic_read(&adapter->running_cap_crqs) != 0)
+ adapter->wait_capability = true;
spin_unlock_irqrestore(&queue->lock, flags);
- return IRQ_HANDLED;
}
static int ibmvnic_reenable_crq_queue(struct ibmvnic_adapter *adapter)
@@ -3494,6 +3528,7 @@ static void ibmvnic_release_crq_queue(struct ibmvnic_adapter *adapter)
netdev_dbg(adapter->netdev, "Releasing CRQ\n");
free_irq(vdev->irq, adapter);
+ tasklet_kill(&adapter->tasklet);
do {
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -3539,6 +3574,9 @@ static int ibmvnic_init_crq_queue(struct ibmvnic_adapter *adapter)
retrc = 0;
+ tasklet_init(&adapter->tasklet, (void *)ibmvnic_tasklet,
+ (unsigned long)adapter);
+
netdev_dbg(adapter->netdev, "registering irq 0x%x\n", vdev->irq);
rc = request_irq(vdev->irq, ibmvnic_interrupt, 0, IBMVNIC_NAME,
adapter);
@@ -3560,6 +3598,7 @@ static int ibmvnic_init_crq_queue(struct ibmvnic_adapter *adapter)
return retrc;
req_irq_failed:
+ tasklet_kill(&adapter->tasklet);
do {
rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
} while (rc == H_BUSY || H_IS_LONG_BUSY(rc));
@@ -3581,9 +3620,9 @@ static int ibmvnic_dump_show(struct seq_file *seq, void *v)
memset(&crq, 0, sizeof(crq));
crq.request_dump_size.first = IBMVNIC_CRQ_CMD;
crq.request_dump_size.cmd = REQUEST_DUMP_SIZE;
- ibmvnic_send_crq(adapter, &crq);
init_completion(&adapter->fw_done);
+ ibmvnic_send_crq(adapter, &crq);
wait_for_completion(&adapter->fw_done);
seq_write(seq, adapter->dump_data, adapter->dump_data_size);
@@ -3629,8 +3668,8 @@ static void handle_crq_init_rsp(struct work_struct *work)
}
}
- send_version_xchg(adapter);
reinit_completion(&adapter->init_done);
+ send_version_xchg(adapter);
if (!wait_for_completion_timeout(&adapter->init_done, timeout)) {
dev_err(dev, "Passive init timeout\n");
goto task_failed;
@@ -3640,9 +3679,9 @@ static void handle_crq_init_rsp(struct work_struct *work)
if (adapter->renegotiate) {
adapter->renegotiate = false;
release_sub_crqs_no_irqs(adapter);
- send_cap_queries(adapter);
reinit_completion(&adapter->init_done);
+ send_cap_queries(adapter);
if (!wait_for_completion_timeout(&adapter->init_done,
timeout)) {
dev_err(dev, "Passive init timeout\n");
@@ -3656,9 +3695,7 @@ static void handle_crq_init_rsp(struct work_struct *work)
goto task_failed;
netdev->real_num_tx_queues = adapter->req_tx_queues;
- netdev->mtu = adapter->req_mtu;
- netdev->min_mtu = adapter->min_mtu;
- netdev->max_mtu = adapter->max_mtu;
+ netdev->mtu = adapter->req_mtu - ETH_HLEN;
if (adapter->failover) {
adapter->failover = false;
@@ -3772,9 +3809,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
adapter->debugfs_dump = ent;
}
}
- ibmvnic_send_crq_init(adapter);
init_completion(&adapter->init_done);
+ ibmvnic_send_crq_init(adapter);
if (!wait_for_completion_timeout(&adapter->init_done, timeout))
return 0;
@@ -3782,9 +3819,9 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
if (adapter->renegotiate) {
adapter->renegotiate = false;
release_sub_crqs_no_irqs(adapter);
- send_cap_queries(adapter);
reinit_completion(&adapter->init_done);
+ send_cap_queries(adapter);
if (!wait_for_completion_timeout(&adapter->init_done,
timeout))
return 0;
@@ -3798,7 +3835,7 @@ static int ibmvnic_probe(struct vio_dev *dev, const struct vio_device_id *id)
}
netdev->real_num_tx_queues = adapter->req_tx_queues;
- netdev->mtu = adapter->req_mtu;
+ netdev->mtu = adapter->req_mtu - ETH_HLEN;
rc = register_netdev(netdev);
if (rc) {
diff --git a/drivers/net/ethernet/ibm/ibmvnic.h b/drivers/net/ethernet/ibm/ibmvnic.h
index dd775d951b73..422824f1f42a 100644
--- a/drivers/net/ethernet/ibm/ibmvnic.h
+++ b/drivers/net/ethernet/ibm/ibmvnic.h
@@ -976,11 +976,11 @@ struct ibmvnic_adapter {
dma_addr_t login_rsp_buf_token;
int login_rsp_buf_sz;
- atomic_t running_cap_queries;
+ atomic_t running_cap_crqs;
+ bool wait_capability;
struct ibmvnic_sub_crq_queue **tx_scrq;
struct ibmvnic_sub_crq_queue **rx_scrq;
- int requested_caps;
bool renegotiate;
/* rx structs */
@@ -1049,5 +1049,6 @@ struct ibmvnic_adapter {
struct work_struct vnic_crq_init;
struct work_struct ibmvnic_xport;
+ struct tasklet_struct tasklet;
bool failover;
};