ncsi-cmd.c 8.7 KB

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