1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright Gavin Shan, IBM Corporation 2016.
6 #include <linux/module.h>
7 #include <linux/kernel.h>
8 #include <linux/init.h>
9 #include <linux/netdevice.h>
10 #include <linux/skbuff.h>
13 #include <net/net_namespace.h>
19 static int ncsi_validate_aen_pkt(struct ncsi_aen_pkt_hdr
*h
,
20 const unsigned short payload
)
25 if (h
->common
.revision
!= NCSI_PKT_REVISION
)
27 if (ntohs(h
->common
.length
) != payload
)
30 /* Validate checksum, which might be zeroes if the
31 * sender doesn't support checksum according to NCSI
34 pchecksum
= (__be32
*)((void *)(h
+ 1) + payload
- 4);
35 if (ntohl(*pchecksum
) == 0)
38 checksum
= ncsi_calculate_checksum((unsigned char *)h
,
39 sizeof(*h
) + payload
- 4);
40 if (*pchecksum
!= htonl(checksum
))
46 static int ncsi_aen_handler_lsc(struct ncsi_dev_priv
*ndp
,
47 struct ncsi_aen_pkt_hdr
*h
)
49 struct ncsi_channel
*nc
, *tmp
;
50 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
;
59 /* Find the NCSI channel */
60 ncsi_find_package_and_channel(ndp
, h
->common
.channel
, NULL
, &nc
);
64 /* Update the link status */
65 lsc
= (struct ncsi_aen_lsc_pkt
*)h
;
67 spin_lock_irqsave(&nc
->lock
, flags
);
68 ncm
= &nc
->modes
[NCSI_MODE_LINK
];
69 old_data
= ncm
->data
[2];
70 data
= ntohl(lsc
->status
);
72 ncm
->data
[4] = ntohl(lsc
->oem_status
);
74 had_link
= !!(old_data
& 0x1);
75 has_link
= !!(data
& 0x1);
77 netdev_dbg(ndp
->ndev
.dev
, "NCSI: LSC AEN - channel %u state %s\n",
78 nc
->id
, data
& 0x1 ? "up" : "down");
80 chained
= !list_empty(&nc
->link
);
82 spin_unlock_irqrestore(&nc
->lock
, flags
);
84 if (state
== NCSI_CHANNEL_INACTIVE
)
85 netdev_warn(ndp
->ndev
.dev
,
86 "NCSI: Inactive channel %u received AEN!\n",
89 if ((had_link
== has_link
) || chained
)
92 if (!ndp
->multi_package
&& !nc
->package
->multi_channel
) {
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
);
101 /* Configured channel came up */
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
);
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
123 ncm
= &tmp
->modes
[NCSI_MODE_TX_ENABLE
];
125 !ncsi_channel_has_link(tmp
)) {
126 ncsi_update_tx_channel(ndp
, nc
->package
,
134 /* Leave configured channels active in a multi-channel scenario so
135 * AEN events are still received.
140 static int ncsi_aen_handler_cr(struct ncsi_dev_priv
*ndp
,
141 struct ncsi_aen_pkt_hdr
*h
)
143 struct ncsi_channel
*nc
;
146 /* Find the NCSI channel */
147 ncsi_find_package_and_channel(ndp
, h
->common
.channel
, NULL
, &nc
);
151 spin_lock_irqsave(&nc
->lock
, flags
);
152 if (!list_empty(&nc
->link
) ||
153 nc
->state
!= NCSI_CHANNEL_ACTIVE
) {
154 spin_unlock_irqrestore(&nc
->lock
, flags
);
157 spin_unlock_irqrestore(&nc
->lock
, flags
);
159 ncsi_stop_channel_monitor(nc
);
160 spin_lock_irqsave(&nc
->lock
, flags
);
161 nc
->state
= NCSI_CHANNEL_INVISIBLE
;
162 spin_unlock_irqrestore(&nc
->lock
, flags
);
164 spin_lock_irqsave(&ndp
->lock
, flags
);
165 nc
->state
= NCSI_CHANNEL_INACTIVE
;
166 list_add_tail_rcu(&nc
->link
, &ndp
->channel_queue
);
167 spin_unlock_irqrestore(&ndp
->lock
, flags
);
169 return ncsi_process_next_channel(ndp
);
172 static int ncsi_aen_handler_hncdsc(struct ncsi_dev_priv
*ndp
,
173 struct ncsi_aen_pkt_hdr
*h
)
175 struct ncsi_channel
*nc
;
176 struct ncsi_channel_mode
*ncm
;
177 struct ncsi_aen_hncdsc_pkt
*hncdsc
;
180 /* Find the NCSI channel */
181 ncsi_find_package_and_channel(ndp
, h
->common
.channel
, NULL
, &nc
);
185 spin_lock_irqsave(&nc
->lock
, flags
);
186 ncm
= &nc
->modes
[NCSI_MODE_LINK
];
187 hncdsc
= (struct ncsi_aen_hncdsc_pkt
*)h
;
188 ncm
->data
[3] = ntohl(hncdsc
->status
);
189 spin_unlock_irqrestore(&nc
->lock
, flags
);
190 netdev_dbg(ndp
->ndev
.dev
,
191 "NCSI: host driver %srunning on channel %u\n",
192 ncm
->data
[3] & 0x1 ? "" : "not ", nc
->id
);
197 static struct ncsi_aen_handler
{
200 int (*handler
)(struct ncsi_dev_priv
*ndp
,
201 struct ncsi_aen_pkt_hdr
*h
);
202 } ncsi_aen_handlers
[] = {
203 { NCSI_PKT_AEN_LSC
, 12, ncsi_aen_handler_lsc
},
204 { NCSI_PKT_AEN_CR
, 4, ncsi_aen_handler_cr
},
205 { NCSI_PKT_AEN_HNCDSC
, 8, ncsi_aen_handler_hncdsc
}
208 int ncsi_aen_handler(struct ncsi_dev_priv
*ndp
, struct sk_buff
*skb
)
210 struct ncsi_aen_pkt_hdr
*h
;
211 struct ncsi_aen_handler
*nah
= NULL
;
214 /* Find the handler */
215 h
= (struct ncsi_aen_pkt_hdr
*)skb_network_header(skb
);
216 for (i
= 0; i
< ARRAY_SIZE(ncsi_aen_handlers
); i
++) {
217 if (ncsi_aen_handlers
[i
].type
== h
->type
) {
218 nah
= &ncsi_aen_handlers
[i
];
224 netdev_warn(ndp
->ndev
.dev
, "Invalid AEN (0x%x) received\n",
229 ret
= ncsi_validate_aen_pkt(h
, nah
->payload
);
231 netdev_warn(ndp
->ndev
.dev
,
232 "NCSI: 'bad' packet ignored for AEN type 0x%x\n",
237 ret
= nah
->handler(ndp
, h
);
239 netdev_err(ndp
->ndev
.dev
,
240 "NCSI: Handler for AEN type 0x%x returned %d\n",