xref: /OK3568_Linux_fs/kernel/net/ncsi/ncsi-cmd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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/etherdevice.h>
10*4882a593Smuzhiyun #include <linux/netdevice.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 
21*4882a593Smuzhiyun static const int padding_bytes = 26;
22*4882a593Smuzhiyun 
ncsi_calculate_checksum(unsigned char * data,int len)23*4882a593Smuzhiyun u32 ncsi_calculate_checksum(unsigned char *data, int len)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	u32 checksum = 0;
26*4882a593Smuzhiyun 	int i;
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	for (i = 0; i < len; i += 2)
29*4882a593Smuzhiyun 		checksum += (((u32)data[i] << 8) | data[i + 1]);
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun 	checksum = (~checksum + 1);
32*4882a593Smuzhiyun 	return checksum;
33*4882a593Smuzhiyun }
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun /* This function should be called after the data area has been
36*4882a593Smuzhiyun  * populated completely.
37*4882a593Smuzhiyun  */
ncsi_cmd_build_header(struct ncsi_pkt_hdr * h,struct ncsi_cmd_arg * nca)38*4882a593Smuzhiyun static void ncsi_cmd_build_header(struct ncsi_pkt_hdr *h,
39*4882a593Smuzhiyun 				  struct ncsi_cmd_arg *nca)
40*4882a593Smuzhiyun {
41*4882a593Smuzhiyun 	u32 checksum;
42*4882a593Smuzhiyun 	__be32 *pchecksum;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	h->mc_id        = 0;
45*4882a593Smuzhiyun 	h->revision     = NCSI_PKT_REVISION;
46*4882a593Smuzhiyun 	h->reserved     = 0;
47*4882a593Smuzhiyun 	h->id           = nca->id;
48*4882a593Smuzhiyun 	h->type         = nca->type;
49*4882a593Smuzhiyun 	h->channel      = NCSI_TO_CHANNEL(nca->package,
50*4882a593Smuzhiyun 					  nca->channel);
51*4882a593Smuzhiyun 	h->length       = htons(nca->payload);
52*4882a593Smuzhiyun 	h->reserved1[0] = 0;
53*4882a593Smuzhiyun 	h->reserved1[1] = 0;
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	/* Fill with calculated checksum */
56*4882a593Smuzhiyun 	checksum = ncsi_calculate_checksum((unsigned char *)h,
57*4882a593Smuzhiyun 					   sizeof(*h) + nca->payload);
58*4882a593Smuzhiyun 	pchecksum = (__be32 *)((void *)h + sizeof(struct ncsi_pkt_hdr) +
59*4882a593Smuzhiyun 		    ALIGN(nca->payload, 4));
60*4882a593Smuzhiyun 	*pchecksum = htonl(checksum);
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
ncsi_cmd_handler_default(struct sk_buff * skb,struct ncsi_cmd_arg * nca)63*4882a593Smuzhiyun static int ncsi_cmd_handler_default(struct sk_buff *skb,
64*4882a593Smuzhiyun 				    struct ncsi_cmd_arg *nca)
65*4882a593Smuzhiyun {
66*4882a593Smuzhiyun 	struct ncsi_cmd_pkt *cmd;
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
69*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun 	return 0;
72*4882a593Smuzhiyun }
73*4882a593Smuzhiyun 
ncsi_cmd_handler_sp(struct sk_buff * skb,struct ncsi_cmd_arg * nca)74*4882a593Smuzhiyun static int ncsi_cmd_handler_sp(struct sk_buff *skb,
75*4882a593Smuzhiyun 			       struct ncsi_cmd_arg *nca)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct ncsi_cmd_sp_pkt *cmd;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
80*4882a593Smuzhiyun 	cmd->hw_arbitration = nca->bytes[0];
81*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	return 0;
84*4882a593Smuzhiyun }
85*4882a593Smuzhiyun 
ncsi_cmd_handler_dc(struct sk_buff * skb,struct ncsi_cmd_arg * nca)86*4882a593Smuzhiyun static int ncsi_cmd_handler_dc(struct sk_buff *skb,
87*4882a593Smuzhiyun 			       struct ncsi_cmd_arg *nca)
88*4882a593Smuzhiyun {
89*4882a593Smuzhiyun 	struct ncsi_cmd_dc_pkt *cmd;
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
92*4882a593Smuzhiyun 	cmd->ald = nca->bytes[0];
93*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
ncsi_cmd_handler_rc(struct sk_buff * skb,struct ncsi_cmd_arg * nca)98*4882a593Smuzhiyun static int ncsi_cmd_handler_rc(struct sk_buff *skb,
99*4882a593Smuzhiyun 			       struct ncsi_cmd_arg *nca)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct ncsi_cmd_rc_pkt *cmd;
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
104*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun 	return 0;
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
ncsi_cmd_handler_ae(struct sk_buff * skb,struct ncsi_cmd_arg * nca)109*4882a593Smuzhiyun static int ncsi_cmd_handler_ae(struct sk_buff *skb,
110*4882a593Smuzhiyun 			       struct ncsi_cmd_arg *nca)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct ncsi_cmd_ae_pkt *cmd;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
115*4882a593Smuzhiyun 	cmd->mc_id = nca->bytes[0];
116*4882a593Smuzhiyun 	cmd->mode = htonl(nca->dwords[1]);
117*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	return 0;
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun 
ncsi_cmd_handler_sl(struct sk_buff * skb,struct ncsi_cmd_arg * nca)122*4882a593Smuzhiyun static int ncsi_cmd_handler_sl(struct sk_buff *skb,
123*4882a593Smuzhiyun 			       struct ncsi_cmd_arg *nca)
124*4882a593Smuzhiyun {
125*4882a593Smuzhiyun 	struct ncsi_cmd_sl_pkt *cmd;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
128*4882a593Smuzhiyun 	cmd->mode = htonl(nca->dwords[0]);
129*4882a593Smuzhiyun 	cmd->oem_mode = htonl(nca->dwords[1]);
130*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return 0;
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
ncsi_cmd_handler_svf(struct sk_buff * skb,struct ncsi_cmd_arg * nca)135*4882a593Smuzhiyun static int ncsi_cmd_handler_svf(struct sk_buff *skb,
136*4882a593Smuzhiyun 				struct ncsi_cmd_arg *nca)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct ncsi_cmd_svf_pkt *cmd;
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
141*4882a593Smuzhiyun 	cmd->vlan = htons(nca->words[1]);
142*4882a593Smuzhiyun 	cmd->index = nca->bytes[6];
143*4882a593Smuzhiyun 	cmd->enable = nca->bytes[7];
144*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun 	return 0;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun 
ncsi_cmd_handler_ev(struct sk_buff * skb,struct ncsi_cmd_arg * nca)149*4882a593Smuzhiyun static int ncsi_cmd_handler_ev(struct sk_buff *skb,
150*4882a593Smuzhiyun 			       struct ncsi_cmd_arg *nca)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	struct ncsi_cmd_ev_pkt *cmd;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
155*4882a593Smuzhiyun 	cmd->mode = nca->bytes[3];
156*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	return 0;
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
ncsi_cmd_handler_sma(struct sk_buff * skb,struct ncsi_cmd_arg * nca)161*4882a593Smuzhiyun static int ncsi_cmd_handler_sma(struct sk_buff *skb,
162*4882a593Smuzhiyun 				struct ncsi_cmd_arg *nca)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun 	struct ncsi_cmd_sma_pkt *cmd;
165*4882a593Smuzhiyun 	int i;
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
168*4882a593Smuzhiyun 	for (i = 0; i < 6; i++)
169*4882a593Smuzhiyun 		cmd->mac[i] = nca->bytes[i];
170*4882a593Smuzhiyun 	cmd->index = nca->bytes[6];
171*4882a593Smuzhiyun 	cmd->at_e = nca->bytes[7];
172*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	return 0;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
ncsi_cmd_handler_ebf(struct sk_buff * skb,struct ncsi_cmd_arg * nca)177*4882a593Smuzhiyun static int ncsi_cmd_handler_ebf(struct sk_buff *skb,
178*4882a593Smuzhiyun 				struct ncsi_cmd_arg *nca)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	struct ncsi_cmd_ebf_pkt *cmd;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
183*4882a593Smuzhiyun 	cmd->mode = htonl(nca->dwords[0]);
184*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	return 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
ncsi_cmd_handler_egmf(struct sk_buff * skb,struct ncsi_cmd_arg * nca)189*4882a593Smuzhiyun static int ncsi_cmd_handler_egmf(struct sk_buff *skb,
190*4882a593Smuzhiyun 				 struct ncsi_cmd_arg *nca)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	struct ncsi_cmd_egmf_pkt *cmd;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
195*4882a593Smuzhiyun 	cmd->mode = htonl(nca->dwords[0]);
196*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
ncsi_cmd_handler_snfc(struct sk_buff * skb,struct ncsi_cmd_arg * nca)201*4882a593Smuzhiyun static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
202*4882a593Smuzhiyun 				 struct ncsi_cmd_arg *nca)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct ncsi_cmd_snfc_pkt *cmd;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, sizeof(*cmd));
207*4882a593Smuzhiyun 	cmd->mode = nca->bytes[0];
208*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	return 0;
211*4882a593Smuzhiyun }
212*4882a593Smuzhiyun 
ncsi_cmd_handler_oem(struct sk_buff * skb,struct ncsi_cmd_arg * nca)213*4882a593Smuzhiyun static int ncsi_cmd_handler_oem(struct sk_buff *skb,
214*4882a593Smuzhiyun 				struct ncsi_cmd_arg *nca)
215*4882a593Smuzhiyun {
216*4882a593Smuzhiyun 	struct ncsi_cmd_oem_pkt *cmd;
217*4882a593Smuzhiyun 	unsigned int len;
218*4882a593Smuzhiyun 	int payload;
219*4882a593Smuzhiyun 	/* NC-SI spec DSP_0222_1.2.0, section 8.2.2.2
220*4882a593Smuzhiyun 	 * requires payload to be padded with 0 to
221*4882a593Smuzhiyun 	 * 32-bit boundary before the checksum field.
222*4882a593Smuzhiyun 	 * Ensure the padding bytes are accounted for in
223*4882a593Smuzhiyun 	 * skb allocation
224*4882a593Smuzhiyun 	 */
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	payload = ALIGN(nca->payload, 4);
227*4882a593Smuzhiyun 	len = sizeof(struct ncsi_cmd_pkt_hdr) + 4;
228*4882a593Smuzhiyun 	len += max(payload, padding_bytes);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	cmd = skb_put_zero(skb, len);
231*4882a593Smuzhiyun 	memcpy(&cmd->mfr_id, nca->data, nca->payload);
232*4882a593Smuzhiyun 	ncsi_cmd_build_header(&cmd->cmd.common, nca);
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	return 0;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun static struct ncsi_cmd_handler {
238*4882a593Smuzhiyun 	unsigned char type;
239*4882a593Smuzhiyun 	int           payload;
240*4882a593Smuzhiyun 	int           (*handler)(struct sk_buff *skb,
241*4882a593Smuzhiyun 				 struct ncsi_cmd_arg *nca);
242*4882a593Smuzhiyun } ncsi_cmd_handlers[] = {
243*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_CIS,    0, ncsi_cmd_handler_default },
244*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_SP,     4, ncsi_cmd_handler_sp      },
245*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_DP,     0, ncsi_cmd_handler_default },
246*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_EC,     0, ncsi_cmd_handler_default },
247*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_DC,     4, ncsi_cmd_handler_dc      },
248*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_RC,     4, ncsi_cmd_handler_rc      },
249*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_ECNT,   0, ncsi_cmd_handler_default },
250*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_DCNT,   0, ncsi_cmd_handler_default },
251*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_AE,     8, ncsi_cmd_handler_ae      },
252*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_SL,     8, ncsi_cmd_handler_sl      },
253*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GLS,    0, ncsi_cmd_handler_default },
254*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_SVF,    8, ncsi_cmd_handler_svf     },
255*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_EV,     4, ncsi_cmd_handler_ev      },
256*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_DV,     0, ncsi_cmd_handler_default },
257*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_SMA,    8, ncsi_cmd_handler_sma     },
258*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_EBF,    4, ncsi_cmd_handler_ebf     },
259*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_DBF,    0, ncsi_cmd_handler_default },
260*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_EGMF,   4, ncsi_cmd_handler_egmf    },
261*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_DGMF,   0, ncsi_cmd_handler_default },
262*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_SNFC,   4, ncsi_cmd_handler_snfc    },
263*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GVI,    0, ncsi_cmd_handler_default },
264*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GC,     0, ncsi_cmd_handler_default },
265*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GP,     0, ncsi_cmd_handler_default },
266*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GCPS,   0, ncsi_cmd_handler_default },
267*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GNS,    0, ncsi_cmd_handler_default },
268*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GNPTS,  0, ncsi_cmd_handler_default },
269*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GPS,    0, ncsi_cmd_handler_default },
270*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_OEM,   -1, ncsi_cmd_handler_oem     },
271*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_PLDM,   0, NULL                     },
272*4882a593Smuzhiyun 	{ NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
273*4882a593Smuzhiyun };
274*4882a593Smuzhiyun 
ncsi_alloc_command(struct ncsi_cmd_arg * nca)275*4882a593Smuzhiyun static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	struct ncsi_dev_priv *ndp = nca->ndp;
278*4882a593Smuzhiyun 	struct ncsi_dev *nd = &ndp->ndev;
279*4882a593Smuzhiyun 	struct net_device *dev = nd->dev;
280*4882a593Smuzhiyun 	int hlen = LL_RESERVED_SPACE(dev);
281*4882a593Smuzhiyun 	int tlen = dev->needed_tailroom;
282*4882a593Smuzhiyun 	int payload;
283*4882a593Smuzhiyun 	int len = hlen + tlen;
284*4882a593Smuzhiyun 	struct sk_buff *skb;
285*4882a593Smuzhiyun 	struct ncsi_request *nr;
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	nr = ncsi_alloc_request(ndp, nca->req_flags);
288*4882a593Smuzhiyun 	if (!nr)
289*4882a593Smuzhiyun 		return NULL;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	/* NCSI command packet has 16-bytes header, payload, 4 bytes checksum.
292*4882a593Smuzhiyun 	 * Payload needs padding so that the checksum field following payload is
293*4882a593Smuzhiyun 	 * aligned to 32-bit boundary.
294*4882a593Smuzhiyun 	 * The packet needs padding if its payload is less than 26 bytes to
295*4882a593Smuzhiyun 	 * meet 64 bytes minimal ethernet frame length.
296*4882a593Smuzhiyun 	 */
297*4882a593Smuzhiyun 	len += sizeof(struct ncsi_cmd_pkt_hdr) + 4;
298*4882a593Smuzhiyun 	payload = ALIGN(nca->payload, 4);
299*4882a593Smuzhiyun 	len += max(payload, padding_bytes);
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	/* Allocate skb */
302*4882a593Smuzhiyun 	skb = alloc_skb(len, GFP_ATOMIC);
303*4882a593Smuzhiyun 	if (!skb) {
304*4882a593Smuzhiyun 		ncsi_free_request(nr);
305*4882a593Smuzhiyun 		return NULL;
306*4882a593Smuzhiyun 	}
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	nr->cmd = skb;
309*4882a593Smuzhiyun 	skb_reserve(skb, hlen);
310*4882a593Smuzhiyun 	skb_reset_network_header(skb);
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	skb->dev = dev;
313*4882a593Smuzhiyun 	skb->protocol = htons(ETH_P_NCSI);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	return nr;
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun 
ncsi_xmit_cmd(struct ncsi_cmd_arg * nca)318*4882a593Smuzhiyun int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
319*4882a593Smuzhiyun {
320*4882a593Smuzhiyun 	struct ncsi_cmd_handler *nch = NULL;
321*4882a593Smuzhiyun 	struct ncsi_request *nr;
322*4882a593Smuzhiyun 	unsigned char type;
323*4882a593Smuzhiyun 	struct ethhdr *eh;
324*4882a593Smuzhiyun 	int i, ret;
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	/* Use OEM generic handler for Netlink request */
327*4882a593Smuzhiyun 	if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN)
328*4882a593Smuzhiyun 		type = NCSI_PKT_CMD_OEM;
329*4882a593Smuzhiyun 	else
330*4882a593Smuzhiyun 		type = nca->type;
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	/* Search for the handler */
333*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
334*4882a593Smuzhiyun 		if (ncsi_cmd_handlers[i].type == type) {
335*4882a593Smuzhiyun 			if (ncsi_cmd_handlers[i].handler)
336*4882a593Smuzhiyun 				nch = &ncsi_cmd_handlers[i];
337*4882a593Smuzhiyun 			else
338*4882a593Smuzhiyun 				nch = NULL;
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 			break;
341*4882a593Smuzhiyun 		}
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	if (!nch) {
345*4882a593Smuzhiyun 		netdev_err(nca->ndp->ndev.dev,
346*4882a593Smuzhiyun 			   "Cannot send packet with type 0x%02x\n", nca->type);
347*4882a593Smuzhiyun 		return -ENOENT;
348*4882a593Smuzhiyun 	}
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	/* Get packet payload length and allocate the request
351*4882a593Smuzhiyun 	 * It is expected that if length set as negative in
352*4882a593Smuzhiyun 	 * handler structure means caller is initializing it
353*4882a593Smuzhiyun 	 * and setting length in nca before calling xmit function
354*4882a593Smuzhiyun 	 */
355*4882a593Smuzhiyun 	if (nch->payload >= 0)
356*4882a593Smuzhiyun 		nca->payload = nch->payload;
357*4882a593Smuzhiyun 	nr = ncsi_alloc_command(nca);
358*4882a593Smuzhiyun 	if (!nr)
359*4882a593Smuzhiyun 		return -ENOMEM;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	/* track netlink information */
362*4882a593Smuzhiyun 	if (nca->req_flags == NCSI_REQ_FLAG_NETLINK_DRIVEN) {
363*4882a593Smuzhiyun 		nr->snd_seq = nca->info->snd_seq;
364*4882a593Smuzhiyun 		nr->snd_portid = nca->info->snd_portid;
365*4882a593Smuzhiyun 		nr->nlhdr = *nca->info->nlhdr;
366*4882a593Smuzhiyun 	}
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/* Prepare the packet */
369*4882a593Smuzhiyun 	nca->id = nr->id;
370*4882a593Smuzhiyun 	ret = nch->handler(nr->cmd, nca);
371*4882a593Smuzhiyun 	if (ret) {
372*4882a593Smuzhiyun 		ncsi_free_request(nr);
373*4882a593Smuzhiyun 		return ret;
374*4882a593Smuzhiyun 	}
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	/* Fill the ethernet header */
377*4882a593Smuzhiyun 	eh = skb_push(nr->cmd, sizeof(*eh));
378*4882a593Smuzhiyun 	eh->h_proto = htons(ETH_P_NCSI);
379*4882a593Smuzhiyun 	eth_broadcast_addr(eh->h_dest);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	/* If mac address received from device then use it for
382*4882a593Smuzhiyun 	 * source address as unicast address else use broadcast
383*4882a593Smuzhiyun 	 * address as source address
384*4882a593Smuzhiyun 	 */
385*4882a593Smuzhiyun 	if (nca->ndp->gma_flag == 1)
386*4882a593Smuzhiyun 		memcpy(eh->h_source, nca->ndp->ndev.dev->dev_addr, ETH_ALEN);
387*4882a593Smuzhiyun 	else
388*4882a593Smuzhiyun 		eth_broadcast_addr(eh->h_source);
389*4882a593Smuzhiyun 
390*4882a593Smuzhiyun 	/* Start the timer for the request that might not have
391*4882a593Smuzhiyun 	 * corresponding response. Given NCSI is an internal
392*4882a593Smuzhiyun 	 * connection a 1 second delay should be sufficient.
393*4882a593Smuzhiyun 	 */
394*4882a593Smuzhiyun 	nr->enabled = true;
395*4882a593Smuzhiyun 	mod_timer(&nr->timer, jiffies + 1 * HZ);
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	/* Send NCSI packet */
398*4882a593Smuzhiyun 	skb_get(nr->cmd);
399*4882a593Smuzhiyun 	ret = dev_queue_xmit(nr->cmd);
400*4882a593Smuzhiyun 	if (ret < 0) {
401*4882a593Smuzhiyun 		ncsi_free_request(nr);
402*4882a593Smuzhiyun 		return ret;
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	return 0;
406*4882a593Smuzhiyun }
407