struct ncsi_aen_lsc_pkt *lsc;
        struct ncsi_channel *nc;
        struct ncsi_channel_mode *ncm;
-       unsigned long old_data;
+       bool chained;
+       int state;
+       unsigned long old_data, data;
        unsigned long flags;
 
        /* Find the NCSI channel */
                return -ENODEV;
 
        /* Update the link status */
-       ncm = &nc->modes[NCSI_MODE_LINK];
        lsc = (struct ncsi_aen_lsc_pkt *)h;
+
+       spin_lock_irqsave(&nc->lock, flags);
+       ncm = &nc->modes[NCSI_MODE_LINK];
        old_data = ncm->data[2];
-       ncm->data[2] = ntohl(lsc->status);
+       data = ntohl(lsc->status);
+       ncm->data[2] = data;
        ncm->data[4] = ntohl(lsc->oem_status);
-       if (!((old_data ^ ncm->data[2]) & 0x1) ||
-           !list_empty(&nc->link))
+
+       chained = !list_empty(&nc->link);
+       state = nc->state;
+       spin_unlock_irqrestore(&nc->lock, flags);
+
+       if (!((old_data ^ data) & 0x1) || chained)
                return 0;
-       if (!(nc->state == NCSI_CHANNEL_INACTIVE && (ncm->data[2] & 0x1)) &&
-           !(nc->state == NCSI_CHANNEL_ACTIVE && !(ncm->data[2] & 0x1)))
+       if (!(state == NCSI_CHANNEL_INACTIVE && (data & 0x1)) &&
+           !(state == NCSI_CHANNEL_ACTIVE && !(data & 0x1)))
                return 0;
 
        if (!(ndp->flags & NCSI_DEV_HWA) &&
-           nc->state == NCSI_CHANNEL_ACTIVE)
+           state == NCSI_CHANNEL_ACTIVE)
                ndp->flags |= NCSI_DEV_RESHUFFLE;
 
        ncsi_stop_channel_monitor(nc);
        if (!nc)
                return -ENODEV;
 
+       spin_lock_irqsave(&nc->lock, flags);
        if (!list_empty(&nc->link) ||
-           nc->state != NCSI_CHANNEL_ACTIVE)
+           nc->state != NCSI_CHANNEL_ACTIVE) {
+               spin_unlock_irqrestore(&nc->lock, flags);
                return 0;
+       }
+       spin_unlock_irqrestore(&nc->lock, flags);
 
        ncsi_stop_channel_monitor(nc);
+       spin_lock_irqsave(&nc->lock, flags);
+       nc->state = NCSI_CHANNEL_INVISIBLE;
+       spin_unlock_irqrestore(&nc->lock, flags);
+
        spin_lock_irqsave(&ndp->lock, flags);
-       xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
+       nc->state = NCSI_CHANNEL_INACTIVE;
        list_add_tail_rcu(&nc->link, &ndp->channel_queue);
        spin_unlock_irqrestore(&ndp->lock, flags);
 
 
        struct ncsi_dev *nd = &ndp->ndev;
        struct ncsi_package *np;
        struct ncsi_channel *nc;
+       unsigned long flags;
 
        nd->state = ncsi_dev_state_functional;
        if (force_down) {
        nd->link_up = 0;
        NCSI_FOR_EACH_PACKAGE(ndp, np) {
                NCSI_FOR_EACH_CHANNEL(np, nc) {
+                       spin_lock_irqsave(&nc->lock, flags);
+
                        if (!list_empty(&nc->link) ||
-                           nc->state != NCSI_CHANNEL_ACTIVE)
+                           nc->state != NCSI_CHANNEL_ACTIVE) {
+                               spin_unlock_irqrestore(&nc->lock, flags);
                                continue;
+                       }
 
                        if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) {
+                               spin_unlock_irqrestore(&nc->lock, flags);
                                nd->link_up = 1;
                                goto report;
                        }
+
+                       spin_unlock_irqrestore(&nc->lock, flags);
                }
        }
 
        struct ncsi_package *np = nc->package;
        struct ncsi_dev_priv *ndp = np->ndp;
        struct ncsi_cmd_arg nca;
-       bool enabled;
+       bool enabled, chained;
        unsigned int timeout;
        unsigned long flags;
-       int ret;
+       int state, ret;
 
        spin_lock_irqsave(&nc->lock, flags);
+       state = nc->state;
+       chained = !list_empty(&nc->link);
        timeout = nc->timeout;
        enabled = nc->enabled;
        spin_unlock_irqrestore(&nc->lock, flags);
 
-       if (!enabled || !list_empty(&nc->link))
+       if (!enabled || chained)
                return;
-       if (nc->state != NCSI_CHANNEL_INACTIVE &&
-           nc->state != NCSI_CHANNEL_ACTIVE)
+       if (state != NCSI_CHANNEL_INACTIVE &&
+           state != NCSI_CHANNEL_ACTIVE)
                return;
 
        if (!(timeout % 2)) {
 
        if (timeout + 1 >= 3) {
                if (!(ndp->flags & NCSI_DEV_HWA) &&
-                   nc->state == NCSI_CHANNEL_ACTIVE)
+                   state == NCSI_CHANNEL_ACTIVE)
                        ncsi_report_link(ndp, true);
 
+               spin_lock_irqsave(&nc->lock, flags);
+               nc->state = NCSI_CHANNEL_INVISIBLE;
+               spin_unlock_irqrestore(&nc->lock, flags);
+
                spin_lock_irqsave(&ndp->lock, flags);
-               xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
+               nc->state = NCSI_CHANNEL_INACTIVE;
                list_add_tail_rcu(&nc->link, &ndp->channel_queue);
                spin_unlock_irqrestore(&ndp->lock, flags);
                ncsi_process_next_channel(ndp);
        struct ncsi_package *np = ndp->active_package;
        struct ncsi_channel *nc = ndp->active_channel;
        struct ncsi_cmd_arg nca;
+       unsigned long flags;
        int ret;
 
        nca.ndp = ndp;
 
                break;
        case ncsi_dev_state_suspend_done:
-               xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
+               spin_lock_irqsave(&nc->lock, flags);
+               nc->state = NCSI_CHANNEL_INACTIVE;
+               spin_unlock_irqrestore(&nc->lock, flags);
                ncsi_process_next_channel(ndp);
 
                break;
        struct ncsi_channel *nc = ndp->active_channel;
        struct ncsi_cmd_arg nca;
        unsigned char index;
+       unsigned long flags;
        int ret;
 
        nca.ndp = ndp;
                        goto error;
                break;
        case ncsi_dev_state_config_done:
+               spin_lock_irqsave(&nc->lock, flags);
                if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1)
-                       xchg(&nc->state, NCSI_CHANNEL_ACTIVE);
+                       nc->state = NCSI_CHANNEL_ACTIVE;
                else
-                       xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
+                       nc->state = NCSI_CHANNEL_INACTIVE;
+               spin_unlock_irqrestore(&nc->lock, flags);
 
                ncsi_start_channel_monitor(nc);
                ncsi_process_next_channel(ndp);
        found = NULL;
        NCSI_FOR_EACH_PACKAGE(ndp, np) {
                NCSI_FOR_EACH_CHANNEL(np, nc) {
+                       spin_lock_irqsave(&nc->lock, flags);
+
                        if (!list_empty(&nc->link) ||
-                           nc->state != NCSI_CHANNEL_INACTIVE)
+                           nc->state != NCSI_CHANNEL_INACTIVE) {
+                               spin_unlock_irqrestore(&nc->lock, flags);
                                continue;
+                       }
 
                        if (!found)
                                found = nc;
 
                        ncm = &nc->modes[NCSI_MODE_LINK];
                        if (ncm->data[2] & 0x1) {
+                               spin_unlock_irqrestore(&nc->lock, flags);
                                found = nc;
                                goto out;
                        }
+
+                       spin_unlock_irqrestore(&nc->lock, flags);
                }
        }
 
                goto out;
        }
 
-       old_state = xchg(&nc->state, NCSI_CHANNEL_INVISIBLE);
        list_del_init(&nc->link);
-
        spin_unlock_irqrestore(&ndp->lock, flags);
 
+       spin_lock_irqsave(&nc->lock, flags);
+       old_state = nc->state;
+       nc->state = NCSI_CHANNEL_INVISIBLE;
+       spin_unlock_irqrestore(&nc->lock, flags);
+
        ndp->active_channel = nc;
        ndp->active_package = nc->package;
 
                break;
        default:
                netdev_err(ndp->ndev.dev, "Invalid state 0x%x on %d:%d\n",
-                          nc->state, nc->package->id, nc->id);
+                          old_state, nc->package->id, nc->id);
                ncsi_report_link(ndp, false);
                return -EINVAL;
        }
        struct ncsi_dev_priv *ndp = TO_NCSI_DEV_PRIV(nd);
        struct ncsi_package *np;
        struct ncsi_channel *nc;
+       unsigned long flags;
+       bool chained;
        int old_state, ret;
 
        if (nd->state != ncsi_dev_state_registered &&
        /* Reset channel's state and start over */
        NCSI_FOR_EACH_PACKAGE(ndp, np) {
                NCSI_FOR_EACH_CHANNEL(np, nc) {
-                       old_state = xchg(&nc->state, NCSI_CHANNEL_INACTIVE);
-                       WARN_ON_ONCE(!list_empty(&nc->link) ||
+                       spin_lock_irqsave(&nc->lock, flags);
+                       chained = !list_empty(&nc->link);
+                       old_state = nc->state;
+                       nc->state = NCSI_CHANNEL_INACTIVE;
+                       spin_unlock_irqrestore(&nc->lock, flags);
+
+                       WARN_ON_ONCE(chained ||
                                     old_state == NCSI_CHANNEL_INVISIBLE);
                }
        }