Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright IBM Corp. 2018
0004  */
0005 
0006 #define KMSG_COMPONENT "qeth"
0007 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
0008 
0009 #include <linux/ethtool.h>
0010 #include "qeth_core.h"
0011 
0012 
0013 #define QETH_TXQ_STAT(_name, _stat) { \
0014     .name = _name, \
0015     .offset = offsetof(struct qeth_out_q_stats, _stat) \
0016 }
0017 
0018 #define QETH_CARD_STAT(_name, _stat) { \
0019     .name = _name, \
0020     .offset = offsetof(struct qeth_card_stats, _stat) \
0021 }
0022 
0023 struct qeth_stats {
0024     char name[ETH_GSTRING_LEN];
0025     unsigned int offset;
0026 };
0027 
0028 static const struct qeth_stats txq_stats[] = {
0029     QETH_TXQ_STAT("IO buffers", bufs),
0030     QETH_TXQ_STAT("IO buffer elements", buf_elements),
0031     QETH_TXQ_STAT("packed IO buffers", bufs_pack),
0032     QETH_TXQ_STAT("skbs", tx_packets),
0033     QETH_TXQ_STAT("packed skbs", skbs_pack),
0034     QETH_TXQ_STAT("SG skbs", skbs_sg),
0035     QETH_TXQ_STAT("HW csum skbs", skbs_csum),
0036     QETH_TXQ_STAT("TSO skbs", skbs_tso),
0037     QETH_TXQ_STAT("linearized skbs", skbs_linearized),
0038     QETH_TXQ_STAT("linearized+error skbs", skbs_linearized_fail),
0039     QETH_TXQ_STAT("TSO bytes", tso_bytes),
0040     QETH_TXQ_STAT("Packing mode switches", packing_mode_switch),
0041     QETH_TXQ_STAT("Queue stopped", stopped),
0042     QETH_TXQ_STAT("Doorbell", doorbell),
0043     QETH_TXQ_STAT("IRQ for frames", coal_frames),
0044     QETH_TXQ_STAT("Completion IRQ", completion_irq),
0045     QETH_TXQ_STAT("Completion yield", completion_yield),
0046     QETH_TXQ_STAT("Completion timer", completion_timer),
0047 };
0048 
0049 static const struct qeth_stats card_stats[] = {
0050     QETH_CARD_STAT("rx0 IO buffers", rx_bufs),
0051     QETH_CARD_STAT("rx0 HW csum skbs", rx_skb_csum),
0052     QETH_CARD_STAT("rx0 SG skbs", rx_sg_skbs),
0053     QETH_CARD_STAT("rx0 SG page frags", rx_sg_frags),
0054     QETH_CARD_STAT("rx0 SG page allocs", rx_sg_alloc_page),
0055     QETH_CARD_STAT("rx0 dropped, no memory", rx_dropped_nomem),
0056     QETH_CARD_STAT("rx0 dropped, bad format", rx_dropped_notsupp),
0057     QETH_CARD_STAT("rx0 dropped, runt", rx_dropped_runt),
0058 };
0059 
0060 #define TXQ_STATS_LEN   ARRAY_SIZE(txq_stats)
0061 #define CARD_STATS_LEN  ARRAY_SIZE(card_stats)
0062 
0063 static void qeth_add_stat_data(u64 **dst, void *src,
0064                    const struct qeth_stats stats[],
0065                    unsigned int size)
0066 {
0067     unsigned int i;
0068     char *stat;
0069 
0070     for (i = 0; i < size; i++) {
0071         stat = (char *)src + stats[i].offset;
0072         **dst = *(u64 *)stat;
0073         (*dst)++;
0074     }
0075 }
0076 
0077 static void qeth_add_stat_strings(u8 **data, const char *prefix,
0078                   const struct qeth_stats stats[],
0079                   unsigned int size)
0080 {
0081     unsigned int i;
0082 
0083     for (i = 0; i < size; i++)
0084         ethtool_sprintf(data, "%s%s", prefix, stats[i].name);
0085 }
0086 
0087 static int qeth_get_sset_count(struct net_device *dev, int stringset)
0088 {
0089     struct qeth_card *card = dev->ml_priv;
0090 
0091     switch (stringset) {
0092     case ETH_SS_STATS:
0093         return CARD_STATS_LEN +
0094                card->qdio.no_out_queues * TXQ_STATS_LEN;
0095     default:
0096         return -EINVAL;
0097     }
0098 }
0099 
0100 static void qeth_get_ethtool_stats(struct net_device *dev,
0101                    struct ethtool_stats *stats, u64 *data)
0102 {
0103     struct qeth_card *card = dev->ml_priv;
0104     unsigned int i;
0105 
0106     qeth_add_stat_data(&data, &card->stats, card_stats, CARD_STATS_LEN);
0107     for (i = 0; i < card->qdio.no_out_queues; i++)
0108         qeth_add_stat_data(&data, &card->qdio.out_qs[i]->stats,
0109                    txq_stats, TXQ_STATS_LEN);
0110 }
0111 
0112 static void __qeth_set_coalesce(struct net_device *dev,
0113                 struct qeth_qdio_out_q *queue,
0114                 struct ethtool_coalesce *coal)
0115 {
0116     WRITE_ONCE(queue->coalesce_usecs, coal->tx_coalesce_usecs);
0117     WRITE_ONCE(queue->max_coalesced_frames, coal->tx_max_coalesced_frames);
0118 
0119     if (coal->tx_coalesce_usecs &&
0120         netif_running(dev) &&
0121         !qeth_out_queue_is_empty(queue))
0122         qeth_tx_arm_timer(queue, coal->tx_coalesce_usecs);
0123 }
0124 
0125 static int qeth_set_coalesce(struct net_device *dev,
0126                  struct ethtool_coalesce *coal,
0127                  struct kernel_ethtool_coalesce *kernel_coal,
0128                  struct netlink_ext_ack *extack)
0129 {
0130     struct qeth_card *card = dev->ml_priv;
0131     struct qeth_qdio_out_q *queue;
0132     unsigned int i;
0133 
0134     if (!IS_IQD(card))
0135         return -EOPNOTSUPP;
0136 
0137     if (!coal->tx_coalesce_usecs && !coal->tx_max_coalesced_frames)
0138         return -EINVAL;
0139 
0140     qeth_for_each_output_queue(card, queue, i)
0141         __qeth_set_coalesce(dev, queue, coal);
0142 
0143     return 0;
0144 }
0145 
0146 static void qeth_get_ringparam(struct net_device *dev,
0147                    struct ethtool_ringparam *param,
0148                    struct kernel_ethtool_ringparam *kernel_param,
0149                    struct netlink_ext_ack *extack)
0150 {
0151     struct qeth_card *card = dev->ml_priv;
0152 
0153     param->rx_max_pending = QDIO_MAX_BUFFERS_PER_Q;
0154     param->rx_mini_max_pending = 0;
0155     param->rx_jumbo_max_pending = 0;
0156     param->tx_max_pending = QDIO_MAX_BUFFERS_PER_Q;
0157 
0158     param->rx_pending = card->qdio.in_buf_pool.buf_count;
0159     param->rx_mini_pending = 0;
0160     param->rx_jumbo_pending = 0;
0161     param->tx_pending = QDIO_MAX_BUFFERS_PER_Q;
0162 }
0163 
0164 static void qeth_get_strings(struct net_device *dev, u32 stringset, u8 *data)
0165 {
0166     struct qeth_card *card = dev->ml_priv;
0167     char prefix[ETH_GSTRING_LEN] = "";
0168     unsigned int i;
0169 
0170     switch (stringset) {
0171     case ETH_SS_STATS:
0172         qeth_add_stat_strings(&data, prefix, card_stats,
0173                       CARD_STATS_LEN);
0174         for (i = 0; i < card->qdio.no_out_queues; i++) {
0175             snprintf(prefix, ETH_GSTRING_LEN, "tx%u ", i);
0176             qeth_add_stat_strings(&data, prefix, txq_stats,
0177                           TXQ_STATS_LEN);
0178         }
0179         break;
0180     default:
0181         WARN_ON(1);
0182         break;
0183     }
0184 }
0185 
0186 static void qeth_get_drvinfo(struct net_device *dev,
0187                  struct ethtool_drvinfo *info)
0188 {
0189     struct qeth_card *card = dev->ml_priv;
0190 
0191     strlcpy(info->driver, IS_LAYER2(card) ? "qeth_l2" : "qeth_l3",
0192         sizeof(info->driver));
0193     strlcpy(info->fw_version, card->info.mcl_level,
0194         sizeof(info->fw_version));
0195     snprintf(info->bus_info, sizeof(info->bus_info), "%s/%s/%s",
0196          CARD_RDEV_ID(card), CARD_WDEV_ID(card), CARD_DDEV_ID(card));
0197 }
0198 
0199 static void qeth_get_channels(struct net_device *dev,
0200                   struct ethtool_channels *channels)
0201 {
0202     struct qeth_card *card = dev->ml_priv;
0203 
0204     channels->max_rx = dev->num_rx_queues;
0205     channels->max_tx = card->qdio.no_out_queues;
0206     channels->max_other = 0;
0207     channels->max_combined = 0;
0208     channels->rx_count = dev->real_num_rx_queues;
0209     channels->tx_count = dev->real_num_tx_queues;
0210     channels->other_count = 0;
0211     channels->combined_count = 0;
0212 }
0213 
0214 static int qeth_set_channels(struct net_device *dev,
0215                  struct ethtool_channels *channels)
0216 {
0217     struct qeth_priv *priv = netdev_priv(dev);
0218     struct qeth_card *card = dev->ml_priv;
0219     int rc;
0220 
0221     if (channels->rx_count == 0 || channels->tx_count == 0)
0222         return -EINVAL;
0223     if (channels->tx_count > card->qdio.no_out_queues)
0224         return -EINVAL;
0225 
0226     /* Prio-queueing needs all TX queues: */
0227     if (qeth_uses_tx_prio_queueing(card))
0228         return -EPERM;
0229 
0230     if (IS_IQD(card)) {
0231         if (channels->tx_count < QETH_IQD_MIN_TXQ)
0232             return -EINVAL;
0233 
0234         /* Reject downgrade while running. It could push displaced
0235          * ucast flows onto txq0, which is reserved for mcast.
0236          */
0237         if (netif_running(dev) &&
0238             channels->tx_count < dev->real_num_tx_queues)
0239             return -EPERM;
0240     }
0241 
0242     rc = qeth_set_real_num_tx_queues(card, channels->tx_count);
0243     if (!rc)
0244         priv->tx_wanted_queues = channels->tx_count;
0245 
0246     return rc;
0247 }
0248 
0249 static int qeth_get_ts_info(struct net_device *dev,
0250                 struct ethtool_ts_info *info)
0251 {
0252     struct qeth_card *card = dev->ml_priv;
0253 
0254     if (!IS_IQD(card))
0255         return -EOPNOTSUPP;
0256 
0257     return ethtool_op_get_ts_info(dev, info);
0258 }
0259 
0260 static int qeth_get_tunable(struct net_device *dev,
0261                 const struct ethtool_tunable *tuna, void *data)
0262 {
0263     struct qeth_priv *priv = netdev_priv(dev);
0264 
0265     switch (tuna->id) {
0266     case ETHTOOL_RX_COPYBREAK:
0267         *(u32 *)data = priv->rx_copybreak;
0268         return 0;
0269     default:
0270         return -EOPNOTSUPP;
0271     }
0272 }
0273 
0274 static int qeth_set_tunable(struct net_device *dev,
0275                 const struct ethtool_tunable *tuna,
0276                 const void *data)
0277 {
0278     struct qeth_priv *priv = netdev_priv(dev);
0279 
0280     switch (tuna->id) {
0281     case ETHTOOL_RX_COPYBREAK:
0282         WRITE_ONCE(priv->rx_copybreak, *(u32 *)data);
0283         return 0;
0284     default:
0285         return -EOPNOTSUPP;
0286     }
0287 }
0288 
0289 static int qeth_get_per_queue_coalesce(struct net_device *dev, u32 __queue,
0290                        struct ethtool_coalesce *coal)
0291 {
0292     struct qeth_card *card = dev->ml_priv;
0293     struct qeth_qdio_out_q *queue;
0294 
0295     if (!IS_IQD(card))
0296         return -EOPNOTSUPP;
0297 
0298     if (__queue >= card->qdio.no_out_queues)
0299         return -EINVAL;
0300 
0301     queue = card->qdio.out_qs[__queue];
0302 
0303     coal->tx_coalesce_usecs = queue->coalesce_usecs;
0304     coal->tx_max_coalesced_frames = queue->max_coalesced_frames;
0305     return 0;
0306 }
0307 
0308 static int qeth_set_per_queue_coalesce(struct net_device *dev, u32 queue,
0309                        struct ethtool_coalesce *coal)
0310 {
0311     struct qeth_card *card = dev->ml_priv;
0312 
0313     if (!IS_IQD(card))
0314         return -EOPNOTSUPP;
0315 
0316     if (queue >= card->qdio.no_out_queues)
0317         return -EINVAL;
0318 
0319     if (!coal->tx_coalesce_usecs && !coal->tx_max_coalesced_frames)
0320         return -EINVAL;
0321 
0322     __qeth_set_coalesce(dev, card->qdio.out_qs[queue], coal);
0323     return 0;
0324 }
0325 
0326 /* Helper function to fill 'advertising' and 'supported' which are the same. */
0327 /* Autoneg and full-duplex are supported and advertised unconditionally.     */
0328 /* Always advertise and support all speeds up to specified, and only one     */
0329 /* specified port type.                              */
0330 static void qeth_set_ethtool_link_modes(struct ethtool_link_ksettings *cmd,
0331                     enum qeth_link_mode link_mode)
0332 {
0333     ethtool_link_ksettings_zero_link_mode(cmd, supported);
0334     ethtool_link_ksettings_zero_link_mode(cmd, advertising);
0335     ethtool_link_ksettings_zero_link_mode(cmd, lp_advertising);
0336 
0337     ethtool_link_ksettings_add_link_mode(cmd, supported, Autoneg);
0338     ethtool_link_ksettings_add_link_mode(cmd, advertising, Autoneg);
0339 
0340     switch (cmd->base.port) {
0341     case PORT_TP:
0342         ethtool_link_ksettings_add_link_mode(cmd, supported, TP);
0343         ethtool_link_ksettings_add_link_mode(cmd, advertising, TP);
0344 
0345         switch (cmd->base.speed) {
0346         case SPEED_10000:
0347             ethtool_link_ksettings_add_link_mode(cmd, supported,
0348                                  10000baseT_Full);
0349             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0350                                  10000baseT_Full);
0351             fallthrough;
0352         case SPEED_1000:
0353             ethtool_link_ksettings_add_link_mode(cmd, supported,
0354                                  1000baseT_Full);
0355             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0356                                  1000baseT_Full);
0357             ethtool_link_ksettings_add_link_mode(cmd, supported,
0358                                  1000baseT_Half);
0359             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0360                                  1000baseT_Half);
0361             fallthrough;
0362         case SPEED_100:
0363             ethtool_link_ksettings_add_link_mode(cmd, supported,
0364                                  100baseT_Full);
0365             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0366                                  100baseT_Full);
0367             ethtool_link_ksettings_add_link_mode(cmd, supported,
0368                                  100baseT_Half);
0369             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0370                                  100baseT_Half);
0371             fallthrough;
0372         case SPEED_10:
0373             ethtool_link_ksettings_add_link_mode(cmd, supported,
0374                                  10baseT_Full);
0375             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0376                                  10baseT_Full);
0377             ethtool_link_ksettings_add_link_mode(cmd, supported,
0378                                  10baseT_Half);
0379             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0380                                  10baseT_Half);
0381             break;
0382         default:
0383             break;
0384         }
0385 
0386         break;
0387     case PORT_FIBRE:
0388         ethtool_link_ksettings_add_link_mode(cmd, supported, FIBRE);
0389         ethtool_link_ksettings_add_link_mode(cmd, advertising, FIBRE);
0390 
0391         switch (cmd->base.speed) {
0392         case SPEED_25000:
0393             ethtool_link_ksettings_add_link_mode(cmd, supported,
0394                                  25000baseSR_Full);
0395             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0396                                  25000baseSR_Full);
0397             break;
0398         case SPEED_10000:
0399             if (link_mode == QETH_LINK_MODE_FIBRE_LONG) {
0400                 ethtool_link_ksettings_add_link_mode(cmd, supported,
0401                                      10000baseLR_Full);
0402                 ethtool_link_ksettings_add_link_mode(cmd, advertising,
0403                                      10000baseLR_Full);
0404             } else if (link_mode == QETH_LINK_MODE_FIBRE_SHORT) {
0405                 ethtool_link_ksettings_add_link_mode(cmd, supported,
0406                                      10000baseSR_Full);
0407                 ethtool_link_ksettings_add_link_mode(cmd, advertising,
0408                                      10000baseSR_Full);
0409             }
0410             break;
0411         case SPEED_1000:
0412             ethtool_link_ksettings_add_link_mode(cmd, supported,
0413                                  1000baseX_Full);
0414             ethtool_link_ksettings_add_link_mode(cmd, advertising,
0415                                  1000baseX_Full);
0416             break;
0417         default:
0418             break;
0419         }
0420 
0421         break;
0422     default:
0423         break;
0424     }
0425 }
0426 
0427 static int qeth_get_link_ksettings(struct net_device *netdev,
0428                    struct ethtool_link_ksettings *cmd)
0429 {
0430     struct qeth_card *card = netdev->ml_priv;
0431 
0432     QETH_CARD_TEXT(card, 4, "ethtglks");
0433     cmd->base.speed = card->info.link_info.speed;
0434     cmd->base.duplex = card->info.link_info.duplex;
0435     cmd->base.port = card->info.link_info.port;
0436     cmd->base.autoneg = AUTONEG_ENABLE;
0437     cmd->base.phy_address = 0;
0438     cmd->base.mdio_support = 0;
0439     cmd->base.eth_tp_mdix = ETH_TP_MDI_INVALID;
0440     cmd->base.eth_tp_mdix_ctrl = ETH_TP_MDI_INVALID;
0441 
0442     qeth_set_ethtool_link_modes(cmd, card->info.link_info.link_mode);
0443 
0444     return 0;
0445 }
0446 
0447 const struct ethtool_ops qeth_ethtool_ops = {
0448     .supported_coalesce_params = ETHTOOL_COALESCE_TX_USECS |
0449                      ETHTOOL_COALESCE_TX_MAX_FRAMES,
0450     .get_link = ethtool_op_get_link,
0451     .set_coalesce = qeth_set_coalesce,
0452     .get_ringparam = qeth_get_ringparam,
0453     .get_strings = qeth_get_strings,
0454     .get_ethtool_stats = qeth_get_ethtool_stats,
0455     .get_sset_count = qeth_get_sset_count,
0456     .get_drvinfo = qeth_get_drvinfo,
0457     .get_channels = qeth_get_channels,
0458     .set_channels = qeth_set_channels,
0459     .get_ts_info = qeth_get_ts_info,
0460     .get_tunable = qeth_get_tunable,
0461     .set_tunable = qeth_set_tunable,
0462     .get_per_queue_coalesce = qeth_get_per_queue_coalesce,
0463     .set_per_queue_coalesce = qeth_set_per_queue_coalesce,
0464     .get_link_ksettings = qeth_get_link_ksettings,
0465 };