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 34KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  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., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <assert.h>
  24. #include <byteswap.h>
  25. #include <ipxe/netdevice.h>
  26. #include <ipxe/iobuf.h>
  27. #include <ipxe/in.h>
  28. #include <ipxe/version.h>
  29. #include <ipxe/efi/efi.h>
  30. #include <ipxe/efi/efi_driver.h>
  31. #include <ipxe/efi/efi_strings.h>
  32. #include <ipxe/efi/efi_snp.h>
  33. #include <usr/autoboot.h>
  34. /** EFI simple network protocol GUID */
  35. static EFI_GUID efi_simple_network_protocol_guid
  36. = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
  37. /** EFI device path protocol GUID */
  38. static EFI_GUID efi_device_path_protocol_guid
  39. = EFI_DEVICE_PATH_PROTOCOL_GUID;
  40. /** EFI network interface identifier GUID */
  41. static EFI_GUID efi_nii_protocol_guid
  42. = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
  43. /** EFI network interface identifier GUID (extra special version) */
  44. static EFI_GUID efi_nii31_protocol_guid = {
  45. /* At some point, it seems that someone decided to change the
  46. * GUID. Current EFI builds ignore the older GUID, older EFI
  47. * builds ignore the newer GUID, so we have to expose both.
  48. */
  49. 0x1ACED566, 0x76ED, 0x4218,
  50. { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 }
  51. };
  52. /** EFI component name protocol GUID */
  53. static EFI_GUID efi_component_name2_protocol_guid
  54. = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
  55. /** EFI load file protocol GUID */
  56. static EFI_GUID efi_load_file_protocol_guid
  57. = EFI_LOAD_FILE_PROTOCOL_GUID;
  58. /** List of SNP devices */
  59. static LIST_HEAD ( efi_snp_devices );
  60. /**
  61. * Set EFI SNP mode state
  62. *
  63. * @v snp SNP interface
  64. */
  65. static void efi_snp_set_state ( struct efi_snp_device *snpdev ) {
  66. struct net_device *netdev = snpdev->netdev;
  67. EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
  68. /* Calculate state */
  69. if ( ! snpdev->started ) {
  70. /* Start() method not called; report as Stopped */
  71. mode->State = EfiSimpleNetworkStopped;
  72. } else if ( ! netdev_is_open ( netdev ) ) {
  73. /* Network device not opened; report as Started */
  74. mode->State = EfiSimpleNetworkStarted;
  75. } else if ( ! netdev_rx_frozen ( netdev ) ) {
  76. /* Network device opened but claimed for use by iPXE; report
  77. * as Started to inhibit receive polling.
  78. */
  79. mode->State = EfiSimpleNetworkStarted;
  80. } else {
  81. /* Network device opened and available for use via SNP; report
  82. * as Initialized.
  83. */
  84. mode->State = EfiSimpleNetworkInitialized;
  85. }
  86. }
  87. /**
  88. * Set EFI SNP mode based on iPXE net device parameters
  89. *
  90. * @v snp SNP interface
  91. */
  92. static void efi_snp_set_mode ( struct efi_snp_device *snpdev ) {
  93. struct net_device *netdev = snpdev->netdev;
  94. EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
  95. struct ll_protocol *ll_protocol = netdev->ll_protocol;
  96. unsigned int ll_addr_len = ll_protocol->ll_addr_len;
  97. mode->HwAddressSize = ll_addr_len;
  98. mode->MediaHeaderSize = ll_protocol->ll_header_len;
  99. mode->MaxPacketSize = netdev->max_pkt_len;
  100. mode->ReceiveFilterMask = ( EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
  101. EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
  102. EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST );
  103. assert ( ll_addr_len <= sizeof ( mode->CurrentAddress ) );
  104. memcpy ( &mode->CurrentAddress, netdev->ll_addr, ll_addr_len );
  105. memcpy ( &mode->BroadcastAddress, netdev->ll_broadcast, ll_addr_len );
  106. ll_protocol->init_addr ( netdev->hw_addr, &mode->PermanentAddress );
  107. mode->IfType = ntohs ( ll_protocol->ll_proto );
  108. mode->MacAddressChangeable = TRUE;
  109. mode->MediaPresentSupported = TRUE;
  110. mode->MediaPresent = ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
  111. }
  112. /**
  113. * Poll net device and count received packets
  114. *
  115. * @v snpdev SNP device
  116. */
  117. static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
  118. struct io_buffer *iobuf;
  119. unsigned int before = 0;
  120. unsigned int after = 0;
  121. unsigned int arrived;
  122. /* We have to report packet arrivals, and this is the easiest
  123. * way to fake it.
  124. */
  125. list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
  126. before++;
  127. netdev_poll ( snpdev->netdev );
  128. list_for_each_entry ( iobuf, &snpdev->netdev->rx_queue, list )
  129. after++;
  130. arrived = ( after - before );
  131. snpdev->rx_count_interrupts += arrived;
  132. snpdev->rx_count_events += arrived;
  133. }
  134. /**
  135. * Change SNP state from "stopped" to "started"
  136. *
  137. * @v snp SNP interface
  138. * @ret efirc EFI status code
  139. */
  140. static EFI_STATUS EFIAPI
  141. efi_snp_start ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  142. struct efi_snp_device *snpdev =
  143. container_of ( snp, struct efi_snp_device, snp );
  144. DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
  145. /* Fail if net device is currently claimed for use by iPXE */
  146. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  147. return EFI_NOT_READY;
  148. snpdev->started = 1;
  149. efi_snp_set_state ( snpdev );
  150. return 0;
  151. }
  152. /**
  153. * Change SNP state from "started" to "stopped"
  154. *
  155. * @v snp SNP interface
  156. * @ret efirc EFI status code
  157. */
  158. static EFI_STATUS EFIAPI
  159. efi_snp_stop ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  160. struct efi_snp_device *snpdev =
  161. container_of ( snp, struct efi_snp_device, snp );
  162. DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
  163. /* Fail if net device is currently claimed for use by iPXE */
  164. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  165. return EFI_NOT_READY;
  166. snpdev->started = 0;
  167. efi_snp_set_state ( snpdev );
  168. return 0;
  169. }
  170. /**
  171. * Open the network device
  172. *
  173. * @v snp SNP interface
  174. * @v extra_rx_bufsize Extra RX buffer size, in bytes
  175. * @v extra_tx_bufsize Extra TX buffer size, in bytes
  176. * @ret efirc EFI status code
  177. */
  178. static EFI_STATUS EFIAPI
  179. efi_snp_initialize ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  180. UINTN extra_rx_bufsize, UINTN extra_tx_bufsize ) {
  181. struct efi_snp_device *snpdev =
  182. container_of ( snp, struct efi_snp_device, snp );
  183. int rc;
  184. DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
  185. snpdev, ( ( unsigned long ) extra_rx_bufsize ),
  186. ( ( unsigned long ) extra_tx_bufsize ) );
  187. /* Fail if net device is currently claimed for use by iPXE */
  188. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  189. return EFI_NOT_READY;
  190. if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
  191. DBGC ( snpdev, "SNPDEV %p could not open %s: %s\n",
  192. snpdev, snpdev->netdev->name, strerror ( rc ) );
  193. return EFIRC ( rc );
  194. }
  195. efi_snp_set_state ( snpdev );
  196. return 0;
  197. }
  198. /**
  199. * Reset the network device
  200. *
  201. * @v snp SNP interface
  202. * @v ext_verify Extended verification required
  203. * @ret efirc EFI status code
  204. */
  205. static EFI_STATUS EFIAPI
  206. efi_snp_reset ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ext_verify ) {
  207. struct efi_snp_device *snpdev =
  208. container_of ( snp, struct efi_snp_device, snp );
  209. int rc;
  210. DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
  211. snpdev, ( ext_verify ? "with" : "without" ) );
  212. /* Fail if net device is currently claimed for use by iPXE */
  213. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  214. return EFI_NOT_READY;
  215. netdev_close ( snpdev->netdev );
  216. efi_snp_set_state ( snpdev );
  217. if ( ( rc = netdev_open ( snpdev->netdev ) ) != 0 ) {
  218. DBGC ( snpdev, "SNPDEV %p could not reopen %s: %s\n",
  219. snpdev, snpdev->netdev->name, strerror ( rc ) );
  220. return EFIRC ( rc );
  221. }
  222. efi_snp_set_state ( snpdev );
  223. return 0;
  224. }
  225. /**
  226. * Shut down the network device
  227. *
  228. * @v snp SNP interface
  229. * @ret efirc EFI status code
  230. */
  231. static EFI_STATUS EFIAPI
  232. efi_snp_shutdown ( EFI_SIMPLE_NETWORK_PROTOCOL *snp ) {
  233. struct efi_snp_device *snpdev =
  234. container_of ( snp, struct efi_snp_device, snp );
  235. DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
  236. /* Fail if net device is currently claimed for use by iPXE */
  237. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  238. return EFI_NOT_READY;
  239. netdev_close ( snpdev->netdev );
  240. efi_snp_set_state ( snpdev );
  241. return 0;
  242. }
  243. /**
  244. * Manage receive filters
  245. *
  246. * @v snp SNP interface
  247. * @v enable Receive filters to enable
  248. * @v disable Receive filters to disable
  249. * @v mcast_reset Reset multicast filters
  250. * @v mcast_count Number of multicast filters
  251. * @v mcast Multicast filters
  252. * @ret efirc EFI status code
  253. */
  254. static EFI_STATUS EFIAPI
  255. efi_snp_receive_filters ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, UINT32 enable,
  256. UINT32 disable, BOOLEAN mcast_reset,
  257. UINTN mcast_count, EFI_MAC_ADDRESS *mcast ) {
  258. struct efi_snp_device *snpdev =
  259. container_of ( snp, struct efi_snp_device, snp );
  260. unsigned int i;
  261. DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
  262. snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
  263. ( ( unsigned long ) mcast_count ) );
  264. for ( i = 0 ; i < mcast_count ; i++ ) {
  265. DBGC2_HDA ( snpdev, i, &mcast[i],
  266. snpdev->netdev->ll_protocol->ll_addr_len );
  267. }
  268. /* Fail if net device is currently claimed for use by iPXE */
  269. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  270. return EFI_NOT_READY;
  271. /* Lie through our teeth, otherwise MNP refuses to accept us */
  272. return 0;
  273. }
  274. /**
  275. * Set station address
  276. *
  277. * @v snp SNP interface
  278. * @v reset Reset to permanent address
  279. * @v new New station address
  280. * @ret efirc EFI status code
  281. */
  282. static EFI_STATUS EFIAPI
  283. efi_snp_station_address ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
  284. EFI_MAC_ADDRESS *new ) {
  285. struct efi_snp_device *snpdev =
  286. container_of ( snp, struct efi_snp_device, snp );
  287. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  288. DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
  289. ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
  290. /* Fail if net device is currently claimed for use by iPXE */
  291. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  292. return EFI_NOT_READY;
  293. /* Set the MAC address */
  294. if ( reset )
  295. new = &snpdev->mode.PermanentAddress;
  296. memcpy ( snpdev->netdev->ll_addr, new, ll_protocol->ll_addr_len );
  297. /* MAC address changes take effect only on netdev_open() */
  298. if ( netdev_is_open ( snpdev->netdev ) ) {
  299. DBGC ( snpdev, "SNPDEV %p MAC address changed while net "
  300. "device open\n", snpdev );
  301. }
  302. return 0;
  303. }
  304. /**
  305. * Get (or reset) statistics
  306. *
  307. * @v snp SNP interface
  308. * @v reset Reset statistics
  309. * @v stats_len Size of statistics table
  310. * @v stats Statistics table
  311. * @ret efirc EFI status code
  312. */
  313. static EFI_STATUS EFIAPI
  314. efi_snp_statistics ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN reset,
  315. UINTN *stats_len, EFI_NETWORK_STATISTICS *stats ) {
  316. struct efi_snp_device *snpdev =
  317. container_of ( snp, struct efi_snp_device, snp );
  318. EFI_NETWORK_STATISTICS stats_buf;
  319. DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
  320. ( reset ? " reset" : "" ) );
  321. /* Fail if net device is currently claimed for use by iPXE */
  322. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  323. return EFI_NOT_READY;
  324. /* Gather statistics */
  325. memset ( &stats_buf, 0, sizeof ( stats_buf ) );
  326. stats_buf.TxGoodFrames = snpdev->netdev->tx_stats.good;
  327. stats_buf.TxDroppedFrames = snpdev->netdev->tx_stats.bad;
  328. stats_buf.TxTotalFrames = ( snpdev->netdev->tx_stats.good +
  329. snpdev->netdev->tx_stats.bad );
  330. stats_buf.RxGoodFrames = snpdev->netdev->rx_stats.good;
  331. stats_buf.RxDroppedFrames = snpdev->netdev->rx_stats.bad;
  332. stats_buf.RxTotalFrames = ( snpdev->netdev->rx_stats.good +
  333. snpdev->netdev->rx_stats.bad );
  334. if ( *stats_len > sizeof ( stats_buf ) )
  335. *stats_len = sizeof ( stats_buf );
  336. if ( stats )
  337. memcpy ( stats, &stats_buf, *stats_len );
  338. /* Reset statistics if requested to do so */
  339. if ( reset ) {
  340. memset ( &snpdev->netdev->tx_stats, 0,
  341. sizeof ( snpdev->netdev->tx_stats ) );
  342. memset ( &snpdev->netdev->rx_stats, 0,
  343. sizeof ( snpdev->netdev->rx_stats ) );
  344. }
  345. return 0;
  346. }
  347. /**
  348. * Convert multicast IP address to MAC address
  349. *
  350. * @v snp SNP interface
  351. * @v ipv6 Address is IPv6
  352. * @v ip IP address
  353. * @v mac MAC address
  354. * @ret efirc EFI status code
  355. */
  356. static EFI_STATUS EFIAPI
  357. efi_snp_mcast_ip_to_mac ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN ipv6,
  358. EFI_IP_ADDRESS *ip, EFI_MAC_ADDRESS *mac ) {
  359. struct efi_snp_device *snpdev =
  360. container_of ( snp, struct efi_snp_device, snp );
  361. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  362. const char *ip_str;
  363. int rc;
  364. ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
  365. inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
  366. DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
  367. /* Fail if net device is currently claimed for use by iPXE */
  368. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  369. return EFI_NOT_READY;
  370. /* Try to hash the address */
  371. if ( ( rc = ll_protocol->mc_hash ( ( ipv6 ? AF_INET6 : AF_INET ),
  372. ip, mac ) ) != 0 ) {
  373. DBGC ( snpdev, "SNPDEV %p could not hash %s: %s\n",
  374. snpdev, ip_str, strerror ( rc ) );
  375. return EFIRC ( rc );
  376. }
  377. return 0;
  378. }
  379. /**
  380. * Read or write non-volatile storage
  381. *
  382. * @v snp SNP interface
  383. * @v read Operation is a read
  384. * @v offset Starting offset within NVRAM
  385. * @v len Length of data buffer
  386. * @v data Data buffer
  387. * @ret efirc EFI status code
  388. */
  389. static EFI_STATUS EFIAPI
  390. efi_snp_nvdata ( EFI_SIMPLE_NETWORK_PROTOCOL *snp, BOOLEAN read,
  391. UINTN offset, UINTN len, VOID *data ) {
  392. struct efi_snp_device *snpdev =
  393. container_of ( snp, struct efi_snp_device, snp );
  394. DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
  395. ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
  396. ( ( unsigned long ) len ) );
  397. if ( ! read )
  398. DBGC2_HDA ( snpdev, offset, data, len );
  399. /* Fail if net device is currently claimed for use by iPXE */
  400. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  401. return EFI_NOT_READY;
  402. return EFI_UNSUPPORTED;
  403. }
  404. /**
  405. * Read interrupt status and TX recycled buffer status
  406. *
  407. * @v snp SNP interface
  408. * @v interrupts Interrupt status, or NULL
  409. * @v txbufs Recycled transmit buffer address, or NULL
  410. * @ret efirc EFI status code
  411. */
  412. static EFI_STATUS EFIAPI
  413. efi_snp_get_status ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  414. UINT32 *interrupts, VOID **txbufs ) {
  415. struct efi_snp_device *snpdev =
  416. container_of ( snp, struct efi_snp_device, snp );
  417. DBGC2 ( snpdev, "SNPDEV %p GET_STATUS", snpdev );
  418. /* Fail if net device is currently claimed for use by iPXE */
  419. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  420. return EFI_NOT_READY;
  421. /* Poll the network device */
  422. efi_snp_poll ( snpdev );
  423. /* Interrupt status. In practice, this seems to be used only
  424. * to detect TX completions.
  425. */
  426. if ( interrupts ) {
  427. *interrupts = 0;
  428. /* Report TX completions once queue is empty; this
  429. * avoids having to add hooks in the net device layer.
  430. */
  431. if ( snpdev->tx_count_interrupts &&
  432. list_empty ( &snpdev->netdev->tx_queue ) ) {
  433. *interrupts |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
  434. snpdev->tx_count_interrupts--;
  435. }
  436. /* Report RX */
  437. if ( snpdev->rx_count_interrupts ) {
  438. *interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
  439. snpdev->rx_count_interrupts--;
  440. }
  441. DBGC2 ( snpdev, " INTS:%02x", *interrupts );
  442. }
  443. /* TX completions. It would be possible to design a more
  444. * idiotic scheme for this, but it would be a challenge.
  445. * According to the UEFI header file, txbufs will be filled in
  446. * with a list of "recycled transmit buffers" (i.e. completed
  447. * TX buffers). Observant readers may care to note that
  448. * *txbufs is a void pointer. Precisely how a list of
  449. * completed transmit buffers is meant to be represented as an
  450. * array of voids is left as an exercise for the reader.
  451. *
  452. * The only users of this interface (MnpDxe/MnpIo.c and
  453. * PxeBcDxe/Bc.c within the EFI dev kit) both just poll until
  454. * seeing a non-NULL result return in txbufs. This is valid
  455. * provided that they do not ever attempt to transmit more
  456. * than one packet concurrently (and that TX never times out).
  457. */
  458. if ( txbufs ) {
  459. if ( snpdev->tx_count_txbufs &&
  460. list_empty ( &snpdev->netdev->tx_queue ) ) {
  461. *txbufs = "Which idiot designed this API?";
  462. snpdev->tx_count_txbufs--;
  463. } else {
  464. *txbufs = NULL;
  465. }
  466. DBGC2 ( snpdev, " TX:%s", ( *txbufs ? "some" : "none" ) );
  467. }
  468. DBGC2 ( snpdev, "\n" );
  469. return 0;
  470. }
  471. /**
  472. * Start packet transmission
  473. *
  474. * @v snp SNP interface
  475. * @v ll_header_len Link-layer header length, if to be filled in
  476. * @v len Length of data buffer
  477. * @v data Data buffer
  478. * @v ll_src Link-layer source address, if specified
  479. * @v ll_dest Link-layer destination address, if specified
  480. * @v net_proto Network-layer protocol (in host order)
  481. * @ret efirc EFI status code
  482. */
  483. static EFI_STATUS EFIAPI
  484. efi_snp_transmit ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  485. UINTN ll_header_len, UINTN len, VOID *data,
  486. EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
  487. UINT16 *net_proto ) {
  488. struct efi_snp_device *snpdev =
  489. container_of ( snp, struct efi_snp_device, snp );
  490. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  491. struct io_buffer *iobuf;
  492. size_t payload_len;
  493. int rc;
  494. DBGC2 ( snpdev, "SNPDEV %p TRANSMIT %p+%lx", snpdev, data,
  495. ( ( unsigned long ) len ) );
  496. if ( ll_header_len ) {
  497. if ( ll_src ) {
  498. DBGC2 ( snpdev, " src %s",
  499. ll_protocol->ntoa ( ll_src ) );
  500. }
  501. if ( ll_dest ) {
  502. DBGC2 ( snpdev, " dest %s",
  503. ll_protocol->ntoa ( ll_dest ) );
  504. }
  505. if ( net_proto ) {
  506. DBGC2 ( snpdev, " proto %04x", *net_proto );
  507. }
  508. }
  509. DBGC2 ( snpdev, "\n" );
  510. /* Fail if net device is currently claimed for use by iPXE */
  511. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  512. return EFI_NOT_READY;
  513. /* Sanity checks */
  514. if ( ll_header_len ) {
  515. if ( ll_header_len != ll_protocol->ll_header_len ) {
  516. DBGC ( snpdev, "SNPDEV %p TX invalid header length "
  517. "%ld\n", snpdev,
  518. ( ( unsigned long ) ll_header_len ) );
  519. rc = -EINVAL;
  520. goto err_sanity;
  521. }
  522. if ( len < ll_header_len ) {
  523. DBGC ( snpdev, "SNPDEV %p invalid packet length %ld\n",
  524. snpdev, ( ( unsigned long ) len ) );
  525. rc = -EINVAL;
  526. goto err_sanity;
  527. }
  528. if ( ! ll_dest ) {
  529. DBGC ( snpdev, "SNPDEV %p TX missing destination "
  530. "address\n", snpdev );
  531. rc = -EINVAL;
  532. goto err_sanity;
  533. }
  534. if ( ! net_proto ) {
  535. DBGC ( snpdev, "SNPDEV %p TX missing network "
  536. "protocol\n", snpdev );
  537. rc = -EINVAL;
  538. goto err_sanity;
  539. }
  540. if ( ! ll_src )
  541. ll_src = &snpdev->mode.CurrentAddress;
  542. }
  543. /* Allocate buffer */
  544. payload_len = ( len - ll_protocol->ll_header_len );
  545. iobuf = alloc_iob ( MAX_LL_HEADER_LEN + ( ( payload_len > IOB_ZLEN ) ?
  546. payload_len : IOB_ZLEN ) );
  547. if ( ! iobuf ) {
  548. DBGC ( snpdev, "SNPDEV %p TX could not allocate %ld-byte "
  549. "buffer\n", snpdev, ( ( unsigned long ) len ) );
  550. rc = -ENOMEM;
  551. goto err_alloc_iob;
  552. }
  553. iob_reserve ( iobuf, ( MAX_LL_HEADER_LEN -
  554. ll_protocol->ll_header_len ) );
  555. memcpy ( iob_put ( iobuf, len ), data, len );
  556. /* Create link-layer header, if specified */
  557. if ( ll_header_len ) {
  558. iob_pull ( iobuf, ll_protocol->ll_header_len );
  559. if ( ( rc = ll_protocol->push ( snpdev->netdev,
  560. iobuf, ll_dest, ll_src,
  561. htons ( *net_proto ) )) != 0 ){
  562. DBGC ( snpdev, "SNPDEV %p TX could not construct "
  563. "header: %s\n", snpdev, strerror ( rc ) );
  564. goto err_ll_push;
  565. }
  566. }
  567. /* Transmit packet */
  568. if ( ( rc = netdev_tx ( snpdev->netdev, iob_disown ( iobuf ) ) ) != 0){
  569. DBGC ( snpdev, "SNPDEV %p TX could not transmit: %s\n",
  570. snpdev, strerror ( rc ) );
  571. goto err_tx;
  572. }
  573. /* Record transmission as outstanding */
  574. snpdev->tx_count_interrupts++;
  575. snpdev->tx_count_txbufs++;
  576. return 0;
  577. err_tx:
  578. err_ll_push:
  579. free_iob ( iobuf );
  580. err_alloc_iob:
  581. err_sanity:
  582. return EFIRC ( rc );
  583. }
  584. /**
  585. * Receive packet
  586. *
  587. * @v snp SNP interface
  588. * @v ll_header_len Link-layer header length, if to be filled in
  589. * @v len Length of data buffer
  590. * @v data Data buffer
  591. * @v ll_src Link-layer source address, if specified
  592. * @v ll_dest Link-layer destination address, if specified
  593. * @v net_proto Network-layer protocol (in host order)
  594. * @ret efirc EFI status code
  595. */
  596. static EFI_STATUS EFIAPI
  597. efi_snp_receive ( EFI_SIMPLE_NETWORK_PROTOCOL *snp,
  598. UINTN *ll_header_len, UINTN *len, VOID *data,
  599. EFI_MAC_ADDRESS *ll_src, EFI_MAC_ADDRESS *ll_dest,
  600. UINT16 *net_proto ) {
  601. struct efi_snp_device *snpdev =
  602. container_of ( snp, struct efi_snp_device, snp );
  603. struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
  604. struct io_buffer *iobuf;
  605. const void *iob_ll_dest;
  606. const void *iob_ll_src;
  607. uint16_t iob_net_proto;
  608. unsigned int iob_flags;
  609. int rc;
  610. DBGC2 ( snpdev, "SNPDEV %p RECEIVE %p(+%lx)", snpdev, data,
  611. ( ( unsigned long ) *len ) );
  612. /* Fail if net device is currently claimed for use by iPXE */
  613. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  614. return EFI_NOT_READY;
  615. /* Poll the network device */
  616. efi_snp_poll ( snpdev );
  617. /* Dequeue a packet, if one is available */
  618. iobuf = netdev_rx_dequeue ( snpdev->netdev );
  619. if ( ! iobuf ) {
  620. DBGC2 ( snpdev, "\n" );
  621. rc = -EAGAIN;
  622. goto out_no_packet;
  623. }
  624. DBGC2 ( snpdev, "+%zx\n", iob_len ( iobuf ) );
  625. /* Return packet to caller */
  626. memcpy ( data, iobuf->data, iob_len ( iobuf ) );
  627. *len = iob_len ( iobuf );
  628. /* Attempt to decode link-layer header */
  629. if ( ( rc = ll_protocol->pull ( snpdev->netdev, iobuf, &iob_ll_dest,
  630. &iob_ll_src, &iob_net_proto,
  631. &iob_flags ) ) != 0 ) {
  632. DBGC ( snpdev, "SNPDEV %p could not parse header: %s\n",
  633. snpdev, strerror ( rc ) );
  634. goto out_bad_ll_header;
  635. }
  636. /* Return link-layer header parameters to caller, if required */
  637. if ( ll_header_len )
  638. *ll_header_len = ll_protocol->ll_header_len;
  639. if ( ll_src )
  640. memcpy ( ll_src, iob_ll_src, ll_protocol->ll_addr_len );
  641. if ( ll_dest )
  642. memcpy ( ll_dest, iob_ll_dest, ll_protocol->ll_addr_len );
  643. if ( net_proto )
  644. *net_proto = ntohs ( iob_net_proto );
  645. rc = 0;
  646. out_bad_ll_header:
  647. free_iob ( iobuf );
  648. out_no_packet:
  649. return EFIRC ( rc );
  650. }
  651. /**
  652. * Poll event
  653. *
  654. * @v event Event
  655. * @v context Event context
  656. */
  657. static VOID EFIAPI efi_snp_wait_for_packet ( EFI_EVENT event,
  658. VOID *context ) {
  659. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  660. struct efi_snp_device *snpdev = context;
  661. DBGCP ( snpdev, "SNPDEV %p WAIT_FOR_PACKET\n", snpdev );
  662. /* Do nothing unless the net device is open */
  663. if ( ! netdev_is_open ( snpdev->netdev ) )
  664. return;
  665. /* Do nothing if net device is currently claimed for use by iPXE */
  666. if ( ! netdev_rx_frozen ( snpdev->netdev ) )
  667. return;
  668. /* Poll the network device */
  669. efi_snp_poll ( snpdev );
  670. /* Fire event if packets have been received */
  671. if ( snpdev->rx_count_events != 0 ) {
  672. DBGC2 ( snpdev, "SNPDEV %p firing WaitForPacket event\n",
  673. snpdev );
  674. bs->SignalEvent ( event );
  675. snpdev->rx_count_events--;
  676. }
  677. }
  678. /** SNP interface */
  679. static EFI_SIMPLE_NETWORK_PROTOCOL efi_snp_device_snp = {
  680. .Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION,
  681. .Start = efi_snp_start,
  682. .Stop = efi_snp_stop,
  683. .Initialize = efi_snp_initialize,
  684. .Reset = efi_snp_reset,
  685. .Shutdown = efi_snp_shutdown,
  686. .ReceiveFilters = efi_snp_receive_filters,
  687. .StationAddress = efi_snp_station_address,
  688. .Statistics = efi_snp_statistics,
  689. .MCastIpToMac = efi_snp_mcast_ip_to_mac,
  690. .NvData = efi_snp_nvdata,
  691. .GetStatus = efi_snp_get_status,
  692. .Transmit = efi_snp_transmit,
  693. .Receive = efi_snp_receive,
  694. };
  695. /******************************************************************************
  696. *
  697. * Component name protocol
  698. *
  699. ******************************************************************************
  700. */
  701. /**
  702. * Look up driver name
  703. *
  704. * @v name2 Component name protocol
  705. * @v language Language to use
  706. * @v driver_name Driver name to fill in
  707. * @ret efirc EFI status code
  708. */
  709. static EFI_STATUS EFIAPI
  710. efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
  711. CHAR8 *language __unused, CHAR16 **driver_name ) {
  712. struct efi_snp_device *snpdev =
  713. container_of ( name2, struct efi_snp_device, name2 );
  714. *driver_name = snpdev->driver_name;
  715. return 0;
  716. }
  717. /**
  718. * Look up controller name
  719. *
  720. * @v name2 Component name protocol
  721. * @v device Device
  722. * @v child Child device, or NULL
  723. * @v language Language to use
  724. * @v driver_name Device name to fill in
  725. * @ret efirc EFI status code
  726. */
  727. static EFI_STATUS EFIAPI
  728. efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2,
  729. EFI_HANDLE device __unused,
  730. EFI_HANDLE child __unused,
  731. CHAR8 *language __unused,
  732. CHAR16 **controller_name ) {
  733. struct efi_snp_device *snpdev =
  734. container_of ( name2, struct efi_snp_device, name2 );
  735. *controller_name = snpdev->controller_name;
  736. return 0;
  737. }
  738. /******************************************************************************
  739. *
  740. * Load file protocol
  741. *
  742. ******************************************************************************
  743. */
  744. /**
  745. * Load file
  746. *
  747. * @v loadfile Load file protocol
  748. * @v path File path
  749. * @v booting Loading as part of a boot attempt
  750. * @ret efirc EFI status code
  751. */
  752. static EFI_STATUS EFIAPI
  753. efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file,
  754. EFI_DEVICE_PATH_PROTOCOL *path __unused,
  755. BOOLEAN booting, UINTN *len __unused,
  756. VOID *data __unused ) {
  757. struct efi_snp_device *snpdev =
  758. container_of ( load_file, struct efi_snp_device, load_file );
  759. struct net_device *netdev = snpdev->netdev;
  760. /* Fail unless this is a boot attempt */
  761. if ( ! booting ) {
  762. DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n",
  763. snpdev );
  764. return EFI_UNSUPPORTED;
  765. }
  766. /* Claim network devices for use by iPXE */
  767. efi_snp_claim();
  768. /* Boot from network device */
  769. ipxe ( netdev );
  770. /* Release network devices for use via SNP */
  771. efi_snp_release();
  772. /* Assume boot process was aborted */
  773. return EFI_ABORTED;
  774. }
  775. /** Load file protocol */
  776. static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = {
  777. .LoadFile = efi_snp_load_file,
  778. };
  779. /******************************************************************************
  780. *
  781. * iPXE network driver
  782. *
  783. ******************************************************************************
  784. */
  785. /**
  786. * Locate SNP device corresponding to network device
  787. *
  788. * @v netdev Network device
  789. * @ret snp SNP device, or NULL if not found
  790. */
  791. static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
  792. struct efi_snp_device *snpdev;
  793. list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
  794. if ( snpdev->netdev == netdev )
  795. return snpdev;
  796. }
  797. return NULL;
  798. }
  799. /**
  800. * Create SNP device
  801. *
  802. * @v netdev Network device
  803. * @ret rc Return status code
  804. */
  805. static int efi_snp_probe ( struct net_device *netdev ) {
  806. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  807. struct efi_device *efidev;
  808. struct efi_snp_device *snpdev;
  809. EFI_DEVICE_PATH_PROTOCOL *path_end;
  810. MAC_ADDR_DEVICE_PATH *macpath;
  811. size_t path_prefix_len = 0;
  812. EFI_STATUS efirc;
  813. int rc;
  814. /* Find parent EFI device */
  815. efidev = efidev_parent ( netdev->dev );
  816. if ( ! efidev ) {
  817. DBG ( "SNP skipping non-EFI device %s\n", netdev->name );
  818. rc = 0;
  819. goto err_no_efidev;
  820. }
  821. /* Calculate device path prefix length */
  822. path_end = efi_devpath_end ( efidev->path );
  823. path_prefix_len = ( ( ( void * ) path_end ) -
  824. ( ( void * ) efidev->path ) );
  825. /* Allocate the SNP device */
  826. snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
  827. sizeof ( *macpath ) );
  828. if ( ! snpdev ) {
  829. rc = -ENOMEM;
  830. goto err_alloc_snp;
  831. }
  832. snpdev->netdev = netdev_get ( netdev );
  833. snpdev->efidev = efidev;
  834. /* Sanity check */
  835. if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
  836. DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
  837. "length %d for %s\n", snpdev,
  838. netdev->ll_protocol->ll_addr_len, netdev->name );
  839. rc = -ENOTSUP;
  840. goto err_ll_addr_len;
  841. }
  842. /* Populate the SNP structure */
  843. memcpy ( &snpdev->snp, &efi_snp_device_snp, sizeof ( snpdev->snp ) );
  844. snpdev->snp.Mode = &snpdev->mode;
  845. if ( ( efirc = bs->CreateEvent ( EVT_NOTIFY_WAIT, TPL_NOTIFY,
  846. efi_snp_wait_for_packet, snpdev,
  847. &snpdev->snp.WaitForPacket ) ) != 0 ){
  848. rc = -EEFI ( efirc );
  849. DBGC ( snpdev, "SNPDEV %p could not create event: %s\n",
  850. snpdev, strerror ( rc ) );
  851. goto err_create_event;
  852. }
  853. /* Populate the SNP mode structure */
  854. snpdev->mode.State = EfiSimpleNetworkStopped;
  855. efi_snp_set_mode ( snpdev );
  856. /* Populate the NII structure */
  857. snpdev->nii.Revision =
  858. EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
  859. strncpy ( snpdev->nii.StringId, "iPXE",
  860. sizeof ( snpdev->nii.StringId ) );
  861. /* Populate the component name structure */
  862. efi_snprintf ( snpdev->driver_name,
  863. ( sizeof ( snpdev->driver_name ) /
  864. sizeof ( snpdev->driver_name[0] ) ),
  865. "%s %s", product_short_name, netdev->dev->driver_name );
  866. efi_snprintf ( snpdev->controller_name,
  867. ( sizeof ( snpdev->controller_name ) /
  868. sizeof ( snpdev->controller_name[0] ) ),
  869. "%s %s (%s, %s)", product_short_name,
  870. netdev->dev->driver_name, netdev->dev->name,
  871. netdev_addr ( netdev ) );
  872. snpdev->name2.GetDriverName = efi_snp_get_driver_name;
  873. snpdev->name2.GetControllerName = efi_snp_get_controller_name;
  874. snpdev->name2.SupportedLanguages = "en";
  875. /* Populate the load file protocol structure */
  876. memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol,
  877. sizeof ( snpdev->load_file ) );
  878. /* Populate the device name */
  879. efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) /
  880. sizeof ( snpdev->name[0] ) ),
  881. "%s", netdev->name );
  882. /* Populate the device path */
  883. memcpy ( &snpdev->path, efidev->path, path_prefix_len );
  884. macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
  885. path_end = ( ( void * ) ( macpath + 1 ) );
  886. memset ( macpath, 0, sizeof ( *macpath ) );
  887. macpath->Header.Type = MESSAGING_DEVICE_PATH;
  888. macpath->Header.SubType = MSG_MAC_ADDR_DP;
  889. macpath->Header.Length[0] = sizeof ( *macpath );
  890. memcpy ( &macpath->MacAddress, netdev->ll_addr,
  891. sizeof ( macpath->MacAddress ) );
  892. macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
  893. memset ( path_end, 0, sizeof ( *path_end ) );
  894. path_end->Type = END_DEVICE_PATH_TYPE;
  895. path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
  896. path_end->Length[0] = sizeof ( *path_end );
  897. /* Install the SNP */
  898. if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
  899. &snpdev->handle,
  900. &efi_simple_network_protocol_guid, &snpdev->snp,
  901. &efi_device_path_protocol_guid, &snpdev->path,
  902. &efi_nii_protocol_guid, &snpdev->nii,
  903. &efi_nii31_protocol_guid, &snpdev->nii,
  904. &efi_component_name2_protocol_guid, &snpdev->name2,
  905. &efi_load_file_protocol_guid, &snpdev->load_file,
  906. NULL ) ) != 0 ) {
  907. rc = -EEFI ( efirc );
  908. DBGC ( snpdev, "SNPDEV %p could not install protocols: "
  909. "%s\n", snpdev, strerror ( rc ) );
  910. goto err_install_protocol_interface;
  911. }
  912. /* Add as child of EFI parent device */
  913. if ( ( rc = efidev_child_add ( efidev, snpdev->handle ) ) != 0 ) {
  914. DBGC ( snpdev, "SNPDEV %p could not become child of %p %s: "
  915. "%s\n", snpdev, efidev->device,
  916. efi_devpath_text ( efidev->path ), strerror ( rc ) );
  917. goto err_efidev_child_add;
  918. }
  919. /* Install HII */
  920. if ( ( rc = efi_snp_hii_install ( snpdev ) ) != 0 ) {
  921. DBGC ( snpdev, "SNPDEV %p could not install HII: %s\n",
  922. snpdev, strerror ( rc ) );
  923. goto err_hii_install;
  924. }
  925. /* Add to list of SNP devices */
  926. list_add ( &snpdev->list, &efi_snp_devices );
  927. DBGC ( snpdev, "SNPDEV %p installed for %s as device %p %s\n",
  928. snpdev, netdev->name, snpdev->handle,
  929. efi_devpath_text ( &snpdev->path ) );
  930. return 0;
  931. efi_snp_hii_uninstall ( snpdev );
  932. err_hii_install:
  933. efidev_child_del ( efidev, snpdev->handle );
  934. err_efidev_child_add:
  935. bs->UninstallMultipleProtocolInterfaces (
  936. snpdev->handle,
  937. &efi_simple_network_protocol_guid, &snpdev->snp,
  938. &efi_device_path_protocol_guid, &snpdev->path,
  939. &efi_nii_protocol_guid, &snpdev->nii,
  940. &efi_nii31_protocol_guid, &snpdev->nii,
  941. &efi_component_name2_protocol_guid, &snpdev->name2,
  942. &efi_load_file_protocol_guid, &snpdev->load_file,
  943. NULL );
  944. err_install_protocol_interface:
  945. bs->CloseEvent ( snpdev->snp.WaitForPacket );
  946. err_create_event:
  947. err_ll_addr_len:
  948. netdev_put ( netdev );
  949. free ( snpdev );
  950. err_alloc_snp:
  951. err_no_efidev:
  952. return rc;
  953. }
  954. /**
  955. * Handle SNP device or link state change
  956. *
  957. * @v netdev Network device
  958. */
  959. static void efi_snp_notify ( struct net_device *netdev ) {
  960. struct efi_snp_device *snpdev;
  961. /* Locate SNP device */
  962. snpdev = efi_snp_demux ( netdev );
  963. if ( ! snpdev ) {
  964. DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
  965. return;
  966. }
  967. /* Update link state */
  968. snpdev->mode.MediaPresent =
  969. ( netdev_link_ok ( netdev ) ? TRUE : FALSE );
  970. DBGC ( snpdev, "SNPDEV %p link is %s\n", snpdev,
  971. ( snpdev->mode.MediaPresent ? "up" : "down" ) );
  972. /* Update mode state */
  973. efi_snp_set_state ( snpdev );
  974. }
  975. /**
  976. * Destroy SNP device
  977. *
  978. * @v netdev Network device
  979. */
  980. static void efi_snp_remove ( struct net_device *netdev ) {
  981. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  982. struct efi_snp_device *snpdev;
  983. /* Locate SNP device */
  984. snpdev = efi_snp_demux ( netdev );
  985. if ( ! snpdev ) {
  986. DBG ( "SNP skipping non-SNP device %s\n", netdev->name );
  987. return;
  988. }
  989. /* Uninstall the SNP */
  990. efi_snp_hii_uninstall ( snpdev );
  991. efidev_child_del ( snpdev->efidev, snpdev->handle );
  992. list_del ( &snpdev->list );
  993. bs->UninstallMultipleProtocolInterfaces (
  994. snpdev->handle,
  995. &efi_simple_network_protocol_guid, &snpdev->snp,
  996. &efi_device_path_protocol_guid, &snpdev->path,
  997. &efi_nii_protocol_guid, &snpdev->nii,
  998. &efi_nii31_protocol_guid, &snpdev->nii,
  999. &efi_component_name2_protocol_guid, &snpdev->name2,
  1000. &efi_load_file_protocol_guid, &snpdev->load_file,
  1001. NULL );
  1002. bs->CloseEvent ( snpdev->snp.WaitForPacket );
  1003. netdev_put ( snpdev->netdev );
  1004. free ( snpdev );
  1005. }
  1006. /** SNP driver */
  1007. struct net_driver efi_snp_driver __net_driver = {
  1008. .name = "SNP",
  1009. .probe = efi_snp_probe,
  1010. .notify = efi_snp_notify,
  1011. .remove = efi_snp_remove,
  1012. };
  1013. /**
  1014. * Find SNP device by EFI device handle
  1015. *
  1016. * @v handle EFI device handle
  1017. * @ret snpdev SNP device, or NULL
  1018. */
  1019. struct efi_snp_device * find_snpdev ( EFI_HANDLE handle ) {
  1020. struct efi_snp_device *snpdev;
  1021. list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
  1022. if ( snpdev->handle == handle )
  1023. return snpdev;
  1024. }
  1025. return NULL;
  1026. }
  1027. /**
  1028. * Get most recently opened SNP device
  1029. *
  1030. * @ret snpdev Most recently opened SNP device, or NULL
  1031. */
  1032. struct efi_snp_device * last_opened_snpdev ( void ) {
  1033. struct net_device *netdev;
  1034. netdev = last_opened_netdev();
  1035. if ( ! netdev )
  1036. return NULL;
  1037. return efi_snp_demux ( netdev );
  1038. }
  1039. /**
  1040. * Claim network devices for use by iPXE
  1041. *
  1042. */
  1043. void efi_snp_claim ( void ) {
  1044. struct net_device *netdev;
  1045. for_each_netdev ( netdev )
  1046. netdev_rx_unfreeze ( netdev );
  1047. }
  1048. /**
  1049. * Release network devices for use via SNP
  1050. *
  1051. */
  1052. void efi_snp_release ( void ) {
  1053. struct net_device *netdev;
  1054. for_each_netdev ( netdev )
  1055. netdev_rx_freeze ( netdev );
  1056. }