ncsi-cmd.c 10 KB

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