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

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