aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet')
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.c24
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmgenet.h2
-rw-r--r--drivers/net/ethernet/broadcom/genet/bcmmii.c6
-rw-r--r--drivers/net/ethernet/cadence/macb.h25
-rw-r--r--drivers/net/ethernet/cadence/macb_main.c140
5 files changed, 190 insertions, 7 deletions
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
index 98971ae4f87d..0d89590d0022 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c
@@ -65,6 +65,12 @@
/* Forward declarations */
static void bcmgenet_set_rx_mode(struct net_device *dev);
+static bool skip_umac_reset = false;
+module_param(skip_umac_reset, bool, 0444);
+MODULE_PARM_DESC(skip_umac_reset, "Skip UMAC reset step");
+static bool eee = true;
+module_param(eee, bool, 0444);
+MODULE_PARM_DESC(eee, "Enable EEE (default Y)");
static inline void bcmgenet_writel(u32 value, void __iomem *offset)
{
@@ -2566,6 +2572,11 @@ static void reset_umac(struct bcmgenet_priv *priv)
bcmgenet_rbuf_ctrl_set(priv, 0);
udelay(10);
+ if (skip_umac_reset) {
+ pr_warn("Skipping UMAC reset\n");
+ return;
+ }
+
/* issue soft reset and disable MAC while updating its registers */
spin_lock_bh(&priv->reg_lock);
bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD);
@@ -2728,7 +2739,7 @@ static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv,
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX);
bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX);
- bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH);
+ bcmgenet_tdma_ring_writel(priv, index, 10, DMA_MBUF_DONE_THRESH);
/* Disable rate control for now */
bcmgenet_tdma_ring_writel(priv, index, flow_period_val,
TDMA_FLOW_PERIOD);
@@ -3363,6 +3374,17 @@ static int bcmgenet_open(struct net_device *dev)
bcmgenet_phy_pause_set(dev, priv->rx_pause, priv->tx_pause);
+ if (!eee) {
+ struct ethtool_keee eee_data;
+
+ ret = bcmgenet_get_eee(dev, &eee_data);
+ if (ret == 0) {
+ eee_data.eee_enabled = 0;
+ bcmgenet_set_eee(dev, &eee_data);
+ netdev_warn(dev, "EEE disabled\n");
+ }
+ }
+
bcmgenet_netif_start(dev);
netif_tx_start_all_queues(dev);
diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
index 5ec3979779ec..3527e8e23a66 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h
+++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h
@@ -34,7 +34,7 @@
#define ENET_PAD 8
#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \
ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD)
-#define DMA_MAX_BURST_LENGTH 0x10
+#define DMA_MAX_BURST_LENGTH 0x08
/* misc. configuration */
#define MAX_NUM_OF_FS_RULES 16
diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c
index 573e8b279e52..f2fd1e5a4015 100644
--- a/drivers/net/ethernet/broadcom/genet/bcmmii.c
+++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c
@@ -309,14 +309,14 @@ int bcmgenet_mii_probe(struct net_device *dev)
struct device_node *dn = kdev->of_node;
phy_interface_t phy_iface = priv->phy_interface;
struct phy_device *phydev;
- u32 phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE |
- PHY_BRCM_DIS_TXCRXC_NOENRGY |
- PHY_BRCM_IDDQ_SUSPEND;
+ u32 phy_flags = 0;
int ret;
/* Communicate the integrated PHY revision */
if (priv->internal_phy)
phy_flags = priv->gphy_rev;
+ else
+ phy_flags = PHY_BRCM_AUTO_PWRDWN_ENABLE;
/* This is an ugly quirk but we have not been correctly interpreting
* the phy_interface values and we have done that across different
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 0830c48973aa..2c814a2d06b7 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -86,6 +86,8 @@
#define GEM_PBUFRXCUT 0x0044 /* RX Partial Store and Forward */
#define GEM_JML 0x0048 /* Jumbo Max Length */
#define GEM_HS_MAC_CONFIG 0x0050 /* GEM high speed config */
+#define GEM_AMP 0x0054 /* AXI Max Pipeline */
+#define GEM_INTMOD 0x005c /* Interrupt moderation */
#define GEM_HRB 0x0080 /* Hash Bottom */
#define GEM_HRT 0x0084 /* Hash Top */
#define GEM_SA1B 0x0088 /* Specific1 Bottom */
@@ -360,6 +362,21 @@
#define GEM_ADDR64_OFFSET 30 /* Address bus width - 64b or 32b */
#define GEM_ADDR64_SIZE 1
+/* Bitfields in AMP */
+#define GEM_AR2R_MAX_PIPE_OFFSET 0 /* Maximum number of outstanding AXI read requests */
+#define GEM_AR2R_MAX_PIPE_SIZE 8
+#define GEM_AW2W_MAX_PIPE_OFFSET 8 /* Maximum number of outstanding AXI write requests */
+#define GEM_AW2W_MAX_PIPE_SIZE 8
+#define GEM_AW2B_FILL_OFFSET 16 /* Select wether the max AW2W transactions operates between: */
+#define GEM_AW2B_FILL_AW2W 0 /* 0: the AW to W AXI channel */
+#define GEM_AW2B_FILL_AW2B 1 /* 1: AW to B channel */
+#define GEM_AW2B_FILL_SIZE 1
+
+/* Bitfields in INTMOD */
+#define GEM_RX_MODERATION_OFFSET 0 /* RX interrupt moderation */
+#define GEM_RX_MODERATION_SIZE 8
+#define GEM_TX_MODERATION_OFFSET 16 /* TX interrupt moderation */
+#define GEM_TX_MODERATION_SIZE 8
/* Bitfields in PBUFRXCUT */
#define GEM_ENCUTTHRU_OFFSET 31 /* Enable RX partial store and forward */
@@ -843,6 +860,7 @@
})
#define MACB_READ_NSR(bp) macb_readl(bp, NSR)
+#define MACB_READ_TSR(bp) macb_readl(bp, TSR)
/* struct macb_dma_desc - Hardware DMA descriptor
* @addr: DMA address of data buffer
@@ -1260,6 +1278,7 @@ struct macb_queue {
dma_addr_t tx_ring_dma;
struct work_struct tx_error_task;
bool txubr_pending;
+ bool tx_pending;
struct napi_struct napi_tx;
dma_addr_t rx_ring_dma;
@@ -1327,9 +1346,15 @@ struct macb {
u32 caps;
unsigned int dma_burst_length;
+ u8 aw2w_max_pipe;
+ u8 ar2r_max_pipe;
+ bool use_aw2b_fill;
phy_interface_t phy_interface;
+ struct gpio_desc *phy_reset_gpio;
+ int phy_reset_ms;
+
/* AT91RM9200 transmit queue (1 on wire + 1 queued) */
struct macb_tx_skb rm9200_txq[2];
unsigned int max_tx_length;
diff --git a/drivers/net/ethernet/cadence/macb_main.c b/drivers/net/ethernet/cadence/macb_main.c
index ca2386b83473..db4c08e1514a 100644
--- a/drivers/net/ethernet/cadence/macb_main.c
+++ b/drivers/net/ethernet/cadence/macb_main.c
@@ -21,6 +21,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/dma-mapping.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_device.h>
#include <linux/phylink.h>
#include <linux/of.h>
@@ -39,6 +40,9 @@
#include <net/pkt_sched.h>
#include "macb.h"
+static unsigned int txdelay = 35;
+module_param(txdelay, uint, 0644);
+
/* This structure is only used for MACB on SiFive FU540 devices */
struct sifive_fu540_macb_mgmt {
void __iomem *reg;
@@ -328,7 +332,7 @@ static int macb_mdio_wait_for_idle(struct macb *bp)
u32 val;
return readx_poll_timeout(MACB_READ_NSR, bp, val, val & MACB_BIT(IDLE),
- 1, MACB_MDIO_TIMEOUT);
+ 100, MACB_MDIO_TIMEOUT);
}
static int macb_mdio_read_c22(struct mii_bus *bus, int mii_id, int regnum)
@@ -487,6 +491,19 @@ mdio_pm_exit:
return status;
}
+static int macb_mdio_reset(struct mii_bus *bus)
+{
+ struct macb *bp = bus->priv;
+
+ if (bp->phy_reset_gpio) {
+ gpiod_set_value_cansleep(bp->phy_reset_gpio, 1);
+ msleep(bp->phy_reset_ms);
+ gpiod_set_value_cansleep(bp->phy_reset_gpio, 0);
+ }
+
+ return 0;
+}
+
static void macb_init_buffers(struct macb *bp)
{
struct macb_queue *queue;
@@ -953,6 +970,7 @@ static int macb_mii_init(struct macb *bp)
bp->mii_bus->write = &macb_mdio_write_c22;
bp->mii_bus->read_c45 = &macb_mdio_read_c45;
bp->mii_bus->write_c45 = &macb_mdio_write_c45;
+ bp->mii_bus->reset = &macb_mdio_reset;
snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x",
bp->pdev->name, bp->pdev->id);
bp->mii_bus->priv = bp;
@@ -1629,6 +1647,11 @@ static int macb_rx(struct macb_queue *queue, struct napi_struct *napi,
macb_init_rx_ring(queue);
queue_writel(queue, RBQP, queue->rx_ring_dma);
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ if (bp->hw_dma_cap & HW_DMA_CAP_64B)
+ macb_writel(bp, RBQPH,
+ upper_32_bits(queue->rx_ring_dma));
+#endif
macb_writel(bp, NCR, ctrl | MACB_BIT(RE));
@@ -1931,8 +1954,9 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id)
queue_writel(queue, ISR, MACB_BIT(TCOMP) |
MACB_BIT(TXUBR));
- if (status & MACB_BIT(TXUBR)) {
+ if (status & MACB_BIT(TXUBR) || queue->tx_pending) {
queue->txubr_pending = true;
+ queue->tx_pending = 0;
wmb(); // ensure softirq can see update
}
@@ -2390,6 +2414,11 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len);
spin_lock(&bp->lock);
+
+ /* TSTART write might get dropped, so make the IRQ retrigger a buffer read */
+ if (macb_readl(bp, TSR) & MACB_BIT(TGO))
+ queue->tx_pending = 1;
+
macb_writel(bp, NCR, macb_readl(bp, NCR) | MACB_BIT(TSTART));
spin_unlock(&bp->lock);
@@ -2813,6 +2842,37 @@ static void macb_configure_dma(struct macb *bp)
}
}
+static void gem_init_axi(struct macb *bp)
+{
+ u32 amp;
+
+ /* AXI pipeline setup - don't touch values unless specified in device
+ * tree. Some hardware could have reset values > 1.
+ */
+ amp = gem_readl(bp, AMP);
+
+ if (bp->use_aw2b_fill)
+ amp = GEM_BFINS(AW2B_FILL, bp->use_aw2b_fill, amp);
+ if (bp->aw2w_max_pipe)
+ amp = GEM_BFINS(AW2W_MAX_PIPE, bp->aw2w_max_pipe, amp);
+ if (bp->ar2r_max_pipe)
+ amp = GEM_BFINS(AR2R_MAX_PIPE, bp->ar2r_max_pipe, amp);
+
+ gem_writel(bp, AMP, amp);
+}
+
+static void gem_init_intmod(struct macb *bp)
+{
+ unsigned int throttle;
+ u32 intmod = 0;
+
+ /* Use sensible interrupt moderation thresholds (50us rx and tx) */
+ throttle = (1000 * 50) / 800;
+ intmod = GEM_BFINS(TX_MODERATION, throttle, intmod);
+ intmod = GEM_BFINS(RX_MODERATION, throttle, intmod);
+ gem_writel(bp, INTMOD, intmod);
+}
+
static void macb_init_hw(struct macb *bp)
{
u32 config;
@@ -2841,6 +2901,11 @@ static void macb_init_hw(struct macb *bp)
if (bp->caps & MACB_CAPS_JUMBO)
bp->rx_frm_len_mask = MACB_RX_JFRMLEN_MASK;
+ if (macb_is_gem(bp)) {
+ gem_init_axi(bp);
+ gem_init_intmod(bp);
+ }
+
macb_configure_dma(bp);
/* Enable RX partial store and forward and set watermark */
@@ -3201,6 +3266,52 @@ static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p)
}
}
+static int gem_set_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct macb *bp = netdev_priv(dev);
+ unsigned int tx_throttle;
+ unsigned int rx_throttle;
+ u32 intmod = 0;
+
+ /* GEM has simple IRQ throttling support. RX and TX interrupts
+ * are separately moderated on 800ns quantums, with no support
+ * for frame coalescing.
+ */
+
+ /* Max is 255 * 0.8us = 204us. Zero implies no moderation. */
+ if (ec->rx_coalesce_usecs > 204 || ec->tx_coalesce_usecs > 204)
+ return -EINVAL;
+
+ tx_throttle = (1000 * ec->tx_coalesce_usecs) / 800;
+ rx_throttle = (1000 * ec->rx_coalesce_usecs) / 800;
+
+ intmod = GEM_BFINS(TX_MODERATION, tx_throttle, intmod);
+ intmod = GEM_BFINS(RX_MODERATION, rx_throttle, intmod);
+
+ gem_writel(bp, INTMOD, intmod);
+
+ return 0;
+}
+
+static int gem_get_coalesce(struct net_device *dev,
+ struct ethtool_coalesce *ec,
+ struct kernel_ethtool_coalesce *kernel_coal,
+ struct netlink_ext_ack *extack)
+{
+ struct macb *bp = netdev_priv(dev);
+ u32 intmod;
+
+ intmod = gem_readl(bp, INTMOD);
+
+ ec->tx_coalesce_usecs = (GEM_BFEXT(TX_MODERATION, intmod) * 800) / 1000;
+ ec->rx_coalesce_usecs = (GEM_BFEXT(RX_MODERATION, intmod) * 800) / 1000;
+
+ return 0;
+}
+
static void macb_get_stats(struct net_device *dev,
struct rtnl_link_stats64 *nstat)
{
@@ -3954,6 +4065,8 @@ static const struct ethtool_ops macb_ethtool_ops = {
};
static const struct ethtool_ops gem_ethtool_ops = {
+ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
+ ETHTOOL_COALESCE_TX_USECS,
.get_regs_len = macb_get_regs_len,
.get_regs = macb_get_regs,
.get_wol = macb_get_wol,
@@ -3967,6 +4080,8 @@ static const struct ethtool_ops gem_ethtool_ops = {
.get_eth_mac_stats = gem_get_eth_mac_stats,
.get_eth_phy_stats = gem_get_eth_phy_stats,
.get_rmon_stats = gem_get_rmon_stats,
+ .get_coalesce = gem_get_coalesce,
+ .set_coalesce = gem_set_coalesce,
.get_link_ksettings = macb_get_link_ksettings,
.set_link_ksettings = macb_set_link_ksettings,
.get_ringparam = macb_get_ringparam,
@@ -5533,6 +5648,11 @@ static int macb_probe(struct platform_device *pdev)
}
}
}
+
+ device_property_read_u8(&pdev->dev, "cdns,aw2w-max-pipe", &bp->aw2w_max_pipe);
+ device_property_read_u8(&pdev->dev, "cdns,ar2r-max-pipe", &bp->ar2r_max_pipe);
+ bp->use_aw2b_fill = device_property_read_bool(&pdev->dev, "cdns,use-aw2b-fill");
+
spin_lock_init(&bp->lock);
spin_lock_init(&bp->stats_lock);
@@ -5593,6 +5713,21 @@ static int macb_probe(struct platform_device *pdev)
else
bp->phy_interface = interface;
+ /* optional PHY reset-related properties */
+ bp->phy_reset_gpio = devm_gpiod_get_optional(&pdev->dev, "phy-reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(bp->phy_reset_gpio)) {
+ dev_err(&pdev->dev, "Failed to obtain phy-reset gpio\n");
+ err = PTR_ERR(bp->phy_reset_gpio);
+ goto err_out_free_netdev;
+ }
+
+ bp->phy_reset_ms = 10;
+ of_property_read_u32(np, "phy-reset-duration", &bp->phy_reset_ms);
+ /* A sane reset duration should not be longer than 1s */
+ if (bp->phy_reset_ms > 1000)
+ bp->phy_reset_ms = 1000;
+
/* IP specific init */
err = init(pdev);
if (err)
@@ -5932,6 +6067,7 @@ static const struct dev_pm_ops macb_pm_ops = {
static struct platform_driver macb_driver = {
.probe = macb_probe,
.remove = macb_remove,
+ .shutdown = macb_shutdown,
.driver = {
.name = "macb",
.of_match_table = of_match_ptr(macb_dt_ids),