You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

efi_snp.c 27KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978
  1. /*
  2. * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <errno.h>
  21. #include <assert.h>
  22. #include <byteswap.h>
  23. #include <gpxe/netdevice.h>
  24. #include <gpxe/iobuf.h>
  25. #include <gpxe/in.h>
  26. #include <gpxe/pci.h>
  27. #include <gpxe/efi/efi.h>
  28. #include <gpxe/efi/Protocol/DriverBinding.h>
  29. #include <gpxe/efi/Protocol/PciIo.h>
  30. #include <gpxe/efi/Protocol/SimpleNetwork.h>
  31. /** @file
  32. *
  33. * gPXE EFI SNP interface
  34. *
  35. */
  36. /** An SNP device */
  37. struct efi_snp_device {
  38. /** The underlying gPXE network device */
  39. struct net_device *netdev;
  40. /** The SNP structure itself */
  41. EFI_SIMPLE_NETWORK_PROTOCOL snp;
  42. /** The SNP "mode" (parameters) */
  43. EFI_SIMPLE_NETWORK_MODE mode;
  44. /** Outstanding TX packet count (via "interrupt status")
  45. *
  46. * Used in order to generate TX completions.
  47. */
  48. unsigned int tx_count_interrupts;
  49. /** Outstanding TX packet count (via "recycled tx buffers")
  50. *
  51. * Used in order to generate TX completions.
  52. */
  53. unsigned int tx_count_txbufs;
  54. /** Outstanding RX packet count (via "interrupt status") */
  55. unsigned int rx_count_interrupts;
  56. /** Outstanding RX packet count (via WaitForPacket event) */
  57. unsigned int rx_count_events;
  58. };
  59. /** EFI simple network protocol GUID */
  60. static EFI_GUID efi_simple_network_protocol_guid
  61. = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
  62. /** EFI driver binding protocol GUID */
  63. static EFI_GUID efi_driver_binding_protocol_guid
  64. = EFI_DRIVER_BINDING_PROTOCOL_GUID;
  65. /** EFI PCI I/O protocol GUID */
  66. static EFI_GUID efi_pci_io_protocol_guid
  67. = EFI_PCI_IO_PROTOCOL_GUID;
  68. /**
  69. * Set EFI SNP mode based on gPXE net device parameters
  70. *
  71. * @v snp SNP interface
  72. */
  73. static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
  74. struct net_device *netdev = snpdev->netdev;
  75. EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
  76. unsigned int ll_addr_len = netdev->ll_protocol->ll_addr_len;
  77. mode->HwAddressSize = ll_addr_len;
  78. mode->MediaHeaderSize = netdev->ll_protocol->ll_header_len;
  79. mode->MaxPacketSize = netdev->max_pkt_len;
  80. mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
  81. EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
  82. EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
  83. assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
  84. memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
  85. memcpy ( &mode->BroadcastAddress, netdev->ll_protocol->ll_broadcast,
  86. ll_addr_len );
  87. memcpy ( &mode->PermanentAddress, netdev->ll_addr, ll_addr_len );
  88. mode->IfType = ntohs ( netdev->ll_protocol->ll_proto );
  89. mode->MacAddressChangeable = TRUE;
  90. mode->MediaPresentSupported = TRUE;
  91. mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
  92. }
  93. /**
  94. * Poll net device and count received packets
  95. *
  96. * @v snpdev SNP device
  97. */
  98. static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
  99. struct io_buffer *iobuf;
  100. unsigned int before = 0;
  101. unsigned int after = 0;
  102. unsigned int arrived;
  103. /* We have to report packet arrivals, and this is the easiest
  104. * way to fake it.
  105. */
  106. list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
  107. before++;
  108. netdev_poll ( snpdev->netdev );
  109. list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
  110. after++;
  111. arrived = ( after - before );
  112. snpdev->rx_count_interrupts += arrived;
  113. snpdev->rx_count_events += arrived;
  114. }
  115. /**
  116. * Change SNP state from "stopped" to "started"
  117. *
  118. * @v snp SNP interface
  119. * @ret efirc EFI status code
  120. */
  121. static EFI_STATUS EFIAPI
  122. efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  123. struct efi_snp_device *snpdev =
  124. container_of ( snp, struct efi_snp_device, snp );
  125. DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
  126. snpdev->mode.State = EfiSimpleNetworkStarted;
  127. return 0;
  128. }
  129. /**
  130. * Change SNP state from "started" to "stopped"
  131. *
  132. * @v snp SNP interface
  133. * @ret efirc EFI status code
  134. */
  135. static EFI_STATUS EFIAPI
  136. efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  137. struct efi_snp_device *snpdev =
  138. container_of ( snp, struct efi_snp_device, snp );
  139. DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
  140. snpdev->mode.State = EfiSimpleNetworkStopped;
  141. return 0;
  142. }
  143. /**
  144. * Open the network device
  145. *
  146. * @v snp SNP interface
  147. * @v extra_rx_bufsize Extra RX buffer size, in bytes
  148. * @v extra_tx_bufsize Extra TX buffer size, in bytes
  149. * @ret efirc EFI status code
  150. */
  151. static EFI_STATUS EFIAPI
  152. efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  153. UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
  154. struct efi_snp_device *snpdev =
  155. container_of ( snp, struct efi_snp_device, snp );
  156. int rc;
  157. DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
  158. snpdev, extra_rx_bufsize, extra_tx_bufsize );
  159. if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
  160. DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
  161. snpdev, snpdev->netdev->name, strerror ( rc ) );
  162. return RC_TO_EFIRC ( rc );
  163. }
  164. snpdev->mode.State = EfiSimpleNetworkInitialized;
  165. return 0;
  166. }
  167. /**
  168. * Reset the network device
  169. *
  170. * @v snp SNP interface
  171. * @v ext_verify Extended verification required
  172. * @ret efirc EFI status code
  173. */
  174. static EFI_STATUS EFIAPI
  175. efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
  176. struct efi_snp_device *snpdev =
  177. container_of ( snp, struct efi_snp_device, snp );
  178. int rc;
  179. DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
  180. snpdev, ( ext_verify ? "with" : "without" ) );
  181. netdev_close ( snpdev->netdev );
  182. snpdev->mode.State = EfiSimpleNetworkStarted;
  183. if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
  184. DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
  185. snpdev, snpdev->netdev->name, strerror ( rc ) );
  186. return RC_TO_EFIRC ( rc );
  187. }
  188. snpdev->mode.State = EfiSimpleNetworkInitialized;
  189. return 0;
  190. }
  191. /**
  192. * Shut down the network device
  193. *
  194. * @v snp SNP interface
  195. * @ret efirc EFI status code
  196. */
  197. static EFI_STATUS EFIAPI
  198. efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  199. struct efi_snp_device *snpdev =
  200. container_of ( snp, struct efi_snp_device, snp );
  201. DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
  202. netdev_close ( snpdev->netdev );
  203. snpdev->mode.State = EfiSimpleNetworkStarted;
  204. return 0;
  205. }
  206. /**
  207. * Manage receive filters
  208. *
  209. * @v snp SNP interface
  210. * @v enable Receive filters to enable
  211. * @v disable Receive filters to disable
  212. * @v mcast_reset Reset multicast filters
  213. * @v mcast_count Number of multicast filters
  214. * @v mcast Multicast filters
  215. * @ret efirc EFI status code
  216. */
  217. static EFI_STATUS EFIAPI
  218. efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
  219. UINT32 disable, BOOLEAN mcast_reset,
  220. UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
  221. struct efi_snp_device *snpdev =
  222. container_of ( snp, struct efi_snp_device, snp );
  223. unsigned int i;
  224. DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08lx&~%08lx%s %ld mcast\n",
  225. snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
  226. mcast_count );
  227. for ( i = 0 ; i < mcast_count ; i++ ) {
  228. DBGC2_HDA ( snpdev, i, &mcast[i],
  229. snpdev->netdev->ll_protocol->ll_addr_len );
  230. }
  231. /* Lie through our teeth, otherwise MNP refuses to accept us */
  232. return 0;
  233. }
  234. /**
  235. * Set station address
  236. *
  237. * @v snp SNP interface
  238. * @v reset Reset to permanent address
  239. * @v new New station address
  240. * @ret efirc EFI status code
  241. */
  242. static EFI_STATUS EFIAPI
  243. efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
  244. EFI_MAC_ADDRESS *new ) {
  245. struct efi_snp_device *snpdev =
  246. container_of ( snp, struct efi_snp_device, snp );
  247. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  248. DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
  249. ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
  250. /* Set the MAC address */
  251. if ( reset )
  252. new = &snpdev->mode.PermanentAddress;
  253. memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
  254. /* MAC address changes take effect only on netdev_open() */
  255. if ( snpdev->netdev->state & NETDEV_OPEN ) {
  256. DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
  257. "devive open\n", snpdev );
  258. }
  259. return 0;
  260. }
  261. /**
  262. * Get (or reset) statistics
  263. *
  264. * @v snp SNP interface
  265. * @v reset Reset statistics
  266. * @v stats_len Size of statistics table
  267. * @v stats Statistics table
  268. * @ret efirc EFI status code
  269. */
  270. static EFI_STATUS EFIAPI
  271. efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
  272. UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
  273. struct efi_snp_device *snpdev =
  274. container_of ( snp, struct efi_snp_device, snp );
  275. EFI_NETWORK_STATISTICS stats_buf;
  276. DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
  277. ( reset ? " reset" : "" ) );
  278. /* Gather statistics */
  279. memset ( &stats_buf, 0, sizeof ( stats_buf ) );
  280. stats_buf.TxGoodFrames = snpdev->netdev->stats.tx_ok;
  281. stats_buf.TxDroppedFrames = snpdev->netdev->stats.tx_err;
  282. stats_buf.TxTotalFrames = ( snpdev->netdev->stats.tx_ok +
  283. snpdev->netdev->stats.tx_err );
  284. stats_buf.RxGoodFrames = snpdev->netdev->stats.rx_ok;
  285. stats_buf.RxDroppedFrames = snpdev->netdev->stats.rx_err;
  286. stats_buf.RxTotalFrames = ( snpdev->netdev->stats.rx_ok +
  287. snpdev->netdev->stats.rx_err );
  288. if ( *stats_len > sizeof ( stats_buf ) )
  289. *stats_len = sizeof ( stats_buf );
  290. if ( stats )
  291. memcpy ( stats, &stats_buf, *stats_len );
  292. /* Reset statistics if requested to do so */
  293. if ( reset ) {
  294. memset ( &snpdev->netdev->stats, 0,
  295. sizeof ( snpdev->netdev->stats ) );
  296. }
  297. return 0;
  298. }
  299. /**
  300. * Convert multicast IP address to MAC address
  301. *
  302. * @v snp SNP interface
  303. * @v ipv6 Address is IPv6
  304. * @v ip IP address
  305. * @v mac MAC address
  306. * @ret efirc EFI status code
  307. */
  308. static EFI_STATUS EFIAPI
  309. efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
  310. EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
  311. struct efi_snp_device *snpdev =
  312. container_of ( snp, struct efi_snp_device, snp );
  313. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  314. const char *ip_str;
  315. int rc;
  316. ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
  317. inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
  318. DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
  319. /* Try to hash the address */
  320. if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
  321. ip, mac ) ) != 0 ) {
  322. DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
  323. snpdev, ip_str, strerror ( rc ) );
  324. return RC_TO_EFIRC ( rc );
  325. }
  326. return 0;
  327. }
  328. /**
  329. * Read or write non-volatile storage
  330. *
  331. * @v snp SNP interface
  332. * @v read Operation is a read
  333. * @v offset Starting offset within NVRAM
  334. * @v len Length of data buffer
  335. * @v data Data buffer
  336. * @ret efirc EFI status code
  337. */
  338. static EFI_STATUS EFIAPI
  339. efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
  340. UINTN offset, UINTN len, VOID *data ) {
  341. struct efi_snp_device *snpdev =
  342. container_of ( snp, struct efi_snp_device, snp );
  343. DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
  344. ( read ? "read" : "write" ), offset, len );
  345. if ( ! read )
  346. DBGC2_HDA ( snpdev, offset, data, len );
  347. return EFI_UNSUPPORTED;
  348. }
  349. /**
  350. * Read interrupt status and TX recycled buffer status
  351. *
  352. * @v snp SNP interface
  353. * @v interrupts Interrupt status, or NULL
  354. * @v txbufs Recycled transmit buffer address, or NULL
  355. * @ret efirc EFI status code
  356. */
  357. static EFI_STATUS EFIAPI
  358. efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  359. UINT32 *interrupts, VOID **txbufs ) {
  360. struct efi_snp_device *snpdev =
  361. container_of ( snp, struct efi_snp_device, snp );
  362. DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
  363. /* Poll the network device */
  364. efi_snp_poll ( snpdev );
  365. /* Interrupt status. In practice, this seems to be used only
  366. * to detect TX completions.
  367. */
  368. if ( interrupts ) {
  369. *interrupts = 0;
  370. /* Report TX completions once queue is empty; this
  371. * avoids having to add hooks in the net device layer.
  372. */
  373. if ( snpdev->tx_count_interrupts &&
  374. list_empty ( &snpdev->netdev->tx_queue ) ) {
  375. *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
  376. snpdev->tx_count_interrupts--;
  377. }
  378. /* Report RX */
  379. if ( snpdev->rx_count_interrupts ) {
  380. *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
  381. snpdev->rx_count_interrupts--;
  382. }
  383. DBGC2 ( snpdev, " INTS:%02lx", *interrupts );
  384. }
  385. /* TX completions. It would be possible to design a more
  386. * idiotic scheme for this, but it would be a challenge.
  387. * According to the UEFI header file, txbufs will be filled in
  388. * with a list of "recycled transmit buffers" (i.e. completed
  389. * TX buffers). Observant readers may care to note that
  390. * *txbufs is a void pointer. Precisely how a list of
  391. * completed transmit buffers is meant to be represented as an
  392. * array of voids is left as an exercise for the reader.
  393. *
  394. * The only users of this interface (MnpDxe/MnpIo.c and
  395. * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
  396. * seeing a non-NULL result return in txbufs. This is valid
  397. * provided that they do not ever attempt to transmit more
  398. * than one packet concurrently (and that TX never times out).
  399. */
  400. if ( txbufs ) {
  401. if ( snpdev->tx_count_txbufs &&
  402. list_empty ( &snpdev->netdev->tx_queue ) ) {
  403. *txbufs = "Which idiot designed this API?";
  404. snpdev->tx_count_txbufs--;
  405. } else {
  406. *txbufs = NULL;
  407. }
  408. DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
  409. }
  410. DBGC2 ( snpdev, "\n" );
  411. return 0;
  412. }
  413. /**
  414. * Start packet transmission
  415. *
  416. * @v snp SNP interface
  417. * @v ll_header_len Link-layer header length, if to be filled in
  418. * @v len Length of data buffer
  419. * @v data Data buffer
  420. * @v ll_src Link-layer source address, if specified
  421. * @v ll_dest Link-layer destination address, if specified
  422. * @v net_proto Network-layer protocol (in host order)
  423. * @ret efirc EFI status code
  424. */
  425. static EFI_STATUS EFIAPI
  426. efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  427. UINTN ll_header_len, UINTN len, VOID *data,
  428. EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
  429. UINT16 *net_proto ) {
  430. struct efi_snp_device *snpdev =
  431. container_of ( snp, struct efi_snp_device, snp );
  432. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  433. struct io_buffer *iobuf;
  434. int rc;
  435. EFI_STATUS efirc;
  436. DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data, len );
  437. if ( ll_header_len ) {
  438. if ( ll_src ) {
  439. DBGC2 ( snpdev, " src %s",
  440. ll_protocol->ntoa ( ll_src ) );
  441. }
  442. if ( ll_dest ) {
  443. DBGC2 ( snpdev, " dest %s",
  444. ll_protocol->ntoa ( ll_dest ) );
  445. }
  446. if ( net_proto ) {
  447. DBGC2 ( snpdev, " proto %04x", *net_proto );
  448. }
  449. }
  450. DBGC2 ( snpdev, "\n" );
  451. /* Sanity checks */
  452. if ( ll_header_len ) {
  453. if ( ll_header_len != ll_protocol->ll_header_len ) {
  454. DBGC ( snpdev, "SNPDEV %p TX invalid header length "
  455. "%ld\n", snpdev, ll_header_len );
  456. efirc = EFI_INVALID_PARAMETER;
  457. goto err_sanity;
  458. }
  459. if ( len < ll_header_len ) {
  460. DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
  461. snpdev, len );
  462. efirc = EFI_BUFFER_TOO_SMALL;
  463. goto err_sanity;
  464. }
  465. if ( ! ll_dest ) {
  466. DBGC ( snpdev, "SNPDEV %p TX missing destination "
  467. "address\n", snpdev );
  468. efirc = EFI_INVALID_PARAMETER;
  469. goto err_sanity;
  470. }
  471. if ( ! net_proto ) {
  472. DBGC ( snpdev, "SNPDEV %p TX missing network "
  473. "protocol\n", snpdev );
  474. efirc = EFI_INVALID_PARAMETER;
  475. goto err_sanity;
  476. }
  477. if ( ! ll_src )
  478. ll_src = &snpdev->mode.CurrentAddress;
  479. }
  480. /* Allocate buffer */
  481. iobuf = alloc_iob ( len );
  482. if ( ! iobuf ) {
  483. DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
  484. "buffer\n", snpdev, len );
  485. efirc = EFI_DEVICE_ERROR;
  486. goto err_alloc_iob;
  487. }
  488. memcpy ( iob_put ( iobuf, len ), data, len );
  489. /* Create link-layer header, if specified */
  490. if ( ll_header_len ) {
  491. iob_pull ( iobuf, ll_header_len );
  492. if ( ( rc = ll_protocol->push ( iobuf, ll_dest, ll_src,
  493. htons ( *net_proto ) )) != 0 ){
  494. DBGC ( snpdev, "SNPDEV %p TX could not construct "
  495. "header: %s\n", snpdev, strerror ( rc ) );
  496. efirc = RC_TO_EFIRC ( rc );
  497. goto err_ll_push;
  498. }
  499. }
  500. /* Transmit packet */
  501. if ( ( rc = netdev_tx ( snpdev->netdev, iobuf ) ) != 0 ) {
  502. DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
  503. snpdev, strerror ( rc ) );
  504. iobuf = NULL;
  505. efirc = RC_TO_EFIRC ( rc );
  506. goto err_tx;
  507. }
  508. /* Record transmission as outstanding */
  509. snpdev->tx_count_interrupts++;
  510. snpdev->tx_count_txbufs++;
  511. return 0;
  512. err_tx:
  513. err_ll_push:
  514. free_iob ( iobuf );
  515. err_alloc_iob:
  516. err_sanity:
  517. return efirc;
  518. }
  519. /**
  520. * Receive packet
  521. *
  522. * @v snp SNP interface
  523. * @v ll_header_len Link-layer header length, if to be filled in
  524. * @v len Length of data buffer
  525. * @v data Data buffer
  526. * @v ll_src Link-layer source address, if specified
  527. * @v ll_dest Link-layer destination address, if specified
  528. * @v net_proto Network-layer protocol (in host order)
  529. * @ret efirc EFI status code
  530. */
  531. static EFI_STATUS EFIAPI
  532. efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  533. UINTN *ll_header_len, UINTN *len, VOID *data,
  534. EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
  535. UINT16 *net_proto ) {
  536. struct efi_snp_device *snpdev =
  537. container_of ( snp, struct efi_snp_device, snp );
  538. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  539. struct io_buffer *iobuf;
  540. const void *iob_ll_dest;
  541. const void *iob_ll_src;
  542. uint16_t iob_net_proto;
  543. int rc;
  544. EFI_STATUS efirc;
  545. DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data, *len );
  546. /* Poll the network device */
  547. efi_snp_poll ( snpdev );
  548. /* Dequeue a packet, if one is available */
  549. iobuf = netdev_rx_dequeue ( snpdev->netdev );
  550. if ( ! iobuf ) {
  551. DBGC2 ( snpdev, "\n" );
  552. efirc = EFI_NOT_READY;
  553. goto out_no_packet;
  554. }
  555. DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
  556. /* Return packet to caller */
  557. memcpy ( data, iobuf->data, iob_len ( iobuf ) );
  558. *len = iob_len ( iobuf );
  559. /* Attempt to decode link-layer header */
  560. if ( ( rc = ll_protocol->pull ( iobuf, &iob_ll_dest, &iob_ll_src,
  561. &iob_net_proto ) ) != 0 ) {
  562. DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
  563. snpdev, strerror ( rc ) );
  564. efirc = RC_TO_EFIRC ( rc );
  565. goto out_bad_ll_header;
  566. }
  567. /* Return link-layer header parameters to caller, if required */
  568. if ( ll_header_len )
  569. *ll_header_len = ll_protocol->ll_header_len;
  570. if ( ll_src )
  571. memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
  572. if ( ll_dest )
  573. memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
  574. if ( net_proto )
  575. *net_proto = ntohs ( iob_net_proto );
  576. efirc = 0;
  577. out_bad_ll_header:
  578. free_iob ( iobuf );
  579. out_no_packet:
  580. return efirc;
  581. }
  582. /**
  583. * Poll event
  584. *
  585. * @v event Event
  586. * @v context Event context
  587. */
  588. static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
  589. VOID *context ) {
  590. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  591. struct efi_snp_device *snpdev = context;
  592. DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
  593. /* Do nothing unless the net device is open */
  594. if ( ! ( snpdev->netdev->state & NETDEV_OPEN ) )
  595. return;
  596. /* Poll the network device */
  597. efi_snp_poll ( snpdev );
  598. /* Fire event if packets have been received */
  599. if ( snpdev->rx_count_events != 0 ) {
  600. DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
  601. snpdev );
  602. bs->SignalEvent ( event );
  603. snpdev->rx_count_events--;
  604. }
  605. }
  606. /** SNP interface */
  607. static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
  608. .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
  609. .Start = efi_snp_start,
  610. .Stop = efi_snp_stop,
  611. .Initialize = efi_snp_initialize,
  612. .Reset = efi_snp_reset,
  613. .Shutdown = efi_snp_shutdown,
  614. .ReceiveFilters = efi_snp_receive_filters,
  615. .StationAddress = efi_snp_station_address,
  616. .Statistics = efi_snp_statistics,
  617. .MCastIpToMac = efi_snp_mcast_ip_to_mac,
  618. .NvData = efi_snp_nvdata,
  619. .GetStatus = efi_snp_get_status,
  620. .Transmit = efi_snp_transmit,
  621. .Receive = efi_snp_receive,
  622. };
  623. /**
  624. * Locate net device corresponding to EFI device
  625. *
  626. * @v driver EFI driver
  627. * @v device EFI device
  628. * @ret netdev Net device, or NULL if not found
  629. */
  630. static struct net_device *
  631. efi_snp_netdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
  632. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  633. union {
  634. EFI_PCI_IO_PROTOCOL *pci;
  635. void *interface;
  636. } u;
  637. UINTN pci_segment, pci_bus, pci_dev, pci_fn;
  638. unsigned int pci_busdevfn;
  639. struct net_device *netdev = NULL;
  640. EFI_STATUS efirc;
  641. /* See if device is a PCI device */
  642. if ( ( efirc = bs->OpenProtocol ( device,
  643. &efi_pci_io_protocol_guid,
  644. &u.interface,
  645. driver->DriverBindingHandle,
  646. device,
  647. EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
  648. DBGCP ( driver, "SNPDRV %p device %p is not a PCI device\n",
  649. driver, device );
  650. goto out_no_pci_io;
  651. }
  652. /* Get PCI bus:dev.fn address */
  653. if ( ( efirc = u.pci->GetLocation ( u.pci, &pci_segment, &pci_bus,
  654. &pci_dev, &pci_fn ) ) != 0 ) {
  655. DBGC ( driver, "SNPDRV %p device %p could not get PCI "
  656. "location: %lx\n", driver, device, efirc );
  657. goto out_no_pci_location;
  658. }
  659. DBGCP ( driver, "SNPDRV %p device %p is PCI %04lx:%02lx:%02lx.%lx\n",
  660. driver, device, pci_segment, pci_bus, pci_dev, pci_fn );
  661. /* Look up corresponding network device */
  662. pci_busdevfn = PCI_BUSDEVFN ( pci_bus, PCI_DEVFN ( pci_dev, pci_fn ) );
  663. if ( ( netdev = find_netdev_by_location ( BUS_TYPE_PCI,
  664. pci_busdevfn ) ) == NULL ) {
  665. DBGCP ( driver, "SNPDRV %p device %p is not a gPXE network "
  666. "device\n", driver, device );
  667. goto out_no_netdev;
  668. }
  669. DBGC ( driver, "SNPDRV %p device %p is %s\n",
  670. driver, device, netdev->name );
  671. out_no_netdev:
  672. out_no_pci_location:
  673. bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
  674. driver->DriverBindingHandle, device );
  675. out_no_pci_io:
  676. return netdev;
  677. }
  678. /**
  679. * Locate SNP corresponding to EFI device
  680. *
  681. * @v driver EFI driver
  682. * @v device EFI device
  683. * @ret snp EFI SNP, or NULL if not found
  684. */
  685. static struct efi_snp_device *
  686. efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
  687. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  688. union {
  689. EFI_SIMPLE_NETWORK_PROTOCOL *snp;
  690. void *interface;
  691. } u;
  692. struct efi_snp_device *snpdev;
  693. EFI_STATUS efirc;
  694. if ( ( efirc = bs->OpenProtocol ( device,
  695. &efi_simple_network_protocol_guid,
  696. &u.interface,
  697. driver->DriverBindingHandle,
  698. device,
  699. EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
  700. DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
  701. "%lx\n", driver, device, efirc );
  702. return NULL;
  703. }
  704. snpdev = container_of ( u.snp, struct efi_snp_device, snp );
  705. DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
  706. driver, device, snpdev );
  707. return snpdev;
  708. }
  709. /**
  710. * Check to see if driver supports a device
  711. *
  712. * @v driver EFI driver
  713. * @v device EFI device
  714. * @v child Path to child device, if any
  715. * @ret efirc EFI status code
  716. */
  717. static EFI_STATUS EFIAPI
  718. efi_snp_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
  719. EFI_HANDLE device,
  720. EFI_DEVICE_PATH_PROTOCOL *child ) {
  721. struct net_device *netdev;
  722. DBGCP ( driver, "SNPDRV %p DRIVER_SUPPORTED %p (%p)\n",
  723. driver, device, child );
  724. netdev = efi_snp_netdev ( driver, device );
  725. return ( netdev ? 0 : EFI_UNSUPPORTED );
  726. }
  727. /**
  728. * Attach driver to device
  729. *
  730. * @v driver EFI driver
  731. * @v device EFI device
  732. * @v child Path to child device, if any
  733. * @ret efirc EFI status code
  734. */
  735. static EFI_STATUS EFIAPI
  736. efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
  737. EFI_HANDLE device,
  738. EFI_DEVICE_PATH_PROTOCOL *child ) {
  739. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  740. struct efi_snp_device *snpdev;
  741. struct net_device *netdev;
  742. EFI_STATUS efirc;
  743. DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
  744. driver, device, child );
  745. /* Allocate the SNP device */
  746. snpdev = zalloc ( sizeof ( *snpdev ) );
  747. if ( ! snpdev ) {
  748. efirc = EFI_OUT_OF_RESOURCES;
  749. goto err_alloc_snp;
  750. }
  751. /* Identify the net device */
  752. netdev = efi_snp_netdev ( driver, device );
  753. if ( ! netdev ) {
  754. DBGC ( snpdev, "SNPDEV %p cannot find netdev for device %p\n",
  755. snpdev, device );
  756. efirc = EFI_UNSUPPORTED;
  757. goto err_no_netdev;
  758. }
  759. snpdev->netdev = netdev_get ( netdev );
  760. /* Sanity check */
  761. if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
  762. DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
  763. "length %zd for %s\n", snpdev,
  764. netdev->ll_protocol->ll_addr_len, netdev->name );
  765. efirc = EFI_INVALID_PARAMETER;
  766. goto err_ll_addr_len;
  767. }
  768. /* Populate the SNP structure */
  769. memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
  770. snpdev->snp.Mode = &snpdev->mode;
  771. if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
  772. efi_snp_wait_for_packet, snpdev,
  773. &snpdev->snp.WaitForPacket ) ) != 0 ){
  774. DBGC ( snpdev, "SNPDEV %p could not create event: %lx\n",
  775. snpdev, efirc );
  776. goto err_create_event;
  777. }
  778. /* Populate the SNP mode structure */
  779. snpdev->mode.State = EfiSimpleNetworkStopped;
  780. efi_snp_set_mode ( snpdev );
  781. /* Install the SNP */
  782. if ( ( efirc = bs->InstallProtocolInterface ( &device,
  783. &efi_simple_network_protocol_guid,
  784. EFI_NATIVE_INTERFACE, &snpdev->snp ) ) != 0 ) {
  785. DBGC ( snpdev, "SNPDEV %p could not install protocol: %lx\n",
  786. snpdev, efirc );
  787. goto err_install_protocol_interface;
  788. }
  789. DBGC ( snpdev, "SNPDEV %p installed for %s on device %p\n",
  790. snpdev, netdev->name, device );
  791. return 0;
  792. bs->UninstallProtocolInterface ( device,
  793. &efi_simple_network_protocol_guid,
  794. &snpdev->snp );
  795. err_install_protocol_interface:
  796. bs->CloseEvent ( snpdev->snp.WaitForPacket );
  797. err_create_event:
  798. err_ll_addr_len:
  799. netdev_put ( netdev );
  800. err_no_netdev:
  801. free ( snpdev );
  802. err_alloc_snp:
  803. return efirc;
  804. }
  805. /**
  806. * Detach driver from device
  807. *
  808. * @v driver EFI driver
  809. * @v device EFI device
  810. * @v num_children Number of child devices
  811. * @v children List of child devices
  812. * @ret efirc EFI status code
  813. */
  814. static EFI_STATUS EFIAPI
  815. efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
  816. EFI_HANDLE device,
  817. UINTN num_children,
  818. EFI_HANDLE *children ) {
  819. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  820. struct efi_snp_device *snpdev;
  821. DBGCP ( driver, "SNPDRV %p DRIVER_STOP %p (%ld %p)\n",
  822. driver, device, num_children, children );
  823. /* Locate SNP device */
  824. snpdev = efi_snp_snpdev ( driver, device );
  825. if ( ! snpdev ) {
  826. DBGC ( driver, "SNPDRV %p device %p could not find SNPDEV\n",
  827. driver, device );
  828. return EFI_DEVICE_ERROR;
  829. }
  830. /* Uninstall the SNP */
  831. bs->UninstallProtocolInterface ( device,
  832. &efi_simple_network_protocol_guid,
  833. &snpdev->snp );
  834. bs->CloseEvent ( snpdev->snp.WaitForPacket );
  835. netdev_put ( snpdev->netdev );
  836. free ( snpdev );
  837. return 0;
  838. }
  839. /** EFI SNP driver binding */
  840. static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
  841. efi_snp_driver_supported,
  842. efi_snp_driver_start,
  843. efi_snp_driver_stop,
  844. 0x10,
  845. NULL,
  846. NULL
  847. };
  848. /**
  849. * Install EFI SNP driver
  850. *
  851. * @ret rc Return status code
  852. */
  853. int efi_snp_install ( void ) {
  854. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  855. EFI_DRIVER_BINDING_PROTOCOL *driver = &efi_snp_binding;
  856. EFI_STATUS efirc;
  857. driver->ImageHandle = efi_image_handle;
  858. if ( ( efirc = bs->InstallProtocolInterface (
  859. &driver->DriverBindingHandle,
  860. &efi_driver_binding_protocol_guid,
  861. EFI_NATIVE_INTERFACE,
  862. driver ) ) != 0 ) {
  863. DBGC ( driver, "SNPDRV %p could not install driver binding: "
  864. "%lx\n", driver, efirc );
  865. return EFIRC_TO_RC ( efirc );
  866. }
  867. DBGC ( driver, "SNPDRV %p driver binding installed as %p\n",
  868. driver, driver->DriverBindingHandle );
  869. return 0;
  870. }