Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ncsi-fixes'

Gavin Shan says:

====================
net/ncsi: More bug fixes

This series fixes 2 issues that were found during NCSI's availability
testing on BCM5718 and improves HNCDSC AEN handler:

* PATCH[1] refactors the code so that minimal code change is put
to PATCH[2].
* PATCH[2] fixes the NCSI channel's stale link state before doing
failover.
* PATCH[3] chooses the hot channel, which was ever chosen as active
channel, when the available channels are all in link-down state.
* PATCH[4] improves Host Network Controller Driver Status Change
(HNCDSC) AEN handler

Changelog
=========
v2:
* Merged PATCH[v1 1/2] to PATCH[v2 1].
* Avoid if/else statements in ncsi_suspend_channel() as Joel suggested.
* Added comments to explain why we need retrieve last link states in
ncsi_suspend_channel().
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+112 -34
+2
net/ncsi/internal.h
··· 246 246 ncsi_dev_state_config_gls, 247 247 ncsi_dev_state_config_done, 248 248 ncsi_dev_state_suspend_select = 0x0401, 249 + ncsi_dev_state_suspend_gls, 249 250 ncsi_dev_state_suspend_dcnt, 250 251 ncsi_dev_state_suspend_dc, 251 252 ncsi_dev_state_suspend_deselect, ··· 265 264 #endif 266 265 unsigned int package_num; /* Number of packages */ 267 266 struct list_head packages; /* List of packages */ 267 + struct ncsi_channel *hot_channel; /* Channel was ever active */ 268 268 struct ncsi_request requests[256]; /* Request table */ 269 269 unsigned int request_id; /* Last used request ID */ 270 270 #define NCSI_REQ_START_IDX 1
+15 -3
net/ncsi/ncsi-aen.c
··· 141 141 return -ENODEV; 142 142 143 143 /* If the channel is active one, we need reconfigure it */ 144 + spin_lock_irqsave(&nc->lock, flags); 144 145 ncm = &nc->modes[NCSI_MODE_LINK]; 145 146 hncdsc = (struct ncsi_aen_hncdsc_pkt *)h; 146 147 ncm->data[3] = ntohl(hncdsc->status); 147 148 if (!list_empty(&nc->link) || 148 - nc->state != NCSI_CHANNEL_ACTIVE || 149 - (ncm->data[3] & 0x1)) 149 + nc->state != NCSI_CHANNEL_ACTIVE) { 150 + spin_unlock_irqrestore(&nc->lock, flags); 150 151 return 0; 152 + } 151 153 152 - if (ndp->flags & NCSI_DEV_HWA) 154 + spin_unlock_irqrestore(&nc->lock, flags); 155 + if (!(ndp->flags & NCSI_DEV_HWA) && !(ncm->data[3] & 0x1)) 153 156 ndp->flags |= NCSI_DEV_RESHUFFLE; 154 157 155 158 /* If this channel is the active one and the link doesn't 156 159 * work, we have to choose another channel to be active one. 157 160 * The logic here is exactly similar to what we do when link 158 161 * is down on the active channel. 162 + * 163 + * On the other hand, we need configure it when host driver 164 + * state on the active channel becomes ready. 159 165 */ 160 166 ncsi_stop_channel_monitor(nc); 167 + 168 + spin_lock_irqsave(&nc->lock, flags); 169 + nc->state = (ncm->data[3] & 0x1) ? NCSI_CHANNEL_INACTIVE : 170 + NCSI_CHANNEL_ACTIVE; 171 + spin_unlock_irqrestore(&nc->lock, flags); 172 + 161 173 spin_lock_irqsave(&ndp->lock, flags); 162 174 list_add_tail_rcu(&nc->link, &ndp->channel_queue); 163 175 spin_unlock_irqrestore(&ndp->lock, flags);
+95 -31
net/ncsi/ncsi-manage.c
··· 540 540 nd->state = ncsi_dev_state_suspend_select; 541 541 /* Fall through */ 542 542 case ncsi_dev_state_suspend_select: 543 + ndp->pending_req_num = 1; 544 + 545 + nca.type = NCSI_PKT_CMD_SP; 546 + nca.package = np->id; 547 + nca.channel = NCSI_RESERVED_CHANNEL; 548 + if (ndp->flags & NCSI_DEV_HWA) 549 + nca.bytes[0] = 0; 550 + else 551 + nca.bytes[0] = 1; 552 + 553 + /* To retrieve the last link states of channels in current 554 + * package when current active channel needs fail over to 555 + * another one. It means we will possibly select another 556 + * channel as next active one. The link states of channels 557 + * are most important factor of the selection. So we need 558 + * accurate link states. Unfortunately, the link states on 559 + * inactive channels can't be updated with LSC AEN in time. 560 + */ 561 + if (ndp->flags & NCSI_DEV_RESHUFFLE) 562 + nd->state = ncsi_dev_state_suspend_gls; 563 + else 564 + nd->state = ncsi_dev_state_suspend_dcnt; 565 + ret = ncsi_xmit_cmd(&nca); 566 + if (ret) 567 + goto error; 568 + 569 + break; 570 + case ncsi_dev_state_suspend_gls: 571 + ndp->pending_req_num = np->channel_num; 572 + 573 + nca.type = NCSI_PKT_CMD_GLS; 574 + nca.package = np->id; 575 + 576 + nd->state = ncsi_dev_state_suspend_dcnt; 577 + NCSI_FOR_EACH_CHANNEL(np, nc) { 578 + nca.channel = nc->id; 579 + ret = ncsi_xmit_cmd(&nca); 580 + if (ret) 581 + goto error; 582 + } 583 + 584 + break; 543 585 case ncsi_dev_state_suspend_dcnt: 586 + ndp->pending_req_num = 1; 587 + 588 + nca.type = NCSI_PKT_CMD_DCNT; 589 + nca.package = np->id; 590 + nca.channel = nc->id; 591 + 592 + nd->state = ncsi_dev_state_suspend_dc; 593 + ret = ncsi_xmit_cmd(&nca); 594 + if (ret) 595 + goto error; 596 + 597 + break; 544 598 case ncsi_dev_state_suspend_dc: 599 + ndp->pending_req_num = 1; 600 + 601 + nca.type = NCSI_PKT_CMD_DC; 602 + nca.package = np->id; 603 + nca.channel = nc->id; 604 + nca.bytes[0] = 1; 605 + 606 + nd->state = ncsi_dev_state_suspend_deselect; 607 + ret = ncsi_xmit_cmd(&nca); 608 + if (ret) 609 + goto error; 610 + 611 + break; 545 612 case ncsi_dev_state_suspend_deselect: 546 613 ndp->pending_req_num = 1; 547 614 548 - np = ndp->active_package; 549 - nc = ndp->active_channel; 615 + nca.type = NCSI_PKT_CMD_DP; 550 616 nca.package = np->id; 551 - if (nd->state == ncsi_dev_state_suspend_select) { 552 - nca.type = NCSI_PKT_CMD_SP; 553 - nca.channel = NCSI_RESERVED_CHANNEL; 554 - if (ndp->flags & NCSI_DEV_HWA) 555 - nca.bytes[0] = 0; 556 - else 557 - nca.bytes[0] = 1; 558 - nd->state = ncsi_dev_state_suspend_dcnt; 559 - } else if (nd->state == ncsi_dev_state_suspend_dcnt) { 560 - nca.type = NCSI_PKT_CMD_DCNT; 561 - nca.channel = nc->id; 562 - nd->state = ncsi_dev_state_suspend_dc; 563 - } else if (nd->state == ncsi_dev_state_suspend_dc) { 564 - nca.type = NCSI_PKT_CMD_DC; 565 - nca.channel = nc->id; 566 - nca.bytes[0] = 1; 567 - nd->state = ncsi_dev_state_suspend_deselect; 568 - } else if (nd->state == ncsi_dev_state_suspend_deselect) { 569 - nca.type = NCSI_PKT_CMD_DP; 570 - nca.channel = NCSI_RESERVED_CHANNEL; 571 - nd->state = ncsi_dev_state_suspend_done; 572 - } 617 + nca.channel = NCSI_RESERVED_CHANNEL; 573 618 619 + nd->state = ncsi_dev_state_suspend_done; 574 620 ret = ncsi_xmit_cmd(&nca); 575 - if (ret) { 576 - nd->state = ncsi_dev_state_functional; 577 - return; 578 - } 621 + if (ret) 622 + goto error; 579 623 580 624 break; 581 625 case ncsi_dev_state_suspend_done: ··· 633 589 netdev_warn(nd->dev, "Wrong NCSI state 0x%x in suspend\n", 634 590 nd->state); 635 591 } 592 + 593 + return; 594 + error: 595 + nd->state = ncsi_dev_state_functional; 636 596 } 637 597 638 598 static void ncsi_configure_channel(struct ncsi_dev_priv *ndp) ··· 645 597 struct net_device *dev = nd->dev; 646 598 struct ncsi_package *np = ndp->active_package; 647 599 struct ncsi_channel *nc = ndp->active_channel; 600 + struct ncsi_channel *hot_nc = NULL; 648 601 struct ncsi_cmd_arg nca; 649 602 unsigned char index; 650 603 unsigned long flags; ··· 751 702 break; 752 703 case ncsi_dev_state_config_done: 753 704 spin_lock_irqsave(&nc->lock, flags); 754 - if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) 705 + if (nc->modes[NCSI_MODE_LINK].data[2] & 0x1) { 706 + hot_nc = nc; 755 707 nc->state = NCSI_CHANNEL_ACTIVE; 756 - else 708 + } else { 709 + hot_nc = NULL; 757 710 nc->state = NCSI_CHANNEL_INACTIVE; 711 + } 758 712 spin_unlock_irqrestore(&nc->lock, flags); 713 + 714 + /* Update the hot channel */ 715 + spin_lock_irqsave(&ndp->lock, flags); 716 + ndp->hot_channel = hot_nc; 717 + spin_unlock_irqrestore(&ndp->lock, flags); 759 718 760 719 ncsi_start_channel_monitor(nc); 761 720 ncsi_process_next_channel(ndp); ··· 782 725 static int ncsi_choose_active_channel(struct ncsi_dev_priv *ndp) 783 726 { 784 727 struct ncsi_package *np; 785 - struct ncsi_channel *nc, *found; 728 + struct ncsi_channel *nc, *found, *hot_nc; 786 729 struct ncsi_channel_mode *ncm; 787 730 unsigned long flags; 731 + 732 + spin_lock_irqsave(&ndp->lock, flags); 733 + hot_nc = ndp->hot_channel; 734 + spin_unlock_irqrestore(&ndp->lock, flags); 788 735 789 736 /* The search is done once an inactive channel with up 790 737 * link is found. ··· 805 744 } 806 745 807 746 if (!found) 747 + found = nc; 748 + 749 + if (nc == hot_nc) 808 750 found = nc; 809 751 810 752 ncm = &nc->modes[NCSI_MODE_LINK];