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

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