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

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