@@ -28,6 +28,115 @@
#define PPE_SCHEDULER_L1_NUM 64
#define PPE_SP_PRIORITY_NUM 8
+#define PPE_ETHTOOL_XGMIB_STAT(x) { #x, \
+ offsetof(struct ppe_xgmib_hw_stats, x) / sizeof(u64) }
+#define PPE_ETHTOOL_GMIB_STAT(x) { #x, \
+ offsetof(struct ppe_gmib_hw_stats, x) / sizeof(u64) }
+
+/* Poll interval time to poll GMAC MIBs for overflow protection */
+#define PPE_GMIB_STATS_POLL_INTERVAL 120000
+
+/* XGMAC strings used by ethtool */
+static const struct ppe_ethtool_gstrings_xgmib_stats {
+ char name[ETH_GSTRING_LEN];
+ u32 offset;
+} ppe_ethtool_gstrings_xgmib_stats[] = {
+ PPE_ETHTOOL_XGMIB_STAT(rx_frames),
+ PPE_ETHTOOL_XGMIB_STAT(rx_bytes),
+ PPE_ETHTOOL_XGMIB_STAT(rx_bytes_g),
+ PPE_ETHTOOL_XGMIB_STAT(rx_broadcast_g),
+ PPE_ETHTOOL_XGMIB_STAT(rx_multicast_g),
+ PPE_ETHTOOL_XGMIB_STAT(rx_unicast_g),
+ PPE_ETHTOOL_XGMIB_STAT(rx_crc_err),
+ PPE_ETHTOOL_XGMIB_STAT(rx_runt_err),
+ PPE_ETHTOOL_XGMIB_STAT(rx_jabber_err),
+ PPE_ETHTOOL_XGMIB_STAT(rx_undersize_g),
+ PPE_ETHTOOL_XGMIB_STAT(rx_oversize_g),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pkt64),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pkt65to127),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pkt128to255),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pkt256to511),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pkt512to1023),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pkt1024tomax),
+ PPE_ETHTOOL_XGMIB_STAT(rx_len_err),
+ PPE_ETHTOOL_XGMIB_STAT(rx_outofrange_err),
+ PPE_ETHTOOL_XGMIB_STAT(rx_pause),
+ PPE_ETHTOOL_XGMIB_STAT(rx_fifo_overflow),
+ PPE_ETHTOOL_XGMIB_STAT(rx_vlan),
+ PPE_ETHTOOL_XGMIB_STAT(rx_wdog_err),
+ PPE_ETHTOOL_XGMIB_STAT(rx_lpi_usec),
+ PPE_ETHTOOL_XGMIB_STAT(rx_lpi_tran),
+ PPE_ETHTOOL_XGMIB_STAT(rx_drop_frames),
+ PPE_ETHTOOL_XGMIB_STAT(rx_drop_bytes),
+ PPE_ETHTOOL_XGMIB_STAT(tx_bytes),
+ PPE_ETHTOOL_XGMIB_STAT(tx_bytes_g),
+ PPE_ETHTOOL_XGMIB_STAT(tx_frames),
+ PPE_ETHTOOL_XGMIB_STAT(tx_frame_g),
+ PPE_ETHTOOL_XGMIB_STAT(tx_broadcast),
+ PPE_ETHTOOL_XGMIB_STAT(tx_broadcast_g),
+ PPE_ETHTOOL_XGMIB_STAT(tx_multicast),
+ PPE_ETHTOOL_XGMIB_STAT(tx_multicast_g),
+ PPE_ETHTOOL_XGMIB_STAT(tx_unicast),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pkt64),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pkt65to127),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pkt128to255),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pkt256to511),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pkt512to1023),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pkt1024tomax),
+ PPE_ETHTOOL_XGMIB_STAT(tx_underflow_err),
+ PPE_ETHTOOL_XGMIB_STAT(tx_pause),
+ PPE_ETHTOOL_XGMIB_STAT(tx_vlan_g),
+ PPE_ETHTOOL_XGMIB_STAT(tx_lpi_usec),
+ PPE_ETHTOOL_XGMIB_STAT(tx_lpi_tran),
+};
+
+/* GMAC strings used by ethtool */
+static const struct ppe_ethtool_gstrings_gmib_stats {
+ char name[ETH_GSTRING_LEN];
+ u32 offset;
+} ppe_ethtool_gstrings_gmib_stats[] = {
+ PPE_ETHTOOL_GMIB_STAT(rx_broadcast),
+ PPE_ETHTOOL_GMIB_STAT(rx_pause),
+ PPE_ETHTOOL_GMIB_STAT(rx_unicast),
+ PPE_ETHTOOL_GMIB_STAT(rx_multicast),
+ PPE_ETHTOOL_GMIB_STAT(rx_fcserr),
+ PPE_ETHTOOL_GMIB_STAT(rx_alignerr),
+ PPE_ETHTOOL_GMIB_STAT(rx_runt),
+ PPE_ETHTOOL_GMIB_STAT(rx_frag),
+ PPE_ETHTOOL_GMIB_STAT(rx_jmbfcserr),
+ PPE_ETHTOOL_GMIB_STAT(rx_jmbalignerr),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt64),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt65to127),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt128to255),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt256to511),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt512to1023),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt1024to1518),
+ PPE_ETHTOOL_GMIB_STAT(rx_pkt1519tomax),
+ PPE_ETHTOOL_GMIB_STAT(rx_toolong),
+ PPE_ETHTOOL_GMIB_STAT(rx_pktgoodbyte),
+ PPE_ETHTOOL_GMIB_STAT(rx_pktbadbyte),
+ PPE_ETHTOOL_GMIB_STAT(tx_broadcast),
+ PPE_ETHTOOL_GMIB_STAT(tx_pause),
+ PPE_ETHTOOL_GMIB_STAT(tx_multicast),
+ PPE_ETHTOOL_GMIB_STAT(tx_underrun),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt64),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt65to127),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt128to255),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt256to511),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt512to1023),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt1024to1518),
+ PPE_ETHTOOL_GMIB_STAT(tx_pkt1519tomax),
+ PPE_ETHTOOL_GMIB_STAT(tx_pktbyte),
+ PPE_ETHTOOL_GMIB_STAT(tx_collisions),
+ PPE_ETHTOOL_GMIB_STAT(tx_abortcol),
+ PPE_ETHTOOL_GMIB_STAT(tx_multicol),
+ PPE_ETHTOOL_GMIB_STAT(tx_singlecol),
+ PPE_ETHTOOL_GMIB_STAT(tx_exesdeffer),
+ PPE_ETHTOOL_GMIB_STAT(tx_deffer),
+ PPE_ETHTOOL_GMIB_STAT(tx_latecol),
+ PPE_ETHTOOL_GMIB_STAT(tx_unicast),
+};
+
static const char * const ppe_clock_name[PPE_CLK_MAX] = {
"cmn_ahb",
"cmn_sys",
@@ -694,6 +803,362 @@ static int ppe_port_bridge_txmac_en_set(struct ppe_device *ppe_dev, int port, bo
return 0;
}
+/* Get GMAC MIBs from GMAC registers and update to PPE port gmib stats */
+static void ppe_gmib_stats_update(struct ppe_port *ppe_port)
+{
+ u32 val, hi;
+ struct ppe_device *ppe_dev = ppe_port->ppe_dev;
+ int port = ppe_port->port_id;
+
+ spin_lock(&ppe_port->stats_lock);
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXBROAD, &val);
+ ppe_port->gmib_stats->rx_broadcast += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPAUSE, &val);
+ ppe_port->gmib_stats->rx_pause += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXMULTI, &val);
+ ppe_port->gmib_stats->rx_multicast += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXFCSERR, &val);
+ ppe_port->gmib_stats->rx_fcserr += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXALIGNERR, &val);
+ ppe_port->gmib_stats->rx_alignerr += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXRUNT, &val);
+ ppe_port->gmib_stats->rx_runt += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXFRAG, &val);
+ ppe_port->gmib_stats->rx_frag += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXJUMBOFCSERR, &val);
+ ppe_port->gmib_stats->rx_jmbfcserr += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXJUMBOALIGNERR, &val);
+ ppe_port->gmib_stats->rx_jmbalignerr += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT64, &val);
+ ppe_port->gmib_stats->rx_pkt64 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT65TO127, &val);
+ ppe_port->gmib_stats->rx_pkt65to127 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT128TO255, &val);
+ ppe_port->gmib_stats->rx_pkt128to255 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT256TO511, &val);
+ ppe_port->gmib_stats->rx_pkt256to511 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT512TO1023, &val);
+ ppe_port->gmib_stats->rx_pkt512to1023 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT1024TO1518, &val);
+ ppe_port->gmib_stats->rx_pkt1024to1518 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXPKT1519TOX, &val);
+ ppe_port->gmib_stats->rx_pkt1519tomax += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXTOOLONG, &val);
+ ppe_port->gmib_stats->rx_toolong += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXGOODBYTE_L, &val);
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXGOODBYTE_H, &hi);
+ ppe_port->gmib_stats->rx_pktgoodbyte += (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXBADBYTE_L, &val);
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXBADBYTE_H, &hi);
+ ppe_port->gmib_stats->rx_pktbadbyte += (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_RXUNI, &val);
+ ppe_port->gmib_stats->rx_unicast += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXBROAD, &val);
+ ppe_port->gmib_stats->tx_broadcast += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPAUSE, &val);
+ ppe_port->gmib_stats->tx_pause += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXMULTI, &val);
+ ppe_port->gmib_stats->tx_multicast += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXUNDERRUN, &val);
+ ppe_port->gmib_stats->tx_underrun += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT64, &val);
+ ppe_port->gmib_stats->tx_pkt64 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT65TO127, &val);
+ ppe_port->gmib_stats->tx_pkt65to127 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT128TO255, &val);
+ ppe_port->gmib_stats->tx_pkt128to255 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT256TO511, &val);
+ ppe_port->gmib_stats->tx_pkt256to511 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT512TO1023, &val);
+ ppe_port->gmib_stats->tx_pkt512to1023 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT1024TO1518, &val);
+ ppe_port->gmib_stats->tx_pkt1024to1518 += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXPKT1519TOX, &val);
+ ppe_port->gmib_stats->tx_pkt1519tomax += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXBYTE_L, &val);
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXBYTE_H, &hi);
+ ppe_port->gmib_stats->tx_pktbyte += (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXCOLLISIONS, &val);
+ ppe_port->gmib_stats->tx_collisions += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXABORTCOL, &val);
+ ppe_port->gmib_stats->tx_abortcol += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXMULTICOL, &val);
+ ppe_port->gmib_stats->tx_multicol += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXSINGLECOL, &val);
+ ppe_port->gmib_stats->tx_singlecol += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXEXCESSIVEDEFER, &val);
+ ppe_port->gmib_stats->tx_exesdeffer += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXDEFER, &val);
+ ppe_port->gmib_stats->tx_deffer += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXLATECOL, &val);
+ ppe_port->gmib_stats->tx_latecol += (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_TXUNI, &val);
+ ppe_port->gmib_stats->tx_unicast += (u64)val;
+
+ spin_unlock(&ppe_port->stats_lock);
+}
+
+/* Get XGMAC MIBs from XGMAC registers */
+static void ppe_xgmib_stats_update(struct ppe_device *ppe_dev, int port,
+ struct ppe_xgmib_hw_stats *xgmib_hw_stats)
+{
+ u32 val, hi;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_OCTET_COUNT_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_OCTET_COUNT_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_bytes = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_FRAME_COUNT_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_FRAME_COUNT_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_frames = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_BROADCAST_FRAMES_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_BROADCAST_FRAMES_GOOD_HIGH, &hi);
+ xgmib_hw_stats->tx_broadcast_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_MULTICAST_FRAMES_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_MULTICAST_FRAMES_GOOD_HIGH, &hi);
+ xgmib_hw_stats->tx_multicast_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_64OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_64OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_pkt64 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_65TO127OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_65TO127OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_pkt65to127 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_128TO255OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_128TO255OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_pkt128to255 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_256TO511OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_256TO511OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_pkt256to511 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_512TO1023OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_512TO1023OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_pkt512to1023 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_pkt1024tomax = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_UNICAST_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_UNICAST_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_unicast = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_MULTICAST_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_MULTICAST_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_multicast = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_BROADCAST_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_BROADCAST_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->tx_broadcast = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_UNDERFLOW_ERROR_FRAMES_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_UNDERFLOW_ERROR_FRAMES_HIGH, &hi);
+ xgmib_hw_stats->tx_underflow_err = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_OCTET_COUNT_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_OCTET_COUNT_GOOD_HIGH, &hi);
+ xgmib_hw_stats->tx_bytes_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_FRAME_COUNT_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_FRAME_COUNT_GOOD_HIGH, &hi);
+ xgmib_hw_stats->tx_frame_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_PAUSE_FRAMES_LOW, &val);
+ xgmib_hw_stats->tx_pause = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_VLAN_FRAMES_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_VLAN_FRAMES_GOOD_HIGH, &hi);
+ xgmib_hw_stats->tx_vlan_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_LPI_USEC_CNTR, &val);
+ xgmib_hw_stats->tx_lpi_usec = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_TX_LPI_TRAN_CNTR, &val);
+ xgmib_hw_stats->tx_lpi_tran = (u64)val;
+
+ /* rx mib stats */
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_FRAME_COUNT_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_FRAME_COUNT_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_frames = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OCTET_COUNT_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OCTET_COUNT_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_bytes = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OCTET_COUNT_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OCTET_COUNT_GOOD_HIGH, &hi);
+ xgmib_hw_stats->rx_bytes_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_BROADCAST_FRAMES_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_BROADCAST_FRAMES_GOOD_HIGH, &hi);
+ xgmib_hw_stats->rx_broadcast_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_MULTICAST_FRAMES_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_MULTICAST_FRAMES_GOOD_HIGH, &hi);
+ xgmib_hw_stats->rx_multicast_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_CRC_ERROR_FRAMES_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_CRC_ERROR_FRAMES_HIGH, &hi);
+ xgmib_hw_stats->rx_crc_err = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_FRAG_ERROR_FRAMES, &val);
+ xgmib_hw_stats->rx_runt_err = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_JABBER_ERROR_FRAMES, &val);
+ xgmib_hw_stats->rx_jabber_err = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_UNDERSIZE_FRAMES_GOOD, &val);
+ xgmib_hw_stats->rx_undersize_g = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OVERSIZE_FRAMES_GOOD, &val);
+ xgmib_hw_stats->rx_oversize_g = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_64OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_64OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_pkt64 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_65TO127OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_65TO127OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_pkt65to127 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_128TO255OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_128TO255OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_pkt128to255 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_256TO511OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_256TO511OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_pkt256to511 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_512TO1023OCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_512TO1023OCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_pkt512to1023 = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_pkt1024tomax = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_UNICAST_FRAMES_GOOD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_UNICAST_FRAMES_GOOD_HIGH, &hi);
+ xgmib_hw_stats->rx_unicast_g = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_LENGTH_ERROR_FRAMES_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_LENGTH_ERROR_FRAMES_HIGH, &hi);
+ xgmib_hw_stats->rx_len_err = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OUTOFRANGE_FRAMES_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_OUTOFRANGE_FRAMES_HIGH, &hi);
+ xgmib_hw_stats->rx_outofrange_err = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_PAUSE_FRAMES_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_PAUSE_FRAMES_HIGH, &hi);
+ xgmib_hw_stats->rx_pause = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_FIFOOVERFLOW_FRAMES_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_FIFOOVERFLOW_FRAMES_HIGH, &hi);
+ xgmib_hw_stats->rx_fifo_overflow = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_VLAN_FRAMES_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_VLAN_FRAMES_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_vlan = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_WATCHDOG_ERROR_FRAMES, &val);
+ xgmib_hw_stats->rx_wdog_err = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_LPI_USEC_CNTR, &val);
+ xgmib_hw_stats->rx_lpi_usec = (u64)val;
+
+ ppe_read(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_LPI_TRAN_CNTR, &val);
+ xgmib_hw_stats->rx_lpi_tran = (u64)val;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_DISCARD_FRAME_COUNT_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_DISCARD_FRAME_COUNT_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_drop_frames = (u64)val | (u64)hi << 32;
+
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_DISCARD_OCTET_COUNT_GOOD_BAD_LOW, &val);
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_RX_DISCARD_OCTET_COUNT_GOOD_BAD_HIGH, &hi);
+ xgmib_hw_stats->rx_drop_bytes = (u64)val | (u64)hi << 32;
+}
+
+static void ppe_gmib_stats_poll(struct work_struct *work)
+{
+ struct ppe_port *ppe_port = container_of(work, struct ppe_port,
+ gmib_read.work);
+
+ ppe_gmib_stats_update(ppe_port);
+
+ schedule_delayed_work(&ppe_port->gmib_read,
+ msecs_to_jiffies(PPE_GMIB_STATS_POLL_INTERVAL));
+}
+
static void ppe_phylink_mac_config(struct ppe_device *ppe_dev, int port,
unsigned int mode, const struct phylink_link_state *state)
{
@@ -862,6 +1327,9 @@ static void ppe_phylink_mac_link_up(struct ppe_device *ppe_dev, int port,
/* Enable ppe bridge port tx mac */
ppe_port_bridge_txmac_en_set(ppe_dev, port, true);
+ /* Start gmib statistics polling */
+ schedule_delayed_work(&ppe_port->gmib_read, 0);
+
dev_info(ppe_dev->dev,
"PPE port %d interface %s link up - %s%s - pause tx %d rx %d\n",
port, phy_modes(interface), phy_speed_to_str(speed),
@@ -886,6 +1354,9 @@ static void ppe_phylink_mac_link_down(struct ppe_device *ppe_dev, int port,
/* Disable ppe mac tx */
ppe_mac_txmac_en_set(ppe_dev, port, false);
+ /* Stop gmib statistics polling */
+ cancel_delayed_work_sync(&ppe_port->gmib_read);
+
dev_info(ppe_dev->dev, "PPE port %d interface %s link down\n",
port, phy_modes(interface));
}
@@ -938,6 +1409,11 @@ static int ppe_mac_init(struct platform_device *pdev)
ppe_ports->port[i].speed = SPEED_UNKNOWN;
ppe_ports->port[i].duplex = DUPLEX_UNKNOWN;
ppe_ports->port[i].pause = MLO_PAUSE_NONE;
+ ppe_ports->port[i].gmib_stats = devm_kzalloc(&pdev->dev,
+ sizeof(*ppe_ports->port[i].gmib_stats),
+ GFP_KERNEL);
+ spin_lock_init(&ppe_ports->port[i].stats_lock);
+ INIT_DELAYED_WORK(&ppe_ports->port[i].gmib_read, ppe_gmib_stats_poll);
i++;
/* Port gmac HW initialization */
@@ -1180,6 +1656,218 @@ static void ppe_phylink_destroy(struct ppe_device *ppe_dev, int port)
}
}
+static int ppe_get_sset_count(struct ppe_device *ppe_dev, int port, int sset)
+{
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+
+ if (!ppe_port) {
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+ return -ENODEV;
+ }
+
+ if (sset != ETH_SS_STATS)
+ return 0;
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC)
+ return ARRAY_SIZE(ppe_ethtool_gstrings_xgmib_stats);
+ else
+ return ARRAY_SIZE(ppe_ethtool_gstrings_gmib_stats);
+}
+
+static void ppe_get_strings(struct ppe_device *ppe_dev, int port, u32 stringset, u8 *data)
+{
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+ int i;
+
+ if (!ppe_port)
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+
+ if (stringset != ETH_SS_STATS)
+ return;
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC) {
+ for (i = 0; i < ARRAY_SIZE(ppe_ethtool_gstrings_xgmib_stats); i++)
+ memcpy(data + i * ETH_GSTRING_LEN,
+ ppe_ethtool_gstrings_xgmib_stats[i].name, ETH_GSTRING_LEN);
+ } else {
+ for (i = 0; i < ARRAY_SIZE(ppe_ethtool_gstrings_gmib_stats); i++)
+ memcpy(data + i * ETH_GSTRING_LEN,
+ ppe_ethtool_gstrings_gmib_stats[i].name, ETH_GSTRING_LEN);
+ }
+}
+
+static void ppe_get_ethtool_stats(struct ppe_device *ppe_dev, int port, u64 *data)
+{
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+ u64 *data_src;
+ int i;
+
+ if (!ppe_port)
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC) {
+ struct ppe_xgmib_hw_stats xgmib_hw_stats;
+
+ ppe_xgmib_stats_update(ppe_dev, port, &xgmib_hw_stats);
+ data_src = (u64 *)(&xgmib_hw_stats);
+ for (i = 0; i < ARRAY_SIZE(ppe_ethtool_gstrings_xgmib_stats); i++)
+ data[i] = *(data_src + ppe_ethtool_gstrings_xgmib_stats[i].offset);
+ } else {
+ ppe_gmib_stats_update(ppe_port);
+ data_src = (u64 *)(ppe_port->gmib_stats);
+ for (i = 0; i < ARRAY_SIZE(ppe_ethtool_gstrings_gmib_stats); i++)
+ data[i] = *(data_src + ppe_ethtool_gstrings_gmib_stats[i].offset);
+ }
+}
+
+static void ppe_get_stats64(struct ppe_device *ppe_dev, int port, struct rtnl_link_stats64 *s)
+{
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+
+ if (!ppe_port)
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC) {
+ struct ppe_xgmib_hw_stats xgmib_hw_stats;
+
+ ppe_xgmib_stats_update(ppe_dev, port, &xgmib_hw_stats);
+ s->rx_packets = xgmib_hw_stats.rx_unicast_g +
+ xgmib_hw_stats.rx_broadcast_g + xgmib_hw_stats.rx_multicast_g;
+ s->tx_packets = xgmib_hw_stats.tx_unicast +
+ xgmib_hw_stats.tx_broadcast_g + xgmib_hw_stats.tx_multicast_g;
+ s->rx_bytes = xgmib_hw_stats.rx_bytes;
+ s->tx_bytes = xgmib_hw_stats.tx_bytes;
+ s->multicast = xgmib_hw_stats.rx_multicast_g;
+
+ s->rx_crc_errors = xgmib_hw_stats.rx_crc_err;
+ s->rx_frame_errors = xgmib_hw_stats.rx_runt_err;
+ s->rx_fifo_errors = xgmib_hw_stats.rx_fifo_overflow;
+ s->rx_length_errors = xgmib_hw_stats.rx_len_err;
+ s->rx_errors = s->rx_crc_errors + s->rx_frame_errors +
+ s->rx_fifo_errors + s->rx_length_errors;
+ s->rx_dropped = xgmib_hw_stats.rx_drop_frames + s->rx_errors;
+
+ s->tx_fifo_errors = xgmib_hw_stats.tx_underflow_err;
+ s->tx_errors = s->tx_fifo_errors;
+ } else {
+ ppe_gmib_stats_update(ppe_port);
+ s->rx_packets = ppe_port->gmib_stats->rx_unicast +
+ ppe_port->gmib_stats->rx_broadcast + ppe_port->gmib_stats->rx_multicast;
+ s->tx_packets = ppe_port->gmib_stats->tx_unicast +
+ ppe_port->gmib_stats->tx_broadcast + ppe_port->gmib_stats->tx_multicast;
+ s->rx_bytes = ppe_port->gmib_stats->rx_pktgoodbyte;
+ s->tx_bytes = ppe_port->gmib_stats->tx_pktbyte;
+
+ s->rx_crc_errors = ppe_port->gmib_stats->rx_fcserr +
+ ppe_port->gmib_stats->rx_jmbfcserr;
+ s->rx_frame_errors = ppe_port->gmib_stats->rx_alignerr +
+ ppe_port->gmib_stats->rx_jmbalignerr;
+ s->rx_fifo_errors = ppe_port->gmib_stats->rx_runt;
+ s->rx_errors = s->rx_crc_errors + s->rx_frame_errors + s->rx_fifo_errors;
+ s->rx_dropped = ppe_port->gmib_stats->rx_toolong + s->rx_errors;
+
+ s->tx_fifo_errors = ppe_port->gmib_stats->tx_underrun;
+ s->tx_aborted_errors = ppe_port->gmib_stats->tx_abortcol;
+ s->tx_errors = s->tx_fifo_errors + s->tx_aborted_errors;
+ s->collisions = ppe_port->gmib_stats->tx_collisions;
+ s->multicast = ppe_port->gmib_stats->rx_multicast;
+ }
+}
+
+static int ppe_set_mac_address(struct ppe_device *ppe_dev, int port, u8 *macaddr)
+{
+ u32 reg_val;
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+
+ if (!ppe_port) {
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+ return -ENODEV;
+ }
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC) {
+ reg_val = (macaddr[5] << 8) | macaddr[4] | XGMAC_ADDR_EN;
+ ppe_write(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_MAC_ADDR0_HIGH, reg_val);
+ reg_val = (macaddr[3] << 24) | (macaddr[2] << 16) | (macaddr[1] << 8) | macaddr[0];
+ ppe_write(ppe_dev, PPE_PORT_XGMAC_ADDR(port) + XGMAC_MAC_ADDR0_LOW, reg_val);
+ } else {
+ reg_val = (macaddr[5] << 8) | macaddr[4];
+ ppe_write(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_GOL_MAC_ADDR0, reg_val);
+ reg_val = (macaddr[0] << 24) | (macaddr[1] << 16) | (macaddr[2] << 8) | macaddr[3];
+ ppe_write(ppe_dev, PPE_PORT_GMAC_ADDR(port) + GMAC_GOL_MAC_ADDR1, reg_val);
+ }
+
+ return 0;
+}
+
+static int ppe_set_mac_eee(struct ppe_device *ppe_dev, int port, struct ethtool_eee *eee)
+{
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+ u32 reg_val;
+
+ if (!ppe_port) {
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+ return -ENODEV;
+ }
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC) {
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_LPI_CONTROL_STATUS,
+ ®_val);
+ reg_val |= (XGMAC_LPI_PLS | XGMAC_LPI_TXA | XGMAC_LPI_TE);
+ if (eee->tx_lpi_enabled)
+ reg_val |= XGMAC_LPI_TXEN;
+ else
+ reg_val &= ~XGMAC_LPI_TXEN;
+ ppe_write(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_LPI_CONTROL_STATUS,
+ reg_val);
+ ppe_mask(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_1US_TIC_COUNTER,
+ XGMAC_1US_TIC_CNTR, FIELD_PREP(XGMAC_1US_TIC_CNTR, 0x15f));
+ ppe_mask(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_LPI_AUTO_ENTRY_TIMER,
+ XGMAC_LPI_ET, FIELD_PREP(XGMAC_LPI_ET, 0x2c));
+ } else {
+ ppe_read(ppe_dev, PPE_LPI_LPI_EN, ®_val);
+ if (eee->tx_lpi_enabled)
+ reg_val |= PPE_LPI_PORT_EN(port);
+ else
+ reg_val &= ~PPE_LPI_PORT_EN(port);
+ ppe_write(ppe_dev, PPE_LPI_LPI_EN, reg_val);
+ }
+
+ return 0;
+}
+
+static int ppe_get_mac_eee(struct ppe_device *ppe_dev, int port, struct ethtool_eee *eee)
+{
+ struct ppe_port *ppe_port = ppe_port_get(ppe_dev, port);
+ u32 reg_val;
+
+ if (!ppe_port) {
+ dev_err(ppe_dev->dev, "Failed to find ppe port %d\n", port);
+ return -ENODEV;
+ }
+
+ if (ppe_port->mac_type == PPE_MAC_TYPE_XGMAC) {
+ ppe_read(ppe_dev,
+ PPE_PORT_XGMAC_ADDR(port) + XGMAC_LPI_CONTROL_STATUS,
+ ®_val);
+ if (reg_val & XGMAC_LPI_TXEN)
+ eee->tx_lpi_enabled = 1;
+ else
+ eee->tx_lpi_enabled = 0;
+ } else {
+ ppe_read(ppe_dev, PPE_LPI_LPI_EN, ®_val);
+ if (reg_val & PPE_LPI_PORT_EN(port))
+ eee->tx_lpi_enabled = 1;
+ else
+ eee->tx_lpi_enabled = 0;
+ }
+
+ return 0;
+}
+
bool ppe_is_probed(struct platform_device *pdev)
{
struct ppe_device *ppe_dev = platform_get_drvdata(pdev);
@@ -1236,6 +1924,13 @@ static struct ppe_device_ops qcom_ppe_ops = {
.phylink_mac_link_up = ppe_phylink_mac_link_up,
.phylink_mac_link_down = ppe_phylink_mac_link_down,
.phylink_mac_select_pcs = ppe_phylink_mac_select_pcs,
+ .get_sset_count = ppe_get_sset_count,
+ .get_strings = ppe_get_strings,
+ .get_ethtool_stats = ppe_get_ethtool_stats,
+ .get_stats64 = ppe_get_stats64,
+ .set_mac_address = ppe_set_mac_address,
+ .set_mac_eee = ppe_set_mac_eee,
+ .get_mac_eee = ppe_get_mac_eee,
.set_maxframe = ppe_port_maxframe_set,
};
@@ -2340,6 +3035,9 @@ static int qcom_ppe_remove(struct platform_device *pdev)
ppe_debugfs_teardown(ppe_dev);
for (i = 0; i < ppe_ports->num; i++) {
+ /* Stop gmib statistics polling */
+ cancel_delayed_work_sync(&ppe_ports->port[i].gmib_read);
+
/* Reset ppe port parent clock to XO clock */
port = ppe_ports->port[i].port_id;
clk_set_rate(ppe_dev_priv->clk[PPE_NSS_PORT1_RX_CLK + ((port - 1) << 1)],
@@ -183,6 +183,101 @@ struct ppe_scheduler_port_resource {
int l1edrr[2];
};
+/* PPE GMAC statistics */
+struct ppe_gmib_hw_stats {
+ u64 rx_broadcast;
+ u64 rx_pause;
+ u64 rx_multicast;
+ u64 rx_fcserr;
+ u64 rx_alignerr;
+ u64 rx_runt;
+ u64 rx_frag;
+ u64 rx_jmbfcserr;
+ u64 rx_jmbalignerr;
+ u64 rx_pkt64;
+ u64 rx_pkt65to127;
+ u64 rx_pkt128to255;
+ u64 rx_pkt256to511;
+ u64 rx_pkt512to1023;
+ u64 rx_pkt1024to1518;
+ u64 rx_pkt1519tomax;
+ u64 rx_toolong;
+ u64 rx_pktgoodbyte;
+ u64 rx_pktbadbyte;
+ u64 rx_unicast;
+ u64 tx_broadcast;
+ u64 tx_pause;
+ u64 tx_multicast;
+ u64 tx_underrun;
+ u64 tx_pkt64;
+ u64 tx_pkt65to127;
+ u64 tx_pkt128to255;
+ u64 tx_pkt256to511;
+ u64 tx_pkt512to1023;
+ u64 tx_pkt1024to1518;
+ u64 tx_pkt1519tomax;
+ u64 tx_pktbyte;
+ u64 tx_collisions;
+ u64 tx_abortcol;
+ u64 tx_multicol;
+ u64 tx_singlecol;
+ u64 tx_exesdeffer;
+ u64 tx_deffer;
+ u64 tx_latecol;
+ u64 tx_unicast;
+};
+
+/* PPE XGMAC statistics */
+struct ppe_xgmib_hw_stats {
+ u64 tx_bytes;
+ u64 tx_frames;
+ u64 tx_broadcast_g;
+ u64 tx_multicast_g;
+ u64 tx_pkt64;
+ u64 tx_pkt65to127;
+ u64 tx_pkt128to255;
+ u64 tx_pkt256to511;
+ u64 tx_pkt512to1023;
+ u64 tx_pkt1024tomax;
+ u64 tx_unicast;
+ u64 tx_multicast;
+ u64 tx_broadcast;
+ u64 tx_underflow_err;
+ u64 tx_bytes_g;
+ u64 tx_frame_g;
+ u64 tx_pause;
+ u64 tx_vlan_g;
+ u64 tx_lpi_usec;
+ u64 tx_lpi_tran;
+ u64 rx_frames;
+ u64 rx_bytes;
+ u64 rx_bytes_g;
+ u64 rx_broadcast_g;
+ u64 rx_multicast_g;
+ u64 rx_crc_err;
+ u64 rx_runt_err;
+ u64 rx_jabber_err;
+ u64 rx_undersize_g;
+ u64 rx_oversize_g;
+ u64 rx_pkt64;
+ u64 rx_pkt65to127;
+ u64 rx_pkt128to255;
+ u64 rx_pkt256to511;
+ u64 rx_pkt512to1023;
+ u64 rx_pkt1024tomax;
+ u64 rx_unicast_g;
+ u64 rx_len_err;
+ u64 rx_outofrange_err;
+ u64 rx_pause;
+ u64 rx_fifo_overflow;
+ u64 rx_vlan;
+ u64 rx_wdog_err;
+ u64 rx_lpi_usec;
+ u64 rx_lpi_tran;
+ u64 rx_drop_frames;
+ u64 rx_drop_bytes;
+};
+
/* PPE per port data type to record port settings such as phylink
* setting, mac type, interface mode and link speed.
*/
@@ -197,6 +292,9 @@ struct ppe_port {
int speed;
int duplex;
int pause;
+ struct delayed_work gmib_read;
+ struct ppe_gmib_hw_stats *gmib_stats;
+ spinlock_t stats_lock; /* Protects gmib stats */
};
/* PPE ports data type */
@@ -17,6 +17,15 @@
#define PPE_PORT5_PCS_SEL BIT(4)
#define PPE_PORT_MAC_SEL(x) (PPE_PORT1_MAC_SEL << ((x) - 1))
+#define PPE_LPI_LPI_EN 0x400
+#define PPE_LPI_PORT1_EN BIT(0)
+#define PPE_LPI_PORT2_EN BIT(1)
+#define PPE_LPI_PORT3_EN BIT(2)
+#define PPE_LPI_PORT4_EN BIT(3)
+#define PPE_LPI_PORT5_EN BIT(4)
+#define PPE_LPI_PORT6_EN BIT(5)
+#define PPE_LPI_PORT_EN(x) (PPE_LPI_PORT1_EN << ((x) - 1))
+
#define PPE_BM_TDM_CTRL 0xb000
#define PPE_BM_TDM_CTRL_NUM 1
#define PPE_BM_TDM_CTRL_INC 4
@@ -848,6 +857,16 @@ union ppe_ac_grp_cfg_u {
#define GMAC_SPEED_100 1
#define GMAC_SPEED_1000 2
+#define GMAC_GOL_MAC_ADDR0 0x8
+#define MAC_ADDR_BYTE5 GENMASK(15, 8)
+#define MAC_ADDR_BYTE4 GENMASK(7, 0)
+
+#define GMAC_GOL_MAC_ADDR1 0xC
+#define MAC_ADDR_BYTE0 GENMASK(31, 24)
+#define MAC_ADDR_BYTE1 GENMASK(23, 16)
+#define MAC_ADDR_BYTE2 GENMASK(15, 8)
+#define MAC_ADDR_BYTE3 GENMASK(7, 0)
+
#define GMAC_MAC_CTRL2 0x18
#define GMAC_TX_THD_MASK GENMASK(27, 24)
#define GMAC_MAXFR_MASK GENMASK(21, 8)
@@ -871,6 +890,50 @@ union ppe_ac_grp_cfg_u {
#define MAC_MIB_RESET BIT(1)
#define MAC_MIB_EN BIT(0)
+#define GMAC_RXBROAD 0x40
+#define GMAC_RXPAUSE 0x44
+#define GMAC_RXMULTI 0x48
+#define GMAC_RXFCSERR 0x4C
+#define GMAC_RXALIGNERR 0x50
+#define GMAC_RXRUNT 0x54
+#define GMAC_RXFRAG 0x58
+#define GMAC_RXJUMBOFCSERR 0x5C
+#define GMAC_RXJUMBOALIGNERR 0x60
+#define GMAC_RXPKT64 0x64
+#define GMAC_RXPKT65TO127 0x68
+#define GMAC_RXPKT128TO255 0x6C
+#define GMAC_RXPKT256TO511 0x70
+#define GMAC_RXPKT512TO1023 0x74
+#define GMAC_RXPKT1024TO1518 0x78
+#define GMAC_RXPKT1519TOX 0x7C
+#define GMAC_RXTOOLONG 0x80
+#define GMAC_RXGOODBYTE_L 0x84
+#define GMAC_RXGOODBYTE_H 0x88
+#define GMAC_RXBADBYTE_L 0x8C
+#define GMAC_RXBADBYTE_H 0x90
+#define GMAC_RXUNI 0x94
+#define GMAC_TXBROAD 0xA0
+#define GMAC_TXPAUSE 0xA4
+#define GMAC_TXMULTI 0xA8
+#define GMAC_TXUNDERRUN 0xAC
+#define GMAC_TXPKT64 0xB0
+#define GMAC_TXPKT65TO127 0xB4
+#define GMAC_TXPKT128TO255 0xB8
+#define GMAC_TXPKT256TO511 0xBC
+#define GMAC_TXPKT512TO1023 0xC0
+#define GMAC_TXPKT1024TO1518 0xC4
+#define GMAC_TXPKT1519TOX 0xC8
+#define GMAC_TXBYTE_L 0xCC
+#define GMAC_TXBYTE_H 0xD0
+#define GMAC_TXCOLLISIONS 0xD4
+#define GMAC_TXABORTCOL 0xD8
+#define GMAC_TXMULTICOL 0xDC
+#define GMAC_TXSINGLECOL 0xE0
+#define GMAC_TXEXCESSIVEDEFER 0xE4
+#define GMAC_TXDEFER 0xE8
+#define GMAC_TXLATECOL 0xEC
+#define GMAC_TXUNI 0xF0
+
/* XGMAC Registers */
#define XGMAC_TX_CONFIGURATION 0x0
#define XGMAC_SPEED_MASK GENMASK(31, 29)
@@ -927,8 +990,117 @@ union ppe_ac_grp_cfg_u {
#define XGMAC_RX_FLOW_CTRL 0x90
#define XGMAC_RFE BIT(0)
+#define XGMAC_LPI_CONTROL_STATUS 0xd0
+#define XGMAC_LPI_TXEN BIT(16)
+#define XGMAC_LPI_PLS BIT(17)
+#define XGMAC_LPI_TXA BIT(19)
+#define XGMAC_LPI_TE BIT(20)
+
+#define XGMAC_LPI_TIMERS_CONTROL 0xd4
+#define XGMAC_LPI_TWT GENMASK(15, 0)
+#define XGMAC_LPI_LST GENMASK(25, 16)
+
+#define XGMAC_LPI_AUTO_ENTRY_TIMER 0xd8
+#define XGMAC_LPI_ET GENMASK(19, 3)
+
+#define XGMAC_1US_TIC_COUNTER 0xdc
+#define XGMAC_1US_TIC_CNTR GENMASK(11, 0)
+
+#define XGMAC_MAC_ADDR0_HIGH 0x300
+#define XGMAC_ADDR_EN BIT(31)
+#define XGMAC_ADDRHI GENMASK(15, 0)
+
+#define XGMAC_MAC_ADDR0_LOW 0x304
+#define XGMAC_ADDRLO GENMASK(31, 0)
+
#define XGMAC_MMC_CONTROL 0x800
#define XGMAC_MCF BIT(3)
#define XGMAC_CNTRST BIT(0)
+#define XGMAC_TX_OCTET_COUNT_GOOD_BAD_LOW 0x814
+#define XGMAC_TX_OCTET_COUNT_GOOD_BAD_HIGH 0x818
+#define XGMAC_TX_FRAME_COUNT_GOOD_BAD_LOW 0x81C
+#define XGMAC_TX_FRAME_COUNT_GOOD_BAD_HIGH 0x820
+#define XGMAC_TX_BROADCAST_FRAMES_GOOD_LOW 0x824
+#define XGMAC_TX_BROADCAST_FRAMES_GOOD_HIGH 0x828
+#define XGMAC_TX_MULTICAST_FRAMES_GOOD_LOW 0x82C
+#define XGMAC_TX_MULTICAST_FRAMES_GOOD_HIGH 0x830
+#define XGMAC_TX_64OCTETS_FRAMES_GOOD_BAD_LOW 0x834
+#define XGMAC_TX_64OCTETS_FRAMES_GOOD_BAD_HIGH 0x838
+#define XGMAC_TX_65TO127OCTETS_FRAMES_GOOD_BAD_LOW 0x83C
+#define XGMAC_TX_65TO127OCTETS_FRAMES_GOOD_BAD_HIGH 0x840
+#define XGMAC_TX_128TO255OCTETS_FRAMES_GOOD_BAD_LOW 0x844
+#define XGMAC_TX_128TO255OCTETS_FRAMES_GOOD_BAD_HIGH 0x848
+#define XGMAC_TX_256TO511OCTETS_FRAMES_GOOD_BAD_LOW 0x84C
+#define XGMAC_TX_256TO511OCTETS_FRAMES_GOOD_BAD_HIGH 0x850
+#define XGMAC_TX_512TO1023OCTETS_FRAMES_GOOD_BAD_LOW 0x854
+#define XGMAC_TX_512TO1023OCTETS_FRAMES_GOOD_BAD_HIGH 0x858
+#define XGMAC_TX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_LOW 0x85C
+#define XGMAC_TX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_HIGH 0x860
+#define XGMAC_TX_UNICAST_FRAMES_GOOD_BAD_LOW 0x864
+#define XGMAC_TX_UNICAST_FRAMES_GOOD_BAD_HIGH 0x868
+#define XGMAC_TX_MULTICAST_FRAMES_GOOD_BAD_LOW 0x86C
+#define XGMAC_TX_MULTICAST_FRAMES_GOOD_BAD_HIGH 0x870
+#define XGMAC_TX_BROADCAST_FRAMES_GOOD_BAD_LOW 0x874
+#define XGMAC_TX_BROADCAST_FRAMES_GOOD_BAD_HIGH 0x878
+#define XGMAC_TX_UNDERFLOW_ERROR_FRAMES_LOW 0x87C
+#define XGMAC_TX_UNDERFLOW_ERROR_FRAMES_HIGH 0x880
+#define XGMAC_TX_OCTET_COUNT_GOOD_LOW 0x884
+#define XGMAC_TX_OCTET_COUNT_GOOD_HIGH 0x888
+#define XGMAC_TX_FRAME_COUNT_GOOD_LOW 0x88C
+#define XGMAC_TX_FRAME_COUNT_GOOD_HIGH 0x890
+#define XGMAC_TX_PAUSE_FRAMES_LOW 0x894
+#define XGMAC_TX_PAUSE_FRAMES_HIGH 0x898
+#define XGMAC_TX_VLAN_FRAMES_GOOD_LOW 0x89C
+#define XGMAC_TX_VLAN_FRAMES_GOOD_HIGH 0x8A0
+#define XGMAC_TX_LPI_USEC_CNTR 0x8A4
+#define XGMAC_TX_LPI_TRAN_CNTR 0x8A8
+#define XGMAC_RX_FRAME_COUNT_GOOD_BAD_LOW 0x900
+#define XGMAC_RX_FRAME_COUNT_GOOD_BAD_HIGH 0x904
+#define XGMAC_RX_OCTET_COUNT_GOOD_BAD_LOW 0x908
+#define XGMAC_RX_OCTET_COUNT_GOOD_BAD_HIGH 0x90C
+#define XGMAC_RX_OCTET_COUNT_GOOD_LOW 0x910
+#define XGMAC_RX_OCTET_COUNT_GOOD_HIGH 0x914
+#define XGMAC_RX_BROADCAST_FRAMES_GOOD_LOW 0x918
+#define XGMAC_RX_BROADCAST_FRAMES_GOOD_HIGH 0x91C
+#define XGMAC_RX_MULTICAST_FRAMES_GOOD_LOW 0x920
+#define XGMAC_RX_MULTICAST_FRAMES_GOOD_HIGH 0x924
+#define XGMAC_RX_CRC_ERROR_FRAMES_LOW 0x928
+#define XGMAC_RX_CRC_ERROR_FRAMES_HIGH 0x92C
+#define XGMAC_RX_FRAG_ERROR_FRAMES 0x930
+#define XGMAC_RX_JABBER_ERROR_FRAMES 0x934
+#define XGMAC_RX_UNDERSIZE_FRAMES_GOOD 0x938
+#define XGMAC_RX_OVERSIZE_FRAMES_GOOD 0x93C
+#define XGMAC_RX_64OCTETS_FRAMES_GOOD_BAD_LOW 0x940
+#define XGMAC_RX_64OCTETS_FRAMES_GOOD_BAD_HIGH 0x944
+#define XGMAC_RX_65TO127OCTETS_FRAMES_GOOD_BAD_LOW 0x948
+#define XGMAC_RX_65TO127OCTETS_FRAMES_GOOD_BAD_HIGH 0x94C
+#define XGMAC_RX_128TO255OCTETS_FRAMES_GOOD_BAD_LOW 0x950
+#define XGMAC_RX_128TO255OCTETS_FRAMES_GOOD_BAD_HIGH 0x954
+#define XGMAC_RX_256TO511OCTETS_FRAMES_GOOD_BAD_LOW 0x958
+#define XGMAC_RX_256TO511OCTETS_FRAMES_GOOD_BAD_HIGH 0x95C
+#define XGMAC_RX_512TO1023OCTETS_FRAMES_GOOD_BAD_LOW 0x960
+#define XGMAC_RX_512TO1023OCTETS_FRAMES_GOOD_BAD_HIGH 0x964
+#define XGMAC_RX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_LOW 0x968
+#define XGMAC_RX_1024TOMAXOCTETS_FRAMES_GOOD_BAD_HIGH 0x96C
+#define XGMAC_RX_UNICAST_FRAMES_GOOD_LOW 0x970
+#define XGMAC_RX_UNICAST_FRAMES_GOOD_HIGH 0x974
+#define XGMAC_RX_LENGTH_ERROR_FRAMES_LOW 0x978
+#define XGMAC_RX_LENGTH_ERROR_FRAMES_HIGH 0x97C
+#define XGMAC_RX_OUTOFRANGE_FRAMES_LOW 0x980
+#define XGMAC_RX_OUTOFRANGE_FRAMES_HIGH 0x984
+#define XGMAC_RX_PAUSE_FRAMES_LOW 0x988
+#define XGMAC_RX_PAUSE_FRAMES_HIGH 0x98C
+#define XGMAC_RX_FIFOOVERFLOW_FRAMES_LOW 0x990
+#define XGMAC_RX_FIFOOVERFLOW_FRAMES_HIGH 0x994
+#define XGMAC_RX_VLAN_FRAMES_GOOD_BAD_LOW 0x998
+#define XGMAC_RX_VLAN_FRAMES_GOOD_BAD_HIGH 0x99C
+#define XGMAC_RX_WATCHDOG_ERROR_FRAMES 0x9A0
+#define XGMAC_RX_LPI_USEC_CNTR 0x9A4
+#define XGMAC_RX_LPI_TRAN_CNTR 0x9A8
+#define XGMAC_RX_DISCARD_FRAME_COUNT_GOOD_BAD_LOW 0x9AC
+#define XGMAC_RX_DISCARD_FRAME_COUNT_GOOD_BAD_HIGH 0x9B0
+#define XGMAC_RX_DISCARD_OCTET_COUNT_GOOD_BAD_LOW 0x9B4
+#define XGMAC_RX_DISCARD_OCTET_COUNT_GOOD_BAD_HIGH 0x9B8
+
#endif
@@ -10,6 +10,7 @@
#include <linux/platform_device.h>
#include <linux/phylink.h>
+#include <linux/if_link.h>
/* PPE platform private data, which is used by external driver like
* Ethernet DMA driver.
@@ -57,6 +58,35 @@ struct ppe_device_ops {
struct phylink_pcs *(*phylink_mac_select_pcs)(struct ppe_device *ppe_dev,
int port,
phy_interface_t interface);
+ /*
+ * Port statistics counters
+ */
+ void (*get_stats64)(struct ppe_device *ppe_dev,
+ int port,
+ struct rtnl_link_stats64 *s);
+ void (*get_strings)(struct ppe_device *ppe_dev,
+ int port,
+ u32 stringset,
+ u8 *data);
+ int (*get_sset_count)(struct ppe_device *ppe_dev,
+ int port,
+ int sset);
+ void (*get_ethtool_stats)(struct ppe_device *ppe_dev,
+ int port,
+ u64 *data);
+ /*
+ * Port MAC address setting
+ */
+ int (*set_mac_address)(struct ppe_device *ppe_dev,
+ int port,
+ u8 *macaddr);
+ /*
+ * Port MAC EEE settings
+ */
+ int (*set_mac_eee)(struct ppe_device *ppe_dev, int port,
+ struct ethtool_eee *eee);
+ int (*get_mac_eee)(struct ppe_device *ppe_dev, int port,
+ struct ethtool_eee *eee);
/*
* Port maximum frame size setting
*/