master.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /*
  2. * Handling of a master device, switching frames via its switch fabric CPU port
  3. *
  4. * Copyright (c) 2017 Savoir-faire Linux Inc.
  5. * Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. */
  12. #include "dsa_priv.h"
  13. static void dsa_master_get_ethtool_stats(struct net_device *dev,
  14. struct ethtool_stats *stats,
  15. uint64_t *data)
  16. {
  17. struct dsa_port *cpu_dp = dev->dsa_ptr;
  18. const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
  19. struct dsa_switch *ds = cpu_dp->ds;
  20. int port = cpu_dp->index;
  21. int count = 0;
  22. if (ops && ops->get_sset_count && ops->get_ethtool_stats) {
  23. count = ops->get_sset_count(dev, ETH_SS_STATS);
  24. ops->get_ethtool_stats(dev, stats, data);
  25. }
  26. if (ds->ops->get_ethtool_stats)
  27. ds->ops->get_ethtool_stats(ds, port, data + count);
  28. }
  29. static int dsa_master_get_sset_count(struct net_device *dev, int sset)
  30. {
  31. struct dsa_port *cpu_dp = dev->dsa_ptr;
  32. const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
  33. struct dsa_switch *ds = cpu_dp->ds;
  34. int count = 0;
  35. if (ops && ops->get_sset_count)
  36. count += ops->get_sset_count(dev, sset);
  37. if (sset == ETH_SS_STATS && ds->ops->get_sset_count)
  38. count += ds->ops->get_sset_count(ds);
  39. return count;
  40. }
  41. static void dsa_master_get_strings(struct net_device *dev, uint32_t stringset,
  42. uint8_t *data)
  43. {
  44. struct dsa_port *cpu_dp = dev->dsa_ptr;
  45. const struct ethtool_ops *ops = cpu_dp->orig_ethtool_ops;
  46. struct dsa_switch *ds = cpu_dp->ds;
  47. int port = cpu_dp->index;
  48. int len = ETH_GSTRING_LEN;
  49. int mcount = 0, count;
  50. unsigned int i;
  51. uint8_t pfx[4];
  52. uint8_t *ndata;
  53. snprintf(pfx, sizeof(pfx), "p%.2d", port);
  54. /* We do not want to be NULL-terminated, since this is a prefix */
  55. pfx[sizeof(pfx) - 1] = '_';
  56. if (ops && ops->get_sset_count && ops->get_strings) {
  57. mcount = ops->get_sset_count(dev, ETH_SS_STATS);
  58. ops->get_strings(dev, stringset, data);
  59. }
  60. if (stringset == ETH_SS_STATS && ds->ops->get_strings) {
  61. ndata = data + mcount * len;
  62. /* This function copies ETH_GSTRINGS_LEN bytes, we will mangle
  63. * the output after to prepend our CPU port prefix we
  64. * constructed earlier
  65. */
  66. ds->ops->get_strings(ds, port, ndata);
  67. count = ds->ops->get_sset_count(ds);
  68. for (i = 0; i < count; i++) {
  69. memmove(ndata + (i * len + sizeof(pfx)),
  70. ndata + i * len, len - sizeof(pfx));
  71. memcpy(ndata + i * len, pfx, sizeof(pfx));
  72. }
  73. }
  74. }
  75. static int dsa_master_ethtool_setup(struct net_device *dev)
  76. {
  77. struct dsa_port *cpu_dp = dev->dsa_ptr;
  78. struct dsa_switch *ds = cpu_dp->ds;
  79. struct ethtool_ops *ops;
  80. ops = devm_kzalloc(ds->dev, sizeof(*ops), GFP_KERNEL);
  81. if (!ops)
  82. return -ENOMEM;
  83. cpu_dp->orig_ethtool_ops = dev->ethtool_ops;
  84. if (cpu_dp->orig_ethtool_ops)
  85. memcpy(ops, cpu_dp->orig_ethtool_ops, sizeof(*ops));
  86. ops->get_sset_count = dsa_master_get_sset_count;
  87. ops->get_ethtool_stats = dsa_master_get_ethtool_stats;
  88. ops->get_strings = dsa_master_get_strings;
  89. dev->ethtool_ops = ops;
  90. return 0;
  91. }
  92. static void dsa_master_ethtool_teardown(struct net_device *dev)
  93. {
  94. struct dsa_port *cpu_dp = dev->dsa_ptr;
  95. dev->ethtool_ops = cpu_dp->orig_ethtool_ops;
  96. cpu_dp->orig_ethtool_ops = NULL;
  97. }
  98. int dsa_master_setup(struct net_device *dev, struct dsa_port *cpu_dp)
  99. {
  100. /* If we use a tagging format that doesn't have an ethertype
  101. * field, make sure that all packets from this point on get
  102. * sent to the tag format's receive function.
  103. */
  104. wmb();
  105. dev->dsa_ptr = cpu_dp;
  106. return dsa_master_ethtool_setup(dev);
  107. }
  108. void dsa_master_teardown(struct net_device *dev)
  109. {
  110. dsa_master_ethtool_teardown(dev);
  111. dev->dsa_ptr = NULL;
  112. /* If we used a tagging format that doesn't have an ethertype
  113. * field, make sure that all packets from this point get sent
  114. * without the tag and go through the regular receive path.
  115. */
  116. wmb();
  117. }