Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions arch/arm/boot/dts/broadcom/bcm2711-rpi-4-b.dts
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,8 @@ i2c_csi_dsi0: &i2c0 {
pwr_led_activelow = <&led_pwr>,"gpios:8";
pwr_led_trigger = <&led_pwr>,"linux,default-trigger";

eee = <&phy1>,"eee-broken-1000t!",
<&phy1>,"eee-broken-100tx!";
eth_led0 = <&phy1>,"led-modes:0";
eth_led1 = <&phy1>,"led-modes:4";
eth_max_speed = <&phy1>,"max-speed:0";
Expand Down
2 changes: 2 additions & 0 deletions arch/arm/boot/dts/broadcom/bcm2711-rpi-cm4.dts
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,8 @@ i2c_csi_dsi0: &i2c0 {
pwr_led_activelow = <&led_pwr>,"gpios:8";
pwr_led_trigger = <&led_pwr>,"linux,default-trigger";

eee = <&phy1>,"eee-broken-1000t!",
<&phy1>,"eee-broken-100tx!";
eth_led0 = <&phy1>,"led-modes:0";
eth_led1 = <&phy1>,"led-modes:4";
eth_max_speed = <&phy1>,"max-speed:0";
Expand Down
1 change: 0 additions & 1 deletion arch/arm/boot/dts/broadcom/bcm2711-rpi-ds.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

__overrides__ {
arm_freq;
eee = <&chosen>,"bootargs{on='',off='genet.eee=N'}";
hdmi = <&hdmi0>,"status",
<&hdmi1>,"status";
nvmem_cust_rw = <&nvmem_cust>,"rw?";
Expand Down
2 changes: 1 addition & 1 deletion arch/arm/boot/dts/overlays/README
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ Params:

eee Enable Energy Efficient Ethernet support for
compatible devices (default "on"). See also
"tx_lpi_timer". Pi3B+, Pi4 and CM4 only.
"tx_lpi_timer". Pi3B+, Pi4, CM4, Pi5 and CM5.

enable_eeprom Set to "on" to enable the onboard bootloader
EEPROM by driving GPIO 57 low
Expand Down
2 changes: 0 additions & 2 deletions arch/arm64/boot/dts/broadcom/bcm2712-rpi-5-b.dts
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,6 @@ rp1_target: &pcie2 {
phy1: ethernet-phy@1 {
reg = <0x1>;
brcm,powerdown-enable;
eee-broken-1000t;
eee-broken-100tx;
};
};

Expand Down
2 changes: 0 additions & 2 deletions arch/arm64/boot/dts/broadcom/bcm2712-rpi-cm5.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ rp1_target: &pcie2 {
brcm,powerdown-enable;
interrupt-parent = <&rp1_gpio>;
interrupts = <37 IRQ_TYPE_LEVEL_LOW>;
eee-broken-1000t;
eee-broken-100tx;
};
};

Expand Down
2 changes: 2 additions & 0 deletions arch/arm64/boot/dts/broadcom/bcm2712-rpi.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ watchdog: &pm {};
drm_fb2_rp1_dsi0 = <&aliases>, "drm-fb2=",&dsi0;
drm_fb2_rp1_dsi1 = <&aliases>, "drm-fb2=",&dsi1;
drm_fb2_vc4 = <&aliases>, "drm-fb2=",&vc4;
eee = <&phy1>,"eee-broken-1000t!",
<&phy1>,"eee-broken-100tx!";
eth_led0 = <&phy1>,"led-modes:0";
eth_led1 = <&phy1>,"led-modes:4";
eth_max_speed = <&phy1>,"max-speed:0";
Expand Down
20 changes: 20 additions & 0 deletions drivers/net/ethernet/cadence/macb.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@
#define GEM_PCSANNPTX 0x021c /* PCS AN Next Page TX */
#define GEM_PCSANNPLP 0x0220 /* PCS AN Next Page LP */
#define GEM_PCSANEXTSTS 0x023c /* PCS AN Extended Status */
#define GEM_RXLPI 0x0270 /* RX LPI Transitions */
#define GEM_RXLPITIME 0x0274 /* RX LPI Time */
#define GEM_TXLPI 0x0278 /* TX LPI Transitions */
#define GEM_TXLPITIME 0x027c /* TX LPI Time */
#define GEM_DCFG1 0x0280 /* Design Config 1 */
#define GEM_DCFG2 0x0284 /* Design Config 2 */
#define GEM_DCFG3 0x0288 /* Design Config 3 */
Expand Down Expand Up @@ -311,6 +315,8 @@
#define MACB_IRXFCS_SIZE 1

/* GEM specific NCR bitfields. */
#define GEM_TXLPIEN_OFFSET 19
#define GEM_TXLPIEN_SIZE 1
#define GEM_ENABLE_HS_MAC_OFFSET 31
#define GEM_ENABLE_HS_MAC_SIZE 1

Expand Down Expand Up @@ -786,6 +792,7 @@
#define MACB_CAPS_NEED_TSUCLK 0x00000400
#define MACB_CAPS_QUEUE_DISABLE 0x00000800
#define MACB_CAPS_QBV 0x00001000
#define MACB_CAPS_EEE 0x00002000
#define MACB_CAPS_PCS 0x01000000
#define MACB_CAPS_HIGH_SPEED 0x02000000
#define MACB_CAPS_CLK_HW_CHG 0x04000000
Expand Down Expand Up @@ -1066,6 +1073,10 @@ struct gem_stats {
u64 rx_ip_header_checksum_errors;
u64 rx_tcp_checksum_errors;
u64 rx_udp_checksum_errors;
u64 rx_lpi_transitions;
u64 rx_lpi_time;
u64 tx_lpi_transitions;
u64 tx_lpi_time;
};

/* Describes the name and offset of an individual statistic register, as
Expand Down Expand Up @@ -1165,6 +1176,10 @@ static const struct gem_statistic gem_statistics[] = {
GEM_BIT(NDS_RXERR)),
GEM_STAT_TITLE_BITS(RXUDPCCNT, "rx_udp_checksum_errors",
GEM_BIT(NDS_RXERR)),
GEM_STAT_TITLE(RXLPI, "rx_lpi_transitions"),
GEM_STAT_TITLE(RXLPITIME, "rx_lpi_time"),
GEM_STAT_TITLE(TXLPI, "tx_lpi_transitions"),
GEM_STAT_TITLE(TXLPITIME, "tx_lpi_time"),
};

#define GEM_STATS_LEN ARRAY_SIZE(gem_statistics)
Expand Down Expand Up @@ -1391,6 +1406,11 @@ struct macb {

struct work_struct hresp_err_bh_work;

/* EEE / LPI state */
bool eee_active;
struct delayed_work tx_lpi_work;
u32 tx_lpi_timer;

int rx_bd_rd_prefetch;
int tx_bd_rd_prefetch;

Expand Down
143 changes: 142 additions & 1 deletion drivers/net/ethernet/cadence/macb_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/crc32.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
Expand Down Expand Up @@ -642,6 +643,107 @@ static const struct phylink_pcs_ops macb_phylink_pcs_ops = {
.pcs_config = macb_pcs_config,
};

static bool macb_tx_lpi_set(struct macb *bp, bool enable)
{
u32 old, ncr;

lockdep_assert_held(&bp->lock);

ncr = macb_readl(bp, NCR);
old = ncr;
if (enable)
ncr |= GEM_BIT(TXLPIEN);
else
ncr &= ~GEM_BIT(TXLPIEN);
if (old != ncr)
macb_writel(bp, NCR, ncr);

return old != ncr;
}

static bool macb_tx_all_queues_idle(struct macb *bp)
{
struct macb_queue *queue;
unsigned int q;

for (q = 0, queue = bp->queues; q < bp->num_queues; ++q, ++queue) {
if (READ_ONCE(queue->tx_head) != READ_ONCE(queue->tx_tail))
return false;
}
return true;
}

static void macb_tx_lpi_work_fn(struct work_struct *work)
{
struct macb *bp = container_of(work, struct macb, tx_lpi_work.work);
unsigned long flags;

spin_lock_irqsave(&bp->lock, flags);
if (bp->eee_active && macb_tx_all_queues_idle(bp))
macb_tx_lpi_set(bp, true);
spin_unlock_irqrestore(&bp->lock, flags);
}

static void macb_tx_lpi_schedule(struct macb *bp)
{
if (bp->eee_active)
mod_delayed_work(system_wq, &bp->tx_lpi_work,
usecs_to_jiffies(bp->tx_lpi_timer));
}

/* Wake from LPI before transmitting. The MAC must deassert TXLPIEN
* and wait for the PHY to exit LPI before any frame can be sent.
* IEEE 802.3az Tw_sys is ~17us for 1000BASE-T, ~30us for 100BASE-TX;
* we use a conservative 50us.
*/
static void macb_tx_lpi_wake(struct macb *bp)
{
lockdep_assert_held(&bp->lock);

if (!bp->eee_active)
return;

if (!macb_tx_lpi_set(bp, false))
return;

cancel_delayed_work(&bp->tx_lpi_work);
udelay(50);
}

static void macb_mac_disable_tx_lpi(struct phylink_config *config)
{
struct net_device *ndev = to_net_dev(config->dev);
struct macb *bp = netdev_priv(ndev);
unsigned long flags;

cancel_delayed_work_sync(&bp->tx_lpi_work);

spin_lock_irqsave(&bp->lock, flags);
bp->eee_active = false;
macb_tx_lpi_set(bp, false);
spin_unlock_irqrestore(&bp->lock, flags);
}

static int macb_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
bool tx_clk_stop)
{
struct net_device *ndev = to_net_dev(config->dev);
struct macb *bp = netdev_priv(ndev);
unsigned long flags;

spin_lock_irqsave(&bp->lock, flags);
bp->tx_lpi_timer = timer;
bp->eee_active = true;
spin_unlock_irqrestore(&bp->lock, flags);

/* Defer initial LPI entry by 1 second after link-up per
* IEEE 802.3az section 22.7a.
*/
mod_delayed_work(system_wq, &bp->tx_lpi_work, msecs_to_jiffies(1000));

return 0;
}

static void macb_mac_config(struct phylink_config *config, unsigned int mode,
const struct phylink_link_state *state)
{
Expand Down Expand Up @@ -806,6 +908,8 @@ static const struct phylink_mac_ops macb_phylink_ops = {
.mac_config = macb_mac_config,
.mac_link_down = macb_mac_link_down,
.mac_link_up = macb_mac_link_up,
.mac_disable_tx_lpi = macb_mac_disable_tx_lpi,
.mac_enable_tx_lpi = macb_mac_enable_tx_lpi,
};

static bool macb_phy_handle_exists(struct device_node *dn)
Expand Down Expand Up @@ -901,6 +1005,18 @@ static int macb_mii_probe(struct net_device *dev)
}
}

/* Configure EEE LPI if supported */
if (bp->caps & MACB_CAPS_EEE) {
__set_bit(PHY_INTERFACE_MODE_MII,
bp->phylink_config.lpi_interfaces);
__set_bit(PHY_INTERFACE_MODE_GMII,
bp->phylink_config.lpi_interfaces);
phy_interface_set_rgmii(bp->phylink_config.lpi_interfaces);
bp->phylink_config.lpi_capabilities = MAC_100FD | MAC_1000FD;
bp->phylink_config.lpi_timer_default = 250000;
bp->phylink_config.eee_enabled_default = true;
}

bp->phylink = phylink_create(&bp->phylink_config, bp->pdev->dev.fwnode,
bp->phy_interface, &macb_phylink_ops);
if (IS_ERR(bp->phylink)) {
Expand Down Expand Up @@ -1302,6 +1418,9 @@ static int macb_tx_complete(struct macb_queue *queue, int budget)
netif_wake_subqueue(bp->dev, queue_index);
spin_unlock_irqrestore(&queue->tx_ptr_lock, flags);

if (packets)
macb_tx_lpi_schedule(bp);

return packets;
}

Expand Down Expand Up @@ -2411,6 +2530,7 @@ static netdev_tx_t macb_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->len);

spin_lock(&bp->lock);
macb_tx_lpi_wake(bp);

/* TSTART write might get dropped, so make the IRQ retrigger a buffer read */
if (macb_readl(bp, TSR) & MACB_BIT(TGO))
Expand Down Expand Up @@ -3108,6 +3228,8 @@ static int macb_close(struct net_device *dev)
netdev_tx_reset_queue(netdev_get_tx_queue(dev, q));
}

cancel_delayed_work_sync(&bp->tx_lpi_work);

phylink_stop(bp->phylink);
phylink_disconnect_phy(bp->phylink);

Expand Down Expand Up @@ -4064,6 +4186,20 @@ static const struct ethtool_ops macb_ethtool_ops = {
.set_ringparam = macb_set_ringparam,
};

static int macb_get_eee(struct net_device *dev, struct ethtool_keee *eee)
{
struct macb *bp = netdev_priv(dev);

return phylink_ethtool_get_eee(bp->phylink, eee);
}

static int macb_set_eee(struct net_device *dev, struct ethtool_keee *eee)
{
struct macb *bp = netdev_priv(dev);

return phylink_ethtool_set_eee(bp->phylink, eee);
}

static const struct ethtool_ops gem_ethtool_ops = {
.supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
ETHTOOL_COALESCE_TX_USECS,
Expand All @@ -4088,6 +4224,8 @@ static const struct ethtool_ops gem_ethtool_ops = {
.set_ringparam = macb_set_ringparam,
.get_rxnfc = gem_get_rxnfc,
.set_rxnfc = gem_set_rxnfc,
.get_eee = macb_get_eee,
.set_eee = macb_set_eee,
};

static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
Expand Down Expand Up @@ -5488,7 +5626,8 @@ static const struct macb_config versal_config = {
static const struct macb_config raspberrypi_rp1_config = {
.caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_CLK_HW_CHG |
MACB_CAPS_JUMBO |
MACB_CAPS_GEM_HAS_PTP,
MACB_CAPS_GEM_HAS_PTP |
MACB_CAPS_EEE,
.dma_burst_length = 16,
.clk_init = macb_clk_init,
.init = macb_init,
Expand Down Expand Up @@ -5746,6 +5885,7 @@ static int macb_probe(struct platform_device *pdev)
}

INIT_WORK(&bp->hresp_err_bh_work, macb_hresp_error_task);
INIT_DELAYED_WORK(&bp->tx_lpi_work, macb_tx_lpi_work_fn);

netdev_info(dev, "Cadence %s rev 0x%08x at 0x%08lx irq %d (%pM)\n",
macb_is_gem(bp) ? "GEM" : "MACB", macb_readl(bp, MID),
Expand Down Expand Up @@ -5790,6 +5930,7 @@ static void macb_remove(struct platform_device *pdev)
mdiobus_free(bp->mii_bus);

device_set_wakeup_enable(&bp->pdev->dev, 0);
cancel_delayed_work_sync(&bp->tx_lpi_work);
cancel_work_sync(&bp->hresp_err_bh_work);
pm_runtime_disable(&pdev->dev);
pm_runtime_dont_use_autosuspend(&pdev->dev);
Expand Down
20 changes: 16 additions & 4 deletions drivers/net/phy/broadcom.c
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,15 @@ static int bcm54xx_config_init(struct phy_device *phydev)
if (of_property_read_bool(np, "brcm,powerdown-enable"))
phydev->dev_flags |= PHY_BRCM_AUTO_PWRDWN_ENABLE;

/* Disable AutogrEEEn and switch to Native EEE mode so the MAC
* can control LPI signaling and observe RX LPI on the RGMII
* interface.
*/
err = bcm_phy_modify_exp(phydev, BCM54XX_TOP_MISC_MII_BUF_CNTL0,
BCM54XX_MII_BUF_CNTL0_AUTOGREEEN_EN, 0);
if (err)
return err;

bcm54xx_adjust_rxrefclk(phydev);

switch (phydev->drv->phy_id & PHY_ID_MATCH_MODEL_MASK) {
Expand All @@ -498,14 +507,17 @@ static int bcm54xx_config_init(struct phy_device *phydev)
err = bcm54xx_config_clock_delay(phydev);
break;
case PHY_ID_BCM54210E:
err = bcm54210e_config_init(phydev);
/* BCM54213PE shares the same model ID as BCM54210E; use the
* exact driver ID to dispatch to the right per-PHY init.
*/
if (phydev->drv->phy_id == PHY_ID_BCM54213PE)
err = bcm54213pe_config_init(phydev);
else
err = bcm54210e_config_init(phydev);
break;
case PHY_ID_BCM54612E:
err = bcm54612e_config_init(phydev);
break;
case PHY_ID_BCM54213PE:
err = bcm54213pe_config_init(phydev);
break;
case PHY_ID_BCM54616S:
err = bcm54616s_config_init(phydev);
break;
Expand Down
3 changes: 3 additions & 0 deletions include/linux/brcmphy.h
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,9 @@
#define BCM54XX_TOP_MISC_IDDQ_SD (1 << 2)
#define BCM54XX_TOP_MISC_IDDQ_SR (1 << 3)

#define BCM54XX_TOP_MISC_MII_BUF_CNTL0 (MII_BCM54XX_EXP_SEL_TOP + 0x00)
#define BCM54XX_MII_BUF_CNTL0_AUTOGREEEN_EN BIT(0)

#define BCM54XX_TOP_MISC_LED_CTL (MII_BCM54XX_EXP_SEL_TOP + 0x0C)
#define BCM54XX_LED4_SEL_INTR BIT(1)

Expand Down