12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2138635ccSGavin Shan /*
3138635ccSGavin Shan * Copyright Gavin Shan, IBM Corporation 2016.
4138635ccSGavin Shan */
5138635ccSGavin Shan
6138635ccSGavin Shan #include <linux/module.h>
7138635ccSGavin Shan #include <linux/kernel.h>
8138635ccSGavin Shan #include <linux/init.h>
9138635ccSGavin Shan #include <linux/netdevice.h>
101c5c12eeSTao Ren #include <linux/etherdevice.h>
11138635ccSGavin Shan #include <linux/skbuff.h>
12138635ccSGavin Shan
13138635ccSGavin Shan #include <net/ncsi.h>
14138635ccSGavin Shan #include <net/net_namespace.h>
15138635ccSGavin Shan #include <net/sock.h>
169771b8ccSJustin.Lee1@Dell.com #include <net/genetlink.h>
17138635ccSGavin Shan
18138635ccSGavin Shan #include "internal.h"
19138635ccSGavin Shan #include "ncsi-pkt.h"
209771b8ccSJustin.Lee1@Dell.com #include "ncsi-netlink.h"
21138635ccSGavin Shan
221c83c708SPeter Delevoryas /* Nibbles within [0xA, 0xF] add zero "0" to the returned value.
231c83c708SPeter Delevoryas * Optional fields (encoded as 0xFF) will default to zero.
241c83c708SPeter Delevoryas */
decode_bcd_u8(u8 x)251c83c708SPeter Delevoryas static u8 decode_bcd_u8(u8 x)
261c83c708SPeter Delevoryas {
271c83c708SPeter Delevoryas int lo = x & 0xF;
281c83c708SPeter Delevoryas int hi = x >> 4;
291c83c708SPeter Delevoryas
301c83c708SPeter Delevoryas lo = lo < 0xA ? lo : 0;
311c83c708SPeter Delevoryas hi = hi < 0xA ? hi : 0;
321c83c708SPeter Delevoryas return lo + hi * 10;
331c83c708SPeter Delevoryas }
341c83c708SPeter Delevoryas
ncsi_validate_rsp_pkt(struct ncsi_request * nr,unsigned short payload)35138635ccSGavin Shan static int ncsi_validate_rsp_pkt(struct ncsi_request *nr,
36138635ccSGavin Shan unsigned short payload)
37138635ccSGavin Shan {
38138635ccSGavin Shan struct ncsi_rsp_pkt_hdr *h;
39138635ccSGavin Shan u32 checksum;
40138635ccSGavin Shan __be32 *pchecksum;
41138635ccSGavin Shan
42138635ccSGavin Shan /* Check NCSI packet header. We don't need validate
43138635ccSGavin Shan * the packet type, which should have been checked
44138635ccSGavin Shan * before calling this function.
45138635ccSGavin Shan */
46138635ccSGavin Shan h = (struct ncsi_rsp_pkt_hdr *)skb_network_header(nr->rsp);
479771b8ccSJustin.Lee1@Dell.com
489771b8ccSJustin.Lee1@Dell.com if (h->common.revision != NCSI_PKT_REVISION) {
499771b8ccSJustin.Lee1@Dell.com netdev_dbg(nr->ndp->ndev.dev,
509771b8ccSJustin.Lee1@Dell.com "NCSI: unsupported header revision\n");
51138635ccSGavin Shan return -EINVAL;
529771b8ccSJustin.Lee1@Dell.com }
539771b8ccSJustin.Lee1@Dell.com if (ntohs(h->common.length) != payload) {
549771b8ccSJustin.Lee1@Dell.com netdev_dbg(nr->ndp->ndev.dev,
559771b8ccSJustin.Lee1@Dell.com "NCSI: payload length mismatched\n");
56138635ccSGavin Shan return -EINVAL;
579771b8ccSJustin.Lee1@Dell.com }
58138635ccSGavin Shan
59138635ccSGavin Shan /* Check on code and reason */
60138635ccSGavin Shan if (ntohs(h->code) != NCSI_PKT_RSP_C_COMPLETED ||
619771b8ccSJustin.Lee1@Dell.com ntohs(h->reason) != NCSI_PKT_RSP_R_NO_ERROR) {
629771b8ccSJustin.Lee1@Dell.com netdev_dbg(nr->ndp->ndev.dev,
6396a1b033STerry S. Duncan "NCSI: non zero response/reason code %04xh, %04xh\n",
6496a1b033STerry S. Duncan ntohs(h->code), ntohs(h->reason));
659771b8ccSJustin.Lee1@Dell.com return -EPERM;
669771b8ccSJustin.Lee1@Dell.com }
67138635ccSGavin Shan
68138635ccSGavin Shan /* Validate checksum, which might be zeroes if the
69138635ccSGavin Shan * sender doesn't support checksum according to NCSI
70138635ccSGavin Shan * specification.
71138635ccSGavin Shan */
7296a1b033STerry S. Duncan pchecksum = (__be32 *)((void *)(h + 1) + ALIGN(payload, 4) - 4);
73138635ccSGavin Shan if (ntohl(*pchecksum) == 0)
74138635ccSGavin Shan return 0;
75138635ccSGavin Shan
76138635ccSGavin Shan checksum = ncsi_calculate_checksum((unsigned char *)h,
77138635ccSGavin Shan sizeof(*h) + payload - 4);
789771b8ccSJustin.Lee1@Dell.com
799771b8ccSJustin.Lee1@Dell.com if (*pchecksum != htonl(checksum)) {
8096a1b033STerry S. Duncan netdev_dbg(nr->ndp->ndev.dev,
8196a1b033STerry S. Duncan "NCSI: checksum mismatched; recd: %08x calc: %08x\n",
8296a1b033STerry S. Duncan *pchecksum, htonl(checksum));
83138635ccSGavin Shan return -EINVAL;
849771b8ccSJustin.Lee1@Dell.com }
85138635ccSGavin Shan
86138635ccSGavin Shan return 0;
87138635ccSGavin Shan }
88138635ccSGavin Shan
ncsi_rsp_handler_cis(struct ncsi_request * nr)89138635ccSGavin Shan static int ncsi_rsp_handler_cis(struct ncsi_request *nr)
90138635ccSGavin Shan {
91138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
92138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
93138635ccSGavin Shan struct ncsi_package *np;
94138635ccSGavin Shan struct ncsi_channel *nc;
95138635ccSGavin Shan unsigned char id;
96138635ccSGavin Shan
97138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
98138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, &np, &nc);
99138635ccSGavin Shan if (!nc) {
100e6f44ed6SGavin Shan if (ndp->flags & NCSI_DEV_PROBED)
101e6f44ed6SGavin Shan return -ENXIO;
102e6f44ed6SGavin Shan
103138635ccSGavin Shan id = NCSI_CHANNEL_INDEX(rsp->rsp.common.channel);
104138635ccSGavin Shan nc = ncsi_add_channel(np, id);
105138635ccSGavin Shan }
106138635ccSGavin Shan
107138635ccSGavin Shan return nc ? 0 : -ENODEV;
108138635ccSGavin Shan }
109138635ccSGavin Shan
ncsi_rsp_handler_sp(struct ncsi_request * nr)110138635ccSGavin Shan static int ncsi_rsp_handler_sp(struct ncsi_request *nr)
111138635ccSGavin Shan {
112138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
113138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
114138635ccSGavin Shan struct ncsi_package *np;
115138635ccSGavin Shan unsigned char id;
116138635ccSGavin Shan
117138635ccSGavin Shan /* Add the package if it's not existing. Otherwise,
118138635ccSGavin Shan * to change the state of its child channels.
119138635ccSGavin Shan */
120138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
121138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
122138635ccSGavin Shan &np, NULL);
123138635ccSGavin Shan if (!np) {
124e6f44ed6SGavin Shan if (ndp->flags & NCSI_DEV_PROBED)
125e6f44ed6SGavin Shan return -ENXIO;
126e6f44ed6SGavin Shan
127138635ccSGavin Shan id = NCSI_PACKAGE_INDEX(rsp->rsp.common.channel);
128138635ccSGavin Shan np = ncsi_add_package(ndp, id);
129138635ccSGavin Shan if (!np)
130138635ccSGavin Shan return -ENODEV;
131138635ccSGavin Shan }
132138635ccSGavin Shan
133138635ccSGavin Shan return 0;
134138635ccSGavin Shan }
135138635ccSGavin Shan
ncsi_rsp_handler_dp(struct ncsi_request * nr)136138635ccSGavin Shan static int ncsi_rsp_handler_dp(struct ncsi_request *nr)
137138635ccSGavin Shan {
138138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
139138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
140138635ccSGavin Shan struct ncsi_package *np;
141138635ccSGavin Shan struct ncsi_channel *nc;
142138635ccSGavin Shan unsigned long flags;
143138635ccSGavin Shan
144138635ccSGavin Shan /* Find the package */
145138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
146138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
147138635ccSGavin Shan &np, NULL);
148138635ccSGavin Shan if (!np)
149138635ccSGavin Shan return -ENODEV;
150138635ccSGavin Shan
151138635ccSGavin Shan /* Change state of all channels attached to the package */
152138635ccSGavin Shan NCSI_FOR_EACH_CHANNEL(np, nc) {
153138635ccSGavin Shan spin_lock_irqsave(&nc->lock, flags);
154138635ccSGavin Shan nc->state = NCSI_CHANNEL_INACTIVE;
155138635ccSGavin Shan spin_unlock_irqrestore(&nc->lock, flags);
156138635ccSGavin Shan }
157138635ccSGavin Shan
158138635ccSGavin Shan return 0;
159138635ccSGavin Shan }
160138635ccSGavin Shan
ncsi_rsp_handler_ec(struct ncsi_request * nr)161138635ccSGavin Shan static int ncsi_rsp_handler_ec(struct ncsi_request *nr)
162138635ccSGavin Shan {
163138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
164138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
165138635ccSGavin Shan struct ncsi_channel *nc;
166138635ccSGavin Shan struct ncsi_channel_mode *ncm;
167138635ccSGavin Shan
168138635ccSGavin Shan /* Find the package and channel */
169138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
170138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
171138635ccSGavin Shan NULL, &nc);
172138635ccSGavin Shan if (!nc)
173138635ccSGavin Shan return -ENODEV;
174138635ccSGavin Shan
175138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_ENABLE];
176138635ccSGavin Shan if (ncm->enable)
17704bad8bdSSamuel Mendoza-Jonas return 0;
178138635ccSGavin Shan
179138635ccSGavin Shan ncm->enable = 1;
180138635ccSGavin Shan return 0;
181138635ccSGavin Shan }
182138635ccSGavin Shan
ncsi_rsp_handler_dc(struct ncsi_request * nr)183138635ccSGavin Shan static int ncsi_rsp_handler_dc(struct ncsi_request *nr)
184138635ccSGavin Shan {
185138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
186138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
187138635ccSGavin Shan struct ncsi_channel *nc;
188138635ccSGavin Shan struct ncsi_channel_mode *ncm;
189138635ccSGavin Shan int ret;
190138635ccSGavin Shan
191138635ccSGavin Shan ret = ncsi_validate_rsp_pkt(nr, 4);
192138635ccSGavin Shan if (ret)
193138635ccSGavin Shan return ret;
194138635ccSGavin Shan
195138635ccSGavin Shan /* Find the package and channel */
196138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
197138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
198138635ccSGavin Shan NULL, &nc);
199138635ccSGavin Shan if (!nc)
200138635ccSGavin Shan return -ENODEV;
201138635ccSGavin Shan
202138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_ENABLE];
203138635ccSGavin Shan if (!ncm->enable)
20404bad8bdSSamuel Mendoza-Jonas return 0;
205138635ccSGavin Shan
206138635ccSGavin Shan ncm->enable = 0;
207138635ccSGavin Shan return 0;
208138635ccSGavin Shan }
209138635ccSGavin Shan
ncsi_rsp_handler_rc(struct ncsi_request * nr)210138635ccSGavin Shan static int ncsi_rsp_handler_rc(struct ncsi_request *nr)
211138635ccSGavin Shan {
212138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
213138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
214138635ccSGavin Shan struct ncsi_channel *nc;
215138635ccSGavin Shan unsigned long flags;
216138635ccSGavin Shan
217138635ccSGavin Shan /* Find the package and channel */
218138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
219138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
220138635ccSGavin Shan NULL, &nc);
221138635ccSGavin Shan if (!nc)
222138635ccSGavin Shan return -ENODEV;
223138635ccSGavin Shan
224138635ccSGavin Shan /* Update state for the specified channel */
225138635ccSGavin Shan spin_lock_irqsave(&nc->lock, flags);
226138635ccSGavin Shan nc->state = NCSI_CHANNEL_INACTIVE;
227138635ccSGavin Shan spin_unlock_irqrestore(&nc->lock, flags);
228138635ccSGavin Shan
229138635ccSGavin Shan return 0;
230138635ccSGavin Shan }
231138635ccSGavin Shan
ncsi_rsp_handler_ecnt(struct ncsi_request * nr)232138635ccSGavin Shan static int ncsi_rsp_handler_ecnt(struct ncsi_request *nr)
233138635ccSGavin Shan {
234138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
235138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
236138635ccSGavin Shan struct ncsi_channel *nc;
237138635ccSGavin Shan struct ncsi_channel_mode *ncm;
238138635ccSGavin Shan
239138635ccSGavin Shan /* Find the package and channel */
240138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
241138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
242138635ccSGavin Shan NULL, &nc);
243138635ccSGavin Shan if (!nc)
244138635ccSGavin Shan return -ENODEV;
245138635ccSGavin Shan
246138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
247138635ccSGavin Shan if (ncm->enable)
24804bad8bdSSamuel Mendoza-Jonas return 0;
249138635ccSGavin Shan
250138635ccSGavin Shan ncm->enable = 1;
251138635ccSGavin Shan return 0;
252138635ccSGavin Shan }
253138635ccSGavin Shan
ncsi_rsp_handler_dcnt(struct ncsi_request * nr)254138635ccSGavin Shan static int ncsi_rsp_handler_dcnt(struct ncsi_request *nr)
255138635ccSGavin Shan {
256138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
257138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
258138635ccSGavin Shan struct ncsi_channel *nc;
259138635ccSGavin Shan struct ncsi_channel_mode *ncm;
260138635ccSGavin Shan
261138635ccSGavin Shan /* Find the package and channel */
262138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
263138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
264138635ccSGavin Shan NULL, &nc);
265138635ccSGavin Shan if (!nc)
266138635ccSGavin Shan return -ENODEV;
267138635ccSGavin Shan
268138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_TX_ENABLE];
269138635ccSGavin Shan if (!ncm->enable)
27004bad8bdSSamuel Mendoza-Jonas return 0;
271138635ccSGavin Shan
2728d951a75SSamuel Mendoza-Jonas ncm->enable = 0;
273138635ccSGavin Shan return 0;
274138635ccSGavin Shan }
275138635ccSGavin Shan
ncsi_rsp_handler_ae(struct ncsi_request * nr)276138635ccSGavin Shan static int ncsi_rsp_handler_ae(struct ncsi_request *nr)
277138635ccSGavin Shan {
278138635ccSGavin Shan struct ncsi_cmd_ae_pkt *cmd;
279138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
280138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
281138635ccSGavin Shan struct ncsi_channel *nc;
282138635ccSGavin Shan struct ncsi_channel_mode *ncm;
283138635ccSGavin Shan
284138635ccSGavin Shan /* Find the package and channel */
285138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
286138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
287138635ccSGavin Shan NULL, &nc);
288138635ccSGavin Shan if (!nc)
289138635ccSGavin Shan return -ENODEV;
290138635ccSGavin Shan
291138635ccSGavin Shan /* Check if the AEN has been enabled */
292138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_AEN];
293138635ccSGavin Shan if (ncm->enable)
29404bad8bdSSamuel Mendoza-Jonas return 0;
295138635ccSGavin Shan
296138635ccSGavin Shan /* Update to AEN configuration */
297138635ccSGavin Shan cmd = (struct ncsi_cmd_ae_pkt *)skb_network_header(nr->cmd);
298138635ccSGavin Shan ncm->enable = 1;
299138635ccSGavin Shan ncm->data[0] = cmd->mc_id;
300138635ccSGavin Shan ncm->data[1] = ntohl(cmd->mode);
301138635ccSGavin Shan
302138635ccSGavin Shan return 0;
303138635ccSGavin Shan }
304138635ccSGavin Shan
ncsi_rsp_handler_sl(struct ncsi_request * nr)305138635ccSGavin Shan static int ncsi_rsp_handler_sl(struct ncsi_request *nr)
306138635ccSGavin Shan {
307138635ccSGavin Shan struct ncsi_cmd_sl_pkt *cmd;
308138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
309138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
310138635ccSGavin Shan struct ncsi_channel *nc;
311138635ccSGavin Shan struct ncsi_channel_mode *ncm;
312138635ccSGavin Shan
313138635ccSGavin Shan /* Find the package and channel */
314138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
315138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
316138635ccSGavin Shan NULL, &nc);
317138635ccSGavin Shan if (!nc)
318138635ccSGavin Shan return -ENODEV;
319138635ccSGavin Shan
320138635ccSGavin Shan cmd = (struct ncsi_cmd_sl_pkt *)skb_network_header(nr->cmd);
321138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_LINK];
322138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode);
323138635ccSGavin Shan ncm->data[1] = ntohl(cmd->oem_mode);
324138635ccSGavin Shan
325138635ccSGavin Shan return 0;
326138635ccSGavin Shan }
327138635ccSGavin Shan
ncsi_rsp_handler_gls(struct ncsi_request * nr)328138635ccSGavin Shan static int ncsi_rsp_handler_gls(struct ncsi_request *nr)
329138635ccSGavin Shan {
330138635ccSGavin Shan struct ncsi_rsp_gls_pkt *rsp;
331138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
332138635ccSGavin Shan struct ncsi_channel *nc;
333138635ccSGavin Shan struct ncsi_channel_mode *ncm;
334e6f44ed6SGavin Shan unsigned long flags;
335138635ccSGavin Shan
336138635ccSGavin Shan /* Find the package and channel */
337138635ccSGavin Shan rsp = (struct ncsi_rsp_gls_pkt *)skb_network_header(nr->rsp);
338138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
339138635ccSGavin Shan NULL, &nc);
340138635ccSGavin Shan if (!nc)
341138635ccSGavin Shan return -ENODEV;
342138635ccSGavin Shan
343138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_LINK];
344138635ccSGavin Shan ncm->data[2] = ntohl(rsp->status);
345138635ccSGavin Shan ncm->data[3] = ntohl(rsp->other);
346138635ccSGavin Shan ncm->data[4] = ntohl(rsp->oem_status);
347138635ccSGavin Shan
348a0509cbeSGavin Shan if (nr->flags & NCSI_REQ_FLAG_EVENT_DRIVEN)
349e6f44ed6SGavin Shan return 0;
350e6f44ed6SGavin Shan
351e6f44ed6SGavin Shan /* Reset the channel monitor if it has been enabled */
352e6f44ed6SGavin Shan spin_lock_irqsave(&nc->lock, flags);
35383afdc6aSGavin Shan nc->monitor.state = NCSI_CHANNEL_MONITOR_START;
354e6f44ed6SGavin Shan spin_unlock_irqrestore(&nc->lock, flags);
355e6f44ed6SGavin Shan
356138635ccSGavin Shan return 0;
357138635ccSGavin Shan }
358138635ccSGavin Shan
ncsi_rsp_handler_svf(struct ncsi_request * nr)359138635ccSGavin Shan static int ncsi_rsp_handler_svf(struct ncsi_request *nr)
360138635ccSGavin Shan {
361138635ccSGavin Shan struct ncsi_cmd_svf_pkt *cmd;
362138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
363138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
364138635ccSGavin Shan struct ncsi_channel *nc;
365062b3e1bSSamuel Mendoza-Jonas struct ncsi_channel_vlan_filter *ncf;
366062b3e1bSSamuel Mendoza-Jonas unsigned long flags;
367062b3e1bSSamuel Mendoza-Jonas void *bitmap;
368138635ccSGavin Shan
369138635ccSGavin Shan /* Find the package and channel */
370138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
371138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
372138635ccSGavin Shan NULL, &nc);
373138635ccSGavin Shan if (!nc)
374138635ccSGavin Shan return -ENODEV;
375138635ccSGavin Shan
376138635ccSGavin Shan cmd = (struct ncsi_cmd_svf_pkt *)skb_network_header(nr->cmd);
377062b3e1bSSamuel Mendoza-Jonas ncf = &nc->vlan_filter;
378990a9d49SDan Carpenter if (cmd->index == 0 || cmd->index > ncf->n_vids)
379138635ccSGavin Shan return -ERANGE;
380138635ccSGavin Shan
381062b3e1bSSamuel Mendoza-Jonas /* Add or remove the VLAN filter. Remember HW indexes from 1 */
382062b3e1bSSamuel Mendoza-Jonas spin_lock_irqsave(&nc->lock, flags);
383062b3e1bSSamuel Mendoza-Jonas bitmap = &ncf->bitmap;
384138635ccSGavin Shan if (!(cmd->enable & 0x1)) {
385062b3e1bSSamuel Mendoza-Jonas if (test_and_clear_bit(cmd->index - 1, bitmap))
386062b3e1bSSamuel Mendoza-Jonas ncf->vids[cmd->index - 1] = 0;
387138635ccSGavin Shan } else {
388062b3e1bSSamuel Mendoza-Jonas set_bit(cmd->index - 1, bitmap);
389062b3e1bSSamuel Mendoza-Jonas ncf->vids[cmd->index - 1] = ntohs(cmd->vlan);
390138635ccSGavin Shan }
391062b3e1bSSamuel Mendoza-Jonas spin_unlock_irqrestore(&nc->lock, flags);
392138635ccSGavin Shan
393062b3e1bSSamuel Mendoza-Jonas return 0;
394138635ccSGavin Shan }
395138635ccSGavin Shan
ncsi_rsp_handler_ev(struct ncsi_request * nr)396138635ccSGavin Shan static int ncsi_rsp_handler_ev(struct ncsi_request *nr)
397138635ccSGavin Shan {
398138635ccSGavin Shan struct ncsi_cmd_ev_pkt *cmd;
399138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
400138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
401138635ccSGavin Shan struct ncsi_channel *nc;
402138635ccSGavin Shan struct ncsi_channel_mode *ncm;
403138635ccSGavin Shan
404138635ccSGavin Shan /* Find the package and channel */
405138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
406138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
407138635ccSGavin Shan NULL, &nc);
408138635ccSGavin Shan if (!nc)
409138635ccSGavin Shan return -ENODEV;
410138635ccSGavin Shan
411138635ccSGavin Shan /* Check if VLAN mode has been enabled */
412138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_VLAN];
413138635ccSGavin Shan if (ncm->enable)
41404bad8bdSSamuel Mendoza-Jonas return 0;
415138635ccSGavin Shan
416138635ccSGavin Shan /* Update to VLAN mode */
417138635ccSGavin Shan cmd = (struct ncsi_cmd_ev_pkt *)skb_network_header(nr->cmd);
418138635ccSGavin Shan ncm->enable = 1;
41927fa107dSIvan Mikhaylov ncm->data[0] = ntohl((__force __be32)cmd->mode);
420138635ccSGavin Shan
421138635ccSGavin Shan return 0;
422138635ccSGavin Shan }
423138635ccSGavin Shan
ncsi_rsp_handler_dv(struct ncsi_request * nr)424138635ccSGavin Shan static int ncsi_rsp_handler_dv(struct ncsi_request *nr)
425138635ccSGavin Shan {
426138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
427138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
428138635ccSGavin Shan struct ncsi_channel *nc;
429138635ccSGavin Shan struct ncsi_channel_mode *ncm;
430138635ccSGavin Shan
431138635ccSGavin Shan /* Find the package and channel */
432138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
433138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
434138635ccSGavin Shan NULL, &nc);
435138635ccSGavin Shan if (!nc)
436138635ccSGavin Shan return -ENODEV;
437138635ccSGavin Shan
438138635ccSGavin Shan /* Check if VLAN mode has been enabled */
439138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_VLAN];
440138635ccSGavin Shan if (!ncm->enable)
44104bad8bdSSamuel Mendoza-Jonas return 0;
442138635ccSGavin Shan
443138635ccSGavin Shan /* Update to VLAN mode */
444138635ccSGavin Shan ncm->enable = 0;
445138635ccSGavin Shan return 0;
446138635ccSGavin Shan }
447138635ccSGavin Shan
ncsi_rsp_handler_sma(struct ncsi_request * nr)448138635ccSGavin Shan static int ncsi_rsp_handler_sma(struct ncsi_request *nr)
449138635ccSGavin Shan {
450138635ccSGavin Shan struct ncsi_cmd_sma_pkt *cmd;
451138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
452138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
453138635ccSGavin Shan struct ncsi_channel *nc;
454062b3e1bSSamuel Mendoza-Jonas struct ncsi_channel_mac_filter *ncf;
455062b3e1bSSamuel Mendoza-Jonas unsigned long flags;
456138635ccSGavin Shan void *bitmap;
457062b3e1bSSamuel Mendoza-Jonas bool enabled;
458062b3e1bSSamuel Mendoza-Jonas int index;
459062b3e1bSSamuel Mendoza-Jonas
460138635ccSGavin Shan
461138635ccSGavin Shan /* Find the package and channel */
462138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
463138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
464138635ccSGavin Shan NULL, &nc);
465138635ccSGavin Shan if (!nc)
466138635ccSGavin Shan return -ENODEV;
467138635ccSGavin Shan
468138635ccSGavin Shan /* According to NCSI spec 1.01, the mixed filter table
469138635ccSGavin Shan * isn't supported yet.
470138635ccSGavin Shan */
471138635ccSGavin Shan cmd = (struct ncsi_cmd_sma_pkt *)skb_network_header(nr->cmd);
472062b3e1bSSamuel Mendoza-Jonas enabled = cmd->at_e & 0x1;
473062b3e1bSSamuel Mendoza-Jonas ncf = &nc->mac_filter;
474062b3e1bSSamuel Mendoza-Jonas bitmap = &ncf->bitmap;
475138635ccSGavin Shan
476990a9d49SDan Carpenter if (cmd->index == 0 ||
477990a9d49SDan Carpenter cmd->index > ncf->n_uc + ncf->n_mc + ncf->n_mixed)
478138635ccSGavin Shan return -ERANGE;
479138635ccSGavin Shan
480062b3e1bSSamuel Mendoza-Jonas index = (cmd->index - 1) * ETH_ALEN;
481062b3e1bSSamuel Mendoza-Jonas spin_lock_irqsave(&nc->lock, flags);
482062b3e1bSSamuel Mendoza-Jonas if (enabled) {
483062b3e1bSSamuel Mendoza-Jonas set_bit(cmd->index - 1, bitmap);
484062b3e1bSSamuel Mendoza-Jonas memcpy(&ncf->addrs[index], cmd->mac, ETH_ALEN);
485138635ccSGavin Shan } else {
486062b3e1bSSamuel Mendoza-Jonas clear_bit(cmd->index - 1, bitmap);
48749b0aa1bSMiaohe Lin eth_zero_addr(&ncf->addrs[index]);
488138635ccSGavin Shan }
489062b3e1bSSamuel Mendoza-Jonas spin_unlock_irqrestore(&nc->lock, flags);
490138635ccSGavin Shan
491138635ccSGavin Shan return 0;
492138635ccSGavin Shan }
493138635ccSGavin Shan
ncsi_rsp_handler_ebf(struct ncsi_request * nr)494138635ccSGavin Shan static int ncsi_rsp_handler_ebf(struct ncsi_request *nr)
495138635ccSGavin Shan {
496138635ccSGavin Shan struct ncsi_cmd_ebf_pkt *cmd;
497138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
498138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
499138635ccSGavin Shan struct ncsi_channel *nc;
500138635ccSGavin Shan struct ncsi_channel_mode *ncm;
501138635ccSGavin Shan
502138635ccSGavin Shan /* Find the package and channel */
503138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
504138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel, NULL, &nc);
505138635ccSGavin Shan if (!nc)
506138635ccSGavin Shan return -ENODEV;
507138635ccSGavin Shan
508138635ccSGavin Shan /* Check if broadcast filter has been enabled */
509138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_BC];
510138635ccSGavin Shan if (ncm->enable)
51104bad8bdSSamuel Mendoza-Jonas return 0;
512138635ccSGavin Shan
513138635ccSGavin Shan /* Update to broadcast filter mode */
514138635ccSGavin Shan cmd = (struct ncsi_cmd_ebf_pkt *)skb_network_header(nr->cmd);
515138635ccSGavin Shan ncm->enable = 1;
516138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode);
517138635ccSGavin Shan
518138635ccSGavin Shan return 0;
519138635ccSGavin Shan }
520138635ccSGavin Shan
ncsi_rsp_handler_dbf(struct ncsi_request * nr)521138635ccSGavin Shan static int ncsi_rsp_handler_dbf(struct ncsi_request *nr)
522138635ccSGavin Shan {
523138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
524138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
525138635ccSGavin Shan struct ncsi_channel *nc;
526138635ccSGavin Shan struct ncsi_channel_mode *ncm;
527138635ccSGavin Shan
528138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
529138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
530138635ccSGavin Shan NULL, &nc);
531138635ccSGavin Shan if (!nc)
532138635ccSGavin Shan return -ENODEV;
533138635ccSGavin Shan
534138635ccSGavin Shan /* Check if broadcast filter isn't enabled */
535138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_BC];
536138635ccSGavin Shan if (!ncm->enable)
53704bad8bdSSamuel Mendoza-Jonas return 0;
538138635ccSGavin Shan
539138635ccSGavin Shan /* Update to broadcast filter mode */
540138635ccSGavin Shan ncm->enable = 0;
541138635ccSGavin Shan ncm->data[0] = 0;
542138635ccSGavin Shan
543138635ccSGavin Shan return 0;
544138635ccSGavin Shan }
545138635ccSGavin Shan
ncsi_rsp_handler_egmf(struct ncsi_request * nr)546138635ccSGavin Shan static int ncsi_rsp_handler_egmf(struct ncsi_request *nr)
547138635ccSGavin Shan {
548138635ccSGavin Shan struct ncsi_cmd_egmf_pkt *cmd;
549138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
550138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
551138635ccSGavin Shan struct ncsi_channel *nc;
552138635ccSGavin Shan struct ncsi_channel_mode *ncm;
553138635ccSGavin Shan
554138635ccSGavin Shan /* Find the channel */
555138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
556138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
557138635ccSGavin Shan NULL, &nc);
558138635ccSGavin Shan if (!nc)
559138635ccSGavin Shan return -ENODEV;
560138635ccSGavin Shan
561138635ccSGavin Shan /* Check if multicast filter has been enabled */
562138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_MC];
563138635ccSGavin Shan if (ncm->enable)
56404bad8bdSSamuel Mendoza-Jonas return 0;
565138635ccSGavin Shan
566138635ccSGavin Shan /* Update to multicast filter mode */
567138635ccSGavin Shan cmd = (struct ncsi_cmd_egmf_pkt *)skb_network_header(nr->cmd);
568138635ccSGavin Shan ncm->enable = 1;
569138635ccSGavin Shan ncm->data[0] = ntohl(cmd->mode);
570138635ccSGavin Shan
571138635ccSGavin Shan return 0;
572138635ccSGavin Shan }
573138635ccSGavin Shan
ncsi_rsp_handler_dgmf(struct ncsi_request * nr)574138635ccSGavin Shan static int ncsi_rsp_handler_dgmf(struct ncsi_request *nr)
575138635ccSGavin Shan {
576138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
577138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
578138635ccSGavin Shan struct ncsi_channel *nc;
579138635ccSGavin Shan struct ncsi_channel_mode *ncm;
580138635ccSGavin Shan
581138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
582138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
583138635ccSGavin Shan NULL, &nc);
584138635ccSGavin Shan if (!nc)
585138635ccSGavin Shan return -ENODEV;
586138635ccSGavin Shan
587138635ccSGavin Shan /* Check if multicast filter has been enabled */
588138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_MC];
589138635ccSGavin Shan if (!ncm->enable)
59004bad8bdSSamuel Mendoza-Jonas return 0;
591138635ccSGavin Shan
592138635ccSGavin Shan /* Update to multicast filter mode */
593138635ccSGavin Shan ncm->enable = 0;
594138635ccSGavin Shan ncm->data[0] = 0;
595138635ccSGavin Shan
596138635ccSGavin Shan return 0;
597138635ccSGavin Shan }
598138635ccSGavin Shan
ncsi_rsp_handler_snfc(struct ncsi_request * nr)599138635ccSGavin Shan static int ncsi_rsp_handler_snfc(struct ncsi_request *nr)
600138635ccSGavin Shan {
601138635ccSGavin Shan struct ncsi_cmd_snfc_pkt *cmd;
602138635ccSGavin Shan struct ncsi_rsp_pkt *rsp;
603138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
604138635ccSGavin Shan struct ncsi_channel *nc;
605138635ccSGavin Shan struct ncsi_channel_mode *ncm;
606138635ccSGavin Shan
607138635ccSGavin Shan /* Find the channel */
608138635ccSGavin Shan rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
609138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
610138635ccSGavin Shan NULL, &nc);
611138635ccSGavin Shan if (!nc)
612138635ccSGavin Shan return -ENODEV;
613138635ccSGavin Shan
614138635ccSGavin Shan /* Check if flow control has been enabled */
615138635ccSGavin Shan ncm = &nc->modes[NCSI_MODE_FC];
616138635ccSGavin Shan if (ncm->enable)
61704bad8bdSSamuel Mendoza-Jonas return 0;
618138635ccSGavin Shan
619138635ccSGavin Shan /* Update to flow control mode */
620138635ccSGavin Shan cmd = (struct ncsi_cmd_snfc_pkt *)skb_network_header(nr->cmd);
621138635ccSGavin Shan ncm->enable = 1;
622138635ccSGavin Shan ncm->data[0] = cmd->mode;
623138635ccSGavin Shan
624138635ccSGavin Shan return 0;
625138635ccSGavin Shan }
626138635ccSGavin Shan
62774b449b9SIvan Mikhaylov /* Response handler for Get Mac Address command */
ncsi_rsp_handler_oem_gma(struct ncsi_request * nr,int mfr_id)62874b449b9SIvan Mikhaylov static int ncsi_rsp_handler_oem_gma(struct ncsi_request *nr, int mfr_id)
62916e8c4caSVijay Khemka {
63016e8c4caSVijay Khemka struct ncsi_dev_priv *ndp = nr->ndp;
631ba32f06eSPaul Fertser struct sockaddr *saddr = &ndp->pending_mac;
63216e8c4caSVijay Khemka struct net_device *ndev = ndp->ndev.dev;
63316e8c4caSVijay Khemka struct ncsi_rsp_oem_pkt *rsp;
63474b449b9SIvan Mikhaylov u32 mac_addr_off = 0;
63516e8c4caSVijay Khemka
63616e8c4caSVijay Khemka /* Get the response header */
63716e8c4caSVijay Khemka rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
63816e8c4caSVijay Khemka
63916e8c4caSVijay Khemka ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
64074b449b9SIvan Mikhaylov if (mfr_id == NCSI_OEM_MFR_BCM_ID)
64174b449b9SIvan Mikhaylov mac_addr_off = BCM_MAC_ADDR_OFFSET;
64274b449b9SIvan Mikhaylov else if (mfr_id == NCSI_OEM_MFR_MLX_ID)
64374b449b9SIvan Mikhaylov mac_addr_off = MLX_MAC_ADDR_OFFSET;
64474b449b9SIvan Mikhaylov else if (mfr_id == NCSI_OEM_MFR_INTEL_ID)
64574b449b9SIvan Mikhaylov mac_addr_off = INTEL_MAC_ADDR_OFFSET;
64674b449b9SIvan Mikhaylov
647ba32f06eSPaul Fertser saddr->sa_family = ndev->type;
648ba32f06eSPaul Fertser memcpy(saddr->sa_data, &rsp->data[mac_addr_off], ETH_ALEN);
64974b449b9SIvan Mikhaylov if (mfr_id == NCSI_OEM_MFR_BCM_ID || mfr_id == NCSI_OEM_MFR_INTEL_ID)
650ba32f06eSPaul Fertser eth_addr_inc((u8 *)saddr->sa_data);
651ba32f06eSPaul Fertser if (!is_valid_ether_addr((const u8 *)saddr->sa_data))
65274b449b9SIvan Mikhaylov return -ENXIO;
65374b449b9SIvan Mikhaylov
6549e860947SVijay Khemka /* Set the flag for GMA command which should only be called once */
6559e860947SVijay Khemka ndp->gma_flag = 1;
6569e860947SVijay Khemka
657ba32f06eSPaul Fertser return 0;
65816e8c4caSVijay Khemka }
65916e8c4caSVijay Khemka
66016e8c4caSVijay Khemka /* Response handler for Mellanox card */
ncsi_rsp_handler_oem_mlx(struct ncsi_request * nr)66116e8c4caSVijay Khemka static int ncsi_rsp_handler_oem_mlx(struct ncsi_request *nr)
66216e8c4caSVijay Khemka {
66316e8c4caSVijay Khemka struct ncsi_rsp_oem_mlx_pkt *mlx;
66416e8c4caSVijay Khemka struct ncsi_rsp_oem_pkt *rsp;
66516e8c4caSVijay Khemka
66616e8c4caSVijay Khemka /* Get the response header */
66716e8c4caSVijay Khemka rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
66816e8c4caSVijay Khemka mlx = (struct ncsi_rsp_oem_mlx_pkt *)(rsp->data);
66916e8c4caSVijay Khemka
67016e8c4caSVijay Khemka if (mlx->cmd == NCSI_OEM_MLX_CMD_GMA &&
67116e8c4caSVijay Khemka mlx->param == NCSI_OEM_MLX_CMD_GMA_PARAM)
67274b449b9SIvan Mikhaylov return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_MLX_ID);
67316e8c4caSVijay Khemka return 0;
67416e8c4caSVijay Khemka }
67516e8c4caSVijay Khemka
676cb10c7c0SVijay Khemka /* Response handler for Broadcom card */
ncsi_rsp_handler_oem_bcm(struct ncsi_request * nr)677cb10c7c0SVijay Khemka static int ncsi_rsp_handler_oem_bcm(struct ncsi_request *nr)
678cb10c7c0SVijay Khemka {
679cb10c7c0SVijay Khemka struct ncsi_rsp_oem_bcm_pkt *bcm;
680cb10c7c0SVijay Khemka struct ncsi_rsp_oem_pkt *rsp;
681cb10c7c0SVijay Khemka
682cb10c7c0SVijay Khemka /* Get the response header */
683cb10c7c0SVijay Khemka rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
684cb10c7c0SVijay Khemka bcm = (struct ncsi_rsp_oem_bcm_pkt *)(rsp->data);
685cb10c7c0SVijay Khemka
686cb10c7c0SVijay Khemka if (bcm->type == NCSI_OEM_BCM_CMD_GMA)
68774b449b9SIvan Mikhaylov return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_BCM_ID);
688cb10c7c0SVijay Khemka return 0;
689cb10c7c0SVijay Khemka }
690cb10c7c0SVijay Khemka
691163f5de5SIvan Mikhaylov /* Response handler for Intel card */
ncsi_rsp_handler_oem_intel(struct ncsi_request * nr)692163f5de5SIvan Mikhaylov static int ncsi_rsp_handler_oem_intel(struct ncsi_request *nr)
693163f5de5SIvan Mikhaylov {
694205b95feSIvan Mikhaylov struct ncsi_rsp_oem_intel_pkt *intel;
695205b95feSIvan Mikhaylov struct ncsi_rsp_oem_pkt *rsp;
696205b95feSIvan Mikhaylov
697205b95feSIvan Mikhaylov /* Get the response header */
698205b95feSIvan Mikhaylov rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
699205b95feSIvan Mikhaylov intel = (struct ncsi_rsp_oem_intel_pkt *)(rsp->data);
700205b95feSIvan Mikhaylov
701205b95feSIvan Mikhaylov if (intel->cmd == NCSI_OEM_INTEL_CMD_GMA)
70274b449b9SIvan Mikhaylov return ncsi_rsp_handler_oem_gma(nr, NCSI_OEM_MFR_INTEL_ID);
703205b95feSIvan Mikhaylov
704163f5de5SIvan Mikhaylov return 0;
705163f5de5SIvan Mikhaylov }
706163f5de5SIvan Mikhaylov
707fb4ee675SVijay Khemka static struct ncsi_rsp_oem_handler {
708fb4ee675SVijay Khemka unsigned int mfr_id;
709fb4ee675SVijay Khemka int (*handler)(struct ncsi_request *nr);
710fb4ee675SVijay Khemka } ncsi_rsp_oem_handlers[] = {
71116e8c4caSVijay Khemka { NCSI_OEM_MFR_MLX_ID, ncsi_rsp_handler_oem_mlx },
712163f5de5SIvan Mikhaylov { NCSI_OEM_MFR_BCM_ID, ncsi_rsp_handler_oem_bcm },
713163f5de5SIvan Mikhaylov { NCSI_OEM_MFR_INTEL_ID, ncsi_rsp_handler_oem_intel }
714fb4ee675SVijay Khemka };
715fb4ee675SVijay Khemka
716fb4ee675SVijay Khemka /* Response handler for OEM command */
ncsi_rsp_handler_oem(struct ncsi_request * nr)717fb4ee675SVijay Khemka static int ncsi_rsp_handler_oem(struct ncsi_request *nr)
718fb4ee675SVijay Khemka {
719fb4ee675SVijay Khemka struct ncsi_rsp_oem_handler *nrh = NULL;
720cb10c7c0SVijay Khemka struct ncsi_rsp_oem_pkt *rsp;
721fb4ee675SVijay Khemka unsigned int mfr_id, i;
722fb4ee675SVijay Khemka
723fb4ee675SVijay Khemka /* Get the response header */
724fb4ee675SVijay Khemka rsp = (struct ncsi_rsp_oem_pkt *)skb_network_header(nr->rsp);
725fb4ee675SVijay Khemka mfr_id = ntohl(rsp->mfr_id);
726fb4ee675SVijay Khemka
727fb4ee675SVijay Khemka /* Check for manufacturer id and Find the handler */
728fb4ee675SVijay Khemka for (i = 0; i < ARRAY_SIZE(ncsi_rsp_oem_handlers); i++) {
729fb4ee675SVijay Khemka if (ncsi_rsp_oem_handlers[i].mfr_id == mfr_id) {
730fb4ee675SVijay Khemka if (ncsi_rsp_oem_handlers[i].handler)
731fb4ee675SVijay Khemka nrh = &ncsi_rsp_oem_handlers[i];
732fb4ee675SVijay Khemka else
733fb4ee675SVijay Khemka nrh = NULL;
734fb4ee675SVijay Khemka
735fb4ee675SVijay Khemka break;
736fb4ee675SVijay Khemka }
737fb4ee675SVijay Khemka }
738fb4ee675SVijay Khemka
739fb4ee675SVijay Khemka if (!nrh) {
740fb4ee675SVijay Khemka netdev_err(nr->ndp->ndev.dev, "Received unrecognized OEM packet with MFR-ID (0x%x)\n",
741fb4ee675SVijay Khemka mfr_id);
742fb4ee675SVijay Khemka return -ENOENT;
743fb4ee675SVijay Khemka }
744fb4ee675SVijay Khemka
745fb4ee675SVijay Khemka /* Process the packet */
746fb4ee675SVijay Khemka return nrh->handler(nr);
747fb4ee675SVijay Khemka }
748fb4ee675SVijay Khemka
ncsi_rsp_handler_gvi(struct ncsi_request * nr)749138635ccSGavin Shan static int ncsi_rsp_handler_gvi(struct ncsi_request *nr)
750138635ccSGavin Shan {
751138635ccSGavin Shan struct ncsi_rsp_gvi_pkt *rsp;
752138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
753138635ccSGavin Shan struct ncsi_channel *nc;
754138635ccSGavin Shan struct ncsi_channel_version *ncv;
755138635ccSGavin Shan int i;
756138635ccSGavin Shan
757138635ccSGavin Shan /* Find the channel */
758138635ccSGavin Shan rsp = (struct ncsi_rsp_gvi_pkt *)skb_network_header(nr->rsp);
759138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
760138635ccSGavin Shan NULL, &nc);
761138635ccSGavin Shan if (!nc)
762138635ccSGavin Shan return -ENODEV;
763138635ccSGavin Shan
7641c83c708SPeter Delevoryas /* Update channel's version info
7651c83c708SPeter Delevoryas *
7661c83c708SPeter Delevoryas * Major, minor, and update fields are supposed to be
7671c83c708SPeter Delevoryas * unsigned integers encoded as packed BCD.
7681c83c708SPeter Delevoryas *
7691c83c708SPeter Delevoryas * Alpha1 and alpha2 are ISO/IEC 8859-1 characters.
7701c83c708SPeter Delevoryas */
771138635ccSGavin Shan ncv = &nc->version;
7721c83c708SPeter Delevoryas ncv->major = decode_bcd_u8(rsp->major);
7731c83c708SPeter Delevoryas ncv->minor = decode_bcd_u8(rsp->minor);
7741c83c708SPeter Delevoryas ncv->update = decode_bcd_u8(rsp->update);
7751c83c708SPeter Delevoryas ncv->alpha1 = rsp->alpha1;
776138635ccSGavin Shan ncv->alpha2 = rsp->alpha2;
777138635ccSGavin Shan memcpy(ncv->fw_name, rsp->fw_name, 12);
778138635ccSGavin Shan ncv->fw_version = ntohl(rsp->fw_version);
779138635ccSGavin Shan for (i = 0; i < ARRAY_SIZE(ncv->pci_ids); i++)
780138635ccSGavin Shan ncv->pci_ids[i] = ntohs(rsp->pci_ids[i]);
781138635ccSGavin Shan ncv->mf_id = ntohl(rsp->mf_id);
782138635ccSGavin Shan
783138635ccSGavin Shan return 0;
784138635ccSGavin Shan }
785138635ccSGavin Shan
ncsi_rsp_handler_gc(struct ncsi_request * nr)786138635ccSGavin Shan static int ncsi_rsp_handler_gc(struct ncsi_request *nr)
787138635ccSGavin Shan {
788138635ccSGavin Shan struct ncsi_rsp_gc_pkt *rsp;
789138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
790138635ccSGavin Shan struct ncsi_channel *nc;
791645e643eSDelphineCCChiu struct ncsi_package *np;
792062b3e1bSSamuel Mendoza-Jonas size_t size;
793138635ccSGavin Shan
794138635ccSGavin Shan /* Find the channel */
795138635ccSGavin Shan rsp = (struct ncsi_rsp_gc_pkt *)skb_network_header(nr->rsp);
796138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
797645e643eSDelphineCCChiu &np, &nc);
798138635ccSGavin Shan if (!nc)
799138635ccSGavin Shan return -ENODEV;
800138635ccSGavin Shan
801138635ccSGavin Shan /* Update channel's capabilities */
802138635ccSGavin Shan nc->caps[NCSI_CAP_GENERIC].cap = ntohl(rsp->cap) &
803138635ccSGavin Shan NCSI_CAP_GENERIC_MASK;
804138635ccSGavin Shan nc->caps[NCSI_CAP_BC].cap = ntohl(rsp->bc_cap) &
805138635ccSGavin Shan NCSI_CAP_BC_MASK;
806138635ccSGavin Shan nc->caps[NCSI_CAP_MC].cap = ntohl(rsp->mc_cap) &
807138635ccSGavin Shan NCSI_CAP_MC_MASK;
808138635ccSGavin Shan nc->caps[NCSI_CAP_BUFFER].cap = ntohl(rsp->buf_cap);
809138635ccSGavin Shan nc->caps[NCSI_CAP_AEN].cap = ntohl(rsp->aen_cap) &
810138635ccSGavin Shan NCSI_CAP_AEN_MASK;
811138635ccSGavin Shan nc->caps[NCSI_CAP_VLAN].cap = rsp->vlan_mode &
812138635ccSGavin Shan NCSI_CAP_VLAN_MASK;
813138635ccSGavin Shan
814062b3e1bSSamuel Mendoza-Jonas size = (rsp->uc_cnt + rsp->mc_cnt + rsp->mixed_cnt) * ETH_ALEN;
815b0949618SSamuel Mendoza-Jonas nc->mac_filter.addrs = kzalloc(size, GFP_ATOMIC);
816062b3e1bSSamuel Mendoza-Jonas if (!nc->mac_filter.addrs)
817138635ccSGavin Shan return -ENOMEM;
818062b3e1bSSamuel Mendoza-Jonas nc->mac_filter.n_uc = rsp->uc_cnt;
819062b3e1bSSamuel Mendoza-Jonas nc->mac_filter.n_mc = rsp->mc_cnt;
820062b3e1bSSamuel Mendoza-Jonas nc->mac_filter.n_mixed = rsp->mixed_cnt;
821138635ccSGavin Shan
822062b3e1bSSamuel Mendoza-Jonas nc->vlan_filter.vids = kcalloc(rsp->vlan_cnt,
823062b3e1bSSamuel Mendoza-Jonas sizeof(*nc->vlan_filter.vids),
824b0949618SSamuel Mendoza-Jonas GFP_ATOMIC);
825062b3e1bSSamuel Mendoza-Jonas if (!nc->vlan_filter.vids)
826062b3e1bSSamuel Mendoza-Jonas return -ENOMEM;
827062b3e1bSSamuel Mendoza-Jonas /* Set VLAN filters active so they are cleared in the first
828062b3e1bSSamuel Mendoza-Jonas * configuration state
82921acf630SSamuel Mendoza-Jonas */
830062b3e1bSSamuel Mendoza-Jonas nc->vlan_filter.bitmap = U64_MAX;
831062b3e1bSSamuel Mendoza-Jonas nc->vlan_filter.n_vids = rsp->vlan_cnt;
832645e643eSDelphineCCChiu np->ndp->channel_count = rsp->channel_cnt;
833138635ccSGavin Shan
834138635ccSGavin Shan return 0;
835138635ccSGavin Shan }
836138635ccSGavin Shan
ncsi_rsp_handler_gp(struct ncsi_request * nr)837138635ccSGavin Shan static int ncsi_rsp_handler_gp(struct ncsi_request *nr)
838138635ccSGavin Shan {
839062b3e1bSSamuel Mendoza-Jonas struct ncsi_channel_vlan_filter *ncvf;
840062b3e1bSSamuel Mendoza-Jonas struct ncsi_channel_mac_filter *ncmf;
841138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
842062b3e1bSSamuel Mendoza-Jonas struct ncsi_rsp_gp_pkt *rsp;
843138635ccSGavin Shan struct ncsi_channel *nc;
844062b3e1bSSamuel Mendoza-Jonas unsigned short enable;
845138635ccSGavin Shan unsigned char *pdata;
846062b3e1bSSamuel Mendoza-Jonas unsigned long flags;
847062b3e1bSSamuel Mendoza-Jonas void *bitmap;
848062b3e1bSSamuel Mendoza-Jonas int i;
849138635ccSGavin Shan
850138635ccSGavin Shan /* Find the channel */
851138635ccSGavin Shan rsp = (struct ncsi_rsp_gp_pkt *)skb_network_header(nr->rsp);
852138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
853138635ccSGavin Shan NULL, &nc);
854138635ccSGavin Shan if (!nc)
855138635ccSGavin Shan return -ENODEV;
856138635ccSGavin Shan
857138635ccSGavin Shan /* Modes with explicit enabled indications */
858138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x1) { /* BC filter mode */
859138635ccSGavin Shan nc->modes[NCSI_MODE_BC].enable = 1;
860138635ccSGavin Shan nc->modes[NCSI_MODE_BC].data[0] = ntohl(rsp->bc_mode);
861138635ccSGavin Shan }
862138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x2) /* Channel enabled */
863138635ccSGavin Shan nc->modes[NCSI_MODE_ENABLE].enable = 1;
864138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x4) /* Channel Tx enabled */
865138635ccSGavin Shan nc->modes[NCSI_MODE_TX_ENABLE].enable = 1;
866138635ccSGavin Shan if (ntohl(rsp->valid_modes) & 0x8) /* MC filter mode */
867138635ccSGavin Shan nc->modes[NCSI_MODE_MC].enable = 1;
868138635ccSGavin Shan
869138635ccSGavin Shan /* Modes without explicit enabled indications */
870138635ccSGavin Shan nc->modes[NCSI_MODE_LINK].enable = 1;
871138635ccSGavin Shan nc->modes[NCSI_MODE_LINK].data[0] = ntohl(rsp->link_mode);
872138635ccSGavin Shan nc->modes[NCSI_MODE_VLAN].enable = 1;
873138635ccSGavin Shan nc->modes[NCSI_MODE_VLAN].data[0] = rsp->vlan_mode;
874138635ccSGavin Shan nc->modes[NCSI_MODE_FC].enable = 1;
875138635ccSGavin Shan nc->modes[NCSI_MODE_FC].data[0] = rsp->fc_mode;
876138635ccSGavin Shan nc->modes[NCSI_MODE_AEN].enable = 1;
877138635ccSGavin Shan nc->modes[NCSI_MODE_AEN].data[0] = ntohl(rsp->aen_mode);
878138635ccSGavin Shan
879138635ccSGavin Shan /* MAC addresses filter table */
880138635ccSGavin Shan pdata = (unsigned char *)rsp + 48;
881138635ccSGavin Shan enable = rsp->mac_enable;
882062b3e1bSSamuel Mendoza-Jonas ncmf = &nc->mac_filter;
883062b3e1bSSamuel Mendoza-Jonas spin_lock_irqsave(&nc->lock, flags);
884062b3e1bSSamuel Mendoza-Jonas bitmap = &ncmf->bitmap;
885138635ccSGavin Shan for (i = 0; i < rsp->mac_cnt; i++, pdata += 6) {
886138635ccSGavin Shan if (!(enable & (0x1 << i)))
887062b3e1bSSamuel Mendoza-Jonas clear_bit(i, bitmap);
888062b3e1bSSamuel Mendoza-Jonas else
889062b3e1bSSamuel Mendoza-Jonas set_bit(i, bitmap);
890138635ccSGavin Shan
891062b3e1bSSamuel Mendoza-Jonas memcpy(&ncmf->addrs[i * ETH_ALEN], pdata, ETH_ALEN);
892138635ccSGavin Shan }
893062b3e1bSSamuel Mendoza-Jonas spin_unlock_irqrestore(&nc->lock, flags);
894138635ccSGavin Shan
895138635ccSGavin Shan /* VLAN filter table */
896138635ccSGavin Shan enable = ntohs(rsp->vlan_enable);
897062b3e1bSSamuel Mendoza-Jonas ncvf = &nc->vlan_filter;
898062b3e1bSSamuel Mendoza-Jonas bitmap = &ncvf->bitmap;
899062b3e1bSSamuel Mendoza-Jonas spin_lock_irqsave(&nc->lock, flags);
900138635ccSGavin Shan for (i = 0; i < rsp->vlan_cnt; i++, pdata += 2) {
901138635ccSGavin Shan if (!(enable & (0x1 << i)))
902062b3e1bSSamuel Mendoza-Jonas clear_bit(i, bitmap);
903062b3e1bSSamuel Mendoza-Jonas else
904062b3e1bSSamuel Mendoza-Jonas set_bit(i, bitmap);
905138635ccSGavin Shan
906062b3e1bSSamuel Mendoza-Jonas ncvf->vids[i] = ntohs(*(__be16 *)pdata);
907138635ccSGavin Shan }
908062b3e1bSSamuel Mendoza-Jonas spin_unlock_irqrestore(&nc->lock, flags);
909138635ccSGavin Shan
910138635ccSGavin Shan return 0;
911138635ccSGavin Shan }
912138635ccSGavin Shan
ncsi_rsp_handler_gcps(struct ncsi_request * nr)913138635ccSGavin Shan static int ncsi_rsp_handler_gcps(struct ncsi_request *nr)
914138635ccSGavin Shan {
915138635ccSGavin Shan struct ncsi_rsp_gcps_pkt *rsp;
916138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
917138635ccSGavin Shan struct ncsi_channel *nc;
918138635ccSGavin Shan struct ncsi_channel_stats *ncs;
919138635ccSGavin Shan
920138635ccSGavin Shan /* Find the channel */
921138635ccSGavin Shan rsp = (struct ncsi_rsp_gcps_pkt *)skb_network_header(nr->rsp);
922138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
923138635ccSGavin Shan NULL, &nc);
924138635ccSGavin Shan if (!nc)
925138635ccSGavin Shan return -ENODEV;
926138635ccSGavin Shan
927138635ccSGavin Shan /* Update HNC's statistics */
928138635ccSGavin Shan ncs = &nc->stats;
929138635ccSGavin Shan ncs->hnc_cnt_hi = ntohl(rsp->cnt_hi);
930138635ccSGavin Shan ncs->hnc_cnt_lo = ntohl(rsp->cnt_lo);
931138635ccSGavin Shan ncs->hnc_rx_bytes = ntohl(rsp->rx_bytes);
932138635ccSGavin Shan ncs->hnc_tx_bytes = ntohl(rsp->tx_bytes);
933138635ccSGavin Shan ncs->hnc_rx_uc_pkts = ntohl(rsp->rx_uc_pkts);
934138635ccSGavin Shan ncs->hnc_rx_mc_pkts = ntohl(rsp->rx_mc_pkts);
935138635ccSGavin Shan ncs->hnc_rx_bc_pkts = ntohl(rsp->rx_bc_pkts);
936138635ccSGavin Shan ncs->hnc_tx_uc_pkts = ntohl(rsp->tx_uc_pkts);
937138635ccSGavin Shan ncs->hnc_tx_mc_pkts = ntohl(rsp->tx_mc_pkts);
938138635ccSGavin Shan ncs->hnc_tx_bc_pkts = ntohl(rsp->tx_bc_pkts);
939138635ccSGavin Shan ncs->hnc_fcs_err = ntohl(rsp->fcs_err);
940138635ccSGavin Shan ncs->hnc_align_err = ntohl(rsp->align_err);
941138635ccSGavin Shan ncs->hnc_false_carrier = ntohl(rsp->false_carrier);
942138635ccSGavin Shan ncs->hnc_runt_pkts = ntohl(rsp->runt_pkts);
943138635ccSGavin Shan ncs->hnc_jabber_pkts = ntohl(rsp->jabber_pkts);
944138635ccSGavin Shan ncs->hnc_rx_pause_xon = ntohl(rsp->rx_pause_xon);
945138635ccSGavin Shan ncs->hnc_rx_pause_xoff = ntohl(rsp->rx_pause_xoff);
946138635ccSGavin Shan ncs->hnc_tx_pause_xon = ntohl(rsp->tx_pause_xon);
947138635ccSGavin Shan ncs->hnc_tx_pause_xoff = ntohl(rsp->tx_pause_xoff);
948138635ccSGavin Shan ncs->hnc_tx_s_collision = ntohl(rsp->tx_s_collision);
949138635ccSGavin Shan ncs->hnc_tx_m_collision = ntohl(rsp->tx_m_collision);
950138635ccSGavin Shan ncs->hnc_l_collision = ntohl(rsp->l_collision);
951138635ccSGavin Shan ncs->hnc_e_collision = ntohl(rsp->e_collision);
952138635ccSGavin Shan ncs->hnc_rx_ctl_frames = ntohl(rsp->rx_ctl_frames);
953138635ccSGavin Shan ncs->hnc_rx_64_frames = ntohl(rsp->rx_64_frames);
954138635ccSGavin Shan ncs->hnc_rx_127_frames = ntohl(rsp->rx_127_frames);
955138635ccSGavin Shan ncs->hnc_rx_255_frames = ntohl(rsp->rx_255_frames);
956138635ccSGavin Shan ncs->hnc_rx_511_frames = ntohl(rsp->rx_511_frames);
957138635ccSGavin Shan ncs->hnc_rx_1023_frames = ntohl(rsp->rx_1023_frames);
958138635ccSGavin Shan ncs->hnc_rx_1522_frames = ntohl(rsp->rx_1522_frames);
959138635ccSGavin Shan ncs->hnc_rx_9022_frames = ntohl(rsp->rx_9022_frames);
960138635ccSGavin Shan ncs->hnc_tx_64_frames = ntohl(rsp->tx_64_frames);
961138635ccSGavin Shan ncs->hnc_tx_127_frames = ntohl(rsp->tx_127_frames);
962138635ccSGavin Shan ncs->hnc_tx_255_frames = ntohl(rsp->tx_255_frames);
963138635ccSGavin Shan ncs->hnc_tx_511_frames = ntohl(rsp->tx_511_frames);
964138635ccSGavin Shan ncs->hnc_tx_1023_frames = ntohl(rsp->tx_1023_frames);
965138635ccSGavin Shan ncs->hnc_tx_1522_frames = ntohl(rsp->tx_1522_frames);
966138635ccSGavin Shan ncs->hnc_tx_9022_frames = ntohl(rsp->tx_9022_frames);
967138635ccSGavin Shan ncs->hnc_rx_valid_bytes = ntohl(rsp->rx_valid_bytes);
968138635ccSGavin Shan ncs->hnc_rx_runt_pkts = ntohl(rsp->rx_runt_pkts);
969138635ccSGavin Shan ncs->hnc_rx_jabber_pkts = ntohl(rsp->rx_jabber_pkts);
970138635ccSGavin Shan
971138635ccSGavin Shan return 0;
972138635ccSGavin Shan }
973138635ccSGavin Shan
ncsi_rsp_handler_gns(struct ncsi_request * nr)974138635ccSGavin Shan static int ncsi_rsp_handler_gns(struct ncsi_request *nr)
975138635ccSGavin Shan {
976138635ccSGavin Shan struct ncsi_rsp_gns_pkt *rsp;
977138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
978138635ccSGavin Shan struct ncsi_channel *nc;
979138635ccSGavin Shan struct ncsi_channel_stats *ncs;
980138635ccSGavin Shan
981138635ccSGavin Shan /* Find the channel */
982138635ccSGavin Shan rsp = (struct ncsi_rsp_gns_pkt *)skb_network_header(nr->rsp);
983138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
984138635ccSGavin Shan NULL, &nc);
985138635ccSGavin Shan if (!nc)
986138635ccSGavin Shan return -ENODEV;
987138635ccSGavin Shan
988138635ccSGavin Shan /* Update HNC's statistics */
989138635ccSGavin Shan ncs = &nc->stats;
990138635ccSGavin Shan ncs->ncsi_rx_cmds = ntohl(rsp->rx_cmds);
991138635ccSGavin Shan ncs->ncsi_dropped_cmds = ntohl(rsp->dropped_cmds);
992138635ccSGavin Shan ncs->ncsi_cmd_type_errs = ntohl(rsp->cmd_type_errs);
993138635ccSGavin Shan ncs->ncsi_cmd_csum_errs = ntohl(rsp->cmd_csum_errs);
994138635ccSGavin Shan ncs->ncsi_rx_pkts = ntohl(rsp->rx_pkts);
995138635ccSGavin Shan ncs->ncsi_tx_pkts = ntohl(rsp->tx_pkts);
996138635ccSGavin Shan ncs->ncsi_tx_aen_pkts = ntohl(rsp->tx_aen_pkts);
997138635ccSGavin Shan
998138635ccSGavin Shan return 0;
999138635ccSGavin Shan }
1000138635ccSGavin Shan
ncsi_rsp_handler_gnpts(struct ncsi_request * nr)1001138635ccSGavin Shan static int ncsi_rsp_handler_gnpts(struct ncsi_request *nr)
1002138635ccSGavin Shan {
1003138635ccSGavin Shan struct ncsi_rsp_gnpts_pkt *rsp;
1004138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
1005138635ccSGavin Shan struct ncsi_channel *nc;
1006138635ccSGavin Shan struct ncsi_channel_stats *ncs;
1007138635ccSGavin Shan
1008138635ccSGavin Shan /* Find the channel */
1009138635ccSGavin Shan rsp = (struct ncsi_rsp_gnpts_pkt *)skb_network_header(nr->rsp);
1010138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1011138635ccSGavin Shan NULL, &nc);
1012138635ccSGavin Shan if (!nc)
1013138635ccSGavin Shan return -ENODEV;
1014138635ccSGavin Shan
1015138635ccSGavin Shan /* Update HNC's statistics */
1016138635ccSGavin Shan ncs = &nc->stats;
1017138635ccSGavin Shan ncs->pt_tx_pkts = ntohl(rsp->tx_pkts);
1018138635ccSGavin Shan ncs->pt_tx_dropped = ntohl(rsp->tx_dropped);
1019138635ccSGavin Shan ncs->pt_tx_channel_err = ntohl(rsp->tx_channel_err);
1020138635ccSGavin Shan ncs->pt_tx_us_err = ntohl(rsp->tx_us_err);
1021138635ccSGavin Shan ncs->pt_rx_pkts = ntohl(rsp->rx_pkts);
1022138635ccSGavin Shan ncs->pt_rx_dropped = ntohl(rsp->rx_dropped);
1023138635ccSGavin Shan ncs->pt_rx_channel_err = ntohl(rsp->rx_channel_err);
1024138635ccSGavin Shan ncs->pt_rx_us_err = ntohl(rsp->rx_us_err);
1025138635ccSGavin Shan ncs->pt_rx_os_err = ntohl(rsp->rx_os_err);
1026138635ccSGavin Shan
1027138635ccSGavin Shan return 0;
1028138635ccSGavin Shan }
1029138635ccSGavin Shan
ncsi_rsp_handler_gps(struct ncsi_request * nr)1030138635ccSGavin Shan static int ncsi_rsp_handler_gps(struct ncsi_request *nr)
1031138635ccSGavin Shan {
1032138635ccSGavin Shan struct ncsi_rsp_gps_pkt *rsp;
1033138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
1034138635ccSGavin Shan struct ncsi_package *np;
1035138635ccSGavin Shan
1036138635ccSGavin Shan /* Find the package */
1037138635ccSGavin Shan rsp = (struct ncsi_rsp_gps_pkt *)skb_network_header(nr->rsp);
1038138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1039138635ccSGavin Shan &np, NULL);
1040138635ccSGavin Shan if (!np)
1041138635ccSGavin Shan return -ENODEV;
1042138635ccSGavin Shan
1043138635ccSGavin Shan return 0;
1044138635ccSGavin Shan }
1045138635ccSGavin Shan
ncsi_rsp_handler_gpuuid(struct ncsi_request * nr)1046138635ccSGavin Shan static int ncsi_rsp_handler_gpuuid(struct ncsi_request *nr)
1047138635ccSGavin Shan {
1048138635ccSGavin Shan struct ncsi_rsp_gpuuid_pkt *rsp;
1049138635ccSGavin Shan struct ncsi_dev_priv *ndp = nr->ndp;
1050138635ccSGavin Shan struct ncsi_package *np;
1051138635ccSGavin Shan
1052138635ccSGavin Shan /* Find the package */
1053138635ccSGavin Shan rsp = (struct ncsi_rsp_gpuuid_pkt *)skb_network_header(nr->rsp);
1054138635ccSGavin Shan ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
1055138635ccSGavin Shan &np, NULL);
1056138635ccSGavin Shan if (!np)
1057138635ccSGavin Shan return -ENODEV;
1058138635ccSGavin Shan
1059138635ccSGavin Shan memcpy(np->uuid, rsp->uuid, sizeof(rsp->uuid));
1060138635ccSGavin Shan
1061138635ccSGavin Shan return 0;
1062138635ccSGavin Shan }
1063138635ccSGavin Shan
ncsi_rsp_handler_pldm(struct ncsi_request * nr)10646f671045SBen Wei static int ncsi_rsp_handler_pldm(struct ncsi_request *nr)
10656f671045SBen Wei {
10666f671045SBen Wei return 0;
10676f671045SBen Wei }
10686f671045SBen Wei
ncsi_rsp_handler_netlink(struct ncsi_request * nr)10699771b8ccSJustin.Lee1@Dell.com static int ncsi_rsp_handler_netlink(struct ncsi_request *nr)
10709771b8ccSJustin.Lee1@Dell.com {
10719771b8ccSJustin.Lee1@Dell.com struct ncsi_dev_priv *ndp = nr->ndp;
10729771b8ccSJustin.Lee1@Dell.com struct ncsi_rsp_pkt *rsp;
10739771b8ccSJustin.Lee1@Dell.com struct ncsi_package *np;
10749771b8ccSJustin.Lee1@Dell.com struct ncsi_channel *nc;
10759771b8ccSJustin.Lee1@Dell.com int ret;
10769771b8ccSJustin.Lee1@Dell.com
10779771b8ccSJustin.Lee1@Dell.com /* Find the package */
10789771b8ccSJustin.Lee1@Dell.com rsp = (struct ncsi_rsp_pkt *)skb_network_header(nr->rsp);
10799771b8ccSJustin.Lee1@Dell.com ncsi_find_package_and_channel(ndp, rsp->rsp.common.channel,
10809771b8ccSJustin.Lee1@Dell.com &np, &nc);
10819771b8ccSJustin.Lee1@Dell.com if (!np)
10829771b8ccSJustin.Lee1@Dell.com return -ENODEV;
10839771b8ccSJustin.Lee1@Dell.com
10849771b8ccSJustin.Lee1@Dell.com ret = ncsi_send_netlink_rsp(nr, np, nc);
10859771b8ccSJustin.Lee1@Dell.com
10869771b8ccSJustin.Lee1@Dell.com return ret;
10879771b8ccSJustin.Lee1@Dell.com }
10889771b8ccSJustin.Lee1@Dell.com
ncsi_rsp_handler_gmcma(struct ncsi_request * nr)108967515088SPeter Delevoryas static int ncsi_rsp_handler_gmcma(struct ncsi_request *nr)
109067515088SPeter Delevoryas {
109167515088SPeter Delevoryas struct ncsi_dev_priv *ndp = nr->ndp;
1092*2cc0f0e1SPaul Fertser struct sockaddr *saddr = &ndp->pending_mac;
109367515088SPeter Delevoryas struct net_device *ndev = ndp->ndev.dev;
109467515088SPeter Delevoryas struct ncsi_rsp_gmcma_pkt *rsp;
109567515088SPeter Delevoryas int i;
109667515088SPeter Delevoryas
109767515088SPeter Delevoryas rsp = (struct ncsi_rsp_gmcma_pkt *)skb_network_header(nr->rsp);
109867515088SPeter Delevoryas ndev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
109967515088SPeter Delevoryas
110067515088SPeter Delevoryas netdev_info(ndev, "NCSI: Received %d provisioned MAC addresses\n",
110167515088SPeter Delevoryas rsp->address_count);
110267515088SPeter Delevoryas for (i = 0; i < rsp->address_count; i++) {
110367515088SPeter Delevoryas netdev_info(ndev, "NCSI: MAC address %d: %02x:%02x:%02x:%02x:%02x:%02x\n",
110467515088SPeter Delevoryas i, rsp->addresses[i][0], rsp->addresses[i][1],
110567515088SPeter Delevoryas rsp->addresses[i][2], rsp->addresses[i][3],
110667515088SPeter Delevoryas rsp->addresses[i][4], rsp->addresses[i][5]);
110767515088SPeter Delevoryas }
110867515088SPeter Delevoryas
1109*2cc0f0e1SPaul Fertser saddr->sa_family = ndev->type;
111067515088SPeter Delevoryas for (i = 0; i < rsp->address_count; i++) {
1111*2cc0f0e1SPaul Fertser if (!is_valid_ether_addr(rsp->addresses[i])) {
111267515088SPeter Delevoryas netdev_warn(ndev, "NCSI: Unable to assign %pM to device\n",
1113*2cc0f0e1SPaul Fertser rsp->addresses[i]);
111467515088SPeter Delevoryas continue;
111567515088SPeter Delevoryas }
1116*2cc0f0e1SPaul Fertser memcpy(saddr->sa_data, rsp->addresses[i], ETH_ALEN);
1117*2cc0f0e1SPaul Fertser netdev_warn(ndev, "NCSI: Will set MAC address to %pM\n", saddr->sa_data);
111867515088SPeter Delevoryas break;
111967515088SPeter Delevoryas }
112067515088SPeter Delevoryas
1121*2cc0f0e1SPaul Fertser ndp->gma_flag = 1;
1122*2cc0f0e1SPaul Fertser return 0;
112367515088SPeter Delevoryas }
112467515088SPeter Delevoryas
1125138635ccSGavin Shan static struct ncsi_rsp_handler {
1126138635ccSGavin Shan unsigned char type;
1127138635ccSGavin Shan int payload;
1128138635ccSGavin Shan int (*handler)(struct ncsi_request *nr);
1129138635ccSGavin Shan } ncsi_rsp_handlers[] = {
1130138635ccSGavin Shan { NCSI_PKT_RSP_CIS, 4, ncsi_rsp_handler_cis },
1131138635ccSGavin Shan { NCSI_PKT_RSP_SP, 4, ncsi_rsp_handler_sp },
1132138635ccSGavin Shan { NCSI_PKT_RSP_DP, 4, ncsi_rsp_handler_dp },
1133138635ccSGavin Shan { NCSI_PKT_RSP_EC, 4, ncsi_rsp_handler_ec },
1134138635ccSGavin Shan { NCSI_PKT_RSP_DC, 4, ncsi_rsp_handler_dc },
1135138635ccSGavin Shan { NCSI_PKT_RSP_RC, 4, ncsi_rsp_handler_rc },
1136138635ccSGavin Shan { NCSI_PKT_RSP_ECNT, 4, ncsi_rsp_handler_ecnt },
1137138635ccSGavin Shan { NCSI_PKT_RSP_DCNT, 4, ncsi_rsp_handler_dcnt },
1138138635ccSGavin Shan { NCSI_PKT_RSP_AE, 4, ncsi_rsp_handler_ae },
1139138635ccSGavin Shan { NCSI_PKT_RSP_SL, 4, ncsi_rsp_handler_sl },
1140138635ccSGavin Shan { NCSI_PKT_RSP_GLS, 16, ncsi_rsp_handler_gls },
1141138635ccSGavin Shan { NCSI_PKT_RSP_SVF, 4, ncsi_rsp_handler_svf },
1142138635ccSGavin Shan { NCSI_PKT_RSP_EV, 4, ncsi_rsp_handler_ev },
1143138635ccSGavin Shan { NCSI_PKT_RSP_DV, 4, ncsi_rsp_handler_dv },
1144138635ccSGavin Shan { NCSI_PKT_RSP_SMA, 4, ncsi_rsp_handler_sma },
1145138635ccSGavin Shan { NCSI_PKT_RSP_EBF, 4, ncsi_rsp_handler_ebf },
1146138635ccSGavin Shan { NCSI_PKT_RSP_DBF, 4, ncsi_rsp_handler_dbf },
1147138635ccSGavin Shan { NCSI_PKT_RSP_EGMF, 4, ncsi_rsp_handler_egmf },
1148138635ccSGavin Shan { NCSI_PKT_RSP_DGMF, 4, ncsi_rsp_handler_dgmf },
1149138635ccSGavin Shan { NCSI_PKT_RSP_SNFC, 4, ncsi_rsp_handler_snfc },
11500a90e251SGavin Shan { NCSI_PKT_RSP_GVI, 40, ncsi_rsp_handler_gvi },
1151138635ccSGavin Shan { NCSI_PKT_RSP_GC, 32, ncsi_rsp_handler_gc },
1152138635ccSGavin Shan { NCSI_PKT_RSP_GP, -1, ncsi_rsp_handler_gp },
11536d24e141SBen Wei { NCSI_PKT_RSP_GCPS, 204, ncsi_rsp_handler_gcps },
11546d24e141SBen Wei { NCSI_PKT_RSP_GNS, 32, ncsi_rsp_handler_gns },
11556d24e141SBen Wei { NCSI_PKT_RSP_GNPTS, 48, ncsi_rsp_handler_gnpts },
1156138635ccSGavin Shan { NCSI_PKT_RSP_GPS, 8, ncsi_rsp_handler_gps },
1157fb4ee675SVijay Khemka { NCSI_PKT_RSP_OEM, -1, ncsi_rsp_handler_oem },
11586f671045SBen Wei { NCSI_PKT_RSP_PLDM, -1, ncsi_rsp_handler_pldm },
11596f671045SBen Wei { NCSI_PKT_RSP_GPUUID, 20, ncsi_rsp_handler_gpuuid },
11606f671045SBen Wei { NCSI_PKT_RSP_QPNPR, -1, ncsi_rsp_handler_pldm },
116167515088SPeter Delevoryas { NCSI_PKT_RSP_SNPR, -1, ncsi_rsp_handler_pldm },
116267515088SPeter Delevoryas { NCSI_PKT_RSP_GMCMA, -1, ncsi_rsp_handler_gmcma },
1163138635ccSGavin Shan };
1164138635ccSGavin Shan
ncsi_rcv_rsp(struct sk_buff * skb,struct net_device * dev,struct packet_type * pt,struct net_device * orig_dev)1165138635ccSGavin Shan int ncsi_rcv_rsp(struct sk_buff *skb, struct net_device *dev,
1166138635ccSGavin Shan struct packet_type *pt, struct net_device *orig_dev)
1167138635ccSGavin Shan {
1168138635ccSGavin Shan struct ncsi_rsp_handler *nrh = NULL;
1169138635ccSGavin Shan struct ncsi_dev *nd;
1170138635ccSGavin Shan struct ncsi_dev_priv *ndp;
1171138635ccSGavin Shan struct ncsi_request *nr;
1172138635ccSGavin Shan struct ncsi_pkt_hdr *hdr;
1173138635ccSGavin Shan unsigned long flags;
1174138635ccSGavin Shan int payload, i, ret;
1175138635ccSGavin Shan
1176138635ccSGavin Shan /* Find the NCSI device */
1177427c9405SJohn Wang nd = ncsi_find_dev(orig_dev);
1178138635ccSGavin Shan ndp = nd ? TO_NCSI_DEV_PRIV(nd) : NULL;
1179138635ccSGavin Shan if (!ndp)
1180138635ccSGavin Shan return -ENODEV;
1181138635ccSGavin Shan
11827a82ecf4SGavin Shan /* Check if it is AEN packet */
1183138635ccSGavin Shan hdr = (struct ncsi_pkt_hdr *)skb_network_header(skb);
11847a82ecf4SGavin Shan if (hdr->type == NCSI_PKT_AEN)
11857a82ecf4SGavin Shan return ncsi_aen_handler(ndp, skb);
11867a82ecf4SGavin Shan
11877a82ecf4SGavin Shan /* Find the handler */
1188138635ccSGavin Shan for (i = 0; i < ARRAY_SIZE(ncsi_rsp_handlers); i++) {
1189138635ccSGavin Shan if (ncsi_rsp_handlers[i].type == hdr->type) {
1190138635ccSGavin Shan if (ncsi_rsp_handlers[i].handler)
1191138635ccSGavin Shan nrh = &ncsi_rsp_handlers[i];
1192138635ccSGavin Shan else
1193138635ccSGavin Shan nrh = NULL;
1194138635ccSGavin Shan
1195138635ccSGavin Shan break;
1196138635ccSGavin Shan }
1197138635ccSGavin Shan }
1198138635ccSGavin Shan
1199138635ccSGavin Shan if (!nrh) {
1200138635ccSGavin Shan netdev_err(nd->dev, "Received unrecognized packet (0x%x)\n",
1201138635ccSGavin Shan hdr->type);
1202138635ccSGavin Shan return -ENOENT;
1203138635ccSGavin Shan }
1204138635ccSGavin Shan
1205138635ccSGavin Shan /* Associate with the request */
1206138635ccSGavin Shan spin_lock_irqsave(&ndp->lock, flags);
1207138635ccSGavin Shan nr = &ndp->requests[hdr->id];
1208138635ccSGavin Shan if (!nr->used) {
1209138635ccSGavin Shan spin_unlock_irqrestore(&ndp->lock, flags);
1210138635ccSGavin Shan return -ENODEV;
1211138635ccSGavin Shan }
1212138635ccSGavin Shan
1213138635ccSGavin Shan nr->rsp = skb;
1214138635ccSGavin Shan if (!nr->enabled) {
1215138635ccSGavin Shan spin_unlock_irqrestore(&ndp->lock, flags);
1216138635ccSGavin Shan ret = -ENOENT;
1217138635ccSGavin Shan goto out;
1218138635ccSGavin Shan }
1219138635ccSGavin Shan
1220138635ccSGavin Shan /* Validate the packet */
1221138635ccSGavin Shan spin_unlock_irqrestore(&ndp->lock, flags);
1222138635ccSGavin Shan payload = nrh->payload;
1223138635ccSGavin Shan if (payload < 0)
1224138635ccSGavin Shan payload = ntohs(hdr->length);
1225138635ccSGavin Shan ret = ncsi_validate_rsp_pkt(nr, payload);
12269ef8690bSSamuel Mendoza-Jonas if (ret) {
12279ef8690bSSamuel Mendoza-Jonas netdev_warn(ndp->ndev.dev,
12289ef8690bSSamuel Mendoza-Jonas "NCSI: 'bad' packet ignored for type 0x%x\n",
12299ef8690bSSamuel Mendoza-Jonas hdr->type);
12309771b8ccSJustin.Lee1@Dell.com
12319771b8ccSJustin.Lee1@Dell.com if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
12329771b8ccSJustin.Lee1@Dell.com if (ret == -EPERM)
12339771b8ccSJustin.Lee1@Dell.com goto out_netlink;
12349771b8ccSJustin.Lee1@Dell.com else
12359771b8ccSJustin.Lee1@Dell.com ncsi_send_netlink_err(ndp->ndev.dev,
12369771b8ccSJustin.Lee1@Dell.com nr->snd_seq,
12379771b8ccSJustin.Lee1@Dell.com nr->snd_portid,
12389771b8ccSJustin.Lee1@Dell.com &nr->nlhdr,
12399771b8ccSJustin.Lee1@Dell.com ret);
12409771b8ccSJustin.Lee1@Dell.com }
1241138635ccSGavin Shan goto out;
12429ef8690bSSamuel Mendoza-Jonas }
1243138635ccSGavin Shan
1244138635ccSGavin Shan /* Process the packet */
1245138635ccSGavin Shan ret = nrh->handler(nr);
12469ef8690bSSamuel Mendoza-Jonas if (ret)
12479ef8690bSSamuel Mendoza-Jonas netdev_err(ndp->ndev.dev,
12489ef8690bSSamuel Mendoza-Jonas "NCSI: Handler for packet type 0x%x returned %d\n",
12499ef8690bSSamuel Mendoza-Jonas hdr->type, ret);
12509771b8ccSJustin.Lee1@Dell.com
12519771b8ccSJustin.Lee1@Dell.com out_netlink:
12529771b8ccSJustin.Lee1@Dell.com if (nr->flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
12539771b8ccSJustin.Lee1@Dell.com ret = ncsi_rsp_handler_netlink(nr);
12549771b8ccSJustin.Lee1@Dell.com if (ret) {
12559771b8ccSJustin.Lee1@Dell.com netdev_err(ndp->ndev.dev,
12569771b8ccSJustin.Lee1@Dell.com "NCSI: Netlink handler for packet type 0x%x returned %d\n",
12579771b8ccSJustin.Lee1@Dell.com hdr->type, ret);
12589771b8ccSJustin.Lee1@Dell.com }
12599771b8ccSJustin.Lee1@Dell.com }
12609771b8ccSJustin.Lee1@Dell.com
1261138635ccSGavin Shan out:
1262138635ccSGavin Shan ncsi_free_request(nr);
1263138635ccSGavin Shan return ret;
1264138635ccSGavin Shan }
1265