diff options
author | David S. Miller <davem@davemloft.net> | 2021-08-19 12:05:29 +0100 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2021-08-19 12:05:29 +0100 |
commit | a27919433b44c8ab657e6ed214dad4ed9a66b8fa (patch) | |
tree | be3691fa2592b7dbe2704971cca0a11c63d4283b | |
parent | 19b8ece42c56aaa122f7e91eb391bb3dd7e193cd (diff) | |
parent | 0b81d67311676c9119ed3b027d1518e974dbca8e (diff) |
Merge branch 'ravb-gbit'
Biju Das says:
====================
ravb: Add Gigabit Ethernet driver support
The DMAC and EMAC blocks of Gigabit Ethernet IP found on RZ/G2L SoC are
similar to the R-Car Ethernet AVB IP.
The Gigabit Ethernet IP consists of Ethernet controller (E-MAC), Internal
TCP/IP Offload Engine (TOE) and Dedicated Direct memory access controller
(DMAC).
With a few changes in the driver we can support both IPs.
Currently a runtime decision based on the chip type is used to distinguish
the HW differences between the SoC families.
This patch series is in preparation for supporting the RZ/G2L SoC by
replacing driver data chip type with struct ravb_hw_info by moving chip
type to it and also adding gstrings_stats, gstrings_size, net_hw_features,
net_features, aligned_tx, stats_len, max_rx_len variables to
it. This patch also adds the feature bit for {RX, TX} clock internal
delays and TX counters HW features found on R-Car Gen3 to struct
ravb_hw_info.
This patch series is based on net-next.
v2->v3:
* Removed num_gstat_queue variable from struct ravb_hw_info.
* started using unsigned int for num_tx_desc variable in struct ravb_private
* split the patch 'Add struct ravb_hw_info to driver data' into two
* Renamed skb_sz to max_rx_len and tx_drop_cntrs to tx_counters
and also updated the comments.
v1->v2:
* Replaced driver data chip type with struct ravb_hw_info
* Added gstrings_stats, gstrings_size, net_hw_features, net_features,
num_gstat_queue, num_tx_desc, stats_len, skb_sz to struct ravb_hw_info
* Added internal_delay and tx_drop_cntrs hw feature bit to struct ravb_hw_info
RFC->V1
* Incorporated feedback from Andrew, Sergei, Geert and Prabhakar
* https://patchwork.kernel.org/project/linux-renesas-soc/list/?series=515525
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/net/ethernet/renesas/ravb.h | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/renesas/ravb_main.c | 112 |
2 files changed, 89 insertions, 42 deletions
diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 80e62ca2e3d3..37ad0f8aaf3c 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -988,6 +988,21 @@ enum ravb_chip_id { RCAR_GEN3, }; +struct ravb_hw_info { + const char (*gstrings_stats)[ETH_GSTRING_LEN]; + size_t gstrings_size; + netdev_features_t net_hw_features; + netdev_features_t net_features; + enum ravb_chip_id chip_id; + int stats_len; + size_t max_rx_len; + unsigned aligned_tx: 1; + + /* hardware features */ + unsigned internal_delay:1; /* AVB-DMAC has internal delays */ + unsigned tx_counters:1; /* E-MAC has TX counters */ +}; + struct ravb_private { struct net_device *ndev; struct platform_device *pdev; @@ -1039,7 +1054,9 @@ struct ravb_private { unsigned rxcidm:1; /* RX Clock Internal Delay Mode */ unsigned txcidm:1; /* TX Clock Internal Delay Mode */ unsigned rgmii_override:1; /* Deprecated rgmii-*id behavior */ - int num_tx_desc; /* TX descriptors per packet */ + unsigned int num_tx_desc; /* TX descriptors per packet */ + + const struct ravb_hw_info *info; }; static inline u32 ravb_read(struct net_device *ndev, enum ravb_reg reg) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 62b0605f02ff..02842b980a7f 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -177,10 +177,10 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) { struct ravb_private *priv = netdev_priv(ndev); struct net_device_stats *stats = &priv->stats[q]; - int num_tx_desc = priv->num_tx_desc; + unsigned int num_tx_desc = priv->num_tx_desc; struct ravb_tx_desc *desc; + unsigned int entry; int free_num = 0; - int entry; u32 size; for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { @@ -220,9 +220,9 @@ static int ravb_tx_free(struct net_device *ndev, int q, bool free_txed_only) static void ravb_ring_free(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - int num_tx_desc = priv->num_tx_desc; - int ring_size; - int i; + unsigned int num_tx_desc = priv->num_tx_desc; + unsigned int ring_size; + unsigned int i; if (priv->rx_ring[q]) { for (i = 0; i < priv->num_rx_ring[q]; i++) { @@ -275,15 +275,15 @@ static void ravb_ring_free(struct net_device *ndev, int q) static void ravb_ring_format(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - int num_tx_desc = priv->num_tx_desc; + unsigned int num_tx_desc = priv->num_tx_desc; struct ravb_ex_rx_desc *rx_desc; struct ravb_tx_desc *tx_desc; struct ravb_desc *desc; - int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; - int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] * - num_tx_desc; + unsigned int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; + unsigned int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] * + num_tx_desc; dma_addr_t dma_addr; - int i; + unsigned int i; priv->cur_rx[q] = 0; priv->cur_tx[q] = 0; @@ -339,10 +339,11 @@ static void ravb_ring_format(struct net_device *ndev, int q) static int ravb_ring_init(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - int num_tx_desc = priv->num_tx_desc; + const struct ravb_hw_info *info = priv->info; + unsigned int num_tx_desc = priv->num_tx_desc; + unsigned int ring_size; struct sk_buff *skb; - int ring_size; - int i; + unsigned int i; /* Allocate RX and TX skb rings */ priv->rx_skb[q] = kcalloc(priv->num_rx_ring[q], @@ -353,7 +354,7 @@ static int ravb_ring_init(struct net_device *ndev, int q) goto error; for (i = 0; i < priv->num_rx_ring[q]; i++) { - skb = netdev_alloc_skb(ndev, RX_BUF_SZ + RAVB_ALIGN - 1); + skb = netdev_alloc_skb(ndev, info->max_rx_len); if (!skb) goto error; ravb_set_buffer_align(skb); @@ -535,6 +536,7 @@ static void ravb_rx_csum(struct sk_buff *skb) static bool ravb_rx(struct net_device *ndev, int *quota, int q) { struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; int entry = priv->cur_rx[q] % priv->num_rx_ring[q]; int boguscnt = (priv->dirty_rx[q] + priv->num_rx_ring[q]) - priv->cur_rx[q]; @@ -619,9 +621,7 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q) desc->ds_cc = cpu_to_le16(RX_BUF_SZ); if (!priv->rx_skb[q][entry]) { - skb = netdev_alloc_skb(ndev, - RX_BUF_SZ + - RAVB_ALIGN - 1); + skb = netdev_alloc_skb(ndev, info->max_rx_len); if (!skb) break; /* Better luck next round. */ ravb_set_buffer_align(skb); @@ -1133,13 +1133,14 @@ static const char ravb_gstrings_stats[][ETH_GSTRING_LEN] = { "rx_queue_1_over_errors", }; -#define RAVB_STATS_LEN ARRAY_SIZE(ravb_gstrings_stats) - static int ravb_get_sset_count(struct net_device *netdev, int sset) { + struct ravb_private *priv = netdev_priv(netdev); + const struct ravb_hw_info *info = priv->info; + switch (sset) { case ETH_SS_STATS: - return RAVB_STATS_LEN; + return info->stats_len; default: return -EOPNOTSUPP; } @@ -1176,9 +1177,12 @@ static void ravb_get_ethtool_stats(struct net_device *ndev, static void ravb_get_strings(struct net_device *ndev, u32 stringset, u8 *data) { + struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; + switch (stringset) { case ETH_SS_STATS: - memcpy(data, ravb_gstrings_stats, sizeof(ravb_gstrings_stats)); + memcpy(data, info->gstrings_stats, info->gstrings_size); break; } } @@ -1488,7 +1492,7 @@ out: static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); - int num_tx_desc = priv->num_tx_desc; + unsigned int num_tx_desc = priv->num_tx_desc; u16 q = skb_get_queue_mapping(skb); struct ravb_tstamp_skb *ts_skb; struct ravb_tx_desc *desc; @@ -1628,13 +1632,14 @@ static u16 ravb_select_queue(struct net_device *ndev, struct sk_buff *skb, static struct net_device_stats *ravb_get_stats(struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; struct net_device_stats *nstats, *stats0, *stats1; nstats = &ndev->stats; stats0 = &priv->stats[RAVB_BE]; stats1 = &priv->stats[RAVB_NC]; - if (priv->chip_id == RCAR_GEN3) { + if (info->tx_counters) { nstats->tx_dropped += ravb_read(ndev, TROCR); ravb_write(ndev, 0, TROCR); /* (write clear) */ } @@ -1924,12 +1929,35 @@ static int ravb_mdio_release(struct ravb_private *priv) return 0; } +static const struct ravb_hw_info ravb_gen3_hw_info = { + .gstrings_stats = ravb_gstrings_stats, + .gstrings_size = sizeof(ravb_gstrings_stats), + .net_hw_features = NETIF_F_RXCSUM, + .net_features = NETIF_F_RXCSUM, + .chip_id = RCAR_GEN3, + .stats_len = ARRAY_SIZE(ravb_gstrings_stats), + .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, + .internal_delay = 1, + .tx_counters = 1, +}; + +static const struct ravb_hw_info ravb_gen2_hw_info = { + .gstrings_stats = ravb_gstrings_stats, + .gstrings_size = sizeof(ravb_gstrings_stats), + .net_hw_features = NETIF_F_RXCSUM, + .net_features = NETIF_F_RXCSUM, + .chip_id = RCAR_GEN2, + .stats_len = ARRAY_SIZE(ravb_gstrings_stats), + .max_rx_len = RX_BUF_SZ + RAVB_ALIGN - 1, + .aligned_tx = 1, +}; + static const struct of_device_id ravb_match_table[] = { - { .compatible = "renesas,etheravb-r8a7790", .data = (void *)RCAR_GEN2 }, - { .compatible = "renesas,etheravb-r8a7794", .data = (void *)RCAR_GEN2 }, - { .compatible = "renesas,etheravb-rcar-gen2", .data = (void *)RCAR_GEN2 }, - { .compatible = "renesas,etheravb-r8a7795", .data = (void *)RCAR_GEN3 }, - { .compatible = "renesas,etheravb-rcar-gen3", .data = (void *)RCAR_GEN3 }, + { .compatible = "renesas,etheravb-r8a7790", .data = &ravb_gen2_hw_info }, + { .compatible = "renesas,etheravb-r8a7794", .data = &ravb_gen2_hw_info }, + { .compatible = "renesas,etheravb-rcar-gen2", .data = &ravb_gen2_hw_info }, + { .compatible = "renesas,etheravb-r8a7795", .data = &ravb_gen3_hw_info }, + { .compatible = "renesas,etheravb-rcar-gen3", .data = &ravb_gen3_hw_info }, { } }; MODULE_DEVICE_TABLE(of, ravb_match_table); @@ -2023,8 +2051,8 @@ static void ravb_set_delay_mode(struct net_device *ndev) static int ravb_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + const struct ravb_hw_info *info; struct ravb_private *priv; - enum ravb_chip_id chip_id; struct net_device *ndev; int error, irq, q; struct resource *res; @@ -2041,15 +2069,15 @@ static int ravb_probe(struct platform_device *pdev) if (!ndev) return -ENOMEM; - ndev->features = NETIF_F_RXCSUM; - ndev->hw_features = NETIF_F_RXCSUM; + info = of_device_get_match_data(&pdev->dev); + + ndev->features = info->net_features; + ndev->hw_features = info->net_hw_features; pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - chip_id = (enum ravb_chip_id)of_device_get_match_data(&pdev->dev); - - if (chip_id == RCAR_GEN3) + if (info->chip_id == RCAR_GEN3) irq = platform_get_irq_byname(pdev, "ch22"); else irq = platform_get_irq(pdev, 0); @@ -2062,6 +2090,7 @@ static int ravb_probe(struct platform_device *pdev) SET_NETDEV_DEV(ndev, &pdev->dev); priv = netdev_priv(ndev); + priv->info = info; priv->ndev = ndev; priv->pdev = pdev; priv->num_tx_ring[RAVB_BE] = BE_TX_RING_SIZE; @@ -2088,7 +2117,7 @@ static int ravb_probe(struct platform_device *pdev) priv->avb_link_active_low = of_property_read_bool(np, "renesas,ether-link-active-low"); - if (chip_id == RCAR_GEN3) { + if (info->chip_id == RCAR_GEN3) { irq = platform_get_irq_byname(pdev, "ch24"); if (irq < 0) { error = irq; @@ -2113,7 +2142,7 @@ static int ravb_probe(struct platform_device *pdev) } } - priv->chip_id = chip_id; + priv->chip_id = info->chip_id; priv->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { @@ -2131,7 +2160,7 @@ static int ravb_probe(struct platform_device *pdev) ndev->max_mtu = 2048 - (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN); ndev->min_mtu = ETH_MIN_MTU; - priv->num_tx_desc = chip_id == RCAR_GEN2 ? + priv->num_tx_desc = info->aligned_tx ? NUM_TX_DESC_GEN2 : NUM_TX_DESC_GEN3; /* Set function */ @@ -2149,7 +2178,7 @@ static int ravb_probe(struct platform_device *pdev) /* Request GTI loading */ ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); - if (priv->chip_id != RCAR_GEN2) { + if (info->internal_delay) { ravb_parse_delay_mode(np, ndev); ravb_set_delay_mode(ndev); } @@ -2173,7 +2202,7 @@ static int ravb_probe(struct platform_device *pdev) INIT_LIST_HEAD(&priv->ts_skb_list); /* Initialise PTP Clock driver */ - if (chip_id != RCAR_GEN2) + if (info->chip_id != RCAR_GEN2) ravb_ptp_init(ndev, pdev); /* Debug message level */ @@ -2221,7 +2250,7 @@ out_dma_free: priv->desc_bat_dma); /* Stop PTP Clock driver */ - if (chip_id != RCAR_GEN2) + if (info->chip_id != RCAR_GEN2) ravb_ptp_stop(ndev); out_disable_refclk: clk_disable_unprepare(priv->refclk); @@ -2322,6 +2351,7 @@ static int __maybe_unused ravb_resume(struct device *dev) { struct net_device *ndev = dev_get_drvdata(dev); struct ravb_private *priv = netdev_priv(ndev); + const struct ravb_hw_info *info = priv->info; int ret = 0; /* If WoL is enabled set reset mode to rearm the WoL logic */ @@ -2344,7 +2374,7 @@ static int __maybe_unused ravb_resume(struct device *dev) /* Request GTI loading */ ravb_modify(ndev, GCCR, GCCR_LTI, GCCR_LTI); - if (priv->chip_id != RCAR_GEN2) + if (info->internal_delay) ravb_set_delay_mode(ndev); /* Restore descriptor base address table */ |