|
@@ -315,6 +315,29 @@ arbel_cmd_mgid_hash ( struct arbel *arbel, const struct ib_gid *gid,
|
315
|
315
|
0, gid, 0, hash );
|
316
|
316
|
}
|
317
|
317
|
|
|
318
|
+static inline int
|
|
319
|
+arbel_cmd_run_fw ( struct arbel *arbel ) {
|
|
320
|
+ return arbel_cmd ( arbel,
|
|
321
|
+ ARBEL_HCR_VOID_CMD ( ARBEL_HCR_RUN_FW ),
|
|
322
|
+ 0, NULL, 0, NULL );
|
|
323
|
+}
|
|
324
|
+
|
|
325
|
+static inline int
|
|
326
|
+arbel_cmd_unmap_fa ( struct arbel *arbel ) {
|
|
327
|
+ return arbel_cmd ( arbel,
|
|
328
|
+ ARBEL_HCR_VOID_CMD ( ARBEL_HCR_UNMAP_FA ),
|
|
329
|
+ 0, NULL, 0, NULL );
|
|
330
|
+}
|
|
331
|
+
|
|
332
|
+static inline int
|
|
333
|
+arbel_cmd_map_fa ( struct arbel *arbel,
|
|
334
|
+ const struct arbelprm_virtual_physical_mapping *map_fa ) {
|
|
335
|
+ return arbel_cmd ( arbel,
|
|
336
|
+ ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_FA,
|
|
337
|
+ 1, sizeof ( *map_fa ) ),
|
|
338
|
+ 0, map_fa, 1, NULL );
|
|
339
|
+}
|
|
340
|
+
|
318
|
341
|
/***************************************************************************
|
319
|
342
|
*
|
320
|
343
|
* Completion queue operations
|
|
@@ -958,15 +981,15 @@ static int arbel_complete ( struct ib_device *ibdev,
|
958
|
981
|
}
|
959
|
982
|
qp = wq->qp;
|
960
|
983
|
arbel_qp = qp->dev_priv;
|
|
984
|
+ arbel_send_wq = &arbel_qp->send;
|
|
985
|
+ arbel_recv_wq = &arbel_qp->recv;
|
961
|
986
|
|
962
|
987
|
/* Identify work queue entry index */
|
963
|
988
|
if ( is_send ) {
|
964
|
|
- arbel_send_wq = &arbel_qp->send;
|
965
|
989
|
wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_send_wq->wqe ) ) /
|
966
|
990
|
sizeof ( arbel_send_wq->wqe[0] ) );
|
967
|
991
|
assert ( wqe_idx < qp->send.num_wqes );
|
968
|
992
|
} else {
|
969
|
|
- arbel_recv_wq = &arbel_qp->recv;
|
970
|
993
|
wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_recv_wq->wqe ) ) /
|
971
|
994
|
sizeof ( arbel_recv_wq->wqe[0] ) );
|
972
|
995
|
assert ( wqe_idx < qp->recv.num_wqes );
|
|
@@ -1177,6 +1200,12 @@ static struct ib_device_operations arbel_ib_operations = {
|
1177
|
1200
|
.mcast_detach = arbel_mcast_detach,
|
1178
|
1201
|
};
|
1179
|
1202
|
|
|
1203
|
+/***************************************************************************
|
|
1204
|
+ *
|
|
1205
|
+ * MAD IFC operations
|
|
1206
|
+ *
|
|
1207
|
+ ***************************************************************************
|
|
1208
|
+ */
|
1180
|
1209
|
|
1181
|
1210
|
static int arbel_mad_ifc ( struct arbel *arbel,
|
1182
|
1211
|
union arbelprm_mad *mad ) {
|
|
@@ -1301,6 +1330,102 @@ static int arbel_get_pkey ( struct arbel *arbel, unsigned int *pkey ) {
|
1301
|
1330
|
return 0;
|
1302
|
1331
|
}
|
1303
|
1332
|
|
|
1333
|
+/***************************************************************************
|
|
1334
|
+ *
|
|
1335
|
+ * Firmware control
|
|
1336
|
+ *
|
|
1337
|
+ ***************************************************************************
|
|
1338
|
+ */
|
|
1339
|
+
|
|
1340
|
+/**
|
|
1341
|
+ * Start firmware running
|
|
1342
|
+ *
|
|
1343
|
+ * @v arbel Arbel device
|
|
1344
|
+ * @ret rc Return status code
|
|
1345
|
+ */
|
|
1346
|
+static int arbel_start_firmware ( struct arbel *arbel ) {
|
|
1347
|
+ struct arbelprm_query_fw fw;
|
|
1348
|
+ struct arbelprm_virtual_physical_mapping map_fa;
|
|
1349
|
+ unsigned int fw_pages;
|
|
1350
|
+ unsigned int log2_fw_pages;
|
|
1351
|
+ size_t fw_size;
|
|
1352
|
+ physaddr_t fw_base;
|
|
1353
|
+ int rc;
|
|
1354
|
+
|
|
1355
|
+ /* Get firmware parameters */
|
|
1356
|
+ if ( ( rc = arbel_cmd_query_fw ( arbel, &fw ) ) != 0 ) {
|
|
1357
|
+ DBGC ( arbel, "Arbel %p could not query firmware: %s\n",
|
|
1358
|
+ arbel, strerror ( rc ) );
|
|
1359
|
+ goto err_query_fw;
|
|
1360
|
+ }
|
|
1361
|
+ DBGC ( arbel, "Arbel %p firmware version %ld.%ld.%ld\n", arbel,
|
|
1362
|
+ MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
|
|
1363
|
+ MLX_GET ( &fw, fw_rev_subminor ) );
|
|
1364
|
+ fw_pages = MLX_GET ( &fw, fw_pages );
|
|
1365
|
+ log2_fw_pages = fls ( fw_pages - 1 );
|
|
1366
|
+ fw_pages = ( 1 << log2_fw_pages );
|
|
1367
|
+ DBGC ( arbel, "Arbel %p requires %d kB for firmware\n",
|
|
1368
|
+ arbel, ( fw_pages * 4 ) );
|
|
1369
|
+
|
|
1370
|
+ /* Allocate firmware pages and map firmware area */
|
|
1371
|
+ fw_size = ( fw_pages * 4096 );
|
|
1372
|
+ arbel->firmware_area = umalloc ( fw_size );
|
|
1373
|
+ if ( ! arbel->firmware_area ) {
|
|
1374
|
+ rc = -ENOMEM;
|
|
1375
|
+ goto err_alloc_fa;
|
|
1376
|
+ }
|
|
1377
|
+ fw_base = ( user_to_phys ( arbel->firmware_area, fw_size ) &
|
|
1378
|
+ ~( fw_size - 1 ) );
|
|
1379
|
+ DBGC ( arbel, "Arbel %p firmware area at physical [%lx,%lx)\n",
|
|
1380
|
+ arbel, fw_base, ( fw_base + fw_size ) );
|
|
1381
|
+ memset ( &map_fa, 0, sizeof ( map_fa ) );
|
|
1382
|
+ MLX_FILL_2 ( &map_fa, 3,
|
|
1383
|
+ log2size, log2_fw_pages,
|
|
1384
|
+ pa_l, ( fw_base >> 12 ) );
|
|
1385
|
+ if ( ( rc = arbel_cmd_map_fa ( arbel, &map_fa ) ) != 0 ) {
|
|
1386
|
+ DBGC ( arbel, "Arbel %p could not map firmware: %s\n",
|
|
1387
|
+ arbel, strerror ( rc ) );
|
|
1388
|
+ goto err_map_fa;
|
|
1389
|
+ }
|
|
1390
|
+
|
|
1391
|
+ /* Start firmware */
|
|
1392
|
+ if ( ( rc = arbel_cmd_run_fw ( arbel ) ) != 0 ) {
|
|
1393
|
+ DBGC ( arbel, "Arbel %p could not run firmware: %s\n",
|
|
1394
|
+ arbel, strerror ( rc ) );
|
|
1395
|
+ goto err_run_fw;
|
|
1396
|
+ }
|
|
1397
|
+
|
|
1398
|
+ DBGC ( arbel, "Arbel %p firmware started\n", arbel );
|
|
1399
|
+ return 0;
|
|
1400
|
+
|
|
1401
|
+ err_run_fw:
|
|
1402
|
+ arbel_cmd_unmap_fa ( arbel );
|
|
1403
|
+ err_map_fa:
|
|
1404
|
+ ufree ( arbel->firmware_area );
|
|
1405
|
+ arbel->firmware_area = UNULL;
|
|
1406
|
+ err_alloc_fa:
|
|
1407
|
+ err_query_fw:
|
|
1408
|
+ return rc;
|
|
1409
|
+}
|
|
1410
|
+
|
|
1411
|
+/**
|
|
1412
|
+ * Stop firmware running
|
|
1413
|
+ *
|
|
1414
|
+ * @v arbel Arbel device
|
|
1415
|
+ */
|
|
1416
|
+static void arbel_stop_firmware ( struct arbel *arbel ) {
|
|
1417
|
+ int rc;
|
|
1418
|
+
|
|
1419
|
+ if ( ( rc = arbel_cmd_unmap_fa ( arbel ) ) != 0 ) {
|
|
1420
|
+ DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n",
|
|
1421
|
+ arbel, strerror ( rc ) );
|
|
1422
|
+ /* Leak memory and return; at least we avoid corruption */
|
|
1423
|
+ return;
|
|
1424
|
+ }
|
|
1425
|
+ ufree ( arbel->firmware_area );
|
|
1426
|
+ arbel->firmware_area = UNULL;
|
|
1427
|
+}
|
|
1428
|
+
|
1304
|
1429
|
/**
|
1305
|
1430
|
* Probe PCI device
|
1306
|
1431
|
*
|
|
@@ -1311,7 +1436,6 @@ static int arbel_get_pkey ( struct arbel *arbel, unsigned int *pkey ) {
|
1311
|
1436
|
static int arbel_probe ( struct pci_device *pci,
|
1312
|
1437
|
const struct pci_device_id *id __unused ) {
|
1313
|
1438
|
struct ib_device *ibdev;
|
1314
|
|
- struct arbelprm_query_fw fw;
|
1315
|
1439
|
struct arbelprm_query_dev_lim dev_lim;
|
1316
|
1440
|
struct arbel *arbel;
|
1317
|
1441
|
udqp_t qph;
|
|
@@ -1329,6 +1453,16 @@ static int arbel_probe ( struct pci_device *pci,
|
1329
|
1453
|
arbel = ibdev->dev_priv;
|
1330
|
1454
|
memset ( arbel, 0, sizeof ( *arbel ) );
|
1331
|
1455
|
|
|
1456
|
+ /* Fix up PCI device */
|
|
1457
|
+ adjust_pci_device ( pci );
|
|
1458
|
+
|
|
1459
|
+ /* Get PCI BARs */
|
|
1460
|
+ arbel->config = ioremap ( pci_bar_start ( pci, ARBEL_PCI_CONFIG_BAR ),
|
|
1461
|
+ ARBEL_PCI_CONFIG_BAR_SIZE );
|
|
1462
|
+ arbel->uar = ioremap ( ( pci_bar_start ( pci, ARBEL_PCI_UAR_BAR ) +
|
|
1463
|
+ ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ),
|
|
1464
|
+ ARBEL_PCI_UAR_SIZE );
|
|
1465
|
+
|
1332
|
1466
|
/* Allocate space for mailboxes */
|
1333
|
1467
|
arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN );
|
1334
|
1468
|
if ( ! arbel->mailbox_in ) {
|
|
@@ -1341,25 +1475,12 @@ static int arbel_probe ( struct pci_device *pci,
|
1341
|
1475
|
goto err_mailbox_out;
|
1342
|
1476
|
}
|
1343
|
1477
|
|
1344
|
|
- /* Fix up PCI device */
|
1345
|
|
- adjust_pci_device ( pci );
|
|
1478
|
+ /* Start firmware */
|
|
1479
|
+ if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 )
|
|
1480
|
+ goto err_start_firmware;
|
1346
|
1481
|
|
1347
|
|
- /* Get PCI BARs */
|
1348
|
|
- arbel->config = ioremap ( pci_bar_start ( pci, ARBEL_PCI_CONFIG_BAR ),
|
1349
|
|
- ARBEL_PCI_CONFIG_BAR_SIZE );
|
1350
|
|
- arbel->uar = ioremap ( ( pci_bar_start ( pci, ARBEL_PCI_UAR_BAR ) +
|
1351
|
|
- ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ),
|
1352
|
|
- ARBEL_PCI_UAR_SIZE );
|
1353
|
1482
|
|
1354
|
|
- /* Initialise firmware */
|
1355
|
|
- if ( ( rc = arbel_cmd_query_fw ( arbel, &fw ) ) != 0 ) {
|
1356
|
|
- DBGC ( arbel, "Arbel %p could not query firmware: %s\n",
|
1357
|
|
- arbel, strerror ( rc ) );
|
1358
|
|
- goto err_query_fw;
|
1359
|
|
- }
|
1360
|
|
- DBGC ( arbel, "Arbel %p firmware version %ld.%ld.%ld\n", arbel,
|
1361
|
|
- MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ),
|
1362
|
|
- MLX_GET ( &fw, fw_rev_subminor ) );
|
|
1483
|
+ while ( 1 ) {}
|
1363
|
1484
|
|
1364
|
1485
|
/* Initialise hardware */
|
1365
|
1486
|
if ( ( rc = ib_driver_init ( pci, &qph ) ) != 0 )
|
|
@@ -1425,7 +1546,9 @@ static int arbel_probe ( struct pci_device *pci,
|
1425
|
1546
|
err_query_dev_lim:
|
1426
|
1547
|
ib_driver_close ( 0 );
|
1427
|
1548
|
err_ib_driver_init:
|
1428
|
|
- err_query_fw:
|
|
1549
|
+
|
|
1550
|
+ arbel_stop_firmware ( arbel );
|
|
1551
|
+ err_start_firmware:
|
1429
|
1552
|
free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
|
1430
|
1553
|
err_mailbox_out:
|
1431
|
1554
|
free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
|
|
@@ -1446,6 +1569,7 @@ static void arbel_remove ( struct pci_device *pci ) {
|
1446
|
1569
|
|
1447
|
1570
|
ipoib_remove ( ibdev );
|
1448
|
1571
|
ib_driver_close ( 0 );
|
|
1572
|
+ arbel_stop_firmware ( arbel );
|
1449
|
1573
|
free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE );
|
1450
|
1574
|
free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE );
|
1451
|
1575
|
free_ibdev ( ibdev );
|