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.

intelxlvf.c 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /*
  2. * Copyright (C) 2019 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 (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <string.h>
  25. #include <unistd.h>
  26. #include <errno.h>
  27. #include <byteswap.h>
  28. #include <ipxe/pci.h>
  29. #include <ipxe/netdevice.h>
  30. #include <ipxe/ethernet.h>
  31. #include "intelxlvf.h"
  32. /** @file
  33. *
  34. * Intel 40 Gigabit Ethernet virtual function network card driver
  35. *
  36. */
  37. /******************************************************************************
  38. *
  39. * Device reset
  40. *
  41. ******************************************************************************
  42. */
  43. /**
  44. * Reset hardware via PCIe function-level reset
  45. *
  46. * @v intelxl Intel device
  47. */
  48. static void intelxlvf_reset_flr ( struct intelxl_nic *intelxl,
  49. struct pci_device *pci ) {
  50. uint16_t control;
  51. /* Perform a PCIe function-level reset */
  52. pci_read_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
  53. &control );
  54. pci_write_config_word ( pci, ( intelxl->exp + PCI_EXP_DEVCTL ),
  55. ( control | PCI_EXP_DEVCTL_FLR ) );
  56. mdelay ( INTELXL_RESET_DELAY_MS );
  57. }
  58. /**
  59. * Wait for admin event queue to be torn down
  60. *
  61. * @v intelxl Intel device
  62. * @ret rc Return status code
  63. */
  64. static int intelxlvf_reset_wait_teardown ( struct intelxl_nic *intelxl ) {
  65. uint32_t admin_evt_len;
  66. unsigned int i;
  67. /* Wait for admin event queue to be torn down */
  68. for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
  69. /* Check admin event queue length register */
  70. admin_evt_len = readl ( intelxl->regs + INTELXLVF_ADMIN +
  71. INTELXLVF_ADMIN_EVT_LEN );
  72. if ( ! ( admin_evt_len & INTELXL_ADMIN_LEN_ENABLE ) )
  73. return 0;
  74. /* Delay */
  75. mdelay ( 1 );
  76. }
  77. DBGC ( intelxl, "INTELXL %p timed out waiting for teardown (%#08x)\n",
  78. intelxl, admin_evt_len );
  79. return -ETIMEDOUT;
  80. }
  81. /**
  82. * Wait for virtual function to be marked as active
  83. *
  84. * @v intelxl Intel device
  85. * @ret rc Return status code
  86. */
  87. static int intelxlvf_reset_wait_active ( struct intelxl_nic *intelxl ) {
  88. uint32_t vfgen_rstat;
  89. unsigned int vfr_state;
  90. unsigned int i;
  91. /* Wait for virtual function to be marked as active */
  92. for ( i = 0 ; i < INTELXLVF_RESET_MAX_WAIT_MS ; i++ ) {
  93. /* Check status as written by physical function driver */
  94. vfgen_rstat = readl ( intelxl->regs + INTELXLVF_VFGEN_RSTAT );
  95. vfr_state = INTELXLVF_VFGEN_RSTAT_VFR_STATE ( vfgen_rstat );
  96. if ( vfr_state == INTELXLVF_VFGEN_RSTAT_VFR_STATE_ACTIVE )
  97. return 0;
  98. /* Delay */
  99. mdelay ( 1 );
  100. }
  101. DBGC ( intelxl, "INTELXL %p timed out waiting for activation "
  102. "(%#08x)\n", intelxl, vfgen_rstat );
  103. return -ETIMEDOUT;
  104. }
  105. /**
  106. * Reset hardware via admin queue
  107. *
  108. * @v intelxl Intel device
  109. * @ret rc Return status code
  110. */
  111. static int intelxlvf_reset_admin ( struct intelxl_nic *intelxl ) {
  112. struct intelxl_admin_descriptor *cmd;
  113. int rc;
  114. /* Populate descriptor */
  115. cmd = intelxl_admin_command_descriptor ( intelxl );
  116. cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
  117. cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_RESET );
  118. /* Issue command */
  119. if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
  120. goto err_command;
  121. /* Wait for minimum reset time */
  122. mdelay ( INTELXL_RESET_DELAY_MS );
  123. /* Wait for reset to take effect */
  124. if ( ( rc = intelxlvf_reset_wait_teardown ( intelxl ) ) != 0 )
  125. goto err_teardown;
  126. /* Wait for virtual function to become active */
  127. if ( ( rc = intelxlvf_reset_wait_active ( intelxl ) ) != 0 )
  128. goto err_active;
  129. err_active:
  130. err_teardown:
  131. intelxl_reopen_admin ( intelxl );
  132. err_command:
  133. return rc;
  134. }
  135. /******************************************************************************
  136. *
  137. * Admin queue
  138. *
  139. ******************************************************************************
  140. */
  141. /** Admin command queue register offsets */
  142. static const struct intelxl_admin_offsets intelxlvf_admin_command_offsets = {
  143. .bal = INTELXLVF_ADMIN_CMD_BAL,
  144. .bah = INTELXLVF_ADMIN_CMD_BAH,
  145. .len = INTELXLVF_ADMIN_CMD_LEN,
  146. .head = INTELXLVF_ADMIN_CMD_HEAD,
  147. .tail = INTELXLVF_ADMIN_CMD_TAIL,
  148. };
  149. /** Admin event queue register offsets */
  150. static const struct intelxl_admin_offsets intelxlvf_admin_event_offsets = {
  151. .bal = INTELXLVF_ADMIN_EVT_BAL,
  152. .bah = INTELXLVF_ADMIN_EVT_BAH,
  153. .len = INTELXLVF_ADMIN_EVT_LEN,
  154. .head = INTELXLVF_ADMIN_EVT_HEAD,
  155. .tail = INTELXLVF_ADMIN_EVT_TAIL,
  156. };
  157. /**
  158. * Issue admin queue virtual function command
  159. *
  160. * @v netdev Network device
  161. * @ret rc Return status code
  162. */
  163. static int intelxlvf_admin_command ( struct net_device *netdev ) {
  164. struct intelxl_nic *intelxl = netdev->priv;
  165. struct intelxl_admin *admin = &intelxl->command;
  166. struct intelxl_admin_descriptor *cmd;
  167. unsigned int i;
  168. int rc;
  169. /* Populate descriptor */
  170. cmd = &admin->desc[ admin->index % INTELXL_ADMIN_NUM_DESC ];
  171. cmd->opcode = cpu_to_le16 ( INTELXL_ADMIN_SEND_TO_PF );
  172. /* Record opcode */
  173. intelxl->vopcode = le32_to_cpu ( cmd->vopcode );
  174. /* Issue command */
  175. if ( ( rc = intelxl_admin_command ( intelxl ) ) != 0 )
  176. goto err_command;
  177. /* Wait for response */
  178. for ( i = 0 ; i < INTELXLVF_ADMIN_MAX_WAIT_MS ; i++ ) {
  179. /* Poll admin event queue */
  180. intelxl_poll_admin ( netdev );
  181. /* If response has not arrived, delay 1ms and retry */
  182. if ( intelxl->vopcode ) {
  183. mdelay ( 1 );
  184. continue;
  185. }
  186. /* Check for errors */
  187. if ( intelxl->vret != 0 )
  188. return -EIO;
  189. return 0;
  190. }
  191. rc = -ETIMEDOUT;
  192. DBGC ( intelxl, "INTELXL %p timed out waiting for admin VF command "
  193. "%#x\n", intelxl, intelxl->vopcode );
  194. err_command:
  195. intelxl->vopcode = 0;
  196. return rc;
  197. }
  198. /**
  199. * Handle link status event
  200. *
  201. * @v netdev Network device
  202. * @v link Link status
  203. */
  204. static void intelxlvf_admin_link ( struct net_device *netdev,
  205. struct intelxl_admin_vf_status_link *link ) {
  206. struct intelxl_nic *intelxl = netdev->priv;
  207. DBGC ( intelxl, "INTELXL %p link %#02x speed %#02x\n", intelxl,
  208. link->status, link->speed );
  209. /* Update network device */
  210. if ( link->status ) {
  211. netdev_link_up ( netdev );
  212. } else {
  213. netdev_link_down ( netdev );
  214. }
  215. }
  216. /**
  217. * Handle status change event
  218. *
  219. * @v netdev Network device
  220. * @v stat Status change event
  221. */
  222. static void
  223. intelxlvf_admin_status ( struct net_device *netdev,
  224. struct intelxl_admin_vf_status_buffer *stat ) {
  225. struct intelxl_nic *intelxl = netdev->priv;
  226. /* Handle event */
  227. switch ( stat->event ) {
  228. case cpu_to_le32 ( INTELXL_ADMIN_VF_STATUS_LINK ):
  229. intelxlvf_admin_link ( netdev, &stat->data.link );
  230. break;
  231. default:
  232. DBGC ( intelxl, "INTELXL %p unrecognised status change "
  233. "event %#x:\n", intelxl, le32_to_cpu ( stat->event ) );
  234. DBGC_HDA ( intelxl, 0, stat, sizeof ( *stat ) );
  235. break;
  236. }
  237. }
  238. /**
  239. * Handle virtual function event
  240. *
  241. * @v netdev Network device
  242. * @v evt Admin queue event descriptor
  243. * @v buf Admin queue event data buffer
  244. */
  245. void intelxlvf_admin_event ( struct net_device *netdev,
  246. struct intelxl_admin_descriptor *evt,
  247. union intelxl_admin_buffer *buf ) {
  248. struct intelxl_nic *intelxl = netdev->priv;
  249. unsigned int vopcode = le32_to_cpu ( evt->vopcode );
  250. /* Record command response if applicable */
  251. if ( vopcode == intelxl->vopcode ) {
  252. memcpy ( &intelxl->vbuf, buf, sizeof ( intelxl->vbuf ) );
  253. intelxl->vopcode = 0;
  254. intelxl->vret = le32_to_cpu ( evt->vret );
  255. if ( intelxl->vret != 0 ) {
  256. DBGC ( intelxl, "INTELXL %p admin VF command %#x "
  257. "error %d\n", intelxl, vopcode, intelxl->vret );
  258. DBGC_HDA ( intelxl, virt_to_bus ( evt ), evt,
  259. sizeof ( *evt ) );
  260. DBGC_HDA ( intelxl, virt_to_bus ( buf ), buf,
  261. le16_to_cpu ( evt->len ) );
  262. }
  263. return;
  264. }
  265. /* Handle unsolicited events */
  266. switch ( vopcode ) {
  267. case INTELXL_ADMIN_VF_STATUS:
  268. intelxlvf_admin_status ( netdev, &buf->stat );
  269. break;
  270. default:
  271. DBGC ( intelxl, "INTELXL %p unrecognised VF event %#x:\n",
  272. intelxl, vopcode );
  273. DBGC_HDA ( intelxl, 0, evt, sizeof ( *evt ) );
  274. DBGC_HDA ( intelxl, 0, buf, le16_to_cpu ( evt->len ) );
  275. break;
  276. }
  277. }
  278. /**
  279. * Get resources
  280. *
  281. * @v netdev Network device
  282. * @ret rc Return status code
  283. */
  284. static int intelxlvf_admin_get_resources ( struct net_device *netdev ) {
  285. struct intelxl_nic *intelxl = netdev->priv;
  286. struct intelxl_admin_descriptor *cmd;
  287. struct intelxl_admin_vf_get_resources_buffer *res;
  288. int rc;
  289. /* Populate descriptor */
  290. cmd = intelxl_admin_command_descriptor ( intelxl );
  291. cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_GET_RESOURCES );
  292. /* Issue command */
  293. if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
  294. return rc;
  295. /* Parse response */
  296. res = &intelxl->vbuf.res;
  297. intelxl->vsi = le16_to_cpu ( res->vsi );
  298. memcpy ( netdev->hw_addr, res->mac, ETH_ALEN );
  299. DBGC ( intelxl, "INTELXL %p VSI %#04x\n", intelxl, intelxl->vsi );
  300. return 0;
  301. }
  302. /******************************************************************************
  303. *
  304. * Network device interface
  305. *
  306. ******************************************************************************
  307. */
  308. /**
  309. * Configure queues
  310. *
  311. * @v netdev Network device
  312. * @ret rc Return status code
  313. */
  314. static int intelxlvf_admin_configure ( struct net_device *netdev ) {
  315. struct intelxl_nic *intelxl = netdev->priv;
  316. struct intelxl_admin_descriptor *cmd;
  317. union intelxl_admin_buffer *buf;
  318. int rc;
  319. /* Populate descriptor */
  320. cmd = intelxl_admin_command_descriptor ( intelxl );
  321. cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_CONFIGURE );
  322. cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
  323. cmd->len = cpu_to_le16 ( sizeof ( buf->cfg ) );
  324. buf = intelxl_admin_command_buffer ( intelxl );
  325. buf->cfg.vsi = cpu_to_le16 ( intelxl->vsi );
  326. buf->cfg.count = cpu_to_le16 ( 1 );
  327. buf->cfg.tx.vsi = cpu_to_le16 ( intelxl->vsi );
  328. buf->cfg.tx.count = cpu_to_le16 ( INTELXL_TX_NUM_DESC );
  329. buf->cfg.tx.base = cpu_to_le64 ( virt_to_bus ( intelxl->tx.desc.raw ) );
  330. buf->cfg.rx.vsi = cpu_to_le16 ( intelxl->vsi );
  331. buf->cfg.rx.count = cpu_to_le32 ( INTELXL_RX_NUM_DESC );
  332. buf->cfg.rx.len = cpu_to_le32 ( intelxl->mfs );
  333. buf->cfg.rx.mfs = cpu_to_le32 ( intelxl->mfs );
  334. buf->cfg.rx.base = cpu_to_le64 ( virt_to_bus ( intelxl->rx.desc.raw ) );
  335. /* Issue command */
  336. if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
  337. return rc;
  338. return 0;
  339. }
  340. /**
  341. * Configure IRQ mapping
  342. *
  343. * @v netdev Network device
  344. * @ret rc Return status code
  345. */
  346. static int intelxlvf_admin_irq_map ( struct net_device *netdev ) {
  347. struct intelxl_nic *intelxl = netdev->priv;
  348. struct intelxl_admin_descriptor *cmd;
  349. union intelxl_admin_buffer *buf;
  350. int rc;
  351. /* Populate descriptor */
  352. cmd = intelxl_admin_command_descriptor ( intelxl );
  353. cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_IRQ_MAP );
  354. cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
  355. cmd->len = cpu_to_le16 ( sizeof ( buf->irq ) );
  356. buf = intelxl_admin_command_buffer ( intelxl );
  357. buf->irq.count = cpu_to_le16 ( 1 );
  358. buf->irq.vsi = cpu_to_le16 ( intelxl->vsi );
  359. buf->irq.rxmap = cpu_to_le16 ( 0x0001 );
  360. buf->irq.txmap = cpu_to_le16 ( 0x0001 );
  361. /* Issue command */
  362. if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
  363. return rc;
  364. return 0;
  365. }
  366. /**
  367. * Enable/disable queues
  368. *
  369. * @v netdev Network device
  370. * @v enable Enable queues
  371. * @ret rc Return status code
  372. */
  373. static int intelxlvf_admin_queues ( struct net_device *netdev, int enable ) {
  374. struct intelxl_nic *intelxl = netdev->priv;
  375. struct intelxl_admin_descriptor *cmd;
  376. union intelxl_admin_buffer *buf;
  377. int rc;
  378. /* Populate descriptor */
  379. cmd = intelxl_admin_command_descriptor ( intelxl );
  380. cmd->vopcode = ( enable ? cpu_to_le32 ( INTELXL_ADMIN_VF_ENABLE ) :
  381. cpu_to_le32 ( INTELXL_ADMIN_VF_DISABLE ) );
  382. cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
  383. cmd->len = cpu_to_le16 ( sizeof ( buf->queues ) );
  384. buf = intelxl_admin_command_buffer ( intelxl );
  385. buf->queues.vsi = cpu_to_le16 ( intelxl->vsi );
  386. buf->queues.rx = cpu_to_le32 ( 1 );
  387. buf->queues.tx = cpu_to_le32 ( 1 );
  388. /* Issue command */
  389. if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
  390. return rc;
  391. return 0;
  392. }
  393. /**
  394. * Configure promiscuous mode
  395. *
  396. * @v netdev Network device
  397. * @ret rc Return status code
  398. */
  399. static int intelxlvf_admin_promisc ( struct net_device *netdev ) {
  400. struct intelxl_nic *intelxl = netdev->priv;
  401. struct intelxl_admin_descriptor *cmd;
  402. union intelxl_admin_buffer *buf;
  403. int rc;
  404. /* Populate descriptor */
  405. cmd = intelxl_admin_command_descriptor ( intelxl );
  406. cmd->vopcode = cpu_to_le32 ( INTELXL_ADMIN_VF_PROMISC );
  407. cmd->flags = cpu_to_le16 ( INTELXL_ADMIN_FL_RD | INTELXL_ADMIN_FL_BUF );
  408. cmd->len = cpu_to_le16 ( sizeof ( buf->promisc ) );
  409. buf = intelxl_admin_command_buffer ( intelxl );
  410. buf->promisc.vsi = cpu_to_le16 ( intelxl->vsi );
  411. buf->promisc.flags = cpu_to_le16 ( INTELXL_ADMIN_PROMISC_FL_UNICAST |
  412. INTELXL_ADMIN_PROMISC_FL_MULTICAST );
  413. /* Issue command */
  414. if ( ( rc = intelxlvf_admin_command ( netdev ) ) != 0 )
  415. return rc;
  416. return 0;
  417. }
  418. /**
  419. * Open network device
  420. *
  421. * @v netdev Network device
  422. * @ret rc Return status code
  423. */
  424. static int intelxlvf_open ( struct net_device *netdev ) {
  425. struct intelxl_nic *intelxl = netdev->priv;
  426. int rc;
  427. /* Calculate maximum frame size */
  428. intelxl->mfs = ( ( ETH_HLEN + netdev->mtu + 4 /* CRC */ +
  429. INTELXL_ALIGN - 1 ) & ~( INTELXL_ALIGN - 1 ) );
  430. /* Allocate transmit descriptor ring */
  431. if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->tx ) ) != 0 )
  432. goto err_alloc_tx;
  433. /* Allocate receive descriptor ring */
  434. if ( ( rc = intelxl_alloc_ring ( intelxl, &intelxl->rx ) ) != 0 )
  435. goto err_alloc_rx;
  436. /* Configure queues */
  437. if ( ( rc = intelxlvf_admin_configure ( netdev ) ) != 0 )
  438. goto err_configure;
  439. /* Configure IRQ map */
  440. if ( ( rc = intelxlvf_admin_irq_map ( netdev ) ) != 0 )
  441. goto err_irq_map;
  442. /* Enable queues */
  443. if ( ( rc = intelxlvf_admin_queues ( netdev, 1 ) ) != 0 )
  444. goto err_enable;
  445. /* Configure promiscuous mode */
  446. if ( ( rc = intelxlvf_admin_promisc ( netdev ) ) != 0 )
  447. goto err_promisc;
  448. return 0;
  449. err_promisc:
  450. intelxlvf_admin_queues ( netdev, INTELXL_ADMIN_VF_DISABLE );
  451. err_enable:
  452. err_irq_map:
  453. err_configure:
  454. intelxl_free_ring ( intelxl, &intelxl->rx );
  455. err_alloc_rx:
  456. intelxl_free_ring ( intelxl, &intelxl->tx );
  457. err_alloc_tx:
  458. return rc;
  459. }
  460. /**
  461. * Close network device
  462. *
  463. * @v netdev Network device
  464. */
  465. static void intelxlvf_close ( struct net_device *netdev ) {
  466. struct intelxl_nic *intelxl = netdev->priv;
  467. int rc;
  468. /* Disable queues */
  469. if ( ( rc = intelxlvf_admin_queues ( netdev, 0 ) ) != 0 ) {
  470. /* Leak memory; there's nothing else we can do */
  471. return;
  472. }
  473. /* Free receive descriptor ring */
  474. intelxl_free_ring ( intelxl, &intelxl->rx );
  475. /* Free transmit descriptor ring */
  476. intelxl_free_ring ( intelxl, &intelxl->tx );
  477. /* Discard any unused receive buffers */
  478. intelxl_empty_rx ( intelxl );
  479. }
  480. /** Network device operations */
  481. static struct net_device_operations intelxlvf_operations = {
  482. .open = intelxlvf_open,
  483. .close = intelxlvf_close,
  484. .transmit = intelxl_transmit,
  485. .poll = intelxl_poll,
  486. };
  487. /******************************************************************************
  488. *
  489. * PCI interface
  490. *
  491. ******************************************************************************
  492. */
  493. /**
  494. * Probe PCI device
  495. *
  496. * @v pci PCI device
  497. * @ret rc Return status code
  498. */
  499. static int intelxlvf_probe ( struct pci_device *pci ) {
  500. struct net_device *netdev;
  501. struct intelxl_nic *intelxl;
  502. int rc;
  503. /* Allocate and initialise net device */
  504. netdev = alloc_etherdev ( sizeof ( *intelxl ) );
  505. if ( ! netdev ) {
  506. rc = -ENOMEM;
  507. goto err_alloc;
  508. }
  509. netdev_init ( netdev, &intelxlvf_operations );
  510. intelxl = netdev->priv;
  511. pci_set_drvdata ( pci, netdev );
  512. netdev->dev = &pci->dev;
  513. memset ( intelxl, 0, sizeof ( *intelxl ) );
  514. intelxl->intr = INTELXLVF_VFINT_DYN_CTL0;
  515. intelxl_init_admin ( &intelxl->command, INTELXLVF_ADMIN,
  516. &intelxlvf_admin_command_offsets );
  517. intelxl_init_admin ( &intelxl->event, INTELXLVF_ADMIN,
  518. &intelxlvf_admin_event_offsets );
  519. intelxlvf_init_ring ( &intelxl->tx, INTELXL_TX_NUM_DESC,
  520. sizeof ( intelxl->tx.desc.tx[0] ),
  521. INTELXLVF_QTX_TAIL );
  522. intelxlvf_init_ring ( &intelxl->rx, INTELXL_RX_NUM_DESC,
  523. sizeof ( intelxl->rx.desc.rx[0] ),
  524. INTELXLVF_QRX_TAIL );
  525. /* Fix up PCI device */
  526. adjust_pci_device ( pci );
  527. /* Map registers */
  528. intelxl->regs = ioremap ( pci->membase, INTELXLVF_BAR_SIZE );
  529. if ( ! intelxl->regs ) {
  530. rc = -ENODEV;
  531. goto err_ioremap;
  532. }
  533. /* Locate PCI Express capability */
  534. intelxl->exp = pci_find_capability ( pci, PCI_CAP_ID_EXP );
  535. if ( ! intelxl->exp ) {
  536. DBGC ( intelxl, "INTELXL %p missing PCIe capability\n",
  537. intelxl );
  538. rc = -ENXIO;
  539. goto err_exp;
  540. }
  541. /* Reset the function via PCIe FLR */
  542. intelxlvf_reset_flr ( intelxl, pci );
  543. /* Enable MSI-X dummy interrupt */
  544. if ( ( rc = intelxl_msix_enable ( intelxl, pci ) ) != 0 )
  545. goto err_msix;
  546. /* Open admin queues */
  547. if ( ( rc = intelxl_open_admin ( intelxl ) ) != 0 )
  548. goto err_open_admin;
  549. /* Reset the function via admin queue */
  550. if ( ( rc = intelxlvf_reset_admin ( intelxl ) ) != 0 )
  551. goto err_reset_admin;
  552. /* Get MAC address */
  553. if ( ( rc = intelxlvf_admin_get_resources ( netdev ) ) != 0 )
  554. goto err_get_resources;
  555. /* Register network device */
  556. if ( ( rc = register_netdev ( netdev ) ) != 0 )
  557. goto err_register_netdev;
  558. return 0;
  559. unregister_netdev ( netdev );
  560. err_register_netdev:
  561. err_get_resources:
  562. err_reset_admin:
  563. intelxl_close_admin ( intelxl );
  564. err_open_admin:
  565. intelxl_msix_disable ( intelxl, pci );
  566. err_msix:
  567. intelxlvf_reset_flr ( intelxl, pci );
  568. err_exp:
  569. iounmap ( intelxl->regs );
  570. err_ioremap:
  571. netdev_nullify ( netdev );
  572. netdev_put ( netdev );
  573. err_alloc:
  574. return rc;
  575. }
  576. /**
  577. * Remove PCI device
  578. *
  579. * @v pci PCI device
  580. */
  581. static void intelxlvf_remove ( struct pci_device *pci ) {
  582. struct net_device *netdev = pci_get_drvdata ( pci );
  583. struct intelxl_nic *intelxl = netdev->priv;
  584. /* Unregister network device */
  585. unregister_netdev ( netdev );
  586. /* Reset the function via admin queue */
  587. intelxlvf_reset_admin ( intelxl );
  588. /* Close admin queues */
  589. intelxl_close_admin ( intelxl );
  590. /* Disable MSI-X dummy interrupt */
  591. intelxl_msix_disable ( intelxl, pci );
  592. /* Reset the function via PCIe FLR */
  593. intelxlvf_reset_flr ( intelxl, pci );
  594. /* Free network device */
  595. iounmap ( intelxl->regs );
  596. netdev_nullify ( netdev );
  597. netdev_put ( netdev );
  598. }
  599. /** PCI device IDs */
  600. static struct pci_device_id intelxlvf_nics[] = {
  601. PCI_ROM ( 0x8086, 0x154c, "xl710-vf", "XL710 VF", 0 ),
  602. PCI_ROM ( 0x8086, 0x1571, "xl710-vf-hv", "XL710 VF (Hyper-V)", 0 ),
  603. PCI_ROM ( 0x8086, 0x1889, "xl710-vf-ad", "XL710 VF (adaptive)", 0 ),
  604. PCI_ROM ( 0x8086, 0x37cd, "x722-vf", "X722 VF", 0 ),
  605. PCI_ROM ( 0x8086, 0x37d9, "x722-vf-hv", "X722 VF (Hyper-V)", 0 ),
  606. };
  607. /** PCI driver */
  608. struct pci_driver intelxlvf_driver __pci_driver = {
  609. .ids = intelxlvf_nics,
  610. .id_count = ( sizeof ( intelxlvf_nics ) /
  611. sizeof ( intelxlvf_nics[0] ) ),
  612. .probe = intelxlvf_probe,
  613. .remove = intelxlvf_remove,
  614. };