1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright Gavin Shan, IBM Corporation 2016.
4*4882a593Smuzhiyun */
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun #include <linux/module.h>
7*4882a593Smuzhiyun #include <linux/kernel.h>
8*4882a593Smuzhiyun #include <linux/init.h>
9*4882a593Smuzhiyun #include <linux/netdevice.h>
10*4882a593Smuzhiyun #include <linux/etherdevice.h>
11*4882a593Smuzhiyun #include <linux/skbuff.h>
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <net/ncsi.h>
14*4882a593Smuzhiyun #include <net/net_namespace.h>
15*4882a593Smuzhiyun #include <net/sock.h>
16*4882a593Smuzhiyun #include <net/genetlink.h>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun #include "internal.h"
19*4882a593Smuzhiyun #include "ncsi-pkt.h"
20*4882a593Smuzhiyun #include "ncsi-netlink.h"
21*4882a593Smuzhiyun
ncsi_validate_rsp_pkt(struct ncsi_request * nr,unsigned short payload)22*4882a593Smuzhiyun static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
23*4882a593Smuzhiyun unsigned short payload)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun struct ncsi_rsp_pkt_hdr *h;
26*4882a593Smuzhiyun u32 checksum;
27*4882a593Smuzhiyun __be32 *pchecksum;
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun /* Check NCSI packet header. We don't need validate
30*4882a593Smuzhiyun * the packet type, which should have been checked
31*4882a593Smuzhiyun * before calling this function.
32*4882a593Smuzhiyun */
33*4882a593Smuzhiyun h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun if (h->common.revision != NCSI_PKT_REVISION) {
36*4882a593Smuzhiyun netdev_dbg(nr->ndp->ndev.dev,
37*4882a593Smuzhiyun "NCSI: unsupported header revision\n");
38*4882a593Smuzhiyun return -EINVAL;
39*4882a593Smuzhiyun }
40*4882a593Smuzhiyun if (ntohs(h->common.length) != payload) {
41*4882a593Smuzhiyun netdev_dbg(nr->ndp->ndev.dev,
42*4882a593Smuzhiyun "NCSI: payload length mismatched\n");
43*4882a593Smuzhiyun return -EINVAL;
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* Check on code and reason */
47*4882a593Smuzhiyun if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
48*4882a593Smuzhiyun ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
49*4882a593Smuzhiyun netdev_dbg(nr->ndp->ndev.dev,
50*4882a593Smuzhiyun "NCSI: non zero response/reason code %04xh, %04xh\n",
51*4882a593Smuzhiyun ntohs(h->code), ntohs(h->reason));
52*4882a593Smuzhiyun return -EPERM;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun /* Validate checksum, which might be zeroes if the
56*4882a593Smuzhiyun * sender doesn't support checksum according to NCSI
57*4882a593Smuzhiyun * specification.
58*4882a593Smuzhiyun */
59*4882a593Smuzhiyun pchecksum = (__be32 *)((void *)(h + 1) + ALIGN(payload, 4) - 4);
60*4882a593Smuzhiyun if (ntohl(*pchecksum) == 0)
61*4882a593Smuzhiyun return 0;
62*4882a593Smuzhiyun
63*4882a593Smuzhiyun checksum = ncsi_calculate_checksum((unsigned char *)h,
64*4882a593Smuzhiyun sizeof(*h) + payload - 4);
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun if (*pchecksum != htonl(checksum)) {
67*4882a593Smuzhiyun netdev_dbg(nr->ndp->ndev.dev,
68*4882a593Smuzhiyun "NCSI: checksum mismatched; recd: %08x calc: %08x\n",
69*4882a593Smuzhiyun *pchecksum, htonl(checksum));
70*4882a593Smuzhiyun return -EINVAL;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
ncsi_rsp_handler_cis(struct ncsi_request * nr)76*4882a593Smuzhiyun static int ncsi_rsp_handler_cis(struct ncsi_request *nr)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
79*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
80*4882a593Smuzhiyun struct ncsi_package *np;
81*4882a593Smuzhiyun struct ncsi_channel *nc;
82*4882a593Smuzhiyun unsigned char id;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
85*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc);
86*4882a593Smuzhiyun if (!nc) {
87*4882a593Smuzhiyun if (ndp->flags & NCSI_DEV_PROBED)
88*4882a593Smuzhiyun return -ENXIO;
89*4882a593Smuzhiyun
90*4882a593Smuzhiyun id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
91*4882a593Smuzhiyun nc = ncsi_add_channel(np, id);
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun return nc ? 0 : -ENODEV;
95*4882a593Smuzhiyun }
96*4882a593Smuzhiyun
ncsi_rsp_handler_sp(struct ncsi_request * nr)97*4882a593Smuzhiyun static int ncsi_rsp_handler_sp(struct ncsi_request *nr)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
100*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
101*4882a593Smuzhiyun struct ncsi_package *np;
102*4882a593Smuzhiyun unsigned char id;
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun /* Add the package if it's not existing. Otherwise,
105*4882a593Smuzhiyun * to change the state of its child channels.
106*4882a593Smuzhiyun */
107*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
108*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
109*4882a593Smuzhiyun &np, NULL);
110*4882a593Smuzhiyun if (!np) {
111*4882a593Smuzhiyun if (ndp->flags & NCSI_DEV_PROBED)
112*4882a593Smuzhiyun return -ENXIO;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel);
115*4882a593Smuzhiyun np = ncsi_add_package(ndp, id);
116*4882a593Smuzhiyun if (!np)
117*4882a593Smuzhiyun return -ENODEV;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun return 0;
121*4882a593Smuzhiyun }
122*4882a593Smuzhiyun
ncsi_rsp_handler_dp(struct ncsi_request * nr)123*4882a593Smuzhiyun static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
126*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
127*4882a593Smuzhiyun struct ncsi_package *np;
128*4882a593Smuzhiyun struct ncsi_channel *nc;
129*4882a593Smuzhiyun unsigned long flags;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun /* Find the package */
132*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
133*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
134*4882a593Smuzhiyun &np, NULL);
135*4882a593Smuzhiyun if (!np)
136*4882a593Smuzhiyun return -ENODEV;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* Change state of all channels attached to the package */
139*4882a593Smuzhiyun NCSI_FOR_EACH_CHANNEL(np, nc) {
140*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
141*4882a593Smuzhiyun nc->state = NCSI_CHANNEL_INACTIVE;
142*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun
145*4882a593Smuzhiyun return 0;
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun
ncsi_rsp_handler_ec(struct ncsi_request * nr)148*4882a593Smuzhiyun static int ncsi_rsp_handler_ec(struct ncsi_request *nr)
149*4882a593Smuzhiyun {
150*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
151*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
152*4882a593Smuzhiyun struct ncsi_channel *nc;
153*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun /* Find the package and channel */
156*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
157*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
158*4882a593Smuzhiyun NULL, &nc);
159*4882a593Smuzhiyun if (!nc)
160*4882a593Smuzhiyun return -ENODEV;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_ENABLE];
163*4882a593Smuzhiyun if (ncm->enable)
164*4882a593Smuzhiyun return 0;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun ncm->enable = 1;
167*4882a593Smuzhiyun return 0;
168*4882a593Smuzhiyun }
169*4882a593Smuzhiyun
ncsi_rsp_handler_dc(struct ncsi_request * nr)170*4882a593Smuzhiyun static int ncsi_rsp_handler_dc(struct ncsi_request *nr)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
173*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
174*4882a593Smuzhiyun struct ncsi_channel *nc;
175*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
176*4882a593Smuzhiyun int ret;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun ret = ncsi_validate_rsp_pkt(nr, 4);
179*4882a593Smuzhiyun if (ret)
180*4882a593Smuzhiyun return ret;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun /* Find the package and channel */
183*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
184*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
185*4882a593Smuzhiyun NULL, &nc);
186*4882a593Smuzhiyun if (!nc)
187*4882a593Smuzhiyun return -ENODEV;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_ENABLE];
190*4882a593Smuzhiyun if (!ncm->enable)
191*4882a593Smuzhiyun return 0;
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun ncm->enable = 0;
194*4882a593Smuzhiyun return 0;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun
ncsi_rsp_handler_rc(struct ncsi_request * nr)197*4882a593Smuzhiyun static int ncsi_rsp_handler_rc(struct ncsi_request *nr)
198*4882a593Smuzhiyun {
199*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
200*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
201*4882a593Smuzhiyun struct ncsi_channel *nc;
202*4882a593Smuzhiyun unsigned long flags;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun /* Find the package and channel */
205*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
206*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
207*4882a593Smuzhiyun NULL, &nc);
208*4882a593Smuzhiyun if (!nc)
209*4882a593Smuzhiyun return -ENODEV;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun /* Update state for the specified channel */
212*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
213*4882a593Smuzhiyun nc->state = NCSI_CHANNEL_INACTIVE;
214*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
ncsi_rsp_handler_ecnt(struct ncsi_request * nr)219*4882a593Smuzhiyun static int ncsi_rsp_handler_ecnt(struct ncsi_request *nr)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
222*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
223*4882a593Smuzhiyun struct ncsi_channel *nc;
224*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /* Find the package and channel */
227*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
228*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
229*4882a593Smuzhiyun NULL, &nc);
230*4882a593Smuzhiyun if (!nc)
231*4882a593Smuzhiyun return -ENODEV;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
234*4882a593Smuzhiyun if (ncm->enable)
235*4882a593Smuzhiyun return 0;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun ncm->enable = 1;
238*4882a593Smuzhiyun return 0;
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun
ncsi_rsp_handler_dcnt(struct ncsi_request * nr)241*4882a593Smuzhiyun static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
244*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
245*4882a593Smuzhiyun struct ncsi_channel *nc;
246*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
247*4882a593Smuzhiyun
248*4882a593Smuzhiyun /* Find the package and channel */
249*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
250*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
251*4882a593Smuzhiyun NULL, &nc);
252*4882a593Smuzhiyun if (!nc)
253*4882a593Smuzhiyun return -ENODEV;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
256*4882a593Smuzhiyun if (!ncm->enable)
257*4882a593Smuzhiyun return 0;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun ncm->enable = 0;
260*4882a593Smuzhiyun return 0;
261*4882a593Smuzhiyun }
262*4882a593Smuzhiyun
ncsi_rsp_handler_ae(struct ncsi_request * nr)263*4882a593Smuzhiyun static int ncsi_rsp_handler_ae(struct ncsi_request *nr)
264*4882a593Smuzhiyun {
265*4882a593Smuzhiyun struct ncsi_cmd_ae_pkt *cmd;
266*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
267*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
268*4882a593Smuzhiyun struct ncsi_channel *nc;
269*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun /* Find the package and channel */
272*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
273*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
274*4882a593Smuzhiyun NULL, &nc);
275*4882a593Smuzhiyun if (!nc)
276*4882a593Smuzhiyun return -ENODEV;
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun /* Check if the AEN has been enabled */
279*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_AEN];
280*4882a593Smuzhiyun if (ncm->enable)
281*4882a593Smuzhiyun return 0;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /* Update to AEN configuration */
284*4882a593Smuzhiyun cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd);
285*4882a593Smuzhiyun ncm->enable = 1;
286*4882a593Smuzhiyun ncm->data[0] = cmd->mc_id;
287*4882a593Smuzhiyun ncm->data[1] = ntohl(cmd->mode);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun return 0;
290*4882a593Smuzhiyun }
291*4882a593Smuzhiyun
ncsi_rsp_handler_sl(struct ncsi_request * nr)292*4882a593Smuzhiyun static int ncsi_rsp_handler_sl(struct ncsi_request *nr)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun struct ncsi_cmd_sl_pkt *cmd;
295*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
296*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
297*4882a593Smuzhiyun struct ncsi_channel *nc;
298*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun /* Find the package and channel */
301*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
302*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
303*4882a593Smuzhiyun NULL, &nc);
304*4882a593Smuzhiyun if (!nc)
305*4882a593Smuzhiyun return -ENODEV;
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd);
308*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_LINK];
309*4882a593Smuzhiyun ncm->data[0] = ntohl(cmd->mode);
310*4882a593Smuzhiyun ncm->data[1] = ntohl(cmd->oem_mode);
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun return 0;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun
ncsi_rsp_handler_gls(struct ncsi_request * nr)315*4882a593Smuzhiyun static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
316*4882a593Smuzhiyun {
317*4882a593Smuzhiyun struct ncsi_rsp_gls_pkt *rsp;
318*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
319*4882a593Smuzhiyun struct ncsi_channel *nc;
320*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
321*4882a593Smuzhiyun unsigned long flags;
322*4882a593Smuzhiyun
323*4882a593Smuzhiyun /* Find the package and channel */
324*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp);
325*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
326*4882a593Smuzhiyun NULL, &nc);
327*4882a593Smuzhiyun if (!nc)
328*4882a593Smuzhiyun return -ENODEV;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_LINK];
331*4882a593Smuzhiyun ncm->data[2] = ntohl(rsp->status);
332*4882a593Smuzhiyun ncm->data[3] = ntohl(rsp->other);
333*4882a593Smuzhiyun ncm->data[4] = ntohl(rsp->oem_status);
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN)
336*4882a593Smuzhiyun return 0;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* Reset the channel monitor if it has been enabled */
339*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
340*4882a593Smuzhiyun nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
341*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun return 0;
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
ncsi_rsp_handler_svf(struct ncsi_request * nr)346*4882a593Smuzhiyun static int ncsi_rsp_handler_svf(struct ncsi_request *nr)
347*4882a593Smuzhiyun {
348*4882a593Smuzhiyun struct ncsi_cmd_svf_pkt *cmd;
349*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
350*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
351*4882a593Smuzhiyun struct ncsi_channel *nc;
352*4882a593Smuzhiyun struct ncsi_channel_vlan_filter *ncf;
353*4882a593Smuzhiyun unsigned long flags;
354*4882a593Smuzhiyun void *bitmap;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun /* Find the package and channel */
357*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
358*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
359*4882a593Smuzhiyun NULL, &nc);
360*4882a593Smuzhiyun if (!nc)
361*4882a593Smuzhiyun return -ENODEV;
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd);
364*4882a593Smuzhiyun ncf = &nc->vlan_filter;
365*4882a593Smuzhiyun if (cmd->index == 0 || cmd->index > ncf->n_vids)
366*4882a593Smuzhiyun return -ERANGE;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun /* Add or remove the VLAN filter. Remember HW indexes from 1 */
369*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
370*4882a593Smuzhiyun bitmap = &ncf->bitmap;
371*4882a593Smuzhiyun if (!(cmd->enable & 0x1)) {
372*4882a593Smuzhiyun if (test_and_clear_bit(cmd->index - 1, bitmap))
373*4882a593Smuzhiyun ncf->vids[cmd->index - 1] = 0;
374*4882a593Smuzhiyun } else {
375*4882a593Smuzhiyun set_bit(cmd->index - 1, bitmap);
376*4882a593Smuzhiyun ncf->vids[cmd->index - 1] = ntohs(cmd->vlan);
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun return 0;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun
ncsi_rsp_handler_ev(struct ncsi_request * nr)383*4882a593Smuzhiyun static int ncsi_rsp_handler_ev(struct ncsi_request *nr)
384*4882a593Smuzhiyun {
385*4882a593Smuzhiyun struct ncsi_cmd_ev_pkt *cmd;
386*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
387*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
388*4882a593Smuzhiyun struct ncsi_channel *nc;
389*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun /* Find the package and channel */
392*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
393*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
394*4882a593Smuzhiyun NULL, &nc);
395*4882a593Smuzhiyun if (!nc)
396*4882a593Smuzhiyun return -ENODEV;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun /* Check if VLAN mode has been enabled */
399*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_VLAN];
400*4882a593Smuzhiyun if (ncm->enable)
401*4882a593Smuzhiyun return 0;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun /* Update to VLAN mode */
404*4882a593Smuzhiyun cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd);
405*4882a593Smuzhiyun ncm->enable = 1;
406*4882a593Smuzhiyun ncm->data[0] = ntohl(cmd->mode);
407*4882a593Smuzhiyun
408*4882a593Smuzhiyun return 0;
409*4882a593Smuzhiyun }
410*4882a593Smuzhiyun
ncsi_rsp_handler_dv(struct ncsi_request * nr)411*4882a593Smuzhiyun static int ncsi_rsp_handler_dv(struct ncsi_request *nr)
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
414*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
415*4882a593Smuzhiyun struct ncsi_channel *nc;
416*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun /* Find the package and channel */
419*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
420*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
421*4882a593Smuzhiyun NULL, &nc);
422*4882a593Smuzhiyun if (!nc)
423*4882a593Smuzhiyun return -ENODEV;
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun /* Check if VLAN mode has been enabled */
426*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_VLAN];
427*4882a593Smuzhiyun if (!ncm->enable)
428*4882a593Smuzhiyun return 0;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /* Update to VLAN mode */
431*4882a593Smuzhiyun ncm->enable = 0;
432*4882a593Smuzhiyun return 0;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun
ncsi_rsp_handler_sma(struct ncsi_request * nr)435*4882a593Smuzhiyun static int ncsi_rsp_handler_sma(struct ncsi_request *nr)
436*4882a593Smuzhiyun {
437*4882a593Smuzhiyun struct ncsi_cmd_sma_pkt *cmd;
438*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
439*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
440*4882a593Smuzhiyun struct ncsi_channel *nc;
441*4882a593Smuzhiyun struct ncsi_channel_mac_filter *ncf;
442*4882a593Smuzhiyun unsigned long flags;
443*4882a593Smuzhiyun void *bitmap;
444*4882a593Smuzhiyun bool enabled;
445*4882a593Smuzhiyun int index;
446*4882a593Smuzhiyun
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* Find the package and channel */
449*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
450*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
451*4882a593Smuzhiyun NULL, &nc);
452*4882a593Smuzhiyun if (!nc)
453*4882a593Smuzhiyun return -ENODEV;
454*4882a593Smuzhiyun
455*4882a593Smuzhiyun /* According to NCSI spec 1.01, the mixed filter table
456*4882a593Smuzhiyun * isn't supported yet.
457*4882a593Smuzhiyun */
458*4882a593Smuzhiyun cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd);
459*4882a593Smuzhiyun enabled = cmd->at_e & 0x1;
460*4882a593Smuzhiyun ncf = &nc->mac_filter;
461*4882a593Smuzhiyun bitmap = &ncf->bitmap;
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun if (cmd->index == 0 ||
464*4882a593Smuzhiyun cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed)
465*4882a593Smuzhiyun return -ERANGE;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun index = (cmd->index - 1) * ETH_ALEN;
468*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
469*4882a593Smuzhiyun if (enabled) {
470*4882a593Smuzhiyun set_bit(cmd->index - 1, bitmap);
471*4882a593Smuzhiyun memcpy(&ncf->addrs[index], cmd->mac, ETH_ALEN);
472*4882a593Smuzhiyun } else {
473*4882a593Smuzhiyun clear_bit(cmd->index - 1, bitmap);
474*4882a593Smuzhiyun eth_zero_addr(&ncf->addrs[index]);
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun return 0;
479*4882a593Smuzhiyun }
480*4882a593Smuzhiyun
ncsi_rsp_handler_ebf(struct ncsi_request * nr)481*4882a593Smuzhiyun static int ncsi_rsp_handler_ebf(struct ncsi_request *nr)
482*4882a593Smuzhiyun {
483*4882a593Smuzhiyun struct ncsi_cmd_ebf_pkt *cmd;
484*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
485*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
486*4882a593Smuzhiyun struct ncsi_channel *nc;
487*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
488*4882a593Smuzhiyun
489*4882a593Smuzhiyun /* Find the package and channel */
490*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
491*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc);
492*4882a593Smuzhiyun if (!nc)
493*4882a593Smuzhiyun return -ENODEV;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun /* Check if broadcast filter has been enabled */
496*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_BC];
497*4882a593Smuzhiyun if (ncm->enable)
498*4882a593Smuzhiyun return 0;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun /* Update to broadcast filter mode */
501*4882a593Smuzhiyun cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd);
502*4882a593Smuzhiyun ncm->enable = 1;
503*4882a593Smuzhiyun ncm->data[0] = ntohl(cmd->mode);
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun return 0;
506*4882a593Smuzhiyun }
507*4882a593Smuzhiyun
ncsi_rsp_handler_dbf(struct ncsi_request * nr)508*4882a593Smuzhiyun static int ncsi_rsp_handler_dbf(struct ncsi_request *nr)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
511*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
512*4882a593Smuzhiyun struct ncsi_channel *nc;
513*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
514*4882a593Smuzhiyun
515*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
516*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
517*4882a593Smuzhiyun NULL, &nc);
518*4882a593Smuzhiyun if (!nc)
519*4882a593Smuzhiyun return -ENODEV;
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun /* Check if broadcast filter isn't enabled */
522*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_BC];
523*4882a593Smuzhiyun if (!ncm->enable)
524*4882a593Smuzhiyun return 0;
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun /* Update to broadcast filter mode */
527*4882a593Smuzhiyun ncm->enable = 0;
528*4882a593Smuzhiyun ncm->data[0] = 0;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun return 0;
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun
ncsi_rsp_handler_egmf(struct ncsi_request * nr)533*4882a593Smuzhiyun static int ncsi_rsp_handler_egmf(struct ncsi_request *nr)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun struct ncsi_cmd_egmf_pkt *cmd;
536*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
537*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
538*4882a593Smuzhiyun struct ncsi_channel *nc;
539*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun /* Find the channel */
542*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
543*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
544*4882a593Smuzhiyun NULL, &nc);
545*4882a593Smuzhiyun if (!nc)
546*4882a593Smuzhiyun return -ENODEV;
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /* Check if multicast filter has been enabled */
549*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_MC];
550*4882a593Smuzhiyun if (ncm->enable)
551*4882a593Smuzhiyun return 0;
552*4882a593Smuzhiyun
553*4882a593Smuzhiyun /* Update to multicast filter mode */
554*4882a593Smuzhiyun cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd);
555*4882a593Smuzhiyun ncm->enable = 1;
556*4882a593Smuzhiyun ncm->data[0] = ntohl(cmd->mode);
557*4882a593Smuzhiyun
558*4882a593Smuzhiyun return 0;
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun
ncsi_rsp_handler_dgmf(struct ncsi_request * nr)561*4882a593Smuzhiyun static int ncsi_rsp_handler_dgmf(struct ncsi_request *nr)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
564*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
565*4882a593Smuzhiyun struct ncsi_channel *nc;
566*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
569*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
570*4882a593Smuzhiyun NULL, &nc);
571*4882a593Smuzhiyun if (!nc)
572*4882a593Smuzhiyun return -ENODEV;
573*4882a593Smuzhiyun
574*4882a593Smuzhiyun /* Check if multicast filter has been enabled */
575*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_MC];
576*4882a593Smuzhiyun if (!ncm->enable)
577*4882a593Smuzhiyun return 0;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun /* Update to multicast filter mode */
580*4882a593Smuzhiyun ncm->enable = 0;
581*4882a593Smuzhiyun ncm->data[0] = 0;
582*4882a593Smuzhiyun
583*4882a593Smuzhiyun return 0;
584*4882a593Smuzhiyun }
585*4882a593Smuzhiyun
ncsi_rsp_handler_snfc(struct ncsi_request * nr)586*4882a593Smuzhiyun static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
587*4882a593Smuzhiyun {
588*4882a593Smuzhiyun struct ncsi_cmd_snfc_pkt *cmd;
589*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
590*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
591*4882a593Smuzhiyun struct ncsi_channel *nc;
592*4882a593Smuzhiyun struct ncsi_channel_mode *ncm;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /* Find the channel */
595*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
596*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
597*4882a593Smuzhiyun NULL, &nc);
598*4882a593Smuzhiyun if (!nc)
599*4882a593Smuzhiyun return -ENODEV;
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun /* Check if flow control has been enabled */
602*4882a593Smuzhiyun ncm = &nc->modes[NCSI_MODE_FC];
603*4882a593Smuzhiyun if (ncm->enable)
604*4882a593Smuzhiyun return 0;
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun /* Update to flow control mode */
607*4882a593Smuzhiyun cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd);
608*4882a593Smuzhiyun ncm->enable = 1;
609*4882a593Smuzhiyun ncm->data[0] = cmd->mode;
610*4882a593Smuzhiyun
611*4882a593Smuzhiyun return 0;
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun /* Response handler for Mellanox command Get Mac Address */
ncsi_rsp_handler_oem_mlx_gma(struct ncsi_request * nr)615*4882a593Smuzhiyun static int ncsi_rsp_handler_oem_mlx_gma(struct ncsi_request *nr)
616*4882a593Smuzhiyun {
617*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
618*4882a593Smuzhiyun struct net_device *ndev = ndp->ndev.dev;
619*4882a593Smuzhiyun const struct net_device_ops *ops = ndev->netdev_ops;
620*4882a593Smuzhiyun struct ncsi_rsp_oem_pkt *rsp;
621*4882a593Smuzhiyun struct sockaddr saddr;
622*4882a593Smuzhiyun int ret = 0;
623*4882a593Smuzhiyun
624*4882a593Smuzhiyun /* Get the response header */
625*4882a593Smuzhiyun rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
626*4882a593Smuzhiyun
627*4882a593Smuzhiyun saddr.sa_family = ndev->type;
628*4882a593Smuzhiyun ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
629*4882a593Smuzhiyun memcpy(saddr.sa_data, &rsp->data[MLX_MAC_ADDR_OFFSET], ETH_ALEN);
630*4882a593Smuzhiyun /* Set the flag for GMA command which should only be called once */
631*4882a593Smuzhiyun ndp->gma_flag = 1;
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun ret = ops->ndo_set_mac_address(ndev, &saddr);
634*4882a593Smuzhiyun if (ret < 0)
635*4882a593Smuzhiyun netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n");
636*4882a593Smuzhiyun
637*4882a593Smuzhiyun return ret;
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun /* Response handler for Mellanox card */
ncsi_rsp_handler_oem_mlx(struct ncsi_request * nr)641*4882a593Smuzhiyun static int ncsi_rsp_handler_oem_mlx(struct ncsi_request *nr)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun struct ncsi_rsp_oem_mlx_pkt *mlx;
644*4882a593Smuzhiyun struct ncsi_rsp_oem_pkt *rsp;
645*4882a593Smuzhiyun
646*4882a593Smuzhiyun /* Get the response header */
647*4882a593Smuzhiyun rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
648*4882a593Smuzhiyun mlx = (struct ncsi_rsp_oem_mlx_pkt *)(rsp->data);
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun if (mlx->cmd == NCSI_OEM_MLX_CMD_GMA &&
651*4882a593Smuzhiyun mlx->param == NCSI_OEM_MLX_CMD_GMA_PARAM)
652*4882a593Smuzhiyun return ncsi_rsp_handler_oem_mlx_gma(nr);
653*4882a593Smuzhiyun return 0;
654*4882a593Smuzhiyun }
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun /* Response handler for Broadcom command Get Mac Address */
ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request * nr)657*4882a593Smuzhiyun static int ncsi_rsp_handler_oem_bcm_gma(struct ncsi_request *nr)
658*4882a593Smuzhiyun {
659*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
660*4882a593Smuzhiyun struct net_device *ndev = ndp->ndev.dev;
661*4882a593Smuzhiyun const struct net_device_ops *ops = ndev->netdev_ops;
662*4882a593Smuzhiyun struct ncsi_rsp_oem_pkt *rsp;
663*4882a593Smuzhiyun struct sockaddr saddr;
664*4882a593Smuzhiyun int ret = 0;
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun /* Get the response header */
667*4882a593Smuzhiyun rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
668*4882a593Smuzhiyun
669*4882a593Smuzhiyun saddr.sa_family = ndev->type;
670*4882a593Smuzhiyun ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
671*4882a593Smuzhiyun memcpy(saddr.sa_data, &rsp->data[BCM_MAC_ADDR_OFFSET], ETH_ALEN);
672*4882a593Smuzhiyun /* Increase mac address by 1 for BMC's address */
673*4882a593Smuzhiyun eth_addr_inc((u8 *)saddr.sa_data);
674*4882a593Smuzhiyun if (!is_valid_ether_addr((const u8 *)saddr.sa_data))
675*4882a593Smuzhiyun return -ENXIO;
676*4882a593Smuzhiyun
677*4882a593Smuzhiyun /* Set the flag for GMA command which should only be called once */
678*4882a593Smuzhiyun ndp->gma_flag = 1;
679*4882a593Smuzhiyun
680*4882a593Smuzhiyun ret = ops->ndo_set_mac_address(ndev, &saddr);
681*4882a593Smuzhiyun if (ret < 0)
682*4882a593Smuzhiyun netdev_warn(ndev, "NCSI: 'Writing mac address to device failed\n");
683*4882a593Smuzhiyun
684*4882a593Smuzhiyun return ret;
685*4882a593Smuzhiyun }
686*4882a593Smuzhiyun
687*4882a593Smuzhiyun /* Response handler for Broadcom card */
ncsi_rsp_handler_oem_bcm(struct ncsi_request * nr)688*4882a593Smuzhiyun static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun struct ncsi_rsp_oem_bcm_pkt *bcm;
691*4882a593Smuzhiyun struct ncsi_rsp_oem_pkt *rsp;
692*4882a593Smuzhiyun
693*4882a593Smuzhiyun /* Get the response header */
694*4882a593Smuzhiyun rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
695*4882a593Smuzhiyun bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
698*4882a593Smuzhiyun return ncsi_rsp_handler_oem_bcm_gma(nr);
699*4882a593Smuzhiyun return 0;
700*4882a593Smuzhiyun }
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun static struct ncsi_rsp_oem_handler {
703*4882a593Smuzhiyun unsigned int mfr_id;
704*4882a593Smuzhiyun int (*handler)(struct ncsi_request *nr);
705*4882a593Smuzhiyun } ncsi_rsp_oem_handlers[] = {
706*4882a593Smuzhiyun { NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx },
707*4882a593Smuzhiyun { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm }
708*4882a593Smuzhiyun };
709*4882a593Smuzhiyun
710*4882a593Smuzhiyun /* Response handler for OEM command */
ncsi_rsp_handler_oem(struct ncsi_request * nr)711*4882a593Smuzhiyun static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
712*4882a593Smuzhiyun {
713*4882a593Smuzhiyun struct ncsi_rsp_oem_handler *nrh = NULL;
714*4882a593Smuzhiyun struct ncsi_rsp_oem_pkt *rsp;
715*4882a593Smuzhiyun unsigned int mfr_id, i;
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun /* Get the response header */
718*4882a593Smuzhiyun rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
719*4882a593Smuzhiyun mfr_id = ntohl(rsp->mfr_id);
720*4882a593Smuzhiyun
721*4882a593Smuzhiyun /* Check for manufacturer id and Find the handler */
722*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
723*4882a593Smuzhiyun if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
724*4882a593Smuzhiyun if (ncsi_rsp_oem_handlers[i].handler)
725*4882a593Smuzhiyun nrh = &ncsi_rsp_oem_handlers[i];
726*4882a593Smuzhiyun else
727*4882a593Smuzhiyun nrh = NULL;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun break;
730*4882a593Smuzhiyun }
731*4882a593Smuzhiyun }
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun if (!nrh) {
734*4882a593Smuzhiyun netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
735*4882a593Smuzhiyun mfr_id);
736*4882a593Smuzhiyun return -ENOENT;
737*4882a593Smuzhiyun }
738*4882a593Smuzhiyun
739*4882a593Smuzhiyun /* Process the packet */
740*4882a593Smuzhiyun return nrh->handler(nr);
741*4882a593Smuzhiyun }
742*4882a593Smuzhiyun
ncsi_rsp_handler_gvi(struct ncsi_request * nr)743*4882a593Smuzhiyun static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
744*4882a593Smuzhiyun {
745*4882a593Smuzhiyun struct ncsi_rsp_gvi_pkt *rsp;
746*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
747*4882a593Smuzhiyun struct ncsi_channel *nc;
748*4882a593Smuzhiyun struct ncsi_channel_version *ncv;
749*4882a593Smuzhiyun int i;
750*4882a593Smuzhiyun
751*4882a593Smuzhiyun /* Find the channel */
752*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp);
753*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
754*4882a593Smuzhiyun NULL, &nc);
755*4882a593Smuzhiyun if (!nc)
756*4882a593Smuzhiyun return -ENODEV;
757*4882a593Smuzhiyun
758*4882a593Smuzhiyun /* Update to channel's version info */
759*4882a593Smuzhiyun ncv = &nc->version;
760*4882a593Smuzhiyun ncv->version = ntohl(rsp->ncsi_version);
761*4882a593Smuzhiyun ncv->alpha2 = rsp->alpha2;
762*4882a593Smuzhiyun memcpy(ncv->fw_name, rsp->fw_name, 12);
763*4882a593Smuzhiyun ncv->fw_version = ntohl(rsp->fw_version);
764*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(ncv->pci_ids); i++)
765*4882a593Smuzhiyun ncv->pci_ids[i] = ntohs(rsp->pci_ids[i]);
766*4882a593Smuzhiyun ncv->mf_id = ntohl(rsp->mf_id);
767*4882a593Smuzhiyun
768*4882a593Smuzhiyun return 0;
769*4882a593Smuzhiyun }
770*4882a593Smuzhiyun
ncsi_rsp_handler_gc(struct ncsi_request * nr)771*4882a593Smuzhiyun static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
772*4882a593Smuzhiyun {
773*4882a593Smuzhiyun struct ncsi_rsp_gc_pkt *rsp;
774*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
775*4882a593Smuzhiyun struct ncsi_channel *nc;
776*4882a593Smuzhiyun size_t size;
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun /* Find the channel */
779*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp);
780*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
781*4882a593Smuzhiyun NULL, &nc);
782*4882a593Smuzhiyun if (!nc)
783*4882a593Smuzhiyun return -ENODEV;
784*4882a593Smuzhiyun
785*4882a593Smuzhiyun /* Update channel's capabilities */
786*4882a593Smuzhiyun nc->caps[NCSI_CAP_GENERIC].cap = ntohl(rsp->cap) &
787*4882a593Smuzhiyun NCSI_CAP_GENERIC_MASK;
788*4882a593Smuzhiyun nc->caps[NCSI_CAP_BC].cap = ntohl(rsp->bc_cap) &
789*4882a593Smuzhiyun NCSI_CAP_BC_MASK;
790*4882a593Smuzhiyun nc->caps[NCSI_CAP_MC].cap = ntohl(rsp->mc_cap) &
791*4882a593Smuzhiyun NCSI_CAP_MC_MASK;
792*4882a593Smuzhiyun nc->caps[NCSI_CAP_BUFFER].cap = ntohl(rsp->buf_cap);
793*4882a593Smuzhiyun nc->caps[NCSI_CAP_AEN].cap = ntohl(rsp->aen_cap) &
794*4882a593Smuzhiyun NCSI_CAP_AEN_MASK;
795*4882a593Smuzhiyun nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode &
796*4882a593Smuzhiyun NCSI_CAP_VLAN_MASK;
797*4882a593Smuzhiyun
798*4882a593Smuzhiyun size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN;
799*4882a593Smuzhiyun nc->mac_filter.addrs = kzalloc(size, GFP_ATOMIC);
800*4882a593Smuzhiyun if (!nc->mac_filter.addrs)
801*4882a593Smuzhiyun return -ENOMEM;
802*4882a593Smuzhiyun nc->mac_filter.n_uc = rsp->uc_cnt;
803*4882a593Smuzhiyun nc->mac_filter.n_mc = rsp->mc_cnt;
804*4882a593Smuzhiyun nc->mac_filter.n_mixed = rsp->mixed_cnt;
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt,
807*4882a593Smuzhiyun sizeof(*nc->vlan_filter.vids),
808*4882a593Smuzhiyun GFP_ATOMIC);
809*4882a593Smuzhiyun if (!nc->vlan_filter.vids)
810*4882a593Smuzhiyun return -ENOMEM;
811*4882a593Smuzhiyun /* Set VLAN filters active so they are cleared in the first
812*4882a593Smuzhiyun * configuration state
813*4882a593Smuzhiyun */
814*4882a593Smuzhiyun nc->vlan_filter.bitmap = U64_MAX;
815*4882a593Smuzhiyun nc->vlan_filter.n_vids = rsp->vlan_cnt;
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun return 0;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
ncsi_rsp_handler_gp(struct ncsi_request * nr)820*4882a593Smuzhiyun static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
821*4882a593Smuzhiyun {
822*4882a593Smuzhiyun struct ncsi_channel_vlan_filter *ncvf;
823*4882a593Smuzhiyun struct ncsi_channel_mac_filter *ncmf;
824*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
825*4882a593Smuzhiyun struct ncsi_rsp_gp_pkt *rsp;
826*4882a593Smuzhiyun struct ncsi_channel *nc;
827*4882a593Smuzhiyun unsigned short enable;
828*4882a593Smuzhiyun unsigned char *pdata;
829*4882a593Smuzhiyun unsigned long flags;
830*4882a593Smuzhiyun void *bitmap;
831*4882a593Smuzhiyun int i;
832*4882a593Smuzhiyun
833*4882a593Smuzhiyun /* Find the channel */
834*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp);
835*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
836*4882a593Smuzhiyun NULL, &nc);
837*4882a593Smuzhiyun if (!nc)
838*4882a593Smuzhiyun return -ENODEV;
839*4882a593Smuzhiyun
840*4882a593Smuzhiyun /* Modes with explicit enabled indications */
841*4882a593Smuzhiyun if (ntohl(rsp->valid_modes) & 0x1) { /* BC filter mode */
842*4882a593Smuzhiyun nc->modes[NCSI_MODE_BC].enable = 1;
843*4882a593Smuzhiyun nc->modes[NCSI_MODE_BC].data[0] = ntohl(rsp->bc_mode);
844*4882a593Smuzhiyun }
845*4882a593Smuzhiyun if (ntohl(rsp->valid_modes) & 0x2) /* Channel enabled */
846*4882a593Smuzhiyun nc->modes[NCSI_MODE_ENABLE].enable = 1;
847*4882a593Smuzhiyun if (ntohl(rsp->valid_modes) & 0x4) /* Channel Tx enabled */
848*4882a593Smuzhiyun nc->modes[NCSI_MODE_TX_ENABLE].enable = 1;
849*4882a593Smuzhiyun if (ntohl(rsp->valid_modes) & 0x8) /* MC filter mode */
850*4882a593Smuzhiyun nc->modes[NCSI_MODE_MC].enable = 1;
851*4882a593Smuzhiyun
852*4882a593Smuzhiyun /* Modes without explicit enabled indications */
853*4882a593Smuzhiyun nc->modes[NCSI_MODE_LINK].enable = 1;
854*4882a593Smuzhiyun nc->modes[NCSI_MODE_LINK].data[0] = ntohl(rsp->link_mode);
855*4882a593Smuzhiyun nc->modes[NCSI_MODE_VLAN].enable = 1;
856*4882a593Smuzhiyun nc->modes[NCSI_MODE_VLAN].data[0] = rsp->vlan_mode;
857*4882a593Smuzhiyun nc->modes[NCSI_MODE_FC].enable = 1;
858*4882a593Smuzhiyun nc->modes[NCSI_MODE_FC].data[0] = rsp->fc_mode;
859*4882a593Smuzhiyun nc->modes[NCSI_MODE_AEN].enable = 1;
860*4882a593Smuzhiyun nc->modes[NCSI_MODE_AEN].data[0] = ntohl(rsp->aen_mode);
861*4882a593Smuzhiyun
862*4882a593Smuzhiyun /* MAC addresses filter table */
863*4882a593Smuzhiyun pdata = (unsigned char *)rsp + 48;
864*4882a593Smuzhiyun enable = rsp->mac_enable;
865*4882a593Smuzhiyun ncmf = &nc->mac_filter;
866*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
867*4882a593Smuzhiyun bitmap = &ncmf->bitmap;
868*4882a593Smuzhiyun for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) {
869*4882a593Smuzhiyun if (!(enable & (0x1 << i)))
870*4882a593Smuzhiyun clear_bit(i, bitmap);
871*4882a593Smuzhiyun else
872*4882a593Smuzhiyun set_bit(i, bitmap);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun memcpy(&ncmf->addrs[i * ETH_ALEN], pdata, ETH_ALEN);
875*4882a593Smuzhiyun }
876*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
877*4882a593Smuzhiyun
878*4882a593Smuzhiyun /* VLAN filter table */
879*4882a593Smuzhiyun enable = ntohs(rsp->vlan_enable);
880*4882a593Smuzhiyun ncvf = &nc->vlan_filter;
881*4882a593Smuzhiyun bitmap = &ncvf->bitmap;
882*4882a593Smuzhiyun spin_lock_irqsave(&nc->lock, flags);
883*4882a593Smuzhiyun for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) {
884*4882a593Smuzhiyun if (!(enable & (0x1 << i)))
885*4882a593Smuzhiyun clear_bit(i, bitmap);
886*4882a593Smuzhiyun else
887*4882a593Smuzhiyun set_bit(i, bitmap);
888*4882a593Smuzhiyun
889*4882a593Smuzhiyun ncvf->vids[i] = ntohs(*(__be16 *)pdata);
890*4882a593Smuzhiyun }
891*4882a593Smuzhiyun spin_unlock_irqrestore(&nc->lock, flags);
892*4882a593Smuzhiyun
893*4882a593Smuzhiyun return 0;
894*4882a593Smuzhiyun }
895*4882a593Smuzhiyun
ncsi_rsp_handler_gcps(struct ncsi_request * nr)896*4882a593Smuzhiyun static int ncsi_rsp_handler_gcps(struct ncsi_request *nr)
897*4882a593Smuzhiyun {
898*4882a593Smuzhiyun struct ncsi_rsp_gcps_pkt *rsp;
899*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
900*4882a593Smuzhiyun struct ncsi_channel *nc;
901*4882a593Smuzhiyun struct ncsi_channel_stats *ncs;
902*4882a593Smuzhiyun
903*4882a593Smuzhiyun /* Find the channel */
904*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gcps_pkt *)skb_network_header(nr->rsp);
905*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
906*4882a593Smuzhiyun NULL, &nc);
907*4882a593Smuzhiyun if (!nc)
908*4882a593Smuzhiyun return -ENODEV;
909*4882a593Smuzhiyun
910*4882a593Smuzhiyun /* Update HNC's statistics */
911*4882a593Smuzhiyun ncs = &nc->stats;
912*4882a593Smuzhiyun ncs->hnc_cnt_hi = ntohl(rsp->cnt_hi);
913*4882a593Smuzhiyun ncs->hnc_cnt_lo = ntohl(rsp->cnt_lo);
914*4882a593Smuzhiyun ncs->hnc_rx_bytes = ntohl(rsp->rx_bytes);
915*4882a593Smuzhiyun ncs->hnc_tx_bytes = ntohl(rsp->tx_bytes);
916*4882a593Smuzhiyun ncs->hnc_rx_uc_pkts = ntohl(rsp->rx_uc_pkts);
917*4882a593Smuzhiyun ncs->hnc_rx_mc_pkts = ntohl(rsp->rx_mc_pkts);
918*4882a593Smuzhiyun ncs->hnc_rx_bc_pkts = ntohl(rsp->rx_bc_pkts);
919*4882a593Smuzhiyun ncs->hnc_tx_uc_pkts = ntohl(rsp->tx_uc_pkts);
920*4882a593Smuzhiyun ncs->hnc_tx_mc_pkts = ntohl(rsp->tx_mc_pkts);
921*4882a593Smuzhiyun ncs->hnc_tx_bc_pkts = ntohl(rsp->tx_bc_pkts);
922*4882a593Smuzhiyun ncs->hnc_fcs_err = ntohl(rsp->fcs_err);
923*4882a593Smuzhiyun ncs->hnc_align_err = ntohl(rsp->align_err);
924*4882a593Smuzhiyun ncs->hnc_false_carrier = ntohl(rsp->false_carrier);
925*4882a593Smuzhiyun ncs->hnc_runt_pkts = ntohl(rsp->runt_pkts);
926*4882a593Smuzhiyun ncs->hnc_jabber_pkts = ntohl(rsp->jabber_pkts);
927*4882a593Smuzhiyun ncs->hnc_rx_pause_xon = ntohl(rsp->rx_pause_xon);
928*4882a593Smuzhiyun ncs->hnc_rx_pause_xoff = ntohl(rsp->rx_pause_xoff);
929*4882a593Smuzhiyun ncs->hnc_tx_pause_xon = ntohl(rsp->tx_pause_xon);
930*4882a593Smuzhiyun ncs->hnc_tx_pause_xoff = ntohl(rsp->tx_pause_xoff);
931*4882a593Smuzhiyun ncs->hnc_tx_s_collision = ntohl(rsp->tx_s_collision);
932*4882a593Smuzhiyun ncs->hnc_tx_m_collision = ntohl(rsp->tx_m_collision);
933*4882a593Smuzhiyun ncs->hnc_l_collision = ntohl(rsp->l_collision);
934*4882a593Smuzhiyun ncs->hnc_e_collision = ntohl(rsp->e_collision);
935*4882a593Smuzhiyun ncs->hnc_rx_ctl_frames = ntohl(rsp->rx_ctl_frames);
936*4882a593Smuzhiyun ncs->hnc_rx_64_frames = ntohl(rsp->rx_64_frames);
937*4882a593Smuzhiyun ncs->hnc_rx_127_frames = ntohl(rsp->rx_127_frames);
938*4882a593Smuzhiyun ncs->hnc_rx_255_frames = ntohl(rsp->rx_255_frames);
939*4882a593Smuzhiyun ncs->hnc_rx_511_frames = ntohl(rsp->rx_511_frames);
940*4882a593Smuzhiyun ncs->hnc_rx_1023_frames = ntohl(rsp->rx_1023_frames);
941*4882a593Smuzhiyun ncs->hnc_rx_1522_frames = ntohl(rsp->rx_1522_frames);
942*4882a593Smuzhiyun ncs->hnc_rx_9022_frames = ntohl(rsp->rx_9022_frames);
943*4882a593Smuzhiyun ncs->hnc_tx_64_frames = ntohl(rsp->tx_64_frames);
944*4882a593Smuzhiyun ncs->hnc_tx_127_frames = ntohl(rsp->tx_127_frames);
945*4882a593Smuzhiyun ncs->hnc_tx_255_frames = ntohl(rsp->tx_255_frames);
946*4882a593Smuzhiyun ncs->hnc_tx_511_frames = ntohl(rsp->tx_511_frames);
947*4882a593Smuzhiyun ncs->hnc_tx_1023_frames = ntohl(rsp->tx_1023_frames);
948*4882a593Smuzhiyun ncs->hnc_tx_1522_frames = ntohl(rsp->tx_1522_frames);
949*4882a593Smuzhiyun ncs->hnc_tx_9022_frames = ntohl(rsp->tx_9022_frames);
950*4882a593Smuzhiyun ncs->hnc_rx_valid_bytes = ntohl(rsp->rx_valid_bytes);
951*4882a593Smuzhiyun ncs->hnc_rx_runt_pkts = ntohl(rsp->rx_runt_pkts);
952*4882a593Smuzhiyun ncs->hnc_rx_jabber_pkts = ntohl(rsp->rx_jabber_pkts);
953*4882a593Smuzhiyun
954*4882a593Smuzhiyun return 0;
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun
ncsi_rsp_handler_gns(struct ncsi_request * nr)957*4882a593Smuzhiyun static int ncsi_rsp_handler_gns(struct ncsi_request *nr)
958*4882a593Smuzhiyun {
959*4882a593Smuzhiyun struct ncsi_rsp_gns_pkt *rsp;
960*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
961*4882a593Smuzhiyun struct ncsi_channel *nc;
962*4882a593Smuzhiyun struct ncsi_channel_stats *ncs;
963*4882a593Smuzhiyun
964*4882a593Smuzhiyun /* Find the channel */
965*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gns_pkt *)skb_network_header(nr->rsp);
966*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
967*4882a593Smuzhiyun NULL, &nc);
968*4882a593Smuzhiyun if (!nc)
969*4882a593Smuzhiyun return -ENODEV;
970*4882a593Smuzhiyun
971*4882a593Smuzhiyun /* Update HNC's statistics */
972*4882a593Smuzhiyun ncs = &nc->stats;
973*4882a593Smuzhiyun ncs->ncsi_rx_cmds = ntohl(rsp->rx_cmds);
974*4882a593Smuzhiyun ncs->ncsi_dropped_cmds = ntohl(rsp->dropped_cmds);
975*4882a593Smuzhiyun ncs->ncsi_cmd_type_errs = ntohl(rsp->cmd_type_errs);
976*4882a593Smuzhiyun ncs->ncsi_cmd_csum_errs = ntohl(rsp->cmd_csum_errs);
977*4882a593Smuzhiyun ncs->ncsi_rx_pkts = ntohl(rsp->rx_pkts);
978*4882a593Smuzhiyun ncs->ncsi_tx_pkts = ntohl(rsp->tx_pkts);
979*4882a593Smuzhiyun ncs->ncsi_tx_aen_pkts = ntohl(rsp->tx_aen_pkts);
980*4882a593Smuzhiyun
981*4882a593Smuzhiyun return 0;
982*4882a593Smuzhiyun }
983*4882a593Smuzhiyun
ncsi_rsp_handler_gnpts(struct ncsi_request * nr)984*4882a593Smuzhiyun static int ncsi_rsp_handler_gnpts(struct ncsi_request *nr)
985*4882a593Smuzhiyun {
986*4882a593Smuzhiyun struct ncsi_rsp_gnpts_pkt *rsp;
987*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
988*4882a593Smuzhiyun struct ncsi_channel *nc;
989*4882a593Smuzhiyun struct ncsi_channel_stats *ncs;
990*4882a593Smuzhiyun
991*4882a593Smuzhiyun /* Find the channel */
992*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(nr->rsp);
993*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
994*4882a593Smuzhiyun NULL, &nc);
995*4882a593Smuzhiyun if (!nc)
996*4882a593Smuzhiyun return -ENODEV;
997*4882a593Smuzhiyun
998*4882a593Smuzhiyun /* Update HNC's statistics */
999*4882a593Smuzhiyun ncs = &nc->stats;
1000*4882a593Smuzhiyun ncs->pt_tx_pkts = ntohl(rsp->tx_pkts);
1001*4882a593Smuzhiyun ncs->pt_tx_dropped = ntohl(rsp->tx_dropped);
1002*4882a593Smuzhiyun ncs->pt_tx_channel_err = ntohl(rsp->tx_channel_err);
1003*4882a593Smuzhiyun ncs->pt_tx_us_err = ntohl(rsp->tx_us_err);
1004*4882a593Smuzhiyun ncs->pt_rx_pkts = ntohl(rsp->rx_pkts);
1005*4882a593Smuzhiyun ncs->pt_rx_dropped = ntohl(rsp->rx_dropped);
1006*4882a593Smuzhiyun ncs->pt_rx_channel_err = ntohl(rsp->rx_channel_err);
1007*4882a593Smuzhiyun ncs->pt_rx_us_err = ntohl(rsp->rx_us_err);
1008*4882a593Smuzhiyun ncs->pt_rx_os_err = ntohl(rsp->rx_os_err);
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun return 0;
1011*4882a593Smuzhiyun }
1012*4882a593Smuzhiyun
ncsi_rsp_handler_gps(struct ncsi_request * nr)1013*4882a593Smuzhiyun static int ncsi_rsp_handler_gps(struct ncsi_request *nr)
1014*4882a593Smuzhiyun {
1015*4882a593Smuzhiyun struct ncsi_rsp_gps_pkt *rsp;
1016*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
1017*4882a593Smuzhiyun struct ncsi_package *np;
1018*4882a593Smuzhiyun
1019*4882a593Smuzhiyun /* Find the package */
1020*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gps_pkt *)skb_network_header(nr->rsp);
1021*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1022*4882a593Smuzhiyun &np, NULL);
1023*4882a593Smuzhiyun if (!np)
1024*4882a593Smuzhiyun return -ENODEV;
1025*4882a593Smuzhiyun
1026*4882a593Smuzhiyun return 0;
1027*4882a593Smuzhiyun }
1028*4882a593Smuzhiyun
ncsi_rsp_handler_gpuuid(struct ncsi_request * nr)1029*4882a593Smuzhiyun static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
1030*4882a593Smuzhiyun {
1031*4882a593Smuzhiyun struct ncsi_rsp_gpuuid_pkt *rsp;
1032*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
1033*4882a593Smuzhiyun struct ncsi_package *np;
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun /* Find the package */
1036*4882a593Smuzhiyun rsp = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(nr->rsp);
1037*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1038*4882a593Smuzhiyun &np, NULL);
1039*4882a593Smuzhiyun if (!np)
1040*4882a593Smuzhiyun return -ENODEV;
1041*4882a593Smuzhiyun
1042*4882a593Smuzhiyun memcpy(np->uuid, rsp->uuid, sizeof(rsp->uuid));
1043*4882a593Smuzhiyun
1044*4882a593Smuzhiyun return 0;
1045*4882a593Smuzhiyun }
1046*4882a593Smuzhiyun
ncsi_rsp_handler_pldm(struct ncsi_request * nr)1047*4882a593Smuzhiyun static int ncsi_rsp_handler_pldm(struct ncsi_request *nr)
1048*4882a593Smuzhiyun {
1049*4882a593Smuzhiyun return 0;
1050*4882a593Smuzhiyun }
1051*4882a593Smuzhiyun
ncsi_rsp_handler_netlink(struct ncsi_request * nr)1052*4882a593Smuzhiyun static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
1053*4882a593Smuzhiyun {
1054*4882a593Smuzhiyun struct ncsi_dev_priv *ndp = nr->ndp;
1055*4882a593Smuzhiyun struct ncsi_rsp_pkt *rsp;
1056*4882a593Smuzhiyun struct ncsi_package *np;
1057*4882a593Smuzhiyun struct ncsi_channel *nc;
1058*4882a593Smuzhiyun int ret;
1059*4882a593Smuzhiyun
1060*4882a593Smuzhiyun /* Find the package */
1061*4882a593Smuzhiyun rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
1062*4882a593Smuzhiyun ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1063*4882a593Smuzhiyun &np, &nc);
1064*4882a593Smuzhiyun if (!np)
1065*4882a593Smuzhiyun return -ENODEV;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun ret = ncsi_send_netlink_rsp(nr, np, nc);
1068*4882a593Smuzhiyun
1069*4882a593Smuzhiyun return ret;
1070*4882a593Smuzhiyun }
1071*4882a593Smuzhiyun
1072*4882a593Smuzhiyun static struct ncsi_rsp_handler {
1073*4882a593Smuzhiyun unsigned char type;
1074*4882a593Smuzhiyun int payload;
1075*4882a593Smuzhiyun int (*handler)(struct ncsi_request *nr);
1076*4882a593Smuzhiyun } ncsi_rsp_handlers[] = {
1077*4882a593Smuzhiyun { NCSI_PKT_RSP_CIS, 4, ncsi_rsp_handler_cis },
1078*4882a593Smuzhiyun { NCSI_PKT_RSP_SP, 4, ncsi_rsp_handler_sp },
1079*4882a593Smuzhiyun { NCSI_PKT_RSP_DP, 4, ncsi_rsp_handler_dp },
1080*4882a593Smuzhiyun { NCSI_PKT_RSP_EC, 4, ncsi_rsp_handler_ec },
1081*4882a593Smuzhiyun { NCSI_PKT_RSP_DC, 4, ncsi_rsp_handler_dc },
1082*4882a593Smuzhiyun { NCSI_PKT_RSP_RC, 4, ncsi_rsp_handler_rc },
1083*4882a593Smuzhiyun { NCSI_PKT_RSP_ECNT, 4, ncsi_rsp_handler_ecnt },
1084*4882a593Smuzhiyun { NCSI_PKT_RSP_DCNT, 4, ncsi_rsp_handler_dcnt },
1085*4882a593Smuzhiyun { NCSI_PKT_RSP_AE, 4, ncsi_rsp_handler_ae },
1086*4882a593Smuzhiyun { NCSI_PKT_RSP_SL, 4, ncsi_rsp_handler_sl },
1087*4882a593Smuzhiyun { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls },
1088*4882a593Smuzhiyun { NCSI_PKT_RSP_SVF, 4, ncsi_rsp_handler_svf },
1089*4882a593Smuzhiyun { NCSI_PKT_RSP_EV, 4, ncsi_rsp_handler_ev },
1090*4882a593Smuzhiyun { NCSI_PKT_RSP_DV, 4, ncsi_rsp_handler_dv },
1091*4882a593Smuzhiyun { NCSI_PKT_RSP_SMA, 4, ncsi_rsp_handler_sma },
1092*4882a593Smuzhiyun { NCSI_PKT_RSP_EBF, 4, ncsi_rsp_handler_ebf },
1093*4882a593Smuzhiyun { NCSI_PKT_RSP_DBF, 4, ncsi_rsp_handler_dbf },
1094*4882a593Smuzhiyun { NCSI_PKT_RSP_EGMF, 4, ncsi_rsp_handler_egmf },
1095*4882a593Smuzhiyun { NCSI_PKT_RSP_DGMF, 4, ncsi_rsp_handler_dgmf },
1096*4882a593Smuzhiyun { NCSI_PKT_RSP_SNFC, 4, ncsi_rsp_handler_snfc },
1097*4882a593Smuzhiyun { NCSI_PKT_RSP_GVI, 40, ncsi_rsp_handler_gvi },
1098*4882a593Smuzhiyun { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc },
1099*4882a593Smuzhiyun { NCSI_PKT_RSP_GP, -1, ncsi_rsp_handler_gp },
1100*4882a593Smuzhiyun { NCSI_PKT_RSP_GCPS, 204, ncsi_rsp_handler_gcps },
1101*4882a593Smuzhiyun { NCSI_PKT_RSP_GNS, 32, ncsi_rsp_handler_gns },
1102*4882a593Smuzhiyun { NCSI_PKT_RSP_GNPTS, 48, ncsi_rsp_handler_gnpts },
1103*4882a593Smuzhiyun { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
1104*4882a593Smuzhiyun { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
1105*4882a593Smuzhiyun { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm },
1106*4882a593Smuzhiyun { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid },
1107*4882a593Smuzhiyun { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm },
1108*4882a593Smuzhiyun { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm }
1109*4882a593Smuzhiyun };
1110*4882a593Smuzhiyun
ncsi_rcv_rsp(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt,struct net_device * orig_dev)1111*4882a593Smuzhiyun int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
1112*4882a593Smuzhiyun struct packet_type *pt, struct net_device *orig_dev)
1113*4882a593Smuzhiyun {
1114*4882a593Smuzhiyun struct ncsi_rsp_handler *nrh = NULL;
1115*4882a593Smuzhiyun struct ncsi_dev *nd;
1116*4882a593Smuzhiyun struct ncsi_dev_priv *ndp;
1117*4882a593Smuzhiyun struct ncsi_request *nr;
1118*4882a593Smuzhiyun struct ncsi_pkt_hdr *hdr;
1119*4882a593Smuzhiyun unsigned long flags;
1120*4882a593Smuzhiyun int payload, i, ret;
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun /* Find the NCSI device */
1123*4882a593Smuzhiyun nd = ncsi_find_dev(orig_dev);
1124*4882a593Smuzhiyun ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
1125*4882a593Smuzhiyun if (!ndp)
1126*4882a593Smuzhiyun return -ENODEV;
1127*4882a593Smuzhiyun
1128*4882a593Smuzhiyun /* Check if it is AEN packet */
1129*4882a593Smuzhiyun hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
1130*4882a593Smuzhiyun if (hdr->type == NCSI_PKT_AEN)
1131*4882a593Smuzhiyun return ncsi_aen_handler(ndp, skb);
1132*4882a593Smuzhiyun
1133*4882a593Smuzhiyun /* Find the handler */
1134*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) {
1135*4882a593Smuzhiyun if (ncsi_rsp_handlers[i].type == hdr->type) {
1136*4882a593Smuzhiyun if (ncsi_rsp_handlers[i].handler)
1137*4882a593Smuzhiyun nrh = &ncsi_rsp_handlers[i];
1138*4882a593Smuzhiyun else
1139*4882a593Smuzhiyun nrh = NULL;
1140*4882a593Smuzhiyun
1141*4882a593Smuzhiyun break;
1142*4882a593Smuzhiyun }
1143*4882a593Smuzhiyun }
1144*4882a593Smuzhiyun
1145*4882a593Smuzhiyun if (!nrh) {
1146*4882a593Smuzhiyun netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
1147*4882a593Smuzhiyun hdr->type);
1148*4882a593Smuzhiyun return -ENOENT;
1149*4882a593Smuzhiyun }
1150*4882a593Smuzhiyun
1151*4882a593Smuzhiyun /* Associate with the request */
1152*4882a593Smuzhiyun spin_lock_irqsave(&ndp->lock, flags);
1153*4882a593Smuzhiyun nr = &ndp->requests[hdr->id];
1154*4882a593Smuzhiyun if (!nr->used) {
1155*4882a593Smuzhiyun spin_unlock_irqrestore(&ndp->lock, flags);
1156*4882a593Smuzhiyun return -ENODEV;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun nr->rsp = skb;
1160*4882a593Smuzhiyun if (!nr->enabled) {
1161*4882a593Smuzhiyun spin_unlock_irqrestore(&ndp->lock, flags);
1162*4882a593Smuzhiyun ret = -ENOENT;
1163*4882a593Smuzhiyun goto out;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun /* Validate the packet */
1167*4882a593Smuzhiyun spin_unlock_irqrestore(&ndp->lock, flags);
1168*4882a593Smuzhiyun payload = nrh->payload;
1169*4882a593Smuzhiyun if (payload < 0)
1170*4882a593Smuzhiyun payload = ntohs(hdr->length);
1171*4882a593Smuzhiyun ret = ncsi_validate_rsp_pkt(nr, payload);
1172*4882a593Smuzhiyun if (ret) {
1173*4882a593Smuzhiyun netdev_warn(ndp->ndev.dev,
1174*4882a593Smuzhiyun "NCSI: 'bad' packet ignored for type 0x%x\n",
1175*4882a593Smuzhiyun hdr->type);
1176*4882a593Smuzhiyun
1177*4882a593Smuzhiyun if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
1178*4882a593Smuzhiyun if (ret == -EPERM)
1179*4882a593Smuzhiyun goto out_netlink;
1180*4882a593Smuzhiyun else
1181*4882a593Smuzhiyun ncsi_send_netlink_err(ndp->ndev.dev,
1182*4882a593Smuzhiyun nr->snd_seq,
1183*4882a593Smuzhiyun nr->snd_portid,
1184*4882a593Smuzhiyun &nr->nlhdr,
1185*4882a593Smuzhiyun ret);
1186*4882a593Smuzhiyun }
1187*4882a593Smuzhiyun goto out;
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun
1190*4882a593Smuzhiyun /* Process the packet */
1191*4882a593Smuzhiyun ret = nrh->handler(nr);
1192*4882a593Smuzhiyun if (ret)
1193*4882a593Smuzhiyun netdev_err(ndp->ndev.dev,
1194*4882a593Smuzhiyun "NCSI: Handler for packet type 0x%x returned %d\n",
1195*4882a593Smuzhiyun hdr->type, ret);
1196*4882a593Smuzhiyun
1197*4882a593Smuzhiyun out_netlink:
1198*4882a593Smuzhiyun if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
1199*4882a593Smuzhiyun ret = ncsi_rsp_handler_netlink(nr);
1200*4882a593Smuzhiyun if (ret) {
1201*4882a593Smuzhiyun netdev_err(ndp->ndev.dev,
1202*4882a593Smuzhiyun "NCSI: Netlink handler for packet type 0x%x returned %d\n",
1203*4882a593Smuzhiyun hdr->type, ret);
1204*4882a593Smuzhiyun }
1205*4882a593Smuzhiyun }
1206*4882a593Smuzhiyun
1207*4882a593Smuzhiyun out:
1208*4882a593Smuzhiyun ncsi_free_request(nr);
1209*4882a593Smuzhiyun return ret;
1210*4882a593Smuzhiyun }
1211