Commit 9efa27bf authored by David S. Miller's avatar David S. Miller

Merge branch 'xgene-Add-ethtool-stats-and-bug-fixes'

Iyappan Subramanian says:

====================
drivers: net: xgene: Add ethtool stats and bug fixes

This patch set,

- adds ethtool extended statistics support
- addresses errata workarounds
- fixes bugs related to statistics

v2: Address review comments from v1
	- Adds lock to protect mdio-xgene indirect MAC access
	- Refactors xgene-enet indirect MAC read/write functions
	- Uses mdio-xgene MAC access routines, if xgene-enet port
	  use the same HW.
v1:
	- Initial version
Signed-off-by: default avatarIyappan Subramanian <isubramanian@apm.com>
Signed-off-by: default avatarQuan Nguyen <qnguyen@apm.com>
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a95cfad9 8aba8474
......@@ -23,9 +23,17 @@
struct xgene_gstrings_stats {
char name[ETH_GSTRING_LEN];
int offset;
u32 addr;
u32 mask;
};
#define XGENE_STAT(m) { #m, offsetof(struct xgene_enet_pdata, stats.m) }
#define XGENE_STAT(m) { #m, offsetof(struct rtnl_link_stats64, m) }
#define XGENE_EXTD_STAT(s, a, m) \
{ \
.name = #s, \
.addr = a ## _ADDR, \
.mask = m \
}
static const struct xgene_gstrings_stats gstrings_stats[] = {
XGENE_STAT(rx_packets),
......@@ -40,7 +48,65 @@ static const struct xgene_gstrings_stats gstrings_stats[] = {
XGENE_STAT(rx_fifo_errors)
};
static const struct xgene_gstrings_stats gstrings_extd_stats[] = {
XGENE_EXTD_STAT(tx_rx_64b_frame_cntr, TR64, 31),
XGENE_EXTD_STAT(tx_rx_127b_frame_cntr, TR127, 31),
XGENE_EXTD_STAT(tx_rx_255b_frame_cntr, TR255, 31),
XGENE_EXTD_STAT(tx_rx_511b_frame_cntr, TR511, 31),
XGENE_EXTD_STAT(tx_rx_1023b_frame_cntr, TR1K, 31),
XGENE_EXTD_STAT(tx_rx_1518b_frame_cntr, TRMAX, 31),
XGENE_EXTD_STAT(tx_rx_1522b_frame_cntr, TRMGV, 31),
XGENE_EXTD_STAT(rx_fcs_error_cntr, RFCS, 16),
XGENE_EXTD_STAT(rx_multicast_pkt_cntr, RMCA, 31),
XGENE_EXTD_STAT(rx_broadcast_pkt_cntr, RBCA, 31),
XGENE_EXTD_STAT(rx_ctrl_frame_pkt_cntr, RXCF, 16),
XGENE_EXTD_STAT(rx_pause_frame_pkt_cntr, RXPF, 16),
XGENE_EXTD_STAT(rx_unk_opcode_cntr, RXUO, 16),
XGENE_EXTD_STAT(rx_align_err_cntr, RALN, 16),
XGENE_EXTD_STAT(rx_frame_len_err_cntr, RFLR, 16),
XGENE_EXTD_STAT(rx_frame_len_err_recov_cntr, DUMP, 0),
XGENE_EXTD_STAT(rx_code_err_cntr, RCDE, 16),
XGENE_EXTD_STAT(rx_carrier_sense_err_cntr, RCSE, 16),
XGENE_EXTD_STAT(rx_undersize_pkt_cntr, RUND, 16),
XGENE_EXTD_STAT(rx_oversize_pkt_cntr, ROVR, 16),
XGENE_EXTD_STAT(rx_fragments_cntr, RFRG, 16),
XGENE_EXTD_STAT(rx_jabber_cntr, RJBR, 16),
XGENE_EXTD_STAT(rx_jabber_recov_cntr, DUMP, 0),
XGENE_EXTD_STAT(rx_dropped_pkt_cntr, RDRP, 16),
XGENE_EXTD_STAT(rx_overrun_cntr, DUMP, 0),
XGENE_EXTD_STAT(tx_multicast_pkt_cntr, TMCA, 31),
XGENE_EXTD_STAT(tx_broadcast_pkt_cntr, TBCA, 31),
XGENE_EXTD_STAT(tx_pause_ctrl_frame_cntr, TXPF, 16),
XGENE_EXTD_STAT(tx_defer_pkt_cntr, TDFR, 31),
XGENE_EXTD_STAT(tx_excv_defer_pkt_cntr, TEDF, 31),
XGENE_EXTD_STAT(tx_single_col_pkt_cntr, TSCL, 31),
XGENE_EXTD_STAT(tx_multi_col_pkt_cntr, TMCL, 31),
XGENE_EXTD_STAT(tx_late_col_pkt_cntr, TLCL, 31),
XGENE_EXTD_STAT(tx_excv_col_pkt_cntr, TXCL, 31),
XGENE_EXTD_STAT(tx_total_col_cntr, TNCL, 31),
XGENE_EXTD_STAT(tx_pause_frames_hnrd_cntr, TPFH, 16),
XGENE_EXTD_STAT(tx_drop_frame_cntr, TDRP, 16),
XGENE_EXTD_STAT(tx_jabber_frame_cntr, TJBR, 12),
XGENE_EXTD_STAT(tx_fcs_error_cntr, TFCS, 12),
XGENE_EXTD_STAT(tx_ctrl_frame_cntr, TXCF, 12),
XGENE_EXTD_STAT(tx_oversize_frame_cntr, TOVR, 12),
XGENE_EXTD_STAT(tx_undersize_frame_cntr, TUND, 12),
XGENE_EXTD_STAT(tx_fragments_cntr, TFRG, 12),
XGENE_EXTD_STAT(tx_underrun_cntr, DUMP, 0)
};
#define XGENE_STATS_LEN ARRAY_SIZE(gstrings_stats)
#define XGENE_EXTD_STATS_LEN ARRAY_SIZE(gstrings_extd_stats)
#define RFCS_IDX 7
#define RALN_IDX 13
#define RFLR_IDX 14
#define FALSE_RFLR_IDX 15
#define RUND_IDX 18
#define FALSE_RJBR_IDX 22
#define RX_OVERRUN_IDX 24
#define TFCS_IDX 38
#define TFRG_IDX 42
#define TX_UNDERRUN_IDX 43
static void xgene_get_drvinfo(struct net_device *ndev,
struct ethtool_drvinfo *info)
......@@ -142,6 +208,11 @@ static void xgene_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
memcpy(p, gstrings_stats[i].name, ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
memcpy(p, gstrings_extd_stats[i].name, ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
}
static int xgene_get_sset_count(struct net_device *ndev, int sset)
......@@ -149,18 +220,71 @@ static int xgene_get_sset_count(struct net_device *ndev, int sset)
if (sset != ETH_SS_STATS)
return -EINVAL;
return XGENE_STATS_LEN;
return XGENE_STATS_LEN + XGENE_EXTD_STATS_LEN;
}
static void xgene_get_extd_stats(struct xgene_enet_pdata *pdata)
{
u32 rx_drop, tx_drop;
u32 mask, tmp;
int i;
for (i = 0; i < XGENE_EXTD_STATS_LEN; i++) {
tmp = xgene_enet_rd_stat(pdata, gstrings_extd_stats[i].addr);
if (gstrings_extd_stats[i].mask) {
mask = GENMASK(gstrings_extd_stats[i].mask - 1, 0);
pdata->extd_stats[i] += (tmp & mask);
}
}
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
/* Errata 10GE_10 - SW should intepret RALN as 0 */
pdata->extd_stats[RALN_IDX] = 0;
} else {
/* Errata ENET_15 - Fixes RFCS, RFLR, TFCS counter */
pdata->extd_stats[RFCS_IDX] -= pdata->extd_stats[RALN_IDX];
pdata->extd_stats[RFLR_IDX] -= pdata->extd_stats[RUND_IDX];
pdata->extd_stats[TFCS_IDX] -= pdata->extd_stats[TFRG_IDX];
}
pdata->mac_ops->get_drop_cnt(pdata, &rx_drop, &tx_drop);
pdata->extd_stats[RX_OVERRUN_IDX] += rx_drop;
pdata->extd_stats[TX_UNDERRUN_IDX] += tx_drop;
/* Errata 10GE_8 - Update Frame recovered from Errata 10GE_8/ENET_11 */
pdata->extd_stats[FALSE_RFLR_IDX] = pdata->false_rflr;
/* Errata ENET_15 - Jabber Frame recov'ed from Errata 10GE_10/ENET_15 */
pdata->extd_stats[FALSE_RJBR_IDX] = pdata->vlan_rjbr;
}
int xgene_extd_stats_init(struct xgene_enet_pdata *pdata)
{
pdata->extd_stats = devm_kmalloc_array(&pdata->pdev->dev,
XGENE_EXTD_STATS_LEN, sizeof(u64), GFP_KERNEL);
if (!pdata->extd_stats)
return -ENOMEM;
xgene_get_extd_stats(pdata);
memset(pdata->extd_stats, 0, XGENE_EXTD_STATS_LEN * sizeof(u64));
return 0;
}
static void xgene_get_ethtool_stats(struct net_device *ndev,
struct ethtool_stats *dummy,
u64 *data)
{
void *pdata = netdev_priv(ndev);
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct rtnl_link_stats64 stats;
int i;
dev_get_stats(ndev, &stats);
for (i = 0; i < XGENE_STATS_LEN; i++)
*data++ = *(u64 *)(pdata + gstrings_stats[i].offset);
data[i] = *(u64 *)((char *)&stats + gstrings_stats[i].offset);
xgene_get_extd_stats(pdata);
for (i = 0; i < XGENE_EXTD_STATS_LEN; i++)
data[i + XGENE_STATS_LEN] = pdata->extd_stats[i];
}
static void xgene_get_pauseparam(struct net_device *ndev,
......
......@@ -115,6 +115,7 @@ enum xgene_enet_rm {
#define BLOCK_ETH_CLKRST_CSR_OFFSET 0xc000
#define BLOCK_ETH_DIAG_CSR_OFFSET 0xD000
#define BLOCK_ETH_MAC_OFFSET 0x0000
#define BLOCK_ETH_STATS_OFFSET 0x0000
#define BLOCK_ETH_MAC_CSR_OFFSET 0x2800
#define CLKEN_ADDR 0xc208
......@@ -126,6 +127,12 @@ enum xgene_enet_rm {
#define MAC_READ_REG_OFFSET 0x0c
#define MAC_COMMAND_DONE_REG_OFFSET 0x10
#define STAT_ADDR_REG_OFFSET 0x14
#define STAT_COMMAND_REG_OFFSET 0x18
#define STAT_WRITE_REG_OFFSET 0x1c
#define STAT_READ_REG_OFFSET 0x20
#define STAT_COMMAND_DONE_REG_OFFSET 0x24
#define PCS_ADDR_REG_OFFSET 0x00
#define PCS_COMMAND_REG_OFFSET 0x04
#define PCS_WRITE_REG_OFFSET 0x08
......@@ -185,6 +192,10 @@ enum xgene_enet_rm {
#define CFG_CLE_NXTFPSEL0(val) (((val) << 20) & GENMASK(23, 20))
#define ICM_CONFIG0_REG_0_ADDR 0x0400
#define ICM_CONFIG2_REG_0_ADDR 0x0410
#define ECM_CONFIG0_REG_0_ADDR 0x0500
#define ECM_CONFIG0_REG_1_ADDR 0x0504
#define ICM_ECM_DROP_COUNT_REG0_ADDR 0x0508
#define ICM_ECM_DROP_COUNT_REG1_ADDR 0x050c
#define RX_DV_GATE_REG_0_ADDR 0x05fc
#define TX_DV_GATE_EN0 BIT(2)
#define RX_DV_GATE_EN0 BIT(1)
......@@ -217,12 +228,53 @@ enum xgene_enet_rm {
#define FULL_DUPLEX2 BIT(0)
#define PAD_CRC BIT(2)
#define LENGTH_CHK BIT(4)
#define SCAN_AUTO_INCR BIT(5)
#define TBYT_ADDR 0x38
#define TPKT_ADDR 0x39
#define TDRP_ADDR 0x45
#define TFCS_ADDR 0x47
#define TUND_ADDR 0x4a
#define TR64_ADDR 0x20
#define TR127_ADDR 0x21
#define TR255_ADDR 0x22
#define TR511_ADDR 0x23
#define TR1K_ADDR 0x24
#define TRMAX_ADDR 0x25
#define TRMGV_ADDR 0x26
#define RFCS_ADDR 0x29
#define RMCA_ADDR 0x2a
#define RBCA_ADDR 0x2b
#define RXCF_ADDR 0x2c
#define RXPF_ADDR 0x2d
#define RXUO_ADDR 0x2e
#define RALN_ADDR 0x2f
#define RFLR_ADDR 0x30
#define RCDE_ADDR 0x31
#define RCSE_ADDR 0x32
#define RUND_ADDR 0x33
#define ROVR_ADDR 0x34
#define RFRG_ADDR 0x35
#define RJBR_ADDR 0x36
#define RDRP_ADDR 0x37
#define TMCA_ADDR 0x3a
#define TBCA_ADDR 0x3b
#define TXPF_ADDR 0x3c
#define TDFR_ADDR 0x3d
#define TEDF_ADDR 0x3e
#define TSCL_ADDR 0x3f
#define TMCL_ADDR 0x40
#define TLCL_ADDR 0x41
#define TXCL_ADDR 0x42
#define TNCL_ADDR 0x43
#define TPFH_ADDR 0x44
#define TDRP_ADDR 0x45
#define TJBR_ADDR 0x46
#define TFCS_ADDR 0x47
#define TXCF_ADDR 0x48
#define TOVR_ADDR 0x49
#define TUND_ADDR 0x4a
#define TFRG_ADDR 0x4b
#define DUMP_ADDR 0x27
#define ECM_DROP_COUNT(src) xgene_get_bits(src, 0, 15)
#define ICM_DROP_COUNT(src) xgene_get_bits(src, 16, 31)
#define TSO_IPPROTO_TCP 1
......@@ -380,14 +432,16 @@ static inline u16 xgene_enet_get_numslots(u16 id, u32 size)
}
void xgene_enet_parse_error(struct xgene_enet_desc_ring *ring,
struct xgene_enet_pdata *pdata,
enum xgene_enet_err_code status);
int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata);
void xgene_enet_mdio_remove(struct xgene_enet_pdata *pdata);
bool xgene_ring_mgr_init(struct xgene_enet_pdata *p);
int xgene_enet_phy_connect(struct net_device *ndev);
void xgene_enet_phy_disconnect(struct xgene_enet_pdata *pdata);
u32 xgene_enet_rd_mac(struct xgene_enet_pdata *pdata, u32 rd_addr);
void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata, u32 wr_addr,
u32 wr_data);
u32 xgene_enet_rd_stat(struct xgene_enet_pdata *pdata, u32 rd_addr);
extern const struct xgene_mac_ops xgene_gmac_ops;
extern const struct xgene_port_ops xgene_gport_ops;
......
......@@ -246,9 +246,9 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
skb_frag_t *frag;
dma_addr_t *frag_dma_addr;
u16 skb_index;
u8 status;
int i, ret = 0;
u8 mss_index;
u8 status;
int i;
skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0));
skb = cp_ring->cp_skb[skb_index];
......@@ -275,19 +275,17 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring,
/* Checking for error */
status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
if (unlikely(status > 2)) {
xgene_enet_parse_error(cp_ring, netdev_priv(cp_ring->ndev),
status);
ret = -EIO;
cp_ring->tx_dropped++;
cp_ring->tx_errors++;
}
if (likely(skb)) {
dev_kfree_skb_any(skb);
} else {
netdev_err(cp_ring->ndev, "completion skb is NULL\n");
ret = -EIO;
}
return ret;
return 0;
}
static int xgene_enet_setup_mss(struct net_device *ndev, u32 mss)
......@@ -658,6 +656,18 @@ static void xgene_enet_free_pagepool(struct xgene_enet_desc_ring *buf_pool,
buf_pool->head = head;
}
/* Errata 10GE_10 and ENET_15 - Fix duplicated HW statistic counters */
static bool xgene_enet_errata_10GE_10(struct sk_buff *skb, u32 len, u8 status)
{
if (status == INGRESS_CRC &&
len >= (ETHER_STD_PACKET + 1) &&
len <= (ETHER_STD_PACKET + 4) &&
skb->protocol == htons(ETH_P_8021Q))
return true;
return false;
}
/* Errata 10GE_8 and ENET_11 - allow packet with length <=64B */
static bool xgene_enet_errata_10GE_8(struct sk_buff *skb, u32 len, u8 status)
{
......@@ -708,10 +718,15 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring,
status = (GET_VAL(ELERR, le64_to_cpu(raw_desc->m0)) << LERR_LEN) |
GET_VAL(LERR, le64_to_cpu(raw_desc->m0));
if (unlikely(status)) {
if (!xgene_enet_errata_10GE_8(skb, datalen, status)) {
if (xgene_enet_errata_10GE_8(skb, datalen, status)) {
pdata->false_rflr++;
} else if (xgene_enet_errata_10GE_10(skb, datalen, status)) {
pdata->vlan_rjbr++;
} else {
dev_kfree_skb_any(skb);
xgene_enet_free_pagepool(page_pool, raw_desc, exp_desc);
xgene_enet_parse_error(rx_ring, pdata, status);
xgene_enet_parse_error(rx_ring, status);
rx_ring->rx_dropped++;
goto out;
}
}
......@@ -1466,10 +1481,9 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev)
static void xgene_enet_get_stats64(
struct net_device *ndev,
struct rtnl_link_stats64 *storage)
struct rtnl_link_stats64 *stats)
{
struct xgene_enet_pdata *pdata = netdev_priv(ndev);
struct rtnl_link_stats64 *stats = &pdata->stats;
struct xgene_enet_desc_ring *ring;
int i;
......@@ -1478,6 +1492,8 @@ static void xgene_enet_get_stats64(
if (ring) {
stats->tx_packets += ring->tx_packets;
stats->tx_bytes += ring->tx_bytes;
stats->tx_dropped += ring->tx_dropped;
stats->tx_errors += ring->tx_errors;
}
}
......@@ -1486,14 +1502,18 @@ static void xgene_enet_get_stats64(
if (ring) {
stats->rx_packets += ring->rx_packets;
stats->rx_bytes += ring->rx_bytes;
stats->rx_errors += ring->rx_length_errors +
stats->rx_dropped += ring->rx_dropped;
stats->rx_errors += ring->rx_errors +
ring->rx_length_errors +
ring->rx_crc_errors +
ring->rx_frame_errors +
ring->rx_fifo_errors;
stats->rx_dropped += ring->rx_dropped;
stats->rx_length_errors += ring->rx_length_errors;
stats->rx_crc_errors += ring->rx_crc_errors;
stats->rx_frame_errors += ring->rx_frame_errors;
stats->rx_fifo_errors += ring->rx_fifo_errors;
}
}
memcpy(storage, stats, sizeof(struct rtnl_link_stats64));
}
static int xgene_enet_set_mac_address(struct net_device *ndev, void *addr)
......@@ -1788,12 +1808,15 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
if (pdata->phy_mode == PHY_INTERFACE_MODE_RGMII ||
pdata->phy_mode == PHY_INTERFACE_MODE_SGMII) {
pdata->mcx_mac_addr = pdata->base_addr + BLOCK_ETH_MAC_OFFSET;
pdata->mcx_stats_addr =
pdata->base_addr + BLOCK_ETH_STATS_OFFSET;
offset = (pdata->enet_id == XGENE_ENET1) ?
BLOCK_ETH_MAC_CSR_OFFSET :
X2_BLOCK_ETH_MAC_CSR_OFFSET;
pdata->mcx_mac_csr_addr = base_addr + offset;
} else {
pdata->mcx_mac_addr = base_addr + BLOCK_AXG_MAC_OFFSET;
pdata->mcx_stats_addr = base_addr + BLOCK_AXG_STATS_OFFSET;
pdata->mcx_mac_csr_addr = base_addr + BLOCK_AXG_MAC_CSR_OFFSET;
pdata->pcs_addr = base_addr + BLOCK_PCS_OFFSET;
}
......@@ -2055,6 +2078,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
goto err;
xgene_enet_setup_ops(pdata);
spin_lock_init(&pdata->mac_lock);
if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) {
ndev->features |= NETIF_F_TSO | NETIF_F_RXCSUM;
......@@ -2085,6 +2109,11 @@ static int xgene_enet_probe(struct platform_device *pdev)
goto err1;
}
spin_lock_init(&pdata->stats_lock);
ret = xgene_extd_stats_init(pdata);
if (ret)
goto err2;
xgene_enet_napi_add(pdata);
ret = register_netdev(ndev);
if (ret) {
......@@ -2130,8 +2159,8 @@ static int xgene_enet_remove(struct platform_device *pdev)
xgene_enet_mdio_remove(pdata);
unregister_netdev(ndev);
pdata->port_ops->shutdown(pdata);
xgene_enet_delete_desc_rings(pdata);
pdata->port_ops->shutdown(pdata);
free_netdev(ndev);
return 0;
......
......@@ -42,6 +42,7 @@
#define XGENE_DRV_VERSION "v1.0"
#define ETHER_MIN_PACKET 64
#define ETHER_STD_PACKET 1518
#define XGENE_ENET_STD_MTU 1536
#define XGENE_ENET_MAX_MTU 9600
#define SKB_BUFFER_SIZE (XGENE_ENET_STD_MTU - NET_IP_ALIGN)
......@@ -138,6 +139,8 @@ struct xgene_enet_desc_ring {
__le64 *exp_bufs;
u64 tx_packets;
u64 tx_bytes;
u64 tx_dropped;
u64 tx_errors;
u64 rx_packets;
u64 rx_bytes;
u64 rx_dropped;
......@@ -155,6 +158,7 @@ struct xgene_mac_ops {
void (*rx_enable)(struct xgene_enet_pdata *pdata);
void (*tx_disable)(struct xgene_enet_pdata *pdata);
void (*rx_disable)(struct xgene_enet_pdata *pdata);
void (*get_drop_cnt)(struct xgene_enet_pdata *pdata, u32 *rx, u32 *tx);
void (*set_speed)(struct xgene_enet_pdata *pdata);
void (*set_mac_addr)(struct xgene_enet_pdata *pdata);
void (*set_framesize)(struct xgene_enet_pdata *pdata, int framesize);
......@@ -212,6 +216,7 @@ struct xgene_enet_pdata {
void __iomem *eth_diag_csr_addr;
void __iomem *mcx_mac_addr;
void __iomem *mcx_mac_csr_addr;
void __iomem *mcx_stats_addr;
void __iomem *base_addr;
void __iomem *pcs_addr;
void __iomem *ring_csr_addr;
......@@ -219,8 +224,12 @@ struct xgene_enet_pdata {
int phy_mode;
enum xgene_enet_rm rm;
struct xgene_enet_cle cle;
struct rtnl_link_stats64 stats;
u64 *extd_stats;
u64 false_rflr;
u64 vlan_rjbr;
spinlock_t stats_lock; /* statistics lock */
const struct xgene_mac_ops *mac_ops;
spinlock_t mac_lock; /* mac lock */
const struct xgene_port_ops *port_ops;
struct xgene_ring_ops *ring_ops;
const struct xgene_cle_ops *cle_ops;
......@@ -263,5 +272,6 @@ static inline u16 xgene_enet_dst_ring_num(struct xgene_enet_desc_ring *ring)
}
void xgene_enet_set_ethtool_ops(struct net_device *netdev);
int xgene_extd_stats_init(struct xgene_enet_pdata *pdata);
#endif /* __XGENE_ENET_MAIN_H__ */
......@@ -54,41 +54,6 @@ static void xgene_enet_wr_mcx_csr(struct xgene_enet_pdata *pdata,
iowrite32(val, addr);
}
static bool xgene_enet_wr_indirect(struct xgene_indirect_ctl *ctl,
u32 wr_addr, u32 wr_data)
{
int i;
iowrite32(wr_addr, ctl->addr);
iowrite32(wr_data, ctl->ctl);
iowrite32(XGENE_ENET_WR_CMD, ctl->cmd);
/* wait for write command to complete */
for (i = 0; i < 10; i++) {
if (ioread32(ctl->cmd_done)) {
iowrite32(0, ctl->cmd);
return true;
}
udelay(1);
}
return false;
}
static void xgene_enet_wr_mac(struct xgene_enet_pdata *p,
u32 wr_addr, u32 wr_data)
{
struct xgene_indirect_ctl ctl = {
.addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET,
.ctl = p->mcx_mac_addr + MAC_WRITE_REG_OFFSET,
.cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET,
.cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET
};
if (!xgene_enet_wr_indirect(&ctl, wr_addr, wr_data))
netdev_err(p->ndev, "mac write failed, addr: %04x\n", wr_addr);
}
static u32 xgene_enet_rd_csr(struct xgene_enet_pdata *p, u32 offset)
{
return ioread32(p->eth_csr_addr + offset);
......@@ -104,42 +69,6 @@ static u32 xgene_enet_rd_mcx_csr(struct xgene_enet_pdata *p, u32 offset)
return ioread32(p->mcx_mac_csr_addr + offset);
}
static u32 xgene_enet_rd_indirect(struct xgene_indirect_ctl *ctl, u32 rd_addr)
{
u32 rd_data;
int i;
iowrite32(rd_addr, ctl->addr);
iowrite32(XGENE_ENET_RD_CMD, ctl->cmd);
/* wait for read command to complete */
for (i = 0; i < 10; i++) {
if (ioread32(ctl->cmd_done)) {
rd_data = ioread32(ctl->ctl);
iowrite32(0, ctl->cmd);
return rd_data;
}
udelay(1);
}
pr_err("%s: mac read failed, addr: %04x\n", __func__, rd_addr);
return 0;
}
static u32 xgene_enet_rd_mac(struct xgene_enet_pdata *p, u32 rd_addr)
{
struct xgene_indirect_ctl ctl = {
.addr = p->mcx_mac_addr + MAC_ADDR_REG_OFFSET,
.ctl = p->mcx_mac_addr + MAC_READ_REG_OFFSET,
.cmd = p->mcx_mac_addr + MAC_COMMAND_REG_OFFSET,
.cmd_done = p->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET
};
return xgene_enet_rd_indirect(&ctl, rd_addr);
}
static int xgene_enet_ecc_init(struct xgene_enet_pdata *p)
{
struct net_device *ndev = p->ndev;
......@@ -166,6 +95,24 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *p)
return -ENODEV;
}
static void xgene_sgmac_get_drop_cnt(struct xgene_enet_pdata *pdata,
u32 *rx, u32 *tx)
{
u32 addr, count;
addr = (pdata->enet_id != XGENE_ENET1) ?
XG_MCX_ICM_ECM_DROP_COUNT_REG0_ADDR :
ICM_ECM_DROP_COUNT_REG0_ADDR + pdata->port_id * OFFSET_4;
count = xgene_enet_rd_mcx_csr(pdata, addr);
*rx = ICM_DROP_COUNT(count);
*tx = ECM_DROP_COUNT(count);
/* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */
addr = (pdata->enet_id != XGENE_ENET1) ?
XG_MCX_ECM_CONFIG0_REG_0_ADDR :
ECM_CONFIG0_REG_0_ADDR + pdata->port_id * OFFSET_4;
xgene_enet_rd_mcx_csr(pdata, addr);
}
static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *p)
{
u32 val;
......@@ -587,26 +534,6 @@ static void xgene_enet_clear(struct xgene_enet_pdata *pdata,
static void xgene_enet_shutdown(struct xgene_enet_pdata *p)
{
struct device *dev = &p->pdev->dev;
struct xgene_enet_desc_ring *ring;
u32 pb;
int i;
pb = 0;
for (i = 0; i < p->rxq_cnt; i++) {
ring = p->rx_ring[i]->buf_pool;
pb |= BIT(xgene_enet_get_fpsel(ring->id));
ring = p->rx_ring[i]->page_pool;
if (ring)
pb |= BIT(xgene_enet_get_fpsel(ring->id));
}
xgene_enet_wr_ring_if(p, ENET_CFGSSQMIFPRESET_ADDR, pb);
pb = 0;
for (i = 0; i < p->txq_cnt; i++) {
ring = p->tx_ring[i];
pb |= BIT(xgene_enet_ring_bufnum(ring->id));
}
xgene_enet_wr_ring_if(p, ENET_CFGSSQMIWQRESET_ADDR, pb);
if (dev->of_node) {
if (!IS_ERR(p->clk))
......@@ -671,6 +598,7 @@ const struct xgene_mac_ops xgene_sgmac_ops = {
.tx_enable = xgene_sgmac_tx_enable,
.rx_disable = xgene_sgmac_rx_disable,
.tx_disable = xgene_sgmac_tx_disable,
.get_drop_cnt = xgene_sgmac_get_drop_cnt,
.set_speed = xgene_sgmac_set_speed,
.set_mac_addr = xgene_sgmac_set_mac_addr,
.set_framesize = xgene_sgmac_set_frame_size,
......
......@@ -71,21 +71,6 @@ static bool xgene_enet_wr_indirect(void __iomem *addr, void __iomem *wr,
return true;
}
static void xgene_enet_wr_mac(struct xgene_enet_pdata *pdata,
u32 wr_addr, u32 wr_data)
{
void __iomem *addr, *wr, *cmd, *cmd_done;
addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
wr = pdata->mcx_mac_addr + MAC_WRITE_REG_OFFSET;
cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
if (!xgene_enet_wr_indirect(addr, wr, cmd, cmd_done, wr_addr, wr_data))
netdev_err(pdata->ndev, "MCX mac write failed, addr: %04x\n",
wr_addr);
}
static void xgene_enet_wr_pcs(struct xgene_enet_pdata *pdata,
u32 wr_addr, u32 wr_data)
{
......@@ -148,21 +133,6 @@ static bool xgene_enet_rd_indirect(void __iomem *addr, void __iomem *rd,
return true;
}
static void xgene_enet_rd_mac(struct xgene_enet_pdata *pdata,
u32 rd_addr, u32 *rd_data)
{
void __iomem *addr, *rd, *cmd, *cmd_done;
addr = pdata->mcx_mac_addr + MAC_ADDR_REG_OFFSET;
rd = pdata->mcx_mac_addr + MAC_READ_REG_OFFSET;
cmd = pdata->mcx_mac_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = pdata->mcx_mac_addr + MAC_COMMAND_DONE_REG_OFFSET;
if (!xgene_enet_rd_indirect(addr, rd, cmd, cmd_done, rd_addr, rd_data))
netdev_err(pdata->ndev, "MCX mac read failed, addr: %04x\n",
rd_addr);
}
static bool xgene_enet_rd_pcs(struct xgene_enet_pdata *pdata,
u32 rd_addr, u32 *rd_data)
{
......@@ -210,6 +180,18 @@ static int xgene_enet_ecc_init(struct xgene_enet_pdata *pdata)
return 0;
}
static void xgene_xgmac_get_drop_cnt(struct xgene_enet_pdata *pdata,
u32 *rx, u32 *tx)
{
u32 count;
xgene_enet_rd_axg_csr(pdata, XGENET_ICM_ECM_DROP_COUNT_REG0, &count);
*rx = ICM_DROP_COUNT(count);
*tx = ECM_DROP_COUNT(count);
/* Errata: 10GE_4 - ICM_ECM_DROP_COUNT not clear-on-read */
xgene_enet_rd_axg_csr(pdata, XGENET_ECM_CONFIG0_REG_0, &count);
}
static void xgene_enet_config_ring_if_assoc(struct xgene_enet_pdata *pdata)
{
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQASSOC_ADDR, 0);
......@@ -300,7 +282,7 @@ static void xgene_xgmac_flowctl_tx(struct xgene_enet_pdata *pdata, bool enable)
{
u32 data;
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
if (enable)
data |= HSTTCTLEN;
......@@ -316,7 +298,7 @@ static void xgene_xgmac_flowctl_rx(struct xgene_enet_pdata *pdata, bool enable)
{
u32 data;
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
if (enable)
data |= HSTRCTLEN;
......@@ -332,7 +314,7 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata)
xgene_xgmac_reset(pdata);
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
data |= HSTPPEN;
data &= ~HSTLENCHK;
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data);
......@@ -379,7 +361,7 @@ static void xgene_xgmac_rx_enable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTRFEN);
}
......@@ -387,7 +369,7 @@ static void xgene_xgmac_tx_enable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data | HSTTFEN);
}
......@@ -395,7 +377,7 @@ static void xgene_xgmac_rx_disable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTRFEN);
}
......@@ -403,7 +385,7 @@ static void xgene_xgmac_tx_disable(struct xgene_enet_pdata *pdata)
{
u32 data;
xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1, &data);
data = xgene_enet_rd_mac(pdata, AXGMAC_CONFIG_1);
xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data & ~HSTTFEN);
}
......@@ -464,26 +446,6 @@ static void xgene_enet_xgcle_bypass(struct xgene_enet_pdata *pdata,
static void xgene_enet_shutdown(struct xgene_enet_pdata *pdata)
{
struct device *dev = &pdata->pdev->dev;
struct xgene_enet_desc_ring *ring;
u32 pb;
int i;
pb = 0;
for (i = 0; i < pdata->rxq_cnt; i++) {
ring = pdata->rx_ring[i]->buf_pool;
pb |= BIT(xgene_enet_get_fpsel(ring->id));
ring = pdata->rx_ring[i]->page_pool;
if (ring)
pb |= BIT(xgene_enet_get_fpsel(ring->id));
}
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIFPRESET_ADDR, pb);
pb = 0;
for (i = 0; i < pdata->txq_cnt; i++) {
ring = pdata->tx_ring[i];
pb |= BIT(xgene_enet_ring_bufnum(ring->id));
}
xgene_enet_wr_ring_if(pdata, ENET_CFGSSQMIWQRESET_ADDR, pb);
if (dev->of_node) {
if (!IS_ERR(pdata->clk))
......@@ -567,6 +529,7 @@ const struct xgene_mac_ops xgene_xgmac_ops = {
.set_mac_addr = xgene_xgmac_set_mac_addr,
.set_framesize = xgene_xgmac_set_frame_size,
.set_mss = xgene_xgmac_set_mss,
.get_drop_cnt = xgene_xgmac_get_drop_cnt,
.link_state = xgene_enet_link_state,
.enable_tx_pause = xgene_xgmac_enable_tx_pause,
.flowctl_rx = xgene_xgmac_flowctl_rx,
......
......@@ -23,6 +23,7 @@
#define X2_BLOCK_ETH_MAC_CSR_OFFSET 0x3000
#define BLOCK_AXG_MAC_OFFSET 0x0800
#define BLOCK_AXG_STATS_OFFSET 0x0800
#define BLOCK_AXG_MAC_CSR_OFFSET 0x2000
#define BLOCK_PCS_OFFSET 0x3800
......@@ -70,6 +71,8 @@
#define XG_RSIF_CONFIG1_REG_ADDR 0x00b8
#define XG_RSIF_PLC_CLE_BUFF_THRESH 0x1
#define RSIF_PLC_CLE_BUFF_THRESH_SET(dst, val) xgene_set_bits(dst, val, 0, 2)
#define XG_MCX_ECM_CONFIG0_REG_0_ADDR 0x0070
#define XG_MCX_ICM_ECM_DROP_COUNT_REG0_ADDR 0x0124
#define XCLE_BYPASS_REG0_ADDR 0x0160
#define XCLE_BYPASS_REG1_ADDR 0x0164
#define XG_CFG_BYPASS_ADDR 0x0204
......@@ -80,6 +83,8 @@
#define XG_ENET_SPARE_CFG_REG_ADDR 0x040c
#define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410
#define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804
#define XGENET_ECM_CONFIG0_REG_0 0x0870
#define XGENET_ICM_ECM_DROP_COUNT_REG0 0x0924
#define XGENET_CSR_ECM_CFG_0_ADDR 0x0880
#define XGENET_CSR_MULTI_DPF0_ADDR 0x0888
#define XGENET_CSR_MULTI_DPF1_ADDR 0x088c
......
......@@ -34,76 +34,73 @@
static bool xgene_mdio_status;
static u32 xgene_enet_rd_mac(void __iomem *base_addr, u32 rd_addr)
u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr)
{
void __iomem *addr, *rd, *cmd, *cmd_done;
u32 done, rd_data = BUSY_MASK;
u8 wait = 10;
addr = base_addr + MAC_ADDR_REG_OFFSET;
rd = base_addr + MAC_READ_REG_OFFSET;
cmd = base_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET;
addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET;
rd = pdata->mac_csr_addr + MAC_READ_REG_OFFSET;
cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET;
spin_lock(&pdata->mac_lock);
iowrite32(rd_addr, addr);
iowrite32(XGENE_ENET_RD_CMD, cmd);
while (wait--) {
done = ioread32(cmd_done);
if (done)
break;
while (!(done = ioread32(cmd_done)) && wait--)
udelay(1);
}
if (!done)
return rd_data;
if (done)
rd_data = ioread32(rd);
rd_data = ioread32(rd);
iowrite32(0, cmd);
spin_unlock(&pdata->mac_lock);
return rd_data;
}
EXPORT_SYMBOL(xgene_mdio_rd_mac);
static void xgene_enet_wr_mac(void __iomem *base_addr, u32 wr_addr, u32 wr_data)
void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data)
{
void __iomem *addr, *wr, *cmd, *cmd_done;
u8 wait = 10;
u32 done;
addr = base_addr + MAC_ADDR_REG_OFFSET;
wr = base_addr + MAC_WRITE_REG_OFFSET;
cmd = base_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = base_addr + MAC_COMMAND_DONE_REG_OFFSET;
addr = pdata->mac_csr_addr + MAC_ADDR_REG_OFFSET;
wr = pdata->mac_csr_addr + MAC_WRITE_REG_OFFSET;
cmd = pdata->mac_csr_addr + MAC_COMMAND_REG_OFFSET;
cmd_done = pdata->mac_csr_addr + MAC_COMMAND_DONE_REG_OFFSET;
spin_lock(&pdata->mac_lock);
iowrite32(wr_addr, addr);
iowrite32(wr_data, wr);
iowrite32(data, wr);
iowrite32(XGENE_ENET_WR_CMD, cmd);
while (wait--) {
done = ioread32(cmd_done);
if (done)
break;
while (!(done = ioread32(cmd_done)) && wait--)
udelay(1);
}
if (!done)
pr_err("MCX mac write failed, addr: 0x%04x\n", wr_addr);
iowrite32(0, cmd);
spin_unlock(&pdata->mac_lock);
}
EXPORT_SYMBOL(xgene_mdio_wr_mac);
int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg)
{
void __iomem *addr = (void __iomem *)bus->priv;
struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv;
u32 data, done;
u8 wait = 10;
data = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg);
xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, data);
xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK);
xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, data);
xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, READ_CYCLE_MASK);
do {
usleep_range(5, 10);
done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR);
done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR);
} while ((done & BUSY_MASK) && wait--);
if (done & BUSY_MASK) {
......@@ -111,8 +108,8 @@ int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg)
return -EBUSY;
}
data = xgene_enet_rd_mac(addr, MII_MGMT_STATUS_ADDR);
xgene_enet_wr_mac(addr, MII_MGMT_COMMAND_ADDR, 0);
data = xgene_mdio_rd_mac(pdata, MII_MGMT_STATUS_ADDR);
xgene_mdio_wr_mac(pdata, MII_MGMT_COMMAND_ADDR, 0);
return data;
}
......@@ -120,17 +117,17 @@ EXPORT_SYMBOL(xgene_mdio_rgmii_read);
int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data)
{
void __iomem *addr = (void __iomem *)bus->priv;
struct xgene_mdio_pdata *pdata = (struct xgene_mdio_pdata *)bus->priv;
u32 val, done;
u8 wait = 10;
val = SET_VAL(PHY_ADDR, phy_id) | SET_VAL(REG_ADDR, reg);
xgene_enet_wr_mac(addr, MII_MGMT_ADDRESS_ADDR, val);
xgene_mdio_wr_mac(pdata, MII_MGMT_ADDRESS_ADDR, val);
xgene_enet_wr_mac(addr, MII_MGMT_CONTROL_ADDR, data);
xgene_mdio_wr_mac(pdata, MII_MGMT_CONTROL_ADDR, data);
do {
usleep_range(5, 10);
done = xgene_enet_rd_mac(addr, MII_MGMT_INDICATORS_ADDR);
done = xgene_mdio_rd_mac(pdata, MII_MGMT_INDICATORS_ADDR);
} while ((done & BUSY_MASK) && wait--);
if (done & BUSY_MASK) {
......@@ -174,8 +171,8 @@ static int xgene_enet_ecc_init(struct xgene_mdio_pdata *pdata)
static void xgene_gmac_reset(struct xgene_mdio_pdata *pdata)
{
xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, SOFT_RESET);
xgene_enet_wr_mac(pdata->mac_csr_addr, MAC_CONFIG_1_ADDR, 0);
xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, SOFT_RESET);
xgene_mdio_wr_mac(pdata, MAC_CONFIG_1_ADDR, 0);
}
static int xgene_mdio_reset(struct xgene_mdio_pdata *pdata)
......@@ -375,6 +372,9 @@ static int xgene_mdio_probe(struct platform_device *pdev)
pdata->mdio_csr_addr = csr_base + BLOCK_XG_MDIO_CSR_OFFSET;
pdata->diag_csr_addr = csr_base + BLOCK_DIAG_CSR_OFFSET;
if (mdio_id == XGENE_MDIO_RGMII)
spin_lock_init(&pdata->mac_lock);
if (dev->of_node) {
pdata->clk = devm_clk_get(dev, NULL);
if (IS_ERR(pdata->clk)) {
......@@ -396,7 +396,7 @@ static int xgene_mdio_probe(struct platform_device *pdev)
if (mdio_id == XGENE_MDIO_RGMII) {
mdio_bus->read = xgene_mdio_rgmii_read;
mdio_bus->write = xgene_mdio_rgmii_write;
mdio_bus->priv = (void __force *)pdata->mac_csr_addr;
mdio_bus->priv = (void __force *)pdata;
snprintf(mdio_bus->id, MII_BUS_ID_SIZE, "%s",
"xgene-mii-rgmii");
} else {
......
......@@ -102,6 +102,7 @@ struct xgene_mdio_pdata {
void __iomem *mdio_csr_addr;
struct mii_bus *mdio_bus;
int mdio_id;
spinlock_t mac_lock; /* mac lock */
};
/* Set the specified value into a bit-field defined by its starting position
......@@ -132,6 +133,8 @@ static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src)
#define GET_BIT(field, src) \
xgene_enet_get_field_value(field ## _POS, 1, src)
u32 xgene_mdio_rd_mac(struct xgene_mdio_pdata *pdata, u32 rd_addr);
void xgene_mdio_wr_mac(struct xgene_mdio_pdata *pdata, u32 wr_addr, u32 data);
int xgene_mdio_rgmii_read(struct mii_bus *bus, int phy_id, int reg);
int xgene_mdio_rgmii_write(struct mii_bus *bus, int phy_id, int reg, u16 data);
struct phy_device *xgene_enet_phy_register(struct mii_bus *bus, int phy_addr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment