]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/net/bonding/bond_3ad.c
Merge remote-tracking branch 'sound-current/for-linus'
[karo-tx-linux.git] / drivers / net / bonding / bond_3ad.c
index 3c45358844eb94bc8d44c3934e0a5689b9adf994..940e2ebbdea81ef459cffa1128361816f7d309f1 100644 (file)
@@ -127,6 +127,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info,
                                    struct port *port);
 static void ad_marker_response_received(struct bond_marker *marker,
                                        struct port *port);
+static void ad_update_actor_keys(struct port *port, bool reset);
 
 
 /* ================= api to bonding and kernel code ================== */
@@ -327,14 +328,12 @@ static u16 __get_link_speed(struct port *port)
 static u8 __get_duplex(struct port *port)
 {
        struct slave *slave = port->slave;
-       u8 retval;
+       u8 retval = 0x0;
 
        /* handling a special case: when the configuration starts with
         * link down, it sets the duplex to 0.
         */
-       if (slave->link != BOND_LINK_UP) {
-               retval = 0x0;
-       } else {
+       if (slave->link == BOND_LINK_UP) {
                switch (slave->duplex) {
                case DUPLEX_FULL:
                        retval = 0x1;
@@ -1953,14 +1952,7 @@ void bond_3ad_bind_slave(struct slave *slave)
                 * user key
                 */
                port->actor_admin_port_key = bond->params.ad_user_port_key << 6;
-               port->actor_admin_port_key |= __get_duplex(port);
-               port->actor_admin_port_key |= (__get_link_speed(port) << 1);
-               port->actor_oper_port_key = port->actor_admin_port_key;
-               /* if the port is not full duplex, then the port should be not
-                * lacp Enabled
-                */
-               if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS))
-                       port->sm_vars &= ~AD_PORT_LACP_ENABLED;
+               ad_update_actor_keys(port, false);
                /* actor system is the bond's system */
                port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr;
                port->actor_system_priority =
@@ -2310,45 +2302,60 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
 }
 
 /**
- * bond_3ad_adapter_speed_changed - handle a slave's speed change indication
- * @slave: slave struct to work on
+ * ad_update_actor_keys - Update the oper / admin keys for a port based on
+ * its current speed and duplex settings.
  *
- * Handle reselection of aggregator (if needed) for this port.
+ * @port: the port we'are looking at
+ * @reset: Boolean to just reset the speed and the duplex part of the key
+ *
+ * The logic to change the oper / admin keys is:
+ * (a) A full duplex port can participate in LACP with partner.
+ * (b) When the speed is changed, LACP need to be reinitiated.
  */
-void bond_3ad_adapter_speed_changed(struct slave *slave)
+static void ad_update_actor_keys(struct port *port, bool reset)
 {
-       struct port *port;
-
-       port = &(SLAVE_AD_INFO(slave)->port);
-
-       /* if slave is null, the whole port is not initialized */
-       if (!port->slave) {
-               netdev_warn(slave->bond->dev, "speed changed for uninitialized port on %s\n",
-                           slave->dev->name);
-               return;
+       u8 duplex = 0;
+       u16 ospeed = 0, speed = 0;
+       u16 old_oper_key = port->actor_oper_port_key;
+
+       port->actor_admin_port_key &= ~(AD_SPEED_KEY_MASKS|AD_DUPLEX_KEY_MASKS);
+       if (!reset) {
+               speed = __get_link_speed(port);
+               ospeed = (old_oper_key & AD_SPEED_KEY_MASKS) >> 1;
+               duplex = __get_duplex(port);
+               port->actor_admin_port_key |= (speed << 1) | duplex;
        }
-
-       spin_lock_bh(&slave->bond->mode_lock);
-
-       port->actor_admin_port_key &= ~AD_SPEED_KEY_MASKS;
-       port->actor_admin_port_key |= __get_link_speed(port) << 1;
        port->actor_oper_port_key = port->actor_admin_port_key;
-       netdev_dbg(slave->bond->dev, "Port %d changed speed\n", port->actor_port_number);
-       /* there is no need to reselect a new aggregator, just signal the
-        * state machines to reinitialize
-        */
-       port->sm_vars |= AD_PORT_BEGIN;
 
-       spin_unlock_bh(&slave->bond->mode_lock);
+       if (old_oper_key != port->actor_oper_port_key) {
+               /* Only 'duplex' port participates in LACP */
+               if (duplex)
+                       port->sm_vars |= AD_PORT_LACP_ENABLED;
+               else
+                       port->sm_vars &= ~AD_PORT_LACP_ENABLED;
+
+               if (!reset) {
+                       if (!speed) {
+                               netdev_err(port->slave->dev,
+                                          "speed changed to 0 for port %s",
+                                          port->slave->dev->name);
+                       } else if (duplex && ospeed != speed) {
+                               /* Speed change restarts LACP state-machine */
+                               port->sm_vars |= AD_PORT_BEGIN;
+                       }
+               }
+       }
 }
 
 /**
- * bond_3ad_adapter_duplex_changed - handle a slave's duplex change indication
+ * bond_3ad_adapter_speed_duplex_changed - handle a slave's speed / duplex
+ * change indication
+ *
  * @slave: slave struct to work on
  *
  * Handle reselection of aggregator (if needed) for this port.
  */
-void bond_3ad_adapter_duplex_changed(struct slave *slave)
+void bond_3ad_adapter_speed_duplex_changed(struct slave *slave)
 {
        struct port *port;
 
@@ -2356,25 +2363,16 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
 
        /* if slave is null, the whole port is not initialized */
        if (!port->slave) {
-               netdev_warn(slave->bond->dev, "duplex changed for uninitialized port on %s\n",
+               netdev_warn(slave->bond->dev,
+                           "speed/duplex changed for uninitialized port %s\n",
                            slave->dev->name);
                return;
        }
 
        spin_lock_bh(&slave->bond->mode_lock);
-
-       port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS;
-       port->actor_admin_port_key |= __get_duplex(port);
-       port->actor_oper_port_key = port->actor_admin_port_key;
-       netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n",
+       ad_update_actor_keys(port, false);
+       netdev_dbg(slave->bond->dev, "Port %d slave %s changed speed/duplex\n",
                   port->actor_port_number, slave->dev->name);
-       if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
-               port->sm_vars |= AD_PORT_LACP_ENABLED;
-       /* there is no need to reselect a new aggregator, just signal the
-        * state machines to reinitialize
-        */
-       port->sm_vars |= AD_PORT_BEGIN;
-
        spin_unlock_bh(&slave->bond->mode_lock);
 }
 
@@ -2406,26 +2404,17 @@ void bond_3ad_handle_link_change(struct slave *slave, char link)
         * on link up we are forcing recheck on the duplex and speed since
         * some of he adaptors(ce1000.lan) report.
         */
-       port->actor_admin_port_key &= ~(AD_DUPLEX_KEY_MASKS|AD_SPEED_KEY_MASKS);
        if (link == BOND_LINK_UP) {
                port->is_enabled = true;
-               port->actor_admin_port_key |=
-                       (__get_link_speed(port) << 1) | __get_duplex(port);
-               if (port->actor_admin_port_key & AD_DUPLEX_KEY_MASKS)
-                       port->sm_vars |= AD_PORT_LACP_ENABLED;
+               ad_update_actor_keys(port, false);
        } else {
                /* link has failed */
                port->is_enabled = false;
-               port->sm_vars &= ~AD_PORT_LACP_ENABLED;
+               ad_update_actor_keys(port, true);
        }
-       port->actor_oper_port_key = port->actor_admin_port_key;
        netdev_dbg(slave->bond->dev, "Port %d changed link status to %s\n",
                   port->actor_port_number,
                   link == BOND_LINK_UP ? "UP" : "DOWN");
-       /* there is no need to reselect a new aggregator, just signal the
-        * state machines to reinitialize
-        */
-       port->sm_vars |= AD_PORT_BEGIN;
 
        spin_unlock_bh(&slave->bond->mode_lock);