hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/net/ncsi/ncsi-aen.c
....@@ -1,10 +1,6 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * Copyright Gavin Shan, IBM Corporation 2016.
3
- *
4
- * This program is free software; you can redistribute it and/or modify
5
- * it under the terms of the GNU General Public License as published by
6
- * the Free Software Foundation; either version 2 of the License, or
7
- * (at your option) any later version.
84 */
95
106 #include <linux/module.h>
....@@ -50,13 +46,15 @@
5046 static int ncsi_aen_handler_lsc(struct ncsi_dev_priv *ndp,
5147 struct ncsi_aen_pkt_hdr *h)
5248 {
53
- struct ncsi_aen_lsc_pkt *lsc;
54
- struct ncsi_channel *nc;
49
+ struct ncsi_channel *nc, *tmp;
5550 struct ncsi_channel_mode *ncm;
51
+ unsigned long old_data, data;
52
+ struct ncsi_aen_lsc_pkt *lsc;
53
+ struct ncsi_package *np;
54
+ bool had_link, has_link;
55
+ unsigned long flags;
5656 bool chained;
5757 int state;
58
- unsigned long old_data, data;
59
- unsigned long flags;
6058
6159 /* Find the NCSI channel */
6260 ncsi_find_package_and_channel(ndp, h->common.channel, NULL, &nc);
....@@ -73,6 +71,9 @@
7371 ncm->data[2] = data;
7472 ncm->data[4] = ntohl(lsc->oem_status);
7573
74
+ had_link = !!(old_data & 0x1);
75
+ has_link = !!(data & 0x1);
76
+
7677 netdev_dbg(ndp->ndev.dev, "NCSI: LSC AEN - channel %u state %s\n",
7778 nc->id, data & 0x1 ? "up" : "down");
7879
....@@ -80,22 +81,60 @@
8081 state = nc->state;
8182 spin_unlock_irqrestore(&nc->lock, flags);
8283
83
- if (!((old_data ^ data) & 0x1) || chained)
84
- return 0;
85
- if (!(state == NCSI_CHANNEL_INACTIVE && (data & 0x1)) &&
86
- !(state == NCSI_CHANNEL_ACTIVE && !(data & 0x1)))
84
+ if (state == NCSI_CHANNEL_INACTIVE)
85
+ netdev_warn(ndp->ndev.dev,
86
+ "NCSI: Inactive channel %u received AEN!\n",
87
+ nc->id);
88
+
89
+ if ((had_link == has_link) || chained)
8790 return 0;
8891
89
- if (!(ndp->flags & NCSI_DEV_HWA) &&
90
- state == NCSI_CHANNEL_ACTIVE)
91
- ndp->flags |= NCSI_DEV_RESHUFFLE;
92
+ if (!ndp->multi_package && !nc->package->multi_channel) {
93
+ if (had_link) {
94
+ ndp->flags |= NCSI_DEV_RESHUFFLE;
95
+ ncsi_stop_channel_monitor(nc);
96
+ spin_lock_irqsave(&ndp->lock, flags);
97
+ list_add_tail_rcu(&nc->link, &ndp->channel_queue);
98
+ spin_unlock_irqrestore(&ndp->lock, flags);
99
+ return ncsi_process_next_channel(ndp);
100
+ }
101
+ /* Configured channel came up */
102
+ return 0;
103
+ }
92104
93
- ncsi_stop_channel_monitor(nc);
94
- spin_lock_irqsave(&ndp->lock, flags);
95
- list_add_tail_rcu(&nc->link, &ndp->channel_queue);
96
- spin_unlock_irqrestore(&ndp->lock, flags);
105
+ if (had_link) {
106
+ ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
107
+ if (ncsi_channel_is_last(ndp, nc)) {
108
+ /* No channels left, reconfigure */
109
+ return ncsi_reset_dev(&ndp->ndev);
110
+ } else if (ncm->enable) {
111
+ /* Need to failover Tx channel */
112
+ ncsi_update_tx_channel(ndp, nc->package, nc, NULL);
113
+ }
114
+ } else if (has_link && nc->package->preferred_channel == nc) {
115
+ /* Return Tx to preferred channel */
116
+ ncsi_update_tx_channel(ndp, nc->package, NULL, nc);
117
+ } else if (has_link) {
118
+ NCSI_FOR_EACH_PACKAGE(ndp, np) {
119
+ NCSI_FOR_EACH_CHANNEL(np, tmp) {
120
+ /* Enable Tx on this channel if the current Tx
121
+ * channel is down.
122
+ */
123
+ ncm = &tmp->modes[NCSI_MODE_TX_ENABLE];
124
+ if (ncm->enable &&
125
+ !ncsi_channel_has_link(tmp)) {
126
+ ncsi_update_tx_channel(ndp, nc->package,
127
+ tmp, nc);
128
+ break;
129
+ }
130
+ }
131
+ }
132
+ }
97133
98
- return ncsi_process_next_channel(ndp);
134
+ /* Leave configured channels active in a multi-channel scenario so
135
+ * AEN events are still received.
136
+ */
137
+ return 0;
99138 }
100139
101140 static int ncsi_aen_handler_cr(struct ncsi_dev_priv *ndp,