162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* Copyright (c) 2022 Amarula Solutions, Dario Binacchi <dario.binacchi@amarulasolutions.com> 362306a36Sopenharmony_ci * Copyright (c) 2022 Pengutronix, Marc Kleine-Budde <kernel@pengutronix.de> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/can/dev.h> 862306a36Sopenharmony_ci#include <linux/ethtool.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/netdevice.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include "flexcan.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_cistatic const char flexcan_priv_flags_strings[][ETH_GSTRING_LEN] = { 1662306a36Sopenharmony_ci#define FLEXCAN_PRIV_FLAGS_RX_RTR BIT(0) 1762306a36Sopenharmony_ci "rx-rtr", 1862306a36Sopenharmony_ci}; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic void 2162306a36Sopenharmony_ciflexcan_get_ringparam(struct net_device *ndev, struct ethtool_ringparam *ring, 2262306a36Sopenharmony_ci struct kernel_ethtool_ringparam *kernel_ring, 2362306a36Sopenharmony_ci struct netlink_ext_ack *ext_ack) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(ndev); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci ring->rx_max_pending = priv->mb_count; 2862306a36Sopenharmony_ci ring->tx_max_pending = priv->mb_count; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci if (priv->devtype_data.quirks & FLEXCAN_QUIRK_USE_RX_MAILBOX) 3162306a36Sopenharmony_ci ring->rx_pending = priv->offload.mb_last - 3262306a36Sopenharmony_ci priv->offload.mb_first + 1; 3362306a36Sopenharmony_ci else 3462306a36Sopenharmony_ci ring->rx_pending = 6; /* RX-FIFO depth is fixed */ 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci /* the drive currently supports only on TX buffer */ 3762306a36Sopenharmony_ci ring->tx_pending = 1; 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void 4162306a36Sopenharmony_ciflexcan_get_strings(struct net_device *ndev, u32 stringset, u8 *data) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci switch (stringset) { 4462306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 4562306a36Sopenharmony_ci memcpy(data, flexcan_priv_flags_strings, 4662306a36Sopenharmony_ci sizeof(flexcan_priv_flags_strings)); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic u32 flexcan_get_priv_flags(struct net_device *ndev) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci const struct flexcan_priv *priv = netdev_priv(ndev); 5362306a36Sopenharmony_ci u32 priv_flags = 0; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (flexcan_active_rx_rtr(priv)) 5662306a36Sopenharmony_ci priv_flags |= FLEXCAN_PRIV_FLAGS_RX_RTR; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return priv_flags; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int flexcan_set_priv_flags(struct net_device *ndev, u32 priv_flags) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct flexcan_priv *priv = netdev_priv(ndev); 6462306a36Sopenharmony_ci u32 quirks = priv->devtype_data.quirks; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci if (priv_flags & FLEXCAN_PRIV_FLAGS_RX_RTR) { 6762306a36Sopenharmony_ci if (flexcan_supports_rx_mailbox_rtr(priv)) 6862306a36Sopenharmony_ci quirks |= FLEXCAN_QUIRK_USE_RX_MAILBOX; 6962306a36Sopenharmony_ci else if (flexcan_supports_rx_fifo(priv)) 7062306a36Sopenharmony_ci quirks &= ~FLEXCAN_QUIRK_USE_RX_MAILBOX; 7162306a36Sopenharmony_ci else 7262306a36Sopenharmony_ci quirks |= FLEXCAN_QUIRK_USE_RX_MAILBOX; 7362306a36Sopenharmony_ci } else { 7462306a36Sopenharmony_ci if (flexcan_supports_rx_mailbox(priv)) 7562306a36Sopenharmony_ci quirks |= FLEXCAN_QUIRK_USE_RX_MAILBOX; 7662306a36Sopenharmony_ci else 7762306a36Sopenharmony_ci quirks &= ~FLEXCAN_QUIRK_USE_RX_MAILBOX; 7862306a36Sopenharmony_ci } 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci if (quirks != priv->devtype_data.quirks && netif_running(ndev)) 8162306a36Sopenharmony_ci return -EBUSY; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci priv->devtype_data.quirks = quirks; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci if (!(priv_flags & FLEXCAN_PRIV_FLAGS_RX_RTR) && 8662306a36Sopenharmony_ci !flexcan_active_rx_rtr(priv)) 8762306a36Sopenharmony_ci netdev_info(ndev, 8862306a36Sopenharmony_ci "Activating RX mailbox mode, cannot receive RTR frames.\n"); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int flexcan_get_sset_count(struct net_device *netdev, int sset) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci switch (sset) { 9662306a36Sopenharmony_ci case ETH_SS_PRIV_FLAGS: 9762306a36Sopenharmony_ci return ARRAY_SIZE(flexcan_priv_flags_strings); 9862306a36Sopenharmony_ci default: 9962306a36Sopenharmony_ci return -EOPNOTSUPP; 10062306a36Sopenharmony_ci } 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ciconst struct ethtool_ops flexcan_ethtool_ops = { 10462306a36Sopenharmony_ci .get_ringparam = flexcan_get_ringparam, 10562306a36Sopenharmony_ci .get_strings = flexcan_get_strings, 10662306a36Sopenharmony_ci .get_priv_flags = flexcan_get_priv_flags, 10762306a36Sopenharmony_ci .set_priv_flags = flexcan_set_priv_flags, 10862306a36Sopenharmony_ci .get_sset_count = flexcan_get_sset_count, 10962306a36Sopenharmony_ci .get_ts_info = ethtool_op_get_ts_info, 11062306a36Sopenharmony_ci}; 111