From patchwork Fri Jul 9 19:08:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503319 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2kq4czxz9sRR; Sat, 10 Jul 2021 05:08:51 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrk-000382-6g; Fri, 09 Jul 2021 19:08:48 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrh-00037Q-Tw for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:46 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:42 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8fJO030183; Fri, 9 Jul 2021 15:08:41 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8fxS005454; Fri, 9 Jul 2021 15:08:41 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 01/23] Revert "UBUNTU: SAUCE: mlxbf_gige: syncup with v1.23 content" Date: Fri, 9 Jul 2021 15:08:08 -0400 Message-Id: <20210709190830.5405-2-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 119e2a48b345d600b896a5125b1c1f74c308c052. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 2 - .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 27 ++++------- .../mellanox/mlxbf_gige/mlxbf_gige_rx.c | 45 ++++++------------- .../mellanox/mlxbf_gige/mlxbf_gige_tx.c | 20 ++++----- 4 files changed, 30 insertions(+), 64 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index 2c049bf114b1..1c59cad682c7 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -105,7 +105,6 @@ struct mlxbf_gige { int llu_plu_irq; int phy_irq; bool promisc_enabled; - u8 valid_polarity; struct napi_struct napi; struct mlxbf_gige_stats stats; u32 tx_pause; @@ -172,7 +171,6 @@ bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv); netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, struct net_device *netdev); struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, - unsigned int map_len, dma_addr_t *buf_dma, enum dma_data_direction dir); int mlxbf_gige_request_irqs(struct mlxbf_gige *priv); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index a17a346baf98..2513c3547ea0 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -21,7 +21,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION 1.23 +#define DRV_VERSION 1.21 /* This setting defines the version of the ACPI table * content that is compatible with this driver version. @@ -36,7 +36,6 @@ * naturally aligned to a 2KB boundary. */ struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, - unsigned int map_len, dma_addr_t *buf_dma, enum dma_data_direction dir) { @@ -61,7 +60,8 @@ struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, skb_reserve(skb, offset); /* Return streaming DMA mapping to caller */ - *buf_dma = dma_map_single(priv->dev, skb->data, map_len, dir); + *buf_dma = dma_map_single(priv->dev, skb->data, + MLXBF_GIGE_DEFAULT_BUF_SZ, dir); if (dma_mapping_error(priv->dev, *buf_dma)) { dev_kfree_skb(skb); *buf_dma = (dma_addr_t)0; @@ -120,9 +120,6 @@ static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; writeq(control, priv->base + MLXBF_GIGE_CONTROL); - /* Ensure completion of "clean port" write before polling status */ - mb(); - err = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp, (temp & MLXBF_GIGE_STATUS_READY), 100, 100000); @@ -148,13 +145,13 @@ static int mlxbf_gige_open(struct net_device *netdev) mlxbf_gige_cache_stats(priv); err = mlxbf_gige_clean_port(priv); if (err) - goto free_irqs; + return err; err = mlxbf_gige_rx_init(priv); if (err) - goto free_irqs; + return err; err = mlxbf_gige_tx_init(priv); if (err) - goto rx_deinit; + return err; phy_start(phydev); @@ -170,17 +167,9 @@ static int mlxbf_gige_open(struct net_device *netdev) MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR | MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR | MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET; - mb(); writeq(int_en, priv->base + MLXBF_GIGE_INT_EN); return 0; - -rx_deinit: - mlxbf_gige_rx_deinit(priv); - -free_irqs: - mlxbf_gige_free_irqs(priv); - return err; } static int mlxbf_gige_stop(struct net_device *netdev) @@ -229,8 +218,8 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) mlxbf_gige_enable_promisc(priv); else mlxbf_gige_disable_promisc(priv); + } } -} static void mlxbf_gige_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) @@ -241,7 +230,7 @@ static void mlxbf_gige_get_stats64(struct net_device *netdev, stats->rx_length_errors = priv->stats.rx_truncate_errors; stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts + - readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); + readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); stats->rx_crc_errors = priv->stats.rx_mac_errors; stats->rx_errors = stats->rx_length_errors + stats->rx_fifo_errors + diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c index 12cb5beb29f9..9e4c507497a1 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c @@ -103,8 +103,7 @@ int mlxbf_gige_rx_init(struct mlxbf_gige *priv) rx_wqe_ptr = priv->rx_wqe_base; for (i = 0; i < priv->rx_q_entries; i++) { - priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, - &rx_buf_dma, DMA_FROM_DEVICE); + priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, DMA_FROM_DEVICE); if (!priv->rx_skb[i]) goto free_wqe_and_skb; *rx_wqe_ptr++ = rx_buf_dma; @@ -120,9 +119,6 @@ int mlxbf_gige_rx_init(struct mlxbf_gige *priv) if (!priv->rx_cqe_base) goto free_wqe_and_skb; - for (i = 0; i < priv->rx_q_entries; i++) - priv->rx_cqe_base[i] |= MLXBF_GIGE_RX_CQE_VALID_MASK; - /* Write RX CQE base address into MMIO reg */ writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); @@ -148,9 +144,7 @@ int mlxbf_gige_rx_init(struct mlxbf_gige *priv) writeq(data, priv->base + MLXBF_GIGE_INT_MASK); /* Enable RX DMA to write new packets to memory */ - data = readq(priv->base + MLXBF_GIGE_RX_DMA); - data |= MLXBF_GIGE_RX_DMA_EN; - writeq(data, priv->base + MLXBF_GIGE_RX_DMA); + writeq(MLXBF_GIGE_RX_DMA_EN, priv->base + MLXBF_GIGE_RX_DMA); writeq(ilog2(priv->rx_q_entries), priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); @@ -178,14 +172,8 @@ void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) { dma_addr_t *rx_wqe_ptr; size_t size; - u64 data; int i; - /* Disable RX DMA to prevent packet transfers to memory */ - data = readq(priv->base + MLXBF_GIGE_RX_DMA); - data &= ~MLXBF_GIGE_RX_DMA_EN; - writeq(data, priv->base + MLXBF_GIGE_RX_DMA); - rx_wqe_ptr = priv->rx_wqe_base; for (i = 0; i < priv->rx_q_entries; i++) { @@ -214,10 +202,10 @@ void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) { struct net_device *netdev = priv->netdev; - struct sk_buff *skb = NULL, *rx_skb; u16 rx_pi_rem, rx_ci_rem; dma_addr_t *rx_wqe_addr; dma_addr_t rx_buf_dma; + struct sk_buff *skb; u64 *rx_cqe_addr; u64 datalen; u64 rx_cqe; @@ -227,14 +215,14 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); rx_pi_rem = rx_pi % priv->rx_q_entries; - rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem; + + dma_unmap_single(priv->dev, *rx_wqe_addr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; rx_cqe = *rx_cqe_addr; - if ((!!(rx_cqe & MLXBF_GIGE_RX_CQE_VALID_MASK)) != priv->valid_polarity) - return false; - if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { /* Packet is OK, increment stats */ datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; @@ -248,15 +236,16 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ skb->protocol = eth_type_trans(skb, netdev); + netif_receive_skb(skb); /* Alloc another RX SKB for this same index */ - rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, - &rx_buf_dma, DMA_FROM_DEVICE); - if (!rx_skb) + priv->rx_skb[rx_pi_rem] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, + DMA_FROM_DEVICE); + if (!priv->rx_skb[rx_pi_rem]) { + netdev->stats.rx_dropped++; return false; - priv->rx_skb[rx_pi_rem] = rx_skb; - dma_unmap_single(priv->dev, *rx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + } + *rx_wqe_addr = rx_buf_dma; } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { priv->stats.rx_mac_errors++; @@ -266,20 +255,14 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) /* Let hardware know we've replenished one buffer */ rx_pi++; - wmb(); writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); (*rx_pkts)++; rx_pi_rem = rx_pi % priv->rx_q_entries; - if (rx_pi_rem == 0) - priv->valid_polarity ^= 1; rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); rx_ci_rem = rx_ci % priv->rx_q_entries; - if (skb) - netif_receive_skb(skb); - return rx_pi_rem != rx_ci_rem; } diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c index 4efa5eff5a98..0c35b2f2dfcd 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c @@ -66,7 +66,7 @@ void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) for (i = 0; i < priv->tx_q_entries; i++) { if (priv->tx_skb[i]) { dma_unmap_single(priv->dev, *tx_wqe_addr, - priv->tx_skb[i]->len, DMA_TO_DEVICE); + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); dev_kfree_skb(priv->tx_skb[i]); priv->tx_skb[i] = NULL; } @@ -156,11 +156,9 @@ bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); dma_unmap_single(priv->dev, *tx_wqe_addr, - priv->tx_skb[tx_wqe_index]->len, DMA_TO_DEVICE); + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); dev_consume_skb_any(priv->tx_skb[tx_wqe_index]); priv->tx_skb[tx_wqe_index] = NULL; - - mb(); } /* Since the TX ring was likely just drained, check if TX queue @@ -194,12 +192,11 @@ netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, long buff_addr, start_dma_page, end_dma_page; struct sk_buff *tx_skb; dma_addr_t tx_buf_dma; - unsigned long flags; u64 *tx_wqe_addr; u64 word2; /* If needed, linearize TX SKB as hardware DMA expects this */ - if ((skb->len > MLXBF_GIGE_DEFAULT_BUF_SZ) || skb_linearize(skb)) { + if (skb_linearize(skb)) { dev_kfree_skb(skb); netdev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -214,8 +211,7 @@ netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, */ if (start_dma_page != end_dma_page) { /* DMA operation would fail as-is, alloc new aligned SKB */ - tx_skb = mlxbf_gige_alloc_skb(priv, skb->len, - &tx_buf_dma, DMA_TO_DEVICE); + tx_skb = mlxbf_gige_alloc_skb(priv, &tx_buf_dma, DMA_TO_DEVICE); if (!tx_skb) { /* Free original skb, could not alloc new aligned SKB */ dev_kfree_skb(skb); @@ -230,7 +226,8 @@ netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, } else { tx_skb = skb; tx_buf_dma = dma_map_single(priv->dev, skb->data, - skb->len, DMA_TO_DEVICE); + MLXBF_GIGE_DEFAULT_BUF_SZ, + DMA_TO_DEVICE); if (dma_mapping_error(priv->dev, tx_buf_dma)) { dev_kfree_skb(skb); netdev->stats.tx_dropped++; @@ -238,6 +235,8 @@ netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, } } + priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; + /* Get address of TX WQE */ tx_wqe_addr = priv->tx_wqe_next; @@ -255,10 +254,7 @@ netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, /* Write entire 2nd word of TX WQE */ *(tx_wqe_addr + 1) = word2; - spin_lock_irqsave(&priv->lock, flags); - priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; priv->tx_pi++; - spin_unlock_irqrestore(&priv->lock, flags); if (!netdev_xmit_more()) { /* Create memory barrier before write to TX PI */ From patchwork Fri Jul 9 19:08:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503320 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2kx3Mrbz9sRR; Sat, 10 Jul 2021 05:08:57 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrp-0003Am-Fc; Fri, 09 Jul 2021 19:08:53 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrm-00039M-W9 for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:45 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8iX1030188; Fri, 9 Jul 2021 15:08:44 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8iH0005455; Fri, 9 Jul 2021 15:08:44 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 02/23] Revert "UBUNTU: SAUCE: mlxbf_gige: syncup with v1.21 content" Date: Fri, 9 Jul 2021 15:08:09 -0400 Message-Id: <20210709190830.5405-3-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit b68212b84f8f9691152dad59d678c70aaf39c9a6. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 6 +-- .../mellanox/mlxbf_gige/mlxbf_gige_intr.c | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 51 +++++++------------ .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_rx.c | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_tx.c | 2 +- 8 files changed, 28 insertions(+), 41 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index 1c59cad682c7..e8cf26f52851 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -4,7 +4,7 @@ * - this file contains software data structures and any chip-specific * data structures (e.g. TX WQE format) that are memory resident. * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #ifndef __MLXBF_GIGE_H__ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c index 1d68b8ba9b02..55b5d67f25ca 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c @@ -2,7 +2,7 @@ /* Ethtool support for Mellanox Gigabit Ethernet driver * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include @@ -158,8 +158,8 @@ static void mlxbf_gige_get_pauseparam(struct net_device *netdev, struct mlxbf_gige *priv = netdev_priv(netdev); pause->autoneg = priv->aneg_pause; - pause->rx_pause = priv->rx_pause; - pause->tx_pause = priv->tx_pause; + pause->rx_pause = priv->tx_pause; + pause->tx_pause = priv->rx_pause; } const struct ethtool_ops mlxbf_gige_ethtool_ops = { diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c index c63a74d730f8..f67826a27203 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c @@ -2,7 +2,7 @@ /* Interrupt related logic for Mellanox Gigabit Ethernet driver * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 2513c3547ea0..c5ffa6887357 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -2,7 +2,7 @@ /* Gigabit Ethernet driver for Mellanox BlueField SoC * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include @@ -21,12 +21,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION 1.21 - -/* This setting defines the version of the ACPI table - * content that is compatible with this driver version. - */ -#define MLXBF_GIGE_ACPI_TABLE_VERSION 1 +#define DRV_VERSION 1.19 /* Allocate SKB whose payload pointer aligns with the Bluefield * hardware DMA limitation, i.e. DMA operation can't cross @@ -76,7 +71,6 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) u8 mac[ETH_ALEN]; u64 local_mac; - memset(mac, 0, ETH_ALEN); mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, &local_mac); u64_to_ether_addr(local_mac, mac); @@ -218,8 +212,8 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) mlxbf_gige_enable_promisc(priv); else mlxbf_gige_disable_promisc(priv); - } - } + } +} static void mlxbf_gige_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) @@ -253,15 +247,7 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = { static void mlxbf_gige_adjust_link(struct net_device *netdev) { - struct mlxbf_gige *priv = netdev_priv(netdev); - struct phy_device *phydev = netdev->phydev; - - if (phydev->link) { - priv->rx_pause = phydev->pause; - priv->tx_pause = phydev->pause; - } - - phy_print_status(phydev); + /* Only one speed and one duplex supported, simply return */ } static int mlxbf_gige_probe(struct platform_device *pdev) @@ -276,21 +262,18 @@ static int mlxbf_gige_probe(struct platform_device *pdev) void __iomem *llu_base; void __iomem *plu_base; void __iomem *base; - u32 version; + int addr, version; u64 control; - int addr; - int err; + int err = 0; - version = 0; - err = device_property_read_u32(&pdev->dev, "version", &version); - if (err) { - dev_err(&pdev->dev, "ACPI table version not found\n"); + if (device_property_read_u32(&pdev->dev, "version", &version)) { + dev_err(&pdev->dev, "Version Info not found\n"); return -EINVAL; } - if (version != MLXBF_GIGE_ACPI_TABLE_VERSION) { - dev_err(&pdev->dev, "ACPI table version mismatch: expected %d found %d\n", - MLXBF_GIGE_ACPI_TABLE_VERSION, version); + if (version != (int)DRV_VERSION) { + dev_err(&pdev->dev, "Version Mismatch. Expected %d Returned %d\n", + (int)DRV_VERSION, version); return -EINVAL; } @@ -384,6 +367,10 @@ static int mlxbf_gige_probe(struct platform_device *pdev) addr = phydev->mdio.addr; phydev->irq = priv->mdiobus->irq[addr] = priv->phy_irq; + /* Sets netdev->phydev to phydev; which will eventually + * be used in ioctl calls. + * Cannot pass NULL handler. + */ err = phy_connect_direct(netdev, phydev, mlxbf_gige_adjust_link, PHY_INTERFACE_MODE_GMII); @@ -403,9 +390,9 @@ static int mlxbf_gige_probe(struct platform_device *pdev) /* MAC supports symmetric flow control */ phy_support_sym_pause(phydev); - /* Initialise pause frame settings */ - priv->rx_pause = 0; - priv->tx_pause = 0; + /* Enable pause */ + priv->rx_pause = phydev->pause; + priv->tx_pause = phydev->pause; priv->aneg_pause = AUTONEG_ENABLE; /* Display information about attached PHY device */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index d1643177ad8a..af4a754d7c25 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -2,7 +2,7 @@ /* MDIO support for Mellanox Gigabit Ethernet driver * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index d4652f9ce225..30ad896f6252 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -2,7 +2,7 @@ /* Header file for Mellanox BlueField GigE register defines * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #ifndef __MLXBF_GIGE_REGS_H__ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c index 9e4c507497a1..1cf8be27ef2a 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c @@ -2,7 +2,7 @@ /* Packet receive logic for Mellanox Gigabit Ethernet driver * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c index 0c35b2f2dfcd..257dd0238129 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c @@ -2,7 +2,7 @@ /* Packet transmit logic for Mellanox Gigabit Ethernet driver * - * Copyright (C) 2020-2021 Mellanox Technologies, Ltd. ALL RIGHTS RESERVED. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include From patchwork Fri Jul 9 19:08:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503331 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lk3fz8z9sRN; Sat, 10 Jul 2021 05:09:38 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsT-0003dN-0Z; Fri, 09 Jul 2021 19:09:33 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrm-00039N-WB for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:46 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8j3Q030196; Fri, 9 Jul 2021 15:08:45 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8jPJ005456; Fri, 9 Jul 2021 15:08:45 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 03/23] Revert "UBUNTU: SAUCE: Automate soft reset of BlueField ARM via GPIO7" Date: Fri, 9 Jul 2021 15:08:10 -0400 Message-Id: <20210709190830.5405-4-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 5f103d71e8812f843fce3763c2688384d766b902. Signed-off-by: Asmaa Mnebhi --- drivers/gpio/gpio-mlxbf2.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index e7f17765ff11..684a3c96f60f 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -16,12 +16,11 @@ #include #include #include -#include #include #include #include -#define DRV_VERSION "1.3" +#define DRV_VERSION "1.2" /* * There are 3 YU GPIO blocks: @@ -353,6 +352,21 @@ static u32 mlxbf2_gpio_get_int_mask(struct mlxbf2_gpio_context *gs) return gpio_int_mask; } +static bool mlxbf2_gpio_is_acpi_event(u32 gpio_block, unsigned long gpio_pin, + struct mlxbf2_gpio_context *gs) +{ + if (gpio_block & BIT(GPIO_BLOCK0)) { + if (gpio_pin & BIT(gs->rst_pin)) + return true; + } + if (gpio_block & BIT(GPIO_BLOCK16)) { + if (gpio_pin & BIT(gs->low_pwr_pin)) + return true; + } + + return false; +} + static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) { struct mlxbf2_gpio_context *gs = ptr; @@ -396,15 +410,8 @@ static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - if (gpio_block & BIT(GPIO_BLOCK16)) { - if (gpio_pin & BIT(gs->low_pwr_pin)) - schedule_work(&gs->send_work); - } - - if (gpio_block & BIT(GPIO_BLOCK0)) { - if (gpio_pin & BIT(gs->rst_pin)) - emergency_restart(); - } + if (mlxbf2_gpio_is_acpi_event(gpio_block, gpio_pin, gs)) + schedule_work(&gs->send_work); return IRQ_HANDLED; } @@ -496,6 +503,7 @@ mlxbf2_gpio_probe(struct platform_device *pdev) if (!gs) return -ENOMEM; + spin_lock_init(&gs->gc.bgpio_lock); INIT_WORK(&gs->send_work, mlxbf2_gpio_send_work); /* YU GPIO block address */ @@ -585,8 +593,6 @@ mlxbf2_gpio_probe(struct platform_device *pdev) girq->init_hw = mlxbf2_gpio_init_hw; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler, IRQF_ONESHOT | IRQF_SHARED, name, gs); if (ret) { From patchwork Fri Jul 9 19:08:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503325 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lG4zGCz9sRR; Sat, 10 Jul 2021 05:09:14 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vs3-0003KV-Tr; Fri, 09 Jul 2021 19:09:08 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrn-00039P-1a for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:46 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8k3k030199; Fri, 9 Jul 2021 15:08:46 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8k0p005457; Fri, 9 Jul 2021 15:08:46 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 04/23] Revert "UBUNTU: SAUCE: Syncup with the latest gpio-mlxbf2 and mlxbf-gige drivers" Date: Fri, 9 Jul 2021 15:08:11 -0400 Message-Id: <20210709190830.5405-5-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit e6a1de26492dd505b7931a9d830d6f780410340a. Signed-off-by: Asmaa Mnebhi --- drivers/gpio/gpio-mlxbf2.c | 397 +++---- .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 2 +- .../net/ethernet/mellanox/mlxbf_gige/Makefile | 4 +- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 31 +- .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 178 ---- .../mellanox/mlxbf_gige/mlxbf_gige_intr.c | 143 --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 989 +++++++++++++++++- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 105 +- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_rx.c | 299 ------ .../mellanox/mlxbf_gige/mlxbf_gige_tx.c | 279 ----- 11 files changed, 1164 insertions(+), 1265 deletions(-) delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 684a3c96f60f..0dc9747c79e4 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -1,26 +1,25 @@ // SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause /* - * Copyright (c) 2020-2021 NVIDIA Corporation. + * Copyright (c) 2020 NVIDIA Corporation. */ #include #include #include #include -#include #include #include #include #include +#include #include #include #include #include #include #include - -#define DRV_VERSION "1.2" +#include /* * There are 3 YU GPIO blocks: @@ -31,13 +30,6 @@ */ #define MLXBF2_GPIO_MAX_PINS_PER_BLOCK 32 -typedef enum { - GPIO_BLOCK0 = 0, - GPIO_BLOCK1 = 1, - GPIO_BLOCK2 = 2, - GPIO_BLOCK16 = 16 -} yu_gpio_block; - /* * arm_gpio_lock register: * bit[31] lock status: active if set @@ -50,9 +42,6 @@ typedef enum { #define YU_ARM_GPIO_LOCK_ACQUIRE 0xd42f #define YU_ARM_GPIO_LOCK_RELEASE 0x0 -#define YU_CAUSE_GPIO_ADDR 0x2801530 -#define YU_CAUSE_GPIO_ADDR_SIZE 0x4 - /* * gpio[x] block registers and their offset */ @@ -61,8 +50,6 @@ typedef enum { #define YU_GPIO_MODE0 0x0c #define YU_GPIO_DATASET 0x14 #define YU_GPIO_DATACLEAR 0x18 -#define YU_GPIO_FUNCTIONAL_ENABLE1 0x24 -#define YU_GPIO_FUNCTIONAL_ENABLE0 0x28 #define YU_GPIO_CAUSE_RISE_EN 0x44 #define YU_GPIO_CAUSE_FALL_EN 0x48 #define YU_GPIO_MODE1_CLEAR 0x50 @@ -72,6 +59,16 @@ typedef enum { #define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 #define YU_GPIO_CAUSE_OR_EVTEN0 0x94 #define YU_GPIO_CAUSE_OR_CLRCAUSE 0x98 +#define YU_GPIO16_LOW_PWR_BIT 0 +#define YU_GPIO0_RST_BIT 7 +#define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0_MASK(gpio_bit) BIT(gpio_bit) +#define YU_GPIO_CAUSE_OR_EVTEN0_MASK(gpio_bit) BIT(gpio_bit) +#define YU_GPIO_CAUSE_RISE_EN_MASK(gpio_bit) BIT(gpio_bit) +#define YU_GPIO_CAUSE_FALL_EN_MASK(gpio_bit) BIT(gpio_bit) +#define YU_GPIO_CAUSE_OR_CLRCAUSE_MASK(gpio_bit) BIT(gpio_bit) +#define YU_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK 0x10 +#define YU_GPIO_CAUSE_IRQ_IS_SET(val) \ + (val & YU_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK) #ifdef CONFIG_PM struct mlxbf2_gpio_context_save_regs { @@ -80,28 +77,28 @@ struct mlxbf2_gpio_context_save_regs { }; #endif +#define RST_GPIO_PIN 7 +#define LOW_PWR_GPIO_PIN 71 +#define MAX_HOST_GPIOS LOW_PWR_GPIO_PIN + /* BlueField-2 gpio block context structure. */ struct mlxbf2_gpio_context { struct gpio_chip gc; - struct irq_chip irq_chip; /* YU GPIO blocks address */ void __iomem *gpio_io; - /* YU cause gpio arm coalesce0 address */ - void __iomem *cause_gpio_arm_coalesce0_io; - - /* YU GPIO pin responsible for low power mode */ + /* GPIO pin responsible for low power mode */ unsigned long low_pwr_pin; - /* YU GPIO pin responsible for soft reset */ + /* GPIO pin responsible for soft reset */ unsigned long rst_pin; - /* YU GPIO pin connected to PHY INT_N signal */ - unsigned long phy_int_pin; - - /* YU GPIO block interrupt mask */ - u32 gpio_int_mask; + /* + * Bit within the YU GPIO block that's conifgued + * as an interrupt. + */ + u32 gpio_int_bit; /* Worker function */ struct work_struct send_work; @@ -131,19 +128,6 @@ static struct mlxbf2_gpio_param yu_arm_gpio_lock_param = { .lock = &yu_arm_gpio_lock_mutex, }; -static struct resource yu_cause_gpio_res = { - .start = YU_CAUSE_GPIO_ADDR, - .end = YU_CAUSE_GPIO_ADDR + YU_CAUSE_GPIO_ADDR_SIZE - 1, - .name = "YU_CAUSE_GPIO", -}; - -static DEFINE_MUTEX(yu_cause_gpio_mutex); - -static struct mlxbf2_gpio_param yu_cause_gpio_param = { - .res = &yu_cause_gpio_res, - .lock = &yu_cause_gpio_mutex, -}; - /* Request memory region and map yu_arm_gpio_lock resource */ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) { @@ -167,8 +151,8 @@ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) } yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size); - if (!yu_arm_gpio_lock_param.io) - ret = -ENOMEM; + if (IS_ERR(yu_arm_gpio_lock_param.io)) + ret = PTR_ERR(yu_arm_gpio_lock_param.io); exit: mutex_unlock(yu_arm_gpio_lock_param.lock); @@ -176,38 +160,6 @@ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) return ret; } -/* Request memory region and map yu cause_gpio_arm.coalesce0 resource */ -static int mlxbf2_gpio_get_yu_cause_gpio_res(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct resource *res; - resource_size_t size; - int ret = 0; - - mutex_lock(yu_cause_gpio_param.lock); - - /* Check if the memory map already exists */ - if (yu_cause_gpio_param.io) - goto exit; - - res = yu_cause_gpio_param.res; - size = resource_size(res); - - if (!devm_request_mem_region(dev, res->start, size, res->name)) { - ret = -EFAULT; - goto exit; - } - - yu_cause_gpio_param.io = devm_ioremap(dev, res->start, size); - if (!yu_cause_gpio_param.io) - ret = -ENOMEM; - -exit: - mutex_unlock(yu_cause_gpio_param.lock); - - return ret; -} - /* * Acquire the YU arm_gpio_lock to be able to change the direction * mode. If the lock_active bit is already set, return an error. @@ -239,8 +191,6 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs) * Release the YU arm_gpio_lock after changing the direction mode. */ static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs) - __releases(&gs->gc.bgpio_lock) - __releases(yu_arm_gpio_lock_param.lock) { writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io); spin_unlock(&gs->gc.bgpio_lock); @@ -297,7 +247,6 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip, { struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip); int ret = 0; - u32 val; /* * Although the arm_gpio_lock was set in the probe function, @@ -311,174 +260,115 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip, writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR); writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_SET); - /* - * Set {functional_enable1,functional_enable0}={0,0} - * to give control to software over these GPIOs. - */ - val = readl(gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE1); - val &= ~BIT(offset); - writel(val, gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE1); - val = readl(gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE0); - val &= ~BIT(offset); - writel(val, gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE0); - mlxbf2_gpio_lock_release(gs); return ret; } -static void mlxbf2_gpio_send_work(struct work_struct *work) +static void mlxbf2_gpio_irq_disable(struct mlxbf2_gpio_context *gs) { -#ifdef CONFIG_ACPI - acpi_bus_generate_netlink_event("button/power.*", "Power Button", - 0x80, 1); -#endif -} - -static u32 mlxbf2_gpio_get_int_mask(struct mlxbf2_gpio_context *gs) -{ - u32 gpio_int_mask = 0; - - /* - * Determine bit mask within the yu gpio block. - */ - if (gs->phy_int_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) - gpio_int_mask = BIT(gs->phy_int_pin); - if (gs->rst_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) - gpio_int_mask |= BIT(gs->rst_pin); - if (gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) - gpio_int_mask = BIT(gs->low_pwr_pin); - - return gpio_int_mask; -} + u32 val; -static bool mlxbf2_gpio_is_acpi_event(u32 gpio_block, unsigned long gpio_pin, - struct mlxbf2_gpio_context *gs) -{ - if (gpio_block & BIT(GPIO_BLOCK0)) { - if (gpio_pin & BIT(gs->rst_pin)) - return true; - } - if (gpio_block & BIT(GPIO_BLOCK16)) { - if (gpio_pin & BIT(gs->low_pwr_pin)) - return true; + spin_lock(&gs->gc.bgpio_lock); + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + if (!val) { + spin_unlock(&gs->gc.bgpio_lock); + /* There is no enabled interrupt */ + return; } - return false; + val &= ~YU_GPIO_CAUSE_OR_EVTEN0_MASK(gs->gpio_int_bit); + writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + spin_unlock(&gs->gc.bgpio_lock); } -static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) +static void mlxbf2_gpio_irq_set_type(struct mlxbf2_gpio_context *gs) { - struct mlxbf2_gpio_context *gs = ptr; - unsigned long gpio_pin; - u32 gpio_block, val; - unsigned long flags; - - spin_lock_irqsave(&gs->gc.bgpio_lock, flags); + u32 val; - /* - * Determine which yu gpio block this interrupt is for. - * Return if the interrupt is not for gpio block 0 or - * gpio block 16. - */ - gpio_block = readl(yu_cause_gpio_param.io); - if (!(gpio_block & BIT(GPIO_BLOCK0)) && - !(gpio_block & BIT(GPIO_BLOCK16))) { - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - return IRQ_NONE; - } + spin_lock(&gs->gc.bgpio_lock); /* - * Check if the interrupt signaled by this yu gpio block is supported. + * The power state gpio interrupt should be detected at rising + * and falling edges. + * + * In the case of low power mode interrupt: + * When it goes from 0 to 1, system should go into low power state + * When it goes from 1 to 0, system should revert to normal state + * + * In the case of soft reset interrupt, trigger interrupt off + * falling edge since it is active low. */ - gpio_pin = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); - if (!(gpio_pin & gs->gpio_int_mask)) { - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - return IRQ_NONE; + if (gs->low_pwr_pin == LOW_PWR_GPIO_PIN) { + val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); + val |= YU_GPIO_CAUSE_RISE_EN_MASK(gs->gpio_int_bit); + writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); } - /* - * Clear interrupt when done, otherwise, no further interrupt - * will be triggered. - */ - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); - val |= gpio_pin; - writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); - - if ((gpio_block & BIT(GPIO_BLOCK0)) && (gpio_pin & BIT(gs->phy_int_pin))) - generic_handle_irq(irq_find_mapping(gs->gc.irq.domain, gs->phy_int_pin)); - - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - - if (mlxbf2_gpio_is_acpi_event(gpio_block, gpio_pin, gs)) - schedule_work(&gs->send_work); - - return IRQ_HANDLED; -} - -static void mlxbf2_gpio_irq_unmask(struct irq_data *data) -{ -} + val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); + val |= YU_GPIO_CAUSE_FALL_EN_MASK(gs->gpio_int_bit); + writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); -static void mlxbf2_gpio_irq_mask(struct irq_data *data) -{ + spin_unlock(&gs->gc.bgpio_lock); } -static int mlxbf2_gpio_init_hw(struct gpio_chip *gc) +static void mlxbf2_gpio_irq_enable(struct mlxbf2_gpio_context *gs) { - struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc); - unsigned long flags; u32 val; - spin_lock_irqsave(&gs->gc.bgpio_lock, flags); - - /* Clear all interrupts */ - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); - val |= gs->gpio_int_mask; - writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); - - if (gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) { - val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); - val |= gs->gpio_int_mask; - writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); - } - - val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); - val |= gs->gpio_int_mask; - writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); + spin_lock(&gs->gc.bgpio_lock); /* * Setting the priority for the GPIO interrupt enables the * interrupt as well */ val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - val |= gs->gpio_int_mask; + val |= YU_GPIO_CAUSE_OR_EVTEN0_MASK(gs->gpio_int_bit); writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + spin_unlock(&gs->gc.bgpio_lock); +} - return 0; +static void mlxbf2_gpio_send_work(struct work_struct *work) +{ + struct mlxbf2_gpio_context *gs; + + gs = container_of(work, struct mlxbf2_gpio_context, send_work); + + acpi_bus_generate_netlink_event("button/power.*", "Power Button", 0x80, 1); } -static void mlxbf2_gpio_disable_int(struct mlxbf2_gpio_context *gs) +static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) { + struct mlxbf2_gpio_context *gs = ptr; unsigned long flags; u32 val; spin_lock_irqsave(&gs->gc.bgpio_lock, flags); - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - val &= ~gs->gpio_int_mask; - writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); -} -static int mlxbf2_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) -{ - struct mlxbf2_gpio_context *gs; + /* + * Check if this interrupt is for bit 0 of yu.gpio[16] + * or bit 7 of yu.gpio[0]. + * Return if it is not. + */ + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); + if (!(val & YU_GPIO_CAUSE_OR_CAUSE_EVTEN0_MASK(gs->gpio_int_bit))) { + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + return IRQ_NONE; + } - gs = gpiochip_get_data(chip); + /* + * Clear interrupt when done, otherwise, no further interrupt + * will be triggered. + */ + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + val |= YU_GPIO_CAUSE_OR_CLRCAUSE_MASK(gs->gpio_int_bit); + writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + + schedule_work(&gs->send_work); - return irq_create_mapping(gs->gc.irq.domain, gpio); + return IRQ_HANDLED; } /* BlueField-2 GPIO driver initialization routine. */ @@ -487,18 +377,13 @@ mlxbf2_gpio_probe(struct platform_device *pdev) { struct mlxbf2_gpio_context *gs; struct device *dev = &pdev->dev; - struct gpio_irq_chip *girq; unsigned int low_pwr_pin; - unsigned int phy_int_pin; unsigned int rst_pin; struct gpio_chip *gc; struct resource *res; unsigned int npins; - const char *name; int ret, irq; - name = dev_name(dev); - gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL); if (!gs) return -ENOMEM; @@ -521,12 +406,6 @@ mlxbf2_gpio_probe(struct platform_device *pdev) return ret; } - ret = mlxbf2_gpio_get_yu_cause_gpio_res(pdev); - if (ret) { - dev_err(dev, "Failed to get yu cause_gpio_arm.coalesce0 resource\n"); - return ret; - } - if (device_property_read_u32(dev, "npins", &npins)) npins = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; @@ -540,79 +419,53 @@ mlxbf2_gpio_probe(struct platform_device *pdev) NULL, 0); - if (ret) { - dev_err(dev, "bgpio_init failed\n"); - return ret; - } - gc->direction_input = mlxbf2_gpio_direction_input; gc->direction_output = mlxbf2_gpio_direction_output; gc->ngpio = npins; gc->owner = THIS_MODULE; - gc->to_irq = mlxbf2_gpio_to_irq; - /* - * PHY interrupt - */ - ret = device_property_read_u32(dev, "phy-int-pin", &phy_int_pin); - if (ret < 0) - phy_int_pin = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; + ret = devm_gpiochip_add_data(dev, &gs->gc, gs); + if (ret) { + dev_err(dev, "Failed adding memory mapped gpiochip\n"); + return ret; + } + platform_set_drvdata(pdev, gs); /* - * OCP3.0 supports the low power mode interrupt. + * OCP3.0 supports the AUX power mode interrupt on bit 0 of yu.gpio[16]. + * BlueSphere and the PRIS boards support the rebooot interrupt on bit + * 7 of yu.gpio[0]. */ ret = device_property_read_u32(dev, "low-pwr-pin", &low_pwr_pin); if (ret < 0) - low_pwr_pin = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; + low_pwr_pin = MAX_HOST_GPIOS + 1; - /* - * BlueSphere and the PRIS boards support the reset interrupt. - */ ret = device_property_read_u32(dev, "rst-pin", &rst_pin); if (ret < 0) - rst_pin = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; + rst_pin = MAX_HOST_GPIOS + 1; - gs->phy_int_pin = phy_int_pin; gs->low_pwr_pin = low_pwr_pin; gs->rst_pin = rst_pin; - gs->gpio_int_mask = mlxbf2_gpio_get_int_mask(gs); - - if (gs->gpio_int_mask) { - gs->irq_chip.name = name; - gs->irq_chip.irq_mask = mlxbf2_gpio_irq_mask; - gs->irq_chip.irq_unmask = mlxbf2_gpio_irq_unmask; - - girq = &gs->gc.irq; - girq->chip = &gs->irq_chip; - /* This will let us handle the parent IRQ in the driver */ - girq->parent_handler = NULL; - girq->num_parents = 0; - girq->parents = NULL; - girq->default_type = IRQ_TYPE_NONE; - girq->handler = handle_simple_irq; - girq->init_hw = mlxbf2_gpio_init_hw; + + if ((low_pwr_pin == LOW_PWR_GPIO_PIN) || (rst_pin == RST_GPIO_PIN)) { + if (rst_pin == RST_GPIO_PIN) + gs->gpio_int_bit = YU_GPIO0_RST_BIT; + else + gs->gpio_int_bit = YU_GPIO16_LOW_PWR_BIT; irq = platform_get_irq(pdev, 0); + /* + * For now, no need to check if interrupt was previously allocated + * by another gpio block. + */ ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler, - IRQF_ONESHOT | IRQF_SHARED, name, gs); + IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED, dev_name(dev), gs); if (ret) { - dev_err(dev, "failed to request IRQ"); + dev_err(dev, "IRQ handler registering failed (%d)\n", ret); return ret; } - } - - ret = devm_gpiochip_add_data(dev, &gs->gc, gs); - if (ret) { - dev_err(dev, "Failed adding memory mapped gpiochip\n"); - return ret; - } - platform_set_drvdata(pdev, gs); - - if (phy_int_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) { - /* Create phy irq mapping */ - mlxbf2_gpio_to_irq(&gs->gc, phy_int_pin); - /* Enable sharing the irq domain with the PHY driver */ - irq_set_default_host(gs->gc.irq.domain); + mlxbf2_gpio_irq_set_type(gs); + mlxbf2_gpio_irq_enable(gs); } return 0; @@ -624,15 +477,8 @@ mlxbf2_gpio_remove(struct platform_device *pdev) struct mlxbf2_gpio_context *gs; gs = platform_get_drvdata(pdev); - - if ((gs->phy_int_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) || - (gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) || - (gs->rst_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK)) { - mlxbf2_gpio_disable_int(gs); - } - - if ((gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) || - (gs->rst_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK)) { + if ((gs->low_pwr_pin == LOW_PWR_GPIO_PIN) || (gs->rst_pin == RST_GPIO_PIN)) { + mlxbf2_gpio_irq_disable(gs); flush_work(&gs->send_work); } @@ -666,7 +512,7 @@ static int mlxbf2_gpio_resume(struct platform_device *pdev) } #endif -static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = { +static const struct acpi_device_id mlxbf2_gpio_acpi_match[] = { { "MLNXBF22", 0 }, {}, }; @@ -688,6 +534,5 @@ static struct platform_driver mlxbf2_gpio_driver = { module_platform_driver(mlxbf2_gpio_driver); MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver"); -MODULE_AUTHOR("Asmaa Mnebhi "); +MODULE_AUTHOR("Mellanox Technologies"); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig index 0338ba5f46b6..08a4487932fe 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig @@ -5,7 +5,7 @@ config MLXBF_GIGE tristate "Mellanox Technologies BlueField Gigabit Ethernet support" - depends on (ARM64 || COMPILE_TEST) && ACPI && GPIO_MLXBF2 + depends on (ARM64 || COMPILE_TEST) && ACPI select PHYLIB help The second generation BlueField SoC from Mellanox Technologies diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile index 6caae3ca41cf..e99fc19ac819 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile @@ -2,6 +2,4 @@ obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o -mlxbf_gige-y := mlxbf_gige_ethtool.o mlxbf_gige_intr.o \ - mlxbf_gige_main.o mlxbf_gige_mdio.o \ - mlxbf_gige_rx.o mlxbf_gige_tx.o +mlxbf_gige-y := mlxbf_gige_main.o mlxbf_gige_mdio.o diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index e8cf26f52851..c3cb50ef8774 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -4,13 +4,12 @@ * - this file contains software data structures and any chip-specific * data structures (e.g. TX WQE format) that are memory resident. * - * Copyright (c) 2020-2021 NVIDIA Corporation. + * Copyright (c) 2020 NVIDIA Corporation. */ #ifndef __MLXBF_GIGE_H__ #define __MLXBF_GIGE_H__ -#include #include #include @@ -54,8 +53,6 @@ #define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3 -#define MLXBF_GIGE_DEFAULT_PHY_INT_GPIO 12 - struct mlxbf_gige_stats { u64 hw_access_errors; u64 tx_invalid_checksums; @@ -80,6 +77,8 @@ struct mlxbf_gige { struct platform_device *pdev; void __iomem *mdio_io; struct mii_bus *mdiobus; + void __iomem *gpio_io; + u32 phy_int_gpio_mask; spinlock_t lock; spinlock_t gpio_lock; u16 rx_q_entries; @@ -144,6 +143,7 @@ struct mlxbf_gige { enum mlxbf_gige_res { MLXBF_GIGE_RES_MAC, MLXBF_GIGE_RES_MDIO9, + MLXBF_GIGE_RES_GPIO0, MLXBF_GIGE_RES_LLU, MLXBF_GIGE_RES_PLU }; @@ -155,28 +155,5 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv); void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv); irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id); -void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv); - -void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 dmac); -void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 *dmac); -void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv); -void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv); -int mlxbf_gige_rx_init(struct mlxbf_gige *priv); -void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv); -int mlxbf_gige_tx_init(struct mlxbf_gige *priv); -void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv); -bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv); -netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, - struct net_device *netdev); -struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, - dma_addr_t *buf_dma, - enum dma_data_direction dir); -int mlxbf_gige_request_irqs(struct mlxbf_gige *priv); -void mlxbf_gige_free_irqs(struct mlxbf_gige *priv); -int mlxbf_gige_poll(struct napi_struct *napi, int budget); -extern const struct ethtool_ops mlxbf_gige_ethtool_ops; -void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv); #endif /* !defined(__MLXBF_GIGE_H__) */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c deleted file mode 100644 index 55b5d67f25ca..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +++ /dev/null @@ -1,178 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause - -/* Ethtool support for Mellanox Gigabit Ethernet driver - * - * Copyright (c) 2020-2021 NVIDIA Corporation. - */ - -#include - -#include "mlxbf_gige.h" -#include "mlxbf_gige_regs.h" - -/* Start of struct ethtool_ops functions */ -static int mlxbf_gige_get_regs_len(struct net_device *netdev) -{ - return MLXBF_GIGE_MMIO_REG_SZ; -} - -static void mlxbf_gige_get_regs(struct net_device *netdev, - struct ethtool_regs *regs, void *p) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - regs->version = MLXBF_GIGE_REGS_VERSION; - - /* Read entire MMIO register space and store results - * into the provided buffer. Each 64-bit word is converted - * to big-endian to make the output more readable. - * - * NOTE: by design, a read to an offset without an existing - * register will be acknowledged and return zero. - */ - memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); -} - -static void mlxbf_gige_get_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ering) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; - ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; - ering->rx_pending = priv->rx_q_entries; - ering->tx_pending = priv->tx_q_entries; -} - -static int mlxbf_gige_set_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ering) -{ - const struct net_device_ops *ops = netdev->netdev_ops; - struct mlxbf_gige *priv = netdev_priv(netdev); - int new_rx_q_entries, new_tx_q_entries; - - /* Device does not have separate queues for small/large frames */ - if (ering->rx_mini_pending || ering->rx_jumbo_pending) - return -EINVAL; - - /* Round up to supported values */ - new_rx_q_entries = roundup_pow_of_two(ering->rx_pending); - new_tx_q_entries = roundup_pow_of_two(ering->tx_pending); - - /* Check against min values, core checks against max values */ - if (new_tx_q_entries < MLXBF_GIGE_MIN_TXQ_SZ || - new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ) - return -EINVAL; - - /* If queue sizes did not change, exit now */ - if (new_rx_q_entries == priv->rx_q_entries && - new_tx_q_entries == priv->tx_q_entries) - return 0; - - if (netif_running(netdev)) - ops->ndo_stop(netdev); - - priv->rx_q_entries = new_rx_q_entries; - priv->tx_q_entries = new_tx_q_entries; - - if (netif_running(netdev)) - ops->ndo_open(netdev); - - return 0; -} - -static const struct { - const char string[ETH_GSTRING_LEN]; -} mlxbf_gige_ethtool_stats_keys[] = { - { "hw_access_errors" }, - { "tx_invalid_checksums" }, - { "tx_small_frames" }, - { "tx_index_errors" }, - { "sw_config_errors" }, - { "sw_access_errors" }, - { "rx_truncate_errors" }, - { "rx_mac_errors" }, - { "rx_din_dropped_pkts" }, - { "tx_fifo_full" }, - { "rx_filter_passed_pkts" }, - { "rx_filter_discard_pkts" }, -}; - -static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) -{ - if (stringset != ETH_SS_STATS) - return -EOPNOTSUPP; - return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); -} - -static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, - u8 *buf) -{ - if (stringset != ETH_SS_STATS) - return; - memcpy(buf, &mlxbf_gige_ethtool_stats_keys, - sizeof(mlxbf_gige_ethtool_stats_keys)); -} - -static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *estats, - u64 *data) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - /* Fill data array with interface statistics - * - * NOTE: the data writes must be in - * sync with the strings shown in - * the mlxbf_gige_ethtool_stats_keys[] array - * - * NOTE2: certain statistics below are zeroed upon - * port disable, so the calculation below - * must include the "cached" value of the stat - * plus the value read directly from hardware. - * Cached statistics are currently: - * rx_din_dropped_pkts - * rx_filter_passed_pkts - * rx_filter_discard_pkts - */ - *data++ = priv->stats.hw_access_errors; - *data++ = priv->stats.tx_invalid_checksums; - *data++ = priv->stats.tx_small_frames; - *data++ = priv->stats.tx_index_errors; - *data++ = priv->stats.sw_config_errors; - *data++ = priv->stats.sw_access_errors; - *data++ = priv->stats.rx_truncate_errors; - *data++ = priv->stats.rx_mac_errors; - *data++ = (priv->stats.rx_din_dropped_pkts + - readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); - *data++ = priv->stats.tx_fifo_full; - *data++ = (priv->stats.rx_filter_passed_pkts + - readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); - *data++ = (priv->stats.rx_filter_discard_pkts + - readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); -} - -static void mlxbf_gige_get_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - pause->autoneg = priv->aneg_pause; - pause->rx_pause = priv->tx_pause; - pause->tx_pause = priv->rx_pause; -} - -const struct ethtool_ops mlxbf_gige_ethtool_ops = { - .get_link = ethtool_op_get_link, - .get_ringparam = mlxbf_gige_get_ringparam, - .set_ringparam = mlxbf_gige_set_ringparam, - .get_regs_len = mlxbf_gige_get_regs_len, - .get_regs = mlxbf_gige_get_regs, - .get_strings = mlxbf_gige_get_strings, - .get_sset_count = mlxbf_gige_get_sset_count, - .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, - .nway_reset = phy_ethtool_nway_reset, - .get_pauseparam = mlxbf_gige_get_pauseparam, - .get_link_ksettings = phy_ethtool_get_link_ksettings, -}; - diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c deleted file mode 100644 index f67826a27203..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c +++ /dev/null @@ -1,143 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause - -/* Interrupt related logic for Mellanox Gigabit Ethernet driver - * - * Copyright (c) 2020-2021 NVIDIA Corporation. - */ - -#include - -#include "mlxbf_gige.h" -#include "mlxbf_gige_regs.h" - -static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) -{ - struct mlxbf_gige *priv; - u64 int_status; - - priv = dev_id; - - priv->error_intr_count++; - - int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); - - if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) - priv->stats.hw_access_errors++; - - if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { - priv->stats.tx_invalid_checksums++; - /* This error condition is latched into MLXBF_GIGE_INT_STATUS - * when the GigE silicon operates on the offending - * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom - * of this routine clears this error condition. - */ - } - - if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) { - priv->stats.tx_small_frames++; - /* This condition happens when the networking stack invokes - * this driver's "start_xmit()" method with a packet whose - * size < 60 bytes. The GigE silicon will automatically pad - * this small frame up to a minimum-sized frame before it is - * sent. The "tx_small_frame" condition is latched into the - * MLXBF_GIGE_INT_STATUS register when the GigE silicon - * operates on the offending TX WQE. The write to - * MLXBF_GIGE_INT_STATUS at the bottom of this routine - * clears this condition. - */ - } - - if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) - priv->stats.tx_index_errors++; - - if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) - priv->stats.sw_config_errors++; - - if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) - priv->stats.sw_access_errors++; - - /* Clear all error interrupts by writing '1' back to - * all the asserted bits in INT_STATUS. Do not write - * '1' back to 'receive packet' bit, since that is - * managed separately. - */ - - int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET; - - writeq(int_status, priv->base + MLXBF_GIGE_INT_STATUS); - - return IRQ_HANDLED; -} - -static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) -{ - struct mlxbf_gige *priv; - - priv = dev_id; - - priv->rx_intr_count++; - - /* NOTE: GigE silicon automatically disables "packet rx" interrupt by - * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt - * to the ARM cores. Software needs to re-enable "packet rx" - * interrupts by clearing MLXBF_GIGE_INT_MASK bit0. - */ - - napi_schedule(&priv->napi); - - return IRQ_HANDLED; -} - -static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) -{ - struct mlxbf_gige *priv; - - priv = dev_id; - priv->llu_plu_intr_count++; - - return IRQ_HANDLED; -} - -int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) -{ - int err; - - err = request_irq(priv->error_irq, mlxbf_gige_error_intr, 0, - "mlxbf_gige_error", priv); - if (err) { - dev_err(priv->dev, "Request error_irq failure\n"); - return err; - } - - err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0, - "mlxbf_gige_rx", priv); - if (err) { - dev_err(priv->dev, "Request rx_irq failure\n"); - goto free_error_irq; - } - - err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, - "mlxbf_gige_llu_plu", priv); - if (err) { - dev_err(priv->dev, "Request llu_plu_irq failure\n"); - goto free_rx_irq; - } - - return 0; - -free_rx_irq: - free_irq(priv->rx_irq, priv); - -free_error_irq: - free_irq(priv->error_irq, priv); - - return err; -} - -void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) -{ - free_irq(priv->error_irq, priv); - free_irq(priv->rx_irq, priv); - free_irq(priv->llu_plu_irq, priv); -} - diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index c5ffa6887357..85a7ce19a6ff 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -2,15 +2,15 @@ /* Gigabit Ethernet driver for Mellanox BlueField SoC * - * Copyright (c) 2020-2021 NVIDIA Corporation. + * Copyright (c) 2020 NVIDIA Corporation. */ #include #include #include #include -#include #include +#include #include #include #include @@ -21,7 +21,65 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION 1.19 +#define DRV_VERSION "1.10" + +static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 dmac) +{ + void __iomem *base = priv->base; + u64 control; + + /* Write destination MAC to specified MAC RX filter */ + writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); + + /* Enable MAC receive filter mask for specified index */ + control = readq(base + MLXBF_GIGE_CONTROL); + control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index); + writeq(control, base + MLXBF_GIGE_CONTROL); +} + +static void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 *dmac) +{ + void __iomem *base = priv->base; + + /* Read destination MAC from specified MAC RX filter */ + *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); +} + +static void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) +{ + void __iomem *base = priv->base; + u64 control; + + /* Enable MAC_ID_RANGE match functionality */ + control = readq(base + MLXBF_GIGE_CONTROL); + control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; + writeq(control, base + MLXBF_GIGE_CONTROL); + + /* Set start of destination MAC range check to 0 */ + writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START); + + /* Set end of destination MAC range check to all FFs */ + writeq(0xFFFFFFFFFFFF, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END); +} + +static void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) +{ + void __iomem *base = priv->base; + u64 control; + + /* Disable MAC_ID_RANGE match functionality */ + control = readq(base + MLXBF_GIGE_CONTROL); + control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; + writeq(control, base + MLXBF_GIGE_CONTROL); + + /* NOTE: no need to change DMAC_RANGE_START or END; + * those values are ignored since MAC_ID_RANGE_EN=0 + */ +} /* Allocate SKB whose payload pointer aligns with the Bluefield * hardware DMA limitation, i.e. DMA operation can't cross @@ -30,9 +88,9 @@ * and then adjusts the headroom so that the SKB data pointer is * naturally aligned to a 2KB boundary. */ -struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, - dma_addr_t *buf_dma, - enum dma_data_direction dir) +static struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, + dma_addr_t *buf_dma, + enum dma_data_direction dir) { struct sk_buff *skb; u64 addr, offset; @@ -66,27 +124,705 @@ struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, return skb; } -static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) +/* Receive Initialization + * 1) Configures RX MAC filters via MMIO registers + * 2) Allocates RX WQE array using coherent DMA mapping + * 3) Initializes each element of RX WQE array with a receive + * buffer pointer (also using coherent DMA mapping) + * 4) Allocates RX CQE array using coherent DMA mapping + * 5) Completes other misc receive initialization + */ +static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) { - u8 mac[ETH_ALEN]; - u64 local_mac; + size_t wq_size, cq_size; + dma_addr_t *rx_wqe_ptr; + dma_addr_t rx_buf_dma; + u64 data; + int i, j; + + /* Configure MAC RX filter #0 to allow RX of broadcast pkts */ + mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX, + BCAST_MAC_ADDR); + + wq_size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; + priv->rx_wqe_base = dma_alloc_coherent(priv->dev, wq_size, + &priv->rx_wqe_base_dma, + GFP_KERNEL); + if (!priv->rx_wqe_base) + return -ENOMEM; - mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, - &local_mac); - u64_to_ether_addr(local_mac, mac); + /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array + * Each RX WQE is simply a receive buffer pointer, so walk + * the entire array, allocating a 2KB buffer for each element + */ + rx_wqe_ptr = priv->rx_wqe_base; - if (is_valid_ether_addr(mac)) { - ether_addr_copy(priv->netdev->dev_addr, mac); - } else { - /* Provide a random MAC if for some reason the device has - * not been configured with a valid MAC address already. + for (i = 0; i < priv->rx_q_entries; i++) { + priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, DMA_FROM_DEVICE); + if (!priv->rx_skb[i]) + goto free_wqe_and_skb; + + *rx_wqe_ptr++ = rx_buf_dma; + } + + /* Write RX WQE base address into MMIO reg */ + writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE); + + cq_size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; + priv->rx_cqe_base = dma_alloc_coherent(priv->dev, cq_size, + &priv->rx_cqe_base_dma, + GFP_KERNEL); + if (!priv->rx_cqe_base) + goto free_wqe_and_skb; + + /* Write RX CQE base address into MMIO reg */ + writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); + + /* Write RX_WQE_PI with current number of replenished buffers */ + writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI); + + /* Enable removal of CRC during RX */ + data = readq(priv->base + MLXBF_GIGE_RX); + data |= MLXBF_GIGE_RX_STRIP_CRC_EN; + writeq(data, priv->base + MLXBF_GIGE_RX); + + /* Enable RX MAC filter pass and discard counters */ + writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN, + priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC); + writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN, + priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS); + + /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to + * indicate readiness to receive interrupts + */ + data = readq(priv->base + MLXBF_GIGE_INT_MASK); + data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; + writeq(data, priv->base + MLXBF_GIGE_INT_MASK); + + /* Enable RX DMA to write new packets to memory */ + writeq(MLXBF_GIGE_RX_DMA_EN, priv->base + MLXBF_GIGE_RX_DMA); + + writeq(ilog2(priv->rx_q_entries), + priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); + + return 0; + +free_wqe_and_skb: + rx_wqe_ptr = priv->rx_wqe_base; + for (j = 0; j < i; j++) { + dma_unmap_single(priv->dev, *rx_wqe_ptr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + dev_kfree_skb(priv->rx_skb[j]); + rx_wqe_ptr++; + } + dma_free_coherent(priv->dev, wq_size, + priv->rx_wqe_base, priv->rx_wqe_base_dma); + return -ENOMEM; +} + +/* Transmit Initialization + * 1) Allocates TX WQE array using coherent DMA mapping + * 2) Allocates TX completion counter using coherent DMA mapping + */ +static int mlxbf_gige_tx_init(struct mlxbf_gige *priv) +{ + size_t size; + + size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; + priv->tx_wqe_base = dma_alloc_coherent(priv->dev, size, + &priv->tx_wqe_base_dma, + GFP_KERNEL); + if (!priv->tx_wqe_base) + return -ENOMEM; + + priv->tx_wqe_next = priv->tx_wqe_base; + + /* Write TX WQE base address into MMIO reg */ + writeq(priv->tx_wqe_base_dma, priv->base + MLXBF_GIGE_TX_WQ_BASE); + + /* Allocate address for TX completion count */ + priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, + &priv->tx_cc_dma, GFP_KERNEL); + if (!priv->tx_cc) { + dma_free_coherent(priv->dev, size, + priv->tx_wqe_base, priv->tx_wqe_base_dma); + return -ENOMEM; + } + + /* Write TX CC base address into MMIO reg */ + writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); + + writeq(ilog2(priv->tx_q_entries), + priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); + + priv->prev_tx_ci = 0; + priv->tx_pi = 0; + + return 0; +} + +/* Receive Deinitialization + * This routine will free allocations done by mlxbf_gige_rx_init(), + * namely the RX WQE and RX CQE arrays, as well as all RX buffers + */ +static void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) +{ + dma_addr_t *rx_wqe_ptr; + size_t size; + int i; + + rx_wqe_ptr = priv->rx_wqe_base; + + for (i = 0; i < priv->rx_q_entries; i++) { + dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ, + DMA_FROM_DEVICE); + dev_kfree_skb(priv->rx_skb[i]); + rx_wqe_ptr++; + } + + size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; + dma_free_coherent(priv->dev, size, + priv->rx_wqe_base, priv->rx_wqe_base_dma); + + size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; + dma_free_coherent(priv->dev, size, + priv->rx_cqe_base, priv->rx_cqe_base_dma); + + priv->rx_wqe_base = NULL; + priv->rx_wqe_base_dma = 0; + priv->rx_cqe_base = NULL; + priv->rx_cqe_base_dma = 0; + writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE); + writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE); +} + +/* Transmit Deinitialization + * This routine will free allocations done by mlxbf_gige_tx_init(), + * namely the TX WQE array and the TX completion counter + */ +static void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) +{ + u64 *tx_wqe_addr; + size_t size; + int i; + + tx_wqe_addr = priv->tx_wqe_base; + + for (i = 0; i < priv->tx_q_entries; i++) { + if (priv->tx_skb[i]) { + dma_unmap_single(priv->dev, *tx_wqe_addr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); + dev_kfree_skb(priv->tx_skb[i]); + priv->tx_skb[i] = NULL; + } + tx_wqe_addr += 2; + } + + size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; + dma_free_coherent(priv->dev, size, + priv->tx_wqe_base, priv->tx_wqe_base_dma); + + dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, + priv->tx_cc, priv->tx_cc_dma); + + priv->tx_wqe_base = NULL; + priv->tx_wqe_base_dma = 0; + priv->tx_cc = NULL; + priv->tx_cc_dma = 0; + priv->tx_wqe_next = NULL; + writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE); + writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); +} + +/* Start of struct ethtool_ops functions */ +static int mlxbf_gige_get_regs_len(struct net_device *netdev) +{ + return MLXBF_GIGE_MMIO_REG_SZ; +} + +static void mlxbf_gige_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + regs->version = MLXBF_GIGE_REGS_VERSION; + + /* Read entire MMIO register space and store results + * into the provided buffer. Each 64-bit word is converted + * to big-endian to make the output more readable. + * + * NOTE: by design, a read to an offset without an existing + * register will be acknowledged and return zero. + */ + memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); +} + +static void mlxbf_gige_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; + ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; + ering->rx_pending = priv->rx_q_entries; + ering->tx_pending = priv->tx_q_entries; +} + +static int mlxbf_gige_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + const struct net_device_ops *ops = netdev->netdev_ops; + struct mlxbf_gige *priv = netdev_priv(netdev); + int new_rx_q_entries, new_tx_q_entries; + + /* Device does not have separate queues for small/large frames */ + if (ering->rx_mini_pending || ering->rx_jumbo_pending) + return -EINVAL; + + /* Round up to supported values */ + new_rx_q_entries = roundup_pow_of_two(ering->rx_pending); + new_tx_q_entries = roundup_pow_of_two(ering->tx_pending); + + /* Check against min values, core checks against max values */ + if (new_tx_q_entries < MLXBF_GIGE_MIN_TXQ_SZ || + new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ) + return -EINVAL; + + /* If queue sizes did not change, exit now */ + if (new_rx_q_entries == priv->rx_q_entries && + new_tx_q_entries == priv->tx_q_entries) + return 0; + + if (netif_running(netdev)) + ops->ndo_stop(netdev); + + priv->rx_q_entries = new_rx_q_entries; + priv->tx_q_entries = new_tx_q_entries; + + if (netif_running(netdev)) + ops->ndo_open(netdev); + + return 0; +} + +static const struct { + const char string[ETH_GSTRING_LEN]; +} mlxbf_gige_ethtool_stats_keys[] = { + { "hw_access_errors" }, + { "tx_invalid_checksums" }, + { "tx_small_frames" }, + { "tx_index_errors" }, + { "sw_config_errors" }, + { "sw_access_errors" }, + { "rx_truncate_errors" }, + { "rx_mac_errors" }, + { "rx_din_dropped_pkts" }, + { "tx_fifo_full" }, + { "rx_filter_passed_pkts" }, + { "rx_filter_discard_pkts" }, +}; + +static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) +{ + if (stringset != ETH_SS_STATS) + return -EOPNOTSUPP; + return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); +} + +static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, + u8 *buf) +{ + if (stringset != ETH_SS_STATS) + return; + memcpy(buf, &mlxbf_gige_ethtool_stats_keys, + sizeof(mlxbf_gige_ethtool_stats_keys)); +} + +static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *estats, + u64 *data) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + /* Fill data array with interface statistics + * + * NOTE: the data writes must be in + * sync with the strings shown in + * the mlxbf_gige_ethtool_stats_keys[] array + * + * NOTE2: certain statistics below are zeroed upon + * port disable, so the calculation below + * must include the "cached" value of the stat + * plus the value read directly from hardware. + * Cached statistics are currently: + * rx_din_dropped_pkts + * rx_filter_passed_pkts + * rx_filter_discard_pkts + */ + *data++ = priv->stats.hw_access_errors; + *data++ = priv->stats.tx_invalid_checksums; + *data++ = priv->stats.tx_small_frames; + *data++ = priv->stats.tx_index_errors; + *data++ = priv->stats.sw_config_errors; + *data++ = priv->stats.sw_access_errors; + *data++ = priv->stats.rx_truncate_errors; + *data++ = priv->stats.rx_mac_errors; + *data++ = (priv->stats.rx_din_dropped_pkts + + readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); + *data++ = priv->stats.tx_fifo_full; + *data++ = (priv->stats.rx_filter_passed_pkts + + readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); + *data++ = (priv->stats.rx_filter_discard_pkts + + readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); +} + +static void mlxbf_gige_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + pause->autoneg = priv->aneg_pause; + pause->rx_pause = priv->tx_pause; + pause->tx_pause = priv->rx_pause; +} + +static const struct ethtool_ops mlxbf_gige_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_ringparam = mlxbf_gige_get_ringparam, + .set_ringparam = mlxbf_gige_set_ringparam, + .get_regs_len = mlxbf_gige_get_regs_len, + .get_regs = mlxbf_gige_get_regs, + .get_strings = mlxbf_gige_get_strings, + .get_sset_count = mlxbf_gige_get_sset_count, + .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, + .nway_reset = phy_ethtool_nway_reset, + .get_pauseparam = mlxbf_gige_get_pauseparam, + .get_link_ksettings = phy_ethtool_get_link_ksettings, +}; + +/* Start of struct net_device_ops functions */ +static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) +{ + struct mlxbf_gige *priv; + u64 int_status; + + priv = dev_id; + + priv->error_intr_count++; + + int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); + + if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) + priv->stats.hw_access_errors++; + + if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { + priv->stats.tx_invalid_checksums++; + /* This error condition is latched into MLXBF_GIGE_INT_STATUS + * when the GigE silicon operates on the offending + * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom + * of this routine clears this error condition. */ - eth_hw_addr_random(priv->netdev); } - local_mac = ether_addr_to_u64(priv->netdev->dev_addr); - mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, - local_mac); + if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) { + priv->stats.tx_small_frames++; + /* This condition happens when the networking stack invokes + * this driver's "start_xmit()" method with a packet whose + * size < 60 bytes. The GigE silicon will automatically pad + * this small frame up to a minimum-sized frame before it is + * sent. The "tx_small_frame" condition is latched into the + * MLXBF_GIGE_INT_STATUS register when the GigE silicon + * operates on the offending TX WQE. The write to + * MLXBF_GIGE_INT_STATUS at the bottom of this routine + * clears this condition. + */ + } + + if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) + priv->stats.tx_index_errors++; + + if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) + priv->stats.sw_config_errors++; + + if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) + priv->stats.sw_access_errors++; + + /* Clear all error interrupts by writing '1' back to + * all the asserted bits in INT_STATUS. Do not write + * '1' back to 'receive packet' bit, since that is + * managed separately. + */ + + int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET; + + writeq(int_status, priv->base + MLXBF_GIGE_INT_STATUS); + + return IRQ_HANDLED; +} + +static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) +{ + struct mlxbf_gige *priv; + + priv = dev_id; + + priv->rx_intr_count++; + + /* NOTE: GigE silicon automatically disables "packet rx" interrupt by + * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt + * to the ARM cores. Software needs to re-enable "packet rx" + * interrupts by clearing MLXBF_GIGE_INT_MASK bit0. + */ + + napi_schedule(&priv->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) +{ + struct mlxbf_gige *priv; + + priv = dev_id; + priv->llu_plu_intr_count++; + + return IRQ_HANDLED; +} + +/* Function that returns status of TX ring: + * 0: TX ring is full, i.e. there are no + * available un-used entries in TX ring. + * non-null: TX ring is not full, i.e. there are + * some available entries in TX ring. + * The non-null value is a measure of + * how many TX entries are available, but + * it is not the exact number of available + * entries (see below). + * + * The algorithm makes the assumption that if + * (prev_tx_ci == tx_pi) then the TX ring is empty. + * An empty ring actually has (tx_q_entries-1) + * entries, which allows the algorithm to differentiate + * the case of an empty ring vs. a full ring. + */ +static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) +{ + unsigned long flags; + u16 avail; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->prev_tx_ci == priv->tx_pi) + avail = priv->tx_q_entries - 1; + else + avail = ((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) + % priv->tx_q_entries) - 1; + + spin_unlock_irqrestore(&priv->lock, flags); + + return avail; +} + +static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) +{ + struct net_device_stats *stats; + u16 tx_wqe_index; + u64 *tx_wqe_addr; + u64 tx_status; + u16 tx_ci; + + tx_status = readq(priv->base + MLXBF_GIGE_TX_STATUS); + if (tx_status & MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL) + priv->stats.tx_fifo_full++; + tx_ci = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); + stats = &priv->netdev->stats; + + /* Transmit completion logic needs to loop until the completion + * index (in SW) equals TX consumer index (from HW). These + * parameters are unsigned 16-bit values and the wrap case needs + * to be supported, that is TX consumer index wrapped from 0xFFFF + * to 0 while TX completion index is still < 0xFFFF. + */ + for (; priv->prev_tx_ci != tx_ci; priv->prev_tx_ci++) { + tx_wqe_index = priv->prev_tx_ci % priv->tx_q_entries; + /* Each TX WQE is 16 bytes. The 8 MSB store the 2KB TX + * buffer address and the 8 LSB contain information + * about the TX WQE. + */ + tx_wqe_addr = priv->tx_wqe_base + + (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS); + + stats->tx_packets++; + stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); + + dma_unmap_single(priv->dev, *tx_wqe_addr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); + dev_consume_skb_any(priv->tx_skb[tx_wqe_index]); + priv->tx_skb[tx_wqe_index] = NULL; + } + + /* Since the TX ring was likely just drained, check if TX queue + * had previously been stopped and now that there are TX buffers + * available the TX queue can be awakened. + */ + if (netif_queue_stopped(priv->netdev) && + mlxbf_gige_tx_buffs_avail(priv)) + netif_wake_queue(priv->netdev); + + return true; +} + +static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) +{ + struct net_device *netdev = priv->netdev; + u16 rx_pi_rem, rx_ci_rem; + dma_addr_t rx_buf_dma; + struct sk_buff *skb; + u64 *rx_cqe_addr; + u64 *rx_wqe_addr; + u64 datalen; + u64 rx_cqe; + u16 rx_ci; + u16 rx_pi; + + /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ + rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); + rx_pi_rem = rx_pi % priv->rx_q_entries; + rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem; + dma_unmap_single(priv->dev, *rx_wqe_addr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; + rx_cqe = *rx_cqe_addr; + + if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { + /* Packet is OK, increment stats */ + datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += datalen; + + skb = priv->rx_skb[rx_pi_rem]; + + skb_put(skb, datalen); + + skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ + + skb->protocol = eth_type_trans(skb, netdev); + netif_receive_skb(skb); + + /* Alloc another RX SKB for this same index */ + priv->rx_skb[rx_pi_rem] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, + DMA_FROM_DEVICE); + if (!priv->rx_skb[rx_pi_rem]) { + netdev->stats.rx_dropped++; + return false; + } + + *rx_wqe_addr = rx_buf_dma; + } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { + priv->stats.rx_mac_errors++; + } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { + priv->stats.rx_truncate_errors++; + } + + /* Let hardware know we've replenished one buffer */ + rx_pi++; + writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); + + (*rx_pkts)++; + + rx_pi_rem = rx_pi % priv->rx_q_entries; + rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); + rx_ci_rem = rx_ci % priv->rx_q_entries; + + return rx_pi_rem != rx_ci_rem; +} + +/* Driver poll() function called by NAPI infrastructure */ +static int mlxbf_gige_poll(struct napi_struct *napi, int budget) +{ + struct mlxbf_gige *priv; + bool remaining_pkts; + int work_done = 0; + u64 data; + + priv = container_of(napi, struct mlxbf_gige, napi); + + mlxbf_gige_handle_tx_complete(priv); + + do { + remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done); + } while (remaining_pkts && work_done < budget); + + /* If amount of work done < budget, turn off NAPI polling + * via napi_complete_done(napi, work_done) and then + * re-enable interrupts. + */ + if (work_done < budget && napi_complete_done(napi, work_done)) { + /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to + * indicate receive readiness + */ + data = readq(priv->base + MLXBF_GIGE_INT_MASK); + data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; + writeq(data, priv->base + MLXBF_GIGE_INT_MASK); + } + + return work_done; +} + +static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) +{ + int err; + + err = request_irq(priv->error_irq, mlxbf_gige_error_intr, 0, + "mlxbf_gige_error", priv); + if (err) { + dev_err(priv->dev, "Request error_irq failure\n"); + return err; + } + + err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0, + "mlxbf_gige_rx", priv); + if (err) { + dev_err(priv->dev, "Request rx_irq failure\n"); + goto free_error_irq; + } + + err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, + "mlxbf_gige_llu_plu", priv); + if (err) { + dev_err(priv->dev, "Request llu_plu_irq failure\n"); + goto free_rx_irq; + } + + err = request_threaded_irq(priv->phy_irq, NULL, + mlxbf_gige_mdio_handle_phy_interrupt, + IRQF_ONESHOT | IRQF_SHARED, + "mlxbf_gige_phy", priv); + if (err) { + dev_err(priv->dev, "Request phy_irq failure\n"); + goto free_llu_plu_irq; + } + + return 0; + +free_llu_plu_irq: + free_irq(priv->llu_plu_irq, priv); + +free_rx_irq: + free_irq(priv->rx_irq, priv); + +free_error_irq: + free_irq(priv->error_irq, priv); + + return err; +} + +static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) +{ + free_irq(priv->error_irq, priv); + free_irq(priv->rx_irq, priv); + free_irq(priv->llu_plu_irq, priv); + free_irq(priv->phy_irq, priv); } static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) @@ -126,6 +862,38 @@ static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) return err; } +static int mlxbf_gige_phy_enable_interrupt(struct phy_device *phydev) +{ + int err = 0; + + if (phydev->drv->ack_interrupt) + err = phydev->drv->ack_interrupt(phydev); + if (err < 0) + return err; + + phydev->interrupts = PHY_INTERRUPT_ENABLED; + if (phydev->drv->config_intr) + err = phydev->drv->config_intr(phydev); + + return err; +} + +static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) +{ + int err = 0; + + if (phydev->drv->ack_interrupt) + err = phydev->drv->ack_interrupt(phydev); + if (err < 0) + return err; + + phydev->interrupts = PHY_INTERRUPT_DISABLED; + if (phydev->drv->config_intr) + err = phydev->drv->config_intr(phydev); + + return err; +} + static int mlxbf_gige_open(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); @@ -148,6 +916,14 @@ static int mlxbf_gige_open(struct net_device *netdev) return err; phy_start(phydev); + /* Always make sure interrupts are enabled since phy_start calls + * __phy_resume which may reset the PHY interrupt control reg. + * __phy_resume only reenables the interrupts if + * phydev->irq != IRQ_IGNORE_INTERRUPT. + */ + err = mlxbf_gige_phy_enable_interrupt(phydev); + if (err) + return err; netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); napi_enable(&priv->napi); @@ -177,6 +953,7 @@ static int mlxbf_gige_stop(struct net_device *netdev) mlxbf_gige_free_irqs(priv); phy_stop(netdev->phydev); + mlxbf_gige_phy_disable_interrupt(netdev->phydev); mlxbf_gige_rx_deinit(priv); mlxbf_gige_tx_deinit(priv); @@ -186,6 +963,110 @@ static int mlxbf_gige_stop(struct net_device *netdev) return 0; } +/* Function to advance the tx_wqe_next pointer to next TX WQE */ +static void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv) +{ + /* Advance tx_wqe_next pointer */ + priv->tx_wqe_next += MLXBF_GIGE_TX_WQE_SZ_QWORDS; + + /* Check if 'next' pointer is beyond end of TX ring */ + /* If so, set 'next' back to 'base' pointer of ring */ + if (priv->tx_wqe_next == (priv->tx_wqe_base + + (priv->tx_q_entries * MLXBF_GIGE_TX_WQE_SZ_QWORDS))) + priv->tx_wqe_next = priv->tx_wqe_base; +} + +static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + u64 buff_addr, start_dma_page, end_dma_page; + struct sk_buff *tx_skb; + dma_addr_t tx_buf_dma; + u64 *tx_wqe_addr; + u64 word2; + + /* If needed, linearize TX SKB as hardware DMA expects this */ + if (skb_linearize(skb)) { + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NET_XMIT_DROP; + } + + buff_addr = (u64)skb->data; + start_dma_page = buff_addr >> MLXBF_GIGE_DMA_PAGE_SHIFT; + end_dma_page = (buff_addr + skb->len - 1) >> MLXBF_GIGE_DMA_PAGE_SHIFT; + + /* Verify that payload pointer and data length of SKB to be + * transmitted does not violate the hardware DMA limitation. + */ + if (start_dma_page != end_dma_page) { + /* DMA operation would fail as-is, alloc new aligned SKB */ + tx_skb = mlxbf_gige_alloc_skb(priv, &tx_buf_dma, DMA_TO_DEVICE); + if (!tx_skb) { + /* Free original skb, could not alloc new aligned SKB */ + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NET_XMIT_DROP; + } + + skb_put_data(tx_skb, skb->data, skb->len); + dev_kfree_skb(skb); + } else { + tx_skb = skb; + tx_buf_dma = dma_map_single(priv->dev, skb->data, + MLXBF_GIGE_DEFAULT_BUF_SZ, + DMA_TO_DEVICE); + if (dma_mapping_error(priv->dev, tx_buf_dma)) { + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NET_XMIT_DROP; + } + } + + priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; + + /* Get address of TX WQE */ + tx_wqe_addr = priv->tx_wqe_next; + + mlxbf_gige_update_tx_wqe_next(priv); + + /* Put PA of buffer address into first 64-bit word of TX WQE */ + *tx_wqe_addr = tx_buf_dma; + + /* Set TX WQE pkt_len appropriately + * NOTE: GigE silicon will automatically pad up to + * minimum packet length if needed. + */ + word2 = tx_skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; + + /* Write entire 2nd word of TX WQE */ + *(tx_wqe_addr + 1) = word2; + + priv->tx_pi++; + + if (!netdev_xmit_more()) { + /* Create memory barrier before write to TX PI */ + wmb(); + writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); + } + + /* Check if the last TX entry was just used */ + if (!mlxbf_gige_tx_buffs_avail(priv)) { + /* TX ring is full, inform stack */ + netif_stop_queue(netdev); + + /* Since there is no separate "TX complete" interrupt, need + * to explicitly schedule NAPI poll. This will trigger logic + * which processes TX completions, and will hopefully drain + * the TX ring allowing the TX queue to be awakened. + */ + napi_schedule(&priv->napi); + } + + return NETDEV_TX_OK; +} + static int mlxbf_gige_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { @@ -212,8 +1093,8 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) mlxbf_gige_enable_promisc(priv); else mlxbf_gige_disable_promisc(priv); - } -} + } + } static void mlxbf_gige_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) @@ -223,8 +1104,7 @@ static void mlxbf_gige_get_stats64(struct net_device *netdev, netdev_stats_to_stats64(stats, &netdev->stats); stats->rx_length_errors = priv->stats.rx_truncate_errors; - stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts + - readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); + stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts; stats->rx_crc_errors = priv->stats.rx_mac_errors; stats->rx_errors = stats->rx_length_errors + stats->rx_fifo_errors + @@ -245,6 +1125,29 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = { .ndo_get_stats64 = mlxbf_gige_get_stats64, }; +static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) +{ + u8 mac[ETH_ALEN]; + u64 local_mac; + + mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, + &local_mac); + u64_to_ether_addr(local_mac, mac); + + if (is_valid_ether_addr(mac)) { + ether_addr_copy(priv->netdev->dev_addr, mac); + } else { + /* Provide a random MAC if for some reason the device has + * not been configured with a valid MAC address already. + */ + eth_hw_addr_random(priv->netdev); + } + + local_mac = ether_addr_to_u64(priv->netdev->dev_addr); + mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, + local_mac); +} + static void mlxbf_gige_adjust_link(struct net_device *netdev) { /* Only one speed and one duplex supported, simply return */ @@ -252,7 +1155,6 @@ static void mlxbf_gige_adjust_link(struct net_device *netdev) static int mlxbf_gige_probe(struct platform_device *pdev) { - unsigned int phy_int_gpio; struct phy_device *phydev; struct net_device *netdev; struct resource *mac_res; @@ -262,20 +1164,9 @@ static int mlxbf_gige_probe(struct platform_device *pdev) void __iomem *llu_base; void __iomem *plu_base; void __iomem *base; - int addr, version; u64 control; int err = 0; - - if (device_property_read_u32(&pdev->dev, "version", &version)) { - dev_err(&pdev->dev, "Version Info not found\n"); - return -EINVAL; - } - - if (version != (int)DRV_VERSION) { - dev_err(&pdev->dev, "Version Mismatch. Expected %d Returned %d\n", - (int)DRV_VERSION, version); - return -EINVAL; - } + int addr; mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); if (!mac_res) @@ -341,31 +1232,20 @@ static int mlxbf_gige_probe(struct platform_device *pdev) err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (err) { dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); - mlxbf_gige_mdio_remove(priv); return err; } priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX); priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); + priv->phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); - err = device_property_read_u32(&pdev->dev, "phy-int-gpio", &phy_int_gpio); - if (err < 0) - phy_int_gpio = MLXBF_GIGE_DEFAULT_PHY_INT_GPIO; - - priv->phy_irq = irq_find_mapping(NULL, phy_int_gpio); - if (priv->phy_irq == 0) { - mlxbf_gige_mdio_remove(priv); - return -ENODEV; - } phydev = phy_find_first(priv->mdiobus); - if (!phydev) { - mlxbf_gige_mdio_remove(priv); + if (!phydev) return -ENODEV; - } addr = phydev->mdio.addr; - phydev->irq = priv->mdiobus->irq[addr] = priv->phy_irq; + phydev->irq = priv->mdiobus->irq[addr] = PHY_IGNORE_INTERRUPT; /* Sets netdev->phydev to phydev; which will eventually * be used in ioctl calls. @@ -376,7 +1256,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) PHY_INTERFACE_MODE_GMII); if (err) { dev_err(&pdev->dev, "Could not attach to PHY\n"); - mlxbf_gige_mdio_remove(priv); return err; } @@ -402,7 +1281,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); phy_disconnect(phydev); - mlxbf_gige_mdio_remove(priv); return err; } @@ -447,9 +1325,8 @@ static struct platform_driver mlxbf_gige_driver = { module_platform_driver(mlxbf_gige_driver); -MODULE_SOFTDEP("pre: gpio_mlxbf2"); MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); MODULE_AUTHOR("David Thompson "); MODULE_AUTHOR("Asmaa Mnebhi "); MODULE_LICENSE("Dual BSD/GPL"); -MODULE_VERSION(__stringify(DRV_VERSION)); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index af4a754d7c25..636e19cf7050 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -2,7 +2,7 @@ /* MDIO support for Mellanox Gigabit Ethernet driver * - * Copyright (c) 2020-2021 NVIDIA Corporation. + * Copyright (c) 2020 NVIDIA Corporation. */ #include @@ -68,10 +68,17 @@ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ - MLXBF_GIGE_MDIO_PERIOD) | \ + MLXBF_GIGE_MDIO_PERIOD) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) +#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48 +#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 +#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94 +#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 + +#define MLXBF_GIGE_GPIO12_BIT 12 + static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, int phy_reg, u32 opcode) { @@ -142,10 +149,88 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, return ret; } +static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->gpio_lock, flags); + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + val &= ~priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + spin_unlock_irqrestore(&priv->gpio_lock, flags); +} + +static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->gpio_lock, flags); + /* The INT_N interrupt level is active low. + * So enable cause fall bit to detect when GPIO + * state goes low. + */ + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); + + /* Enable PHY interrupt by setting the priority level */ + val = readl(priv->gpio_io + + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + spin_unlock_irqrestore(&priv->gpio_lock, flags); +} + +/* Interrupt handler is called from mlxbf_gige_main.c + * driver whenever a phy interrupt is received. + */ +irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) +{ + struct phy_device *phydev; + struct mlxbf_gige *priv; + u32 val; + + priv = dev_id; + phydev = priv->netdev->phydev; + + /* Check if this interrupt is from PHY device. + * Return if it is not. + */ + val = readl(priv->gpio_io + + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); + if (!(val & priv->phy_int_gpio_mask)) + return IRQ_NONE; + + phy_mac_interrupt(phydev); + + /* Clear interrupt when done, otherwise, no further interrupt + * will be triggered. + */ + val = readl(priv->gpio_io + + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); + + /* Make sure to clear the PHY device interrupt */ + if (phydev->drv->ack_interrupt) + phydev->drv->ack_interrupt(phydev); + + phydev->interrupts = PHY_INTERRUPT_ENABLED; + if (phydev->drv->config_intr) + phydev->drv->config_intr(phydev); + + return IRQ_HANDLED; +} + int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) { struct device *dev = &pdev->dev; struct resource *res; + u32 phy_int_gpio; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); @@ -156,10 +241,25 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) if (IS_ERR(priv->mdio_io)) return PTR_ERR(priv->mdio_io); + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0); + if (!res) + return -ENODEV; + + priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->gpio_io) + return -ENOMEM; + /* Configure mdio parameters */ writel(MLXBF_GIGE_MDIO_CFG_VAL, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); + ret = device_property_read_u32(dev, "phy-int-gpio", &phy_int_gpio); + if (ret < 0) + phy_int_gpio = MLXBF_GIGE_GPIO12_BIT; + priv->phy_int_gpio_mask = BIT(phy_int_gpio); + + mlxbf_gige_mdio_enable_phy_int(priv); + priv->mdiobus = devm_mdiobus_alloc(dev); if (!priv->mdiobus) { dev_err(dev, "Failed to alloc MDIO bus\n"); @@ -183,5 +283,6 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv) { + mlxbf_gige_mdio_disable_phy_int(priv); mdiobus_unregister(priv->mdiobus); } diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index 30ad896f6252..128e12894885 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -2,7 +2,7 @@ /* Header file for Mellanox BlueField GigE register defines * - * Copyright (c) 2020-2021 NVIDIA Corporation. + * Copyright (c) 2020 NVIDIA Corporation. */ #ifndef __MLXBF_GIGE_REGS_H__ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c deleted file mode 100644 index 1cf8be27ef2a..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c +++ /dev/null @@ -1,299 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause - -/* Packet receive logic for Mellanox Gigabit Ethernet driver - * - * Copyright (c) 2020-2021 NVIDIA Corporation. - */ - -#include -#include - -#include "mlxbf_gige.h" -#include "mlxbf_gige_regs.h" - -void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 dmac) -{ - void __iomem *base = priv->base; - u64 control; - - /* Write destination MAC to specified MAC RX filter */ - writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + - (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); - - /* Enable MAC receive filter mask for specified index */ - control = readq(base + MLXBF_GIGE_CONTROL); - control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index); - writeq(control, base + MLXBF_GIGE_CONTROL); -} - -void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 *dmac) -{ - void __iomem *base = priv->base; - - /* Read destination MAC from specified MAC RX filter */ - *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + - (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); -} - -void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) -{ - void __iomem *base = priv->base; - u64 control; - - /* Enable MAC_ID_RANGE match functionality */ - control = readq(base + MLXBF_GIGE_CONTROL); - control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; - writeq(control, base + MLXBF_GIGE_CONTROL); - - /* Set start of destination MAC range check to 0 */ - writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START); - - /* Set end of destination MAC range check to all FFs */ - writeq(0xFFFFFFFFFFFF, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END); -} - -void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) -{ - void __iomem *base = priv->base; - u64 control; - - /* Disable MAC_ID_RANGE match functionality */ - control = readq(base + MLXBF_GIGE_CONTROL); - control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; - writeq(control, base + MLXBF_GIGE_CONTROL); - - /* NOTE: no need to change DMAC_RANGE_START or END; - * those values are ignored since MAC_ID_RANGE_EN=0 - */ -} - -/* Receive Initialization - * 1) Configures RX MAC filters via MMIO registers - * 2) Allocates RX WQE array using coherent DMA mapping - * 3) Initializes each element of RX WQE array with a receive - * buffer pointer (also using coherent DMA mapping) - * 4) Allocates RX CQE array using coherent DMA mapping - * 5) Completes other misc receive initialization - */ -int mlxbf_gige_rx_init(struct mlxbf_gige *priv) -{ - size_t wq_size, cq_size; - dma_addr_t *rx_wqe_ptr; - dma_addr_t rx_buf_dma; - u64 data; - int i, j; - - /* Configure MAC RX filter #0 to allow RX of broadcast pkts */ - mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX, - BCAST_MAC_ADDR); - - wq_size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; - priv->rx_wqe_base = dma_alloc_coherent(priv->dev, wq_size, - &priv->rx_wqe_base_dma, - GFP_KERNEL); - if (!priv->rx_wqe_base) - return -ENOMEM; - - /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array - * Each RX WQE is simply a receive buffer pointer, so walk - * the entire array, allocating a 2KB buffer for each element - */ - rx_wqe_ptr = priv->rx_wqe_base; - - for (i = 0; i < priv->rx_q_entries; i++) { - priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, DMA_FROM_DEVICE); - if (!priv->rx_skb[i]) - goto free_wqe_and_skb; - *rx_wqe_ptr++ = rx_buf_dma; - } - - /* Write RX WQE base address into MMIO reg */ - writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE); - - cq_size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; - priv->rx_cqe_base = dma_alloc_coherent(priv->dev, cq_size, - &priv->rx_cqe_base_dma, - GFP_KERNEL); - if (!priv->rx_cqe_base) - goto free_wqe_and_skb; - - /* Write RX CQE base address into MMIO reg */ - writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); - - /* Write RX_WQE_PI with current number of replenished buffers */ - writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI); - - /* Enable removal of CRC during RX */ - data = readq(priv->base + MLXBF_GIGE_RX); - data |= MLXBF_GIGE_RX_STRIP_CRC_EN; - writeq(data, priv->base + MLXBF_GIGE_RX); - - /* Enable RX MAC filter pass and discard counters */ - writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN, - priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC); - writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN, - priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS); - - /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to - * indicate readiness to receive interrupts - */ - data = readq(priv->base + MLXBF_GIGE_INT_MASK); - data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; - writeq(data, priv->base + MLXBF_GIGE_INT_MASK); - - /* Enable RX DMA to write new packets to memory */ - writeq(MLXBF_GIGE_RX_DMA_EN, priv->base + MLXBF_GIGE_RX_DMA); - - writeq(ilog2(priv->rx_q_entries), - priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); - - return 0; - -free_wqe_and_skb: - rx_wqe_ptr = priv->rx_wqe_base; - for (j = 0; j < i; j++) { - dma_unmap_single(priv->dev, *rx_wqe_ptr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); - dev_kfree_skb(priv->rx_skb[j]); - rx_wqe_ptr++; - } - dma_free_coherent(priv->dev, wq_size, - priv->rx_wqe_base, priv->rx_wqe_base_dma); - return -ENOMEM; -} - -/* Receive Deinitialization - * This routine will free allocations done by mlxbf_gige_rx_init(), - * namely the RX WQE and RX CQE arrays, as well as all RX buffers - */ -void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) -{ - dma_addr_t *rx_wqe_ptr; - size_t size; - int i; - - rx_wqe_ptr = priv->rx_wqe_base; - - for (i = 0; i < priv->rx_q_entries; i++) { - dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ, - DMA_FROM_DEVICE); - dev_kfree_skb(priv->rx_skb[i]); - rx_wqe_ptr++; - } - - size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; - dma_free_coherent(priv->dev, size, - priv->rx_wqe_base, priv->rx_wqe_base_dma); - - size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; - dma_free_coherent(priv->dev, size, - priv->rx_cqe_base, priv->rx_cqe_base_dma); - - priv->rx_wqe_base = NULL; - priv->rx_wqe_base_dma = 0; - priv->rx_cqe_base = NULL; - priv->rx_cqe_base_dma = 0; - writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE); - writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE); -} - -static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) -{ - struct net_device *netdev = priv->netdev; - u16 rx_pi_rem, rx_ci_rem; - dma_addr_t *rx_wqe_addr; - dma_addr_t rx_buf_dma; - struct sk_buff *skb; - u64 *rx_cqe_addr; - u64 datalen; - u64 rx_cqe; - u16 rx_ci; - u16 rx_pi; - - /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ - rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); - rx_pi_rem = rx_pi % priv->rx_q_entries; - rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem; - - dma_unmap_single(priv->dev, *rx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); - - rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; - rx_cqe = *rx_cqe_addr; - - if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { - /* Packet is OK, increment stats */ - datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; - netdev->stats.rx_packets++; - netdev->stats.rx_bytes += datalen; - - skb = priv->rx_skb[rx_pi_rem]; - - skb_put(skb, datalen); - - skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ - - skb->protocol = eth_type_trans(skb, netdev); - netif_receive_skb(skb); - - /* Alloc another RX SKB for this same index */ - priv->rx_skb[rx_pi_rem] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, - DMA_FROM_DEVICE); - if (!priv->rx_skb[rx_pi_rem]) { - netdev->stats.rx_dropped++; - return false; - } - - *rx_wqe_addr = rx_buf_dma; - } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { - priv->stats.rx_mac_errors++; - } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { - priv->stats.rx_truncate_errors++; - } - - /* Let hardware know we've replenished one buffer */ - rx_pi++; - writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); - - (*rx_pkts)++; - - rx_pi_rem = rx_pi % priv->rx_q_entries; - rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); - rx_ci_rem = rx_ci % priv->rx_q_entries; - - return rx_pi_rem != rx_ci_rem; -} - -/* Driver poll() function called by NAPI infrastructure */ -int mlxbf_gige_poll(struct napi_struct *napi, int budget) -{ - struct mlxbf_gige *priv; - bool remaining_pkts; - int work_done = 0; - u64 data; - - priv = container_of(napi, struct mlxbf_gige, napi); - - mlxbf_gige_handle_tx_complete(priv); - - do { - remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done); - } while (remaining_pkts && work_done < budget); - - /* If amount of work done < budget, turn off NAPI polling - * via napi_complete_done(napi, work_done) and then - * re-enable interrupts. - */ - if (work_done < budget && napi_complete_done(napi, work_done)) { - /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to - * indicate receive readiness - */ - data = readq(priv->base + MLXBF_GIGE_INT_MASK); - data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; - writeq(data, priv->base + MLXBF_GIGE_INT_MASK); - } - - return work_done; -} diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c deleted file mode 100644 index 257dd0238129..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c +++ /dev/null @@ -1,279 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause - -/* Packet transmit logic for Mellanox Gigabit Ethernet driver - * - * Copyright (c) 2020-2021 NVIDIA Corporation. - */ - -#include - -#include "mlxbf_gige.h" -#include "mlxbf_gige_regs.h" - -/* Transmit Initialization - * 1) Allocates TX WQE array using coherent DMA mapping - * 2) Allocates TX completion counter using coherent DMA mapping - */ -int mlxbf_gige_tx_init(struct mlxbf_gige *priv) -{ - size_t size; - - size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; - priv->tx_wqe_base = dma_alloc_coherent(priv->dev, size, - &priv->tx_wqe_base_dma, - GFP_KERNEL); - if (!priv->tx_wqe_base) - return -ENOMEM; - - priv->tx_wqe_next = priv->tx_wqe_base; - - /* Write TX WQE base address into MMIO reg */ - writeq(priv->tx_wqe_base_dma, priv->base + MLXBF_GIGE_TX_WQ_BASE); - - /* Allocate address for TX completion count */ - priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, - &priv->tx_cc_dma, GFP_KERNEL); - if (!priv->tx_cc) { - dma_free_coherent(priv->dev, size, - priv->tx_wqe_base, priv->tx_wqe_base_dma); - return -ENOMEM; - } - - /* Write TX CC base address into MMIO reg */ - writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); - - writeq(ilog2(priv->tx_q_entries), - priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); - - priv->prev_tx_ci = 0; - priv->tx_pi = 0; - - return 0; -} - -/* Transmit Deinitialization - * This routine will free allocations done by mlxbf_gige_tx_init(), - * namely the TX WQE array and the TX completion counter - */ -void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) -{ - u64 *tx_wqe_addr; - size_t size; - int i; - - tx_wqe_addr = priv->tx_wqe_base; - - for (i = 0; i < priv->tx_q_entries; i++) { - if (priv->tx_skb[i]) { - dma_unmap_single(priv->dev, *tx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); - dev_kfree_skb(priv->tx_skb[i]); - priv->tx_skb[i] = NULL; - } - tx_wqe_addr += 2; - } - - size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; - dma_free_coherent(priv->dev, size, - priv->tx_wqe_base, priv->tx_wqe_base_dma); - - dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, - priv->tx_cc, priv->tx_cc_dma); - - priv->tx_wqe_base = NULL; - priv->tx_wqe_base_dma = 0; - priv->tx_cc = NULL; - priv->tx_cc_dma = 0; - priv->tx_wqe_next = NULL; - writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE); - writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); -} - -/* Function that returns status of TX ring: - * 0: TX ring is full, i.e. there are no - * available un-used entries in TX ring. - * non-null: TX ring is not full, i.e. there are - * some available entries in TX ring. - * The non-null value is a measure of - * how many TX entries are available, but - * it is not the exact number of available - * entries (see below). - * - * The algorithm makes the assumption that if - * (prev_tx_ci == tx_pi) then the TX ring is empty. - * An empty ring actually has (tx_q_entries-1) - * entries, which allows the algorithm to differentiate - * the case of an empty ring vs. a full ring. - */ -static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) -{ - unsigned long flags; - u16 avail; - - spin_lock_irqsave(&priv->lock, flags); - - if (priv->prev_tx_ci == priv->tx_pi) - avail = priv->tx_q_entries - 1; - else - avail = ((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) - % priv->tx_q_entries) - 1; - - spin_unlock_irqrestore(&priv->lock, flags); - - return avail; -} - -bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) -{ - struct net_device_stats *stats; - u16 tx_wqe_index; - u64 *tx_wqe_addr; - u64 tx_status; - u16 tx_ci; - - tx_status = readq(priv->base + MLXBF_GIGE_TX_STATUS); - if (tx_status & MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL) - priv->stats.tx_fifo_full++; - tx_ci = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); - stats = &priv->netdev->stats; - - /* Transmit completion logic needs to loop until the completion - * index (in SW) equals TX consumer index (from HW). These - * parameters are unsigned 16-bit values and the wrap case needs - * to be supported, that is TX consumer index wrapped from 0xFFFF - * to 0 while TX completion index is still < 0xFFFF. - */ - for (; priv->prev_tx_ci != tx_ci; priv->prev_tx_ci++) { - tx_wqe_index = priv->prev_tx_ci % priv->tx_q_entries; - /* Each TX WQE is 16 bytes. The 8 MSB store the 2KB TX - * buffer address and the 8 LSB contain information - * about the TX WQE. - */ - tx_wqe_addr = priv->tx_wqe_base + - (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS); - - stats->tx_packets++; - stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); - - dma_unmap_single(priv->dev, *tx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); - dev_consume_skb_any(priv->tx_skb[tx_wqe_index]); - priv->tx_skb[tx_wqe_index] = NULL; - } - - /* Since the TX ring was likely just drained, check if TX queue - * had previously been stopped and now that there are TX buffers - * available the TX queue can be awakened. - */ - if (netif_queue_stopped(priv->netdev) && - mlxbf_gige_tx_buffs_avail(priv)) - netif_wake_queue(priv->netdev); - - return true; -} - -/* Function to advance the tx_wqe_next pointer to next TX WQE */ -void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv) -{ - /* Advance tx_wqe_next pointer */ - priv->tx_wqe_next += MLXBF_GIGE_TX_WQE_SZ_QWORDS; - - /* Check if 'next' pointer is beyond end of TX ring */ - /* If so, set 'next' back to 'base' pointer of ring */ - if (priv->tx_wqe_next == (priv->tx_wqe_base + - (priv->tx_q_entries * MLXBF_GIGE_TX_WQE_SZ_QWORDS))) - priv->tx_wqe_next = priv->tx_wqe_base; -} - -netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - long buff_addr, start_dma_page, end_dma_page; - struct sk_buff *tx_skb; - dma_addr_t tx_buf_dma; - u64 *tx_wqe_addr; - u64 word2; - - /* If needed, linearize TX SKB as hardware DMA expects this */ - if (skb_linearize(skb)) { - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - buff_addr = (long)skb->data; - start_dma_page = buff_addr >> MLXBF_GIGE_DMA_PAGE_SHIFT; - end_dma_page = (buff_addr + skb->len - 1) >> MLXBF_GIGE_DMA_PAGE_SHIFT; - - /* Verify that payload pointer and data length of SKB to be - * transmitted does not violate the hardware DMA limitation. - */ - if (start_dma_page != end_dma_page) { - /* DMA operation would fail as-is, alloc new aligned SKB */ - tx_skb = mlxbf_gige_alloc_skb(priv, &tx_buf_dma, DMA_TO_DEVICE); - if (!tx_skb) { - /* Free original skb, could not alloc new aligned SKB */ - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - - skb_put_data(tx_skb, skb->data, skb->len); - - /* Free the original SKB */ - dev_kfree_skb(skb); - } else { - tx_skb = skb; - tx_buf_dma = dma_map_single(priv->dev, skb->data, - MLXBF_GIGE_DEFAULT_BUF_SZ, - DMA_TO_DEVICE); - if (dma_mapping_error(priv->dev, tx_buf_dma)) { - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; - return NETDEV_TX_OK; - } - } - - priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; - - /* Get address of TX WQE */ - tx_wqe_addr = priv->tx_wqe_next; - - mlxbf_gige_update_tx_wqe_next(priv); - - /* Put PA of buffer address into first 64-bit word of TX WQE */ - *tx_wqe_addr = tx_buf_dma; - - /* Set TX WQE pkt_len appropriately - * NOTE: GigE silicon will automatically pad up to - * minimum packet length if needed. - */ - word2 = tx_skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; - - /* Write entire 2nd word of TX WQE */ - *(tx_wqe_addr + 1) = word2; - - priv->tx_pi++; - - if (!netdev_xmit_more()) { - /* Create memory barrier before write to TX PI */ - wmb(); - writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); - } - - /* Check if the last TX entry was just used */ - if (!mlxbf_gige_tx_buffs_avail(priv)) { - /* TX ring is full, inform stack */ - netif_stop_queue(netdev); - - /* Since there is no separate "TX complete" interrupt, need - * to explicitly schedule NAPI poll. This will trigger logic - * which processes TX completions, and will hopefully drain - * the TX ring allowing the TX queue to be awakened. - */ - napi_schedule(&priv->napi); - } - - return NETDEV_TX_OK; -} From patchwork Fri Jul 9 19:08:12 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503321 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2kz0HTRz9sRN; Sat, 10 Jul 2021 05:08:59 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrr-0003Bo-2d; Fri, 09 Jul 2021 19:08:55 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrn-00039R-3c for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:47 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8l8t030202; Fri, 9 Jul 2021 15:08:47 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8lRB005458; Fri, 9 Jul 2021 15:08:47 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 05/23] Revert "Revert "UBUNTU: SAUCE: Fix intermittent OOB link up issue"" Date: Fri, 9 Jul 2021 15:08:12 -0400 Message-Id: <20210709190830.5405-6-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 846c602c6b93c9ff08abc6615973efcdd35a92bb. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 39 +++++-------------- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 4 +- 2 files changed, 12 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 85a7ce19a6ff..63ea74ad5ee5 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -21,7 +21,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.10" +#define DRV_VERSION "1.14" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -862,34 +862,18 @@ static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) return err; } -static int mlxbf_gige_phy_enable_interrupt(struct phy_device *phydev) +static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) { int err = 0; - if (phydev->drv->ack_interrupt) - err = phydev->drv->ack_interrupt(phydev); - if (err < 0) - return err; - - phydev->interrupts = PHY_INTERRUPT_ENABLED; + phydev->interrupts = PHY_INTERRUPT_DISABLED; if (phydev->drv->config_intr) err = phydev->drv->config_intr(phydev); - - return err; -} - -static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) -{ - int err = 0; - - if (phydev->drv->ack_interrupt) - err = phydev->drv->ack_interrupt(phydev); if (err < 0) return err; - phydev->interrupts = PHY_INTERRUPT_DISABLED; - if (phydev->drv->config_intr) - err = phydev->drv->config_intr(phydev); + if (phydev->drv->ack_interrupt) + err = phydev->drv->ack_interrupt(phydev); return err; } @@ -915,15 +899,10 @@ static int mlxbf_gige_open(struct net_device *netdev) if (err) return err; + phydev->irq = priv->phy_irq; + mlxbf_gige_mdio_enable_phy_int(priv); + phy_start(phydev); - /* Always make sure interrupts are enabled since phy_start calls - * __phy_resume which may reset the PHY interrupt control reg. - * __phy_resume only reenables the interrupts if - * phydev->irq != IRQ_IGNORE_INTERRUPT. - */ - err = mlxbf_gige_phy_enable_interrupt(phydev); - if (err) - return err; netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); napi_enable(&priv->napi); @@ -1292,6 +1271,8 @@ static int mlxbf_gige_remove(struct platform_device *pdev) struct mlxbf_gige *priv = platform_get_drvdata(pdev); unregister_netdev(priv->netdev); + priv->netdev->phydev->irq = PHY_IGNORE_INTERRUPT; + mlxbf_gige_phy_disable_interrupt(priv->netdev->phydev); phy_disconnect(priv->netdev->phydev); mlxbf_gige_mdio_remove(priv); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 636e19cf7050..4b063330ec28 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -161,7 +161,7 @@ static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv) spin_unlock_irqrestore(&priv->gpio_lock, flags); } -static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) +void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) { unsigned long flags; u32 val; @@ -258,7 +258,7 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) phy_int_gpio = MLXBF_GIGE_GPIO12_BIT; priv->phy_int_gpio_mask = BIT(phy_int_gpio); - mlxbf_gige_mdio_enable_phy_int(priv); + mlxbf_gige_mdio_disable_phy_int(priv); priv->mdiobus = devm_mdiobus_alloc(dev); if (!priv->mdiobus) { From patchwork Fri Jul 9 19:08:13 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503322 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2kz72Wvz9sWl; Sat, 10 Jul 2021 05:08:59 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrr-0003C9-Bz; Fri, 09 Jul 2021 19:08:55 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrn-00039Q-3c for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:48 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8mCj030205; Fri, 9 Jul 2021 15:08:48 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8mR0005459; Fri, 9 Jul 2021 15:08:48 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 06/23] Revert "UBUNTU: SAUCE: Fix intermittent OOB link up issue" Date: Fri, 9 Jul 2021 15:08:13 -0400 Message-Id: <20210709190830.5405-7-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit a354f8cd7c1e1e7c89a314c1ffc8c724e52758fc. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 39 ++++++++++++++----- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 4 +- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 63ea74ad5ee5..85a7ce19a6ff 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -21,7 +21,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.14" +#define DRV_VERSION "1.10" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -862,18 +862,34 @@ static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) return err; } -static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) +static int mlxbf_gige_phy_enable_interrupt(struct phy_device *phydev) { int err = 0; - phydev->interrupts = PHY_INTERRUPT_DISABLED; - if (phydev->drv->config_intr) - err = phydev->drv->config_intr(phydev); + if (phydev->drv->ack_interrupt) + err = phydev->drv->ack_interrupt(phydev); if (err < 0) return err; + phydev->interrupts = PHY_INTERRUPT_ENABLED; + if (phydev->drv->config_intr) + err = phydev->drv->config_intr(phydev); + + return err; +} + +static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) +{ + int err = 0; + if (phydev->drv->ack_interrupt) err = phydev->drv->ack_interrupt(phydev); + if (err < 0) + return err; + + phydev->interrupts = PHY_INTERRUPT_DISABLED; + if (phydev->drv->config_intr) + err = phydev->drv->config_intr(phydev); return err; } @@ -899,10 +915,15 @@ static int mlxbf_gige_open(struct net_device *netdev) if (err) return err; - phydev->irq = priv->phy_irq; - mlxbf_gige_mdio_enable_phy_int(priv); - phy_start(phydev); + /* Always make sure interrupts are enabled since phy_start calls + * __phy_resume which may reset the PHY interrupt control reg. + * __phy_resume only reenables the interrupts if + * phydev->irq != IRQ_IGNORE_INTERRUPT. + */ + err = mlxbf_gige_phy_enable_interrupt(phydev); + if (err) + return err; netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); napi_enable(&priv->napi); @@ -1271,8 +1292,6 @@ static int mlxbf_gige_remove(struct platform_device *pdev) struct mlxbf_gige *priv = platform_get_drvdata(pdev); unregister_netdev(priv->netdev); - priv->netdev->phydev->irq = PHY_IGNORE_INTERRUPT; - mlxbf_gige_phy_disable_interrupt(priv->netdev->phydev); phy_disconnect(priv->netdev->phydev); mlxbf_gige_mdio_remove(priv); platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 4b063330ec28..636e19cf7050 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -161,7 +161,7 @@ static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv) spin_unlock_irqrestore(&priv->gpio_lock, flags); } -void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) +static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) { unsigned long flags; u32 val; @@ -258,7 +258,7 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) phy_int_gpio = MLXBF_GIGE_GPIO12_BIT; priv->phy_int_gpio_mask = BIT(phy_int_gpio); - mlxbf_gige_mdio_disable_phy_int(priv); + mlxbf_gige_mdio_enable_phy_int(priv); priv->mdiobus = devm_mdiobus_alloc(dev); if (!priv->mdiobus) { From patchwork Fri Jul 9 19:08:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503324 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2l65MVzz9sWl; Sat, 10 Jul 2021 05:09:06 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vru-0003Eo-T8; Fri, 09 Jul 2021 19:08:58 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrn-00039T-67 for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:49 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8meC030208; Fri, 9 Jul 2021 15:08:48 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8meL005460; Fri, 9 Jul 2021 15:08:48 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 07/23] Revert "UBUNTU: SAUCE: mlxbf_gige_mdio.c: Support PHY interrupt on Bluesphere" Date: Fri, 9 Jul 2021 15:08:14 -0400 Message-Id: <20210709190830.5405-8-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit b418d3395a83a3e9c5c93bb44a07957ed5402904. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 20 +++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 85a7ce19a6ff..ba6fd81d8fe6 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -21,7 +21,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.10" +#define DRV_VERSION "1.9" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 636e19cf7050..dfe68aef9707 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -78,6 +78,10 @@ #define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 #define MLXBF_GIGE_GPIO12_BIT 12 +#define MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) +#define MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) +#define MLXBF_GIGE_CAUSE_FALL_EN_MASK BIT(MLXBF_GIGE_GPIO12_BIT) +#define MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK BIT(MLXBF_GIGE_GPIO12_BIT) static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, int phy_reg, u32 opcode) @@ -156,7 +160,7 @@ static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv) spin_lock_irqsave(&priv->gpio_lock, flags); val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val &= ~priv->phy_int_gpio_mask; + val &= ~MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); spin_unlock_irqrestore(&priv->gpio_lock, flags); } @@ -172,13 +176,13 @@ static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) * state goes low. */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); - val |= priv->phy_int_gpio_mask; + val |= MLXBF_GIGE_CAUSE_FALL_EN_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); /* Enable PHY interrupt by setting the priority level */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val |= priv->phy_int_gpio_mask; + val |= MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); spin_unlock_irqrestore(&priv->gpio_lock, flags); @@ -201,7 +205,7 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); - if (!(val & priv->phy_int_gpio_mask)) + if (!(val & MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK)) return IRQ_NONE; phy_mac_interrupt(phydev); @@ -211,7 +215,7 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); - val |= priv->phy_int_gpio_mask; + val |= MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); @@ -230,7 +234,6 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) { struct device *dev = &pdev->dev; struct resource *res; - u32 phy_int_gpio; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); @@ -253,11 +256,6 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) writel(MLXBF_GIGE_MDIO_CFG_VAL, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); - ret = device_property_read_u32(dev, "phy-int-gpio", &phy_int_gpio); - if (ret < 0) - phy_int_gpio = MLXBF_GIGE_GPIO12_BIT; - priv->phy_int_gpio_mask = BIT(phy_int_gpio); - mlxbf_gige_mdio_enable_phy_int(priv); priv->mdiobus = devm_mdiobus_alloc(dev); From patchwork Fri Jul 9 19:08:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503323 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2l05R8zz9sX2; Sat, 10 Jul 2021 05:09:00 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003Cp-7Y; Fri, 09 Jul 2021 19:08:56 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrn-00039Z-AU for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:51 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:50 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8nb4030211; Fri, 9 Jul 2021 15:08:49 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8nr9005461; Fri, 9 Jul 2021 15:08:49 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 08/23] Revert "UBUNTU: SAUCE: mlxbf_gige_main.c: Fix OOB PHY interrupt" Date: Fri, 9 Jul 2021 15:08:15 -0400 Message-Id: <20210709190830.5405-9-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 6793808914c0604c2c890a9551cc28f835412a1f. Signed-off-by: Asmaa Mnebhi --- drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c | 2 +- drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index ba6fd81d8fe6..be6acb3c09f8 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -21,7 +21,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.9" +#define DRV_VERSION "1.8" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index dfe68aef9707..3b241d1491f9 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -223,10 +223,6 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) if (phydev->drv->ack_interrupt) phydev->drv->ack_interrupt(phydev); - phydev->interrupts = PHY_INTERRUPT_ENABLED; - if (phydev->drv->config_intr) - phydev->drv->config_intr(phydev); - return IRQ_HANDLED; } From patchwork Fri Jul 9 19:08:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503326 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lM1J0hz9sRN; Sat, 10 Jul 2021 05:09:19 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vs9-0003Or-Nf; Fri, 09 Jul 2021 19:09:13 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003Co-Dj for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:56 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:51 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8obs030214; Fri, 9 Jul 2021 15:08:50 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8oC1005462; Fri, 9 Jul 2021 15:08:50 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 09/23] Revert "UBUNTU: SAUCE: mlxbf_gige: use streaming DMA mapping for packet buffers" Date: Fri, 9 Jul 2021 15:08:16 -0400 Message-Id: <20210709190830.5405-10-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 9f4f2258bacc13425902ef01c698bf2899091b24. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 9 +- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 239 +++++++----------- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 7 +- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 4 +- 4 files changed, 94 insertions(+), 165 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index c3cb50ef8774..27786512d35f 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -4,7 +4,7 @@ * - this file contains software data structures and any chip-specific * data structures (e.g. TX WQE format) that are memory resident. * - * Copyright (c) 2020 NVIDIA Corporation. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. */ #ifndef __MLXBF_GIGE_H__ @@ -28,9 +28,6 @@ #define MLXBF_GIGE_DEFAULT_BUF_SZ 2048 -#define MLXBF_GIGE_DMA_PAGE_SZ 4096 -#define MLXBF_GIGE_DMA_PAGE_SHIFT 12 - /* There are four individual MAC RX filters. Currently * two of them are being used: one for the broadcast MAC * (index 0) and one for local MAC (index 1) @@ -97,8 +94,8 @@ struct mlxbf_gige { u64 error_intr_count; u64 rx_intr_count; u64 llu_plu_intr_count; - struct sk_buff *rx_skb[MLXBF_GIGE_MAX_RXQ_SZ]; - struct sk_buff *tx_skb[MLXBF_GIGE_MAX_TXQ_SZ]; + u8 *rx_buf[MLXBF_GIGE_MAX_RXQ_SZ]; + u8 *tx_buf[MLXBF_GIGE_MAX_TXQ_SZ]; int error_irq; int rx_irq; int llu_plu_irq; diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index be6acb3c09f8..db5c491cf2ad 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -2,12 +2,11 @@ /* Gigabit Ethernet driver for Mellanox BlueField SoC * - * Copyright (c) 2020 NVIDIA Corporation. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. */ #include #include -#include #include #include #include @@ -15,13 +14,12 @@ #include #include #include -#include #include "mlxbf_gige.h" #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.8" +#define DRV_VERSION "1.7" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -81,49 +79,6 @@ static void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) */ } -/* Allocate SKB whose payload pointer aligns with the Bluefield - * hardware DMA limitation, i.e. DMA operation can't cross - * a 4KB boundary. A maximum packet size of 2KB is assumed in the - * alignment formula. The alignment logic overallocates an SKB, - * and then adjusts the headroom so that the SKB data pointer is - * naturally aligned to a 2KB boundary. - */ -static struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, - dma_addr_t *buf_dma, - enum dma_data_direction dir) -{ - struct sk_buff *skb; - u64 addr, offset; - - /* Overallocate the SKB so that any headroom adjustment (to - * provide 2KB natural alignment) does not exceed payload area - */ - skb = netdev_alloc_skb(priv->netdev, MLXBF_GIGE_DEFAULT_BUF_SZ * 2); - if (!skb) - return NULL; - - /* Adjust the headroom so that skb->data is naturally aligned to - * a 2KB boundary, which is the maximum packet size supported. - */ - addr = (u64)skb->data; - offset = (addr + MLXBF_GIGE_DEFAULT_BUF_SZ - 1) & - ~(MLXBF_GIGE_DEFAULT_BUF_SZ - 1); - offset -= addr; - if (offset) - skb_reserve(skb, offset); - - /* Return streaming DMA mapping to caller */ - *buf_dma = dma_map_single(priv->dev, skb->data, - MLXBF_GIGE_DEFAULT_BUF_SZ, dir); - if (dma_mapping_error(priv->dev, *buf_dma)) { - dev_kfree_skb(skb); - *buf_dma = (dma_addr_t)0; - return NULL; - } - - return skb; -} - /* Receive Initialization * 1) Configures RX MAC filters via MMIO registers * 2) Allocates RX WQE array using coherent DMA mapping @@ -158,9 +113,19 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) rx_wqe_ptr = priv->rx_wqe_base; for (i = 0; i < priv->rx_q_entries; i++) { - priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, DMA_FROM_DEVICE); - if (!priv->rx_skb[i]) - goto free_wqe_and_skb; + /* Allocate a receive buffer for this RX WQE. The DMA + * form (dma_addr_t) of the receive buffer address is + * stored in the RX WQE array (via 'rx_wqe_ptr') where + * it is accessible by the GigE device. The VA form of + * the receive buffer is stored in 'rx_buf[]' array in + * the driver private storage for housekeeping. + */ + priv->rx_buf[i] = dma_alloc_coherent(priv->dev, + MLXBF_GIGE_DEFAULT_BUF_SZ, + &rx_buf_dma, + GFP_KERNEL); + if (!priv->rx_buf[i]) + goto free_wqe_and_buf; *rx_wqe_ptr++ = rx_buf_dma; } @@ -173,7 +138,7 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) &priv->rx_cqe_base_dma, GFP_KERNEL); if (!priv->rx_cqe_base) - goto free_wqe_and_skb; + goto free_wqe_and_buf; /* Write RX CQE base address into MMIO reg */ writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); @@ -207,12 +172,11 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) return 0; -free_wqe_and_skb: +free_wqe_and_buf: rx_wqe_ptr = priv->rx_wqe_base; for (j = 0; j < i; j++) { - dma_unmap_single(priv->dev, *rx_wqe_ptr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); - dev_kfree_skb(priv->rx_skb[j]); + dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, + priv->rx_buf[j], *rx_wqe_ptr); rx_wqe_ptr++; } dma_free_coherent(priv->dev, wq_size, @@ -274,9 +238,9 @@ static void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) rx_wqe_ptr = priv->rx_wqe_base; for (i = 0; i < priv->rx_q_entries; i++) { - dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ, - DMA_FROM_DEVICE); - dev_kfree_skb(priv->rx_skb[i]); + dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, + priv->rx_buf[i], *rx_wqe_ptr); + priv->rx_buf[i] = NULL; rx_wqe_ptr++; } @@ -302,20 +266,19 @@ static void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) */ static void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) { - u64 *tx_wqe_addr; + u64 *tx_wqe_ptr; size_t size; int i; - tx_wqe_addr = priv->tx_wqe_base; + tx_wqe_ptr = priv->tx_wqe_base; for (i = 0; i < priv->tx_q_entries; i++) { - if (priv->tx_skb[i]) { - dma_unmap_single(priv->dev, *tx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); - dev_kfree_skb(priv->tx_skb[i]); - priv->tx_skb[i] = NULL; + if (priv->tx_buf[i]) { + dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, + priv->tx_buf[i], *tx_wqe_ptr); + priv->tx_buf[i] = NULL; } - tx_wqe_addr += 2; + tx_wqe_ptr += 2; } size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; @@ -654,11 +617,9 @@ static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) stats->tx_packets++; stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); - - dma_unmap_single(priv->dev, *tx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_TO_DEVICE); - dev_consume_skb_any(priv->tx_skb[tx_wqe_index]); - priv->tx_skb[tx_wqe_index] = NULL; + dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, + priv->tx_buf[tx_wqe_index], *tx_wqe_addr); + priv->tx_buf[tx_wqe_index] = NULL; } /* Since the TX ring was likely just drained, check if TX queue @@ -676,48 +637,40 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) { struct net_device *netdev = priv->netdev; u16 rx_pi_rem, rx_ci_rem; - dma_addr_t rx_buf_dma; struct sk_buff *skb; u64 *rx_cqe_addr; - u64 *rx_wqe_addr; u64 datalen; u64 rx_cqe; u16 rx_ci; u16 rx_pi; + u8 *pktp; /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); rx_pi_rem = rx_pi % priv->rx_q_entries; - rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem; - dma_unmap_single(priv->dev, *rx_wqe_addr, - MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + pktp = priv->rx_buf[rx_pi_rem]; rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; rx_cqe = *rx_cqe_addr; + datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { /* Packet is OK, increment stats */ - datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; netdev->stats.rx_packets++; netdev->stats.rx_bytes += datalen; - skb = priv->rx_skb[rx_pi_rem]; + skb = dev_alloc_skb(datalen); + if (!skb) { + netdev->stats.rx_dropped++; + return false; + } - skb_put(skb, datalen); + memcpy(skb_put(skb, datalen), pktp, datalen); + skb->dev = netdev; + skb->protocol = eth_type_trans(skb, netdev); skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ - skb->protocol = eth_type_trans(skb, netdev); netif_receive_skb(skb); - - /* Alloc another RX SKB for this same index */ - priv->rx_skb[rx_pi_rem] = mlxbf_gige_alloc_skb(priv, &rx_buf_dma, - DMA_FROM_DEVICE); - if (!priv->rx_skb[rx_pi_rem]) { - netdev->stats.rx_dropped++; - return false; - } - - *rx_wqe_addr = rx_buf_dma; } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { priv->stats.rx_mac_errors++; } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { @@ -795,9 +748,9 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) } err = request_threaded_irq(priv->phy_irq, NULL, - mlxbf_gige_mdio_handle_phy_interrupt, - IRQF_ONESHOT | IRQF_SHARED, - "mlxbf_gige_phy", priv); + mlxbf_gige_mdio_handle_phy_interrupt, + IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", + priv); if (err) { dev_err(priv->dev, "Request phy_irq failure\n"); goto free_llu_plu_irq; @@ -815,6 +768,7 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) free_irq(priv->error_irq, priv); return err; + } static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) @@ -839,18 +793,18 @@ static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) MLXBF_GIGE_RX_DISC_COUNTER_ALL); } -static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) +static void mlxbf_gige_clean_port(struct mlxbf_gige *priv) { u64 control; u64 temp; - int err; + int ret; /* Set the CLEAN_PORT_EN bit to trigger SW reset */ control = readq(priv->base + MLXBF_GIGE_CONTROL); control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; writeq(control, priv->base + MLXBF_GIGE_CONTROL); - err = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp, + ret = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp, (temp & MLXBF_GIGE_STATUS_READY), 100, 100000); @@ -858,40 +812,38 @@ static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) control = readq(priv->base + MLXBF_GIGE_CONTROL); control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; writeq(control, priv->base + MLXBF_GIGE_CONTROL); - - return err; } static int mlxbf_gige_phy_enable_interrupt(struct phy_device *phydev) { - int err = 0; + int ret = 0; if (phydev->drv->ack_interrupt) - err = phydev->drv->ack_interrupt(phydev); - if (err < 0) - return err; + ret = phydev->drv->ack_interrupt(phydev); + if (ret < 0) + return ret; phydev->interrupts = PHY_INTERRUPT_ENABLED; if (phydev->drv->config_intr) - err = phydev->drv->config_intr(phydev); + ret = phydev->drv->config_intr(phydev); - return err; + return ret; } static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) { - int err = 0; + int ret = 0; if (phydev->drv->ack_interrupt) - err = phydev->drv->ack_interrupt(phydev); - if (err < 0) - return err; + ret = phydev->drv->ack_interrupt(phydev); + if (ret < 0) + return ret; phydev->interrupts = PHY_INTERRUPT_DISABLED; if (phydev->drv->config_intr) - err = phydev->drv->config_intr(phydev); + ret = phydev->drv->config_intr(phydev); - return err; + return ret; } static int mlxbf_gige_open(struct net_device *netdev) @@ -905,9 +857,7 @@ static int mlxbf_gige_open(struct net_device *netdev) if (err) return err; mlxbf_gige_cache_stats(priv); - err = mlxbf_gige_clean_port(priv); - if (err) - return err; + mlxbf_gige_clean_port(priv); err = mlxbf_gige_rx_init(priv); if (err) return err; @@ -980,51 +930,31 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); - u64 buff_addr, start_dma_page, end_dma_page; - struct sk_buff *tx_skb; dma_addr_t tx_buf_dma; + u8 *tx_buf = NULL; u64 *tx_wqe_addr; u64 word2; - /* If needed, linearize TX SKB as hardware DMA expects this */ - if (skb_linearize(skb)) { + /* Allocate ptr for buffer */ + if (skb->len < MLXBF_GIGE_DEFAULT_BUF_SZ) + tx_buf = dma_alloc_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, + &tx_buf_dma, GFP_KERNEL); + + if (!tx_buf) { + /* Free incoming skb, could not alloc TX buffer */ dev_kfree_skb(skb); netdev->stats.tx_dropped++; return NET_XMIT_DROP; } - buff_addr = (u64)skb->data; - start_dma_page = buff_addr >> MLXBF_GIGE_DMA_PAGE_SHIFT; - end_dma_page = (buff_addr + skb->len - 1) >> MLXBF_GIGE_DMA_PAGE_SHIFT; + priv->tx_buf[priv->tx_pi % priv->tx_q_entries] = tx_buf; - /* Verify that payload pointer and data length of SKB to be - * transmitted does not violate the hardware DMA limitation. + /* Copy data from skb to allocated TX buffer + * + * NOTE: GigE silicon will automatically pad up to + * minimum packet length if needed. */ - if (start_dma_page != end_dma_page) { - /* DMA operation would fail as-is, alloc new aligned SKB */ - tx_skb = mlxbf_gige_alloc_skb(priv, &tx_buf_dma, DMA_TO_DEVICE); - if (!tx_skb) { - /* Free original skb, could not alloc new aligned SKB */ - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; - return NET_XMIT_DROP; - } - - skb_put_data(tx_skb, skb->data, skb->len); - dev_kfree_skb(skb); - } else { - tx_skb = skb; - tx_buf_dma = dma_map_single(priv->dev, skb->data, - MLXBF_GIGE_DEFAULT_BUF_SZ, - DMA_TO_DEVICE); - if (dma_mapping_error(priv->dev, tx_buf_dma)) { - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; - return NET_XMIT_DROP; - } - } - - priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; + skb_copy_bits(skb, 0, tx_buf, skb->len); /* Get address of TX WQE */ tx_wqe_addr = priv->tx_wqe_next; @@ -1034,11 +964,8 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, /* Put PA of buffer address into first 64-bit word of TX WQE */ *tx_wqe_addr = tx_buf_dma; - /* Set TX WQE pkt_len appropriately - * NOTE: GigE silicon will automatically pad up to - * minimum packet length if needed. - */ - word2 = tx_skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; + /* Set TX WQE pkt_len appropriately */ + word2 = skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; /* Write entire 2nd word of TX WQE */ *(tx_wqe_addr + 1) = word2; @@ -1051,6 +978,11 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); } + writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); + + /* Free incoming skb, contents already copied to HW */ + dev_kfree_skb(skb); + /* Check if the last TX entry was just used */ if (!mlxbf_gige_tx_buffs_avail(priv)) { /* TX ring is full, inform stack */ @@ -1150,7 +1082,8 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) static void mlxbf_gige_adjust_link(struct net_device *netdev) { - /* Only one speed and one duplex supported, simply return */ + /* Only one speed and one duplex supported */ + return; } static int mlxbf_gige_probe(struct platform_device *pdev) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 3b241d1491f9..13e9af57fc77 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -1,8 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause - -/* MDIO support for Mellanox Gigabit Ethernet driver +/* MDIO support for Mellanox GigE driver * - * Copyright (c) 2020 NVIDIA Corporation. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. */ #include @@ -68,7 +67,7 @@ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ - MLXBF_GIGE_MDIO_PERIOD) | \ + MLXBF_GIGE_MDIO_PERIOD) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index 128e12894885..41e4450bd290 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -2,7 +2,7 @@ /* Header file for Mellanox BlueField GigE register defines * - * Copyright (c) 2020 NVIDIA Corporation. + * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. */ #ifndef __MLXBF_GIGE_REGS_H__ @@ -73,6 +73,6 @@ /* NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset, * so use that plus size of single register to derive total size */ -#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG + 8) +#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG+8) #endif /* !defined(__MLXBF_GIGE_REGS_H__) */ From patchwork Fri Jul 9 19:08:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503328 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lY11mtz9sPf; Sat, 10 Jul 2021 05:09:29 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsJ-0003X5-A7; Fri, 09 Jul 2021 19:09:23 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003Cs-F6 for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:56 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:51 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8p6l030217; Fri, 9 Jul 2021 15:08:51 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8pcZ005463; Fri, 9 Jul 2021 15:08:51 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 10/23] Revert "UBUNTU: SAUCE: mlxbf_gige: address upstream comments on RX and TX" Date: Fri, 9 Jul 2021 15:08:17 -0400 Message-Id: <20210709190830.5405-11-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit dc29f7ee78304d13ed731fadb8347b5c7af48241. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 77 +++++++------------ 1 file changed, 29 insertions(+), 48 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index db5c491cf2ad..0a0e5ea76e66 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -19,7 +19,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.7" +#define DRV_VERSION "1.6" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -678,11 +678,10 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) } /* Let hardware know we've replenished one buffer */ - rx_pi++; - writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); + writeq(rx_pi + 1, priv->base + MLXBF_GIGE_RX_WQE_PI); (*rx_pkts)++; - + rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); rx_pi_rem = rx_pi % priv->rx_q_entries; rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); rx_ci_rem = rx_ci % priv->rx_q_entries; @@ -737,14 +736,14 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) "mlxbf_gige_rx", priv); if (err) { dev_err(priv->dev, "Request rx_irq failure\n"); - goto free_error_irq; + return err; } err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, "mlxbf_gige_llu_plu", priv); if (err) { dev_err(priv->dev, "Request llu_plu_irq failure\n"); - goto free_rx_irq; + return err; } err = request_threaded_irq(priv->phy_irq, NULL, @@ -753,22 +752,10 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) priv); if (err) { dev_err(priv->dev, "Request phy_irq failure\n"); - goto free_llu_plu_irq; + return err; } return 0; - -free_llu_plu_irq: - free_irq(priv->llu_plu_irq, priv); - -free_rx_irq: - free_irq(priv->rx_irq, priv); - -free_error_irq: - free_irq(priv->error_irq, priv); - - return err; - } static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) @@ -853,15 +840,15 @@ static int mlxbf_gige_open(struct net_device *netdev) u64 int_en; int err; - err = mlxbf_gige_request_irqs(priv); - if (err) - return err; mlxbf_gige_cache_stats(priv); mlxbf_gige_clean_port(priv); - err = mlxbf_gige_rx_init(priv); - if (err) - return err; - err = mlxbf_gige_tx_init(priv); + mlxbf_gige_rx_init(priv); + mlxbf_gige_tx_init(priv); + netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); + napi_enable(&priv->napi); + netif_start_queue(netdev); + + err = mlxbf_gige_request_irqs(priv); if (err) return err; @@ -875,10 +862,6 @@ static int mlxbf_gige_open(struct net_device *netdev) if (err) return err; - netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); - napi_enable(&priv->napi); - netif_start_queue(netdev); - /* Set bits in INT_EN that we care about */ int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS | @@ -935,6 +918,20 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, u64 *tx_wqe_addr; u64 word2; + /* Check that there is room left in TX ring */ + if (!mlxbf_gige_tx_buffs_avail(priv)) { + /* TX ring is full, inform stack but do not free SKB */ + netif_stop_queue(netdev); + netdev->stats.tx_dropped++; + /* Since there is no separate "TX complete" interrupt, need + * to explicitly schedule NAPI poll. This will trigger logic + * which processes TX completions, and will hopefully drain + * the TX ring allowing the TX queue to be awakened. + */ + napi_schedule(&priv->napi); + return NETDEV_TX_BUSY; + } + /* Allocate ptr for buffer */ if (skb->len < MLXBF_GIGE_DEFAULT_BUF_SZ) tx_buf = dma_alloc_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, @@ -972,30 +969,14 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, priv->tx_pi++; - if (!netdev_xmit_more()) { - /* Create memory barrier before write to TX PI */ - wmb(); - writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); - } + /* Create memory barrier before write to TX PI */ + wmb(); writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); /* Free incoming skb, contents already copied to HW */ dev_kfree_skb(skb); - /* Check if the last TX entry was just used */ - if (!mlxbf_gige_tx_buffs_avail(priv)) { - /* TX ring is full, inform stack */ - netif_stop_queue(netdev); - - /* Since there is no separate "TX complete" interrupt, need - * to explicitly schedule NAPI poll. This will trigger logic - * which processes TX completions, and will hopefully drain - * the TX ring allowing the TX queue to be awakened. - */ - napi_schedule(&priv->napi); - } - return NETDEV_TX_OK; } From patchwork Fri Jul 9 19:08:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503332 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lm2fDbz9sX2; Sat, 10 Jul 2021 05:09:40 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsV-0003fB-N1; Fri, 09 Jul 2021 19:09:35 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003Cu-IS for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:56 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:52 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8pjW030220; Fri, 9 Jul 2021 15:08:51 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8pjF005464; Fri, 9 Jul 2021 15:08:51 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 11/23] Revert "UBUNTU: SAUCE: mlxbf-gige: remove gpio interrupt coalesce resources" Date: Fri, 9 Jul 2021 15:08:18 -0400 Message-Id: <20210709190830.5405-12-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit d11fc64e9e4bd09536448b4571660e1ad38a6a83. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 4 +++ .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 34 +++++++++++++++++++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index 27786512d35f..63e07e60108d 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -75,6 +75,8 @@ struct mlxbf_gige { void __iomem *mdio_io; struct mii_bus *mdiobus; void __iomem *gpio_io; + void __iomem *cause_rsh_coalesce0_io; + void __iomem *cause_gpio_arm_coalesce0_io; u32 phy_int_gpio_mask; spinlock_t lock; spinlock_t gpio_lock; @@ -141,6 +143,8 @@ enum mlxbf_gige_res { MLXBF_GIGE_RES_MAC, MLXBF_GIGE_RES_MDIO9, MLXBF_GIGE_RES_GPIO0, + MLXBF_GIGE_RES_CAUSE_RSH_COALESCE0, + MLXBF_GIGE_RES_CAUSE_GPIO_ARM_COALESCE0, MLXBF_GIGE_RES_LLU, MLXBF_GIGE_RES_PLU }; diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 0a0e5ea76e66..a4ac1dc947d0 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -19,7 +19,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.6" +#define DRV_VERSION "1.5" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 13e9af57fc77..464bfac9a650 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -71,6 +71,16 @@ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) +/* The PHY interrupt line is shared with other interrupt lines such + * as GPIO and SMBus. So use YU registers to determine whether the + * interrupt comes from the PHY. + */ +#define MLXBF_GIGE_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK 0x10 +#define MLXBF_GIGE_GPIO_CAUSE_IRQ_IS_SET(val) \ + ((val) & MLXBF_GIGE_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK) + +#define MLXBF_GIGE_GPIO_BLOCK0_MASK BIT(0) + #define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48 #define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 #define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94 @@ -211,6 +221,10 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) /* Clear interrupt when done, otherwise, no further interrupt * will be triggered. + * Writing 0x1 to the clear cause register also clears the + * following registers: + * cause_gpio_arm_coalesce0 + * cause_rsh_coalesce0 */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); @@ -247,6 +261,26 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) if (!priv->gpio_io) return -ENOMEM; + res = platform_get_resource(pdev, IORESOURCE_MEM, + MLXBF_GIGE_RES_CAUSE_RSH_COALESCE0); + if (!res) + return -ENODEV; + + priv->cause_rsh_coalesce0_io = + devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->cause_rsh_coalesce0_io) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, + MLXBF_GIGE_RES_CAUSE_GPIO_ARM_COALESCE0); + if (!res) + return -ENODEV; + + priv->cause_gpio_arm_coalesce0_io = + devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->cause_gpio_arm_coalesce0_io) + return -ENOMEM; + /* Configure mdio parameters */ writel(MLXBF_GIGE_MDIO_CFG_VAL, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); From patchwork Fri Jul 9 19:08:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503333 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2ln45T9z9sWk; Sat, 10 Jul 2021 05:09:41 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsW-0003gj-Qd; Fri, 09 Jul 2021 19:09:36 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003D2-M9 for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:56 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:53 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8qBF030223; Fri, 9 Jul 2021 15:08:52 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8qqj005465; Fri, 9 Jul 2021 15:08:52 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 12/23] Revert "UBUNTU: SAUCE: mlxbf_gige: add support for ndo_get_stats64" Date: Fri, 9 Jul 2021 15:08:19 -0400 Message-Id: <20210709190830.5405-13-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 5732076cd8c01a565ebae7fdfb23e4b3536a1ff4. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 22 ++----------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index a4ac1dc947d0..e488962bd411 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -19,7 +19,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.5" +#define DRV_VERSION "1.4" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -406,6 +406,7 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, u64 *data) { struct mlxbf_gige *priv = netdev_priv(netdev); + unsigned long flags; /* Fill data array with interface statistics * @@ -1009,24 +1010,6 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) } } -static void mlxbf_gige_get_stats64(struct net_device *netdev, - struct rtnl_link_stats64 *stats) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - netdev_stats_to_stats64(stats, &netdev->stats); - - stats->rx_length_errors = priv->stats.rx_truncate_errors; - stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts; - stats->rx_crc_errors = priv->stats.rx_mac_errors; - stats->rx_errors = stats->rx_length_errors + - stats->rx_fifo_errors + - stats->rx_crc_errors; - - stats->tx_fifo_errors = priv->stats.tx_fifo_full; - stats->tx_errors = stats->tx_fifo_errors; -} - static const struct net_device_ops mlxbf_gige_netdev_ops = { .ndo_open = mlxbf_gige_open, .ndo_stop = mlxbf_gige_stop, @@ -1035,7 +1018,6 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = mlxbf_gige_do_ioctl, .ndo_set_rx_mode = mlxbf_gige_set_rx_mode, - .ndo_get_stats64 = mlxbf_gige_get_stats64, }; static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) From patchwork Fri Jul 9 19:08:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503327 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lP4Wl4z9sX2; Sat, 10 Jul 2021 05:09:21 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsC-0003SY-8M; Fri, 09 Jul 2021 19:09:16 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003D4-NH for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:56 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:53 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8rfp030226; Fri, 9 Jul 2021 15:08:53 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8r59005466; Fri, 9 Jul 2021 15:08:53 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 13/23] Revert "UBUNTU: SAUCE: mlxbf_gige: address some general upstream comments" Date: Fri, 9 Jul 2021 15:08:20 -0400 Message-Id: <20210709190830.5405-14-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit a7a667e31b5f301466459342832d1a2ae1d81b33. Signed-off-by: Asmaa Mnebhi --- .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 2 +- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 130 +++++++++++++----- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 5 - 3 files changed, 100 insertions(+), 37 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig index 08a4487932fe..41c7a8997190 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig @@ -5,7 +5,7 @@ config MLXBF_GIGE tristate "Mellanox Technologies BlueField Gigabit Ethernet support" - depends on (ARM64 || COMPILE_TEST) && ACPI + depends on (ARM64 || COMPILE_TEST) && ACPI && INET select PHYLIB help The second generation BlueField SoC from Mellanox Technologies diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index e488962bd411..0fd540bc50f7 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -19,7 +18,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.4" +#define DRV_VERSION "1.3" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -146,6 +145,9 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) /* Write RX_WQE_PI with current number of replenished buffers */ writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI); + /* Enable RX DMA to write new packets to memory */ + writeq(MLXBF_GIGE_RX_DMA_EN, priv->base + MLXBF_GIGE_RX_DMA); + /* Enable removal of CRC during RX */ data = readq(priv->base + MLXBF_GIGE_RX); data |= MLXBF_GIGE_RX_STRIP_CRC_EN; @@ -158,15 +160,12 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS); /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to - * indicate readiness to receive interrupts + * indicate readiness to receive pkts */ data = readq(priv->base + MLXBF_GIGE_INT_MASK); data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; writeq(data, priv->base + MLXBF_GIGE_INT_MASK); - /* Enable RX DMA to write new packets to memory */ - writeq(MLXBF_GIGE_RX_DMA_EN, priv->base + MLXBF_GIGE_RX_DMA); - writeq(ilog2(priv->rx_q_entries), priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); @@ -207,6 +206,7 @@ static int mlxbf_gige_tx_init(struct mlxbf_gige *priv) /* Allocate address for TX completion count */ priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, &priv->tx_cc_dma, GFP_KERNEL); + if (!priv->tx_cc) { dma_free_coherent(priv->dev, size, priv->tx_wqe_base, priv->tx_wqe_base_dma); @@ -300,13 +300,20 @@ static void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) /* Start of struct ethtool_ops functions */ static int mlxbf_gige_get_regs_len(struct net_device *netdev) { - return MLXBF_GIGE_MMIO_REG_SZ; + /* Return size of MMIO register space (in bytes). + * + * NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset, + * so use that plus size of single register to derive total size + */ + return MLXBF_GIGE_MAC_CFG + 8; } static void mlxbf_gige_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct mlxbf_gige *priv = netdev_priv(netdev); + __be64 *buff = p; + int reg; regs->version = MLXBF_GIGE_REGS_VERSION; @@ -317,7 +324,8 @@ static void mlxbf_gige_get_regs(struct net_device *netdev, * NOTE: by design, a read to an offset without an existing * register will be acknowledged and return zero. */ - memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); + for (reg = 0; reg <= MLXBF_GIGE_MAC_CFG; reg += 8) + *buff++ = cpu_to_be64(readq(priv->base + reg)); } static void mlxbf_gige_get_ringparam(struct net_device *netdev, @@ -325,6 +333,7 @@ static void mlxbf_gige_get_ringparam(struct net_device *netdev, { struct mlxbf_gige *priv = netdev_priv(netdev); + memset(ering, 0, sizeof(*ering)); ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; ering->rx_pending = priv->rx_q_entries; @@ -346,9 +355,11 @@ static int mlxbf_gige_set_ringparam(struct net_device *netdev, new_rx_q_entries = roundup_pow_of_two(ering->rx_pending); new_tx_q_entries = roundup_pow_of_two(ering->tx_pending); - /* Check against min values, core checks against max values */ + /* Range check the new values */ if (new_tx_q_entries < MLXBF_GIGE_MIN_TXQ_SZ || - new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ) + new_tx_q_entries > MLXBF_GIGE_MAX_TXQ_SZ || + new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ || + new_rx_q_entries > MLXBF_GIGE_MAX_RXQ_SZ) return -EINVAL; /* If queue sizes did not change, exit now */ @@ -368,9 +379,21 @@ static int mlxbf_gige_set_ringparam(struct net_device *netdev, return 0; } +static void mlxbf_gige_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); + strlcpy(info->version, DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info)); +} + static const struct { const char string[ETH_GSTRING_LEN]; } mlxbf_gige_ethtool_stats_keys[] = { + { "rx_bytes" }, + { "rx_packets" }, + { "tx_bytes" }, + { "tx_packets" }, { "hw_access_errors" }, { "tx_invalid_checksums" }, { "tx_small_frames" }, @@ -408,6 +431,8 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, struct mlxbf_gige *priv = netdev_priv(netdev); unsigned long flags; + spin_lock_irqsave(&priv->lock, flags); + /* Fill data array with interface statistics * * NOTE: the data writes must be in @@ -423,6 +448,10 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, * rx_filter_passed_pkts * rx_filter_discard_pkts */ + *data++ = netdev->stats.rx_bytes; + *data++ = netdev->stats.rx_packets; + *data++ = netdev->stats.tx_bytes; + *data++ = netdev->stats.tx_packets; *data++ = priv->stats.hw_access_errors; *data++ = priv->stats.tx_invalid_checksums; *data++ = priv->stats.tx_small_frames; @@ -438,6 +467,8 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); *data++ = (priv->stats.rx_filter_discard_pkts + readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); + + spin_unlock_irqrestore(&priv->lock, flags); } static void mlxbf_gige_get_pauseparam(struct net_device *netdev, @@ -451,6 +482,7 @@ static void mlxbf_gige_get_pauseparam(struct net_device *netdev, } static const struct ethtool_ops mlxbf_gige_ethtool_ops = { + .get_drvinfo = mlxbf_gige_get_drvinfo, .get_link = ethtool_op_get_link, .get_ringparam = mlxbf_gige_get_ringparam, .set_ringparam = mlxbf_gige_set_ringparam, @@ -532,12 +564,18 @@ static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) priv->rx_intr_count++; - /* NOTE: GigE silicon automatically disables "packet rx" interrupt by + /* Driver has been interrupted because a new packet is available, + * but do not process packets at this time. Instead, disable any + * further "packet rx" interrupts and tell the networking subsystem + * to poll the driver to pick up all available packets. + * + * NOTE: GigE silicon automatically disables "packet rx" interrupt by * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt * to the ARM cores. Software needs to re-enable "packet rx" * interrupts by clearing MLXBF_GIGE_INT_MASK bit0. */ + /* Tell networking subsystem to poll GigE driver */ napi_schedule(&priv->napi); return IRQ_HANDLED; @@ -628,8 +666,9 @@ static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) * available the TX queue can be awakened. */ if (netif_queue_stopped(priv->netdev) && - mlxbf_gige_tx_buffs_avail(priv)) + mlxbf_gige_tx_buffs_avail(priv)) { netif_wake_queue(priv->netdev); + } return true; } @@ -726,22 +765,25 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) { int err; - err = request_irq(priv->error_irq, mlxbf_gige_error_intr, 0, - "mlxbf_gige_error", priv); + err = devm_request_irq(priv->dev, priv->error_irq, + mlxbf_gige_error_intr, 0, "mlxbf_gige_error", + priv); if (err) { dev_err(priv->dev, "Request error_irq failure\n"); return err; } - err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0, - "mlxbf_gige_rx", priv); + err = devm_request_irq(priv->dev, priv->rx_irq, + mlxbf_gige_rx_intr, 0, "mlxbf_gige_rx", + priv); if (err) { dev_err(priv->dev, "Request rx_irq failure\n"); return err; } - err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, - "mlxbf_gige_llu_plu", priv); + err = devm_request_irq(priv->dev, priv->llu_plu_irq, + mlxbf_gige_llu_plu_intr, 0, "mlxbf_gige_llu_plu", + priv); if (err) { dev_err(priv->dev, "Request llu_plu_irq failure\n"); return err; @@ -761,9 +803,9 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) { - free_irq(priv->error_irq, priv); - free_irq(priv->rx_irq, priv); - free_irq(priv->llu_plu_irq, priv); + devm_free_irq(priv->dev, priv->error_irq, priv); + devm_free_irq(priv->dev, priv->rx_irq, priv); + devm_free_irq(priv->dev, priv->llu_plu_irq, priv); free_irq(priv->phy_irq, priv); } @@ -783,18 +825,22 @@ static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) static void mlxbf_gige_clean_port(struct mlxbf_gige *priv) { - u64 control; - u64 temp; - int ret; + u64 control, status; + int cnt; /* Set the CLEAN_PORT_EN bit to trigger SW reset */ control = readq(priv->base + MLXBF_GIGE_CONTROL); control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; writeq(control, priv->base + MLXBF_GIGE_CONTROL); - ret = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp, - (temp & MLXBF_GIGE_STATUS_READY), - 100, 100000); + /* Loop waiting for status ready bit to assert */ + cnt = 1000; + do { + status = readq(priv->base + MLXBF_GIGE_STATUS); + if (status & MLXBF_GIGE_STATUS_READY) + break; + usleep_range(50, 100); + } while (--cnt > 0); /* Clear the CLEAN_PORT_EN bit at end of this loop */ control = readq(priv->base + MLXBF_GIGE_CONTROL); @@ -1020,6 +1066,28 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = { .ndo_set_rx_mode = mlxbf_gige_set_rx_mode, }; +static u64 mlxbf_gige_mac_to_u64(u8 *addr) +{ + u64 mac = 0; + int i; + + for (i = 0; i < ETH_ALEN; i++) { + mac <<= 8; + mac |= addr[i]; + } + return mac; +} + +static void mlxbf_gige_u64_to_mac(u8 *addr, u64 mac) +{ + int i; + + for (i = ETH_ALEN; i > 0; i--) { + addr[i - 1] = mac & 0xFF; + mac >>= 8; + } +} + static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) { u8 mac[ETH_ALEN]; @@ -1027,7 +1095,7 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, &local_mac); - u64_to_ether_addr(local_mac, mac); + mlxbf_gige_u64_to_mac(mac, local_mac); if (is_valid_ether_addr(mac)) { ether_addr_copy(priv->netdev->dev_addr, mac); @@ -1038,7 +1106,7 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) eth_hw_addr_random(priv->netdev); } - local_mac = ether_addr_to_u64(priv->netdev->dev_addr); + local_mac = mlxbf_gige_mac_to_u64(priv->netdev->dev_addr); mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, local_mac); } @@ -1222,7 +1290,7 @@ static struct platform_driver mlxbf_gige_driver = { module_platform_driver(mlxbf_gige_driver); MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); -MODULE_AUTHOR("David Thompson "); -MODULE_AUTHOR("Asmaa Mnebhi "); +MODULE_AUTHOR("David Thompson "); +MODULE_AUTHOR("Asmaa Mnebhi "); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index 41e4450bd290..06e3c7145bbd 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -70,9 +70,4 @@ #define MLXBF_GIGE_RX_CQE_PACKET_CI 0x05b0 #define MLXBF_GIGE_MAC_CFG 0x05e8 -/* NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset, - * so use that plus size of single register to derive total size - */ -#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG+8) - #endif /* !defined(__MLXBF_GIGE_REGS_H__) */ From patchwork Fri Jul 9 19:08:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503329 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lc63LZz9sPf; Sat, 10 Jul 2021 05:09:32 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsM-0003ZR-VH; Fri, 09 Jul 2021 19:09:27 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003D8-SG for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:57 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:54 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8rHZ030229; Fri, 9 Jul 2021 15:08:53 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8rlB005467; Fri, 9 Jul 2021 15:08:53 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 14/23] Revert "UBUNTU: SAUCE: Address upstream comments from patch v6 for PHY driver" Date: Fri, 9 Jul 2021 15:08:21 -0400 Message-Id: <20210709190830.5405-15-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit e65518a6eeb7dc24198700b1ec7e96ffdeab2b46. Signed-off-by: Asmaa Mnebhi --- .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 2 +- .../net/ethernet/mellanox/mlxbf_gige/Makefile | 2 +- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 10 +- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 103 ++------- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 208 ++++++++++++++---- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 4 +- 6 files changed, 192 insertions(+), 137 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig index 41c7a8997190..73c5d74081ee 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB # # Mellanox GigE driver configuration # diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile index e99fc19ac819..f6be6c692093 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index 63e07e60108d..f89199d562ad 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB */ /* Header file for Gigabit Ethernet driver for Mellanox BlueField SoC * - this file contains software data structures and any chip-specific * data structures (e.g. TX WQE format) that are memory resident. * - * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2020 Mellanox Technologies Ltd. */ #ifndef __MLXBF_GIGE_H__ @@ -101,13 +101,9 @@ struct mlxbf_gige { int error_irq; int rx_irq; int llu_plu_irq; - int phy_irq; bool promisc_enabled; struct napi_struct napi; struct mlxbf_gige_stats stats; - u32 tx_pause; - u32 rx_pause; - u32 aneg_pause; }; /* Rx Work Queue Element definitions */ @@ -155,6 +151,6 @@ enum mlxbf_gige_res { int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv); void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv); -irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id); +irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv); #endif /* !defined(__MLXBF_GIGE_H__) */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 0fd540bc50f7..d650e9c0a57f 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -1,8 +1,8 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB /* Gigabit Ethernet driver for Mellanox BlueField SoC * - * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2020 Mellanox Technologies Ltd. */ #include @@ -18,7 +18,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.3" +#define DRV_VERSION "1.2" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -474,11 +474,9 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, static void mlxbf_gige_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *pause) { - struct mlxbf_gige *priv = netdev_priv(netdev); - - pause->autoneg = priv->aneg_pause; - pause->rx_pause = priv->tx_pause; - pause->tx_pause = priv->rx_pause; + pause->autoneg = AUTONEG_ENABLE; + pause->rx_pause = 1; + pause->tx_pause = 1; } static const struct ethtool_ops mlxbf_gige_ethtool_ops = { @@ -496,6 +494,20 @@ static const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_link_ksettings = phy_ethtool_get_link_ksettings, }; +static void mlxbf_gige_handle_link_change(struct net_device *netdev) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; + irqreturn_t ret; + + ret = mlxbf_gige_mdio_handle_phy_interrupt(priv); + if (ret != IRQ_HANDLED) + return; + + /* print new link status only if the interrupt came from the PHY */ + phy_print_status(phydev); +} + /* Start of struct net_device_ops functions */ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) { @@ -789,15 +801,6 @@ static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) return err; } - err = request_threaded_irq(priv->phy_irq, NULL, - mlxbf_gige_mdio_handle_phy_interrupt, - IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", - priv); - if (err) { - dev_err(priv->dev, "Request phy_irq failure\n"); - return err; - } - return 0; } @@ -806,7 +809,6 @@ static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) devm_free_irq(priv->dev, priv->error_irq, priv); devm_free_irq(priv->dev, priv->rx_irq, priv); devm_free_irq(priv->dev, priv->llu_plu_irq, priv); - free_irq(priv->phy_irq, priv); } static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) @@ -848,38 +850,6 @@ static void mlxbf_gige_clean_port(struct mlxbf_gige *priv) writeq(control, priv->base + MLXBF_GIGE_CONTROL); } -static int mlxbf_gige_phy_enable_interrupt(struct phy_device *phydev) -{ - int ret = 0; - - if (phydev->drv->ack_interrupt) - ret = phydev->drv->ack_interrupt(phydev); - if (ret < 0) - return ret; - - phydev->interrupts = PHY_INTERRUPT_ENABLED; - if (phydev->drv->config_intr) - ret = phydev->drv->config_intr(phydev); - - return ret; -} - -static int mlxbf_gige_phy_disable_interrupt(struct phy_device *phydev) -{ - int ret = 0; - - if (phydev->drv->ack_interrupt) - ret = phydev->drv->ack_interrupt(phydev); - if (ret < 0) - return ret; - - phydev->interrupts = PHY_INTERRUPT_DISABLED; - if (phydev->drv->config_intr) - ret = phydev->drv->config_intr(phydev); - - return ret; -} - static int mlxbf_gige_open(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); @@ -900,14 +870,6 @@ static int mlxbf_gige_open(struct net_device *netdev) return err; phy_start(phydev); - /* Always make sure interrupts are enabled since phy_start calls - * __phy_resume which may reset the PHY interrupt control reg. - * __phy_resume only reenables the interrupts if - * phydev->irq != IRQ_IGNORE_INTERRUPT. - */ - err = mlxbf_gige_phy_enable_interrupt(phydev); - if (err) - return err; /* Set bits in INT_EN that we care about */ int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | @@ -932,8 +894,8 @@ static int mlxbf_gige_stop(struct net_device *netdev) netif_napi_del(&priv->napi); mlxbf_gige_free_irqs(priv); - phy_stop(netdev->phydev); - mlxbf_gige_phy_disable_interrupt(netdev->phydev); + if (netdev->phydev) + phy_stop(netdev->phydev); mlxbf_gige_rx_deinit(priv); mlxbf_gige_tx_deinit(priv); @@ -1111,12 +1073,6 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) local_mac); } -static void mlxbf_gige_adjust_link(struct net_device *netdev) -{ - /* Only one speed and one duplex supported */ - return; -} - static int mlxbf_gige_probe(struct platform_device *pdev) { struct phy_device *phydev; @@ -1130,7 +1086,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) void __iomem *base; u64 control; int err = 0; - int addr; mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); if (!mac_res) @@ -1202,21 +1157,16 @@ static int mlxbf_gige_probe(struct platform_device *pdev) priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX); priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); - priv->phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); phydev = phy_find_first(priv->mdiobus); if (!phydev) - return -ENODEV; - - addr = phydev->mdio.addr; - phydev->irq = priv->mdiobus->irq[addr] = PHY_IGNORE_INTERRUPT; + return -EIO; /* Sets netdev->phydev to phydev; which will eventually * be used in ioctl calls. - * Cannot pass NULL handler. */ err = phy_connect_direct(netdev, phydev, - mlxbf_gige_adjust_link, + mlxbf_gige_handle_link_change, PHY_INTERFACE_MODE_GMII); if (err) { dev_err(&pdev->dev, "Could not attach to PHY\n"); @@ -1233,11 +1183,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) /* MAC supports symmetric flow control */ phy_support_sym_pause(phydev); - /* Enable pause */ - priv->rx_pause = phydev->pause; - priv->tx_pause = phydev->pause; - priv->aneg_pause = AUTONEG_ENABLE; - /* Display information about attached PHY device */ phy_attached_info(phydev); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 464bfac9a650..7a225036ab59 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -1,7 +1,7 @@ -// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB /* MDIO support for Mellanox GigE driver * - * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2020 Mellanox Technologies Ltd. */ #include @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -22,6 +21,9 @@ #include "mlxbf_gige.h" +#define MLXBF_GIGE_MDIO_POLL_BUSY_TIMEOUT 100 /* ms */ +#define MLXBF_GIGE_MDIO_POLL_DELAY_USEC 100 /* us */ + #define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 #define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 @@ -32,6 +34,8 @@ /* Busy bit is set by software and cleared by hardware */ #define MLXBF_GIGE_MDIO_SET_BUSY 0x1 +/* Lock bit should be set/cleared by software */ +#define MLXBF_GIGE_MDIO_SET_LOCK 0x1 /* MDIO GW register bits */ #define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) @@ -40,6 +44,7 @@ #define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) #define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) #define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) +#define MLXBF_GIGE_MDIO_GW_LOCK_MASK GENMASK(31, 31) /* MDIO config register bits */ #define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) @@ -63,13 +68,20 @@ #define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) -#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ - MLXBF_GIGE_MDIO_PERIOD) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) +/* PHY should operate in master mode only */ +#define MLXBF_GIGE_MDIO_MODE_MASTER 1 + +/* PHY input voltage has to be 3.3V */ +#define MLXBF_GIGE_MDIO3_3 1 + +/* Operate in full drive mode */ +#define MLXBF_GIGE_MDIO_FULL_DRIVE 1 + +/* 6 cycles before the i1clk (core clock) rising edge that triggers the mdc */ +#define MLXBF_GIGE_MDIO_IN_SAMP 6 + +/* 13 cycles after the i1clk (core clock) rising edge that triggers the mdc */ +#define MLXBF_GIGE_MDIO_OUT_SAMP 13 /* The PHY interrupt line is shared with other interrupt lines such * as GPIO and SMBus. So use YU registers to determine whether the @@ -87,10 +99,6 @@ #define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 #define MLXBF_GIGE_GPIO12_BIT 12 -#define MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) -#define MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) -#define MLXBF_GIGE_CAUSE_FALL_EN_MASK BIT(MLXBF_GIGE_GPIO12_BIT) -#define MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK BIT(MLXBF_GIGE_GPIO12_BIT) static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, int phy_reg, u32 opcode) @@ -106,36 +114,65 @@ static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK, MLXBF_GIGE_MDIO_SET_BUSY); + /* Hold the lock until the read/write is completed so that no other + * program accesses the mdio bus. + */ + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_LOCK_MASK, + MLXBF_GIGE_MDIO_SET_LOCK); + return gw_reg; } +static int mlxbf_gige_mdio_poll_bit(struct mlxbf_gige *priv, u32 bit_mask) +{ + unsigned long timeout; + u32 val; + + timeout = jiffies + msecs_to_jiffies(MLXBF_GIGE_MDIO_POLL_BUSY_TIMEOUT); + do { + val = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + if (!(val & bit_mask)) + return 0; + udelay(MLXBF_GIGE_MDIO_POLL_DELAY_USEC); + } while (time_before(jiffies, timeout)); + + return -ETIME; +} + static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) { struct mlxbf_gige *priv = bus->priv; u32 cmd; - int ret; - u32 val; + u32 ret; - if (phy_reg & MII_ADDR_C45) - return -EOPNOTSUPP; + /* If the lock is held by something else, drop the request. + * If the lock is cleared, that means the busy bit was cleared. + */ + ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_LOCK_MASK); + if (ret) + return -EBUSY; /* Send mdio read request */ cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ); writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, - val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); - + ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_BUSY_MASK); if (ret) { writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - return ret; + return -EBUSY; } ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); /* Only return ad bits of the gw register */ ret &= MLXBF_GIGE_MDIO_GW_AD_MASK; + /* To release the YU MDIO lock, clear gw register, + * so that the YU does not confuse this write with a new + * MDIO read/write request. + */ + writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + return ret; } @@ -145,10 +182,13 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, struct mlxbf_gige *priv = bus->priv; u32 cmd; int ret; - u32 temp; - if (phy_reg & MII_ADDR_C45) - return -EOPNOTSUPP; + /* If the lock is held by something else, drop the request. + * If the lock is cleared, that means the busy bit was cleared. + */ + ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_LOCK_MASK); + if (ret) + return -EBUSY; /* Send mdio write request */ cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg, @@ -156,8 +196,13 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); /* If the poll timed out, drop the request */ - ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, - temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); + ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_BUSY_MASK); + + /* To release the YU MDIO lock, clear gw register, + * so that the YU does not confuse this write as a new + * MDIO read/write request. + */ + writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); return ret; } @@ -169,7 +214,7 @@ static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv) spin_lock_irqsave(&priv->gpio_lock, flags); val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val &= ~MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; + val &= ~priv->phy_int_gpio_mask; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); spin_unlock_irqrestore(&priv->gpio_lock, flags); } @@ -185,13 +230,13 @@ static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) * state goes low. */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); - val |= MLXBF_GIGE_CAUSE_FALL_EN_MASK; + val |= priv->phy_int_gpio_mask; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); /* Enable PHY interrupt by setting the priority level */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val |= MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; + val |= priv->phy_int_gpio_mask; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); spin_unlock_irqrestore(&priv->gpio_lock, flags); @@ -200,25 +245,33 @@ static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) /* Interrupt handler is called from mlxbf_gige_main.c * driver whenever a phy interrupt is received. */ -irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) +irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv) { - struct phy_device *phydev; - struct mlxbf_gige *priv; u32 val; - priv = dev_id; - phydev = priv->netdev->phydev; + /* The YU interrupt is shared between SMBus and GPIOs. + * So first, determine whether this is a GPIO interrupt. + */ + val = readl(priv->cause_rsh_coalesce0_io); + if (!MLXBF_GIGE_GPIO_CAUSE_IRQ_IS_SET(val)) { + /* Nothing to do here, not a GPIO interrupt */ + return IRQ_NONE; + } + /* Then determine which gpio register this interrupt is for. + * Return if the interrupt is not for gpio block 0. + */ + val = readl(priv->cause_gpio_arm_coalesce0_io); + if (!(val & MLXBF_GIGE_GPIO_BLOCK0_MASK)) + return IRQ_NONE; - /* Check if this interrupt is from PHY device. + /* Finally check if this interrupt is from PHY device. * Return if it is not. */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); - if (!(val & MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK)) + if (!(val & priv->phy_int_gpio_mask)) return IRQ_NONE; - phy_mac_interrupt(phydev); - /* Clear interrupt when done, otherwise, no further interrupt * will be triggered. * Writing 0x1 to the clear cause register also clears the @@ -228,22 +281,67 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id) */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); - val |= MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK; + val |= priv->phy_int_gpio_mask; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); - /* Make sure to clear the PHY device interrupt */ - if (phydev->drv->ack_interrupt) - phydev->drv->ack_interrupt(phydev); - return IRQ_HANDLED; } +static void mlxbf_gige_mdio_init_config(struct mlxbf_gige *priv) +{ + struct device *dev = priv->dev; + u32 mdio_full_drive; + u32 mdio_out_sample; + u32 mdio_in_sample; + u32 mdio_voltage; + u32 mdc_period; + u32 mdio_mode; + u32 mdio_cfg; + int ret; + + ret = device_property_read_u32(dev, "mdio-mode", &mdio_mode); + if (ret < 0) + mdio_mode = MLXBF_GIGE_MDIO_MODE_MASTER; + + ret = device_property_read_u32(dev, "mdio-voltage", &mdio_voltage); + if (ret < 0) + mdio_voltage = MLXBF_GIGE_MDIO3_3; + + ret = device_property_read_u32(dev, "mdio-full-drive", &mdio_full_drive); + if (ret < 0) + mdio_full_drive = MLXBF_GIGE_MDIO_FULL_DRIVE; + + ret = device_property_read_u32(dev, "mdc-period", &mdc_period); + if (ret < 0) + mdc_period = MLXBF_GIGE_MDIO_PERIOD; + + ret = device_property_read_u32(dev, "mdio-in-sample", &mdio_in_sample); + if (ret < 0) + mdio_in_sample = MLXBF_GIGE_MDIO_IN_SAMP; + + ret = device_property_read_u32(dev, "mdio-out-sample", &mdio_out_sample); + if (ret < 0) + mdio_out_sample = MLXBF_GIGE_MDIO_OUT_SAMP; + + mdio_cfg = FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, mdio_mode) | + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, mdio_voltage) | + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, mdio_full_drive) | + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdc_period) | + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, mdio_in_sample) | + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, mdio_out_sample); + + writel(mdio_cfg, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); +} + int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) { struct device *dev = &pdev->dev; struct resource *res; + u32 phy_int_gpio; + u32 phy_addr; int ret; + int irq; res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); if (!res) @@ -281,9 +379,12 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) if (!priv->cause_gpio_arm_coalesce0_io) return -ENOMEM; - /* Configure mdio parameters */ - writel(MLXBF_GIGE_MDIO_CFG_VAL, - priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); + mlxbf_gige_mdio_init_config(priv); + + ret = device_property_read_u32(dev, "phy-int-gpio", &phy_int_gpio); + if (ret < 0) + phy_int_gpio = MLXBF_GIGE_GPIO12_BIT; + priv->phy_int_gpio_mask = BIT(phy_int_gpio); mlxbf_gige_mdio_enable_phy_int(priv); @@ -301,6 +402,19 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s", dev_name(dev)); + ret = device_property_read_u32(dev, "phy-addr", &phy_addr); + if (ret < 0) + phy_addr = MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR; + + irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); + if (irq < 0) { + dev_err(dev, "Failed to retrieve irq 0x%x\n", irq); + return -ENODEV; + } + priv->mdiobus->irq[phy_addr] = PHY_POLL; + + /* Auto probe PHY at the corresponding address */ + priv->mdiobus->phy_mask = ~(1 << phy_addr); ret = mdiobus_register(priv->mdiobus); if (ret) dev_err(dev, "Failed to register MDIO bus\n"); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index 06e3c7145bbd..9c7af820c197 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ +/* SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB */ /* Header file for Mellanox BlueField GigE register defines * - * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2020 Mellanox Technologies Ltd. */ #ifndef __MLXBF_GIGE_REGS_H__ From patchwork Fri Jul 9 19:08:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503338 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2mM03B8z9sRN; Sat, 10 Jul 2021 05:10:11 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsy-0003yg-Rq; Fri, 09 Jul 2021 19:10:04 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrt-0003DG-12 for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:57 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:55 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8st4030232; Fri, 9 Jul 2021 15:08:54 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8sPb005468; Fri, 9 Jul 2021 15:08:54 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 15/23] Revert "UBUNTU: SAUCE: mlxbf-gige: cleanups from review" Date: Fri, 9 Jul 2021 15:08:22 -0400 Message-Id: <20210709190830.5405-16-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 3a4caceacdce4bda2c60220e6a2d22a1243a1121. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index d650e9c0a57f..d074bf9ef5c2 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -18,7 +18,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.2" +#define DRV_VERSION "1.1" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -36,14 +36,16 @@ static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, writeq(control, base + MLXBF_GIGE_CONTROL); } -static void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 *dmac) +static int mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 *dmac) { void __iomem *base = priv->base; /* Read destination MAC from specified MAC RX filter */ *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); + + return 0; } static void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) @@ -252,9 +254,9 @@ static void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) dma_free_coherent(priv->dev, size, priv->rx_cqe_base, priv->rx_cqe_base_dma); - priv->rx_wqe_base = NULL; + priv->rx_wqe_base = 0; priv->rx_wqe_base_dma = 0; - priv->rx_cqe_base = NULL; + priv->rx_cqe_base = 0; priv->rx_cqe_base_dma = 0; writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE); writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE); @@ -288,11 +290,11 @@ static void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, priv->tx_cc, priv->tx_cc_dma); - priv->tx_wqe_base = NULL; + priv->tx_wqe_base = 0; priv->tx_wqe_base_dma = 0; - priv->tx_cc = NULL; + priv->tx_cc = 0; priv->tx_cc_dma = 0; - priv->tx_wqe_next = NULL; + priv->tx_wqe_next = 0; writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE); writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); } @@ -312,7 +314,7 @@ static void mlxbf_gige_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { struct mlxbf_gige *priv = netdev_priv(netdev); - __be64 *buff = p; + u64 *buff = p; int reg; regs->version = MLXBF_GIGE_REGS_VERSION; @@ -1054,9 +1056,10 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) { u8 mac[ETH_ALEN]; u64 local_mac; + int status; - mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, - &local_mac); + status = mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, + &local_mac); mlxbf_gige_u64_to_mac(mac, local_mac); if (is_valid_ether_addr(mac)) { @@ -1189,7 +1192,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); - phy_disconnect(phydev); return err; } @@ -1200,8 +1202,8 @@ static int mlxbf_gige_remove(struct platform_device *pdev) { struct mlxbf_gige *priv = platform_get_drvdata(pdev); - unregister_netdev(priv->netdev); phy_disconnect(priv->netdev->phydev); + unregister_netdev(priv->netdev); mlxbf_gige_mdio_remove(priv); platform_set_drvdata(pdev, NULL); From patchwork Fri Jul 9 19:08:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503330 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lg5rpTz9sWw; Sat, 10 Jul 2021 05:09:35 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsQ-0003bZ-66; Fri, 09 Jul 2021 19:09:30 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrs-0003DK-Us for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:08:57 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:55 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8tC6030237; Fri, 9 Jul 2021 15:08:55 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8t9D005469; Fri, 9 Jul 2021 15:08:55 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 16/23] Revert "UBUNTU: SAUCE: mlxbf-gige: v5 patch cleanup and napi_schedule" Date: Fri, 9 Jul 2021 15:08:23 -0400 Message-Id: <20210709190830.5405-17-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 7053846f4bf68ff28386eda82aac2aa05e544c6b. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 5 +- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 21 +- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 198 +++++++----------- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 2 +- 4 files changed, 89 insertions(+), 137 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index f89199d562ad..a32e5da07f56 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -4,7 +4,7 @@ * - this file contains software data structures and any chip-specific * data structures (e.g. TX WQE format) that are memory resident. * - * Copyright (c) 2020 Mellanox Technologies Ltd. + * Copyright (c) 2020, Mellanox Technologies */ #ifndef __MLXBF_GIGE_H__ @@ -48,7 +48,7 @@ #define MLXBF_GIGE_LLU_PLU_INTR_IDX 2 #define MLXBF_GIGE_PHY_INT_N 3 -#define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3 +#define MLXBF_GIGE_DEFAULT_PHY_ADDR 0x3 struct mlxbf_gige_stats { u64 hw_access_errors; @@ -77,7 +77,6 @@ struct mlxbf_gige { void __iomem *gpio_io; void __iomem *cause_rsh_coalesce0_io; void __iomem *cause_gpio_arm_coalesce0_io; - u32 phy_int_gpio_mask; spinlock_t lock; spinlock_t gpio_lock; u16 rx_q_entries; diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index d074bf9ef5c2..75263fcd542e 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -2,7 +2,7 @@ /* Gigabit Ethernet driver for Mellanox BlueField SoC * - * Copyright (c) 2020 Mellanox Technologies Ltd. + * Copyright (c) 2020, Mellanox Technologies */ #include @@ -631,8 +631,8 @@ static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) if (priv->prev_tx_ci == priv->tx_pi) avail = priv->tx_q_entries - 1; else - avail = ((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) - % priv->tx_q_entries) - 1; + avail = (((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) + % priv->tx_q_entries) - 1); spin_unlock_irqrestore(&priv->lock, flags); @@ -665,8 +665,8 @@ static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) * buffer address and the 8 LSB contain information * about the TX WQE. */ - tx_wqe_addr = priv->tx_wqe_base + - (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS); + tx_wqe_addr = (priv->tx_wqe_base + + (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS)); stats->tx_packets++; stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); @@ -934,12 +934,6 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, /* TX ring is full, inform stack but do not free SKB */ netif_stop_queue(netdev); netdev->stats.tx_dropped++; - /* Since there is no separate "TX complete" interrupt, need - * to explicitly schedule NAPI poll. This will trigger logic - * which processes TX completions, and will hopefully drain - * the TX ring allowing the TX queue to be awakened. - */ - napi_schedule(&priv->napi); return NETDEV_TX_BUSY; } @@ -980,9 +974,6 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, priv->tx_pi++; - /* Create memory barrier before write to TX PI */ - wmb(); - writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); /* Free incoming skb, contents already copied to HW */ @@ -1017,8 +1008,8 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) mlxbf_gige_enable_promisc(priv); else mlxbf_gige_disable_promisc(priv); - } } +} static const struct net_device_ops mlxbf_gige_netdev_ops = { .ndo_open = mlxbf_gige_open, diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 7a225036ab59..200a221deb3e 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -1,11 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB /* MDIO support for Mellanox GigE driver * - * Copyright (c) 2020 Mellanox Technologies Ltd. + * Copyright (C) 2020 Mellanox Technologies, Ltd. */ #include -#include #include #include #include @@ -21,38 +20,45 @@ #include "mlxbf_gige.h" -#define MLXBF_GIGE_MDIO_POLL_BUSY_TIMEOUT 100 /* ms */ -#define MLXBF_GIGE_MDIO_POLL_DELAY_USEC 100 /* us */ +#define MLXBF_GIGE_POLL_BUSY_TIMEOUT 100 /* ms */ +#define MLXBF_GIGE_POLL_DELAY_USEC 100 /* microsec */ #define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 #define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 /* Support clause 22 */ -#define MLXBF_GIGE_MDIO_CL22_ST1 0x1 -#define MLXBF_GIGE_MDIO_CL22_WRITE 0x1 -#define MLXBF_GIGE_MDIO_CL22_READ 0x2 +#define MLXBF_GIGE_CL22_ST1 0x1 +#define MLXBF_GIGE_CL22_MDIO_WRITE 0x1 +#define MLXBF_GIGE_CL22_MDIO_READ 0x2 /* Busy bit is set by software and cleared by hardware */ -#define MLXBF_GIGE_MDIO_SET_BUSY 0x1 +#define MLXBF_GIGE_SET_MDIO_BUSY 0x1 /* Lock bit should be set/cleared by software */ -#define MLXBF_GIGE_MDIO_SET_LOCK 0x1 +#define MLXBF_GIGE_SET_MDIO_LOCK 0x1 /* MDIO GW register bits */ -#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) -#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) -#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) -#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) -#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) -#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) -#define MLXBF_GIGE_MDIO_GW_LOCK_MASK GENMASK(31, 31) +#define MLXBF_GIGE_MDIO_GW_AD_SHIFT 0 +#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) +#define MLXBF_GIGE_MDIO_GW_DEVAD_SHIFT 16 +#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) +#define MLXBF_GIGE_MDIO_GW_PARTAD_SHIFT 21 +#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) +#define MLXBF_GIGE_MDIO_GW_OPCODE_SHIFT 26 +#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) +#define MLXBF_GIGE_MDIO_GW_ST1_SHIFT 28 +#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) +#define MLXBF_GIGE_MDIO_GW_BUSY_SHIFT 30 +#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) +#define MLXBF_GIGE_MDIO_GW_LOCK_SHIFT 31 +#define MLXBF_GIGE_MDIO_GW_LOCK_MASK GENMASK(31, 31) /* MDIO config register bits */ -#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) -#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK GENMASK(2, 2) -#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(4, 4) -#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(15, 8) -#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) -#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) +#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_SHIFT 0 +#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_SHIFT 2 +#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_SHIFT 4 +#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_SHIFT 8 +#define MLXBF_GIGE_MDIO_CFG_MASTER_IN_SAMP_SHIFT 16 +#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_SHIFT 24 /* Formula for encoding the MDIO period. The encoded value is * passed to the MDIO config register. @@ -66,22 +72,26 @@ #define MLXBF_GIGE_I1CLK_MHZ 430 #define MLXBF_GIGE_MDC_CLK_NS 400 -#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) +#define MLXBF_GIGE_MDIO_PERIOD_VAL (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) +#define MLXBF_GIGE_MDIO_PERIOD (MLXBF_GIGE_MDIO_PERIOD_VAL << MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_SHIFT) /* PHY should operate in master mode only */ -#define MLXBF_GIGE_MDIO_MODE_MASTER 1 - +#define MLXBF_GIGE_MDIO_MODE_MASTER (0x1 << MLXBF_GIGE_MDIO_CFG_MDIO_MODE_SHIFT) /* PHY input voltage has to be 3.3V */ -#define MLXBF_GIGE_MDIO3_3 1 - +#define MLXBF_GIGE_MDIO3_3 (0x1 << MLXBF_GIGE_MDIO_CFG_MDIO3_3_SHIFT) /* Operate in full drive mode */ -#define MLXBF_GIGE_MDIO_FULL_DRIVE 1 - +#define MLXBF_GIGE_MDIO_FULL_DRIVE (0x1 << MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_SHIFT) /* 6 cycles before the i1clk (core clock) rising edge that triggers the mdc */ -#define MLXBF_GIGE_MDIO_IN_SAMP 6 - +#define MLXBF_GIGE_MDIO_MASTER_IN_SAMP (6 << MLXBF_GIGE_MDIO_CFG_MASTER_IN_SAMP_SHIFT) /* 13 cycles after the i1clk (core clock) rising edge that triggers the mdc */ -#define MLXBF_GIGE_MDIO_OUT_SAMP 13 +#define MLXBF_GIGE_MDIO_MDIO_OUT_SAMP (13 << MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_SHIFT) + +#define MLXBF_GIGE_MDIO_CFG_VAL (MLXBF_GIGE_MDIO_MODE_MASTER | \ + MLXBF_GIGE_MDIO3_3 | \ + MLXBF_GIGE_MDIO_FULL_DRIVE | \ + MLXBF_GIGE_MDIO_PERIOD | \ + MLXBF_GIGE_MDIO_MASTER_IN_SAMP | \ + MLXBF_GIGE_MDIO_MDIO_OUT_SAMP) /* The PHY interrupt line is shared with other interrupt lines such * as GPIO and SMBus. So use YU registers to determine whether the @@ -99,26 +109,34 @@ #define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 #define MLXBF_GIGE_GPIO12_BIT 12 +#define MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) +#define MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) +#define MLXBF_GIGE_CAUSE_FALL_EN_MASK BIT(MLXBF_GIGE_GPIO12_BIT) +#define MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK BIT(MLXBF_GIGE_GPIO12_BIT) static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, int phy_reg, u32 opcode) { u32 gw_reg = 0; - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data); - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg); - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add); - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode); - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK, - MLXBF_GIGE_MDIO_CL22_ST1); - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK, - MLXBF_GIGE_MDIO_SET_BUSY); + gw_reg |= (data << MLXBF_GIGE_MDIO_GW_AD_SHIFT) & + MLXBF_GIGE_MDIO_GW_AD_MASK; + gw_reg |= ((phy_reg << MLXBF_GIGE_MDIO_GW_DEVAD_SHIFT) & + MLXBF_GIGE_MDIO_GW_DEVAD_MASK); + gw_reg |= ((phy_add << MLXBF_GIGE_MDIO_GW_PARTAD_SHIFT) & + MLXBF_GIGE_MDIO_GW_PARTAD_MASK); + gw_reg |= ((opcode << MLXBF_GIGE_MDIO_GW_OPCODE_SHIFT) & + MLXBF_GIGE_MDIO_GW_OPCODE_MASK); + gw_reg |= ((MLXBF_GIGE_CL22_ST1 << MLXBF_GIGE_MDIO_GW_ST1_SHIFT) & + MLXBF_GIGE_MDIO_GW_ST1_MASK); + gw_reg |= ((MLXBF_GIGE_SET_MDIO_BUSY << MLXBF_GIGE_MDIO_GW_BUSY_SHIFT) & + MLXBF_GIGE_MDIO_GW_BUSY_MASK); /* Hold the lock until the read/write is completed so that no other * program accesses the mdio bus. */ - gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_LOCK_MASK, - MLXBF_GIGE_MDIO_SET_LOCK); + gw_reg |= ((MLXBF_GIGE_SET_MDIO_LOCK << MLXBF_GIGE_MDIO_GW_LOCK_SHIFT) & + MLXBF_GIGE_MDIO_GW_LOCK_MASK); return gw_reg; } @@ -128,12 +146,12 @@ static int mlxbf_gige_mdio_poll_bit(struct mlxbf_gige *priv, u32 bit_mask) unsigned long timeout; u32 val; - timeout = jiffies + msecs_to_jiffies(MLXBF_GIGE_MDIO_POLL_BUSY_TIMEOUT); + timeout = jiffies + msecs_to_jiffies(MLXBF_GIGE_POLL_BUSY_TIMEOUT); do { val = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); if (!(val & bit_mask)) return 0; - udelay(MLXBF_GIGE_MDIO_POLL_DELAY_USEC); + udelay(MLXBF_GIGE_POLL_DELAY_USEC); } while (time_before(jiffies, timeout)); return -ETIME; @@ -153,7 +171,7 @@ static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) return -EBUSY; /* Send mdio read request */ - cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ); + cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_CL22_MDIO_READ); writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); @@ -192,7 +210,7 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, /* Send mdio write request */ cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg, - MLXBF_GIGE_MDIO_CL22_WRITE); + MLXBF_GIGE_CL22_MDIO_WRITE); writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); /* If the poll timed out, drop the request */ @@ -207,19 +225,19 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, return ret; } -static void mlxbf_gige_mdio_disable_phy_int(struct mlxbf_gige *priv) +static void mlxbf_gige_mdio_disable_gpio12_irq(struct mlxbf_gige *priv) { unsigned long flags; u32 val; spin_lock_irqsave(&priv->gpio_lock, flags); val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val &= ~priv->phy_int_gpio_mask; + val &= ~MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); spin_unlock_irqrestore(&priv->gpio_lock, flags); } -static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) +static void mlxbf_gige_mdio_enable_gpio12_irq(struct mlxbf_gige *priv) { unsigned long flags; u32 val; @@ -230,13 +248,13 @@ static void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv) * state goes low. */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); - val |= priv->phy_int_gpio_mask; + val |= MLXBF_GIGE_CAUSE_FALL_EN_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); - /* Enable PHY interrupt by setting the priority level */ + /* Enable GPIO 12 interrupt by setting the priority level */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val |= priv->phy_int_gpio_mask; + val |= MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); spin_unlock_irqrestore(&priv->gpio_lock, flags); @@ -264,84 +282,36 @@ irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv) if (!(val & MLXBF_GIGE_GPIO_BLOCK0_MASK)) return IRQ_NONE; - /* Finally check if this interrupt is from PHY device. + /* Finally check if this interrupt is for gpio pin 12. * Return if it is not. */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); - if (!(val & priv->phy_int_gpio_mask)) + if (!(val & MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK)) return IRQ_NONE; /* Clear interrupt when done, otherwise, no further interrupt * will be triggered. - * Writing 0x1 to the clear cause register also clears the + * Writing 0x1 to the clrcause register also clears the * following registers: * cause_gpio_arm_coalesce0 * cause_rsh_coalesce0 */ val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); - val |= priv->phy_int_gpio_mask; + val |= MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); return IRQ_HANDLED; } -static void mlxbf_gige_mdio_init_config(struct mlxbf_gige *priv) -{ - struct device *dev = priv->dev; - u32 mdio_full_drive; - u32 mdio_out_sample; - u32 mdio_in_sample; - u32 mdio_voltage; - u32 mdc_period; - u32 mdio_mode; - u32 mdio_cfg; - int ret; - - ret = device_property_read_u32(dev, "mdio-mode", &mdio_mode); - if (ret < 0) - mdio_mode = MLXBF_GIGE_MDIO_MODE_MASTER; - - ret = device_property_read_u32(dev, "mdio-voltage", &mdio_voltage); - if (ret < 0) - mdio_voltage = MLXBF_GIGE_MDIO3_3; - - ret = device_property_read_u32(dev, "mdio-full-drive", &mdio_full_drive); - if (ret < 0) - mdio_full_drive = MLXBF_GIGE_MDIO_FULL_DRIVE; - - ret = device_property_read_u32(dev, "mdc-period", &mdc_period); - if (ret < 0) - mdc_period = MLXBF_GIGE_MDIO_PERIOD; - - ret = device_property_read_u32(dev, "mdio-in-sample", &mdio_in_sample); - if (ret < 0) - mdio_in_sample = MLXBF_GIGE_MDIO_IN_SAMP; - - ret = device_property_read_u32(dev, "mdio-out-sample", &mdio_out_sample); - if (ret < 0) - mdio_out_sample = MLXBF_GIGE_MDIO_OUT_SAMP; - - mdio_cfg = FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, mdio_mode) | - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, mdio_voltage) | - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, mdio_full_drive) | - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, mdc_period) | - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, mdio_in_sample) | - FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, mdio_out_sample); - - writel(mdio_cfg, priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); -} - int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) { struct device *dev = &pdev->dev; struct resource *res; - u32 phy_int_gpio; u32 phy_addr; int ret; - int irq; res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); if (!res) @@ -379,14 +349,11 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) if (!priv->cause_gpio_arm_coalesce0_io) return -ENOMEM; - mlxbf_gige_mdio_init_config(priv); - - ret = device_property_read_u32(dev, "phy-int-gpio", &phy_int_gpio); - if (ret < 0) - phy_int_gpio = MLXBF_GIGE_GPIO12_BIT; - priv->phy_int_gpio_mask = BIT(phy_int_gpio); + /* Configure mdio parameters */ + writel(MLXBF_GIGE_MDIO_CFG_VAL, + priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); - mlxbf_gige_mdio_enable_phy_int(priv); + mlxbf_gige_mdio_enable_gpio12_irq(priv); priv->mdiobus = devm_mdiobus_alloc(dev); if (!priv->mdiobus) { @@ -404,13 +371,8 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) ret = device_property_read_u32(dev, "phy-addr", &phy_addr); if (ret < 0) - phy_addr = MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR; + phy_addr = MLXBF_GIGE_DEFAULT_PHY_ADDR; - irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); - if (irq < 0) { - dev_err(dev, "Failed to retrieve irq 0x%x\n", irq); - return -ENODEV; - } priv->mdiobus->irq[phy_addr] = PHY_POLL; /* Auto probe PHY at the corresponding address */ @@ -424,6 +386,6 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv) { - mlxbf_gige_mdio_disable_phy_int(priv); + mlxbf_gige_mdio_disable_gpio12_irq(priv); mdiobus_unregister(priv->mdiobus); } diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index 9c7af820c197..ff490c70fff1 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -2,7 +2,7 @@ /* Header file for Mellanox BlueField GigE register defines * - * Copyright (c) 2020 Mellanox Technologies Ltd. + * Copyright (c) 2020, Mellanox Technologies */ #ifndef __MLXBF_GIGE_REGS_H__ From patchwork Fri Jul 9 19:08:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503335 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2m03Hlvz9sPf; Sat, 10 Jul 2021 05:09:52 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsf-0003mi-6d; Fri, 09 Jul 2021 19:09:45 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrx-0003G2-17 for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:01 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:56 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8tMD030244; Fri, 9 Jul 2021 15:08:55 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8tdI005470; Fri, 9 Jul 2021 15:08:55 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 17/23] Revert "UBUNTU: SAUCE: mlxbf_gige_main.c: Fix OOB's ethtool command" Date: Fri, 9 Jul 2021 15:08:24 -0400 Message-Id: <20210709190830.5405-18-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit a9139cd0033706cfc4610009f61035ec2c155a16. Signed-off-by: Asmaa Mnebhi --- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 75263fcd542e..b267d473f978 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -481,6 +481,50 @@ static void mlxbf_gige_get_pauseparam(struct net_device *netdev, pause->tx_pause = 1; } +static int mlxbf_gige_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *link_ksettings) +{ + struct phy_device *phydev = netdev->phydev; + u32 supported, advertising; + u32 lp_advertising = 0; + int status; + + supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full | + SUPPORTED_Autoneg | SUPPORTED_Pause; + + advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | + ADVERTISED_Pause; + + status = phy_read(phydev, MII_LPA); + if (status >= 0) { + lp_advertising = mii_lpa_to_ethtool_lpa_t(status & 0xffff); + } + + status = phy_read(phydev, MII_STAT1000); + if (status >= 0) { + lp_advertising |= mii_stat1000_to_ethtool_lpa_t(status & 0xffff); + } + + ethtool_convert_legacy_u32_to_link_mode(link_ksettings->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(link_ksettings->link_modes.advertising, + advertising); + ethtool_convert_legacy_u32_to_link_mode(link_ksettings->link_modes.lp_advertising, + lp_advertising); + + link_ksettings->base.autoneg = AUTONEG_ENABLE; + link_ksettings->base.speed = SPEED_1000; + link_ksettings->base.duplex = DUPLEX_FULL; + link_ksettings->base.port = PORT_TP; + link_ksettings->base.phy_address = MLXBF_GIGE_DEFAULT_PHY_ADDR; + link_ksettings->base.transceiver = XCVR_INTERNAL; + link_ksettings->base.mdio_support = ETH_MDIO_SUPPORTS_C22; + link_ksettings->base.eth_tp_mdix = ETH_TP_MDI_INVALID; + link_ksettings->base.eth_tp_mdix_ctrl = ETH_TP_MDI_INVALID; + + return 0; +} + static const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_drvinfo = mlxbf_gige_get_drvinfo, .get_link = ethtool_op_get_link, @@ -493,7 +537,7 @@ static const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, .nway_reset = phy_ethtool_nway_reset, .get_pauseparam = mlxbf_gige_get_pauseparam, - .get_link_ksettings = phy_ethtool_get_link_ksettings, + .get_link_ksettings = mlxbf_gige_get_link_ksettings, }; static void mlxbf_gige_handle_link_change(struct net_device *netdev) From patchwork Fri Jul 9 19:08:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503336 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2m41SY7z9sRN; Sat, 10 Jul 2021 05:09:56 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsk-0003pa-4J; Fri, 09 Jul 2021 19:09:50 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrx-0003G3-0Y for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:01 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:57 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8uM2030247; Fri, 9 Jul 2021 15:08:56 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8ugL005471; Fri, 9 Jul 2021 15:08:56 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 18/23] Revert "UBUNTU: SAUCE: mlxbf_gige_main.c: Support ethtool options" Date: Fri, 9 Jul 2021 15:08:25 -0400 Message-Id: <20210709190830.5405-19-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 9f965ce4074635f1e477e6e67aa0d9de8963f55d. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 2 - .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 55 ------------------- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 2 + 3 files changed, 2 insertions(+), 57 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index a32e5da07f56..adbdc90ddae4 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -48,8 +48,6 @@ #define MLXBF_GIGE_LLU_PLU_INTR_IDX 2 #define MLXBF_GIGE_PHY_INT_N 3 -#define MLXBF_GIGE_DEFAULT_PHY_ADDR 0x3 - struct mlxbf_gige_stats { u64 hw_access_errors; u64 tx_invalid_checksums; diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index b267d473f978..abd3fc661e6f 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -473,58 +473,6 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, spin_unlock_irqrestore(&priv->lock, flags); } -static void mlxbf_gige_get_pauseparam(struct net_device *netdev, - struct ethtool_pauseparam *pause) -{ - pause->autoneg = AUTONEG_ENABLE; - pause->rx_pause = 1; - pause->tx_pause = 1; -} - -static int mlxbf_gige_get_link_ksettings(struct net_device *netdev, - struct ethtool_link_ksettings *link_ksettings) -{ - struct phy_device *phydev = netdev->phydev; - u32 supported, advertising; - u32 lp_advertising = 0; - int status; - - supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full | - SUPPORTED_Autoneg | SUPPORTED_Pause; - - advertising = ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg | - ADVERTISED_Pause; - - status = phy_read(phydev, MII_LPA); - if (status >= 0) { - lp_advertising = mii_lpa_to_ethtool_lpa_t(status & 0xffff); - } - - status = phy_read(phydev, MII_STAT1000); - if (status >= 0) { - lp_advertising |= mii_stat1000_to_ethtool_lpa_t(status & 0xffff); - } - - ethtool_convert_legacy_u32_to_link_mode(link_ksettings->link_modes.supported, - supported); - ethtool_convert_legacy_u32_to_link_mode(link_ksettings->link_modes.advertising, - advertising); - ethtool_convert_legacy_u32_to_link_mode(link_ksettings->link_modes.lp_advertising, - lp_advertising); - - link_ksettings->base.autoneg = AUTONEG_ENABLE; - link_ksettings->base.speed = SPEED_1000; - link_ksettings->base.duplex = DUPLEX_FULL; - link_ksettings->base.port = PORT_TP; - link_ksettings->base.phy_address = MLXBF_GIGE_DEFAULT_PHY_ADDR; - link_ksettings->base.transceiver = XCVR_INTERNAL; - link_ksettings->base.mdio_support = ETH_MDIO_SUPPORTS_C22; - link_ksettings->base.eth_tp_mdix = ETH_TP_MDI_INVALID; - link_ksettings->base.eth_tp_mdix_ctrl = ETH_TP_MDI_INVALID; - - return 0; -} - static const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_drvinfo = mlxbf_gige_get_drvinfo, .get_link = ethtool_op_get_link, @@ -535,9 +483,6 @@ static const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_strings = mlxbf_gige_get_strings, .get_sset_count = mlxbf_gige_get_sset_count, .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, - .nway_reset = phy_ethtool_nway_reset, - .get_pauseparam = mlxbf_gige_get_pauseparam, - .get_link_ksettings = mlxbf_gige_get_link_ksettings, }; static void mlxbf_gige_handle_link_change(struct net_device *netdev) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index 200a221deb3e..e5c535270a25 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -20,6 +20,8 @@ #include "mlxbf_gige.h" +#define MLXBF_GIGE_DEFAULT_PHY_ADDR 0x3 + #define MLXBF_GIGE_POLL_BUSY_TIMEOUT 100 /* ms */ #define MLXBF_GIGE_POLL_DELAY_USEC 100 /* microsec */ From patchwork Fri Jul 9 19:08:26 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503339 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2mP49Q6z9sWw; Sat, 10 Jul 2021 05:10:13 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vt2-00041e-Ia; Fri, 09 Jul 2021 19:10:08 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrx-0003G5-4R for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:01 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:57 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8vLx030250; Fri, 9 Jul 2021 15:08:57 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8vJt005472; Fri, 9 Jul 2021 15:08:57 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 19/23] Revert "UBUNTU: SAUCE: mlxbf-gige: multiple fixes for stability" Date: Fri, 9 Jul 2021 15:08:26 -0400 Message-Id: <20210709190830.5405-20-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 1ebccff108540a2134e27abb7d3c12caf9b9810c. Signed-off-by: Asmaa Mnebhi --- .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 2 +- .../net/ethernet/mellanox/mlxbf_gige/Makefile | 2 +- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 15 +- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 236 +++++++++--------- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 18 +- 5 files changed, 133 insertions(+), 140 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig index 73c5d74081ee..60712e2d0a69 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB +# SPDX-License-Identifier: GPL-2.0-only # # Mellanox GigE driver configuration # diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile index f6be6c692093..165122b9622a 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile @@ -1,4 +1,4 @@ -# SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB +# SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index adbdc90ddae4..31213c47919c 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -13,13 +13,8 @@ #include #include -/* The silicon design supports a maximum RX ring size of - * 32K entries. Based on current testing this maximum size - * is not required to be supported. Instead the RX ring - * will be capped at a realistic value of 1024 entries. - */ #define MLXBF_GIGE_MIN_RXQ_SZ 32 -#define MLXBF_GIGE_MAX_RXQ_SZ 1024 +#define MLXBF_GIGE_MAX_RXQ_SZ 32768 #define MLXBF_GIGE_DEFAULT_RXQ_SZ 128 #define MLXBF_GIGE_MIN_TXQ_SZ 4 @@ -28,6 +23,9 @@ #define MLXBF_GIGE_DEFAULT_BUF_SZ 2048 +/* Known pattern for initial state of RX buffers */ +#define MLXBF_GIGE_INIT_BYTE_RX_BUF 0x10 + /* There are four individual MAC RX filters. Currently * two of them are being used: one for the broadcast MAC * (index 0) and one for local MAC (index 1) @@ -75,7 +73,6 @@ struct mlxbf_gige { void __iomem *gpio_io; void __iomem *cause_rsh_coalesce0_io; void __iomem *cause_gpio_arm_coalesce0_io; - spinlock_t lock; spinlock_t gpio_lock; u16 rx_q_entries; u16 tx_q_entries; @@ -93,8 +90,8 @@ struct mlxbf_gige { u64 error_intr_count; u64 rx_intr_count; u64 llu_plu_intr_count; - u8 *rx_buf[MLXBF_GIGE_MAX_RXQ_SZ]; - u8 *tx_buf[MLXBF_GIGE_MAX_TXQ_SZ]; + u8 *rx_buf[MLXBF_GIGE_DEFAULT_RXQ_SZ]; + u8 *tx_buf[MLXBF_GIGE_DEFAULT_TXQ_SZ]; int error_irq; int rx_irq; int llu_plu_irq; diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index abd3fc661e6f..88b0406c2d9e 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -18,7 +18,7 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.1" +#define DRV_VERSION "1.0" static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) @@ -431,9 +431,6 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, u64 *data) { struct mlxbf_gige *priv = netdev_priv(netdev); - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); /* Fill data array with interface statistics * @@ -469,8 +466,6 @@ static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); *data++ = (priv->stats.rx_filter_discard_pkts + readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); - - spin_unlock_irqrestore(&priv->lock, flags); } static const struct ethtool_ops mlxbf_gige_ethtool_ops = { @@ -511,8 +506,9 @@ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); - if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) + if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) { priv->stats.hw_access_errors++; + } if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { priv->stats.tx_invalid_checksums++; @@ -537,14 +533,17 @@ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) */ } - if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) + if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) { priv->stats.tx_index_errors++; + } - if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) + if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) { priv->stats.sw_config_errors++; + } - if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) + if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) { priv->stats.sw_access_errors++; + } /* Clear all error interrupts by writing '1' back to * all the asserted bits in INT_STATUS. Do not write @@ -612,19 +611,13 @@ static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) */ static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) { - unsigned long flags; u16 avail; - spin_lock_irqsave(&priv->lock, flags); - if (priv->prev_tx_ci == priv->tx_pi) avail = priv->tx_q_entries - 1; else avail = (((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) % priv->tx_q_entries) - 1); - - spin_unlock_irqrestore(&priv->lock, flags); - return avail; } @@ -700,29 +693,28 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) /* Packet is OK, increment stats */ netdev->stats.rx_packets++; netdev->stats.rx_bytes += datalen; - - skb = dev_alloc_skb(datalen); - if (!skb) { - netdev->stats.rx_dropped++; - return false; - } - - memcpy(skb_put(skb, datalen), pktp, datalen); - - skb->dev = netdev; - skb->protocol = eth_type_trans(skb, netdev); - skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ - - netif_receive_skb(skb); } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { priv->stats.rx_mac_errors++; } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { priv->stats.rx_truncate_errors++; } + skb = dev_alloc_skb(datalen); + if (!skb) { + netdev->stats.rx_dropped++; + return false; + } + + memcpy(skb_put(skb, datalen), pktp, datalen); + /* Let hardware know we've replenished one buffer */ writeq(rx_pi + 1, priv->base + MLXBF_GIGE_RX_WQE_PI); + skb->dev = netdev; + skb->protocol = eth_type_trans(skb, netdev); + skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ + + netif_receive_skb(skb); (*rx_pkts)++; rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); rx_pi_rem = rx_pi % priv->rx_q_entries; @@ -802,54 +794,15 @@ static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) devm_free_irq(priv->dev, priv->llu_plu_irq, priv); } -static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) -{ - struct mlxbf_gige_stats *p; - - /* Cache stats that will be cleared by clean port operation */ - p = &priv->stats; - p->rx_din_dropped_pkts += readq(priv->base + - MLXBF_GIGE_RX_DIN_DROP_COUNTER); - p->rx_filter_passed_pkts += readq(priv->base + - MLXBF_GIGE_RX_PASS_COUNTER_ALL); - p->rx_filter_discard_pkts += readq(priv->base + - MLXBF_GIGE_RX_DISC_COUNTER_ALL); -} - -static void mlxbf_gige_clean_port(struct mlxbf_gige *priv) -{ - u64 control, status; - int cnt; - - /* Set the CLEAN_PORT_EN bit to trigger SW reset */ - control = readq(priv->base + MLXBF_GIGE_CONTROL); - control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; - writeq(control, priv->base + MLXBF_GIGE_CONTROL); - - /* Loop waiting for status ready bit to assert */ - cnt = 1000; - do { - status = readq(priv->base + MLXBF_GIGE_STATUS); - if (status & MLXBF_GIGE_STATUS_READY) - break; - usleep_range(50, 100); - } while (--cnt > 0); - - /* Clear the CLEAN_PORT_EN bit at end of this loop */ - control = readq(priv->base + MLXBF_GIGE_CONTROL); - control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; - writeq(control, priv->base + MLXBF_GIGE_CONTROL); -} - static int mlxbf_gige_open(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); - struct phy_device *phydev = netdev->phydev; + struct phy_device *phydev; u64 int_en; int err; - mlxbf_gige_cache_stats(priv); - mlxbf_gige_clean_port(priv); + memset(&priv->stats, 0, sizeof(priv->stats)); + mlxbf_gige_rx_init(priv); mlxbf_gige_tx_init(priv); netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); @@ -860,7 +813,40 @@ static int mlxbf_gige_open(struct net_device *netdev) if (err) return err; + phydev = phy_find_first(priv->mdiobus); + if (!phydev) + return -EIO; + + /* Sets netdev->phydev to phydev; which will eventually + * be used in ioctl calls. + */ + err = phy_connect_direct(netdev, phydev, + mlxbf_gige_handle_link_change, + PHY_INTERFACE_MODE_GMII); + if (err) { + netdev_err(netdev, "Could not attach to PHY\n"); + return err; + } + + /* MAC only supports 1000T full duplex mode */ + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + + /* MAC supports symmetric flow control */ + phy_support_sym_pause(phydev); phy_start(phydev); + err = phy_start_aneg(phydev); + if (err < 0) { + netdev_err(netdev, "phy_start_aneg failure: 0x%x\n", err); + return err; + } + + /* Display information about attached PHY device */ + phy_attached_info(phydev); + /* Set bits in INT_EN that we care about */ int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | @@ -875,6 +861,41 @@ static int mlxbf_gige_open(struct net_device *netdev) return 0; } +static void mlxbf_gige_clean_port(struct mlxbf_gige *priv) +{ + struct mlxbf_gige_stats *p; + u64 control, status; + int cnt; + + /* Cache stats that will be cleared by clean port operation */ + p = &priv->stats; + p->rx_din_dropped_pkts = readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); + p->rx_filter_passed_pkts = readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL); + p->rx_filter_discard_pkts = readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL); + + /* Set the CLEAN_PORT_EN bit to trigger SW reset */ + control = readq(priv->base + MLXBF_GIGE_CONTROL); + control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; + writeq(control, priv->base + MLXBF_GIGE_CONTROL); + + /* Create memory barrier before reading status */ + wmb(); + + /* Loop waiting for status ready bit to assert */ + cnt = 1000; + do { + status = readq(priv->base + MLXBF_GIGE_STATUS); + if (status & MLXBF_GIGE_STATUS_READY) + break; + usleep_range(50, 100); + } while (--cnt > 0); + + /* Clear the CLEAN_PORT_EN bit at end of this loop */ + control = readq(priv->base + MLXBF_GIGE_CONTROL); + control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; + writeq(control, priv->base + MLXBF_GIGE_CONTROL); +} + static int mlxbf_gige_stop(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); @@ -885,12 +906,11 @@ static int mlxbf_gige_stop(struct net_device *netdev) netif_napi_del(&priv->napi); mlxbf_gige_free_irqs(priv); - if (netdev->phydev) - phy_stop(netdev->phydev); + phy_stop(netdev->phydev); + phy_disconnect(netdev->phydev); mlxbf_gige_rx_deinit(priv); mlxbf_gige_tx_deinit(priv); - mlxbf_gige_cache_stats(priv); mlxbf_gige_clean_port(priv); return 0; @@ -963,6 +983,9 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, priv->tx_pi++; + /* Create memory barrier before write to TX PI */ + wmb(); + writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); /* Free incoming skb, contents already copied to HW */ @@ -993,10 +1016,11 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) if (new_promisc_enabled != priv->promisc_enabled) { priv->promisc_enabled = new_promisc_enabled; - if (new_promisc_enabled) + if (new_promisc_enabled) { mlxbf_gige_enable_promisc(priv); - else + } else { mlxbf_gige_disable_promisc(priv); + } } } @@ -1058,7 +1082,6 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) static int mlxbf_gige_probe(struct platform_device *pdev) { - struct phy_device *phydev; struct net_device *netdev; struct resource *mac_res; struct resource *llu_res; @@ -1100,8 +1123,9 @@ static int mlxbf_gige_probe(struct platform_device *pdev) writeq(control, base + MLXBF_GIGE_CONTROL); netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv)); - if (!netdev) + if (!netdev) { return -ENOMEM; + } SET_NETDEV_DEV(netdev, &pdev->dev); netdev->netdev_ops = &mlxbf_gige_netdev_ops; @@ -1109,13 +1133,13 @@ static int mlxbf_gige_probe(struct platform_device *pdev) priv = netdev_priv(netdev); priv->netdev = netdev; + /* Initialize feature set supported by hardware (skbuff.h) */ + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM; + platform_set_drvdata(pdev, priv); priv->dev = &pdev->dev; priv->pdev = pdev; - spin_lock_init(&priv->lock); - spin_lock_init(&priv->gpio_lock); - /* Attach MDIO device */ err = mlxbf_gige_mdio_probe(pdev, priv); if (err) @@ -1141,34 +1165,6 @@ static int mlxbf_gige_probe(struct platform_device *pdev) priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); - phydev = phy_find_first(priv->mdiobus); - if (!phydev) - return -EIO; - - /* Sets netdev->phydev to phydev; which will eventually - * be used in ioctl calls. - */ - err = phy_connect_direct(netdev, phydev, - mlxbf_gige_handle_link_change, - PHY_INTERFACE_MODE_GMII); - if (err) { - dev_err(&pdev->dev, "Could not attach to PHY\n"); - return err; - } - - /* MAC only supports 1000T full duplex mode */ - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); - - /* MAC supports symmetric flow control */ - phy_support_sym_pause(phydev); - - /* Display information about attached PHY device */ - phy_attached_info(phydev); - err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); @@ -1178,26 +1174,23 @@ static int mlxbf_gige_probe(struct platform_device *pdev) return 0; } +/* Device remove function. */ static int mlxbf_gige_remove(struct platform_device *pdev) { - struct mlxbf_gige *priv = platform_get_drvdata(pdev); + struct mlxbf_gige *priv; + + priv = platform_get_drvdata(pdev); - phy_disconnect(priv->netdev->phydev); unregister_netdev(priv->netdev); + + /* Remove mdio */ mlxbf_gige_mdio_remove(priv); + platform_set_drvdata(pdev, NULL); return 0; } -static void mlxbf_gige_shutdown(struct platform_device *pdev) -{ - struct mlxbf_gige *priv = platform_get_drvdata(pdev); - - writeq(0, priv->base + MLXBF_GIGE_INT_EN); - mlxbf_gige_clean_port(priv); -} - static const struct acpi_device_id mlxbf_gige_acpi_match[] = { { "MLNXBF17", 0 }, {}, @@ -1207,7 +1200,6 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_gige_acpi_match); static struct platform_driver mlxbf_gige_driver = { .probe = mlxbf_gige_probe, .remove = mlxbf_gige_remove, - .shutdown = mlxbf_gige_shutdown, .driver = { .name = DRV_NAME, .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match), @@ -1219,5 +1211,5 @@ module_platform_driver(mlxbf_gige_driver); MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); MODULE_AUTHOR("David Thompson "); MODULE_AUTHOR("Asmaa Mnebhi "); -MODULE_LICENSE("Dual BSD/GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c index e5c535270a25..2a1362698cb6 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -229,22 +229,20 @@ static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, static void mlxbf_gige_mdio_disable_gpio12_irq(struct mlxbf_gige *priv) { - unsigned long flags; u32 val; - spin_lock_irqsave(&priv->gpio_lock, flags); + spin_lock(&priv->gpio_lock); val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); val &= ~MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - spin_unlock_irqrestore(&priv->gpio_lock, flags); + spin_unlock(&priv->gpio_lock); } static void mlxbf_gige_mdio_enable_gpio12_irq(struct mlxbf_gige *priv) { - unsigned long flags; u32 val; - spin_lock_irqsave(&priv->gpio_lock, flags); + spin_lock(&priv->gpio_lock); /* The INT_N interrupt level is active low. * So enable cause fall bit to detect when GPIO * state goes low. @@ -259,7 +257,7 @@ static void mlxbf_gige_mdio_enable_gpio12_irq(struct mlxbf_gige *priv) val |= MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - spin_unlock_irqrestore(&priv->gpio_lock, flags); + spin_unlock(&priv->gpio_lock); } /* Interrupt handler is called from mlxbf_gige_main.c @@ -314,6 +312,7 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) struct resource *res; u32 phy_addr; int ret; + int irq; res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); if (!res) @@ -375,7 +374,12 @@ int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) if (ret < 0) phy_addr = MLXBF_GIGE_DEFAULT_PHY_ADDR; - priv->mdiobus->irq[phy_addr] = PHY_POLL; + irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); + if (irq < 0) { + dev_err(dev, "Failed to retrieve irq\n"); + return -ENODEV; + } + priv->mdiobus->irq[phy_addr] = irq; /* Auto probe PHY at the corresponding address */ priv->mdiobus->phy_mask = ~(1 << phy_addr); From patchwork Fri Jul 9 19:08:27 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503340 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2mQ1vlqz9sX2; Sat, 10 Jul 2021 05:10:14 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vt3-00042v-Ok; Fri, 09 Jul 2021 19:10:09 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrx-0003G6-6G for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:01 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:58 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8wce030253; Fri, 9 Jul 2021 15:08:58 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8wvO005473; Fri, 9 Jul 2021 15:08:58 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 20/23] Revert "UBUNTU: SAUCE: Remove built-in tests from mlxbf_gige driver" Date: Fri, 9 Jul 2021 15:08:27 -0400 Message-Id: <20210709190830.5405-21-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 4dd38f4ed12f5ec4f612a73623b4ac39b710b62d. Signed-off-by: Asmaa Mnebhi --- .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 41 + .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 1207 +++++++++++++++++ .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 18 + 3 files changed, 1266 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h index 31213c47919c..86a8f0d6993c 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -13,6 +13,9 @@ #include #include +/* Always define this for internal Mellanox use */ +#define MLXBF_GIGE_INTERNAL + #define MLXBF_GIGE_MIN_RXQ_SZ 32 #define MLXBF_GIGE_MAX_RXQ_SZ 32768 #define MLXBF_GIGE_DEFAULT_RXQ_SZ 128 @@ -26,6 +29,26 @@ /* Known pattern for initial state of RX buffers */ #define MLXBF_GIGE_INIT_BYTE_RX_BUF 0x10 +#ifdef MLXBF_GIGE_INTERNAL +/* Number of bytes in packet to be displayed by debug routines */ +#define MLXBF_GIGE_NUM_BYTES_IN_PKT_DUMP 64 + +/* Known pattern for fake destination MAC. This + * value should be different from the value of + * MLXBF_GIGE_INIT_BYTE_RX_BUF in order to track RX. + */ +#define MLXBF_GIGE_FAKE_DMAC_BYTE 0x20 + +/* Known pattern for fake source MAC. */ +#define MLXBF_GIGE_FAKE_SMAC_BYTE 0xFF + +/* Number of packets to transmit with verbose debugging on */ +#define MLXBF_GIGE_MAX_TX_PKTS_VERBOSE 5 + +/* Default TX packet size used in 'start_tx_store' */ +#define MLXBF_GIGE_DEFAULT_TX_PKT_SIZE 60 +#endif /* MLXBF_GIGE_INTERNAL */ + /* There are four individual MAC RX filters. Currently * two of them are being used: one for the broadcast MAC * (index 0) and one for local MAC (index 1) @@ -98,6 +121,11 @@ struct mlxbf_gige { bool promisc_enabled; struct napi_struct napi; struct mlxbf_gige_stats stats; + +#ifdef MLXBF_GIGE_INTERNAL + /* Starting seed for data in loopback packets */ + u8 tx_data_seed; +#endif /* MLXBF_GIGE_INTERNAL */ }; /* Rx Work Queue Element definitions */ @@ -111,6 +139,12 @@ struct mlxbf_gige { #define MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR GENMASK(12, 12) #define MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED GENMASK(13, 13) #define MLXBF_GIGE_RX_CQE_CHKSUM_MASK GENMASK(31, 16) +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_RX_CQE_PKT_LEN_SHIFT 0 +#define MLXBF_GIGE_RX_CQE_VALID_SHIFT 11 +#define MLXBF_GIGE_RX_CQE_PKT_STATUS_SHIFT 12 +#define MLXBF_GIGE_RX_CQE_CHKSUM_SHIFT 16 +#endif /* Tx Work Queue Element definitions */ #define MLXBF_GIGE_TX_WQE_SZ_QWORDS 2 @@ -120,6 +154,13 @@ struct mlxbf_gige { #define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK GENMASK(42, 32) #define MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK GENMASK(55, 48) #define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK GENMASK(63, 56) +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_TX_WQE_PKT_LEN_SHIFT 0 +#define MLXBF_GIGE_TX_WQE_UPDATE_SHIFT 31 +#define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_SHIFT 32 +#define MLXBF_GIGE_TX_WQE_CHKSUM_START_SHIFT 48 +#define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_SHIFT 56 +#endif /* Macro to return packet length of specified TX WQE */ #define MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr) \ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index 88b0406c2d9e..0432d836add7 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -5,6 +5,9 @@ * Copyright (c) 2020, Mellanox Technologies */ +/* Standard method to enable kernel debug (e.g. dev_dbg) */ +#define DEBUG + #include #include #include @@ -14,18 +17,240 @@ #include #include +/* The MLXBF_GIGE_INTERNAL setting is defined in the + * "mlxbf_gige.h" header file, so this header file must + * be included before any processing of that setting. + */ #include "mlxbf_gige.h" #include "mlxbf_gige_regs.h" +#ifdef MLXBF_GIGE_INTERNAL +#include +/* + * Upstreaming guidelines: + * ======================= + * 1) Do not upstream any code that is encapsulated by + * the "MLXBF_GIGE_INTERNAL" tag; that tag is for code + * that is for internal use only. + * 2) Remove all code that defines or checks for the + * definition of "FAST_MODELS". The code encapsulated + * by "#ifdef FAST_MODELS" should always be enabled + * in the upstream source since it is PHY related. + * 3) Remove all code that defines or checks for the + * definition of "MLXBF_GIGE_LOOPBACK". The code encapsulated + * by "#ifndef MLXBF_GIGE_LOOPBACK" should always be enabled, + * i.e. upstream code should run in non-loopback mode. + * 4) Remove any code that checks for current Linux version + * via "LINUX_VERSION_CODE". The upstream code should + * always be tailored to a specific Linux kernel. + * 5) Remove "#define DEBUG" at top of this file. + */ + +/* Define to create mmio read/write sysfs entries */ +#define MLXBF_GIGE_MMIO_SYSFS + +/* Define this to perform read/write tests to MMIO regs */ +#define MLXBF_GIGE_MMIO_TESTS + +/* Define this to perform read/write tests to LLU MMIO regs + * NOTE: there is no LLU on FastModels, so don't try it. + */ +/* #define LLU_MMIO_TESTS */ + +/* Define this to perform read/write tests to PLU MMIO regs + * NOTE: there is no PLU on FastModels, so don't try it. + */ +/* #define PLU_MMIO_TESTS */ + +/* Define this to put IP networking stack into loopback mode, + * where IP stack will not transmit packets out the GigE interface. + * Instead use the GigE sysfs entry (e.g. 'echo > start_tx') + * to send packets. It is assumed that interface is being put into + * loopback mode by one of these methods: + * a) Fast Models loopback + * b) PLU loopback mode + * c) PHY loopback mode + */ +/* #define MLXBF_GIGE_LOOPBACK */ +#endif /* MLXBF_GIGE_INTERNAL */ + +#define FAST_MODELS + #define DRV_NAME "mlxbf_gige" #define DRV_VERSION "1.0" +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_MSG_FORMAT \ + " %02x %02x %02x %02x %02x %02x %02x %02x" \ + " %02x %02x %02x %02x %02x %02x %02x %02x\n" + +#define MLXBF_GIGE_MSG_ARGS(p) \ + *p, *(p + 1), *(p + 2), *(p + 3), \ + *(p + 4), *(p + 5), *(p + 6), *(p + 7), \ + *(p + 8), *(p + 9), *(p + 10), *(p + 11), \ + *(p + 12), *(p + 13), *(p + 14), *(p + 15) + +static void mlxbf_gige_plu_selftests(struct platform_device *pdev, + struct mlxbf_gige *priv) +{ +#ifdef PLU_MMIO_TESTS + u32 rd_data, exp_data; + + dev_dbg(&pdev->dev, "Running PLU MMIO tests\n"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->plu_base + 0x8); + exp_data = 0x1ff; + dev_dbg(&pdev->dev, "PLU 0x8 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->plu_base + 0x140); + exp_data = 0xe8001870; + dev_dbg(&pdev->dev, "PLU 0x140 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->plu_base + 0x610); + exp_data = 0x31001; + dev_dbg(&pdev->dev, "PLU 0x610 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->plu_base + 0x618); + exp_data = 0xb0000; + dev_dbg(&pdev->dev, "PLU 0x618 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->plu_base + 0x890); + exp_data = 0x9; + dev_dbg(&pdev->dev, "PLU 0x890 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->plu_base + 0x894); + exp_data = 0x1; + dev_dbg(&pdev->dev, "PLU 0x894 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); +#endif +} + +static void mlxbf_gige_llu_selftests(struct platform_device *pdev, + struct mlxbf_gige *priv) +{ +#ifdef LLU_MMIO_TESTS + u32 rd_data, exp_data; + + dev_dbg(&pdev->dev, "Running LLU MMIO tests\n"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->llu_base + 0x2200); + exp_data = 0x91008808; + dev_dbg(&pdev->dev, "LLU 0x2200 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->llu_base + 0x2204); + exp_data = 0x810088a8; + dev_dbg(&pdev->dev, "LLU 0x2204 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->llu_base + 0x2208); + exp_data = 0x22e90000; + dev_dbg(&pdev->dev, "LLU 0x2208 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->llu_base + 0x220c); + exp_data = 0x893f0000; + dev_dbg(&pdev->dev, "LLU 0x220c equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->llu_base + 0x2260); + exp_data = 0x8060806; + dev_dbg(&pdev->dev, "LLU 0x2260 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readl(priv->llu_base + 0x2264); + exp_data = 0x891422e7; + dev_dbg(&pdev->dev, "LLU 0x2264 equals %x - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); +#endif +} + +static void mlxbf_gige_selftests(struct platform_device *pdev, + struct mlxbf_gige *priv) +{ +#ifdef MLXBF_GIGE_MMIO_TESTS + u64 rd_data, wr_data, exp_data; + + dev_dbg(&pdev->dev, "Running MLXBF_GIGE MMIO tests\n"); + + /* Read data should match reset value in register header file */ + rd_data = readq(priv->base + MLXBF_GIGE_CONFIG); + exp_data = (MLXBF_GIGE_CONFIG_MAX_PKT_SZ_RESET_VAL + << MLXBF_GIGE_CONFIG_MAX_PKT_SZ_SHIFT); + dev_dbg(&pdev->dev, "MLXBF_GIGE_CONFIG equals %llx - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readq(priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); + exp_data = MLXBF_GIGE_RX_WQE_SIZE_LOG2_RESET_VAL; + dev_dbg(&pdev->dev, "MLXBF_GIGE_RX_WQE_SIZE_LOG2 equals %llx - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Read data should match reset value in register header file */ + rd_data = readq(priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); + exp_data = MLXBF_GIGE_TX_WQ_SIZE_LOG2_RESET_VAL; + dev_dbg(&pdev->dev, "MLXBF_GIGE_TX_WQ_SIZE_LOG2 equals %llx - %s\n", + rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); + + /* Do some SCRATCHPAD testing */ + rd_data = readq(priv->base + MLXBF_GIGE_SCRATCHPAD); + dev_dbg(&pdev->dev, "MLXBF_GIGE_SCRATCHPAD equals %llx\n", rd_data); + + wr_data = 0x1122334455667788; + writeq(wr_data, priv->base + MLXBF_GIGE_SCRATCHPAD); + dev_dbg(&pdev->dev, "Will write %llx to MLXBF_GIGE_SCRATCHPAD\n", + wr_data); + + rd_data = readq(priv->base + MLXBF_GIGE_SCRATCHPAD); + dev_dbg(&pdev->dev, "MLXBF_GIGE_SCRATCHPAD equals %llx - %s\n", + rd_data, (rd_data == wr_data) ? "OK" : "FAIL"); + + wr_data = 0xaabbccddeeff4321; + writeq(wr_data, priv->base + MLXBF_GIGE_SCRATCHPAD); + dev_dbg(&pdev->dev, "Will write %llx to MLXBF_GIGE_SCRATCHPAD\n", + wr_data); + + rd_data = readq(priv->base + MLXBF_GIGE_SCRATCHPAD); + dev_dbg(&pdev->dev, "MLXBF_GIGE_SCRATCHPAD equals %llx - %s\n", + rd_data, (rd_data == wr_data) ? "OK" : "FAIL"); +#endif /* MLXBF_GIGE_MMIO_TESTS */ +} +#endif /* MLXBF_GIGE_INTERNAL */ + static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, unsigned int index, u64 dmac) { void __iomem *base = priv->base; u64 control; +#ifdef MLXBF_GIGE_INTERNAL + if (index > 3) { + dev_err(priv->dev, "%s: invalid index %d\n", + __func__, index); + return; + } + + dev_dbg(priv->dev, "set_mac_rx_filter: index=%d dmac=%llx\n", + index, dmac); +#endif + /* Write destination MAC to specified MAC RX filter */ writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); @@ -41,10 +266,29 @@ static int mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, { void __iomem *base = priv->base; +#ifdef MLXBF_GIGE_INTERNAL + if (index > 3) { + dev_err(priv->dev, "%s: invalid index %d\n", + __func__, index); + return -EINVAL; + } + + if (!dmac) { + dev_err(priv->dev, "%s: invalid dmac pointer NULL\n", + __func__); + return -EINVAL; + } +#endif + /* Read destination MAC from specified MAC RX filter */ *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "get_mac_rx_filter: index=%d dmac=%llx\n", + index, *dmac); +#endif + return 0; } @@ -53,6 +297,10 @@ static void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) void __iomem *base = priv->base; u64 control; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "%s\n", __func__); +#endif + /* Enable MAC_ID_RANGE match functionality */ control = readq(base + MLXBF_GIGE_CONTROL); control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; @@ -70,6 +318,10 @@ static void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) void __iomem *base = priv->base; u64 control; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "%s\n", __func__); +#endif + /* Disable MAC_ID_RANGE match functionality */ control = readq(base + MLXBF_GIGE_CONTROL); control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; @@ -107,6 +359,11 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) if (!priv->rx_wqe_base) return -ENOMEM; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "rx_init: RX WQE base 0x%llx 0x%llx\n", + (u64)priv->rx_wqe_base, (u64)priv->rx_wqe_base_dma); +#endif + /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array * Each RX WQE is simply a receive buffer pointer, so walk * the entire array, allocating a 2KB buffer for each element @@ -114,6 +371,9 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) rx_wqe_ptr = priv->rx_wqe_base; for (i = 0; i < priv->rx_q_entries; i++) { +#ifdef MLXBF_GIGE_INTERNAL + u8 *p; +#endif /* Allocate a receive buffer for this RX WQE. The DMA * form (dma_addr_t) of the receive buffer address is * stored in the RX WQE array (via 'rx_wqe_ptr') where @@ -128,6 +388,14 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) if (!priv->rx_buf[i]) goto free_wqe_and_buf; +#ifdef MLXBF_GIGE_INTERNAL + /* Initialize the first 16 bytes of each RX buffer + * to a known pattern. This will make it easy to + * identify when each receive buffer is populated + */ + p = priv->rx_buf[i]; + memset(p, MLXBF_GIGE_INIT_BYTE_RX_BUF, 16); +#endif *rx_wqe_ptr++ = rx_buf_dma; } @@ -141,6 +409,11 @@ static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) if (!priv->rx_cqe_base) goto free_wqe_and_buf; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "rx_init: RX CQE base 0x%llx 0x%llx\n", + (u64)priv->rx_cqe_base, (u64)priv->rx_cqe_base_dma); +#endif + /* Write RX CQE base address into MMIO reg */ writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); @@ -200,6 +473,11 @@ static int mlxbf_gige_tx_init(struct mlxbf_gige *priv) if (!priv->tx_wqe_base) return -ENOMEM; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "tx_init: TX WQE base 0x%llx 0x%llx\n", + (u64)priv->tx_wqe_base, (u64)priv->tx_wqe_base_dma); +#endif + priv->tx_wqe_next = priv->tx_wqe_base; /* Write TX WQE base address into MMIO reg */ @@ -215,6 +493,11 @@ static int mlxbf_gige_tx_init(struct mlxbf_gige *priv) return -ENOMEM; } +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "tx_init: TX CC 0x%llx 0x%llx\n", + (u64)priv->tx_cc, (u64)priv->tx_cc_dma); +#endif + /* Write TX CC base address into MMIO reg */ writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); @@ -369,6 +652,12 @@ static int mlxbf_gige_set_ringparam(struct net_device *netdev, new_tx_q_entries == priv->tx_q_entries) return 0; +#ifdef MLXBF_GIGE_INTERNAL + netdev_printk(KERN_DEBUG, netdev, + "set_ringparam(): new_tx=%x new_rx=%x\n", + new_tx_q_entries, new_rx_q_entries); +#endif + if (netif_running(netdev)) ops->ndo_stop(netdev); @@ -480,6 +769,7 @@ static const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, }; +#ifdef FAST_MODELS static void mlxbf_gige_handle_link_change(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); @@ -493,6 +783,7 @@ static void mlxbf_gige_handle_link_change(struct net_device *netdev) /* print new link status only if the interrupt came from the PHY */ phy_print_status(phydev); } +#endif /* FAST_MODELS */ /* Start of struct net_device_ops functions */ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) @@ -506,12 +797,33 @@ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); +#ifdef MLXBF_GIGE_INTERNAL + /* Trigger kernel log message on first interrupt of each + * type and then service the asserted error condition(s). + */ +#endif + if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) { priv->stats.hw_access_errors++; +#ifdef MLXBF_GIGE_INTERNAL + if (priv->stats.hw_access_errors == 1) { + dev_info(priv->dev, + "%s: hw_access_error triggered\n", + __func__); + } + /* TODO - add logic to service hw_access_error */ +#endif } if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { priv->stats.tx_invalid_checksums++; +#ifdef MLXBF_GIGE_INTERNAL + if (priv->stats.tx_invalid_checksums == 1) { + dev_info(priv->dev, + "%s: tx_invalid_checksum triggered\n", + __func__); + } +#endif /* This error condition is latched into MLXBF_GIGE_INT_STATUS * when the GigE silicon operates on the offending * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom @@ -535,14 +847,38 @@ static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) { priv->stats.tx_index_errors++; +#ifdef MLXBF_GIGE_INTERNAL + if (priv->stats.tx_index_errors == 1) { + dev_info(priv->dev, + "%s: tx_index_error triggered\n", + __func__); + } + /* TODO - add logic to service tx_index_error */ +#endif } if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) { priv->stats.sw_config_errors++; +#ifdef MLXBF_GIGE_INTERNAL + if (priv->stats.sw_config_errors == 1) { + dev_info(priv->dev, + "%s: sw_config_error triggered\n", + __func__); + } + /* TODO - add logic to service sw_config_error */ +#endif } if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) { priv->stats.sw_access_errors++; +#ifdef MLXBF_GIGE_INTERNAL + if (priv->stats.sw_access_errors == 1) { + dev_info(priv->dev, + "%s: sw_access_error triggered\n", + __func__); + } + /* TODO - add logic to service sw_access_error */ +#endif } /* Clear all error interrupts by writing '1' back to @@ -590,6 +926,14 @@ static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) priv = dev_id; priv->llu_plu_intr_count++; +#ifdef MLXBF_GIGE_INTERNAL + /* Trigger kernel log message on first interrupt */ + if (priv->llu_plu_intr_count == 1) + dev_info(priv->dev, "%s: triggered\n", __func__); + + /* TODO - add logic to service LLU and PLU interrupts */ +#endif + return IRQ_HANDLED; } @@ -652,9 +996,11 @@ static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) stats->tx_packets++; stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); +#ifndef MLXBF_GIGE_LOOPBACK dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, priv->tx_buf[tx_wqe_index], *tx_wqe_addr); priv->tx_buf[tx_wqe_index] = NULL; +#endif } /* Since the TX ring was likely just drained, check if TX queue @@ -663,6 +1009,9 @@ static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) */ if (netif_queue_stopped(priv->netdev) && mlxbf_gige_tx_buffs_avail(priv)) { +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "%s: waking TX queue", __func__); +#endif netif_wake_queue(priv->netdev); } @@ -695,8 +1044,14 @@ static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) netdev->stats.rx_bytes += datalen; } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { priv->stats.rx_mac_errors++; +#ifdef MLXBF_GIGE_INTERNAL + /* TODO - handle error case */ +#endif } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { priv->stats.rx_truncate_errors++; +#ifdef MLXBF_GIGE_INTERNAL + /* TODO - handle error case */ +#endif } skb = dev_alloc_skb(datalen); @@ -797,10 +1152,17 @@ static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) static int mlxbf_gige_open(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); +#ifdef FAST_MODELS struct phy_device *phydev; +#endif u64 int_en; int err; +#ifdef MLXBF_GIGE_INTERNAL + netdev_printk(KERN_DEBUG, netdev, "open: priv=%llx\n", + (u64)priv); +#endif + memset(&priv->stats, 0, sizeof(priv->stats)); mlxbf_gige_rx_init(priv); @@ -813,6 +1175,7 @@ static int mlxbf_gige_open(struct net_device *netdev) if (err) return err; +#ifdef FAST_MODELS phydev = phy_find_first(priv->mdiobus); if (!phydev) return -EIO; @@ -828,6 +1191,7 @@ static int mlxbf_gige_open(struct net_device *netdev) return err; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) /* MAC only supports 1000T full duplex mode */ phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); @@ -837,6 +1201,18 @@ static int mlxbf_gige_open(struct net_device *netdev) /* MAC supports symmetric flow control */ phy_support_sym_pause(phydev); +#else + /* MAC only supports 1000T full duplex mode */ + phydev->supported &= ~SUPPORTED_1000baseT_Half; + phydev->supported &= ~SUPPORTED_100baseT_Full; + phydev->supported &= ~SUPPORTED_100baseT_Half; + phydev->supported &= ~SUPPORTED_10baseT_Full; + phydev->supported &= ~SUPPORTED_10baseT_Half; + + /* MAC supports symmetric flow control */ + phydev->supported |= SUPPORTED_Pause; +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */ + phy_start(phydev); err = phy_start_aneg(phydev); if (err < 0) { @@ -844,9 +1220,29 @@ static int mlxbf_gige_open(struct net_device *netdev) return err; } +#ifdef MLXBF_GIGE_INTERNAL +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) + netdev_printk(KERN_DEBUG, netdev, "supported: %*pb, advertising: %*pb," + " speed: 0x%x, duplex: 0x%x, autoneg: 0x%x, pause: 0x%x," + " asym_pause: 0x%x\n", + __ETHTOOL_LINK_MODE_MASK_NBITS, phydev->supported, + __ETHTOOL_LINK_MODE_MASK_NBITS, phydev->advertising, + phydev->speed, phydev->duplex, phydev->autoneg, + phydev->pause, phydev->asym_pause); +#else + netdev_printk(KERN_DEBUG, netdev, "supported: 0x%x, advertising: 0x%x," + " speed: 0x%x, duplex: 0x%x, autoneg: 0x%x, pause: 0x%x," + " asym_pause: 0x%x\n", + phydev->supported, phydev->advertising, phydev->speed, + phydev->duplex, phydev->autoneg, phydev->pause, + phydev->asym_pause); +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */ +#endif /* MLXBF_GIGE_INTERNAL */ + /* Display information about attached PHY device */ phy_attached_info(phydev); +#endif /* FAST_MODELS */ /* Set bits in INT_EN that we care about */ int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | @@ -900,14 +1296,21 @@ static int mlxbf_gige_stop(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); +#ifdef MLXBF_GIGE_INTERNAL + netdev_printk(KERN_DEBUG, netdev, "stop: priv=%llx\n", + (u64)priv); +#endif + writeq(0, priv->base + MLXBF_GIGE_INT_EN); netif_stop_queue(netdev); napi_disable(&priv->napi); netif_napi_del(&priv->napi); mlxbf_gige_free_irqs(priv); +#ifdef FAST_MODELS phy_stop(netdev->phydev); phy_disconnect(netdev->phydev); +#endif /* FAST_MODELS */ mlxbf_gige_rx_deinit(priv); mlxbf_gige_tx_deinit(priv); @@ -932,6 +1335,7 @@ static void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv) static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, struct net_device *netdev) { +#ifndef MLXBF_GIGE_LOOPBACK struct mlxbf_gige *priv = netdev_priv(netdev); dma_addr_t tx_buf_dma; u8 *tx_buf = NULL; @@ -941,6 +1345,10 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, /* Check that there is room left in TX ring */ if (!mlxbf_gige_tx_buffs_avail(priv)) { /* TX ring is full, inform stack but do not free SKB */ +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(priv->dev, "%s: TX ring is full, stopping TX queue\n", + __func__); +#endif netif_stop_queue(netdev); netdev->stats.tx_dropped++; return NETDEV_TX_BUSY; @@ -987,6 +1395,7 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, wmb(); writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); +#endif /* Free incoming skb, contents already copied to HW */ dev_kfree_skb(skb); @@ -997,17 +1406,34 @@ static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, static int mlxbf_gige_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) { +#ifdef FAST_MODELS if (!(netif_running(netdev))) return -EINVAL; return phy_mii_ioctl(netdev->phydev, ifr, cmd); +#else + return 0; + +#endif /* FAST_MODELS*/ } +#ifdef MLXBF_GIGE_INTERNAL +static void mlxbf_gige_tx_timeout(struct net_device *netdev) +{ + /* TODO - add TX timeout logic */ +} +#endif + static void mlxbf_gige_set_rx_mode(struct net_device *netdev) { struct mlxbf_gige *priv = netdev_priv(netdev); bool new_promisc_enabled; +#ifdef MLXBF_GIGE_INTERNAL + netdev_printk(KERN_DEBUG, netdev, "set_rx_mode: priv=%llx flags=%x\n", + (u64)priv, netdev->flags); +#endif + new_promisc_enabled = netdev->flags & IFF_PROMISC; /* Only write to the hardware registers if the new setting @@ -1017,8 +1443,16 @@ static void mlxbf_gige_set_rx_mode(struct net_device *netdev) priv->promisc_enabled = new_promisc_enabled; if (new_promisc_enabled) { +#ifdef MLXBF_GIGE_INTERNAL + netdev_printk(KERN_DEBUG, netdev, + "set_rx_mode: enable promisc\n"); +#endif mlxbf_gige_enable_promisc(priv); } else { +#ifdef MLXBF_GIGE_INTERNAL + netdev_printk(KERN_DEBUG, netdev, + "set_rx_mode: disable promisc\n"); +#endif mlxbf_gige_disable_promisc(priv); } } @@ -1032,8 +1466,686 @@ static const struct net_device_ops mlxbf_gige_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_do_ioctl = mlxbf_gige_do_ioctl, .ndo_set_rx_mode = mlxbf_gige_set_rx_mode, +#ifdef MLXBF_GIGE_INTERNAL + .ndo_tx_timeout = mlxbf_gige_tx_timeout, +#endif }; +#ifdef MLXBF_GIGE_INTERNAL +#ifdef MLXBF_GIGE_MMIO_SYSFS +static ssize_t mmio_read_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + u64 offset; + int cnt; + + priv = dev_get_drvdata(dev); + + cnt = sscanf(buf, "%llx\n", &offset); + + if (cnt != 1) { + dev_err(dev, "MMIO read: invalid arguments\n"); + return len; + } + + /* Make sure offset is within MAC block and 8-byte aligned */ + if (offset <= MLXBF_GIGE_MAC_CFG && + ((offset & 0x7) == 0)) { + dev_err(dev, + "MMIO read: offset=0x%llx data=0x%llx\n", + offset, readq(priv->base + offset)); + } else { + dev_err(dev, + "MMIO read: invalid offset 0x%llx\n", + offset); + } + + return len; +} + +static ssize_t mmio_write_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + u64 offset, data; + int cnt; + + priv = dev_get_drvdata(dev); + + cnt = sscanf(buf, "%llx %llx\n", &offset, &data); + + if (cnt != 2) { + dev_err(dev, "MMIO write: invalid arguments\n"); + return len; + } + + /* Make sure offset is within MAC block and 8-byte aligned */ + if (offset <= MLXBF_GIGE_MAC_CFG && + ((offset & 0x7) == 0)) { + dev_err(dev, + "MMIO write: offset=0x%llx data=0x%llx\n", + offset, data); + writeq(data, priv->base + offset); + } else { + dev_err(dev, + "MMIO write: invalid offset 0x%llx\n", + offset); + } + + return len; +} + +static ssize_t llu_mmio_read_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + u64 offset; + int cnt; + + priv = dev_get_drvdata(dev); + + cnt = sscanf(buf, "%llx\n", &offset); + + if (cnt != 1) { + dev_err(dev, "LLU MMIO read: invalid arguments\n"); + return len; + } + + /* Make sure offset is within LLU and 4-byte aligned */ + if (offset <= MLXBF_GIGE_LLU_MAX_OFFSET && + ((offset & 0x3) == 0)) { + dev_err(dev, + "LLU MMIO read: offset=0x%llx data=0x%x\n", + offset, readl(priv->llu_base + offset)); + } else { + dev_err(dev, + "LLU MMIO read: invalid offset 0x%llx\n", + offset); + } + + return len; +} + +static ssize_t llu_mmio_write_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + u64 offset; + u32 data; + int cnt; + + priv = dev_get_drvdata(dev); + + cnt = sscanf(buf, "%llx %x\n", &offset, &data); + + if (cnt != 2) { + dev_err(dev, "LLU MMIO write: invalid arguments\n"); + return len; + } + + /* Make sure offset is within LLU and 4-byte aligned */ + if (offset <= MLXBF_GIGE_LLU_MAX_OFFSET && + ((offset & 0x3) == 0)) { + dev_err(dev, + "LLU MMIO write: offset=0x%llx data=0x%x\n", + offset, data); + writel(data, priv->llu_base + offset); + } else { + dev_err(dev, + "LLU MMIO write: invalid offset 0x%llx\n", + offset); + } + + return len; +} + +static ssize_t plu_mmio_read_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + u64 offset; + int cnt; + + priv = dev_get_drvdata(dev); + + cnt = sscanf(buf, "%llx\n", &offset); + + if (cnt != 1) { + dev_err(dev, "PLU MMIO read: invalid arguments\n"); + return len; + } + + /* Make sure offset is within PLU and 4-byte aligned */ + if (offset <= MLXBF_GIGE_PLU_MAX_OFFSET && + ((offset & 0x3) == 0)) { + dev_err(dev, + "PLU MMIO read: offset=0x%llx data=0x%x\n", + offset, readl(priv->plu_base + offset)); + } else { + dev_err(dev, + "PLU MMIO read: invalid offset 0x%llx\n", + offset); + } + + return len; +} + +static ssize_t plu_mmio_write_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + u64 offset; + u32 data; + int cnt; + + priv = dev_get_drvdata(dev); + + cnt = sscanf(buf, "%llx %x\n", &offset, &data); + + if (cnt != 2) { + dev_err(dev, "PLU MMIO write: invalid arguments\n"); + return len; + } + + /* Make sure offset is within PLU and 4-byte aligned */ + if (offset <= MLXBF_GIGE_PLU_MAX_OFFSET && + ((offset & 0x3) == 0)) { + dev_err(dev, + "PLU MMIO write: offset=0x%llx data=0x%x\n", + offset, data); + writel(data, priv->plu_base + offset); + } else { + dev_err(dev, + "PLU MMIO write: invalid offset 0x%llx\n", + offset); + } + + return len; +} + +DEVICE_ATTR_WO(mmio_read); +DEVICE_ATTR_WO(mmio_write); +DEVICE_ATTR_WO(llu_mmio_read); +DEVICE_ATTR_WO(llu_mmio_write); +DEVICE_ATTR_WO(plu_mmio_read); +DEVICE_ATTR_WO(plu_mmio_write); +#endif /* MLXBF_GIGE_MMIO_SYSFS */ + +static void oob_dump_tx_wqe(struct device *dev, u64 *tx_wqe_addr) +{ + u64 word1, word2; + + /* Sanity check the TX WQE address */ + if (!tx_wqe_addr) + return; + + word1 = *tx_wqe_addr; + word2 = *(tx_wqe_addr + 1); + + /* If TX WQE is empty (i.e. both words are 0) + * then don't bother displaying WQE details + */ + if (word1 == (u64)0 && word2 == (u64)0) { + dev_dbg(dev, "%s(%llx)=%llx %llx", __func__, + (u64)tx_wqe_addr, word1, word2); + } else { + dev_dbg(dev, "%s(%llx)", __func__, + (u64)tx_wqe_addr); + + dev_dbg(dev, " buffer addr: %llx\n", word1); + + dev_dbg(dev, " pkt_len: %llx\n", + ((word2 & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK) + >> MLXBF_GIGE_TX_WQE_PKT_LEN_SHIFT)); + + dev_dbg(dev, " update: %llx\n", + ((word2 & MLXBF_GIGE_TX_WQE_UPDATE_MASK) + >> MLXBF_GIGE_TX_WQE_UPDATE_SHIFT)); + + dev_dbg(dev, " cksum_len: %llx\n", + ((word2 & MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK) + >> MLXBF_GIGE_TX_WQE_CHKSUM_LEN_SHIFT)); + + dev_dbg(dev, " cksum_start: %llx\n", + ((word2 & MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK) + >> MLXBF_GIGE_TX_WQE_CHKSUM_START_SHIFT)); + + dev_dbg(dev, " cksum_offset: %llx\n", + ((word2 & MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK) + >> MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_SHIFT)); + } +} + +/* Handler for sysfs entry 'dump_tx' found at + * /sys/devices/platform/MLNXBF17:00/ + * Issue 'cat dump_tx' to invoke this routine + */ +static ssize_t dump_tx_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mlxbf_gige *priv; + u64 data; + int i; + + priv = dev_get_drvdata(dev); + + dev_dbg(dev, "============================================\n"); + + dev_dbg(dev, "%s: dev_get_drvdata=%llx\n", + __func__, (u64)priv); + + /* Loop through 'n' TX WQE entries */ + for (i = 0; + (priv->netdev->flags & IFF_UP) && (i < priv->tx_q_entries); + i++) { + u8 *p; + + oob_dump_tx_wqe(dev, + (u64 *)((u64)priv->tx_wqe_base + + (i * MLXBF_GIGE_TX_WQE_SZ))); + + p = priv->tx_buf[i]; + dev_dbg(dev, " tx_buf[%d] = %llx\n", i, (u64)priv->tx_buf[i]); + + if (p) { + int j; + + for (j = 0; + j < (MLXBF_GIGE_NUM_BYTES_IN_PKT_DUMP / 16); + j++, p += 16) { + dev_dbg(dev, MLXBF_GIGE_MSG_FORMAT, + MLXBF_GIGE_MSG_ARGS(p)); + } + } + } + + if (priv->netdev->flags & IFF_UP) { + dev_dbg(dev, "tx_cc=%llx *tx_cc=%llx\n", + (u64)priv->tx_cc, *(u64 *)priv->tx_cc); + } + + /* Display TX producer index */ + data = readq(priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); + dev_dbg(dev, "tx_producer_index=%llx\n", (u64)data); + + /* Display TX consumer index */ + data = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); + dev_dbg(dev, "tx_consumer_index=%llx\n", (u64)data); + + /* Display TX status */ + data = readq(priv->base + MLXBF_GIGE_TX_STATUS); + dev_dbg(dev, "tx_status=%llx\n", (u64)data); + + /* Display TX FIFO status */ + data = readq(priv->base + MLXBF_GIGE_TX_FIFOS_STATUS); + dev_dbg(dev, "tx_fifos_status=%llx\n", (u64)data); + + return strlen(buf); +} + +DEVICE_ATTR_RO(dump_tx); + +static void oob_dump_rx_wqe(struct device *dev, u64 *rx_wqe_addr) +{ + /* Sanity check the RX WQE address */ + if (!rx_wqe_addr) + return; + + dev_dbg(dev, "%s(%llx)=%llx\n", __func__, + (u64)rx_wqe_addr, *rx_wqe_addr); +} + +static void oob_dump_rx_cqe(struct device *dev, u64 *rx_cqe_addr) +{ + u64 rx_cqe; + + /* Sanity check the RX CQE address */ + if (!rx_cqe_addr) + return; + + rx_cqe = *rx_cqe_addr; + + /* If RX CQE is empty (i.e. value is 0) then + * don't bother displaying CQE details + */ + if (rx_cqe == (u64)0) { + dev_dbg(dev, "%s(%llx)=%llx", __func__, + (u64)rx_cqe_addr, rx_cqe); + } else { + dev_dbg(dev, "%s(%llx)", __func__, + (u64)rx_cqe_addr); + + dev_dbg(dev, " pkt_len: %llx\n", + (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK)); + + dev_dbg(dev, " valid: %llx\n", + ((rx_cqe & MLXBF_GIGE_RX_CQE_VALID_MASK) + >> MLXBF_GIGE_RX_CQE_VALID_SHIFT)); + + dev_dbg(dev, " pkt_status: %llx\n", + ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) + >> MLXBF_GIGE_RX_CQE_PKT_STATUS_SHIFT)); + + dev_dbg(dev, " chksum: %llx\n", + ((rx_cqe & MLXBF_GIGE_RX_CQE_CHKSUM_MASK) + >> MLXBF_GIGE_RX_CQE_CHKSUM_SHIFT)); + } +} + +/* Handler for sysfs entry 'dump_rx' found at + * /sys/devices/platform/MLNXBF17:00/ + * Issue 'cat dump_rx' to invoke this routine + */ +static ssize_t dump_rx_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mlxbf_gige *priv; + u64 data; + int i; + + priv = dev_get_drvdata(dev); + + dev_dbg(dev, "============================================\n"); + dev_dbg(dev, "%s: dev_get_drvdata=%llx\n", __func__, (u64)priv); + + /* Loop through 'n' RX WQE entries */ + for (i = 0; + (priv->netdev->flags & IFF_UP) && (i < priv->rx_q_entries); + i++) { + u8 *p; + + oob_dump_rx_wqe(dev, priv->rx_wqe_base + i); + + p = priv->rx_buf[i]; + dev_dbg(dev, " rx_buf[%d] = %llx\n", i, (u64)priv->rx_buf[i]); + + /* Only display RX buffer contents if not in initial state */ + if (p && (*p != MLXBF_GIGE_INIT_BYTE_RX_BUF)) { + int j; + + for (j = 0; + j < (MLXBF_GIGE_NUM_BYTES_IN_PKT_DUMP / 16); + j++, p += 16) { + dev_dbg(dev, MLXBF_GIGE_MSG_FORMAT, + MLXBF_GIGE_MSG_ARGS(p)); + } + } + } + + /* Loop through 'n' RX CQE entries */ + for (i = 0; + (priv->netdev->flags & IFF_UP) && (i < priv->rx_q_entries); + i++) { + oob_dump_rx_cqe(dev, priv->rx_cqe_base + i); + } + + /* Display RX WQE producer index */ + data = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); + dev_dbg(dev, "rx_wqe_pi=%llx\n", (u64)data); + + /* Display INT_STATUS */ + data = readq(priv->base + MLXBF_GIGE_INT_STATUS); + dev_dbg(dev, "int_status=%llx\n", (u64)data); + + /* Then, clear INT_STATUS */ + data = 0x1FF; + writeq(data, priv->base + MLXBF_GIGE_INT_STATUS); + + /* Display RX_DIN_DROP_COUNTER */ + data = readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); + dev_dbg(dev, "rx_din_drop_counter=%llx\n", (u64)data); + + /* Display INT_STATUS_EXP */ + data = readq(priv->base + MLXBF_GIGE_INT_STATUS_EXP); + dev_dbg(dev, "int_status_exp=%llx\n", (u64)data); + + /* Then, clear INT_STATUS_EXP */ + data = 0; + writeq(data, priv->base + MLXBF_GIGE_INT_STATUS_EXP); + + /* Display RX_MAC_FILTER_PASS_COUNTER_ALL */ + data = readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL); + dev_dbg(dev, "rx_mac_filter_pass_counter_all=%llx\n", (u64)data); + + /* Display RX_MAC_FILTER_DISC_COUNTER_ALL */ + data = readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL); + dev_dbg(dev, "rx_mac_filter_disc_counter_all=%llx\n", (u64)data); + + /* Display first word of RX_MAC_FILTER */ + data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER); + dev_dbg(dev, "rx_mac_filter0=%llx\n", (u64)data); + + /* Display second word of RX_MAC_FILTER */ + data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER + 0x8); + dev_dbg(dev, "rx_mac_filter1=%llx\n", (u64)data); + + /* Display third word of RX_MAC_FILTER */ + data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER + 0x10); + dev_dbg(dev, "rx_mac_filter2=%llx\n", (u64)data); + + /* Display fourth word of RX_MAC_FILTER */ + data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER + 0x18); + dev_dbg(dev, "rx_mac_filter3=%llx\n", (u64)data); + + /* Display MLXBF_GIGE_RX_CQE_PACKET_CI */ + data = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); + dev_dbg(dev, "MLXBF_GIGE_RX_CQE_PACKET_CI=%llx\n", (u64)data); + + dev_dbg(dev, "error_intr_count=%llx\n", priv->error_intr_count); + dev_dbg(dev, "rx_intr_count=%llx\n", priv->rx_intr_count); + dev_dbg(dev, "llu_plu_intr_count=%llx\n", priv->llu_plu_intr_count); + + /* Display INT_EN */ + data = readq(priv->base + MLXBF_GIGE_INT_EN); + dev_dbg(dev, "int_en=%llx\n", (u64)data); + + /* Display INT_MASK */ + data = readq(priv->base + MLXBF_GIGE_INT_MASK); + dev_dbg(dev, "int_mask=%llx\n", (u64)data); + + return strlen(buf); +} + +DEVICE_ATTR_RO(dump_rx); + +/* Handler for sysfs entry 'start_tx' found at + * /sys/devices/platform/MLNXBF17:00/ + * Issue 'echo > start_tx' to invoke this routine + * which will send dummy IP packets to GigE port + */ +static ssize_t start_tx_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct mlxbf_gige *priv; + dma_addr_t tx_buf_dma; + u8 oob_tx_data_seed; + int oob_tx_pkt_size; + long num_pkts = 1; + u64 *tx_wqe_addr; + u8 *tx_buf; + u16 data16; + u64 word2; + int i, j; + int ret; + + priv = dev_get_drvdata(dev); + + oob_tx_pkt_size = MLXBF_GIGE_DEFAULT_TX_PKT_SIZE; + + if (buf) { + ret = kstrtol(buf, 10, &num_pkts); + + if (ret == 0) { + dev_dbg(dev, "%s: num_pkts %d\n", + __func__, (int)num_pkts); + } + } + + for (i = 0; i < num_pkts; i++) { + /* The data seed is used to populate the packet with + * fake, but predictable, data. The value of seed + * is stored in the first byte after the L2 header, + * then (seed+1) is stored in the second byte, etc. + */ + oob_tx_data_seed = priv->tx_data_seed; + priv->tx_data_seed += 4; + + /* To limit output only perform debug logging if number + * of packets to send is less than some maximum value. + */ + if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { + dev_dbg(dev, "%s: size=%x seed=%x\n", + __func__, oob_tx_pkt_size, + oob_tx_data_seed); + } + + /* Allocate ptr for buffer */ + tx_buf = dma_alloc_coherent(dev, MLXBF_GIGE_DEFAULT_BUF_SZ, + &tx_buf_dma, GFP_KERNEL); + + if (!tx_buf) + return -ENOMEM; + + if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { + dev_dbg(dev, "%s: tx_buf %llx %llx\n", + __func__, (u64)tx_buf, (u64)tx_buf_dma); + } + + if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { + dev_dbg(dev, "%s: pkt num %llx buffer index %x\n", + __func__, (u64)priv->tx_pi, + (priv->tx_pi % priv->tx_q_entries)); + } + + priv->tx_buf[priv->tx_pi % priv->tx_q_entries] = tx_buf; + + /* Put in four bytes of fake destination MAC, but use real + * value of 'tx_pi' in order to track TX producer index + * in the actual packet contents. + */ + *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; + *tx_buf++ = (priv->tx_pi & 0xFF00) >> 8; + *tx_buf++ = (priv->tx_pi & 0xFF); + + /* Put in fake source MAC */ + *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; + *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; + + /* Set ethertype for IP (0x0800) */ + *tx_buf++ = 0x08; + *tx_buf++ = 0x00; + + /* Put in fake packet payload */ + for (j = 0; j < (oob_tx_pkt_size - ETH_HLEN); j++) + *tx_buf++ = (u8)(j + oob_tx_data_seed); + + /* TODO - should really reorganize all low-level TX */ + /* logic and call it here and in 'xmit' function also */ + + /* Get address of TX WQE */ + tx_wqe_addr = priv->tx_wqe_next; + + if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { + dev_dbg(dev, "%s: tx_wqe_addr=%llx\n", + __func__, (u64)tx_wqe_addr); + } + + mlxbf_gige_update_tx_wqe_next(priv); + + if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { + dev_dbg(dev, "%s: tx_wqe_next=%llx\n", + __func__, (u64)priv->tx_wqe_next); + } + + /* Put PA of buffer address into first 64-bit word of TX WQE */ + *tx_wqe_addr = tx_buf_dma; + + /* Set TX WQE pkt_len appropriately */ + word2 = oob_tx_pkt_size & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; + + if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { + dev_dbg(dev, "%s: word2=%llx\n", + __func__, (u64)word2); + } + + /* Write entire 2nd word of TX WQE */ + *(tx_wqe_addr + 1) = word2; + + /* Create memory barrier before write to TX PI */ + wmb(); + + priv->tx_pi++; + + writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); + + if (priv->tx_pi >= 0x20) { + data16 = readq(priv->base + MLXBF_GIGE_RX_WQE_PI) + 1; + writeq(data16, priv->base + MLXBF_GIGE_RX_WQE_PI); + } + } /* end - i loop */ + + return len; +} + +DEVICE_ATTR_WO(start_tx); + +void mlxbf_gige_create_sysfs(struct device *dev) +{ +#ifdef MLXBF_GIGE_MMIO_SYSFS + if (device_create_file(dev, &dev_attr_mmio_read)) + dev_info(dev, "failed to create mmio_read sysfs entry\n"); + if (device_create_file(dev, &dev_attr_mmio_write)) + dev_info(dev, "failed to create mmio_write sysfs entry\n"); + if (device_create_file(dev, &dev_attr_llu_mmio_read)) + dev_info(dev, "failed to create llu_mmio_read sysfs entry\n"); + if (device_create_file(dev, &dev_attr_llu_mmio_write)) + dev_info(dev, "failed to create llu_mmio_write sysfs entry\n"); + if (device_create_file(dev, &dev_attr_plu_mmio_read)) + dev_info(dev, "failed to create plu_mmio_read sysfs entry\n"); + if (device_create_file(dev, &dev_attr_plu_mmio_write)) + dev_info(dev, "failed to create plu_mmio_write sysfs entry\n"); +#endif + + if (device_create_file(dev, &dev_attr_dump_rx)) + dev_info(dev, "failed to create dump_rx sysfs entry\n"); + if (device_create_file(dev, &dev_attr_dump_tx)) + dev_info(dev, "failed to create dump_tx sysfs entry\n"); + if (device_create_file(dev, &dev_attr_start_tx)) + dev_info(dev, "failed to create start_tx sysfs entry\n"); +} + +void mlxbf_gige_remove_sysfs(struct device *dev) +{ +#ifdef MLXBF_GIGE_MMIO_SYSFS + device_remove_file(dev, &dev_attr_mmio_read); + device_remove_file(dev, &dev_attr_mmio_write); + device_remove_file(dev, &dev_attr_llu_mmio_read); + device_remove_file(dev, &dev_attr_llu_mmio_write); + device_remove_file(dev, &dev_attr_plu_mmio_read); + device_remove_file(dev, &dev_attr_plu_mmio_write); +#endif + + device_remove_file(dev, &dev_attr_dump_rx); + device_remove_file(dev, &dev_attr_dump_tx); + device_remove_file(dev, &dev_attr_start_tx); +} +#endif /* MLXBF_GIGE_INTERNAL */ + static u64 mlxbf_gige_mac_to_u64(u8 *addr) { u64 mac = 0; @@ -1068,11 +2180,18 @@ static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) if (is_valid_ether_addr(mac)) { ether_addr_copy(priv->netdev->dev_addr, mac); +#ifdef MLXBF_GIGE_INTERNAL + dev_info(priv->dev, "Read MAC address %pM from chip\n", mac); +#endif } else { /* Provide a random MAC if for some reason the device has * not been configured with a valid MAC address already. */ eth_hw_addr_random(priv->netdev); +#ifdef MLXBF_GIGE_INTERNAL + dev_info(priv->dev, "Generated random MAC address %pM\n", + priv->netdev->dev_addr); +#endif } local_mac = mlxbf_gige_mac_to_u64(priv->netdev->dev_addr); @@ -1093,10 +2212,22 @@ static int mlxbf_gige_probe(struct platform_device *pdev) u64 control; int err = 0; +#ifdef MLXBF_GIGE_INTERNAL + u64 exp_data; + + dev_dbg(&pdev->dev, "probe: pdev=0x%llx pdev->dev=0x%llx\n", + (u64)pdev, (u64)&pdev->dev); +#endif + mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); if (!mac_res) return -ENXIO; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "probe: resource %d (MAC) start=0x%llx end=0x%llx\n", + MLXBF_GIGE_RES_MAC, mac_res->start, mac_res->end); +#endif + base = devm_ioremap_resource(&pdev->dev, mac_res); if (IS_ERR(base)) return PTR_ERR(base); @@ -1105,6 +2236,11 @@ static int mlxbf_gige_probe(struct platform_device *pdev) if (!llu_res) return -ENXIO; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "probe: resource %d (LLU) start=0x%llx end=0x%llx\n", + MLXBF_GIGE_RES_LLU, llu_res->start, llu_res->end); +#endif + llu_base = devm_ioremap_resource(&pdev->dev, llu_res); if (IS_ERR(llu_base)) return PTR_ERR(llu_base); @@ -1113,10 +2249,26 @@ static int mlxbf_gige_probe(struct platform_device *pdev) if (!plu_res) return -ENXIO; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "probe: resource %d (PLU) start=0x%llx end=0x%llx\n", + MLXBF_GIGE_RES_PLU, plu_res->start, plu_res->end); +#endif + plu_base = devm_ioremap_resource(&pdev->dev, plu_res); if (IS_ERR(plu_base)) return PTR_ERR(plu_base); +#ifdef MLXBF_GIGE_INTERNAL + /* Read single MMIO register and compare to expected value */ + exp_data = (MLXBF_GIGE_CONFIG_MAX_PKT_SZ_RESET_VAL + << MLXBF_GIGE_CONFIG_MAX_PKT_SZ_SHIFT); + if (readq(base + MLXBF_GIGE_CONFIG) != exp_data) { + dev_err(&pdev->dev, + "probe failed, unexpected value in MLXBF_GIGE_CONFIG\n"); + return -ENODEV; + } +#endif + /* Perform general init of GigE block */ control = readq(base + MLXBF_GIGE_CONTROL); control |= MLXBF_GIGE_CONTROL_PORT_EN; @@ -1124,9 +2276,16 @@ static int mlxbf_gige_probe(struct platform_device *pdev) netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv)); if (!netdev) { +#ifdef MLXBF_GIGE_INTERNAL + dev_err(&pdev->dev, "Failed to allocate etherdev\n"); +#endif return -ENOMEM; } +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "probe: netdev=%llx\n", (u64)netdev); +#endif + SET_NETDEV_DEV(netdev, &pdev->dev); netdev->netdev_ops = &mlxbf_gige_netdev_ops; netdev->ethtool_ops = &mlxbf_gige_ethtool_ops; @@ -1140,21 +2299,47 @@ static int mlxbf_gige_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->pdev = pdev; +#ifdef FAST_MODELS + /* + * TODO: Palladium has no connection to the PHY hardware, so + * the MDIO probe will fail. + * This needs to be removed once palladium provides a connection + * to the PHY device. + */ + /* Attach MDIO device */ err = mlxbf_gige_mdio_probe(pdev, priv); if (err) return err; +#endif /* FAST_MODELS */ priv->base = base; priv->llu_base = llu_base; priv->plu_base = plu_base; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "probe: priv=0x%llx priv->base=0x%llx\n", + (u64)priv, (u64)priv->base); + dev_dbg(&pdev->dev, "probe: llu_base=0x%llx plu_base=0x%llx\n", + (u64)priv->llu_base, (u64)priv->plu_base); + + /* Perform some self tests on MAC, PLU, LLU */ + mlxbf_gige_selftests(pdev, priv); + mlxbf_gige_plu_selftests(pdev, priv); + mlxbf_gige_llu_selftests(pdev, priv); +#endif + priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ; priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ; /* Write initial MAC address to hardware */ mlxbf_gige_initial_mac(priv); +#ifdef MLXBF_GIGE_INTERNAL + /* Create sysfs entries for driver */ + mlxbf_gige_create_sysfs(&pdev->dev); +#endif + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (err) { dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); @@ -1165,12 +2350,23 @@ static int mlxbf_gige_probe(struct platform_device *pdev) priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "probe: irq[] = %d %d %d\n", + priv->error_irq, priv->rx_irq, priv->llu_plu_irq); +#endif + err = register_netdev(netdev); if (err) { dev_err(&pdev->dev, "Failed to register netdev\n"); return err; } +#ifdef MLXBF_GIGE_INTERNAL + dev_info(&pdev->dev, "probed\n"); + + priv->tx_data_seed = 0xB0; +#endif + return 0; } @@ -1179,12 +2375,23 @@ static int mlxbf_gige_remove(struct platform_device *pdev) { struct mlxbf_gige *priv; +#ifdef MLXBF_GIGE_INTERNAL + dev_dbg(&pdev->dev, "remove: pdev=%llx\n", (u64)pdev); +#endif + priv = platform_get_drvdata(pdev); unregister_netdev(priv->netdev); +#ifdef MLXBF_GIGE_INTERNAL + /* Remove driver sysfs entries */ + mlxbf_gige_remove_sysfs(&pdev->dev); +#endif + +#ifdef FAST_MODELS /* Remove mdio */ mlxbf_gige_mdio_remove(priv); +#endif /* FAST_MODELS */ platform_set_drvdata(pdev, NULL); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h index ff490c70fff1..4aeb6e45579e 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -8,8 +8,16 @@ #ifndef __MLXBF_GIGE_REGS_H__ #define __MLXBF_GIGE_REGS_H__ +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_CONFIG 0x0008 +#define MLXBF_GIGE_CONFIG_MAX_PKT_SZ_SHIFT 16 +#define MLXBF_GIGE_CONFIG_MAX_PKT_SZ_RESET_VAL 1522 +#endif /* MLXBF_GIGE_INTERNAL */ #define MLXBF_GIGE_STATUS 0x0010 #define MLXBF_GIGE_STATUS_READY BIT(0) +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_SCRATCHPAD 0x0020 +#endif /* MLXBF_GIGE_INTERNAL */ #define MLXBF_GIGE_INT_STATUS 0x0028 #define MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET BIT(0) #define MLXBF_GIGE_INT_STATUS_RX_MAC_ERROR BIT(1) @@ -50,11 +58,17 @@ #define MLXBF_GIGE_RX_MAC_FILTER 0x0240 #define MLXBF_GIGE_RX_MAC_FILTER_STRIDE 0x0008 #define MLXBF_GIGE_RX_DIN_DROP_COUNTER 0x0260 +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_INT_STATUS_EXP 0x0308 +#endif /* MLXBF_GIGE_INTERNAL */ #define MLXBF_GIGE_TX_CONSUMER_INDEX 0x0310 #define MLXBF_GIGE_TX_CONTROL 0x0318 #define MLXBF_GIGE_TX_CONTROL_GRACEFUL_STOP BIT(0) #define MLXBF_GIGE_TX_STATUS 0x0388 #define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1) +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_TX_FIFOS_STATUS 0x0390 +#endif /* MLXBF_GIGE_INTERNAL */ #define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520 #define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528 #define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540 @@ -69,5 +83,9 @@ #define MLXBF_GIGE_RX_DMA_EN BIT(0) #define MLXBF_GIGE_RX_CQE_PACKET_CI 0x05b0 #define MLXBF_GIGE_MAC_CFG 0x05e8 +#ifdef MLXBF_GIGE_INTERNAL +#define MLXBF_GIGE_LLU_MAX_OFFSET 0xa0fc +#define MLXBF_GIGE_PLU_MAX_OFFSET 0x10fc +#endif /* MLXBF_GIGE_INTERNAL */ #endif /* !defined(__MLXBF_GIGE_REGS_H__) */ From patchwork Fri Jul 9 19:08:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503341 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2mS2rMQz9sRN; Sat, 10 Jul 2021 05:10:16 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vt5-00044G-6w; Fri, 09 Jul 2021 19:10:11 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vrx-0003G7-4R for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:01 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:08:59 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J8xi6030256; Fri, 9 Jul 2021 15:08:59 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J8xSF005474; Fri, 9 Jul 2021 15:08:59 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 21/23] Revert "UBUNTU: SAUCE: Add Mellanox BlueField Gigabit Ethernet driver" Date: Fri, 9 Jul 2021 15:08:28 -0400 Message-Id: <20210709190830.5405-22-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 This reverts commit 594370b663715a0af9da3cfa9ec5cab43e19b5f4. Signed-off-by: Asmaa Mnebhi --- drivers/net/ethernet/mellanox/Kconfig | 1 - drivers/net/ethernet/mellanox/Makefile | 1 - .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 13 - .../net/ethernet/mellanox/mlxbf_gige/Makefile | 5 - .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 191 -- .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 2422 ----------------- .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 397 --- .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 91 - 8 files changed, 3121 deletions(-) delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/Makefile delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c delete mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index d778909ebd95..23cf7917a0c9 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -22,6 +22,5 @@ source "drivers/net/ethernet/mellanox/mlx4/Kconfig" source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" source "drivers/net/ethernet/mellanox/mlxfw/Kconfig" -source "drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig" endif # NET_VENDOR_MELLANOX diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile index d4b5f547a727..79773ac331ee 100644 --- a/drivers/net/ethernet/mellanox/Makefile +++ b/drivers/net/ethernet/mellanox/Makefile @@ -7,4 +7,3 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_MLX5_CORE) += mlx5/core/ obj-$(CONFIG_MLXSW_CORE) += mlxsw/ obj-$(CONFIG_MLXFW) += mlxfw/ -obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige/ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig deleted file mode 100644 index 60712e2d0a69..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -# -# Mellanox GigE driver configuration -# - -config MLXBF_GIGE - tristate "Mellanox Technologies BlueField Gigabit Ethernet support" - depends on (ARM64 || COMPILE_TEST) && ACPI && INET - select PHYLIB - help - The second generation BlueField SoC from Mellanox Technologies - supports an out-of-band Gigabit Ethernet management port to the - Arm subsystem. diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile deleted file mode 100644 index 165122b9622a..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only - -obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o - -mlxbf_gige-y := mlxbf_gige_main.o mlxbf_gige_mdio.o diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h deleted file mode 100644 index 86a8f0d6993c..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h +++ /dev/null @@ -1,191 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB */ - -/* Header file for Gigabit Ethernet driver for Mellanox BlueField SoC - * - this file contains software data structures and any chip-specific - * data structures (e.g. TX WQE format) that are memory resident. - * - * Copyright (c) 2020, Mellanox Technologies - */ - -#ifndef __MLXBF_GIGE_H__ -#define __MLXBF_GIGE_H__ - -#include -#include - -/* Always define this for internal Mellanox use */ -#define MLXBF_GIGE_INTERNAL - -#define MLXBF_GIGE_MIN_RXQ_SZ 32 -#define MLXBF_GIGE_MAX_RXQ_SZ 32768 -#define MLXBF_GIGE_DEFAULT_RXQ_SZ 128 - -#define MLXBF_GIGE_MIN_TXQ_SZ 4 -#define MLXBF_GIGE_MAX_TXQ_SZ 256 -#define MLXBF_GIGE_DEFAULT_TXQ_SZ 128 - -#define MLXBF_GIGE_DEFAULT_BUF_SZ 2048 - -/* Known pattern for initial state of RX buffers */ -#define MLXBF_GIGE_INIT_BYTE_RX_BUF 0x10 - -#ifdef MLXBF_GIGE_INTERNAL -/* Number of bytes in packet to be displayed by debug routines */ -#define MLXBF_GIGE_NUM_BYTES_IN_PKT_DUMP 64 - -/* Known pattern for fake destination MAC. This - * value should be different from the value of - * MLXBF_GIGE_INIT_BYTE_RX_BUF in order to track RX. - */ -#define MLXBF_GIGE_FAKE_DMAC_BYTE 0x20 - -/* Known pattern for fake source MAC. */ -#define MLXBF_GIGE_FAKE_SMAC_BYTE 0xFF - -/* Number of packets to transmit with verbose debugging on */ -#define MLXBF_GIGE_MAX_TX_PKTS_VERBOSE 5 - -/* Default TX packet size used in 'start_tx_store' */ -#define MLXBF_GIGE_DEFAULT_TX_PKT_SIZE 60 -#endif /* MLXBF_GIGE_INTERNAL */ - -/* There are four individual MAC RX filters. Currently - * two of them are being used: one for the broadcast MAC - * (index 0) and one for local MAC (index 1) - */ -#define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0 -#define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1 - -/* Define for broadcast MAC literal */ -#define BCAST_MAC_ADDR 0xFFFFFFFFFFFF - -/* There are three individual interrupts: - * 1) Errors, "OOB" interrupt line - * 2) Receive Packet, "OOB_LLU" interrupt line - * 3) LLU and PLU Events, "OOB_PLU" interrupt line - */ -#define MLXBF_GIGE_ERROR_INTR_IDX 0 -#define MLXBF_GIGE_RECEIVE_PKT_INTR_IDX 1 -#define MLXBF_GIGE_LLU_PLU_INTR_IDX 2 -#define MLXBF_GIGE_PHY_INT_N 3 - -struct mlxbf_gige_stats { - u64 hw_access_errors; - u64 tx_invalid_checksums; - u64 tx_small_frames; - u64 tx_index_errors; - u64 sw_config_errors; - u64 sw_access_errors; - u64 rx_truncate_errors; - u64 rx_mac_errors; - u64 rx_din_dropped_pkts; - u64 tx_fifo_full; - u64 rx_filter_passed_pkts; - u64 rx_filter_discard_pkts; -}; - -struct mlxbf_gige { - void __iomem *base; - void __iomem *llu_base; - void __iomem *plu_base; - struct device *dev; - struct net_device *netdev; - struct platform_device *pdev; - void __iomem *mdio_io; - struct mii_bus *mdiobus; - void __iomem *gpio_io; - void __iomem *cause_rsh_coalesce0_io; - void __iomem *cause_gpio_arm_coalesce0_io; - spinlock_t gpio_lock; - u16 rx_q_entries; - u16 tx_q_entries; - u64 *tx_wqe_base; - dma_addr_t tx_wqe_base_dma; - u64 *tx_wqe_next; - u64 *tx_cc; - dma_addr_t tx_cc_dma; - dma_addr_t *rx_wqe_base; - dma_addr_t rx_wqe_base_dma; - u64 *rx_cqe_base; - dma_addr_t rx_cqe_base_dma; - u16 tx_pi; - u16 prev_tx_ci; - u64 error_intr_count; - u64 rx_intr_count; - u64 llu_plu_intr_count; - u8 *rx_buf[MLXBF_GIGE_DEFAULT_RXQ_SZ]; - u8 *tx_buf[MLXBF_GIGE_DEFAULT_TXQ_SZ]; - int error_irq; - int rx_irq; - int llu_plu_irq; - bool promisc_enabled; - struct napi_struct napi; - struct mlxbf_gige_stats stats; - -#ifdef MLXBF_GIGE_INTERNAL - /* Starting seed for data in loopback packets */ - u8 tx_data_seed; -#endif /* MLXBF_GIGE_INTERNAL */ -}; - -/* Rx Work Queue Element definitions */ -#define MLXBF_GIGE_RX_WQE_SZ 8 - -/* Rx Completion Queue Element definitions */ -#define MLXBF_GIGE_RX_CQE_SZ 8 -#define MLXBF_GIGE_RX_CQE_PKT_LEN_MASK GENMASK(10, 0) -#define MLXBF_GIGE_RX_CQE_VALID_MASK GENMASK(11, 11) -#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK GENMASK(15, 12) -#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR GENMASK(12, 12) -#define MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED GENMASK(13, 13) -#define MLXBF_GIGE_RX_CQE_CHKSUM_MASK GENMASK(31, 16) -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_RX_CQE_PKT_LEN_SHIFT 0 -#define MLXBF_GIGE_RX_CQE_VALID_SHIFT 11 -#define MLXBF_GIGE_RX_CQE_PKT_STATUS_SHIFT 12 -#define MLXBF_GIGE_RX_CQE_CHKSUM_SHIFT 16 -#endif - -/* Tx Work Queue Element definitions */ -#define MLXBF_GIGE_TX_WQE_SZ_QWORDS 2 -#define MLXBF_GIGE_TX_WQE_SZ 16 -#define MLXBF_GIGE_TX_WQE_PKT_LEN_MASK GENMASK(10, 0) -#define MLXBF_GIGE_TX_WQE_UPDATE_MASK GENMASK(31, 31) -#define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK GENMASK(42, 32) -#define MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK GENMASK(55, 48) -#define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK GENMASK(63, 56) -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_TX_WQE_PKT_LEN_SHIFT 0 -#define MLXBF_GIGE_TX_WQE_UPDATE_SHIFT 31 -#define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_SHIFT 32 -#define MLXBF_GIGE_TX_WQE_CHKSUM_START_SHIFT 48 -#define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_SHIFT 56 -#endif - -/* Macro to return packet length of specified TX WQE */ -#define MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr) \ - (*(tx_wqe_addr + 1) & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK) - -/* Tx Completion Count */ -#define MLXBF_GIGE_TX_CC_SZ 8 - -/* List of resources in ACPI table */ -enum mlxbf_gige_res { - MLXBF_GIGE_RES_MAC, - MLXBF_GIGE_RES_MDIO9, - MLXBF_GIGE_RES_GPIO0, - MLXBF_GIGE_RES_CAUSE_RSH_COALESCE0, - MLXBF_GIGE_RES_CAUSE_GPIO_ARM_COALESCE0, - MLXBF_GIGE_RES_LLU, - MLXBF_GIGE_RES_PLU -}; - -/* Version of register data returned by mlxbf_gige_get_regs() */ -#define MLXBF_GIGE_REGS_VERSION 1 - -int mlxbf_gige_mdio_probe(struct platform_device *pdev, - struct mlxbf_gige *priv); -void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv); -irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv); - -#endif /* !defined(__MLXBF_GIGE_H__) */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c deleted file mode 100644 index 0432d836add7..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ /dev/null @@ -1,2422 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB - -/* Gigabit Ethernet driver for Mellanox BlueField SoC - * - * Copyright (c) 2020, Mellanox Technologies - */ - -/* Standard method to enable kernel debug (e.g. dev_dbg) */ -#define DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include - -/* The MLXBF_GIGE_INTERNAL setting is defined in the - * "mlxbf_gige.h" header file, so this header file must - * be included before any processing of that setting. - */ -#include "mlxbf_gige.h" -#include "mlxbf_gige_regs.h" - -#ifdef MLXBF_GIGE_INTERNAL -#include -/* - * Upstreaming guidelines: - * ======================= - * 1) Do not upstream any code that is encapsulated by - * the "MLXBF_GIGE_INTERNAL" tag; that tag is for code - * that is for internal use only. - * 2) Remove all code that defines or checks for the - * definition of "FAST_MODELS". The code encapsulated - * by "#ifdef FAST_MODELS" should always be enabled - * in the upstream source since it is PHY related. - * 3) Remove all code that defines or checks for the - * definition of "MLXBF_GIGE_LOOPBACK". The code encapsulated - * by "#ifndef MLXBF_GIGE_LOOPBACK" should always be enabled, - * i.e. upstream code should run in non-loopback mode. - * 4) Remove any code that checks for current Linux version - * via "LINUX_VERSION_CODE". The upstream code should - * always be tailored to a specific Linux kernel. - * 5) Remove "#define DEBUG" at top of this file. - */ - -/* Define to create mmio read/write sysfs entries */ -#define MLXBF_GIGE_MMIO_SYSFS - -/* Define this to perform read/write tests to MMIO regs */ -#define MLXBF_GIGE_MMIO_TESTS - -/* Define this to perform read/write tests to LLU MMIO regs - * NOTE: there is no LLU on FastModels, so don't try it. - */ -/* #define LLU_MMIO_TESTS */ - -/* Define this to perform read/write tests to PLU MMIO regs - * NOTE: there is no PLU on FastModels, so don't try it. - */ -/* #define PLU_MMIO_TESTS */ - -/* Define this to put IP networking stack into loopback mode, - * where IP stack will not transmit packets out the GigE interface. - * Instead use the GigE sysfs entry (e.g. 'echo > start_tx') - * to send packets. It is assumed that interface is being put into - * loopback mode by one of these methods: - * a) Fast Models loopback - * b) PLU loopback mode - * c) PHY loopback mode - */ -/* #define MLXBF_GIGE_LOOPBACK */ -#endif /* MLXBF_GIGE_INTERNAL */ - -#define FAST_MODELS - -#define DRV_NAME "mlxbf_gige" -#define DRV_VERSION "1.0" - -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_MSG_FORMAT \ - " %02x %02x %02x %02x %02x %02x %02x %02x" \ - " %02x %02x %02x %02x %02x %02x %02x %02x\n" - -#define MLXBF_GIGE_MSG_ARGS(p) \ - *p, *(p + 1), *(p + 2), *(p + 3), \ - *(p + 4), *(p + 5), *(p + 6), *(p + 7), \ - *(p + 8), *(p + 9), *(p + 10), *(p + 11), \ - *(p + 12), *(p + 13), *(p + 14), *(p + 15) - -static void mlxbf_gige_plu_selftests(struct platform_device *pdev, - struct mlxbf_gige *priv) -{ -#ifdef PLU_MMIO_TESTS - u32 rd_data, exp_data; - - dev_dbg(&pdev->dev, "Running PLU MMIO tests\n"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->plu_base + 0x8); - exp_data = 0x1ff; - dev_dbg(&pdev->dev, "PLU 0x8 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->plu_base + 0x140); - exp_data = 0xe8001870; - dev_dbg(&pdev->dev, "PLU 0x140 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->plu_base + 0x610); - exp_data = 0x31001; - dev_dbg(&pdev->dev, "PLU 0x610 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->plu_base + 0x618); - exp_data = 0xb0000; - dev_dbg(&pdev->dev, "PLU 0x618 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->plu_base + 0x890); - exp_data = 0x9; - dev_dbg(&pdev->dev, "PLU 0x890 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->plu_base + 0x894); - exp_data = 0x1; - dev_dbg(&pdev->dev, "PLU 0x894 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); -#endif -} - -static void mlxbf_gige_llu_selftests(struct platform_device *pdev, - struct mlxbf_gige *priv) -{ -#ifdef LLU_MMIO_TESTS - u32 rd_data, exp_data; - - dev_dbg(&pdev->dev, "Running LLU MMIO tests\n"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->llu_base + 0x2200); - exp_data = 0x91008808; - dev_dbg(&pdev->dev, "LLU 0x2200 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->llu_base + 0x2204); - exp_data = 0x810088a8; - dev_dbg(&pdev->dev, "LLU 0x2204 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->llu_base + 0x2208); - exp_data = 0x22e90000; - dev_dbg(&pdev->dev, "LLU 0x2208 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->llu_base + 0x220c); - exp_data = 0x893f0000; - dev_dbg(&pdev->dev, "LLU 0x220c equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->llu_base + 0x2260); - exp_data = 0x8060806; - dev_dbg(&pdev->dev, "LLU 0x2260 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readl(priv->llu_base + 0x2264); - exp_data = 0x891422e7; - dev_dbg(&pdev->dev, "LLU 0x2264 equals %x - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); -#endif -} - -static void mlxbf_gige_selftests(struct platform_device *pdev, - struct mlxbf_gige *priv) -{ -#ifdef MLXBF_GIGE_MMIO_TESTS - u64 rd_data, wr_data, exp_data; - - dev_dbg(&pdev->dev, "Running MLXBF_GIGE MMIO tests\n"); - - /* Read data should match reset value in register header file */ - rd_data = readq(priv->base + MLXBF_GIGE_CONFIG); - exp_data = (MLXBF_GIGE_CONFIG_MAX_PKT_SZ_RESET_VAL - << MLXBF_GIGE_CONFIG_MAX_PKT_SZ_SHIFT); - dev_dbg(&pdev->dev, "MLXBF_GIGE_CONFIG equals %llx - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readq(priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); - exp_data = MLXBF_GIGE_RX_WQE_SIZE_LOG2_RESET_VAL; - dev_dbg(&pdev->dev, "MLXBF_GIGE_RX_WQE_SIZE_LOG2 equals %llx - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Read data should match reset value in register header file */ - rd_data = readq(priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); - exp_data = MLXBF_GIGE_TX_WQ_SIZE_LOG2_RESET_VAL; - dev_dbg(&pdev->dev, "MLXBF_GIGE_TX_WQ_SIZE_LOG2 equals %llx - %s\n", - rd_data, (rd_data == exp_data) ? "OK" : "FAIL"); - - /* Do some SCRATCHPAD testing */ - rd_data = readq(priv->base + MLXBF_GIGE_SCRATCHPAD); - dev_dbg(&pdev->dev, "MLXBF_GIGE_SCRATCHPAD equals %llx\n", rd_data); - - wr_data = 0x1122334455667788; - writeq(wr_data, priv->base + MLXBF_GIGE_SCRATCHPAD); - dev_dbg(&pdev->dev, "Will write %llx to MLXBF_GIGE_SCRATCHPAD\n", - wr_data); - - rd_data = readq(priv->base + MLXBF_GIGE_SCRATCHPAD); - dev_dbg(&pdev->dev, "MLXBF_GIGE_SCRATCHPAD equals %llx - %s\n", - rd_data, (rd_data == wr_data) ? "OK" : "FAIL"); - - wr_data = 0xaabbccddeeff4321; - writeq(wr_data, priv->base + MLXBF_GIGE_SCRATCHPAD); - dev_dbg(&pdev->dev, "Will write %llx to MLXBF_GIGE_SCRATCHPAD\n", - wr_data); - - rd_data = readq(priv->base + MLXBF_GIGE_SCRATCHPAD); - dev_dbg(&pdev->dev, "MLXBF_GIGE_SCRATCHPAD equals %llx - %s\n", - rd_data, (rd_data == wr_data) ? "OK" : "FAIL"); -#endif /* MLXBF_GIGE_MMIO_TESTS */ -} -#endif /* MLXBF_GIGE_INTERNAL */ - -static void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 dmac) -{ - void __iomem *base = priv->base; - u64 control; - -#ifdef MLXBF_GIGE_INTERNAL - if (index > 3) { - dev_err(priv->dev, "%s: invalid index %d\n", - __func__, index); - return; - } - - dev_dbg(priv->dev, "set_mac_rx_filter: index=%d dmac=%llx\n", - index, dmac); -#endif - - /* Write destination MAC to specified MAC RX filter */ - writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + - (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); - - /* Enable MAC receive filter mask for specified index */ - control = readq(base + MLXBF_GIGE_CONTROL); - control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index); - writeq(control, base + MLXBF_GIGE_CONTROL); -} - -static int mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, - unsigned int index, u64 *dmac) -{ - void __iomem *base = priv->base; - -#ifdef MLXBF_GIGE_INTERNAL - if (index > 3) { - dev_err(priv->dev, "%s: invalid index %d\n", - __func__, index); - return -EINVAL; - } - - if (!dmac) { - dev_err(priv->dev, "%s: invalid dmac pointer NULL\n", - __func__); - return -EINVAL; - } -#endif - - /* Read destination MAC from specified MAC RX filter */ - *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + - (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "get_mac_rx_filter: index=%d dmac=%llx\n", - index, *dmac); -#endif - - return 0; -} - -static void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) -{ - void __iomem *base = priv->base; - u64 control; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "%s\n", __func__); -#endif - - /* Enable MAC_ID_RANGE match functionality */ - control = readq(base + MLXBF_GIGE_CONTROL); - control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; - writeq(control, base + MLXBF_GIGE_CONTROL); - - /* Set start of destination MAC range check to 0 */ - writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START); - - /* Set end of destination MAC range check to all FFs */ - writeq(0xFFFFFFFFFFFF, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END); -} - -static void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) -{ - void __iomem *base = priv->base; - u64 control; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "%s\n", __func__); -#endif - - /* Disable MAC_ID_RANGE match functionality */ - control = readq(base + MLXBF_GIGE_CONTROL); - control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; - writeq(control, base + MLXBF_GIGE_CONTROL); - - /* NOTE: no need to change DMAC_RANGE_START or END; - * those values are ignored since MAC_ID_RANGE_EN=0 - */ -} - -/* Receive Initialization - * 1) Configures RX MAC filters via MMIO registers - * 2) Allocates RX WQE array using coherent DMA mapping - * 3) Initializes each element of RX WQE array with a receive - * buffer pointer (also using coherent DMA mapping) - * 4) Allocates RX CQE array using coherent DMA mapping - * 5) Completes other misc receive initialization - */ -static int mlxbf_gige_rx_init(struct mlxbf_gige *priv) -{ - size_t wq_size, cq_size; - dma_addr_t *rx_wqe_ptr; - dma_addr_t rx_buf_dma; - u64 data; - int i, j; - - /* Configure MAC RX filter #0 to allow RX of broadcast pkts */ - mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX, - BCAST_MAC_ADDR); - - wq_size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; - priv->rx_wqe_base = dma_alloc_coherent(priv->dev, wq_size, - &priv->rx_wqe_base_dma, - GFP_KERNEL); - if (!priv->rx_wqe_base) - return -ENOMEM; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "rx_init: RX WQE base 0x%llx 0x%llx\n", - (u64)priv->rx_wqe_base, (u64)priv->rx_wqe_base_dma); -#endif - - /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array - * Each RX WQE is simply a receive buffer pointer, so walk - * the entire array, allocating a 2KB buffer for each element - */ - rx_wqe_ptr = priv->rx_wqe_base; - - for (i = 0; i < priv->rx_q_entries; i++) { -#ifdef MLXBF_GIGE_INTERNAL - u8 *p; -#endif - /* Allocate a receive buffer for this RX WQE. The DMA - * form (dma_addr_t) of the receive buffer address is - * stored in the RX WQE array (via 'rx_wqe_ptr') where - * it is accessible by the GigE device. The VA form of - * the receive buffer is stored in 'rx_buf[]' array in - * the driver private storage for housekeeping. - */ - priv->rx_buf[i] = dma_alloc_coherent(priv->dev, - MLXBF_GIGE_DEFAULT_BUF_SZ, - &rx_buf_dma, - GFP_KERNEL); - if (!priv->rx_buf[i]) - goto free_wqe_and_buf; - -#ifdef MLXBF_GIGE_INTERNAL - /* Initialize the first 16 bytes of each RX buffer - * to a known pattern. This will make it easy to - * identify when each receive buffer is populated - */ - p = priv->rx_buf[i]; - memset(p, MLXBF_GIGE_INIT_BYTE_RX_BUF, 16); -#endif - *rx_wqe_ptr++ = rx_buf_dma; - } - - /* Write RX WQE base address into MMIO reg */ - writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE); - - cq_size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; - priv->rx_cqe_base = dma_alloc_coherent(priv->dev, cq_size, - &priv->rx_cqe_base_dma, - GFP_KERNEL); - if (!priv->rx_cqe_base) - goto free_wqe_and_buf; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "rx_init: RX CQE base 0x%llx 0x%llx\n", - (u64)priv->rx_cqe_base, (u64)priv->rx_cqe_base_dma); -#endif - - /* Write RX CQE base address into MMIO reg */ - writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); - - /* Write RX_WQE_PI with current number of replenished buffers */ - writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI); - - /* Enable RX DMA to write new packets to memory */ - writeq(MLXBF_GIGE_RX_DMA_EN, priv->base + MLXBF_GIGE_RX_DMA); - - /* Enable removal of CRC during RX */ - data = readq(priv->base + MLXBF_GIGE_RX); - data |= MLXBF_GIGE_RX_STRIP_CRC_EN; - writeq(data, priv->base + MLXBF_GIGE_RX); - - /* Enable RX MAC filter pass and discard counters */ - writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN, - priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC); - writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN, - priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS); - - /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to - * indicate readiness to receive pkts - */ - data = readq(priv->base + MLXBF_GIGE_INT_MASK); - data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; - writeq(data, priv->base + MLXBF_GIGE_INT_MASK); - - writeq(ilog2(priv->rx_q_entries), - priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); - - return 0; - -free_wqe_and_buf: - rx_wqe_ptr = priv->rx_wqe_base; - for (j = 0; j < i; j++) { - dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, - priv->rx_buf[j], *rx_wqe_ptr); - rx_wqe_ptr++; - } - dma_free_coherent(priv->dev, wq_size, - priv->rx_wqe_base, priv->rx_wqe_base_dma); - return -ENOMEM; -} - -/* Transmit Initialization - * 1) Allocates TX WQE array using coherent DMA mapping - * 2) Allocates TX completion counter using coherent DMA mapping - */ -static int mlxbf_gige_tx_init(struct mlxbf_gige *priv) -{ - size_t size; - - size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; - priv->tx_wqe_base = dma_alloc_coherent(priv->dev, size, - &priv->tx_wqe_base_dma, - GFP_KERNEL); - if (!priv->tx_wqe_base) - return -ENOMEM; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "tx_init: TX WQE base 0x%llx 0x%llx\n", - (u64)priv->tx_wqe_base, (u64)priv->tx_wqe_base_dma); -#endif - - priv->tx_wqe_next = priv->tx_wqe_base; - - /* Write TX WQE base address into MMIO reg */ - writeq(priv->tx_wqe_base_dma, priv->base + MLXBF_GIGE_TX_WQ_BASE); - - /* Allocate address for TX completion count */ - priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, - &priv->tx_cc_dma, GFP_KERNEL); - - if (!priv->tx_cc) { - dma_free_coherent(priv->dev, size, - priv->tx_wqe_base, priv->tx_wqe_base_dma); - return -ENOMEM; - } - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "tx_init: TX CC 0x%llx 0x%llx\n", - (u64)priv->tx_cc, (u64)priv->tx_cc_dma); -#endif - - /* Write TX CC base address into MMIO reg */ - writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); - - writeq(ilog2(priv->tx_q_entries), - priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); - - priv->prev_tx_ci = 0; - priv->tx_pi = 0; - - return 0; -} - -/* Receive Deinitialization - * This routine will free allocations done by mlxbf_gige_rx_init(), - * namely the RX WQE and RX CQE arrays, as well as all RX buffers - */ -static void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) -{ - dma_addr_t *rx_wqe_ptr; - size_t size; - int i; - - rx_wqe_ptr = priv->rx_wqe_base; - - for (i = 0; i < priv->rx_q_entries; i++) { - dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, - priv->rx_buf[i], *rx_wqe_ptr); - priv->rx_buf[i] = NULL; - rx_wqe_ptr++; - } - - size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; - dma_free_coherent(priv->dev, size, - priv->rx_wqe_base, priv->rx_wqe_base_dma); - - size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; - dma_free_coherent(priv->dev, size, - priv->rx_cqe_base, priv->rx_cqe_base_dma); - - priv->rx_wqe_base = 0; - priv->rx_wqe_base_dma = 0; - priv->rx_cqe_base = 0; - priv->rx_cqe_base_dma = 0; - writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE); - writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE); -} - -/* Transmit Deinitialization - * This routine will free allocations done by mlxbf_gige_tx_init(), - * namely the TX WQE array and the TX completion counter - */ -static void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) -{ - u64 *tx_wqe_ptr; - size_t size; - int i; - - tx_wqe_ptr = priv->tx_wqe_base; - - for (i = 0; i < priv->tx_q_entries; i++) { - if (priv->tx_buf[i]) { - dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, - priv->tx_buf[i], *tx_wqe_ptr); - priv->tx_buf[i] = NULL; - } - tx_wqe_ptr += 2; - } - - size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; - dma_free_coherent(priv->dev, size, - priv->tx_wqe_base, priv->tx_wqe_base_dma); - - dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, - priv->tx_cc, priv->tx_cc_dma); - - priv->tx_wqe_base = 0; - priv->tx_wqe_base_dma = 0; - priv->tx_cc = 0; - priv->tx_cc_dma = 0; - priv->tx_wqe_next = 0; - writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE); - writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); -} - -/* Start of struct ethtool_ops functions */ -static int mlxbf_gige_get_regs_len(struct net_device *netdev) -{ - /* Return size of MMIO register space (in bytes). - * - * NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset, - * so use that plus size of single register to derive total size - */ - return MLXBF_GIGE_MAC_CFG + 8; -} - -static void mlxbf_gige_get_regs(struct net_device *netdev, - struct ethtool_regs *regs, void *p) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - u64 *buff = p; - int reg; - - regs->version = MLXBF_GIGE_REGS_VERSION; - - /* Read entire MMIO register space and store results - * into the provided buffer. Each 64-bit word is converted - * to big-endian to make the output more readable. - * - * NOTE: by design, a read to an offset without an existing - * register will be acknowledged and return zero. - */ - for (reg = 0; reg <= MLXBF_GIGE_MAC_CFG; reg += 8) - *buff++ = cpu_to_be64(readq(priv->base + reg)); -} - -static void mlxbf_gige_get_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ering) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - memset(ering, 0, sizeof(*ering)); - ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; - ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; - ering->rx_pending = priv->rx_q_entries; - ering->tx_pending = priv->tx_q_entries; -} - -static int mlxbf_gige_set_ringparam(struct net_device *netdev, - struct ethtool_ringparam *ering) -{ - const struct net_device_ops *ops = netdev->netdev_ops; - struct mlxbf_gige *priv = netdev_priv(netdev); - int new_rx_q_entries, new_tx_q_entries; - - /* Device does not have separate queues for small/large frames */ - if (ering->rx_mini_pending || ering->rx_jumbo_pending) - return -EINVAL; - - /* Round up to supported values */ - new_rx_q_entries = roundup_pow_of_two(ering->rx_pending); - new_tx_q_entries = roundup_pow_of_two(ering->tx_pending); - - /* Range check the new values */ - if (new_tx_q_entries < MLXBF_GIGE_MIN_TXQ_SZ || - new_tx_q_entries > MLXBF_GIGE_MAX_TXQ_SZ || - new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ || - new_rx_q_entries > MLXBF_GIGE_MAX_RXQ_SZ) - return -EINVAL; - - /* If queue sizes did not change, exit now */ - if (new_rx_q_entries == priv->rx_q_entries && - new_tx_q_entries == priv->tx_q_entries) - return 0; - -#ifdef MLXBF_GIGE_INTERNAL - netdev_printk(KERN_DEBUG, netdev, - "set_ringparam(): new_tx=%x new_rx=%x\n", - new_tx_q_entries, new_rx_q_entries); -#endif - - if (netif_running(netdev)) - ops->ndo_stop(netdev); - - priv->rx_q_entries = new_rx_q_entries; - priv->tx_q_entries = new_tx_q_entries; - - if (netif_running(netdev)) - ops->ndo_open(netdev); - - return 0; -} - -static void mlxbf_gige_get_drvinfo(struct net_device *netdev, - struct ethtool_drvinfo *info) -{ - strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); - strlcpy(info->version, DRV_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, dev_name(&netdev->dev), sizeof(info->bus_info)); -} - -static const struct { - const char string[ETH_GSTRING_LEN]; -} mlxbf_gige_ethtool_stats_keys[] = { - { "rx_bytes" }, - { "rx_packets" }, - { "tx_bytes" }, - { "tx_packets" }, - { "hw_access_errors" }, - { "tx_invalid_checksums" }, - { "tx_small_frames" }, - { "tx_index_errors" }, - { "sw_config_errors" }, - { "sw_access_errors" }, - { "rx_truncate_errors" }, - { "rx_mac_errors" }, - { "rx_din_dropped_pkts" }, - { "tx_fifo_full" }, - { "rx_filter_passed_pkts" }, - { "rx_filter_discard_pkts" }, -}; - -static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) -{ - if (stringset != ETH_SS_STATS) - return -EOPNOTSUPP; - return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); -} - -static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, - u8 *buf) -{ - if (stringset != ETH_SS_STATS) - return; - memcpy(buf, &mlxbf_gige_ethtool_stats_keys, - sizeof(mlxbf_gige_ethtool_stats_keys)); -} - -static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, - struct ethtool_stats *estats, - u64 *data) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - - /* Fill data array with interface statistics - * - * NOTE: the data writes must be in - * sync with the strings shown in - * the mlxbf_gige_ethtool_stats_keys[] array - * - * NOTE2: certain statistics below are zeroed upon - * port disable, so the calculation below - * must include the "cached" value of the stat - * plus the value read directly from hardware. - * Cached statistics are currently: - * rx_din_dropped_pkts - * rx_filter_passed_pkts - * rx_filter_discard_pkts - */ - *data++ = netdev->stats.rx_bytes; - *data++ = netdev->stats.rx_packets; - *data++ = netdev->stats.tx_bytes; - *data++ = netdev->stats.tx_packets; - *data++ = priv->stats.hw_access_errors; - *data++ = priv->stats.tx_invalid_checksums; - *data++ = priv->stats.tx_small_frames; - *data++ = priv->stats.tx_index_errors; - *data++ = priv->stats.sw_config_errors; - *data++ = priv->stats.sw_access_errors; - *data++ = priv->stats.rx_truncate_errors; - *data++ = priv->stats.rx_mac_errors; - *data++ = (priv->stats.rx_din_dropped_pkts + - readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); - *data++ = priv->stats.tx_fifo_full; - *data++ = (priv->stats.rx_filter_passed_pkts + - readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); - *data++ = (priv->stats.rx_filter_discard_pkts + - readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); -} - -static const struct ethtool_ops mlxbf_gige_ethtool_ops = { - .get_drvinfo = mlxbf_gige_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_ringparam = mlxbf_gige_get_ringparam, - .set_ringparam = mlxbf_gige_set_ringparam, - .get_regs_len = mlxbf_gige_get_regs_len, - .get_regs = mlxbf_gige_get_regs, - .get_strings = mlxbf_gige_get_strings, - .get_sset_count = mlxbf_gige_get_sset_count, - .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, -}; - -#ifdef FAST_MODELS -static void mlxbf_gige_handle_link_change(struct net_device *netdev) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - struct phy_device *phydev = netdev->phydev; - irqreturn_t ret; - - ret = mlxbf_gige_mdio_handle_phy_interrupt(priv); - if (ret != IRQ_HANDLED) - return; - - /* print new link status only if the interrupt came from the PHY */ - phy_print_status(phydev); -} -#endif /* FAST_MODELS */ - -/* Start of struct net_device_ops functions */ -static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) -{ - struct mlxbf_gige *priv; - u64 int_status; - - priv = dev_id; - - priv->error_intr_count++; - - int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); - -#ifdef MLXBF_GIGE_INTERNAL - /* Trigger kernel log message on first interrupt of each - * type and then service the asserted error condition(s). - */ -#endif - - if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) { - priv->stats.hw_access_errors++; -#ifdef MLXBF_GIGE_INTERNAL - if (priv->stats.hw_access_errors == 1) { - dev_info(priv->dev, - "%s: hw_access_error triggered\n", - __func__); - } - /* TODO - add logic to service hw_access_error */ -#endif - } - - if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { - priv->stats.tx_invalid_checksums++; -#ifdef MLXBF_GIGE_INTERNAL - if (priv->stats.tx_invalid_checksums == 1) { - dev_info(priv->dev, - "%s: tx_invalid_checksum triggered\n", - __func__); - } -#endif - /* This error condition is latched into MLXBF_GIGE_INT_STATUS - * when the GigE silicon operates on the offending - * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom - * of this routine clears this error condition. - */ - } - - if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) { - priv->stats.tx_small_frames++; - /* This condition happens when the networking stack invokes - * this driver's "start_xmit()" method with a packet whose - * size < 60 bytes. The GigE silicon will automatically pad - * this small frame up to a minimum-sized frame before it is - * sent. The "tx_small_frame" condition is latched into the - * MLXBF_GIGE_INT_STATUS register when the GigE silicon - * operates on the offending TX WQE. The write to - * MLXBF_GIGE_INT_STATUS at the bottom of this routine - * clears this condition. - */ - } - - if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) { - priv->stats.tx_index_errors++; -#ifdef MLXBF_GIGE_INTERNAL - if (priv->stats.tx_index_errors == 1) { - dev_info(priv->dev, - "%s: tx_index_error triggered\n", - __func__); - } - /* TODO - add logic to service tx_index_error */ -#endif - } - - if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) { - priv->stats.sw_config_errors++; -#ifdef MLXBF_GIGE_INTERNAL - if (priv->stats.sw_config_errors == 1) { - dev_info(priv->dev, - "%s: sw_config_error triggered\n", - __func__); - } - /* TODO - add logic to service sw_config_error */ -#endif - } - - if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) { - priv->stats.sw_access_errors++; -#ifdef MLXBF_GIGE_INTERNAL - if (priv->stats.sw_access_errors == 1) { - dev_info(priv->dev, - "%s: sw_access_error triggered\n", - __func__); - } - /* TODO - add logic to service sw_access_error */ -#endif - } - - /* Clear all error interrupts by writing '1' back to - * all the asserted bits in INT_STATUS. Do not write - * '1' back to 'receive packet' bit, since that is - * managed separately. - */ - - int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET; - - writeq(int_status, priv->base + MLXBF_GIGE_INT_STATUS); - - return IRQ_HANDLED; -} - -static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) -{ - struct mlxbf_gige *priv; - - priv = dev_id; - - priv->rx_intr_count++; - - /* Driver has been interrupted because a new packet is available, - * but do not process packets at this time. Instead, disable any - * further "packet rx" interrupts and tell the networking subsystem - * to poll the driver to pick up all available packets. - * - * NOTE: GigE silicon automatically disables "packet rx" interrupt by - * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt - * to the ARM cores. Software needs to re-enable "packet rx" - * interrupts by clearing MLXBF_GIGE_INT_MASK bit0. - */ - - /* Tell networking subsystem to poll GigE driver */ - napi_schedule(&priv->napi); - - return IRQ_HANDLED; -} - -static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) -{ - struct mlxbf_gige *priv; - - priv = dev_id; - priv->llu_plu_intr_count++; - -#ifdef MLXBF_GIGE_INTERNAL - /* Trigger kernel log message on first interrupt */ - if (priv->llu_plu_intr_count == 1) - dev_info(priv->dev, "%s: triggered\n", __func__); - - /* TODO - add logic to service LLU and PLU interrupts */ -#endif - - return IRQ_HANDLED; -} - -/* Function that returns status of TX ring: - * 0: TX ring is full, i.e. there are no - * available un-used entries in TX ring. - * non-null: TX ring is not full, i.e. there are - * some available entries in TX ring. - * The non-null value is a measure of - * how many TX entries are available, but - * it is not the exact number of available - * entries (see below). - * - * The algorithm makes the assumption that if - * (prev_tx_ci == tx_pi) then the TX ring is empty. - * An empty ring actually has (tx_q_entries-1) - * entries, which allows the algorithm to differentiate - * the case of an empty ring vs. a full ring. - */ -static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) -{ - u16 avail; - - if (priv->prev_tx_ci == priv->tx_pi) - avail = priv->tx_q_entries - 1; - else - avail = (((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) - % priv->tx_q_entries) - 1); - return avail; -} - -static bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) -{ - struct net_device_stats *stats; - u16 tx_wqe_index; - u64 *tx_wqe_addr; - u64 tx_status; - u16 tx_ci; - - tx_status = readq(priv->base + MLXBF_GIGE_TX_STATUS); - if (tx_status & MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL) - priv->stats.tx_fifo_full++; - tx_ci = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); - stats = &priv->netdev->stats; - - /* Transmit completion logic needs to loop until the completion - * index (in SW) equals TX consumer index (from HW). These - * parameters are unsigned 16-bit values and the wrap case needs - * to be supported, that is TX consumer index wrapped from 0xFFFF - * to 0 while TX completion index is still < 0xFFFF. - */ - for (; priv->prev_tx_ci != tx_ci; priv->prev_tx_ci++) { - tx_wqe_index = priv->prev_tx_ci % priv->tx_q_entries; - /* Each TX WQE is 16 bytes. The 8 MSB store the 2KB TX - * buffer address and the 8 LSB contain information - * about the TX WQE. - */ - tx_wqe_addr = (priv->tx_wqe_base + - (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS)); - - stats->tx_packets++; - stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); -#ifndef MLXBF_GIGE_LOOPBACK - dma_free_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, - priv->tx_buf[tx_wqe_index], *tx_wqe_addr); - priv->tx_buf[tx_wqe_index] = NULL; -#endif - } - - /* Since the TX ring was likely just drained, check if TX queue - * had previously been stopped and now that there are TX buffers - * available the TX queue can be awakened. - */ - if (netif_queue_stopped(priv->netdev) && - mlxbf_gige_tx_buffs_avail(priv)) { -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "%s: waking TX queue", __func__); -#endif - netif_wake_queue(priv->netdev); - } - - return true; -} - -static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) -{ - struct net_device *netdev = priv->netdev; - u16 rx_pi_rem, rx_ci_rem; - struct sk_buff *skb; - u64 *rx_cqe_addr; - u64 datalen; - u64 rx_cqe; - u16 rx_ci; - u16 rx_pi; - u8 *pktp; - - /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ - rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); - rx_pi_rem = rx_pi % priv->rx_q_entries; - pktp = priv->rx_buf[rx_pi_rem]; - rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; - rx_cqe = *rx_cqe_addr; - datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; - - if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { - /* Packet is OK, increment stats */ - netdev->stats.rx_packets++; - netdev->stats.rx_bytes += datalen; - } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { - priv->stats.rx_mac_errors++; -#ifdef MLXBF_GIGE_INTERNAL - /* TODO - handle error case */ -#endif - } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { - priv->stats.rx_truncate_errors++; -#ifdef MLXBF_GIGE_INTERNAL - /* TODO - handle error case */ -#endif - } - - skb = dev_alloc_skb(datalen); - if (!skb) { - netdev->stats.rx_dropped++; - return false; - } - - memcpy(skb_put(skb, datalen), pktp, datalen); - - /* Let hardware know we've replenished one buffer */ - writeq(rx_pi + 1, priv->base + MLXBF_GIGE_RX_WQE_PI); - - skb->dev = netdev; - skb->protocol = eth_type_trans(skb, netdev); - skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ - - netif_receive_skb(skb); - (*rx_pkts)++; - rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); - rx_pi_rem = rx_pi % priv->rx_q_entries; - rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); - rx_ci_rem = rx_ci % priv->rx_q_entries; - - return rx_pi_rem != rx_ci_rem; -} - -/* Driver poll() function called by NAPI infrastructure */ -static int mlxbf_gige_poll(struct napi_struct *napi, int budget) -{ - struct mlxbf_gige *priv; - bool remaining_pkts; - int work_done = 0; - u64 data; - - priv = container_of(napi, struct mlxbf_gige, napi); - - mlxbf_gige_handle_tx_complete(priv); - - do { - remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done); - } while (remaining_pkts && work_done < budget); - - /* If amount of work done < budget, turn off NAPI polling - * via napi_complete_done(napi, work_done) and then - * re-enable interrupts. - */ - if (work_done < budget && napi_complete_done(napi, work_done)) { - /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to - * indicate receive readiness - */ - data = readq(priv->base + MLXBF_GIGE_INT_MASK); - data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; - writeq(data, priv->base + MLXBF_GIGE_INT_MASK); - } - - return work_done; -} - -static int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) -{ - int err; - - err = devm_request_irq(priv->dev, priv->error_irq, - mlxbf_gige_error_intr, 0, "mlxbf_gige_error", - priv); - if (err) { - dev_err(priv->dev, "Request error_irq failure\n"); - return err; - } - - err = devm_request_irq(priv->dev, priv->rx_irq, - mlxbf_gige_rx_intr, 0, "mlxbf_gige_rx", - priv); - if (err) { - dev_err(priv->dev, "Request rx_irq failure\n"); - return err; - } - - err = devm_request_irq(priv->dev, priv->llu_plu_irq, - mlxbf_gige_llu_plu_intr, 0, "mlxbf_gige_llu_plu", - priv); - if (err) { - dev_err(priv->dev, "Request llu_plu_irq failure\n"); - return err; - } - - return 0; -} - -static void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) -{ - devm_free_irq(priv->dev, priv->error_irq, priv); - devm_free_irq(priv->dev, priv->rx_irq, priv); - devm_free_irq(priv->dev, priv->llu_plu_irq, priv); -} - -static int mlxbf_gige_open(struct net_device *netdev) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); -#ifdef FAST_MODELS - struct phy_device *phydev; -#endif - u64 int_en; - int err; - -#ifdef MLXBF_GIGE_INTERNAL - netdev_printk(KERN_DEBUG, netdev, "open: priv=%llx\n", - (u64)priv); -#endif - - memset(&priv->stats, 0, sizeof(priv->stats)); - - mlxbf_gige_rx_init(priv); - mlxbf_gige_tx_init(priv); - netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); - napi_enable(&priv->napi); - netif_start_queue(netdev); - - err = mlxbf_gige_request_irqs(priv); - if (err) - return err; - -#ifdef FAST_MODELS - phydev = phy_find_first(priv->mdiobus); - if (!phydev) - return -EIO; - - /* Sets netdev->phydev to phydev; which will eventually - * be used in ioctl calls. - */ - err = phy_connect_direct(netdev, phydev, - mlxbf_gige_handle_link_change, - PHY_INTERFACE_MODE_GMII); - if (err) { - netdev_err(netdev, "Could not attach to PHY\n"); - return err; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) - /* MAC only supports 1000T full duplex mode */ - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); - phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); - - /* MAC supports symmetric flow control */ - phy_support_sym_pause(phydev); -#else - /* MAC only supports 1000T full duplex mode */ - phydev->supported &= ~SUPPORTED_1000baseT_Half; - phydev->supported &= ~SUPPORTED_100baseT_Full; - phydev->supported &= ~SUPPORTED_100baseT_Half; - phydev->supported &= ~SUPPORTED_10baseT_Full; - phydev->supported &= ~SUPPORTED_10baseT_Half; - - /* MAC supports symmetric flow control */ - phydev->supported |= SUPPORTED_Pause; -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */ - - phy_start(phydev); - err = phy_start_aneg(phydev); - if (err < 0) { - netdev_err(netdev, "phy_start_aneg failure: 0x%x\n", err); - return err; - } - -#ifdef MLXBF_GIGE_INTERNAL -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) - netdev_printk(KERN_DEBUG, netdev, "supported: %*pb, advertising: %*pb," - " speed: 0x%x, duplex: 0x%x, autoneg: 0x%x, pause: 0x%x," - " asym_pause: 0x%x\n", - __ETHTOOL_LINK_MODE_MASK_NBITS, phydev->supported, - __ETHTOOL_LINK_MODE_MASK_NBITS, phydev->advertising, - phydev->speed, phydev->duplex, phydev->autoneg, - phydev->pause, phydev->asym_pause); -#else - netdev_printk(KERN_DEBUG, netdev, "supported: 0x%x, advertising: 0x%x," - " speed: 0x%x, duplex: 0x%x, autoneg: 0x%x, pause: 0x%x," - " asym_pause: 0x%x\n", - phydev->supported, phydev->advertising, phydev->speed, - phydev->duplex, phydev->autoneg, phydev->pause, - phydev->asym_pause); -#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0) */ -#endif /* MLXBF_GIGE_INTERNAL */ - - /* Display information about attached PHY device */ - phy_attached_info(phydev); - -#endif /* FAST_MODELS */ - - /* Set bits in INT_EN that we care about */ - int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | - MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS | - MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE | - MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE | - MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR | - MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR | - MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET; - writeq(int_en, priv->base + MLXBF_GIGE_INT_EN); - - return 0; -} - -static void mlxbf_gige_clean_port(struct mlxbf_gige *priv) -{ - struct mlxbf_gige_stats *p; - u64 control, status; - int cnt; - - /* Cache stats that will be cleared by clean port operation */ - p = &priv->stats; - p->rx_din_dropped_pkts = readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); - p->rx_filter_passed_pkts = readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL); - p->rx_filter_discard_pkts = readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL); - - /* Set the CLEAN_PORT_EN bit to trigger SW reset */ - control = readq(priv->base + MLXBF_GIGE_CONTROL); - control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; - writeq(control, priv->base + MLXBF_GIGE_CONTROL); - - /* Create memory barrier before reading status */ - wmb(); - - /* Loop waiting for status ready bit to assert */ - cnt = 1000; - do { - status = readq(priv->base + MLXBF_GIGE_STATUS); - if (status & MLXBF_GIGE_STATUS_READY) - break; - usleep_range(50, 100); - } while (--cnt > 0); - - /* Clear the CLEAN_PORT_EN bit at end of this loop */ - control = readq(priv->base + MLXBF_GIGE_CONTROL); - control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; - writeq(control, priv->base + MLXBF_GIGE_CONTROL); -} - -static int mlxbf_gige_stop(struct net_device *netdev) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - -#ifdef MLXBF_GIGE_INTERNAL - netdev_printk(KERN_DEBUG, netdev, "stop: priv=%llx\n", - (u64)priv); -#endif - - writeq(0, priv->base + MLXBF_GIGE_INT_EN); - netif_stop_queue(netdev); - napi_disable(&priv->napi); - netif_napi_del(&priv->napi); - mlxbf_gige_free_irqs(priv); - -#ifdef FAST_MODELS - phy_stop(netdev->phydev); - phy_disconnect(netdev->phydev); -#endif /* FAST_MODELS */ - - mlxbf_gige_rx_deinit(priv); - mlxbf_gige_tx_deinit(priv); - mlxbf_gige_clean_port(priv); - - return 0; -} - -/* Function to advance the tx_wqe_next pointer to next TX WQE */ -static void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv) -{ - /* Advance tx_wqe_next pointer */ - priv->tx_wqe_next += MLXBF_GIGE_TX_WQE_SZ_QWORDS; - - /* Check if 'next' pointer is beyond end of TX ring */ - /* If so, set 'next' back to 'base' pointer of ring */ - if (priv->tx_wqe_next == (priv->tx_wqe_base + - (priv->tx_q_entries * MLXBF_GIGE_TX_WQE_SZ_QWORDS))) - priv->tx_wqe_next = priv->tx_wqe_base; -} - -static netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, - struct net_device *netdev) -{ -#ifndef MLXBF_GIGE_LOOPBACK - struct mlxbf_gige *priv = netdev_priv(netdev); - dma_addr_t tx_buf_dma; - u8 *tx_buf = NULL; - u64 *tx_wqe_addr; - u64 word2; - - /* Check that there is room left in TX ring */ - if (!mlxbf_gige_tx_buffs_avail(priv)) { - /* TX ring is full, inform stack but do not free SKB */ -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(priv->dev, "%s: TX ring is full, stopping TX queue\n", - __func__); -#endif - netif_stop_queue(netdev); - netdev->stats.tx_dropped++; - return NETDEV_TX_BUSY; - } - - /* Allocate ptr for buffer */ - if (skb->len < MLXBF_GIGE_DEFAULT_BUF_SZ) - tx_buf = dma_alloc_coherent(priv->dev, MLXBF_GIGE_DEFAULT_BUF_SZ, - &tx_buf_dma, GFP_KERNEL); - - if (!tx_buf) { - /* Free incoming skb, could not alloc TX buffer */ - dev_kfree_skb(skb); - netdev->stats.tx_dropped++; - return NET_XMIT_DROP; - } - - priv->tx_buf[priv->tx_pi % priv->tx_q_entries] = tx_buf; - - /* Copy data from skb to allocated TX buffer - * - * NOTE: GigE silicon will automatically pad up to - * minimum packet length if needed. - */ - skb_copy_bits(skb, 0, tx_buf, skb->len); - - /* Get address of TX WQE */ - tx_wqe_addr = priv->tx_wqe_next; - - mlxbf_gige_update_tx_wqe_next(priv); - - /* Put PA of buffer address into first 64-bit word of TX WQE */ - *tx_wqe_addr = tx_buf_dma; - - /* Set TX WQE pkt_len appropriately */ - word2 = skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; - - /* Write entire 2nd word of TX WQE */ - *(tx_wqe_addr + 1) = word2; - - priv->tx_pi++; - - /* Create memory barrier before write to TX PI */ - wmb(); - - writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); -#endif - - /* Free incoming skb, contents already copied to HW */ - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static int mlxbf_gige_do_ioctl(struct net_device *netdev, - struct ifreq *ifr, int cmd) -{ -#ifdef FAST_MODELS - if (!(netif_running(netdev))) - return -EINVAL; - - return phy_mii_ioctl(netdev->phydev, ifr, cmd); -#else - return 0; - -#endif /* FAST_MODELS*/ -} - -#ifdef MLXBF_GIGE_INTERNAL -static void mlxbf_gige_tx_timeout(struct net_device *netdev) -{ - /* TODO - add TX timeout logic */ -} -#endif - -static void mlxbf_gige_set_rx_mode(struct net_device *netdev) -{ - struct mlxbf_gige *priv = netdev_priv(netdev); - bool new_promisc_enabled; - -#ifdef MLXBF_GIGE_INTERNAL - netdev_printk(KERN_DEBUG, netdev, "set_rx_mode: priv=%llx flags=%x\n", - (u64)priv, netdev->flags); -#endif - - new_promisc_enabled = netdev->flags & IFF_PROMISC; - - /* Only write to the hardware registers if the new setting - * of promiscuous mode is different from the current one. - */ - if (new_promisc_enabled != priv->promisc_enabled) { - priv->promisc_enabled = new_promisc_enabled; - - if (new_promisc_enabled) { -#ifdef MLXBF_GIGE_INTERNAL - netdev_printk(KERN_DEBUG, netdev, - "set_rx_mode: enable promisc\n"); -#endif - mlxbf_gige_enable_promisc(priv); - } else { -#ifdef MLXBF_GIGE_INTERNAL - netdev_printk(KERN_DEBUG, netdev, - "set_rx_mode: disable promisc\n"); -#endif - mlxbf_gige_disable_promisc(priv); - } - } -} - -static const struct net_device_ops mlxbf_gige_netdev_ops = { - .ndo_open = mlxbf_gige_open, - .ndo_stop = mlxbf_gige_stop, - .ndo_start_xmit = mlxbf_gige_start_xmit, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_do_ioctl = mlxbf_gige_do_ioctl, - .ndo_set_rx_mode = mlxbf_gige_set_rx_mode, -#ifdef MLXBF_GIGE_INTERNAL - .ndo_tx_timeout = mlxbf_gige_tx_timeout, -#endif -}; - -#ifdef MLXBF_GIGE_INTERNAL -#ifdef MLXBF_GIGE_MMIO_SYSFS -static ssize_t mmio_read_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - u64 offset; - int cnt; - - priv = dev_get_drvdata(dev); - - cnt = sscanf(buf, "%llx\n", &offset); - - if (cnt != 1) { - dev_err(dev, "MMIO read: invalid arguments\n"); - return len; - } - - /* Make sure offset is within MAC block and 8-byte aligned */ - if (offset <= MLXBF_GIGE_MAC_CFG && - ((offset & 0x7) == 0)) { - dev_err(dev, - "MMIO read: offset=0x%llx data=0x%llx\n", - offset, readq(priv->base + offset)); - } else { - dev_err(dev, - "MMIO read: invalid offset 0x%llx\n", - offset); - } - - return len; -} - -static ssize_t mmio_write_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - u64 offset, data; - int cnt; - - priv = dev_get_drvdata(dev); - - cnt = sscanf(buf, "%llx %llx\n", &offset, &data); - - if (cnt != 2) { - dev_err(dev, "MMIO write: invalid arguments\n"); - return len; - } - - /* Make sure offset is within MAC block and 8-byte aligned */ - if (offset <= MLXBF_GIGE_MAC_CFG && - ((offset & 0x7) == 0)) { - dev_err(dev, - "MMIO write: offset=0x%llx data=0x%llx\n", - offset, data); - writeq(data, priv->base + offset); - } else { - dev_err(dev, - "MMIO write: invalid offset 0x%llx\n", - offset); - } - - return len; -} - -static ssize_t llu_mmio_read_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - u64 offset; - int cnt; - - priv = dev_get_drvdata(dev); - - cnt = sscanf(buf, "%llx\n", &offset); - - if (cnt != 1) { - dev_err(dev, "LLU MMIO read: invalid arguments\n"); - return len; - } - - /* Make sure offset is within LLU and 4-byte aligned */ - if (offset <= MLXBF_GIGE_LLU_MAX_OFFSET && - ((offset & 0x3) == 0)) { - dev_err(dev, - "LLU MMIO read: offset=0x%llx data=0x%x\n", - offset, readl(priv->llu_base + offset)); - } else { - dev_err(dev, - "LLU MMIO read: invalid offset 0x%llx\n", - offset); - } - - return len; -} - -static ssize_t llu_mmio_write_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - u64 offset; - u32 data; - int cnt; - - priv = dev_get_drvdata(dev); - - cnt = sscanf(buf, "%llx %x\n", &offset, &data); - - if (cnt != 2) { - dev_err(dev, "LLU MMIO write: invalid arguments\n"); - return len; - } - - /* Make sure offset is within LLU and 4-byte aligned */ - if (offset <= MLXBF_GIGE_LLU_MAX_OFFSET && - ((offset & 0x3) == 0)) { - dev_err(dev, - "LLU MMIO write: offset=0x%llx data=0x%x\n", - offset, data); - writel(data, priv->llu_base + offset); - } else { - dev_err(dev, - "LLU MMIO write: invalid offset 0x%llx\n", - offset); - } - - return len; -} - -static ssize_t plu_mmio_read_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - u64 offset; - int cnt; - - priv = dev_get_drvdata(dev); - - cnt = sscanf(buf, "%llx\n", &offset); - - if (cnt != 1) { - dev_err(dev, "PLU MMIO read: invalid arguments\n"); - return len; - } - - /* Make sure offset is within PLU and 4-byte aligned */ - if (offset <= MLXBF_GIGE_PLU_MAX_OFFSET && - ((offset & 0x3) == 0)) { - dev_err(dev, - "PLU MMIO read: offset=0x%llx data=0x%x\n", - offset, readl(priv->plu_base + offset)); - } else { - dev_err(dev, - "PLU MMIO read: invalid offset 0x%llx\n", - offset); - } - - return len; -} - -static ssize_t plu_mmio_write_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - u64 offset; - u32 data; - int cnt; - - priv = dev_get_drvdata(dev); - - cnt = sscanf(buf, "%llx %x\n", &offset, &data); - - if (cnt != 2) { - dev_err(dev, "PLU MMIO write: invalid arguments\n"); - return len; - } - - /* Make sure offset is within PLU and 4-byte aligned */ - if (offset <= MLXBF_GIGE_PLU_MAX_OFFSET && - ((offset & 0x3) == 0)) { - dev_err(dev, - "PLU MMIO write: offset=0x%llx data=0x%x\n", - offset, data); - writel(data, priv->plu_base + offset); - } else { - dev_err(dev, - "PLU MMIO write: invalid offset 0x%llx\n", - offset); - } - - return len; -} - -DEVICE_ATTR_WO(mmio_read); -DEVICE_ATTR_WO(mmio_write); -DEVICE_ATTR_WO(llu_mmio_read); -DEVICE_ATTR_WO(llu_mmio_write); -DEVICE_ATTR_WO(plu_mmio_read); -DEVICE_ATTR_WO(plu_mmio_write); -#endif /* MLXBF_GIGE_MMIO_SYSFS */ - -static void oob_dump_tx_wqe(struct device *dev, u64 *tx_wqe_addr) -{ - u64 word1, word2; - - /* Sanity check the TX WQE address */ - if (!tx_wqe_addr) - return; - - word1 = *tx_wqe_addr; - word2 = *(tx_wqe_addr + 1); - - /* If TX WQE is empty (i.e. both words are 0) - * then don't bother displaying WQE details - */ - if (word1 == (u64)0 && word2 == (u64)0) { - dev_dbg(dev, "%s(%llx)=%llx %llx", __func__, - (u64)tx_wqe_addr, word1, word2); - } else { - dev_dbg(dev, "%s(%llx)", __func__, - (u64)tx_wqe_addr); - - dev_dbg(dev, " buffer addr: %llx\n", word1); - - dev_dbg(dev, " pkt_len: %llx\n", - ((word2 & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK) - >> MLXBF_GIGE_TX_WQE_PKT_LEN_SHIFT)); - - dev_dbg(dev, " update: %llx\n", - ((word2 & MLXBF_GIGE_TX_WQE_UPDATE_MASK) - >> MLXBF_GIGE_TX_WQE_UPDATE_SHIFT)); - - dev_dbg(dev, " cksum_len: %llx\n", - ((word2 & MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK) - >> MLXBF_GIGE_TX_WQE_CHKSUM_LEN_SHIFT)); - - dev_dbg(dev, " cksum_start: %llx\n", - ((word2 & MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK) - >> MLXBF_GIGE_TX_WQE_CHKSUM_START_SHIFT)); - - dev_dbg(dev, " cksum_offset: %llx\n", - ((word2 & MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK) - >> MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_SHIFT)); - } -} - -/* Handler for sysfs entry 'dump_tx' found at - * /sys/devices/platform/MLNXBF17:00/ - * Issue 'cat dump_tx' to invoke this routine - */ -static ssize_t dump_tx_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mlxbf_gige *priv; - u64 data; - int i; - - priv = dev_get_drvdata(dev); - - dev_dbg(dev, "============================================\n"); - - dev_dbg(dev, "%s: dev_get_drvdata=%llx\n", - __func__, (u64)priv); - - /* Loop through 'n' TX WQE entries */ - for (i = 0; - (priv->netdev->flags & IFF_UP) && (i < priv->tx_q_entries); - i++) { - u8 *p; - - oob_dump_tx_wqe(dev, - (u64 *)((u64)priv->tx_wqe_base + - (i * MLXBF_GIGE_TX_WQE_SZ))); - - p = priv->tx_buf[i]; - dev_dbg(dev, " tx_buf[%d] = %llx\n", i, (u64)priv->tx_buf[i]); - - if (p) { - int j; - - for (j = 0; - j < (MLXBF_GIGE_NUM_BYTES_IN_PKT_DUMP / 16); - j++, p += 16) { - dev_dbg(dev, MLXBF_GIGE_MSG_FORMAT, - MLXBF_GIGE_MSG_ARGS(p)); - } - } - } - - if (priv->netdev->flags & IFF_UP) { - dev_dbg(dev, "tx_cc=%llx *tx_cc=%llx\n", - (u64)priv->tx_cc, *(u64 *)priv->tx_cc); - } - - /* Display TX producer index */ - data = readq(priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); - dev_dbg(dev, "tx_producer_index=%llx\n", (u64)data); - - /* Display TX consumer index */ - data = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); - dev_dbg(dev, "tx_consumer_index=%llx\n", (u64)data); - - /* Display TX status */ - data = readq(priv->base + MLXBF_GIGE_TX_STATUS); - dev_dbg(dev, "tx_status=%llx\n", (u64)data); - - /* Display TX FIFO status */ - data = readq(priv->base + MLXBF_GIGE_TX_FIFOS_STATUS); - dev_dbg(dev, "tx_fifos_status=%llx\n", (u64)data); - - return strlen(buf); -} - -DEVICE_ATTR_RO(dump_tx); - -static void oob_dump_rx_wqe(struct device *dev, u64 *rx_wqe_addr) -{ - /* Sanity check the RX WQE address */ - if (!rx_wqe_addr) - return; - - dev_dbg(dev, "%s(%llx)=%llx\n", __func__, - (u64)rx_wqe_addr, *rx_wqe_addr); -} - -static void oob_dump_rx_cqe(struct device *dev, u64 *rx_cqe_addr) -{ - u64 rx_cqe; - - /* Sanity check the RX CQE address */ - if (!rx_cqe_addr) - return; - - rx_cqe = *rx_cqe_addr; - - /* If RX CQE is empty (i.e. value is 0) then - * don't bother displaying CQE details - */ - if (rx_cqe == (u64)0) { - dev_dbg(dev, "%s(%llx)=%llx", __func__, - (u64)rx_cqe_addr, rx_cqe); - } else { - dev_dbg(dev, "%s(%llx)", __func__, - (u64)rx_cqe_addr); - - dev_dbg(dev, " pkt_len: %llx\n", - (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK)); - - dev_dbg(dev, " valid: %llx\n", - ((rx_cqe & MLXBF_GIGE_RX_CQE_VALID_MASK) - >> MLXBF_GIGE_RX_CQE_VALID_SHIFT)); - - dev_dbg(dev, " pkt_status: %llx\n", - ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) - >> MLXBF_GIGE_RX_CQE_PKT_STATUS_SHIFT)); - - dev_dbg(dev, " chksum: %llx\n", - ((rx_cqe & MLXBF_GIGE_RX_CQE_CHKSUM_MASK) - >> MLXBF_GIGE_RX_CQE_CHKSUM_SHIFT)); - } -} - -/* Handler for sysfs entry 'dump_rx' found at - * /sys/devices/platform/MLNXBF17:00/ - * Issue 'cat dump_rx' to invoke this routine - */ -static ssize_t dump_rx_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct mlxbf_gige *priv; - u64 data; - int i; - - priv = dev_get_drvdata(dev); - - dev_dbg(dev, "============================================\n"); - dev_dbg(dev, "%s: dev_get_drvdata=%llx\n", __func__, (u64)priv); - - /* Loop through 'n' RX WQE entries */ - for (i = 0; - (priv->netdev->flags & IFF_UP) && (i < priv->rx_q_entries); - i++) { - u8 *p; - - oob_dump_rx_wqe(dev, priv->rx_wqe_base + i); - - p = priv->rx_buf[i]; - dev_dbg(dev, " rx_buf[%d] = %llx\n", i, (u64)priv->rx_buf[i]); - - /* Only display RX buffer contents if not in initial state */ - if (p && (*p != MLXBF_GIGE_INIT_BYTE_RX_BUF)) { - int j; - - for (j = 0; - j < (MLXBF_GIGE_NUM_BYTES_IN_PKT_DUMP / 16); - j++, p += 16) { - dev_dbg(dev, MLXBF_GIGE_MSG_FORMAT, - MLXBF_GIGE_MSG_ARGS(p)); - } - } - } - - /* Loop through 'n' RX CQE entries */ - for (i = 0; - (priv->netdev->flags & IFF_UP) && (i < priv->rx_q_entries); - i++) { - oob_dump_rx_cqe(dev, priv->rx_cqe_base + i); - } - - /* Display RX WQE producer index */ - data = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); - dev_dbg(dev, "rx_wqe_pi=%llx\n", (u64)data); - - /* Display INT_STATUS */ - data = readq(priv->base + MLXBF_GIGE_INT_STATUS); - dev_dbg(dev, "int_status=%llx\n", (u64)data); - - /* Then, clear INT_STATUS */ - data = 0x1FF; - writeq(data, priv->base + MLXBF_GIGE_INT_STATUS); - - /* Display RX_DIN_DROP_COUNTER */ - data = readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); - dev_dbg(dev, "rx_din_drop_counter=%llx\n", (u64)data); - - /* Display INT_STATUS_EXP */ - data = readq(priv->base + MLXBF_GIGE_INT_STATUS_EXP); - dev_dbg(dev, "int_status_exp=%llx\n", (u64)data); - - /* Then, clear INT_STATUS_EXP */ - data = 0; - writeq(data, priv->base + MLXBF_GIGE_INT_STATUS_EXP); - - /* Display RX_MAC_FILTER_PASS_COUNTER_ALL */ - data = readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL); - dev_dbg(dev, "rx_mac_filter_pass_counter_all=%llx\n", (u64)data); - - /* Display RX_MAC_FILTER_DISC_COUNTER_ALL */ - data = readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL); - dev_dbg(dev, "rx_mac_filter_disc_counter_all=%llx\n", (u64)data); - - /* Display first word of RX_MAC_FILTER */ - data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER); - dev_dbg(dev, "rx_mac_filter0=%llx\n", (u64)data); - - /* Display second word of RX_MAC_FILTER */ - data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER + 0x8); - dev_dbg(dev, "rx_mac_filter1=%llx\n", (u64)data); - - /* Display third word of RX_MAC_FILTER */ - data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER + 0x10); - dev_dbg(dev, "rx_mac_filter2=%llx\n", (u64)data); - - /* Display fourth word of RX_MAC_FILTER */ - data = readq(priv->base + MLXBF_GIGE_RX_MAC_FILTER + 0x18); - dev_dbg(dev, "rx_mac_filter3=%llx\n", (u64)data); - - /* Display MLXBF_GIGE_RX_CQE_PACKET_CI */ - data = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); - dev_dbg(dev, "MLXBF_GIGE_RX_CQE_PACKET_CI=%llx\n", (u64)data); - - dev_dbg(dev, "error_intr_count=%llx\n", priv->error_intr_count); - dev_dbg(dev, "rx_intr_count=%llx\n", priv->rx_intr_count); - dev_dbg(dev, "llu_plu_intr_count=%llx\n", priv->llu_plu_intr_count); - - /* Display INT_EN */ - data = readq(priv->base + MLXBF_GIGE_INT_EN); - dev_dbg(dev, "int_en=%llx\n", (u64)data); - - /* Display INT_MASK */ - data = readq(priv->base + MLXBF_GIGE_INT_MASK); - dev_dbg(dev, "int_mask=%llx\n", (u64)data); - - return strlen(buf); -} - -DEVICE_ATTR_RO(dump_rx); - -/* Handler for sysfs entry 'start_tx' found at - * /sys/devices/platform/MLNXBF17:00/ - * Issue 'echo > start_tx' to invoke this routine - * which will send dummy IP packets to GigE port - */ -static ssize_t start_tx_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - struct mlxbf_gige *priv; - dma_addr_t tx_buf_dma; - u8 oob_tx_data_seed; - int oob_tx_pkt_size; - long num_pkts = 1; - u64 *tx_wqe_addr; - u8 *tx_buf; - u16 data16; - u64 word2; - int i, j; - int ret; - - priv = dev_get_drvdata(dev); - - oob_tx_pkt_size = MLXBF_GIGE_DEFAULT_TX_PKT_SIZE; - - if (buf) { - ret = kstrtol(buf, 10, &num_pkts); - - if (ret == 0) { - dev_dbg(dev, "%s: num_pkts %d\n", - __func__, (int)num_pkts); - } - } - - for (i = 0; i < num_pkts; i++) { - /* The data seed is used to populate the packet with - * fake, but predictable, data. The value of seed - * is stored in the first byte after the L2 header, - * then (seed+1) is stored in the second byte, etc. - */ - oob_tx_data_seed = priv->tx_data_seed; - priv->tx_data_seed += 4; - - /* To limit output only perform debug logging if number - * of packets to send is less than some maximum value. - */ - if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { - dev_dbg(dev, "%s: size=%x seed=%x\n", - __func__, oob_tx_pkt_size, - oob_tx_data_seed); - } - - /* Allocate ptr for buffer */ - tx_buf = dma_alloc_coherent(dev, MLXBF_GIGE_DEFAULT_BUF_SZ, - &tx_buf_dma, GFP_KERNEL); - - if (!tx_buf) - return -ENOMEM; - - if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { - dev_dbg(dev, "%s: tx_buf %llx %llx\n", - __func__, (u64)tx_buf, (u64)tx_buf_dma); - } - - if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { - dev_dbg(dev, "%s: pkt num %llx buffer index %x\n", - __func__, (u64)priv->tx_pi, - (priv->tx_pi % priv->tx_q_entries)); - } - - priv->tx_buf[priv->tx_pi % priv->tx_q_entries] = tx_buf; - - /* Put in four bytes of fake destination MAC, but use real - * value of 'tx_pi' in order to track TX producer index - * in the actual packet contents. - */ - *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_DMAC_BYTE; - *tx_buf++ = (priv->tx_pi & 0xFF00) >> 8; - *tx_buf++ = (priv->tx_pi & 0xFF); - - /* Put in fake source MAC */ - *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; - *tx_buf++ = MLXBF_GIGE_FAKE_SMAC_BYTE; - - /* Set ethertype for IP (0x0800) */ - *tx_buf++ = 0x08; - *tx_buf++ = 0x00; - - /* Put in fake packet payload */ - for (j = 0; j < (oob_tx_pkt_size - ETH_HLEN); j++) - *tx_buf++ = (u8)(j + oob_tx_data_seed); - - /* TODO - should really reorganize all low-level TX */ - /* logic and call it here and in 'xmit' function also */ - - /* Get address of TX WQE */ - tx_wqe_addr = priv->tx_wqe_next; - - if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { - dev_dbg(dev, "%s: tx_wqe_addr=%llx\n", - __func__, (u64)tx_wqe_addr); - } - - mlxbf_gige_update_tx_wqe_next(priv); - - if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { - dev_dbg(dev, "%s: tx_wqe_next=%llx\n", - __func__, (u64)priv->tx_wqe_next); - } - - /* Put PA of buffer address into first 64-bit word of TX WQE */ - *tx_wqe_addr = tx_buf_dma; - - /* Set TX WQE pkt_len appropriately */ - word2 = oob_tx_pkt_size & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; - - if (num_pkts < MLXBF_GIGE_MAX_TX_PKTS_VERBOSE) { - dev_dbg(dev, "%s: word2=%llx\n", - __func__, (u64)word2); - } - - /* Write entire 2nd word of TX WQE */ - *(tx_wqe_addr + 1) = word2; - - /* Create memory barrier before write to TX PI */ - wmb(); - - priv->tx_pi++; - - writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); - - if (priv->tx_pi >= 0x20) { - data16 = readq(priv->base + MLXBF_GIGE_RX_WQE_PI) + 1; - writeq(data16, priv->base + MLXBF_GIGE_RX_WQE_PI); - } - } /* end - i loop */ - - return len; -} - -DEVICE_ATTR_WO(start_tx); - -void mlxbf_gige_create_sysfs(struct device *dev) -{ -#ifdef MLXBF_GIGE_MMIO_SYSFS - if (device_create_file(dev, &dev_attr_mmio_read)) - dev_info(dev, "failed to create mmio_read sysfs entry\n"); - if (device_create_file(dev, &dev_attr_mmio_write)) - dev_info(dev, "failed to create mmio_write sysfs entry\n"); - if (device_create_file(dev, &dev_attr_llu_mmio_read)) - dev_info(dev, "failed to create llu_mmio_read sysfs entry\n"); - if (device_create_file(dev, &dev_attr_llu_mmio_write)) - dev_info(dev, "failed to create llu_mmio_write sysfs entry\n"); - if (device_create_file(dev, &dev_attr_plu_mmio_read)) - dev_info(dev, "failed to create plu_mmio_read sysfs entry\n"); - if (device_create_file(dev, &dev_attr_plu_mmio_write)) - dev_info(dev, "failed to create plu_mmio_write sysfs entry\n"); -#endif - - if (device_create_file(dev, &dev_attr_dump_rx)) - dev_info(dev, "failed to create dump_rx sysfs entry\n"); - if (device_create_file(dev, &dev_attr_dump_tx)) - dev_info(dev, "failed to create dump_tx sysfs entry\n"); - if (device_create_file(dev, &dev_attr_start_tx)) - dev_info(dev, "failed to create start_tx sysfs entry\n"); -} - -void mlxbf_gige_remove_sysfs(struct device *dev) -{ -#ifdef MLXBF_GIGE_MMIO_SYSFS - device_remove_file(dev, &dev_attr_mmio_read); - device_remove_file(dev, &dev_attr_mmio_write); - device_remove_file(dev, &dev_attr_llu_mmio_read); - device_remove_file(dev, &dev_attr_llu_mmio_write); - device_remove_file(dev, &dev_attr_plu_mmio_read); - device_remove_file(dev, &dev_attr_plu_mmio_write); -#endif - - device_remove_file(dev, &dev_attr_dump_rx); - device_remove_file(dev, &dev_attr_dump_tx); - device_remove_file(dev, &dev_attr_start_tx); -} -#endif /* MLXBF_GIGE_INTERNAL */ - -static u64 mlxbf_gige_mac_to_u64(u8 *addr) -{ - u64 mac = 0; - int i; - - for (i = 0; i < ETH_ALEN; i++) { - mac <<= 8; - mac |= addr[i]; - } - return mac; -} - -static void mlxbf_gige_u64_to_mac(u8 *addr, u64 mac) -{ - int i; - - for (i = ETH_ALEN; i > 0; i--) { - addr[i - 1] = mac & 0xFF; - mac >>= 8; - } -} - -static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) -{ - u8 mac[ETH_ALEN]; - u64 local_mac; - int status; - - status = mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, - &local_mac); - mlxbf_gige_u64_to_mac(mac, local_mac); - - if (is_valid_ether_addr(mac)) { - ether_addr_copy(priv->netdev->dev_addr, mac); -#ifdef MLXBF_GIGE_INTERNAL - dev_info(priv->dev, "Read MAC address %pM from chip\n", mac); -#endif - } else { - /* Provide a random MAC if for some reason the device has - * not been configured with a valid MAC address already. - */ - eth_hw_addr_random(priv->netdev); -#ifdef MLXBF_GIGE_INTERNAL - dev_info(priv->dev, "Generated random MAC address %pM\n", - priv->netdev->dev_addr); -#endif - } - - local_mac = mlxbf_gige_mac_to_u64(priv->netdev->dev_addr); - mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, - local_mac); -} - -static int mlxbf_gige_probe(struct platform_device *pdev) -{ - struct net_device *netdev; - struct resource *mac_res; - struct resource *llu_res; - struct resource *plu_res; - struct mlxbf_gige *priv; - void __iomem *llu_base; - void __iomem *plu_base; - void __iomem *base; - u64 control; - int err = 0; - -#ifdef MLXBF_GIGE_INTERNAL - u64 exp_data; - - dev_dbg(&pdev->dev, "probe: pdev=0x%llx pdev->dev=0x%llx\n", - (u64)pdev, (u64)&pdev->dev); -#endif - - mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); - if (!mac_res) - return -ENXIO; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "probe: resource %d (MAC) start=0x%llx end=0x%llx\n", - MLXBF_GIGE_RES_MAC, mac_res->start, mac_res->end); -#endif - - base = devm_ioremap_resource(&pdev->dev, mac_res); - if (IS_ERR(base)) - return PTR_ERR(base); - - llu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_LLU); - if (!llu_res) - return -ENXIO; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "probe: resource %d (LLU) start=0x%llx end=0x%llx\n", - MLXBF_GIGE_RES_LLU, llu_res->start, llu_res->end); -#endif - - llu_base = devm_ioremap_resource(&pdev->dev, llu_res); - if (IS_ERR(llu_base)) - return PTR_ERR(llu_base); - - plu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_PLU); - if (!plu_res) - return -ENXIO; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "probe: resource %d (PLU) start=0x%llx end=0x%llx\n", - MLXBF_GIGE_RES_PLU, plu_res->start, plu_res->end); -#endif - - plu_base = devm_ioremap_resource(&pdev->dev, plu_res); - if (IS_ERR(plu_base)) - return PTR_ERR(plu_base); - -#ifdef MLXBF_GIGE_INTERNAL - /* Read single MMIO register and compare to expected value */ - exp_data = (MLXBF_GIGE_CONFIG_MAX_PKT_SZ_RESET_VAL - << MLXBF_GIGE_CONFIG_MAX_PKT_SZ_SHIFT); - if (readq(base + MLXBF_GIGE_CONFIG) != exp_data) { - dev_err(&pdev->dev, - "probe failed, unexpected value in MLXBF_GIGE_CONFIG\n"); - return -ENODEV; - } -#endif - - /* Perform general init of GigE block */ - control = readq(base + MLXBF_GIGE_CONTROL); - control |= MLXBF_GIGE_CONTROL_PORT_EN; - writeq(control, base + MLXBF_GIGE_CONTROL); - - netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv)); - if (!netdev) { -#ifdef MLXBF_GIGE_INTERNAL - dev_err(&pdev->dev, "Failed to allocate etherdev\n"); -#endif - return -ENOMEM; - } - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "probe: netdev=%llx\n", (u64)netdev); -#endif - - SET_NETDEV_DEV(netdev, &pdev->dev); - netdev->netdev_ops = &mlxbf_gige_netdev_ops; - netdev->ethtool_ops = &mlxbf_gige_ethtool_ops; - priv = netdev_priv(netdev); - priv->netdev = netdev; - - /* Initialize feature set supported by hardware (skbuff.h) */ - netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_HW_CSUM; - - platform_set_drvdata(pdev, priv); - priv->dev = &pdev->dev; - priv->pdev = pdev; - -#ifdef FAST_MODELS - /* - * TODO: Palladium has no connection to the PHY hardware, so - * the MDIO probe will fail. - * This needs to be removed once palladium provides a connection - * to the PHY device. - */ - - /* Attach MDIO device */ - err = mlxbf_gige_mdio_probe(pdev, priv); - if (err) - return err; -#endif /* FAST_MODELS */ - - priv->base = base; - priv->llu_base = llu_base; - priv->plu_base = plu_base; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "probe: priv=0x%llx priv->base=0x%llx\n", - (u64)priv, (u64)priv->base); - dev_dbg(&pdev->dev, "probe: llu_base=0x%llx plu_base=0x%llx\n", - (u64)priv->llu_base, (u64)priv->plu_base); - - /* Perform some self tests on MAC, PLU, LLU */ - mlxbf_gige_selftests(pdev, priv); - mlxbf_gige_plu_selftests(pdev, priv); - mlxbf_gige_llu_selftests(pdev, priv); -#endif - - priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ; - priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ; - - /* Write initial MAC address to hardware */ - mlxbf_gige_initial_mac(priv); - -#ifdef MLXBF_GIGE_INTERNAL - /* Create sysfs entries for driver */ - mlxbf_gige_create_sysfs(&pdev->dev); -#endif - - err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); - if (err) { - dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); - return err; - } - - priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX); - priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); - priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "probe: irq[] = %d %d %d\n", - priv->error_irq, priv->rx_irq, priv->llu_plu_irq); -#endif - - err = register_netdev(netdev); - if (err) { - dev_err(&pdev->dev, "Failed to register netdev\n"); - return err; - } - -#ifdef MLXBF_GIGE_INTERNAL - dev_info(&pdev->dev, "probed\n"); - - priv->tx_data_seed = 0xB0; -#endif - - return 0; -} - -/* Device remove function. */ -static int mlxbf_gige_remove(struct platform_device *pdev) -{ - struct mlxbf_gige *priv; - -#ifdef MLXBF_GIGE_INTERNAL - dev_dbg(&pdev->dev, "remove: pdev=%llx\n", (u64)pdev); -#endif - - priv = platform_get_drvdata(pdev); - - unregister_netdev(priv->netdev); - -#ifdef MLXBF_GIGE_INTERNAL - /* Remove driver sysfs entries */ - mlxbf_gige_remove_sysfs(&pdev->dev); -#endif - -#ifdef FAST_MODELS - /* Remove mdio */ - mlxbf_gige_mdio_remove(priv); -#endif /* FAST_MODELS */ - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static const struct acpi_device_id mlxbf_gige_acpi_match[] = { - { "MLNXBF17", 0 }, - {}, -}; -MODULE_DEVICE_TABLE(acpi, mlxbf_gige_acpi_match); - -static struct platform_driver mlxbf_gige_driver = { - .probe = mlxbf_gige_probe, - .remove = mlxbf_gige_remove, - .driver = { - .name = DRV_NAME, - .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match), - }, -}; - -module_platform_driver(mlxbf_gige_driver); - -MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); -MODULE_AUTHOR("David Thompson "); -MODULE_AUTHOR("Asmaa Mnebhi "); -MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c deleted file mode 100644 index 2a1362698cb6..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c +++ /dev/null @@ -1,397 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB -/* MDIO support for Mellanox GigE driver - * - * Copyright (C) 2020 Mellanox Technologies, Ltd. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mlxbf_gige.h" - -#define MLXBF_GIGE_DEFAULT_PHY_ADDR 0x3 - -#define MLXBF_GIGE_POLL_BUSY_TIMEOUT 100 /* ms */ -#define MLXBF_GIGE_POLL_DELAY_USEC 100 /* microsec */ - -#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 -#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 - -/* Support clause 22 */ -#define MLXBF_GIGE_CL22_ST1 0x1 -#define MLXBF_GIGE_CL22_MDIO_WRITE 0x1 -#define MLXBF_GIGE_CL22_MDIO_READ 0x2 - -/* Busy bit is set by software and cleared by hardware */ -#define MLXBF_GIGE_SET_MDIO_BUSY 0x1 -/* Lock bit should be set/cleared by software */ -#define MLXBF_GIGE_SET_MDIO_LOCK 0x1 - -/* MDIO GW register bits */ -#define MLXBF_GIGE_MDIO_GW_AD_SHIFT 0 -#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) -#define MLXBF_GIGE_MDIO_GW_DEVAD_SHIFT 16 -#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) -#define MLXBF_GIGE_MDIO_GW_PARTAD_SHIFT 21 -#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) -#define MLXBF_GIGE_MDIO_GW_OPCODE_SHIFT 26 -#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) -#define MLXBF_GIGE_MDIO_GW_ST1_SHIFT 28 -#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) -#define MLXBF_GIGE_MDIO_GW_BUSY_SHIFT 30 -#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) -#define MLXBF_GIGE_MDIO_GW_LOCK_SHIFT 31 -#define MLXBF_GIGE_MDIO_GW_LOCK_MASK GENMASK(31, 31) - -/* MDIO config register bits */ -#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_SHIFT 0 -#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_SHIFT 2 -#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_SHIFT 4 -#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_SHIFT 8 -#define MLXBF_GIGE_MDIO_CFG_MASTER_IN_SAMP_SHIFT 16 -#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_SHIFT 24 - -/* Formula for encoding the MDIO period. The encoded value is - * passed to the MDIO config register. - * - * mdc_clk = 2*(val + 1)*i1clk - * - * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) - * - * val = (((400 * 430 / 1000) / 2) - 1) - */ -#define MLXBF_GIGE_I1CLK_MHZ 430 -#define MLXBF_GIGE_MDC_CLK_NS 400 - -#define MLXBF_GIGE_MDIO_PERIOD_VAL (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) -#define MLXBF_GIGE_MDIO_PERIOD (MLXBF_GIGE_MDIO_PERIOD_VAL << MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_SHIFT) - -/* PHY should operate in master mode only */ -#define MLXBF_GIGE_MDIO_MODE_MASTER (0x1 << MLXBF_GIGE_MDIO_CFG_MDIO_MODE_SHIFT) -/* PHY input voltage has to be 3.3V */ -#define MLXBF_GIGE_MDIO3_3 (0x1 << MLXBF_GIGE_MDIO_CFG_MDIO3_3_SHIFT) -/* Operate in full drive mode */ -#define MLXBF_GIGE_MDIO_FULL_DRIVE (0x1 << MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_SHIFT) -/* 6 cycles before the i1clk (core clock) rising edge that triggers the mdc */ -#define MLXBF_GIGE_MDIO_MASTER_IN_SAMP (6 << MLXBF_GIGE_MDIO_CFG_MASTER_IN_SAMP_SHIFT) -/* 13 cycles after the i1clk (core clock) rising edge that triggers the mdc */ -#define MLXBF_GIGE_MDIO_MDIO_OUT_SAMP (13 << MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_SHIFT) - -#define MLXBF_GIGE_MDIO_CFG_VAL (MLXBF_GIGE_MDIO_MODE_MASTER | \ - MLXBF_GIGE_MDIO3_3 | \ - MLXBF_GIGE_MDIO_FULL_DRIVE | \ - MLXBF_GIGE_MDIO_PERIOD | \ - MLXBF_GIGE_MDIO_MASTER_IN_SAMP | \ - MLXBF_GIGE_MDIO_MDIO_OUT_SAMP) - -/* The PHY interrupt line is shared with other interrupt lines such - * as GPIO and SMBus. So use YU registers to determine whether the - * interrupt comes from the PHY. - */ -#define MLXBF_GIGE_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK 0x10 -#define MLXBF_GIGE_GPIO_CAUSE_IRQ_IS_SET(val) \ - ((val) & MLXBF_GIGE_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK) - -#define MLXBF_GIGE_GPIO_BLOCK0_MASK BIT(0) - -#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48 -#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 -#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94 -#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 - -#define MLXBF_GIGE_GPIO12_BIT 12 -#define MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) -#define MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK BIT(MLXBF_GIGE_GPIO12_BIT) -#define MLXBF_GIGE_CAUSE_FALL_EN_MASK BIT(MLXBF_GIGE_GPIO12_BIT) -#define MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK BIT(MLXBF_GIGE_GPIO12_BIT) - -static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, - int phy_reg, u32 opcode) -{ - u32 gw_reg = 0; - - gw_reg |= (data << MLXBF_GIGE_MDIO_GW_AD_SHIFT) & - MLXBF_GIGE_MDIO_GW_AD_MASK; - gw_reg |= ((phy_reg << MLXBF_GIGE_MDIO_GW_DEVAD_SHIFT) & - MLXBF_GIGE_MDIO_GW_DEVAD_MASK); - gw_reg |= ((phy_add << MLXBF_GIGE_MDIO_GW_PARTAD_SHIFT) & - MLXBF_GIGE_MDIO_GW_PARTAD_MASK); - gw_reg |= ((opcode << MLXBF_GIGE_MDIO_GW_OPCODE_SHIFT) & - MLXBF_GIGE_MDIO_GW_OPCODE_MASK); - gw_reg |= ((MLXBF_GIGE_CL22_ST1 << MLXBF_GIGE_MDIO_GW_ST1_SHIFT) & - MLXBF_GIGE_MDIO_GW_ST1_MASK); - gw_reg |= ((MLXBF_GIGE_SET_MDIO_BUSY << MLXBF_GIGE_MDIO_GW_BUSY_SHIFT) & - MLXBF_GIGE_MDIO_GW_BUSY_MASK); - - /* Hold the lock until the read/write is completed so that no other - * program accesses the mdio bus. - */ - gw_reg |= ((MLXBF_GIGE_SET_MDIO_LOCK << MLXBF_GIGE_MDIO_GW_LOCK_SHIFT) & - MLXBF_GIGE_MDIO_GW_LOCK_MASK); - - return gw_reg; -} - -static int mlxbf_gige_mdio_poll_bit(struct mlxbf_gige *priv, u32 bit_mask) -{ - unsigned long timeout; - u32 val; - - timeout = jiffies + msecs_to_jiffies(MLXBF_GIGE_POLL_BUSY_TIMEOUT); - do { - val = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - if (!(val & bit_mask)) - return 0; - udelay(MLXBF_GIGE_POLL_DELAY_USEC); - } while (time_before(jiffies, timeout)); - - return -ETIME; -} - -static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) -{ - struct mlxbf_gige *priv = bus->priv; - u32 cmd; - u32 ret; - - /* If the lock is held by something else, drop the request. - * If the lock is cleared, that means the busy bit was cleared. - */ - ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_LOCK_MASK); - if (ret) - return -EBUSY; - - /* Send mdio read request */ - cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_CL22_MDIO_READ); - - writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - - ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_BUSY_MASK); - if (ret) { - writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - return -EBUSY; - } - - ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - /* Only return ad bits of the gw register */ - ret &= MLXBF_GIGE_MDIO_GW_AD_MASK; - - /* To release the YU MDIO lock, clear gw register, - * so that the YU does not confuse this write with a new - * MDIO read/write request. - */ - writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - - return ret; -} - -static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, - int phy_reg, u16 val) -{ - struct mlxbf_gige *priv = bus->priv; - u32 cmd; - int ret; - - /* If the lock is held by something else, drop the request. - * If the lock is cleared, that means the busy bit was cleared. - */ - ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_LOCK_MASK); - if (ret) - return -EBUSY; - - /* Send mdio write request */ - cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg, - MLXBF_GIGE_CL22_MDIO_WRITE); - writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - - /* If the poll timed out, drop the request */ - ret = mlxbf_gige_mdio_poll_bit(priv, MLXBF_GIGE_MDIO_GW_BUSY_MASK); - - /* To release the YU MDIO lock, clear gw register, - * so that the YU does not confuse this write as a new - * MDIO read/write request. - */ - writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); - - return ret; -} - -static void mlxbf_gige_mdio_disable_gpio12_irq(struct mlxbf_gige *priv) -{ - u32 val; - - spin_lock(&priv->gpio_lock); - val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val &= ~MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; - writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - spin_unlock(&priv->gpio_lock); -} - -static void mlxbf_gige_mdio_enable_gpio12_irq(struct mlxbf_gige *priv) -{ - u32 val; - - spin_lock(&priv->gpio_lock); - /* The INT_N interrupt level is active low. - * So enable cause fall bit to detect when GPIO - * state goes low. - */ - val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); - val |= MLXBF_GIGE_CAUSE_FALL_EN_MASK; - writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); - - /* Enable GPIO 12 interrupt by setting the priority level */ - val = readl(priv->gpio_io + - MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - val |= MLXBF_GIGE_CAUSE_OR_EVTEN0_MASK; - writel(val, priv->gpio_io + - MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); - spin_unlock(&priv->gpio_lock); -} - -/* Interrupt handler is called from mlxbf_gige_main.c - * driver whenever a phy interrupt is received. - */ -irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(struct mlxbf_gige *priv) -{ - u32 val; - - /* The YU interrupt is shared between SMBus and GPIOs. - * So first, determine whether this is a GPIO interrupt. - */ - val = readl(priv->cause_rsh_coalesce0_io); - if (!MLXBF_GIGE_GPIO_CAUSE_IRQ_IS_SET(val)) { - /* Nothing to do here, not a GPIO interrupt */ - return IRQ_NONE; - } - /* Then determine which gpio register this interrupt is for. - * Return if the interrupt is not for gpio block 0. - */ - val = readl(priv->cause_gpio_arm_coalesce0_io); - if (!(val & MLXBF_GIGE_GPIO_BLOCK0_MASK)) - return IRQ_NONE; - - /* Finally check if this interrupt is for gpio pin 12. - * Return if it is not. - */ - val = readl(priv->gpio_io + - MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); - if (!(val & MLXBF_GIGE_CAUSE_OR_CAUSE_EVTEN0_MASK)) - return IRQ_NONE; - - /* Clear interrupt when done, otherwise, no further interrupt - * will be triggered. - * Writing 0x1 to the clrcause register also clears the - * following registers: - * cause_gpio_arm_coalesce0 - * cause_rsh_coalesce0 - */ - val = readl(priv->gpio_io + - MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); - val |= MLXBF_GIGE_CAUSE_OR_CLRCAUSE_MASK; - writel(val, priv->gpio_io + - MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); - - return IRQ_HANDLED; -} - -int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) -{ - struct device *dev = &pdev->dev; - struct resource *res; - u32 phy_addr; - int ret; - int irq; - - res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); - if (!res) - return -ENODEV; - - priv->mdio_io = devm_ioremap_resource(dev, res); - if (IS_ERR(priv->mdio_io)) - return PTR_ERR(priv->mdio_io); - - res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0); - if (!res) - return -ENODEV; - - priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); - if (!priv->gpio_io) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, - MLXBF_GIGE_RES_CAUSE_RSH_COALESCE0); - if (!res) - return -ENODEV; - - priv->cause_rsh_coalesce0_io = - devm_ioremap(dev, res->start, resource_size(res)); - if (!priv->cause_rsh_coalesce0_io) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, - MLXBF_GIGE_RES_CAUSE_GPIO_ARM_COALESCE0); - if (!res) - return -ENODEV; - - priv->cause_gpio_arm_coalesce0_io = - devm_ioremap(dev, res->start, resource_size(res)); - if (!priv->cause_gpio_arm_coalesce0_io) - return -ENOMEM; - - /* Configure mdio parameters */ - writel(MLXBF_GIGE_MDIO_CFG_VAL, - priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); - - mlxbf_gige_mdio_enable_gpio12_irq(priv); - - priv->mdiobus = devm_mdiobus_alloc(dev); - if (!priv->mdiobus) { - dev_err(dev, "Failed to alloc MDIO bus\n"); - return -ENOMEM; - } - - priv->mdiobus->name = "mlxbf-mdio"; - priv->mdiobus->read = mlxbf_gige_mdio_read; - priv->mdiobus->write = mlxbf_gige_mdio_write; - priv->mdiobus->parent = dev; - priv->mdiobus->priv = priv; - snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s", - dev_name(dev)); - - ret = device_property_read_u32(dev, "phy-addr", &phy_addr); - if (ret < 0) - phy_addr = MLXBF_GIGE_DEFAULT_PHY_ADDR; - - irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); - if (irq < 0) { - dev_err(dev, "Failed to retrieve irq\n"); - return -ENODEV; - } - priv->mdiobus->irq[phy_addr] = irq; - - /* Auto probe PHY at the corresponding address */ - priv->mdiobus->phy_mask = ~(1 << phy_addr); - ret = mdiobus_register(priv->mdiobus); - if (ret) - dev_err(dev, "Failed to register MDIO bus\n"); - - return ret; -} - -void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv) -{ - mlxbf_gige_mdio_disable_gpio12_irq(priv); - mdiobus_unregister(priv->mdiobus); -} diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h deleted file mode 100644 index 4aeb6e45579e..000000000000 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only OR Linux-OpenIB */ - -/* Header file for Mellanox BlueField GigE register defines - * - * Copyright (c) 2020, Mellanox Technologies - */ - -#ifndef __MLXBF_GIGE_REGS_H__ -#define __MLXBF_GIGE_REGS_H__ - -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_CONFIG 0x0008 -#define MLXBF_GIGE_CONFIG_MAX_PKT_SZ_SHIFT 16 -#define MLXBF_GIGE_CONFIG_MAX_PKT_SZ_RESET_VAL 1522 -#endif /* MLXBF_GIGE_INTERNAL */ -#define MLXBF_GIGE_STATUS 0x0010 -#define MLXBF_GIGE_STATUS_READY BIT(0) -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_SCRATCHPAD 0x0020 -#endif /* MLXBF_GIGE_INTERNAL */ -#define MLXBF_GIGE_INT_STATUS 0x0028 -#define MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET BIT(0) -#define MLXBF_GIGE_INT_STATUS_RX_MAC_ERROR BIT(1) -#define MLXBF_GIGE_INT_STATUS_RX_TRN_ERROR BIT(2) -#define MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR BIT(3) -#define MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR BIT(4) -#define MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE BIT(5) -#define MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE BIT(6) -#define MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS BIT(7) -#define MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR BIT(8) -#define MLXBF_GIGE_INT_EN 0x0030 -#define MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET BIT(0) -#define MLXBF_GIGE_INT_EN_RX_MAC_ERROR BIT(1) -#define MLXBF_GIGE_INT_EN_RX_TRN_ERROR BIT(2) -#define MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR BIT(3) -#define MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR BIT(4) -#define MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE BIT(5) -#define MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE BIT(6) -#define MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS BIT(7) -#define MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR BIT(8) -#define MLXBF_GIGE_INT_MASK 0x0038 -#define MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET BIT(0) -#define MLXBF_GIGE_CONTROL 0x0040 -#define MLXBF_GIGE_CONTROL_PORT_EN BIT(0) -#define MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN BIT(1) -#define MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC BIT(4) -#define MLXBF_GIGE_CONTROL_CLEAN_PORT_EN BIT(31) -#define MLXBF_GIGE_RX_WQ_BASE 0x0200 -#define MLXBF_GIGE_RX_WQE_SIZE_LOG2 0x0208 -#define MLXBF_GIGE_RX_WQE_SIZE_LOG2_RESET_VAL 7 -#define MLXBF_GIGE_RX_CQ_BASE 0x0210 -#define MLXBF_GIGE_TX_WQ_BASE 0x0218 -#define MLXBF_GIGE_TX_WQ_SIZE_LOG2 0x0220 -#define MLXBF_GIGE_TX_WQ_SIZE_LOG2_RESET_VAL 7 -#define MLXBF_GIGE_TX_CI_UPDATE_ADDRESS 0x0228 -#define MLXBF_GIGE_RX_WQE_PI 0x0230 -#define MLXBF_GIGE_TX_PRODUCER_INDEX 0x0238 -#define MLXBF_GIGE_RX_MAC_FILTER 0x0240 -#define MLXBF_GIGE_RX_MAC_FILTER_STRIDE 0x0008 -#define MLXBF_GIGE_RX_DIN_DROP_COUNTER 0x0260 -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_INT_STATUS_EXP 0x0308 -#endif /* MLXBF_GIGE_INTERNAL */ -#define MLXBF_GIGE_TX_CONSUMER_INDEX 0x0310 -#define MLXBF_GIGE_TX_CONTROL 0x0318 -#define MLXBF_GIGE_TX_CONTROL_GRACEFUL_STOP BIT(0) -#define MLXBF_GIGE_TX_STATUS 0x0388 -#define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1) -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_TX_FIFOS_STATUS 0x0390 -#endif /* MLXBF_GIGE_INTERNAL */ -#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520 -#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528 -#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540 -#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN BIT(0) -#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS 0x0548 -#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN BIT(0) -#define MLXBF_GIGE_RX_PASS_COUNTER_ALL 0x0550 -#define MLXBF_GIGE_RX_DISC_COUNTER_ALL 0x0560 -#define MLXBF_GIGE_RX 0x0578 -#define MLXBF_GIGE_RX_STRIP_CRC_EN BIT(1) -#define MLXBF_GIGE_RX_DMA 0x0580 -#define MLXBF_GIGE_RX_DMA_EN BIT(0) -#define MLXBF_GIGE_RX_CQE_PACKET_CI 0x05b0 -#define MLXBF_GIGE_MAC_CFG 0x05e8 -#ifdef MLXBF_GIGE_INTERNAL -#define MLXBF_GIGE_LLU_MAX_OFFSET 0xa0fc -#define MLXBF_GIGE_PLU_MAX_OFFSET 0x10fc -#endif /* MLXBF_GIGE_INTERNAL */ - -#endif /* !defined(__MLXBF_GIGE_REGS_H__) */ From patchwork Fri Jul 9 19:08:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503337 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2mF38T8z9sRN; Sat, 10 Jul 2021 05:10:05 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsr-0003u1-5t; Fri, 09 Jul 2021 19:09:57 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vs2-0003Jz-4x for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:06 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:09:00 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J90dk030259; Fri, 9 Jul 2021 15:09:00 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J90ru005475; Fri, 9 Jul 2021 15:09:00 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 22/23] Add Mellanox BlueField Gigabit Ethernet driver Date: Fri, 9 Jul 2021 15:08:29 -0400 Message-Id: <20210709190830.5405-23-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Liming Sun , "David S . Miller" , asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: David Thompson BugLink: https://bugs.launchpad.net/bugs/1934923 This patch adds build and driver logic for the "mlxbf_gige" Ethernet driver from Mellanox Technologies. The second generation BlueField SoC from Mellanox supports an out-of-band GigaBit Ethernet management port to the Arm subsystem. This driver supports TCP/IP network connectivity for that port, and provides back-end routines to handle basic ethtool requests. The driver interfaces to the Gigabit Ethernet block of BlueField SoC via MMIO accesses to registers, which contain control information or pointers describing transmit and receive resources. There is a single transmit queue, and the port supports transmit ring sizes of 4 to 256 entries. There is a single receive queue, and the port supports receive ring sizes of 32 to 32K entries. The transmit and receive rings are allocated from DMA coherent memory. There is a 16-bit producer and consumer index per ring to denote software ownership and hardware ownership, respectively. The main driver logic such as probe(), remove(), and netdev ops are in "mlxbf_gige_main.c". Logic in "mlxbf_gige_rx.c" and "mlxbf_gige_tx.c" handles the packet processing for receive and transmit respectively. The logic in "mlxbf_gige_ethtool.c" supports the handling of some basic ethtool requests: get driver info, get ring parameters, get registers, and get statistics. The logic in "mlxbf_gige_mdio.c" is the driver controlling the Mellanox BlueField hardware that interacts with a PHY device via MDIO/MDC pins. This driver does the following: - At driver probe time, it configures several BlueField MDIO parameters such as sample rate, full drive, voltage and MDC - It defines functions to read and write MDIO registers and registers the MDIO bus. - It defines the phy interrupt handler reporting a link up/down status change - This driver's probe is invoked from the main driver logic while the phy interrupt handler is registered in ndo_open. Driver limitations - Only supports 1Gbps speed - Only supports GMII protocol - Supports maximum packet size of 2KB - Does not support scatter-gather buffering Testing - Successful build of kernel for ARM64, ARM32, X86_64 - Tested ARM64 build on FastModels & Palladium - Tested ARM64 build on several Mellanox boards that are built with the BlueField-2 SoC. The testing includes coverage in the areas of networking (e.g. ping, iperf, ifconfig, route), file transfers (e.g. SCP), and various ethtool options relevant to this driver. Signed-off-by: David Thompson Signed-off-by: Asmaa Mnebhi Reviewed-by: Liming Sun Signed-off-by: David S. Miller (cherry picked from commit f92e1869d74e1acc6551256eb084a1c14a054e19) --- drivers/net/ethernet/mellanox/Kconfig | 1 + drivers/net/ethernet/mellanox/Makefile | 1 + .../net/ethernet/mellanox/mlxbf_gige/Kconfig | 13 + .../net/ethernet/mellanox/mlxbf_gige/Makefile | 11 + .../ethernet/mellanox/mlxbf_gige/mlxbf_gige.h | 190 ++++++++ .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 137 ++++++ .../mellanox/mlxbf_gige/mlxbf_gige_gpio.c | 212 ++++++++ .../mellanox/mlxbf_gige/mlxbf_gige_intr.c | 142 ++++++ .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 452 ++++++++++++++++++ .../mellanox/mlxbf_gige/mlxbf_gige_mdio.c | 187 ++++++++ .../mellanox/mlxbf_gige/mlxbf_gige_regs.h | 78 +++ .../mellanox/mlxbf_gige/mlxbf_gige_rx.c | 320 +++++++++++++ .../mellanox/mlxbf_gige/mlxbf_gige_tx.c | 284 +++++++++++ 13 files changed, 2028 insertions(+) create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/Makefile create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c create mode 100644 drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c diff --git a/drivers/net/ethernet/mellanox/Kconfig b/drivers/net/ethernet/mellanox/Kconfig index 23cf7917a0c9..d778909ebd95 100644 --- a/drivers/net/ethernet/mellanox/Kconfig +++ b/drivers/net/ethernet/mellanox/Kconfig @@ -22,5 +22,6 @@ source "drivers/net/ethernet/mellanox/mlx4/Kconfig" source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" source "drivers/net/ethernet/mellanox/mlxfw/Kconfig" +source "drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig" endif # NET_VENDOR_MELLANOX diff --git a/drivers/net/ethernet/mellanox/Makefile b/drivers/net/ethernet/mellanox/Makefile index 79773ac331ee..d4b5f547a727 100644 --- a/drivers/net/ethernet/mellanox/Makefile +++ b/drivers/net/ethernet/mellanox/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_MLX4_CORE) += mlx4/ obj-$(CONFIG_MLX5_CORE) += mlx5/core/ obj-$(CONFIG_MLXSW_CORE) += mlxsw/ obj-$(CONFIG_MLXFW) += mlxfw/ +obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige/ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig new file mode 100644 index 000000000000..4cdebafaf222 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause +# +# Mellanox GigE driver configuration +# + +config MLXBF_GIGE + tristate "Mellanox Technologies BlueField Gigabit Ethernet support" + depends on (ARM64 && ACPI) || COMPILE_TEST + select PHYLIB + help + The second generation BlueField SoC from Mellanox Technologies + supports an out-of-band Gigabit Ethernet management port to the + Arm subsystem. diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile new file mode 100644 index 000000000000..e57c1375f236 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/Makefile @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +obj-$(CONFIG_MLXBF_GIGE) += mlxbf_gige.o + +mlxbf_gige-y := mlxbf_gige_ethtool.o \ + mlxbf_gige_gpio.o \ + mlxbf_gige_intr.o \ + mlxbf_gige_main.o \ + mlxbf_gige_mdio.o \ + mlxbf_gige_rx.o \ + mlxbf_gige_tx.o diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h new file mode 100644 index 000000000000..e3509e69ed1c --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige.h @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ + +/* Header file for Gigabit Ethernet driver for Mellanox BlueField SoC + * - this file contains software data structures and any chip-specific + * data structures (e.g. TX WQE format) that are memory resident. + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#ifndef __MLXBF_GIGE_H__ +#define __MLXBF_GIGE_H__ + +#include +#include +#include +#include + +/* The silicon design supports a maximum RX ring size of + * 32K entries. Based on current testing this maximum size + * is not required to be supported. Instead the RX ring + * will be capped at a realistic value of 1024 entries. + */ +#define MLXBF_GIGE_MIN_RXQ_SZ 32 +#define MLXBF_GIGE_MAX_RXQ_SZ 1024 +#define MLXBF_GIGE_DEFAULT_RXQ_SZ 128 + +#define MLXBF_GIGE_MIN_TXQ_SZ 4 +#define MLXBF_GIGE_MAX_TXQ_SZ 256 +#define MLXBF_GIGE_DEFAULT_TXQ_SZ 128 + +#define MLXBF_GIGE_DEFAULT_BUF_SZ 2048 + +#define MLXBF_GIGE_DMA_PAGE_SZ 4096 +#define MLXBF_GIGE_DMA_PAGE_SHIFT 12 + +/* There are four individual MAC RX filters. Currently + * two of them are being used: one for the broadcast MAC + * (index 0) and one for local MAC (index 1) + */ +#define MLXBF_GIGE_BCAST_MAC_FILTER_IDX 0 +#define MLXBF_GIGE_LOCAL_MAC_FILTER_IDX 1 + +/* Define for broadcast MAC literal */ +#define BCAST_MAC_ADDR 0xFFFFFFFFFFFF + +/* There are three individual interrupts: + * 1) Errors, "OOB" interrupt line + * 2) Receive Packet, "OOB_LLU" interrupt line + * 3) LLU and PLU Events, "OOB_PLU" interrupt line + */ +#define MLXBF_GIGE_ERROR_INTR_IDX 0 +#define MLXBF_GIGE_RECEIVE_PKT_INTR_IDX 1 +#define MLXBF_GIGE_LLU_PLU_INTR_IDX 2 +#define MLXBF_GIGE_PHY_INT_N 3 + +#define MLXBF_GIGE_MDIO_DEFAULT_PHY_ADDR 0x3 + +#define MLXBF_GIGE_DEFAULT_PHY_INT_GPIO 12 + +struct mlxbf_gige_stats { + u64 hw_access_errors; + u64 tx_invalid_checksums; + u64 tx_small_frames; + u64 tx_index_errors; + u64 sw_config_errors; + u64 sw_access_errors; + u64 rx_truncate_errors; + u64 rx_mac_errors; + u64 rx_din_dropped_pkts; + u64 tx_fifo_full; + u64 rx_filter_passed_pkts; + u64 rx_filter_discard_pkts; +}; + +struct mlxbf_gige { + void __iomem *base; + void __iomem *llu_base; + void __iomem *plu_base; + struct device *dev; + struct net_device *netdev; + struct platform_device *pdev; + void __iomem *mdio_io; + struct mii_bus *mdiobus; + void __iomem *gpio_io; + struct irq_domain *irqdomain; + u32 phy_int_gpio_mask; + spinlock_t lock; /* for packet processing indices */ + spinlock_t gpio_lock; /* for GPIO bus access */ + u16 rx_q_entries; + u16 tx_q_entries; + u64 *tx_wqe_base; + dma_addr_t tx_wqe_base_dma; + u64 *tx_wqe_next; + u64 *tx_cc; + dma_addr_t tx_cc_dma; + dma_addr_t *rx_wqe_base; + dma_addr_t rx_wqe_base_dma; + u64 *rx_cqe_base; + dma_addr_t rx_cqe_base_dma; + u16 tx_pi; + u16 prev_tx_ci; + u64 error_intr_count; + u64 rx_intr_count; + u64 llu_plu_intr_count; + struct sk_buff *rx_skb[MLXBF_GIGE_MAX_RXQ_SZ]; + struct sk_buff *tx_skb[MLXBF_GIGE_MAX_TXQ_SZ]; + int error_irq; + int rx_irq; + int llu_plu_irq; + int phy_irq; + int hw_phy_irq; + bool promisc_enabled; + u8 valid_polarity; + struct napi_struct napi; + struct mlxbf_gige_stats stats; +}; + +/* Rx Work Queue Element definitions */ +#define MLXBF_GIGE_RX_WQE_SZ 8 + +/* Rx Completion Queue Element definitions */ +#define MLXBF_GIGE_RX_CQE_SZ 8 +#define MLXBF_GIGE_RX_CQE_PKT_LEN_MASK GENMASK(10, 0) +#define MLXBF_GIGE_RX_CQE_VALID_MASK GENMASK(11, 11) +#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK GENMASK(15, 12) +#define MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR GENMASK(12, 12) +#define MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED GENMASK(13, 13) +#define MLXBF_GIGE_RX_CQE_CHKSUM_MASK GENMASK(31, 16) + +/* Tx Work Queue Element definitions */ +#define MLXBF_GIGE_TX_WQE_SZ_QWORDS 2 +#define MLXBF_GIGE_TX_WQE_SZ 16 +#define MLXBF_GIGE_TX_WQE_PKT_LEN_MASK GENMASK(10, 0) +#define MLXBF_GIGE_TX_WQE_UPDATE_MASK GENMASK(31, 31) +#define MLXBF_GIGE_TX_WQE_CHKSUM_LEN_MASK GENMASK(42, 32) +#define MLXBF_GIGE_TX_WQE_CHKSUM_START_MASK GENMASK(55, 48) +#define MLXBF_GIGE_TX_WQE_CHKSUM_OFFSET_MASK GENMASK(63, 56) + +/* Macro to return packet length of specified TX WQE */ +#define MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr) \ + (*((tx_wqe_addr) + 1) & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK) + +/* Tx Completion Count */ +#define MLXBF_GIGE_TX_CC_SZ 8 + +/* List of resources in ACPI table */ +enum mlxbf_gige_res { + MLXBF_GIGE_RES_MAC, + MLXBF_GIGE_RES_MDIO9, + MLXBF_GIGE_RES_GPIO0, + MLXBF_GIGE_RES_LLU, + MLXBF_GIGE_RES_PLU +}; + +/* Version of register data returned by mlxbf_gige_get_regs() */ +#define MLXBF_GIGE_REGS_VERSION 1 + +int mlxbf_gige_mdio_probe(struct platform_device *pdev, + struct mlxbf_gige *priv); +void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv); +irqreturn_t mlxbf_gige_mdio_handle_phy_interrupt(int irq, void *dev_id); +void mlxbf_gige_mdio_enable_phy_int(struct mlxbf_gige *priv); + +void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 dmac); +void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 *dmac); +void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv); +void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv); +int mlxbf_gige_rx_init(struct mlxbf_gige *priv); +void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv); +int mlxbf_gige_tx_init(struct mlxbf_gige *priv); +void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv); +bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv); +netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, + struct net_device *netdev); +struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, + unsigned int map_len, + dma_addr_t *buf_dma, + enum dma_data_direction dir); +int mlxbf_gige_request_irqs(struct mlxbf_gige *priv); +void mlxbf_gige_free_irqs(struct mlxbf_gige *priv); +int mlxbf_gige_poll(struct napi_struct *napi, int budget); +extern const struct ethtool_ops mlxbf_gige_ethtool_ops; +void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv); + +int mlxbf_gige_gpio_init(struct platform_device *pdev, struct mlxbf_gige *priv); +void mlxbf_gige_gpio_free(struct mlxbf_gige *priv); + +#endif /* !defined(__MLXBF_GIGE_H__) */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c new file mode 100644 index 000000000000..92b798f8e73a --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* Ethtool support for Mellanox Gigabit Ethernet driver + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include + +#include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" + +/* Start of struct ethtool_ops functions */ +static int mlxbf_gige_get_regs_len(struct net_device *netdev) +{ + return MLXBF_GIGE_MMIO_REG_SZ; +} + +static void mlxbf_gige_get_regs(struct net_device *netdev, + struct ethtool_regs *regs, void *p) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + regs->version = MLXBF_GIGE_REGS_VERSION; + + /* Read entire MMIO register space and store results + * into the provided buffer. Each 64-bit word is converted + * to big-endian to make the output more readable. + * + * NOTE: by design, a read to an offset without an existing + * register will be acknowledged and return zero. + */ + memcpy_fromio(p, priv->base, MLXBF_GIGE_MMIO_REG_SZ); +} + +static void mlxbf_gige_get_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + ering->rx_max_pending = MLXBF_GIGE_MAX_RXQ_SZ; + ering->tx_max_pending = MLXBF_GIGE_MAX_TXQ_SZ; + ering->rx_pending = priv->rx_q_entries; + ering->tx_pending = priv->tx_q_entries; +} + +static const struct { + const char string[ETH_GSTRING_LEN]; +} mlxbf_gige_ethtool_stats_keys[] = { + { "hw_access_errors" }, + { "tx_invalid_checksums" }, + { "tx_small_frames" }, + { "tx_index_errors" }, + { "sw_config_errors" }, + { "sw_access_errors" }, + { "rx_truncate_errors" }, + { "rx_mac_errors" }, + { "rx_din_dropped_pkts" }, + { "tx_fifo_full" }, + { "rx_filter_passed_pkts" }, + { "rx_filter_discard_pkts" }, +}; + +static int mlxbf_gige_get_sset_count(struct net_device *netdev, int stringset) +{ + if (stringset != ETH_SS_STATS) + return -EOPNOTSUPP; + return ARRAY_SIZE(mlxbf_gige_ethtool_stats_keys); +} + +static void mlxbf_gige_get_strings(struct net_device *netdev, u32 stringset, + u8 *buf) +{ + if (stringset != ETH_SS_STATS) + return; + memcpy(buf, &mlxbf_gige_ethtool_stats_keys, + sizeof(mlxbf_gige_ethtool_stats_keys)); +} + +static void mlxbf_gige_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *estats, + u64 *data) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + /* Fill data array with interface statistics + * + * NOTE: the data writes must be in + * sync with the strings shown in + * the mlxbf_gige_ethtool_stats_keys[] array + * + * NOTE2: certain statistics below are zeroed upon + * port disable, so the calculation below + * must include the "cached" value of the stat + * plus the value read directly from hardware. + * Cached statistics are currently: + * rx_din_dropped_pkts + * rx_filter_passed_pkts + * rx_filter_discard_pkts + */ + *data++ = priv->stats.hw_access_errors; + *data++ = priv->stats.tx_invalid_checksums; + *data++ = priv->stats.tx_small_frames; + *data++ = priv->stats.tx_index_errors; + *data++ = priv->stats.sw_config_errors; + *data++ = priv->stats.sw_access_errors; + *data++ = priv->stats.rx_truncate_errors; + *data++ = priv->stats.rx_mac_errors; + *data++ = (priv->stats.rx_din_dropped_pkts + + readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER)); + *data++ = priv->stats.tx_fifo_full; + *data++ = (priv->stats.rx_filter_passed_pkts + + readq(priv->base + MLXBF_GIGE_RX_PASS_COUNTER_ALL)); + *data++ = (priv->stats.rx_filter_discard_pkts + + readq(priv->base + MLXBF_GIGE_RX_DISC_COUNTER_ALL)); +} + +static void mlxbf_gige_get_pauseparam(struct net_device *netdev, + struct ethtool_pauseparam *pause) +{ + pause->autoneg = AUTONEG_DISABLE; + pause->rx_pause = 1; + pause->tx_pause = 1; +} + +const struct ethtool_ops mlxbf_gige_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_ringparam = mlxbf_gige_get_ringparam, + .get_regs_len = mlxbf_gige_get_regs_len, + .get_regs = mlxbf_gige_get_regs, + .get_strings = mlxbf_gige_get_strings, + .get_sset_count = mlxbf_gige_get_sset_count, + .get_ethtool_stats = mlxbf_gige_get_ethtool_stats, + .nway_reset = phy_ethtool_nway_reset, + .get_pauseparam = mlxbf_gige_get_pauseparam, + .get_link_ksettings = phy_ethtool_get_link_ksettings, +}; diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c new file mode 100644 index 000000000000..a8d966db5715 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_gpio.c @@ -0,0 +1,212 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* Initialize and handle GPIO interrupt triggered by INT_N PHY signal. + * This GPIO interrupt triggers the PHY state machine to bring the link + * up/down. + * + * Copyright (C) 2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" + +#define MLXBF_GIGE_GPIO_CAUSE_FALL_EN 0x48 +#define MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 +#define MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0 0x94 +#define MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE 0x98 + +static void mlxbf_gige_gpio_enable(struct mlxbf_gige *priv) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->gpio_lock, flags); + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); + + /* The INT_N interrupt level is active low. + * So enable cause fall bit to detect when GPIO + * state goes low. + */ + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_FALL_EN); + + /* Enable PHY interrupt by setting the priority level */ + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + spin_unlock_irqrestore(&priv->gpio_lock, flags); +} + +static void mlxbf_gige_gpio_disable(struct mlxbf_gige *priv) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&priv->gpio_lock, flags); + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + val &= ~priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_EVTEN0); + spin_unlock_irqrestore(&priv->gpio_lock, flags); +} + +static irqreturn_t mlxbf_gige_gpio_handler(int irq, void *ptr) +{ + struct mlxbf_gige *priv; + u32 val; + + priv = ptr; + + /* Check if this interrupt is from PHY device. + * Return if it is not. + */ + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CAUSE_EVTEN0); + if (!(val & priv->phy_int_gpio_mask)) + return IRQ_NONE; + + /* Clear interrupt when done, otherwise, no further interrupt + * will be triggered. + */ + val = readl(priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); + val |= priv->phy_int_gpio_mask; + writel(val, priv->gpio_io + MLXBF_GIGE_GPIO_CAUSE_OR_CLRCAUSE); + + generic_handle_irq(priv->phy_irq); + + return IRQ_HANDLED; +} + +static void mlxbf_gige_gpio_mask(struct irq_data *irqd) +{ + struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd); + + mlxbf_gige_gpio_disable(priv); +} + +static void mlxbf_gige_gpio_unmask(struct irq_data *irqd) +{ + struct mlxbf_gige *priv = irq_data_get_irq_chip_data(irqd); + + mlxbf_gige_gpio_enable(priv); +} + +static struct irq_chip mlxbf_gige_gpio_chip = { + .name = "mlxbf_gige_phy", + .irq_mask = mlxbf_gige_gpio_mask, + .irq_unmask = mlxbf_gige_gpio_unmask, +}; + +static int mlxbf_gige_gpio_domain_map(struct irq_domain *d, + unsigned int irq, + irq_hw_number_t hwirq) +{ + irq_set_chip_data(irq, d->host_data); + irq_set_chip_and_handler(irq, &mlxbf_gige_gpio_chip, handle_simple_irq); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops mlxbf_gige_gpio_domain_ops = { + .map = mlxbf_gige_gpio_domain_map, + .xlate = irq_domain_xlate_twocell, +}; + +#ifdef CONFIG_ACPI +static int mlxbf_gige_gpio_resources(struct acpi_resource *ares, + void *data) +{ + struct acpi_resource_gpio *gpio; + u32 *phy_int_gpio = data; + + if (ares->type == ACPI_RESOURCE_TYPE_GPIO) { + gpio = &ares->data.gpio; + *phy_int_gpio = gpio->pin_table[0]; + } + + return 1; +} +#endif + +void mlxbf_gige_gpio_free(struct mlxbf_gige *priv) +{ + irq_dispose_mapping(priv->phy_irq); + irq_domain_remove(priv->irqdomain); +} + +int mlxbf_gige_gpio_init(struct platform_device *pdev, + struct mlxbf_gige *priv) +{ + struct device *dev = &pdev->dev; + struct resource *res; + u32 phy_int_gpio = 0; + int ret; + + LIST_HEAD(resources); + + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_GPIO0); + if (!res) + return -ENODEV; + + priv->gpio_io = devm_ioremap(dev, res->start, resource_size(res)); + if (!priv->gpio_io) + return -ENOMEM; + +#ifdef CONFIG_ACPI + ret = acpi_dev_get_resources(ACPI_COMPANION(dev), + &resources, mlxbf_gige_gpio_resources, + &phy_int_gpio); + acpi_dev_free_resource_list(&resources); + if (ret < 0 || !phy_int_gpio) { + dev_err(dev, "Error retrieving the gpio phy pin"); + return -EINVAL; + } +#endif + + priv->phy_int_gpio_mask = BIT(phy_int_gpio); + + mlxbf_gige_gpio_disable(priv); + + priv->hw_phy_irq = platform_get_irq(pdev, MLXBF_GIGE_PHY_INT_N); + + priv->irqdomain = irq_domain_add_simple(NULL, 1, 0, + &mlxbf_gige_gpio_domain_ops, + priv); + if (!priv->irqdomain) { + dev_err(dev, "Failed to add IRQ domain\n"); + return -ENOMEM; + } + + priv->phy_irq = irq_create_mapping(priv->irqdomain, 0); + if (!priv->phy_irq) { + irq_domain_remove(priv->irqdomain); + priv->irqdomain = NULL; + dev_err(dev, "Error mapping PHY IRQ\n"); + return -EINVAL; + } + + ret = devm_request_irq(dev, priv->hw_phy_irq, mlxbf_gige_gpio_handler, + IRQF_ONESHOT | IRQF_SHARED, "mlxbf_gige_phy", priv); + if (ret) { + dev_err(dev, "Failed to request PHY IRQ"); + mlxbf_gige_gpio_free(priv); + return ret; + } + + return ret; +} diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c new file mode 100644 index 000000000000..c38795be04a2 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_intr.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* Interrupt related logic for Mellanox Gigabit Ethernet driver + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include + +#include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" + +static irqreturn_t mlxbf_gige_error_intr(int irq, void *dev_id) +{ + struct mlxbf_gige *priv; + u64 int_status; + + priv = dev_id; + + priv->error_intr_count++; + + int_status = readq(priv->base + MLXBF_GIGE_INT_STATUS); + + if (int_status & MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR) + priv->stats.hw_access_errors++; + + if (int_status & MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS) { + priv->stats.tx_invalid_checksums++; + /* This error condition is latched into MLXBF_GIGE_INT_STATUS + * when the GigE silicon operates on the offending + * TX WQE. The write to MLXBF_GIGE_INT_STATUS at the bottom + * of this routine clears this error condition. + */ + } + + if (int_status & MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE) { + priv->stats.tx_small_frames++; + /* This condition happens when the networking stack invokes + * this driver's "start_xmit()" method with a packet whose + * size < 60 bytes. The GigE silicon will automatically pad + * this small frame up to a minimum-sized frame before it is + * sent. The "tx_small_frame" condition is latched into the + * MLXBF_GIGE_INT_STATUS register when the GigE silicon + * operates on the offending TX WQE. The write to + * MLXBF_GIGE_INT_STATUS at the bottom of this routine + * clears this condition. + */ + } + + if (int_status & MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE) + priv->stats.tx_index_errors++; + + if (int_status & MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR) + priv->stats.sw_config_errors++; + + if (int_status & MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR) + priv->stats.sw_access_errors++; + + /* Clear all error interrupts by writing '1' back to + * all the asserted bits in INT_STATUS. Do not write + * '1' back to 'receive packet' bit, since that is + * managed separately. + */ + + int_status &= ~MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET; + + writeq(int_status, priv->base + MLXBF_GIGE_INT_STATUS); + + return IRQ_HANDLED; +} + +static irqreturn_t mlxbf_gige_rx_intr(int irq, void *dev_id) +{ + struct mlxbf_gige *priv; + + priv = dev_id; + + priv->rx_intr_count++; + + /* NOTE: GigE silicon automatically disables "packet rx" interrupt by + * setting MLXBF_GIGE_INT_MASK bit0 upon triggering the interrupt + * to the ARM cores. Software needs to re-enable "packet rx" + * interrupts by clearing MLXBF_GIGE_INT_MASK bit0. + */ + + napi_schedule(&priv->napi); + + return IRQ_HANDLED; +} + +static irqreturn_t mlxbf_gige_llu_plu_intr(int irq, void *dev_id) +{ + struct mlxbf_gige *priv; + + priv = dev_id; + priv->llu_plu_intr_count++; + + return IRQ_HANDLED; +} + +int mlxbf_gige_request_irqs(struct mlxbf_gige *priv) +{ + int err; + + err = request_irq(priv->error_irq, mlxbf_gige_error_intr, 0, + "mlxbf_gige_error", priv); + if (err) { + dev_err(priv->dev, "Request error_irq failure\n"); + return err; + } + + err = request_irq(priv->rx_irq, mlxbf_gige_rx_intr, 0, + "mlxbf_gige_rx", priv); + if (err) { + dev_err(priv->dev, "Request rx_irq failure\n"); + goto free_error_irq; + } + + err = request_irq(priv->llu_plu_irq, mlxbf_gige_llu_plu_intr, 0, + "mlxbf_gige_llu_plu", priv); + if (err) { + dev_err(priv->dev, "Request llu_plu_irq failure\n"); + goto free_rx_irq; + } + + return 0; + +free_rx_irq: + free_irq(priv->rx_irq, priv); + +free_error_irq: + free_irq(priv->error_irq, priv); + + return err; +} + +void mlxbf_gige_free_irqs(struct mlxbf_gige *priv) +{ + free_irq(priv->error_irq, priv); + free_irq(priv->rx_irq, priv); + free_irq(priv->llu_plu_irq, priv); +} diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c new file mode 100644 index 000000000000..a0a059e0154f --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -0,0 +1,452 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* Gigabit Ethernet driver for Mellanox BlueField SoC + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" + +#define DRV_NAME "mlxbf_gige" + +/* Allocate SKB whose payload pointer aligns with the Bluefield + * hardware DMA limitation, i.e. DMA operation can't cross + * a 4KB boundary. A maximum packet size of 2KB is assumed in the + * alignment formula. The alignment logic overallocates an SKB, + * and then adjusts the headroom so that the SKB data pointer is + * naturally aligned to a 2KB boundary. + */ +struct sk_buff *mlxbf_gige_alloc_skb(struct mlxbf_gige *priv, + unsigned int map_len, + dma_addr_t *buf_dma, + enum dma_data_direction dir) +{ + struct sk_buff *skb; + u64 addr, offset; + + /* Overallocate the SKB so that any headroom adjustment (to + * provide 2KB natural alignment) does not exceed payload area + */ + skb = netdev_alloc_skb(priv->netdev, MLXBF_GIGE_DEFAULT_BUF_SZ * 2); + if (!skb) + return NULL; + + /* Adjust the headroom so that skb->data is naturally aligned to + * a 2KB boundary, which is the maximum packet size supported. + */ + addr = (long)skb->data; + offset = (addr + MLXBF_GIGE_DEFAULT_BUF_SZ - 1) & + ~(MLXBF_GIGE_DEFAULT_BUF_SZ - 1); + offset -= addr; + if (offset) + skb_reserve(skb, offset); + + /* Return streaming DMA mapping to caller */ + *buf_dma = dma_map_single(priv->dev, skb->data, map_len, dir); + if (dma_mapping_error(priv->dev, *buf_dma)) { + dev_kfree_skb(skb); + *buf_dma = (dma_addr_t)0; + return NULL; + } + + return skb; +} + +static void mlxbf_gige_initial_mac(struct mlxbf_gige *priv) +{ + u8 mac[ETH_ALEN]; + u64 local_mac; + + memset(mac, 0, ETH_ALEN); + mlxbf_gige_get_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, + &local_mac); + u64_to_ether_addr(local_mac, mac); + + if (is_valid_ether_addr(mac)) { + ether_addr_copy(priv->netdev->dev_addr, mac); + } else { + /* Provide a random MAC if for some reason the device has + * not been configured with a valid MAC address already. + */ + eth_hw_addr_random(priv->netdev); + } + + local_mac = ether_addr_to_u64(priv->netdev->dev_addr); + mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_LOCAL_MAC_FILTER_IDX, + local_mac); +} + +static void mlxbf_gige_cache_stats(struct mlxbf_gige *priv) +{ + struct mlxbf_gige_stats *p; + + /* Cache stats that will be cleared by clean port operation */ + p = &priv->stats; + p->rx_din_dropped_pkts += readq(priv->base + + MLXBF_GIGE_RX_DIN_DROP_COUNTER); + p->rx_filter_passed_pkts += readq(priv->base + + MLXBF_GIGE_RX_PASS_COUNTER_ALL); + p->rx_filter_discard_pkts += readq(priv->base + + MLXBF_GIGE_RX_DISC_COUNTER_ALL); +} + +static int mlxbf_gige_clean_port(struct mlxbf_gige *priv) +{ + u64 control; + u64 temp; + int err; + + /* Set the CLEAN_PORT_EN bit to trigger SW reset */ + control = readq(priv->base + MLXBF_GIGE_CONTROL); + control |= MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; + writeq(control, priv->base + MLXBF_GIGE_CONTROL); + + /* Ensure completion of "clean port" write before polling status */ + mb(); + + err = readq_poll_timeout_atomic(priv->base + MLXBF_GIGE_STATUS, temp, + (temp & MLXBF_GIGE_STATUS_READY), + 100, 100000); + + /* Clear the CLEAN_PORT_EN bit at end of this loop */ + control = readq(priv->base + MLXBF_GIGE_CONTROL); + control &= ~MLXBF_GIGE_CONTROL_CLEAN_PORT_EN; + writeq(control, priv->base + MLXBF_GIGE_CONTROL); + + return err; +} + +static int mlxbf_gige_open(struct net_device *netdev) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + struct phy_device *phydev = netdev->phydev; + u64 int_en; + int err; + + err = mlxbf_gige_request_irqs(priv); + if (err) + return err; + mlxbf_gige_cache_stats(priv); + err = mlxbf_gige_clean_port(priv); + if (err) + goto free_irqs; + err = mlxbf_gige_rx_init(priv); + if (err) + goto free_irqs; + err = mlxbf_gige_tx_init(priv); + if (err) + goto rx_deinit; + + phy_start(phydev); + + netif_napi_add(netdev, &priv->napi, mlxbf_gige_poll, NAPI_POLL_WEIGHT); + napi_enable(&priv->napi); + netif_start_queue(netdev); + + /* Set bits in INT_EN that we care about */ + int_en = MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR | + MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS | + MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE | + MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE | + MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR | + MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR | + MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET; + + /* Ensure completion of all initialization before enabling interrupts */ + mb(); + + writeq(int_en, priv->base + MLXBF_GIGE_INT_EN); + + return 0; + +rx_deinit: + mlxbf_gige_rx_deinit(priv); + +free_irqs: + mlxbf_gige_free_irqs(priv); + return err; +} + +static int mlxbf_gige_stop(struct net_device *netdev) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + writeq(0, priv->base + MLXBF_GIGE_INT_EN); + netif_stop_queue(netdev); + napi_disable(&priv->napi); + netif_napi_del(&priv->napi); + mlxbf_gige_free_irqs(priv); + + phy_stop(netdev->phydev); + + mlxbf_gige_rx_deinit(priv); + mlxbf_gige_tx_deinit(priv); + mlxbf_gige_cache_stats(priv); + mlxbf_gige_clean_port(priv); + + return 0; +} + +static int mlxbf_gige_do_ioctl(struct net_device *netdev, + struct ifreq *ifr, int cmd) +{ + if (!(netif_running(netdev))) + return -EINVAL; + + return phy_mii_ioctl(netdev->phydev, ifr, cmd); +} + +static void mlxbf_gige_set_rx_mode(struct net_device *netdev) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + bool new_promisc_enabled; + + new_promisc_enabled = netdev->flags & IFF_PROMISC; + + /* Only write to the hardware registers if the new setting + * of promiscuous mode is different from the current one. + */ + if (new_promisc_enabled != priv->promisc_enabled) { + priv->promisc_enabled = new_promisc_enabled; + + if (new_promisc_enabled) + mlxbf_gige_enable_promisc(priv); + else + mlxbf_gige_disable_promisc(priv); + } +} + +static void mlxbf_gige_get_stats64(struct net_device *netdev, + struct rtnl_link_stats64 *stats) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + + netdev_stats_to_stats64(stats, &netdev->stats); + + stats->rx_length_errors = priv->stats.rx_truncate_errors; + stats->rx_fifo_errors = priv->stats.rx_din_dropped_pkts + + readq(priv->base + MLXBF_GIGE_RX_DIN_DROP_COUNTER); + stats->rx_crc_errors = priv->stats.rx_mac_errors; + stats->rx_errors = stats->rx_length_errors + + stats->rx_fifo_errors + + stats->rx_crc_errors; + + stats->tx_fifo_errors = priv->stats.tx_fifo_full; + stats->tx_errors = stats->tx_fifo_errors; +} + +static const struct net_device_ops mlxbf_gige_netdev_ops = { + .ndo_open = mlxbf_gige_open, + .ndo_stop = mlxbf_gige_stop, + .ndo_start_xmit = mlxbf_gige_start_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = mlxbf_gige_do_ioctl, + .ndo_set_rx_mode = mlxbf_gige_set_rx_mode, + .ndo_get_stats64 = mlxbf_gige_get_stats64, +}; + +static void mlxbf_gige_adjust_link(struct net_device *netdev) +{ + struct phy_device *phydev = netdev->phydev; + + phy_print_status(phydev); +} + +static int mlxbf_gige_probe(struct platform_device *pdev) +{ + struct phy_device *phydev; + struct net_device *netdev; + struct resource *mac_res; + struct resource *llu_res; + struct resource *plu_res; + struct mlxbf_gige *priv; + void __iomem *llu_base; + void __iomem *plu_base; + void __iomem *base; + u64 control; + int addr; + int err; + + mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); + if (!mac_res) + return -ENXIO; + + base = devm_ioremap_resource(&pdev->dev, mac_res); + if (IS_ERR(base)) + return PTR_ERR(base); + + llu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_LLU); + if (!llu_res) + return -ENXIO; + + llu_base = devm_ioremap_resource(&pdev->dev, llu_res); + if (IS_ERR(llu_base)) + return PTR_ERR(llu_base); + + plu_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_PLU); + if (!plu_res) + return -ENXIO; + + plu_base = devm_ioremap_resource(&pdev->dev, plu_res); + if (IS_ERR(plu_base)) + return PTR_ERR(plu_base); + + /* Perform general init of GigE block */ + control = readq(base + MLXBF_GIGE_CONTROL); + control |= MLXBF_GIGE_CONTROL_PORT_EN; + writeq(control, base + MLXBF_GIGE_CONTROL); + + netdev = devm_alloc_etherdev(&pdev->dev, sizeof(*priv)); + if (!netdev) + return -ENOMEM; + + SET_NETDEV_DEV(netdev, &pdev->dev); + netdev->netdev_ops = &mlxbf_gige_netdev_ops; + netdev->ethtool_ops = &mlxbf_gige_ethtool_ops; + priv = netdev_priv(netdev); + priv->netdev = netdev; + + platform_set_drvdata(pdev, priv); + priv->dev = &pdev->dev; + priv->pdev = pdev; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->gpio_lock); + + /* Attach MDIO device */ + err = mlxbf_gige_mdio_probe(pdev, priv); + if (err) + return err; + + err = mlxbf_gige_gpio_init(pdev, priv); + if (err) { + dev_err(&pdev->dev, "PHY IRQ initialization failed\n"); + mlxbf_gige_mdio_remove(priv); + return -ENODEV; + } + + priv->base = base; + priv->llu_base = llu_base; + priv->plu_base = plu_base; + + priv->rx_q_entries = MLXBF_GIGE_DEFAULT_RXQ_SZ; + priv->tx_q_entries = MLXBF_GIGE_DEFAULT_TXQ_SZ; + + /* Write initial MAC address to hardware */ + mlxbf_gige_initial_mac(priv); + + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "DMA configuration failed: 0x%x\n", err); + goto out; + } + + priv->error_irq = platform_get_irq(pdev, MLXBF_GIGE_ERROR_INTR_IDX); + priv->rx_irq = platform_get_irq(pdev, MLXBF_GIGE_RECEIVE_PKT_INTR_IDX); + priv->llu_plu_irq = platform_get_irq(pdev, MLXBF_GIGE_LLU_PLU_INTR_IDX); + + phydev = phy_find_first(priv->mdiobus); + if (!phydev) { + err = -ENODEV; + goto out; + } + + addr = phydev->mdio.addr; + priv->mdiobus->irq[addr] = priv->phy_irq; + phydev->irq = priv->phy_irq; + + err = phy_connect_direct(netdev, phydev, + mlxbf_gige_adjust_link, + PHY_INTERFACE_MODE_GMII); + if (err) { + dev_err(&pdev->dev, "Could not attach to PHY\n"); + goto out; + } + + /* MAC only supports 1000T full duplex mode */ + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Full_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_100baseT_Half_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Full_BIT); + phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_10baseT_Half_BIT); + + /* Only symmetric pause with flow control enabled is supported so no + * need to negotiate pause. + */ + linkmode_clear_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->advertising); + linkmode_clear_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->advertising); + + /* Display information about attached PHY device */ + phy_attached_info(phydev); + + err = register_netdev(netdev); + if (err) { + dev_err(&pdev->dev, "Failed to register netdev\n"); + phy_disconnect(phydev); + goto out; + } + + return 0; + +out: + mlxbf_gige_gpio_free(priv); + mlxbf_gige_mdio_remove(priv); + return err; +} + +static int mlxbf_gige_remove(struct platform_device *pdev) +{ + struct mlxbf_gige *priv = platform_get_drvdata(pdev); + + unregister_netdev(priv->netdev); + phy_disconnect(priv->netdev->phydev); + mlxbf_gige_gpio_free(priv); + mlxbf_gige_mdio_remove(priv); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +static void mlxbf_gige_shutdown(struct platform_device *pdev) +{ + struct mlxbf_gige *priv = platform_get_drvdata(pdev); + + writeq(0, priv->base + MLXBF_GIGE_INT_EN); + mlxbf_gige_clean_port(priv); +} + +static const struct acpi_device_id __maybe_unused mlxbf_gige_acpi_match[] = { + { "MLNXBF17", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, mlxbf_gige_acpi_match); + +static struct platform_driver mlxbf_gige_driver = { + .probe = mlxbf_gige_probe, + .remove = mlxbf_gige_remove, + .shutdown = mlxbf_gige_shutdown, + .driver = { + .name = DRV_NAME, + .acpi_match_table = ACPI_PTR(mlxbf_gige_acpi_match), + }, +}; + +module_platform_driver(mlxbf_gige_driver); + +MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); +MODULE_AUTHOR("David Thompson "); +MODULE_AUTHOR("Asmaa Mnebhi "); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c new file mode 100644 index 000000000000..e32dd34fdcc0 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_mdio.c @@ -0,0 +1,187 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* MDIO support for Mellanox Gigabit Ethernet driver + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mlxbf_gige.h" + +#define MLXBF_GIGE_MDIO_GW_OFFSET 0x0 +#define MLXBF_GIGE_MDIO_CFG_OFFSET 0x4 + +/* Support clause 22 */ +#define MLXBF_GIGE_MDIO_CL22_ST1 0x1 +#define MLXBF_GIGE_MDIO_CL22_WRITE 0x1 +#define MLXBF_GIGE_MDIO_CL22_READ 0x2 + +/* Busy bit is set by software and cleared by hardware */ +#define MLXBF_GIGE_MDIO_SET_BUSY 0x1 + +/* MDIO GW register bits */ +#define MLXBF_GIGE_MDIO_GW_AD_MASK GENMASK(15, 0) +#define MLXBF_GIGE_MDIO_GW_DEVAD_MASK GENMASK(20, 16) +#define MLXBF_GIGE_MDIO_GW_PARTAD_MASK GENMASK(25, 21) +#define MLXBF_GIGE_MDIO_GW_OPCODE_MASK GENMASK(27, 26) +#define MLXBF_GIGE_MDIO_GW_ST1_MASK GENMASK(28, 28) +#define MLXBF_GIGE_MDIO_GW_BUSY_MASK GENMASK(30, 30) + +/* MDIO config register bits */ +#define MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK GENMASK(1, 0) +#define MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK GENMASK(2, 2) +#define MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK GENMASK(4, 4) +#define MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK GENMASK(15, 8) +#define MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK GENMASK(23, 16) +#define MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK GENMASK(31, 24) + +/* Formula for encoding the MDIO period. The encoded value is + * passed to the MDIO config register. + * + * mdc_clk = 2*(val + 1)*i1clk + * + * 400 ns = 2*(val + 1)*(((1/430)*1000) ns) + * + * val = (((400 * 430 / 1000) / 2) - 1) + */ +#define MLXBF_GIGE_I1CLK_MHZ 430 +#define MLXBF_GIGE_MDC_CLK_NS 400 + +#define MLXBF_GIGE_MDIO_PERIOD (((MLXBF_GIGE_MDC_CLK_NS * MLXBF_GIGE_I1CLK_MHZ / 1000) / 2) - 1) + +#define MLXBF_GIGE_MDIO_CFG_VAL (FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_MODE_MASK, 1) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO3_3_MASK, 1) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_FULL_DRIVE_MASK, 1) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDC_PERIOD_MASK, \ + MLXBF_GIGE_MDIO_PERIOD) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_IN_SAMP_MASK, 6) | \ + FIELD_PREP(MLXBF_GIGE_MDIO_CFG_MDIO_OUT_SAMP_MASK, 13)) + +static u32 mlxbf_gige_mdio_create_cmd(u16 data, int phy_add, + int phy_reg, u32 opcode) +{ + u32 gw_reg = 0; + + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_AD_MASK, data); + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_DEVAD_MASK, phy_reg); + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_PARTAD_MASK, phy_add); + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_OPCODE_MASK, opcode); + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_ST1_MASK, + MLXBF_GIGE_MDIO_CL22_ST1); + gw_reg |= FIELD_PREP(MLXBF_GIGE_MDIO_GW_BUSY_MASK, + MLXBF_GIGE_MDIO_SET_BUSY); + + return gw_reg; +} + +static int mlxbf_gige_mdio_read(struct mii_bus *bus, int phy_add, int phy_reg) +{ + struct mlxbf_gige *priv = bus->priv; + u32 cmd; + int ret; + u32 val; + + if (phy_reg & MII_ADDR_C45) + return -EOPNOTSUPP; + + /* Send mdio read request */ + cmd = mlxbf_gige_mdio_create_cmd(0, phy_add, phy_reg, MLXBF_GIGE_MDIO_CL22_READ); + + writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + + ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, + val, !(val & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); + + if (ret) { + writel(0, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + return ret; + } + + ret = readl(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + /* Only return ad bits of the gw register */ + ret &= MLXBF_GIGE_MDIO_GW_AD_MASK; + + return ret; +} + +static int mlxbf_gige_mdio_write(struct mii_bus *bus, int phy_add, + int phy_reg, u16 val) +{ + struct mlxbf_gige *priv = bus->priv; + u32 cmd; + int ret; + u32 temp; + + if (phy_reg & MII_ADDR_C45) + return -EOPNOTSUPP; + + /* Send mdio write request */ + cmd = mlxbf_gige_mdio_create_cmd(val, phy_add, phy_reg, + MLXBF_GIGE_MDIO_CL22_WRITE); + writel(cmd, priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET); + + /* If the poll timed out, drop the request */ + ret = readl_poll_timeout_atomic(priv->mdio_io + MLXBF_GIGE_MDIO_GW_OFFSET, + temp, !(temp & MLXBF_GIGE_MDIO_GW_BUSY_MASK), 100, 1000000); + + return ret; +} + +int mlxbf_gige_mdio_probe(struct platform_device *pdev, struct mlxbf_gige *priv) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + + res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MDIO9); + if (!res) + return -ENODEV; + + priv->mdio_io = devm_ioremap_resource(dev, res); + if (IS_ERR(priv->mdio_io)) + return PTR_ERR(priv->mdio_io); + + /* Configure mdio parameters */ + writel(MLXBF_GIGE_MDIO_CFG_VAL, + priv->mdio_io + MLXBF_GIGE_MDIO_CFG_OFFSET); + + priv->mdiobus = devm_mdiobus_alloc(dev); + if (!priv->mdiobus) { + dev_err(dev, "Failed to alloc MDIO bus\n"); + return -ENOMEM; + } + + priv->mdiobus->name = "mlxbf-mdio"; + priv->mdiobus->read = mlxbf_gige_mdio_read; + priv->mdiobus->write = mlxbf_gige_mdio_write; + priv->mdiobus->parent = dev; + priv->mdiobus->priv = priv; + snprintf(priv->mdiobus->id, MII_BUS_ID_SIZE, "%s", + dev_name(dev)); + + ret = mdiobus_register(priv->mdiobus); + if (ret) + dev_err(dev, "Failed to register MDIO bus\n"); + + return ret; +} + +void mlxbf_gige_mdio_remove(struct mlxbf_gige *priv) +{ + mdiobus_unregister(priv->mdiobus); +} diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h new file mode 100644 index 000000000000..5fb33c9294bf --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_regs.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause */ + +/* Header file for Mellanox BlueField GigE register defines + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#ifndef __MLXBF_GIGE_REGS_H__ +#define __MLXBF_GIGE_REGS_H__ + +#define MLXBF_GIGE_STATUS 0x0010 +#define MLXBF_GIGE_STATUS_READY BIT(0) +#define MLXBF_GIGE_INT_STATUS 0x0028 +#define MLXBF_GIGE_INT_STATUS_RX_RECEIVE_PACKET BIT(0) +#define MLXBF_GIGE_INT_STATUS_RX_MAC_ERROR BIT(1) +#define MLXBF_GIGE_INT_STATUS_RX_TRN_ERROR BIT(2) +#define MLXBF_GIGE_INT_STATUS_SW_ACCESS_ERROR BIT(3) +#define MLXBF_GIGE_INT_STATUS_SW_CONFIG_ERROR BIT(4) +#define MLXBF_GIGE_INT_STATUS_TX_PI_CI_EXCEED_WQ_SIZE BIT(5) +#define MLXBF_GIGE_INT_STATUS_TX_SMALL_FRAME_SIZE BIT(6) +#define MLXBF_GIGE_INT_STATUS_TX_CHECKSUM_INPUTS BIT(7) +#define MLXBF_GIGE_INT_STATUS_HW_ACCESS_ERROR BIT(8) +#define MLXBF_GIGE_INT_EN 0x0030 +#define MLXBF_GIGE_INT_EN_RX_RECEIVE_PACKET BIT(0) +#define MLXBF_GIGE_INT_EN_RX_MAC_ERROR BIT(1) +#define MLXBF_GIGE_INT_EN_RX_TRN_ERROR BIT(2) +#define MLXBF_GIGE_INT_EN_SW_ACCESS_ERROR BIT(3) +#define MLXBF_GIGE_INT_EN_SW_CONFIG_ERROR BIT(4) +#define MLXBF_GIGE_INT_EN_TX_PI_CI_EXCEED_WQ_SIZE BIT(5) +#define MLXBF_GIGE_INT_EN_TX_SMALL_FRAME_SIZE BIT(6) +#define MLXBF_GIGE_INT_EN_TX_CHECKSUM_INPUTS BIT(7) +#define MLXBF_GIGE_INT_EN_HW_ACCESS_ERROR BIT(8) +#define MLXBF_GIGE_INT_MASK 0x0038 +#define MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET BIT(0) +#define MLXBF_GIGE_CONTROL 0x0040 +#define MLXBF_GIGE_CONTROL_PORT_EN BIT(0) +#define MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN BIT(1) +#define MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC BIT(4) +#define MLXBF_GIGE_CONTROL_CLEAN_PORT_EN BIT(31) +#define MLXBF_GIGE_RX_WQ_BASE 0x0200 +#define MLXBF_GIGE_RX_WQE_SIZE_LOG2 0x0208 +#define MLXBF_GIGE_RX_WQE_SIZE_LOG2_RESET_VAL 7 +#define MLXBF_GIGE_RX_CQ_BASE 0x0210 +#define MLXBF_GIGE_TX_WQ_BASE 0x0218 +#define MLXBF_GIGE_TX_WQ_SIZE_LOG2 0x0220 +#define MLXBF_GIGE_TX_WQ_SIZE_LOG2_RESET_VAL 7 +#define MLXBF_GIGE_TX_CI_UPDATE_ADDRESS 0x0228 +#define MLXBF_GIGE_RX_WQE_PI 0x0230 +#define MLXBF_GIGE_TX_PRODUCER_INDEX 0x0238 +#define MLXBF_GIGE_RX_MAC_FILTER 0x0240 +#define MLXBF_GIGE_RX_MAC_FILTER_STRIDE 0x0008 +#define MLXBF_GIGE_RX_DIN_DROP_COUNTER 0x0260 +#define MLXBF_GIGE_TX_CONSUMER_INDEX 0x0310 +#define MLXBF_GIGE_TX_CONTROL 0x0318 +#define MLXBF_GIGE_TX_CONTROL_GRACEFUL_STOP BIT(0) +#define MLXBF_GIGE_TX_STATUS 0x0388 +#define MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL BIT(1) +#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START 0x0520 +#define MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END 0x0528 +#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC 0x0540 +#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN BIT(0) +#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS 0x0548 +#define MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN BIT(0) +#define MLXBF_GIGE_RX_PASS_COUNTER_ALL 0x0550 +#define MLXBF_GIGE_RX_DISC_COUNTER_ALL 0x0560 +#define MLXBF_GIGE_RX 0x0578 +#define MLXBF_GIGE_RX_STRIP_CRC_EN BIT(1) +#define MLXBF_GIGE_RX_DMA 0x0580 +#define MLXBF_GIGE_RX_DMA_EN BIT(0) +#define MLXBF_GIGE_RX_CQE_PACKET_CI 0x05b0 +#define MLXBF_GIGE_MAC_CFG 0x05e8 + +/* NOTE: MLXBF_GIGE_MAC_CFG is the last defined register offset, + * so use that plus size of single register to derive total size + */ +#define MLXBF_GIGE_MMIO_REG_SZ (MLXBF_GIGE_MAC_CFG + 8) + +#endif /* !defined(__MLXBF_GIGE_REGS_H__) */ diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c new file mode 100644 index 000000000000..afa3b92a6905 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_rx.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* Packet receive logic for Mellanox Gigabit Ethernet driver + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include +#include + +#include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" + +void mlxbf_gige_set_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 dmac) +{ + void __iomem *base = priv->base; + u64 control; + + /* Write destination MAC to specified MAC RX filter */ + writeq(dmac, base + MLXBF_GIGE_RX_MAC_FILTER + + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); + + /* Enable MAC receive filter mask for specified index */ + control = readq(base + MLXBF_GIGE_CONTROL); + control |= (MLXBF_GIGE_CONTROL_EN_SPECIFIC_MAC << index); + writeq(control, base + MLXBF_GIGE_CONTROL); +} + +void mlxbf_gige_get_mac_rx_filter(struct mlxbf_gige *priv, + unsigned int index, u64 *dmac) +{ + void __iomem *base = priv->base; + + /* Read destination MAC from specified MAC RX filter */ + *dmac = readq(base + MLXBF_GIGE_RX_MAC_FILTER + + (index * MLXBF_GIGE_RX_MAC_FILTER_STRIDE)); +} + +void mlxbf_gige_enable_promisc(struct mlxbf_gige *priv) +{ + void __iomem *base = priv->base; + u64 control; + u64 end_mac; + + /* Enable MAC_ID_RANGE match functionality */ + control = readq(base + MLXBF_GIGE_CONTROL); + control |= MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; + writeq(control, base + MLXBF_GIGE_CONTROL); + + /* Set start of destination MAC range check to 0 */ + writeq(0, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_START); + + /* Set end of destination MAC range check to all FFs */ + end_mac = BCAST_MAC_ADDR; + writeq(end_mac, base + MLXBF_GIGE_RX_MAC_FILTER_DMAC_RANGE_END); +} + +void mlxbf_gige_disable_promisc(struct mlxbf_gige *priv) +{ + void __iomem *base = priv->base; + u64 control; + + /* Disable MAC_ID_RANGE match functionality */ + control = readq(base + MLXBF_GIGE_CONTROL); + control &= ~MLXBF_GIGE_CONTROL_MAC_ID_RANGE_EN; + writeq(control, base + MLXBF_GIGE_CONTROL); + + /* NOTE: no need to change DMAC_RANGE_START or END; + * those values are ignored since MAC_ID_RANGE_EN=0 + */ +} + +/* Receive Initialization + * 1) Configures RX MAC filters via MMIO registers + * 2) Allocates RX WQE array using coherent DMA mapping + * 3) Initializes each element of RX WQE array with a receive + * buffer pointer (also using coherent DMA mapping) + * 4) Allocates RX CQE array using coherent DMA mapping + * 5) Completes other misc receive initialization + */ +int mlxbf_gige_rx_init(struct mlxbf_gige *priv) +{ + size_t wq_size, cq_size; + dma_addr_t *rx_wqe_ptr; + dma_addr_t rx_buf_dma; + u64 data; + int i, j; + + /* Configure MAC RX filter #0 to allow RX of broadcast pkts */ + mlxbf_gige_set_mac_rx_filter(priv, MLXBF_GIGE_BCAST_MAC_FILTER_IDX, + BCAST_MAC_ADDR); + + wq_size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; + priv->rx_wqe_base = dma_alloc_coherent(priv->dev, wq_size, + &priv->rx_wqe_base_dma, + GFP_KERNEL); + if (!priv->rx_wqe_base) + return -ENOMEM; + + /* Initialize 'rx_wqe_ptr' to point to first RX WQE in array + * Each RX WQE is simply a receive buffer pointer, so walk + * the entire array, allocating a 2KB buffer for each element + */ + rx_wqe_ptr = priv->rx_wqe_base; + + for (i = 0; i < priv->rx_q_entries; i++) { + priv->rx_skb[i] = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, + &rx_buf_dma, DMA_FROM_DEVICE); + if (!priv->rx_skb[i]) + goto free_wqe_and_skb; + *rx_wqe_ptr++ = rx_buf_dma; + } + + /* Write RX WQE base address into MMIO reg */ + writeq(priv->rx_wqe_base_dma, priv->base + MLXBF_GIGE_RX_WQ_BASE); + + cq_size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; + priv->rx_cqe_base = dma_alloc_coherent(priv->dev, cq_size, + &priv->rx_cqe_base_dma, + GFP_KERNEL); + if (!priv->rx_cqe_base) + goto free_wqe_and_skb; + + for (i = 0; i < priv->rx_q_entries; i++) + priv->rx_cqe_base[i] |= MLXBF_GIGE_RX_CQE_VALID_MASK; + + /* Write RX CQE base address into MMIO reg */ + writeq(priv->rx_cqe_base_dma, priv->base + MLXBF_GIGE_RX_CQ_BASE); + + /* Write RX_WQE_PI with current number of replenished buffers */ + writeq(priv->rx_q_entries, priv->base + MLXBF_GIGE_RX_WQE_PI); + + /* Enable removal of CRC during RX */ + data = readq(priv->base + MLXBF_GIGE_RX); + data |= MLXBF_GIGE_RX_STRIP_CRC_EN; + writeq(data, priv->base + MLXBF_GIGE_RX); + + /* Enable RX MAC filter pass and discard counters */ + writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC_EN, + priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_DISC); + writeq(MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS_EN, + priv->base + MLXBF_GIGE_RX_MAC_FILTER_COUNT_PASS); + + /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to + * indicate readiness to receive interrupts + */ + data = readq(priv->base + MLXBF_GIGE_INT_MASK); + data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; + writeq(data, priv->base + MLXBF_GIGE_INT_MASK); + + /* Enable RX DMA to write new packets to memory */ + data = readq(priv->base + MLXBF_GIGE_RX_DMA); + data |= MLXBF_GIGE_RX_DMA_EN; + writeq(data, priv->base + MLXBF_GIGE_RX_DMA); + + writeq(ilog2(priv->rx_q_entries), + priv->base + MLXBF_GIGE_RX_WQE_SIZE_LOG2); + + return 0; + +free_wqe_and_skb: + rx_wqe_ptr = priv->rx_wqe_base; + for (j = 0; j < i; j++) { + dma_unmap_single(priv->dev, *rx_wqe_ptr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + dev_kfree_skb(priv->rx_skb[j]); + rx_wqe_ptr++; + } + dma_free_coherent(priv->dev, wq_size, + priv->rx_wqe_base, priv->rx_wqe_base_dma); + return -ENOMEM; +} + +/* Receive Deinitialization + * This routine will free allocations done by mlxbf_gige_rx_init(), + * namely the RX WQE and RX CQE arrays, as well as all RX buffers + */ +void mlxbf_gige_rx_deinit(struct mlxbf_gige *priv) +{ + dma_addr_t *rx_wqe_ptr; + size_t size; + u64 data; + int i; + + /* Disable RX DMA to prevent packet transfers to memory */ + data = readq(priv->base + MLXBF_GIGE_RX_DMA); + data &= ~MLXBF_GIGE_RX_DMA_EN; + writeq(data, priv->base + MLXBF_GIGE_RX_DMA); + + rx_wqe_ptr = priv->rx_wqe_base; + + for (i = 0; i < priv->rx_q_entries; i++) { + dma_unmap_single(priv->dev, *rx_wqe_ptr, MLXBF_GIGE_DEFAULT_BUF_SZ, + DMA_FROM_DEVICE); + dev_kfree_skb(priv->rx_skb[i]); + rx_wqe_ptr++; + } + + size = MLXBF_GIGE_RX_WQE_SZ * priv->rx_q_entries; + dma_free_coherent(priv->dev, size, + priv->rx_wqe_base, priv->rx_wqe_base_dma); + + size = MLXBF_GIGE_RX_CQE_SZ * priv->rx_q_entries; + dma_free_coherent(priv->dev, size, + priv->rx_cqe_base, priv->rx_cqe_base_dma); + + priv->rx_wqe_base = NULL; + priv->rx_wqe_base_dma = 0; + priv->rx_cqe_base = NULL; + priv->rx_cqe_base_dma = 0; + writeq(0, priv->base + MLXBF_GIGE_RX_WQ_BASE); + writeq(0, priv->base + MLXBF_GIGE_RX_CQ_BASE); +} + +static bool mlxbf_gige_rx_packet(struct mlxbf_gige *priv, int *rx_pkts) +{ + struct net_device *netdev = priv->netdev; + struct sk_buff *skb = NULL, *rx_skb; + u16 rx_pi_rem, rx_ci_rem; + dma_addr_t *rx_wqe_addr; + dma_addr_t rx_buf_dma; + u64 *rx_cqe_addr; + u64 datalen; + u64 rx_cqe; + u16 rx_ci; + u16 rx_pi; + + /* Index into RX buffer array is rx_pi w/wrap based on RX_CQE_SIZE */ + rx_pi = readq(priv->base + MLXBF_GIGE_RX_WQE_PI); + rx_pi_rem = rx_pi % priv->rx_q_entries; + + rx_wqe_addr = priv->rx_wqe_base + rx_pi_rem; + rx_cqe_addr = priv->rx_cqe_base + rx_pi_rem; + rx_cqe = *rx_cqe_addr; + + if ((!!(rx_cqe & MLXBF_GIGE_RX_CQE_VALID_MASK)) != priv->valid_polarity) + return false; + + if ((rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MASK) == 0) { + /* Packet is OK, increment stats */ + datalen = rx_cqe & MLXBF_GIGE_RX_CQE_PKT_LEN_MASK; + netdev->stats.rx_packets++; + netdev->stats.rx_bytes += datalen; + + skb = priv->rx_skb[rx_pi_rem]; + + skb_put(skb, datalen); + + skb->ip_summed = CHECKSUM_NONE; /* device did not checksum packet */ + + skb->protocol = eth_type_trans(skb, netdev); + + /* Alloc another RX SKB for this same index */ + rx_skb = mlxbf_gige_alloc_skb(priv, MLXBF_GIGE_DEFAULT_BUF_SZ, + &rx_buf_dma, DMA_FROM_DEVICE); + if (!rx_skb) + return false; + priv->rx_skb[rx_pi_rem] = rx_skb; + dma_unmap_single(priv->dev, *rx_wqe_addr, + MLXBF_GIGE_DEFAULT_BUF_SZ, DMA_FROM_DEVICE); + *rx_wqe_addr = rx_buf_dma; + } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_MAC_ERR) { + priv->stats.rx_mac_errors++; + } else if (rx_cqe & MLXBF_GIGE_RX_CQE_PKT_STATUS_TRUNCATED) { + priv->stats.rx_truncate_errors++; + } + + /* Let hardware know we've replenished one buffer */ + rx_pi++; + + /* Ensure completion of all writes before notifying HW of replenish */ + wmb(); + writeq(rx_pi, priv->base + MLXBF_GIGE_RX_WQE_PI); + + (*rx_pkts)++; + + rx_pi_rem = rx_pi % priv->rx_q_entries; + if (rx_pi_rem == 0) + priv->valid_polarity ^= 1; + rx_ci = readq(priv->base + MLXBF_GIGE_RX_CQE_PACKET_CI); + rx_ci_rem = rx_ci % priv->rx_q_entries; + + if (skb) + netif_receive_skb(skb); + + return rx_pi_rem != rx_ci_rem; +} + +/* Driver poll() function called by NAPI infrastructure */ +int mlxbf_gige_poll(struct napi_struct *napi, int budget) +{ + struct mlxbf_gige *priv; + bool remaining_pkts; + int work_done = 0; + u64 data; + + priv = container_of(napi, struct mlxbf_gige, napi); + + mlxbf_gige_handle_tx_complete(priv); + + do { + remaining_pkts = mlxbf_gige_rx_packet(priv, &work_done); + } while (remaining_pkts && work_done < budget); + + /* If amount of work done < budget, turn off NAPI polling + * via napi_complete_done(napi, work_done) and then + * re-enable interrupts. + */ + if (work_done < budget && napi_complete_done(napi, work_done)) { + /* Clear MLXBF_GIGE_INT_MASK 'receive pkt' bit to + * indicate receive readiness + */ + data = readq(priv->base + MLXBF_GIGE_INT_MASK); + data &= ~MLXBF_GIGE_INT_MASK_RX_RECEIVE_PACKET; + writeq(data, priv->base + MLXBF_GIGE_INT_MASK); + } + + return work_done; +} diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c new file mode 100644 index 000000000000..04982e888c63 --- /dev/null +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_tx.c @@ -0,0 +1,284 @@ +// SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause + +/* Packet transmit logic for Mellanox Gigabit Ethernet driver + * + * Copyright (C) 2020-2021 NVIDIA CORPORATION & AFFILIATES + */ + +#include + +#include "mlxbf_gige.h" +#include "mlxbf_gige_regs.h" + +/* Transmit Initialization + * 1) Allocates TX WQE array using coherent DMA mapping + * 2) Allocates TX completion counter using coherent DMA mapping + */ +int mlxbf_gige_tx_init(struct mlxbf_gige *priv) +{ + size_t size; + + size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; + priv->tx_wqe_base = dma_alloc_coherent(priv->dev, size, + &priv->tx_wqe_base_dma, + GFP_KERNEL); + if (!priv->tx_wqe_base) + return -ENOMEM; + + priv->tx_wqe_next = priv->tx_wqe_base; + + /* Write TX WQE base address into MMIO reg */ + writeq(priv->tx_wqe_base_dma, priv->base + MLXBF_GIGE_TX_WQ_BASE); + + /* Allocate address for TX completion count */ + priv->tx_cc = dma_alloc_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, + &priv->tx_cc_dma, GFP_KERNEL); + if (!priv->tx_cc) { + dma_free_coherent(priv->dev, size, + priv->tx_wqe_base, priv->tx_wqe_base_dma); + return -ENOMEM; + } + + /* Write TX CC base address into MMIO reg */ + writeq(priv->tx_cc_dma, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); + + writeq(ilog2(priv->tx_q_entries), + priv->base + MLXBF_GIGE_TX_WQ_SIZE_LOG2); + + priv->prev_tx_ci = 0; + priv->tx_pi = 0; + + return 0; +} + +/* Transmit Deinitialization + * This routine will free allocations done by mlxbf_gige_tx_init(), + * namely the TX WQE array and the TX completion counter + */ +void mlxbf_gige_tx_deinit(struct mlxbf_gige *priv) +{ + u64 *tx_wqe_addr; + size_t size; + int i; + + tx_wqe_addr = priv->tx_wqe_base; + + for (i = 0; i < priv->tx_q_entries; i++) { + if (priv->tx_skb[i]) { + dma_unmap_single(priv->dev, *tx_wqe_addr, + priv->tx_skb[i]->len, DMA_TO_DEVICE); + dev_kfree_skb(priv->tx_skb[i]); + priv->tx_skb[i] = NULL; + } + tx_wqe_addr += 2; + } + + size = MLXBF_GIGE_TX_WQE_SZ * priv->tx_q_entries; + dma_free_coherent(priv->dev, size, + priv->tx_wqe_base, priv->tx_wqe_base_dma); + + dma_free_coherent(priv->dev, MLXBF_GIGE_TX_CC_SZ, + priv->tx_cc, priv->tx_cc_dma); + + priv->tx_wqe_base = NULL; + priv->tx_wqe_base_dma = 0; + priv->tx_cc = NULL; + priv->tx_cc_dma = 0; + priv->tx_wqe_next = NULL; + writeq(0, priv->base + MLXBF_GIGE_TX_WQ_BASE); + writeq(0, priv->base + MLXBF_GIGE_TX_CI_UPDATE_ADDRESS); +} + +/* Function that returns status of TX ring: + * 0: TX ring is full, i.e. there are no + * available un-used entries in TX ring. + * non-null: TX ring is not full, i.e. there are + * some available entries in TX ring. + * The non-null value is a measure of + * how many TX entries are available, but + * it is not the exact number of available + * entries (see below). + * + * The algorithm makes the assumption that if + * (prev_tx_ci == tx_pi) then the TX ring is empty. + * An empty ring actually has (tx_q_entries-1) + * entries, which allows the algorithm to differentiate + * the case of an empty ring vs. a full ring. + */ +static u16 mlxbf_gige_tx_buffs_avail(struct mlxbf_gige *priv) +{ + unsigned long flags; + u16 avail; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->prev_tx_ci == priv->tx_pi) + avail = priv->tx_q_entries - 1; + else + avail = ((priv->tx_q_entries + priv->prev_tx_ci - priv->tx_pi) + % priv->tx_q_entries) - 1; + + spin_unlock_irqrestore(&priv->lock, flags); + + return avail; +} + +bool mlxbf_gige_handle_tx_complete(struct mlxbf_gige *priv) +{ + struct net_device_stats *stats; + u16 tx_wqe_index; + u64 *tx_wqe_addr; + u64 tx_status; + u16 tx_ci; + + tx_status = readq(priv->base + MLXBF_GIGE_TX_STATUS); + if (tx_status & MLXBF_GIGE_TX_STATUS_DATA_FIFO_FULL) + priv->stats.tx_fifo_full++; + tx_ci = readq(priv->base + MLXBF_GIGE_TX_CONSUMER_INDEX); + stats = &priv->netdev->stats; + + /* Transmit completion logic needs to loop until the completion + * index (in SW) equals TX consumer index (from HW). These + * parameters are unsigned 16-bit values and the wrap case needs + * to be supported, that is TX consumer index wrapped from 0xFFFF + * to 0 while TX completion index is still < 0xFFFF. + */ + for (; priv->prev_tx_ci != tx_ci; priv->prev_tx_ci++) { + tx_wqe_index = priv->prev_tx_ci % priv->tx_q_entries; + /* Each TX WQE is 16 bytes. The 8 MSB store the 2KB TX + * buffer address and the 8 LSB contain information + * about the TX WQE. + */ + tx_wqe_addr = priv->tx_wqe_base + + (tx_wqe_index * MLXBF_GIGE_TX_WQE_SZ_QWORDS); + + stats->tx_packets++; + stats->tx_bytes += MLXBF_GIGE_TX_WQE_PKT_LEN(tx_wqe_addr); + + dma_unmap_single(priv->dev, *tx_wqe_addr, + priv->tx_skb[tx_wqe_index]->len, DMA_TO_DEVICE); + dev_consume_skb_any(priv->tx_skb[tx_wqe_index]); + priv->tx_skb[tx_wqe_index] = NULL; + + /* Ensure completion of updates across all cores */ + mb(); + } + + /* Since the TX ring was likely just drained, check if TX queue + * had previously been stopped and now that there are TX buffers + * available the TX queue can be awakened. + */ + if (netif_queue_stopped(priv->netdev) && + mlxbf_gige_tx_buffs_avail(priv)) + netif_wake_queue(priv->netdev); + + return true; +} + +/* Function to advance the tx_wqe_next pointer to next TX WQE */ +void mlxbf_gige_update_tx_wqe_next(struct mlxbf_gige *priv) +{ + /* Advance tx_wqe_next pointer */ + priv->tx_wqe_next += MLXBF_GIGE_TX_WQE_SZ_QWORDS; + + /* Check if 'next' pointer is beyond end of TX ring */ + /* If so, set 'next' back to 'base' pointer of ring */ + if (priv->tx_wqe_next == (priv->tx_wqe_base + + (priv->tx_q_entries * MLXBF_GIGE_TX_WQE_SZ_QWORDS))) + priv->tx_wqe_next = priv->tx_wqe_base; +} + +netdev_tx_t mlxbf_gige_start_xmit(struct sk_buff *skb, + struct net_device *netdev) +{ + struct mlxbf_gige *priv = netdev_priv(netdev); + long buff_addr, start_dma_page, end_dma_page; + struct sk_buff *tx_skb; + dma_addr_t tx_buf_dma; + unsigned long flags; + u64 *tx_wqe_addr; + u64 word2; + + /* If needed, linearize TX SKB as hardware DMA expects this */ + if (skb->len > MLXBF_GIGE_DEFAULT_BUF_SZ || skb_linearize(skb)) { + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + buff_addr = (long)skb->data; + start_dma_page = buff_addr >> MLXBF_GIGE_DMA_PAGE_SHIFT; + end_dma_page = (buff_addr + skb->len - 1) >> MLXBF_GIGE_DMA_PAGE_SHIFT; + + /* Verify that payload pointer and data length of SKB to be + * transmitted does not violate the hardware DMA limitation. + */ + if (start_dma_page != end_dma_page) { + /* DMA operation would fail as-is, alloc new aligned SKB */ + tx_skb = mlxbf_gige_alloc_skb(priv, skb->len, + &tx_buf_dma, DMA_TO_DEVICE); + if (!tx_skb) { + /* Free original skb, could not alloc new aligned SKB */ + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + skb_put_data(tx_skb, skb->data, skb->len); + + /* Free the original SKB */ + dev_kfree_skb(skb); + } else { + tx_skb = skb; + tx_buf_dma = dma_map_single(priv->dev, skb->data, + skb->len, DMA_TO_DEVICE); + if (dma_mapping_error(priv->dev, tx_buf_dma)) { + dev_kfree_skb(skb); + netdev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + } + + /* Get address of TX WQE */ + tx_wqe_addr = priv->tx_wqe_next; + + mlxbf_gige_update_tx_wqe_next(priv); + + /* Put PA of buffer address into first 64-bit word of TX WQE */ + *tx_wqe_addr = tx_buf_dma; + + /* Set TX WQE pkt_len appropriately + * NOTE: GigE silicon will automatically pad up to + * minimum packet length if needed. + */ + word2 = tx_skb->len & MLXBF_GIGE_TX_WQE_PKT_LEN_MASK; + + /* Write entire 2nd word of TX WQE */ + *(tx_wqe_addr + 1) = word2; + + spin_lock_irqsave(&priv->lock, flags); + priv->tx_skb[priv->tx_pi % priv->tx_q_entries] = tx_skb; + priv->tx_pi++; + spin_unlock_irqrestore(&priv->lock, flags); + + if (!netdev_xmit_more()) { + /* Create memory barrier before write to TX PI */ + wmb(); + writeq(priv->tx_pi, priv->base + MLXBF_GIGE_TX_PRODUCER_INDEX); + } + + /* Check if the last TX entry was just used */ + if (!mlxbf_gige_tx_buffs_avail(priv)) { + /* TX ring is full, inform stack */ + netif_stop_queue(netdev); + + /* Since there is no separate "TX complete" interrupt, need + * to explicitly schedule NAPI poll. This will trigger logic + * which processes TX completions, and will hopefully drain + * the TX ring allowing the TX queue to be awakened. + */ + napi_schedule(&priv->napi); + } + + return NETDEV_TX_OK; +} From patchwork Fri Jul 9 19:08:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Asmaa Mnebhi X-Patchwork-Id: 1503334 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4GM2lv4nBpz9sRN; Sat, 10 Jul 2021 05:09:47 +1000 (AEST) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vsa-0003j6-T7; Fri, 09 Jul 2021 19:09:41 +0000 Received: from mail-il-dmz.mellanox.com ([193.47.165.129] helo=mellanox.co.il) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1m1vs2-0003K1-4x for kernel-team@lists.ubuntu.com; Fri, 09 Jul 2021 19:09:06 +0000 Received: from Internal Mail-Server by MTLPINE1 (envelope-from asmaa@mellanox.com) with SMTP; 9 Jul 2021 22:09:01 +0300 Received: from farm-0002.mtbu.labs.mlnx (farm-0002.mtbu.labs.mlnx [10.15.2.32]) by mtbu-labmailer.labs.mlnx (8.14.4/8.14.4) with ESMTP id 169J90j6030262; Fri, 9 Jul 2021 15:09:00 -0400 Received: (from asmaa@localhost) by farm-0002.mtbu.labs.mlnx (8.14.7/8.13.8/Submit) id 169J90ri005476; Fri, 9 Jul 2021 15:09:00 -0400 From: Asmaa Mnebhi To: kernel-team@lists.ubuntu.com Subject: [SRU][F][PULL][PATCH v2 23/23] mlxbf-gige upstream effort: update gpio-mlxbf2.c and mlxbf-gige.c Date: Fri, 9 Jul 2021 15:08:30 -0400 Message-Id: <20210709190830.5405-24-asmaa@nvidia.com> X-Mailer: git-send-email 2.30.1 In-Reply-To: <20210709190830.5405-1-asmaa@nvidia.com> References: <20210709190830.5405-1-asmaa@nvidia.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: asmaa@nvidia.com, davthompson@nvidia.com Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" BugLink: https://bugs.launchpad.net/bugs/1934923 The upstreamed version of the mlxbf-gige driver removes dependencies on the gpio-mlxbf2 driver so the latter needs to be updated accordingly. Add the set_ring size function to mlxbf-gige which was left out from the upstreamed version. Signed-off-by: Asmaa Mnebhi Reviewed-by: David Thompson --- drivers/gpio/gpio-mlxbf2.c | 361 ++++++++++++------ .../mellanox/mlxbf_gige/mlxbf_gige_ethtool.c | 38 ++ .../mellanox/mlxbf_gige/mlxbf_gige_main.c | 21 + 3 files changed, 295 insertions(+), 125 deletions(-) diff --git a/drivers/gpio/gpio-mlxbf2.c b/drivers/gpio/gpio-mlxbf2.c index 0dc9747c79e4..905fe7766e19 100644 --- a/drivers/gpio/gpio-mlxbf2.c +++ b/drivers/gpio/gpio-mlxbf2.c @@ -1,25 +1,27 @@ // SPDX-License-Identifier: GPL-2.0-only or BSD-3-Clause /* - * Copyright (c) 2020 NVIDIA Corporation. + * Copyright (c) 2020-2021 NVIDIA Corporation. */ #include #include #include #include +#include #include #include #include #include -#include #include #include #include +#include #include #include #include -#include + +#define DRV_VERSION "1.4" /* * There are 3 YU GPIO blocks: @@ -30,6 +32,13 @@ */ #define MLXBF2_GPIO_MAX_PINS_PER_BLOCK 32 +typedef enum { + GPIO_BLOCK0 = 0, + GPIO_BLOCK1 = 1, + GPIO_BLOCK2 = 2, + GPIO_BLOCK16 = 16 +} yu_gpio_block; + /* * arm_gpio_lock register: * bit[31] lock status: active if set @@ -42,6 +51,9 @@ #define YU_ARM_GPIO_LOCK_ACQUIRE 0xd42f #define YU_ARM_GPIO_LOCK_RELEASE 0x0 +#define YU_CAUSE_GPIO_ADDR 0x2801530 +#define YU_CAUSE_GPIO_ADDR_SIZE 0x4 + /* * gpio[x] block registers and their offset */ @@ -50,6 +62,8 @@ #define YU_GPIO_MODE0 0x0c #define YU_GPIO_DATASET 0x14 #define YU_GPIO_DATACLEAR 0x18 +#define YU_GPIO_FUNCTIONAL_ENABLE1 0x24 +#define YU_GPIO_FUNCTIONAL_ENABLE0 0x28 #define YU_GPIO_CAUSE_RISE_EN 0x44 #define YU_GPIO_CAUSE_FALL_EN 0x48 #define YU_GPIO_MODE1_CLEAR 0x50 @@ -59,16 +73,6 @@ #define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0 0x80 #define YU_GPIO_CAUSE_OR_EVTEN0 0x94 #define YU_GPIO_CAUSE_OR_CLRCAUSE 0x98 -#define YU_GPIO16_LOW_PWR_BIT 0 -#define YU_GPIO0_RST_BIT 7 -#define YU_GPIO_CAUSE_OR_CAUSE_EVTEN0_MASK(gpio_bit) BIT(gpio_bit) -#define YU_GPIO_CAUSE_OR_EVTEN0_MASK(gpio_bit) BIT(gpio_bit) -#define YU_GPIO_CAUSE_RISE_EN_MASK(gpio_bit) BIT(gpio_bit) -#define YU_GPIO_CAUSE_FALL_EN_MASK(gpio_bit) BIT(gpio_bit) -#define YU_GPIO_CAUSE_OR_CLRCAUSE_MASK(gpio_bit) BIT(gpio_bit) -#define YU_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK 0x10 -#define YU_GPIO_CAUSE_IRQ_IS_SET(val) \ - (val & YU_CAUSE_RSH_COALESCE0_GPIO_CAUSE_MASK) #ifdef CONFIG_PM struct mlxbf2_gpio_context_save_regs { @@ -77,28 +81,25 @@ struct mlxbf2_gpio_context_save_regs { }; #endif -#define RST_GPIO_PIN 7 -#define LOW_PWR_GPIO_PIN 71 -#define MAX_HOST_GPIOS LOW_PWR_GPIO_PIN - /* BlueField-2 gpio block context structure. */ struct mlxbf2_gpio_context { struct gpio_chip gc; + struct irq_chip irq_chip; /* YU GPIO blocks address */ void __iomem *gpio_io; - /* GPIO pin responsible for low power mode */ + /* YU cause gpio arm coalesce0 address */ + void __iomem *cause_gpio_arm_coalesce0_io; + + /* YU GPIO pin responsible for low power mode */ unsigned long low_pwr_pin; - /* GPIO pin responsible for soft reset */ + /* YU GPIO pin responsible for soft reset */ unsigned long rst_pin; - /* - * Bit within the YU GPIO block that's conifgued - * as an interrupt. - */ - u32 gpio_int_bit; + /* YU GPIO block interrupt mask */ + u32 gpio_int_mask; /* Worker function */ struct work_struct send_work; @@ -128,6 +129,19 @@ static struct mlxbf2_gpio_param yu_arm_gpio_lock_param = { .lock = &yu_arm_gpio_lock_mutex, }; +static struct resource yu_cause_gpio_res = { + .start = YU_CAUSE_GPIO_ADDR, + .end = YU_CAUSE_GPIO_ADDR + YU_CAUSE_GPIO_ADDR_SIZE - 1, + .name = "YU_CAUSE_GPIO", +}; + +static DEFINE_MUTEX(yu_cause_gpio_mutex); + +static struct mlxbf2_gpio_param yu_cause_gpio_param = { + .res = &yu_cause_gpio_res, + .lock = &yu_cause_gpio_mutex, +}; + /* Request memory region and map yu_arm_gpio_lock resource */ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) { @@ -151,8 +165,8 @@ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) } yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size); - if (IS_ERR(yu_arm_gpio_lock_param.io)) - ret = PTR_ERR(yu_arm_gpio_lock_param.io); + if (!yu_arm_gpio_lock_param.io) + ret = -ENOMEM; exit: mutex_unlock(yu_arm_gpio_lock_param.lock); @@ -160,6 +174,38 @@ static int mlxbf2_gpio_get_lock_res(struct platform_device *pdev) return ret; } +/* Request memory region and map yu cause_gpio_arm.coalesce0 resource */ +static int mlxbf2_gpio_get_yu_cause_gpio_res(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct resource *res; + resource_size_t size; + int ret = 0; + + mutex_lock(yu_cause_gpio_param.lock); + + /* Check if the memory map already exists */ + if (yu_cause_gpio_param.io) + goto exit; + + res = yu_cause_gpio_param.res; + size = resource_size(res); + + if (!devm_request_mem_region(dev, res->start, size, res->name)) { + ret = -EFAULT; + goto exit; + } + + yu_cause_gpio_param.io = devm_ioremap(dev, res->start, size); + if (!yu_cause_gpio_param.io) + ret = -ENOMEM; + +exit: + mutex_unlock(yu_cause_gpio_param.lock); + + return ret; +} + /* * Acquire the YU arm_gpio_lock to be able to change the direction * mode. If the lock_active bit is already set, return an error. @@ -191,6 +237,8 @@ static int mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs) * Release the YU arm_gpio_lock after changing the direction mode. */ static void mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs) + __releases(&gs->gc.bgpio_lock) + __releases(yu_arm_gpio_lock_param.lock) { writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io); spin_unlock(&gs->gc.bgpio_lock); @@ -247,6 +295,7 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip, { struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip); int ret = 0; + u32 val; /* * Although the arm_gpio_lock was set in the probe function, @@ -260,115 +309,152 @@ static int mlxbf2_gpio_direction_output(struct gpio_chip *chip, writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE1_CLEAR); writel(BIT(offset), gs->gpio_io + YU_GPIO_MODE0_SET); + /* + * Set {functional_enable1,functional_enable0}={0,0} + * to give control to software over these GPIOs. + */ + val = readl(gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE1); + val &= ~BIT(offset); + writel(val, gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE1); + val = readl(gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE0); + val &= ~BIT(offset); + writel(val, gs->gpio_io + YU_GPIO_FUNCTIONAL_ENABLE0); + mlxbf2_gpio_lock_release(gs); return ret; } -static void mlxbf2_gpio_irq_disable(struct mlxbf2_gpio_context *gs) +static void mlxbf2_gpio_send_work(struct work_struct *work) +{ +#ifdef CONFIG_ACPI + acpi_bus_generate_netlink_event("button/power.*", "Power Button", + 0x80, 1); +#endif +} + +static u32 mlxbf2_gpio_get_int_mask(struct mlxbf2_gpio_context *gs) { - u32 val; + u32 gpio_int_mask = 0; - spin_lock(&gs->gc.bgpio_lock); - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - if (!val) { - spin_unlock(&gs->gc.bgpio_lock); - /* There is no enabled interrupt */ - return; - } + /* + * Determine bit mask within the yu gpio block. + */ + if (gs->rst_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) + gpio_int_mask |= BIT(gs->rst_pin); + if (gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) + gpio_int_mask = BIT(gs->low_pwr_pin); - val &= ~YU_GPIO_CAUSE_OR_EVTEN0_MASK(gs->gpio_int_bit); - writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - spin_unlock(&gs->gc.bgpio_lock); + return gpio_int_mask; } -static void mlxbf2_gpio_irq_set_type(struct mlxbf2_gpio_context *gs) +static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) { - u32 val; + struct mlxbf2_gpio_context *gs = ptr; + unsigned long gpio_pin; + u32 gpio_block, val; + unsigned long flags; - spin_lock(&gs->gc.bgpio_lock); + spin_lock_irqsave(&gs->gc.bgpio_lock, flags); /* - * The power state gpio interrupt should be detected at rising - * and falling edges. - * - * In the case of low power mode interrupt: - * When it goes from 0 to 1, system should go into low power state - * When it goes from 1 to 0, system should revert to normal state - * - * In the case of soft reset interrupt, trigger interrupt off - * falling edge since it is active low. + * Determine which yu gpio block this interrupt is for. + * Return if the interrupt is not for gpio block 0 or + * gpio block 16. */ - if (gs->low_pwr_pin == LOW_PWR_GPIO_PIN) { - val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); - val |= YU_GPIO_CAUSE_RISE_EN_MASK(gs->gpio_int_bit); - writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); + gpio_block = readl(yu_cause_gpio_param.io); + if (!(gpio_block & BIT(GPIO_BLOCK0)) && + !(gpio_block & BIT(GPIO_BLOCK16))) { + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + return IRQ_NONE; } - val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); - val |= YU_GPIO_CAUSE_FALL_EN_MASK(gs->gpio_int_bit); - writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); + /* + * Check if the interrupt signaled by this yu gpio block is supported. + */ + gpio_pin = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); + if (!(gpio_pin & gs->gpio_int_mask)) { + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); + return IRQ_NONE; + } - spin_unlock(&gs->gc.bgpio_lock); -} + /* + * Clear interrupt when done, otherwise, no further interrupt + * will be triggered. + */ + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + val |= gpio_pin; + writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); -static void mlxbf2_gpio_irq_enable(struct mlxbf2_gpio_context *gs) -{ - u32 val; + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - spin_lock(&gs->gc.bgpio_lock); + if (gpio_block & BIT(GPIO_BLOCK16)) { + if (gpio_pin & BIT(gs->low_pwr_pin)) + schedule_work(&gs->send_work); + } - /* - * Setting the priority for the GPIO interrupt enables the - * interrupt as well - */ - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); - val |= YU_GPIO_CAUSE_OR_EVTEN0_MASK(gs->gpio_int_bit); - writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + if (gpio_block & BIT(GPIO_BLOCK0)) { + if (gpio_pin & BIT(gs->rst_pin)) + emergency_restart(); + } - spin_unlock(&gs->gc.bgpio_lock); + return IRQ_HANDLED; } -static void mlxbf2_gpio_send_work(struct work_struct *work) +static void mlxbf2_gpio_irq_unmask(struct irq_data *data) { - struct mlxbf2_gpio_context *gs; - - gs = container_of(work, struct mlxbf2_gpio_context, send_work); +} - acpi_bus_generate_netlink_event("button/power.*", "Power Button", 0x80, 1); +static void mlxbf2_gpio_irq_mask(struct irq_data *data) +{ } -static irqreturn_t mlxbf2_gpio_irq_handler(int irq, void *ptr) +static int mlxbf2_gpio_init_hw(struct gpio_chip *gc) { - struct mlxbf2_gpio_context *gs = ptr; + struct mlxbf2_gpio_context *gs = gpiochip_get_data(gc); unsigned long flags; u32 val; spin_lock_irqsave(&gs->gc.bgpio_lock, flags); - /* - * Check if this interrupt is for bit 0 of yu.gpio[16] - * or bit 7 of yu.gpio[0]. - * Return if it is not. - */ - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CAUSE_EVTEN0); - if (!(val & YU_GPIO_CAUSE_OR_CAUSE_EVTEN0_MASK(gs->gpio_int_bit))) { - spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - return IRQ_NONE; + /* Clear all interrupts */ + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + val |= gs->gpio_int_mask; + writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + + if (gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) { + val = readl(gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); + val |= gs->gpio_int_mask; + writel(val, gs->gpio_io + YU_GPIO_CAUSE_RISE_EN); } + val = readl(gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); + val |= gs->gpio_int_mask; + writel(val, gs->gpio_io + YU_GPIO_CAUSE_FALL_EN); + /* - * Clear interrupt when done, otherwise, no further interrupt - * will be triggered. + * Setting the priority for the GPIO interrupt enables the + * interrupt as well */ - val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); - val |= YU_GPIO_CAUSE_OR_CLRCAUSE_MASK(gs->gpio_int_bit); - writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_CLRCAUSE); + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + val |= gs->gpio_int_mask; + writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); - schedule_work(&gs->send_work); + return 0; +} - return IRQ_HANDLED; +static void mlxbf2_gpio_disable_int(struct mlxbf2_gpio_context *gs) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&gs->gc.bgpio_lock, flags); + val = readl(gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + val &= ~gs->gpio_int_mask; + writel(val, gs->gpio_io + YU_GPIO_CAUSE_OR_EVTEN0); + spin_unlock_irqrestore(&gs->gc.bgpio_lock, flags); } /* BlueField-2 GPIO driver initialization routine. */ @@ -377,18 +463,21 @@ mlxbf2_gpio_probe(struct platform_device *pdev) { struct mlxbf2_gpio_context *gs; struct device *dev = &pdev->dev; + struct gpio_irq_chip *girq; unsigned int low_pwr_pin; unsigned int rst_pin; struct gpio_chip *gc; struct resource *res; unsigned int npins; + const char *name; int ret, irq; + name = dev_name(dev); + gs = devm_kzalloc(dev, sizeof(*gs), GFP_KERNEL); if (!gs) return -ENOMEM; - spin_lock_init(&gs->gc.bgpio_lock); INIT_WORK(&gs->send_work, mlxbf2_gpio_send_work); /* YU GPIO block address */ @@ -406,6 +495,12 @@ mlxbf2_gpio_probe(struct platform_device *pdev) return ret; } + ret = mlxbf2_gpio_get_yu_cause_gpio_res(pdev); + if (ret) { + dev_err(dev, "Failed to get yu cause_gpio_arm.coalesce0 resource\n"); + return ret; + } + if (device_property_read_u32(dev, "npins", &npins)) npins = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; @@ -419,55 +514,68 @@ mlxbf2_gpio_probe(struct platform_device *pdev) NULL, 0); + if (ret) { + dev_err(dev, "bgpio_init failed\n"); + return ret; + } + gc->direction_input = mlxbf2_gpio_direction_input; gc->direction_output = mlxbf2_gpio_direction_output; gc->ngpio = npins; gc->owner = THIS_MODULE; - ret = devm_gpiochip_add_data(dev, &gs->gc, gs); - if (ret) { - dev_err(dev, "Failed adding memory mapped gpiochip\n"); - return ret; - } - platform_set_drvdata(pdev, gs); - /* - * OCP3.0 supports the AUX power mode interrupt on bit 0 of yu.gpio[16]. - * BlueSphere and the PRIS boards support the rebooot interrupt on bit - * 7 of yu.gpio[0]. + * OCP3.0 supports the low power mode interrupt. */ ret = device_property_read_u32(dev, "low-pwr-pin", &low_pwr_pin); if (ret < 0) - low_pwr_pin = MAX_HOST_GPIOS + 1; + low_pwr_pin = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; + /* + * BlueSphere and the PRIS boards support the reset interrupt. + */ ret = device_property_read_u32(dev, "rst-pin", &rst_pin); if (ret < 0) - rst_pin = MAX_HOST_GPIOS + 1; + rst_pin = MLXBF2_GPIO_MAX_PINS_PER_BLOCK; gs->low_pwr_pin = low_pwr_pin; gs->rst_pin = rst_pin; - - if ((low_pwr_pin == LOW_PWR_GPIO_PIN) || (rst_pin == RST_GPIO_PIN)) { - if (rst_pin == RST_GPIO_PIN) - gs->gpio_int_bit = YU_GPIO0_RST_BIT; - else - gs->gpio_int_bit = YU_GPIO16_LOW_PWR_BIT; + gs->gpio_int_mask = mlxbf2_gpio_get_int_mask(gs); + + if (gs->gpio_int_mask) { + gs->irq_chip.name = name; + gs->irq_chip.irq_mask = mlxbf2_gpio_irq_mask; + gs->irq_chip.irq_unmask = mlxbf2_gpio_irq_unmask; + + girq = &gs->gc.irq; + girq->chip = &gs->irq_chip; + /* This will let us handle the parent IRQ in the driver */ + girq->parent_handler = NULL; + girq->num_parents = 0; + girq->parents = NULL; + girq->default_type = IRQ_TYPE_NONE; + girq->handler = handle_simple_irq; + girq->init_hw = mlxbf2_gpio_init_hw; irq = platform_get_irq(pdev, 0); - /* - * For now, no need to check if interrupt was previously allocated - * by another gpio block. - */ + if (irq < 0) + return irq; ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler, - IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED, dev_name(dev), gs); + IRQF_ONESHOT | IRQF_SHARED, name, gs); if (ret) { - dev_err(dev, "IRQ handler registering failed (%d)\n", ret); + dev_err(dev, "failed to request IRQ"); return ret; } - mlxbf2_gpio_irq_set_type(gs); - mlxbf2_gpio_irq_enable(gs); } + ret = devm_gpiochip_add_data(dev, &gs->gc, gs); + if (ret) { + dev_err(dev, "Failed adding memory mapped gpiochip\n"); + return ret; + } + platform_set_drvdata(pdev, gs); + + return 0; } @@ -477,8 +585,10 @@ mlxbf2_gpio_remove(struct platform_device *pdev) struct mlxbf2_gpio_context *gs; gs = platform_get_drvdata(pdev); - if ((gs->low_pwr_pin == LOW_PWR_GPIO_PIN) || (gs->rst_pin == RST_GPIO_PIN)) { - mlxbf2_gpio_irq_disable(gs); + + if ((gs->low_pwr_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK) || + (gs->rst_pin != MLXBF2_GPIO_MAX_PINS_PER_BLOCK)) { + mlxbf2_gpio_disable_int(gs); flush_work(&gs->send_work); } @@ -512,7 +622,7 @@ static int mlxbf2_gpio_resume(struct platform_device *pdev) } #endif -static const struct acpi_device_id mlxbf2_gpio_acpi_match[] = { +static const struct acpi_device_id __maybe_unused mlxbf2_gpio_acpi_match[] = { { "MLNXBF22", 0 }, {}, }; @@ -534,5 +644,6 @@ static struct platform_driver mlxbf2_gpio_driver = { module_platform_driver(mlxbf2_gpio_driver); MODULE_DESCRIPTION("Mellanox BlueField-2 GPIO Driver"); -MODULE_AUTHOR("Mellanox Technologies"); +MODULE_AUTHOR("Asmaa Mnebhi "); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(DRV_VERSION); diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c index 92b798f8e73a..24a32ffee4e4 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_ethtool.c @@ -44,6 +44,43 @@ static void mlxbf_gige_get_ringparam(struct net_device *netdev, ering->tx_pending = priv->tx_q_entries; } +static int mlxbf_gige_set_ringparam(struct net_device *netdev, + struct ethtool_ringparam *ering) +{ + const struct net_device_ops *ops = netdev->netdev_ops; + struct mlxbf_gige *priv = netdev_priv(netdev); + int new_rx_q_entries, new_tx_q_entries; + + /* Device does not have separate queues for small/large frames */ + if (ering->rx_mini_pending || ering->rx_jumbo_pending) + return -EINVAL; + + /* Round up to supported values */ + new_rx_q_entries = roundup_pow_of_two(ering->rx_pending); + new_tx_q_entries = roundup_pow_of_two(ering->tx_pending); + + /* Check against min values, core checks against max values */ + if (new_tx_q_entries < MLXBF_GIGE_MIN_TXQ_SZ || + new_rx_q_entries < MLXBF_GIGE_MIN_RXQ_SZ) + return -EINVAL; + + /* If queue sizes did not change, exit now */ + if (new_rx_q_entries == priv->rx_q_entries && + new_tx_q_entries == priv->tx_q_entries) + return 0; + + if (netif_running(netdev)) + ops->ndo_stop(netdev); + + priv->rx_q_entries = new_rx_q_entries; + priv->tx_q_entries = new_tx_q_entries; + + if (netif_running(netdev)) + ops->ndo_open(netdev); + + return 0; +} + static const struct { const char string[ETH_GSTRING_LEN]; } mlxbf_gige_ethtool_stats_keys[] = { @@ -126,6 +163,7 @@ static void mlxbf_gige_get_pauseparam(struct net_device *netdev, const struct ethtool_ops mlxbf_gige_ethtool_ops = { .get_link = ethtool_op_get_link, .get_ringparam = mlxbf_gige_get_ringparam, + .set_ringparam = mlxbf_gige_set_ringparam, .get_regs_len = mlxbf_gige_get_regs_len, .get_regs = mlxbf_gige_get_regs, .get_strings = mlxbf_gige_get_strings, diff --git a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c index a0a059e0154f..7caa1ca4461f 100644 --- a/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c +++ b/drivers/net/ethernet/mellanox/mlxbf_gige/mlxbf_gige_main.c @@ -20,6 +20,12 @@ #include "mlxbf_gige_regs.h" #define DRV_NAME "mlxbf_gige" +#define DRV_VERSION 1.24 + +/* This setting defines the version of the ACPI table + * content that is compatible with this driver version. + */ +#define MLXBF_GIGE_ACPI_TABLE_VERSION 2 /* Allocate SKB whose payload pointer aligns with the Bluefield * hardware DMA limitation, i.e. DMA operation can't cross @@ -276,10 +282,24 @@ static int mlxbf_gige_probe(struct platform_device *pdev) void __iomem *llu_base; void __iomem *plu_base; void __iomem *base; + u32 version; u64 control; int addr; int err; + version = 0; + err = device_property_read_u32(&pdev->dev, "version", &version); + if (err) { + dev_err(&pdev->dev, "ACPI table version not found\n"); + return -EINVAL; + } + + if (version != MLXBF_GIGE_ACPI_TABLE_VERSION) { + dev_err(&pdev->dev, "ACPI table version mismatch: expected %d found %d\n", + MLXBF_GIGE_ACPI_TABLE_VERSION, version); + return -EINVAL; + } + mac_res = platform_get_resource(pdev, IORESOURCE_MEM, MLXBF_GIGE_RES_MAC); if (!mac_res) return -ENXIO; @@ -450,3 +470,4 @@ MODULE_DESCRIPTION("Mellanox BlueField SoC Gigabit Ethernet Driver"); MODULE_AUTHOR("David Thompson "); MODULE_AUTHOR("Asmaa Mnebhi "); MODULE_LICENSE("Dual BSD/GPL"); +MODULE_VERSION(__stringify(DRV_VERSION));