您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

efi_snp.c 28KB

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