ncsi-cmd.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  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 = (struct ncsi_cmd_pkt *)skb_put(skb, sizeof(*cmd));
  59. memset(cmd, 0, sizeof(*cmd));
  60. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  61. return 0;
  62. }
  63. static int ncsi_cmd_handler_sp(struct sk_buff *skb,
  64. struct ncsi_cmd_arg *nca)
  65. {
  66. struct ncsi_cmd_sp_pkt *cmd;
  67. cmd = (struct ncsi_cmd_sp_pkt *)skb_put(skb, sizeof(*cmd));
  68. memset(cmd, 0, sizeof(*cmd));
  69. cmd->hw_arbitration = nca->bytes[0];
  70. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  71. return 0;
  72. }
  73. static int ncsi_cmd_handler_dc(struct sk_buff *skb,
  74. struct ncsi_cmd_arg *nca)
  75. {
  76. struct ncsi_cmd_dc_pkt *cmd;
  77. cmd = (struct ncsi_cmd_dc_pkt *)skb_put(skb, sizeof(*cmd));
  78. memset(cmd, 0, sizeof(*cmd));
  79. cmd->ald = nca->bytes[0];
  80. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  81. return 0;
  82. }
  83. static int ncsi_cmd_handler_rc(struct sk_buff *skb,
  84. struct ncsi_cmd_arg *nca)
  85. {
  86. struct ncsi_cmd_rc_pkt *cmd;
  87. cmd = (struct ncsi_cmd_rc_pkt *)skb_put(skb, sizeof(*cmd));
  88. memset(cmd, 0, sizeof(*cmd));
  89. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  90. return 0;
  91. }
  92. static int ncsi_cmd_handler_ae(struct sk_buff *skb,
  93. struct ncsi_cmd_arg *nca)
  94. {
  95. struct ncsi_cmd_ae_pkt *cmd;
  96. cmd = (struct ncsi_cmd_ae_pkt *)skb_put(skb, sizeof(*cmd));
  97. memset(cmd, 0, sizeof(*cmd));
  98. cmd->mc_id = nca->bytes[0];
  99. cmd->mode = htonl(nca->dwords[1]);
  100. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  101. return 0;
  102. }
  103. static int ncsi_cmd_handler_sl(struct sk_buff *skb,
  104. struct ncsi_cmd_arg *nca)
  105. {
  106. struct ncsi_cmd_sl_pkt *cmd;
  107. cmd = (struct ncsi_cmd_sl_pkt *)skb_put(skb, sizeof(*cmd));
  108. memset(cmd, 0, sizeof(*cmd));
  109. cmd->mode = htonl(nca->dwords[0]);
  110. cmd->oem_mode = htonl(nca->dwords[1]);
  111. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  112. return 0;
  113. }
  114. static int ncsi_cmd_handler_svf(struct sk_buff *skb,
  115. struct ncsi_cmd_arg *nca)
  116. {
  117. struct ncsi_cmd_svf_pkt *cmd;
  118. cmd = (struct ncsi_cmd_svf_pkt *)skb_put(skb, sizeof(*cmd));
  119. memset(cmd, 0, sizeof(*cmd));
  120. cmd->vlan = htons(nca->words[0]);
  121. cmd->index = nca->bytes[2];
  122. cmd->enable = nca->bytes[3];
  123. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  124. return 0;
  125. }
  126. static int ncsi_cmd_handler_ev(struct sk_buff *skb,
  127. struct ncsi_cmd_arg *nca)
  128. {
  129. struct ncsi_cmd_ev_pkt *cmd;
  130. cmd = (struct ncsi_cmd_ev_pkt *)skb_put(skb, sizeof(*cmd));
  131. memset(cmd, 0, sizeof(*cmd));
  132. cmd->mode = nca->bytes[0];
  133. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  134. return 0;
  135. }
  136. static int ncsi_cmd_handler_sma(struct sk_buff *skb,
  137. struct ncsi_cmd_arg *nca)
  138. {
  139. struct ncsi_cmd_sma_pkt *cmd;
  140. int i;
  141. cmd = (struct ncsi_cmd_sma_pkt *)skb_put(skb, sizeof(*cmd));
  142. memset(cmd, 0, sizeof(*cmd));
  143. for (i = 0; i < 6; i++)
  144. cmd->mac[i] = nca->bytes[i];
  145. cmd->index = nca->bytes[6];
  146. cmd->at_e = nca->bytes[7];
  147. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  148. return 0;
  149. }
  150. static int ncsi_cmd_handler_ebf(struct sk_buff *skb,
  151. struct ncsi_cmd_arg *nca)
  152. {
  153. struct ncsi_cmd_ebf_pkt *cmd;
  154. cmd = (struct ncsi_cmd_ebf_pkt *)skb_put(skb, sizeof(*cmd));
  155. memset(cmd, 0, sizeof(*cmd));
  156. cmd->mode = htonl(nca->dwords[0]);
  157. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  158. return 0;
  159. }
  160. static int ncsi_cmd_handler_egmf(struct sk_buff *skb,
  161. struct ncsi_cmd_arg *nca)
  162. {
  163. struct ncsi_cmd_egmf_pkt *cmd;
  164. cmd = (struct ncsi_cmd_egmf_pkt *)skb_put(skb, sizeof(*cmd));
  165. memset(cmd, 0, sizeof(*cmd));
  166. cmd->mode = htonl(nca->dwords[0]);
  167. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  168. return 0;
  169. }
  170. static int ncsi_cmd_handler_snfc(struct sk_buff *skb,
  171. struct ncsi_cmd_arg *nca)
  172. {
  173. struct ncsi_cmd_snfc_pkt *cmd;
  174. cmd = (struct ncsi_cmd_snfc_pkt *)skb_put(skb, sizeof(*cmd));
  175. memset(cmd, 0, sizeof(*cmd));
  176. cmd->mode = nca->bytes[0];
  177. ncsi_cmd_build_header(&cmd->cmd.common, nca);
  178. return 0;
  179. }
  180. static struct ncsi_cmd_handler {
  181. unsigned char type;
  182. int payload;
  183. int (*handler)(struct sk_buff *skb,
  184. struct ncsi_cmd_arg *nca);
  185. } ncsi_cmd_handlers[] = {
  186. { NCSI_PKT_CMD_CIS, 0, ncsi_cmd_handler_default },
  187. { NCSI_PKT_CMD_SP, 4, ncsi_cmd_handler_sp },
  188. { NCSI_PKT_CMD_DP, 0, ncsi_cmd_handler_default },
  189. { NCSI_PKT_CMD_EC, 0, ncsi_cmd_handler_default },
  190. { NCSI_PKT_CMD_DC, 4, ncsi_cmd_handler_dc },
  191. { NCSI_PKT_CMD_RC, 4, ncsi_cmd_handler_rc },
  192. { NCSI_PKT_CMD_ECNT, 0, ncsi_cmd_handler_default },
  193. { NCSI_PKT_CMD_DCNT, 0, ncsi_cmd_handler_default },
  194. { NCSI_PKT_CMD_AE, 8, ncsi_cmd_handler_ae },
  195. { NCSI_PKT_CMD_SL, 8, ncsi_cmd_handler_sl },
  196. { NCSI_PKT_CMD_GLS, 0, ncsi_cmd_handler_default },
  197. { NCSI_PKT_CMD_SVF, 4, ncsi_cmd_handler_svf },
  198. { NCSI_PKT_CMD_EV, 4, ncsi_cmd_handler_ev },
  199. { NCSI_PKT_CMD_DV, 0, ncsi_cmd_handler_default },
  200. { NCSI_PKT_CMD_SMA, 8, ncsi_cmd_handler_sma },
  201. { NCSI_PKT_CMD_EBF, 4, ncsi_cmd_handler_ebf },
  202. { NCSI_PKT_CMD_DBF, 0, ncsi_cmd_handler_default },
  203. { NCSI_PKT_CMD_EGMF, 4, ncsi_cmd_handler_egmf },
  204. { NCSI_PKT_CMD_DGMF, 0, ncsi_cmd_handler_default },
  205. { NCSI_PKT_CMD_SNFC, 4, ncsi_cmd_handler_snfc },
  206. { NCSI_PKT_CMD_GVI, 0, ncsi_cmd_handler_default },
  207. { NCSI_PKT_CMD_GC, 0, ncsi_cmd_handler_default },
  208. { NCSI_PKT_CMD_GP, 0, ncsi_cmd_handler_default },
  209. { NCSI_PKT_CMD_GCPS, 0, ncsi_cmd_handler_default },
  210. { NCSI_PKT_CMD_GNS, 0, ncsi_cmd_handler_default },
  211. { NCSI_PKT_CMD_GNPTS, 0, ncsi_cmd_handler_default },
  212. { NCSI_PKT_CMD_GPS, 0, ncsi_cmd_handler_default },
  213. { NCSI_PKT_CMD_OEM, 0, NULL },
  214. { NCSI_PKT_CMD_PLDM, 0, NULL },
  215. { NCSI_PKT_CMD_GPUUID, 0, ncsi_cmd_handler_default }
  216. };
  217. static struct ncsi_request *ncsi_alloc_command(struct ncsi_cmd_arg *nca)
  218. {
  219. struct ncsi_dev_priv *ndp = nca->ndp;
  220. struct ncsi_dev *nd = &ndp->ndev;
  221. struct net_device *dev = nd->dev;
  222. int hlen = LL_RESERVED_SPACE(dev);
  223. int tlen = dev->needed_tailroom;
  224. int len = hlen + tlen;
  225. struct sk_buff *skb;
  226. struct ncsi_request *nr;
  227. nr = ncsi_alloc_request(ndp, nca->req_flags);
  228. if (!nr)
  229. return NULL;
  230. /* NCSI command packet has 16-bytes header, payload, 4 bytes checksum.
  231. * The packet needs padding if its payload is less than 26 bytes to
  232. * meet 64 bytes minimal ethernet frame length.
  233. */
  234. len += sizeof(struct ncsi_cmd_pkt_hdr) + 4;
  235. if (nca->payload < 26)
  236. len += 26;
  237. else
  238. len += nca->payload;
  239. /* Allocate skb */
  240. skb = alloc_skb(len, GFP_ATOMIC);
  241. if (!skb) {
  242. ncsi_free_request(nr);
  243. return NULL;
  244. }
  245. nr->cmd = skb;
  246. skb_reserve(skb, hlen);
  247. skb_reset_network_header(skb);
  248. skb->dev = dev;
  249. skb->protocol = htons(ETH_P_NCSI);
  250. return nr;
  251. }
  252. int ncsi_xmit_cmd(struct ncsi_cmd_arg *nca)
  253. {
  254. struct ncsi_request *nr;
  255. struct ethhdr *eh;
  256. struct ncsi_cmd_handler *nch = NULL;
  257. int i, ret;
  258. /* Search for the handler */
  259. for (i = 0; i < ARRAY_SIZE(ncsi_cmd_handlers); i++) {
  260. if (ncsi_cmd_handlers[i].type == nca->type) {
  261. if (ncsi_cmd_handlers[i].handler)
  262. nch = &ncsi_cmd_handlers[i];
  263. else
  264. nch = NULL;
  265. break;
  266. }
  267. }
  268. if (!nch) {
  269. netdev_err(nca->ndp->ndev.dev,
  270. "Cannot send packet with type 0x%02x\n", nca->type);
  271. return -ENOENT;
  272. }
  273. /* Get packet payload length and allocate the request */
  274. nca->payload = nch->payload;
  275. nr = ncsi_alloc_command(nca);
  276. if (!nr)
  277. return -ENOMEM;
  278. /* Prepare the packet */
  279. nca->id = nr->id;
  280. ret = nch->handler(nr->cmd, nca);
  281. if (ret) {
  282. ncsi_free_request(nr);
  283. return ret;
  284. }
  285. /* Fill the ethernet header */
  286. eh = (struct ethhdr *)skb_push(nr->cmd, sizeof(*eh));
  287. eh->h_proto = htons(ETH_P_NCSI);
  288. eth_broadcast_addr(eh->h_dest);
  289. eth_broadcast_addr(eh->h_source);
  290. /* Start the timer for the request that might not have
  291. * corresponding response. Given NCSI is an internal
  292. * connection a 1 second delay should be sufficient.
  293. */
  294. nr->enabled = true;
  295. mod_timer(&nr->timer, jiffies + 1 * HZ);
  296. /* Send NCSI packet */
  297. skb_get(nr->cmd);
  298. ret = dev_queue_xmit(nr->cmd);
  299. if (ret < 0) {
  300. ncsi_free_request(nr);
  301. return ret;
  302. }
  303. return 0;
  304. }