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.

pxe_undi.c 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. /** @file
  2. *
  3. * PXE UNDI API
  4. *
  5. */
  6. /*
  7. * Copyright (C) 2004 Michael Brown <mbrown@fensystems.co.uk>.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License as
  11. * published by the Free Software Foundation; either version 2 of the
  12. * License, or any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful, but
  15. * WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, write to the Free Software
  21. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER );
  24. #include <stdint.h>
  25. #include <stdio.h>
  26. #include <string.h>
  27. #include <byteswap.h>
  28. #include <basemem_packet.h>
  29. #include <gpxe/netdevice.h>
  30. #include <gpxe/iobuf.h>
  31. #include <gpxe/device.h>
  32. #include <gpxe/pci.h>
  33. #include <gpxe/if_ether.h>
  34. #include <gpxe/ip.h>
  35. #include <gpxe/arp.h>
  36. #include <gpxe/rarp.h>
  37. #include "pxe.h"
  38. /**
  39. * Count of outstanding transmitted packets
  40. *
  41. * This is incremented each time PXENV_UNDI_TRANSMIT is called, and
  42. * decremented each time that PXENV_UNDI_ISR is called with the TX
  43. * queue empty, stopping when the count reaches zero. This allows us
  44. * to provide a pessimistic approximation of TX completion events to
  45. * the PXE NBP simply by monitoring the netdev's TX queue.
  46. */
  47. static int undi_tx_count = 0;
  48. struct net_device *pxe_netdev = NULL;
  49. /**
  50. * Set network device as current PXE network device
  51. *
  52. * @v netdev Network device, or NULL
  53. */
  54. void pxe_set_netdev ( struct net_device *netdev ) {
  55. if ( pxe_netdev )
  56. netdev_put ( pxe_netdev );
  57. pxe_netdev = NULL;
  58. if ( netdev )
  59. pxe_netdev = netdev_get ( netdev );
  60. }
  61. /**
  62. * Open PXE network device
  63. *
  64. * @ret rc Return status code
  65. */
  66. static int pxe_netdev_open ( void ) {
  67. int rc;
  68. if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
  69. return rc;
  70. netdev_irq ( pxe_netdev, 1 );
  71. return 0;
  72. }
  73. /**
  74. * Close PXE network device
  75. *
  76. */
  77. static void pxe_netdev_close ( void ) {
  78. netdev_irq ( pxe_netdev, 0 );
  79. netdev_close ( pxe_netdev );
  80. undi_tx_count = 0;
  81. }
  82. /**
  83. * Dump multicast address list
  84. *
  85. * @v mcast PXE multicast address list
  86. */
  87. static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
  88. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  89. unsigned int i;
  90. for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
  91. DBG ( " %s", ll_protocol->ntoa ( mcast->McastAddr[i] ) );
  92. }
  93. }
  94. /* PXENV_UNDI_STARTUP
  95. *
  96. * Status: working
  97. */
  98. PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
  99. DBG ( "PXENV_UNDI_STARTUP\n" );
  100. undi_startup->Status = PXENV_STATUS_SUCCESS;
  101. return PXENV_EXIT_SUCCESS;
  102. }
  103. /* PXENV_UNDI_CLEANUP
  104. *
  105. * Status: working
  106. */
  107. PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
  108. DBG ( "PXENV_UNDI_CLEANUP\n" );
  109. pxe_netdev_close();
  110. undi_cleanup->Status = PXENV_STATUS_SUCCESS;
  111. return PXENV_EXIT_SUCCESS;
  112. }
  113. /* PXENV_UNDI_INITIALIZE
  114. *
  115. * Status: working
  116. */
  117. PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
  118. *undi_initialize ) {
  119. DBG ( "PXENV_UNDI_INITIALIZE protocolini %08x\n",
  120. undi_initialize->ProtocolIni );
  121. undi_initialize->Status = PXENV_STATUS_SUCCESS;
  122. return PXENV_EXIT_SUCCESS;
  123. }
  124. /* PXENV_UNDI_RESET_ADAPTER
  125. *
  126. * Status: working
  127. */
  128. PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
  129. *undi_reset_adapter ) {
  130. int rc;
  131. DBG ( "PXENV_UNDI_RESET_ADAPTER" );
  132. pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
  133. DBG ( "\n" );
  134. pxe_netdev_close();
  135. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  136. DBG ( "PXENV_UNDI_RESET_ADAPTER could not reopen %s: %s\n",
  137. pxe_netdev->name, strerror ( rc ) );
  138. undi_reset_adapter->Status = PXENV_STATUS ( rc );
  139. return PXENV_EXIT_FAILURE;
  140. }
  141. undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
  142. return PXENV_EXIT_SUCCESS;
  143. }
  144. /* PXENV_UNDI_SHUTDOWN
  145. *
  146. * Status: working
  147. */
  148. PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
  149. *undi_shutdown ) {
  150. DBG ( "PXENV_UNDI_SHUTDOWN\n" );
  151. pxe_netdev_close();
  152. undi_shutdown->Status = PXENV_STATUS_SUCCESS;
  153. return PXENV_EXIT_SUCCESS;
  154. }
  155. /* PXENV_UNDI_OPEN
  156. *
  157. * Status: working
  158. */
  159. PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
  160. int rc;
  161. DBG ( "PXENV_UNDI_OPEN flag %04x filter %04x",
  162. undi_open->OpenFlag, undi_open->PktFilter );
  163. pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
  164. DBG ( "\n" );
  165. if ( ( rc = pxe_netdev_open() ) != 0 ) {
  166. DBG ( "PXENV_UNDI_OPEN could not open %s: %s\n",
  167. pxe_netdev->name, strerror ( rc ) );
  168. undi_open->Status = PXENV_STATUS ( rc );
  169. return PXENV_EXIT_FAILURE;
  170. }
  171. undi_open->Status = PXENV_STATUS_SUCCESS;
  172. return PXENV_EXIT_SUCCESS;
  173. }
  174. /* PXENV_UNDI_CLOSE
  175. *
  176. * Status: working
  177. */
  178. PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
  179. DBG ( "PXENV_UNDI_CLOSE\n" );
  180. pxe_netdev_close();
  181. undi_close->Status = PXENV_STATUS_SUCCESS;
  182. return PXENV_EXIT_SUCCESS;
  183. }
  184. /* PXENV_UNDI_TRANSMIT
  185. *
  186. * Status: working
  187. */
  188. PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
  189. *undi_transmit ) {
  190. struct s_PXENV_UNDI_TBD tbd;
  191. struct DataBlk *datablk;
  192. struct io_buffer *iobuf;
  193. struct net_protocol *net_protocol;
  194. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  195. char destaddr[MAX_LL_ADDR_LEN];
  196. const void *ll_dest;
  197. size_t ll_hlen = ll_protocol->ll_header_len;
  198. size_t len;
  199. unsigned int i;
  200. int rc;
  201. DBG2 ( "PXENV_UNDI_TRANSMIT" );
  202. /* Forcibly enable interrupts at this point, to work around
  203. * callers that never call PXENV_UNDI_OPEN before attempting
  204. * to use the UNDI API.
  205. */
  206. netdev_irq ( pxe_netdev, 1 );
  207. /* Identify network-layer protocol */
  208. switch ( undi_transmit->Protocol ) {
  209. case P_IP: net_protocol = &ipv4_protocol; break;
  210. case P_ARP: net_protocol = &arp_protocol; break;
  211. case P_RARP: net_protocol = &rarp_protocol; break;
  212. case P_UNKNOWN:
  213. net_protocol = NULL;
  214. ll_hlen = 0;
  215. break;
  216. default:
  217. DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol );
  218. undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  219. return PXENV_EXIT_FAILURE;
  220. }
  221. DBG2 ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
  222. /* Calculate total packet length */
  223. copy_from_real ( &tbd, undi_transmit->TBD.segment,
  224. undi_transmit->TBD.offset, sizeof ( tbd ) );
  225. len = tbd.ImmedLength;
  226. DBG2 ( " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
  227. tbd.ImmedLength );
  228. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  229. datablk = &tbd.DataBlock[i];
  230. len += datablk->TDDataLen;
  231. DBG2 ( " %04x:%04x+%x", datablk->TDDataPtr.segment,
  232. datablk->TDDataPtr.offset, datablk->TDDataLen );
  233. }
  234. /* Allocate and fill I/O buffer */
  235. iobuf = alloc_iob ( ll_hlen + len );
  236. if ( ! iobuf ) {
  237. DBG2 ( " could not allocate iobuf\n" );
  238. undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
  239. return PXENV_EXIT_FAILURE;
  240. }
  241. iob_reserve ( iobuf, ll_hlen );
  242. copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
  243. tbd.Xmit.offset, tbd.ImmedLength );
  244. for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
  245. datablk = &tbd.DataBlock[i];
  246. copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
  247. datablk->TDDataPtr.segment,
  248. datablk->TDDataPtr.offset,
  249. datablk->TDDataLen );
  250. }
  251. /* Add link-layer header, if required to do so */
  252. if ( net_protocol != NULL ) {
  253. /* Calculate destination address */
  254. if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
  255. copy_from_real ( destaddr,
  256. undi_transmit->DestAddr.segment,
  257. undi_transmit->DestAddr.offset,
  258. ll_protocol->ll_addr_len );
  259. ll_dest = destaddr;
  260. DBG2 ( " DEST %s", ll_protocol->ntoa ( ll_dest ) );
  261. } else {
  262. ll_dest = pxe_netdev->ll_broadcast;
  263. DBG2 ( " BCAST" );
  264. }
  265. /* Add link-layer header */
  266. if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
  267. pxe_netdev->ll_addr,
  268. net_protocol->net_proto ))!=0){
  269. DBG2 ( " could not add link-layer header: %s\n",
  270. strerror ( rc ) );
  271. free_iob ( iobuf );
  272. undi_transmit->Status = PXENV_STATUS ( rc );
  273. return PXENV_EXIT_FAILURE;
  274. }
  275. }
  276. /* Flag transmission as in-progress. Do this before starting
  277. * to transmit the packet, because the ISR may trigger before
  278. * we return from netdev_tx().
  279. */
  280. undi_tx_count++;
  281. /* Transmit packet */
  282. DBG2 ( "\n" );
  283. if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
  284. DBG2 ( "PXENV_UNDI_TRANSMIT could not transmit: %s\n",
  285. strerror ( rc ) );
  286. undi_tx_count--;
  287. undi_transmit->Status = PXENV_STATUS ( rc );
  288. return PXENV_EXIT_FAILURE;
  289. }
  290. undi_transmit->Status = PXENV_STATUS_SUCCESS;
  291. return PXENV_EXIT_SUCCESS;
  292. }
  293. /* PXENV_UNDI_SET_MCAST_ADDRESS
  294. *
  295. * Status: working (for NICs that support receive-all-multicast)
  296. */
  297. PXENV_EXIT_t
  298. pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
  299. *undi_set_mcast_address ) {
  300. DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
  301. pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
  302. DBG ( "\n" );
  303. undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
  304. return PXENV_EXIT_SUCCESS;
  305. }
  306. /* PXENV_UNDI_SET_STATION_ADDRESS
  307. *
  308. * Status: working
  309. */
  310. PXENV_EXIT_t
  311. pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
  312. *undi_set_station_address ) {
  313. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  314. DBG ( "PXENV_UNDI_SET_STATION_ADDRESS %s",
  315. ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
  316. /* If adapter is open, the change will have no effect; return
  317. * an error
  318. */
  319. if ( pxe_netdev->state & NETDEV_OPEN ) {
  320. DBG ( " failed: netdev is open\n" );
  321. undi_set_station_address->Status =
  322. PXENV_STATUS_UNDI_INVALID_STATE;
  323. return PXENV_EXIT_FAILURE;
  324. }
  325. /* Update MAC address */
  326. memcpy ( pxe_netdev->ll_addr,
  327. &undi_set_station_address->StationAddress,
  328. ll_protocol->ll_addr_len );
  329. DBG ( "\n" );
  330. undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
  331. return PXENV_EXIT_SUCCESS;
  332. }
  333. /* PXENV_UNDI_SET_PACKET_FILTER
  334. *
  335. * Status: won't implement (would require driver API changes for no
  336. * real benefit)
  337. */
  338. PXENV_EXIT_t
  339. pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
  340. *undi_set_packet_filter ) {
  341. DBG ( "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
  342. undi_set_packet_filter->filter );
  343. /* Pretend that we succeeded, otherwise the 3Com DOS UNDI
  344. * driver refuses to load. (We ignore the filter value in the
  345. * PXENV_UNDI_OPEN call anyway.)
  346. */
  347. undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;
  348. return PXENV_EXIT_SUCCESS;
  349. }
  350. /* PXENV_UNDI_GET_INFORMATION
  351. *
  352. * Status: working
  353. */
  354. PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
  355. *undi_get_information ) {
  356. struct device *dev = pxe_netdev->dev;
  357. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  358. DBG ( "PXENV_UNDI_GET_INFORMATION" );
  359. undi_get_information->BaseIo = dev->desc.ioaddr;
  360. undi_get_information->IntNumber = dev->desc.irq;
  361. /* Cheat: assume all cards can cope with this */
  362. undi_get_information->MaxTranUnit = ETH_MAX_MTU;
  363. undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
  364. undi_get_information->HwAddrLen = ll_protocol->ll_addr_len;
  365. memcpy ( &undi_get_information->CurrentNodeAddress,
  366. pxe_netdev->ll_addr,
  367. sizeof ( undi_get_information->CurrentNodeAddress ) );
  368. memcpy ( &undi_get_information->PermNodeAddress,
  369. pxe_netdev->hw_addr,
  370. sizeof ( undi_get_information->PermNodeAddress ) );
  371. undi_get_information->ROMAddress = 0;
  372. /* nic.rom_info->rom_segment; */
  373. /* We only provide the ability to receive or transmit a single
  374. * packet at a time. This is a bootloader, not an OS.
  375. */
  376. undi_get_information->RxBufCt = 1;
  377. undi_get_information->TxBufCt = 1;
  378. DBG ( " io %04x irq %d mtu %d %s %s\n",
  379. undi_get_information->BaseIo, undi_get_information->IntNumber,
  380. undi_get_information->MaxTranUnit, ll_protocol->name,
  381. ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
  382. undi_get_information->Status = PXENV_STATUS_SUCCESS;
  383. return PXENV_EXIT_SUCCESS;
  384. }
  385. /* PXENV_UNDI_GET_STATISTICS
  386. *
  387. * Status: working
  388. */
  389. PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
  390. *undi_get_statistics ) {
  391. DBG ( "PXENV_UNDI_GET_STATISTICS" );
  392. undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
  393. undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
  394. undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
  395. undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
  396. DBG ( " txok %d rxok %d rxcrc %d rxrsrc %d\n",
  397. undi_get_statistics->XmtGoodFrames,
  398. undi_get_statistics->RcvGoodFrames,
  399. undi_get_statistics->RcvCRCErrors,
  400. undi_get_statistics->RcvResourceErrors );
  401. undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
  402. return PXENV_EXIT_SUCCESS;
  403. }
  404. /* PXENV_UNDI_CLEAR_STATISTICS
  405. *
  406. * Status: working
  407. */
  408. PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
  409. *undi_clear_statistics ) {
  410. DBG ( "PXENV_UNDI_CLEAR_STATISTICS\n" );
  411. memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
  412. memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
  413. undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
  414. return PXENV_EXIT_SUCCESS;
  415. }
  416. /* PXENV_UNDI_INITIATE_DIAGS
  417. *
  418. * Status: won't implement (would require driver API changes for no
  419. * real benefit)
  420. */
  421. PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
  422. *undi_initiate_diags ) {
  423. DBG ( "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
  424. undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
  425. return PXENV_EXIT_FAILURE;
  426. }
  427. /* PXENV_UNDI_FORCE_INTERRUPT
  428. *
  429. * Status: won't implement (would require driver API changes for no
  430. * perceptible benefit)
  431. */
  432. PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
  433. *undi_force_interrupt ) {
  434. DBG ( "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
  435. undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
  436. return PXENV_EXIT_FAILURE;
  437. }
  438. /* PXENV_UNDI_GET_MCAST_ADDRESS
  439. *
  440. * Status: working
  441. */
  442. PXENV_EXIT_t
  443. pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
  444. *undi_get_mcast_address ) {
  445. struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
  446. struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
  447. int rc;
  448. DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS %s", inet_ntoa ( ip ) );
  449. if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
  450. undi_get_mcast_address->MediaAddr ))!=0){
  451. DBG ( " failed: %s\n", strerror ( rc ) );
  452. undi_get_mcast_address->Status = PXENV_STATUS ( rc );
  453. return PXENV_EXIT_FAILURE;
  454. }
  455. DBG ( "=>%s\n",
  456. ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
  457. undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
  458. return PXENV_EXIT_SUCCESS;
  459. }
  460. /* PXENV_UNDI_GET_NIC_TYPE
  461. *
  462. * Status: working
  463. */
  464. PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
  465. *undi_get_nic_type ) {
  466. struct device *dev = pxe_netdev->dev;
  467. DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
  468. memset ( &undi_get_nic_type->info, 0,
  469. sizeof ( undi_get_nic_type->info ) );
  470. switch ( dev->desc.bus_type ) {
  471. case BUS_TYPE_PCI: {
  472. struct pci_nic_info *info = &undi_get_nic_type->info.pci;
  473. undi_get_nic_type->NicType = PCI_NIC;
  474. info->Vendor_ID = dev->desc.vendor;
  475. info->Dev_ID = dev->desc.device;
  476. info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
  477. info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
  478. info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
  479. info->BusDevFunc = dev->desc.location;
  480. /* Cheat: remaining fields are probably unnecessary,
  481. * and would require adding extra code to pci.c.
  482. */
  483. undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
  484. undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
  485. DBG ( " PCI %02x:%02x.%x %04x:%04x (%04x:%04x) %02x%02x%02x "
  486. "rev %02x\n", PCI_BUS ( info->BusDevFunc ),
  487. PCI_SLOT ( info->BusDevFunc ),
  488. PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
  489. info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
  490. info->Base_Class, info->Sub_Class, info->Prog_Intf,
  491. info->Rev );
  492. break; }
  493. case BUS_TYPE_ISAPNP: {
  494. struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
  495. undi_get_nic_type->NicType = PnP_NIC;
  496. info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
  497. dev->desc.device );
  498. info->CardSelNum = dev->desc.location;
  499. /* Cheat: remaining fields are probably unnecessary,
  500. * and would require adding extra code to isapnp.c.
  501. */
  502. DBG ( " ISAPnP CSN %04x %08x %02x%02x%02x\n",
  503. info->CardSelNum, info->EISA_Dev_ID,
  504. info->Base_Class, info->Sub_Class, info->Prog_Intf );
  505. break; }
  506. default:
  507. DBG ( " failed: unknown bus type\n" );
  508. undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
  509. return PXENV_EXIT_FAILURE;
  510. }
  511. undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
  512. return PXENV_EXIT_SUCCESS;
  513. }
  514. /* PXENV_UNDI_GET_IFACE_INFO
  515. *
  516. * Status: working
  517. */
  518. PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
  519. *undi_get_iface_info ) {
  520. DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
  521. /* Just hand back some info, doesn't really matter what it is.
  522. * Most PXE stacks seem to take this approach.
  523. */
  524. snprintf ( ( char * ) undi_get_iface_info->IfaceType,
  525. sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
  526. undi_get_iface_info->LinkSpeed = 10000000; /* 10 Mbps */
  527. undi_get_iface_info->ServiceFlags =
  528. ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
  529. SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
  530. SUPPORTED_OPEN_CLOSE | SUPPORTED_IRQ );
  531. memset ( undi_get_iface_info->Reserved, 0,
  532. sizeof(undi_get_iface_info->Reserved) );
  533. DBG ( " %s %dbps flags %08x\n", undi_get_iface_info->IfaceType,
  534. undi_get_iface_info->LinkSpeed,
  535. undi_get_iface_info->ServiceFlags );
  536. undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
  537. return PXENV_EXIT_SUCCESS;
  538. }
  539. /* PXENV_UNDI_GET_STATE
  540. *
  541. * Status: impossible
  542. */
  543. PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
  544. *undi_get_state ) {
  545. DBG ( "PXENV_UNDI_GET_STATE failed: unsupported\n" );
  546. undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
  547. return PXENV_EXIT_FAILURE;
  548. };
  549. /* PXENV_UNDI_ISR
  550. *
  551. * Status: working
  552. */
  553. PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
  554. struct io_buffer *iobuf;
  555. size_t len;
  556. struct ll_protocol *ll_protocol;
  557. const void *ll_dest;
  558. const void *ll_source;
  559. uint16_t net_proto;
  560. size_t ll_hlen;
  561. struct net_protocol *net_protocol;
  562. unsigned int prottype;
  563. int rc;
  564. /* Use coloured debug, since UNDI ISR messages are likely to
  565. * be interspersed amongst other UNDI messages.
  566. */
  567. DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );
  568. /* Just in case some idiot actually looks at these fields when
  569. * we weren't meant to fill them in...
  570. */
  571. undi_isr->BufferLength = 0;
  572. undi_isr->FrameLength = 0;
  573. undi_isr->FrameHeaderLength = 0;
  574. undi_isr->ProtType = 0;
  575. undi_isr->PktType = 0;
  576. switch ( undi_isr->FuncFlag ) {
  577. case PXENV_UNDI_ISR_IN_START :
  578. DBGC2 ( &pxenv_undi_isr, " START" );
  579. /* Call poll(). This should acknowledge the device
  580. * interrupt and queue up any received packet.
  581. */
  582. netdev_poll ( pxe_netdev );
  583. /* Disable interrupts to avoid interrupt storm */
  584. netdev_irq ( pxe_netdev, 0 );
  585. /* Always say it was ours for the sake of simplicity */
  586. DBGC2 ( &pxenv_undi_isr, " OURS" );
  587. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
  588. break;
  589. case PXENV_UNDI_ISR_IN_PROCESS :
  590. case PXENV_UNDI_ISR_IN_GET_NEXT :
  591. DBGC2 ( &pxenv_undi_isr, " %s",
  592. ( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ?
  593. "PROCESS" : "GET_NEXT" ) );
  594. /* Some dumb NBPs (e.g. emBoot's winBoot/i) never call
  595. * PXENV_UNDI_ISR with FuncFlag=PXENV_UNDI_ISR_START;
  596. * they just sit in a tight polling loop merrily
  597. * violating the PXE spec with repeated calls to
  598. * PXENV_UNDI_ISR_IN_PROCESS. Force extra polls to
  599. * cope with these out-of-spec clients.
  600. */
  601. netdev_poll ( pxe_netdev );
  602. /* If we have not yet marked a TX as complete, and the
  603. * netdev TX queue is empty, report the TX completion.
  604. */
  605. if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
  606. DBGC2 ( &pxenv_undi_isr, " TXC" );
  607. undi_tx_count--;
  608. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
  609. break;
  610. }
  611. /* Remove first packet from netdev RX queue */
  612. iobuf = netdev_rx_dequeue ( pxe_netdev );
  613. if ( ! iobuf ) {
  614. DBGC2 ( &pxenv_undi_isr, " DONE" );
  615. /* No more packets remaining */
  616. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  617. /* Re-enable interrupts */
  618. netdev_irq ( pxe_netdev, 1 );
  619. break;
  620. }
  621. /* Copy packet to base memory buffer */
  622. len = iob_len ( iobuf );
  623. DBGC2 ( &pxenv_undi_isr, " RX" );
  624. if ( len > sizeof ( basemem_packet ) ) {
  625. /* Should never happen */
  626. DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len );
  627. len = sizeof ( basemem_packet );
  628. }
  629. memcpy ( basemem_packet, iobuf->data, len );
  630. /* Strip link-layer header */
  631. ll_protocol = pxe_netdev->ll_protocol;
  632. if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
  633. &ll_source, &net_proto )) !=0){
  634. /* Assume unknown net_proto and no ll_source */
  635. net_proto = 0;
  636. ll_source = NULL;
  637. }
  638. ll_hlen = ( len - iob_len ( iobuf ) );
  639. /* Determine network-layer protocol */
  640. switch ( net_proto ) {
  641. case htons ( ETH_P_IP ):
  642. net_protocol = &ipv4_protocol;
  643. prottype = P_IP;
  644. break;
  645. case htons ( ETH_P_ARP ):
  646. net_protocol = &arp_protocol;
  647. prottype = P_ARP;
  648. break;
  649. case htons ( ETH_P_RARP ):
  650. net_protocol = &rarp_protocol;
  651. prottype = P_RARP;
  652. break;
  653. default:
  654. net_protocol = NULL;
  655. prottype = P_UNKNOWN;
  656. break;
  657. }
  658. /* Fill in UNDI_ISR structure */
  659. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
  660. undi_isr->BufferLength = len;
  661. undi_isr->FrameLength = len;
  662. undi_isr->FrameHeaderLength = ll_hlen;
  663. undi_isr->Frame.segment = rm_ds;
  664. undi_isr->Frame.offset = __from_data16 ( basemem_packet );
  665. undi_isr->ProtType = prottype;
  666. undi_isr->PktType = XMT_DESTADDR;
  667. DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
  668. undi_isr->Frame.segment, undi_isr->Frame.offset,
  669. undi_isr->BufferLength, undi_isr->FrameLength,
  670. ( net_protocol ? net_protocol->name : "RAW" ),
  671. undi_isr->FrameHeaderLength );
  672. /* Free packet */
  673. free_iob ( iobuf );
  674. break;
  675. default :
  676. DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n",
  677. undi_isr->FuncFlag );
  678. /* Should never happen */
  679. undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
  680. undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
  681. return PXENV_EXIT_FAILURE;
  682. }
  683. DBGC2 ( &pxenv_undi_isr, "\n" );
  684. undi_isr->Status = PXENV_STATUS_SUCCESS;
  685. return PXENV_EXIT_SUCCESS;
  686. }