return phylink_ethtool_set_pauseparam(wx->phylink, pause);
}
EXPORT_SYMBOL(wx_set_pauseparam);
+
+void wx_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+
+ ring->rx_max_pending = WX_MAX_RXD;
+ ring->tx_max_pending = WX_MAX_TXD;
+ ring->rx_mini_max_pending = 0;
+ ring->rx_jumbo_max_pending = 0;
+ ring->rx_pending = wx->rx_ring_count;
+ ring->tx_pending = wx->tx_ring_count;
+ ring->rx_mini_pending = 0;
+ ring->rx_jumbo_pending = 0;
+}
+EXPORT_SYMBOL(wx_get_ringparam);
struct ethtool_pauseparam *pause);
int wx_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause);
+void wx_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack);
#endif /* _WX_ETHTOOL_H_ */
}
EXPORT_SYMBOL(wx_set_features);
+void wx_set_ring(struct wx *wx, u32 new_tx_count,
+ u32 new_rx_count, struct wx_ring *temp_ring)
+{
+ int i, err = 0;
+
+ /* Setup new Tx resources and free the old Tx resources in that order.
+ * We can then assign the new resources to the rings via a memcpy.
+ * The advantage to this approach is that we are guaranteed to still
+ * have resources even in the case of an allocation failure.
+ */
+ if (new_tx_count != wx->tx_ring_count) {
+ for (i = 0; i < wx->num_tx_queues; i++) {
+ memcpy(&temp_ring[i], wx->tx_ring[i],
+ sizeof(struct wx_ring));
+
+ temp_ring[i].count = new_tx_count;
+ err = wx_setup_tx_resources(&temp_ring[i]);
+ if (err) {
+ wx_err(wx, "setup new tx resources failed, keep using the old config\n");
+ while (i) {
+ i--;
+ wx_free_tx_resources(&temp_ring[i]);
+ }
+ return;
+ }
+ }
+
+ for (i = 0; i < wx->num_tx_queues; i++) {
+ wx_free_tx_resources(wx->tx_ring[i]);
+
+ memcpy(wx->tx_ring[i], &temp_ring[i],
+ sizeof(struct wx_ring));
+ }
+
+ wx->tx_ring_count = new_tx_count;
+ }
+
+ /* Repeat the process for the Rx rings if needed */
+ if (new_rx_count != wx->rx_ring_count) {
+ for (i = 0; i < wx->num_rx_queues; i++) {
+ memcpy(&temp_ring[i], wx->rx_ring[i],
+ sizeof(struct wx_ring));
+
+ temp_ring[i].count = new_rx_count;
+ err = wx_setup_rx_resources(&temp_ring[i]);
+ if (err) {
+ wx_err(wx, "setup new rx resources failed, keep using the old config\n");
+ while (i) {
+ i--;
+ wx_free_rx_resources(&temp_ring[i]);
+ }
+ return;
+ }
+ }
+
+ for (i = 0; i < wx->num_rx_queues; i++) {
+ wx_free_rx_resources(wx->rx_ring[i]);
+ memcpy(wx->rx_ring[i], &temp_ring[i],
+ sizeof(struct wx_ring));
+ }
+
+ wx->rx_ring_count = new_rx_count;
+ }
+}
+EXPORT_SYMBOL(wx_set_ring);
+
MODULE_LICENSE("GPL");
void wx_get_stats64(struct net_device *netdev,
struct rtnl_link_stats64 *stats);
int wx_set_features(struct net_device *netdev, netdev_features_t features);
+void wx_set_ring(struct wx *wx, u32 new_tx_count,
+ u32 new_rx_count, struct wx_ring *temp_ring);
#endif /* _NGBE_LIB_H_ */
#define WX_MAX_RXD 8192
#define WX_MAX_TXD 8192
+#define WX_MIN_RXD 128
+#define WX_MIN_TXD 128
+
+/* Number of Transmit and Receive Descriptors must be a multiple of 8 */
+#define WX_REQ_RX_DESCRIPTOR_MULTIPLE 8
+#define WX_REQ_TX_DESCRIPTOR_MULTIPLE 8
#define WX_MAX_JUMBO_FRAME_SIZE 9432 /* max payload 9414 */
#define VMDQ_P(p) p
#include "../libwx/wx_ethtool.h"
#include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
+#include "../libwx/wx_hw.h"
#include "ngbe_ethtool.h"
+#include "ngbe_type.h"
static void ngbe_get_wol(struct net_device *netdev,
struct ethtool_wolinfo *wol)
return 0;
}
+static int ngbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+ u32 new_rx_count, new_tx_count;
+ struct wx_ring *temp_ring;
+ int i;
+
+ new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ if (new_tx_count == wx->tx_ring_count &&
+ new_rx_count == wx->rx_ring_count)
+ return 0;
+
+ if (!netif_running(wx->netdev)) {
+ for (i = 0; i < wx->num_tx_queues; i++)
+ wx->tx_ring[i]->count = new_tx_count;
+ for (i = 0; i < wx->num_rx_queues; i++)
+ wx->rx_ring[i]->count = new_rx_count;
+ wx->tx_ring_count = new_tx_count;
+ wx->rx_ring_count = new_rx_count;
+
+ return 0;
+ }
+
+ /* allocate temporary buffer to store rings in */
+ i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
+ temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
+ if (!temp_ring)
+ return -ENOMEM;
+
+ ngbe_down(wx);
+
+ wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
+ kvfree(temp_ring);
+
+ wx_configure(wx);
+ ngbe_up(wx);
+
+ return 0;
+}
+
static const struct ethtool_ops ngbe_ethtool_ops = {
.get_drvinfo = wx_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_pause_stats = wx_get_pause_stats,
.get_pauseparam = wx_get_pauseparam,
.set_pauseparam = wx_set_pauseparam,
+ .get_ringparam = wx_get_ringparam,
+ .set_ringparam = ngbe_set_ringparam,
};
void ngbe_set_ethtool_ops(struct net_device *netdev)
wx_update_stats(wx);
}
-static void ngbe_down(struct wx *wx)
+void ngbe_down(struct wx *wx)
{
phylink_stop(wx->phylink);
ngbe_disable_device(wx);
wx_clean_all_rx_rings(wx);
}
-static void ngbe_up(struct wx *wx)
+void ngbe_up(struct wx *wx)
{
wx_configure_vectors(wx);
extern char ngbe_driver_name[];
+void ngbe_down(struct wx *wx);
+void ngbe_up(struct wx *wx);
+
#endif /* _NGBE_TYPE_H_ */
#include "../libwx/wx_ethtool.h"
#include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
#include "txgbe_type.h"
#include "txgbe_ethtool.h"
+static int txgbe_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ring,
+ struct kernel_ethtool_ringparam *kernel_ring,
+ struct netlink_ext_ack *extack)
+{
+ struct wx *wx = netdev_priv(netdev);
+ u32 new_rx_count, new_tx_count;
+ struct wx_ring *temp_ring;
+ int i;
+
+ new_tx_count = clamp_t(u32, ring->tx_pending, WX_MIN_TXD, WX_MAX_TXD);
+ new_tx_count = ALIGN(new_tx_count, WX_REQ_TX_DESCRIPTOR_MULTIPLE);
+
+ new_rx_count = clamp_t(u32, ring->rx_pending, WX_MIN_RXD, WX_MAX_RXD);
+ new_rx_count = ALIGN(new_rx_count, WX_REQ_RX_DESCRIPTOR_MULTIPLE);
+
+ if (new_tx_count == wx->tx_ring_count &&
+ new_rx_count == wx->rx_ring_count)
+ return 0;
+
+ if (!netif_running(wx->netdev)) {
+ for (i = 0; i < wx->num_tx_queues; i++)
+ wx->tx_ring[i]->count = new_tx_count;
+ for (i = 0; i < wx->num_rx_queues; i++)
+ wx->rx_ring[i]->count = new_rx_count;
+ wx->tx_ring_count = new_tx_count;
+ wx->rx_ring_count = new_rx_count;
+
+ return 0;
+ }
+
+ /* allocate temporary buffer to store rings in */
+ i = max_t(int, wx->num_tx_queues, wx->num_rx_queues);
+ temp_ring = kvmalloc_array(i, sizeof(struct wx_ring), GFP_KERNEL);
+ if (!temp_ring)
+ return -ENOMEM;
+
+ txgbe_down(wx);
+
+ wx_set_ring(wx, new_tx_count, new_rx_count, temp_ring);
+ kvfree(temp_ring);
+
+ txgbe_up(wx);
+
+ return 0;
+}
+
static const struct ethtool_ops txgbe_ethtool_ops = {
.get_drvinfo = wx_get_drvinfo,
.nway_reset = wx_nway_reset,
.get_pause_stats = wx_get_pause_stats,
.get_pauseparam = wx_get_pauseparam,
.set_pauseparam = wx_set_pauseparam,
+ .get_ringparam = wx_get_ringparam,
+ .set_ringparam = txgbe_set_ringparam,
};
void txgbe_set_ethtool_ops(struct net_device *netdev)
wx_update_stats(wx);
}
-static void txgbe_down(struct wx *wx)
+void txgbe_down(struct wx *wx)
{
txgbe_disable_device(wx);
txgbe_reset(wx);
wx_clean_all_rx_rings(wx);
}
+void txgbe_up(struct wx *wx)
+{
+ wx_configure(wx);
+ txgbe_up_complete(wx);
+}
+
/**
* txgbe_init_type_code - Initialize the shared code
* @wx: pointer to hardware structure
extern char txgbe_driver_name[];
+void txgbe_down(struct wx *wx);
+void txgbe_up(struct wx *wx);
+
#define NODE_PROP(_NAME, _PROP) \
(const struct software_node) { \
.name = _NAME, \