summaryrefslogtreecommitdiff
path: root/drivers/net/bonding
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/bonding')
-rw-r--r--drivers/net/bonding/bond_3ad.c1
-rw-r--r--drivers/net/bonding/bond_alb.c63
2 files changed, 53 insertions, 11 deletions
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index b8e4b4d68dd6..d91533b80996 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2071,7 +2071,6 @@ static void ad_initialize_port(struct port *port, const struct bond_params *bond
port->sm_periodic_timer_counter = 0;
port->sm_mux_state = 0;
port->sm_mux_timer_counter = 0;
- port->sm_tx_state = 0;
port->aggregator = NULL;
port->next_port_in_aggregator = NULL;
port->transaction_id = 0;
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index 43ac8e28e418..a5a0f19a22ac 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -6,6 +6,7 @@
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/pkt_sched.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -74,8 +75,8 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
static inline void tlb_init_table_entry(struct tlb_client_info *entry, int save_load)
{
if (save_load) {
- entry->load_history = 1 + entry->tx_bytes /
- BOND_TLB_REBALANCE_INTERVAL;
+ entry->load_history = 1 + div_u64(entry->tx_bytes,
+ BOND_TLB_REBALANCE_INTERVAL);
entry->tx_bytes = 0;
}
@@ -133,6 +134,10 @@ static int tlb_initialize(struct bonding *bond)
if (!new_hashtbl)
return -ENOMEM;
+ bond_info->unbalanced_load = netdev_alloc_pcpu_stats(struct unbalanced_load_stats);
+ if (!bond_info->unbalanced_load)
+ goto out;
+
spin_lock_bh(&bond->mode_lock);
bond_info->tx_hashtbl = new_hashtbl;
@@ -143,6 +148,10 @@ static int tlb_initialize(struct bonding *bond)
spin_unlock_bh(&bond->mode_lock);
return 0;
+
+out:
+ kfree(new_hashtbl);
+ return -ENOMEM;
}
/* Must be called only after all slaves have been released */
@@ -154,14 +163,18 @@ static void tlb_deinitialize(struct bonding *bond)
kfree(bond_info->tx_hashtbl);
bond_info->tx_hashtbl = NULL;
+ free_percpu(bond_info->unbalanced_load);
+ bond_info->prev_total_unbalanced = 0;
spin_unlock_bh(&bond->mode_lock);
}
static long long compute_gap(struct slave *slave)
{
- return (s64) (slave->speed << 20) - /* Convert to Megabit per sec */
- (s64) (SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
+ u32 raw_speed = READ_ONCE(slave->speed);
+
+ return ((s64)raw_speed << 20) - /* Convert to bits per sec */
+ ((s64)SLAVE_TLB_INFO(slave).load << 3); /* Bytes to bits */
}
static struct slave *tlb_get_least_loaded_slave(struct bonding *bond)
@@ -1350,8 +1363,14 @@ static netdev_tx_t bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,
if (!tx_slave) {
/* unbalanced or unassigned, send through primary */
tx_slave = rcu_dereference(bond->curr_active_slave);
- if (bond->params.tlb_dynamic_lb)
- bond_info->unbalanced_load += skb->len;
+ if (bond->params.tlb_dynamic_lb) {
+ struct unbalanced_load_stats *pcpu_load;
+
+ pcpu_load = this_cpu_ptr(bond_info->unbalanced_load);
+ u64_stats_update_begin(&pcpu_load->syncp);
+ u64_stats_add(&pcpu_load->tx_bytes, skb->len);
+ u64_stats_update_end(&pcpu_load->syncp);
+ }
}
if (tx_slave && bond_slave_can_tx(tx_slave)) {
@@ -1535,6 +1554,29 @@ netdev_tx_t bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev)
return bond_do_alb_xmit(skb, bond, tx_slave);
}
+static u64 reset_unbalanced_load(struct alb_bond_info *bond_info)
+{
+ u64 delta, tx_bytes, total_bytes = 0;
+ struct unbalanced_load_stats *p;
+ unsigned int start;
+ int i;
+
+ for_each_possible_cpu(i) {
+ p = per_cpu_ptr(bond_info->unbalanced_load, i);
+ do {
+ start = u64_stats_fetch_begin(&p->syncp);
+ tx_bytes = u64_stats_read(&p->tx_bytes);
+ } while (u64_stats_fetch_retry(&p->syncp, start));
+
+ total_bytes += tx_bytes;
+ }
+
+ delta = total_bytes - bond_info->prev_total_unbalanced;
+ bond_info->prev_total_unbalanced = total_bytes;
+
+ return div_u64(delta, BOND_TLB_REBALANCE_INTERVAL);
+}
+
void bond_alb_monitor(struct work_struct *work)
{
struct bonding *bond = container_of(work, struct bonding,
@@ -1577,10 +1619,11 @@ void bond_alb_monitor(struct work_struct *work)
bond_for_each_slave_rcu(bond, slave, iter) {
tlb_clear_slave(bond, slave, 1);
if (slave == rcu_access_pointer(bond->curr_active_slave)) {
- SLAVE_TLB_INFO(slave).load =
- bond_info->unbalanced_load /
- BOND_TLB_REBALANCE_INTERVAL;
- bond_info->unbalanced_load = 0;
+ u64 new_load = reset_unbalanced_load(bond_info);
+
+ spin_lock_bh(&bond->mode_lock);
+ SLAVE_TLB_INFO(slave).load = new_load;
+ spin_unlock_bh(&bond->mode_lock);
}
}
atomic_set(&bond_info->tx_rebalance_counter, 0);