|
@@ -275,20 +275,31 @@ arbel_cmd_sw2hw_mpt ( struct arbel *arbel, unsigned int index,
|
275
|
275
|
0, mpt, index, NULL );
|
276
|
276
|
}
|
277
|
277
|
|
|
278
|
+static inline int
|
|
279
|
+arbel_cmd_map_eq ( struct arbel *arbel, unsigned long index_map,
|
|
280
|
+ const struct arbelprm_event_mask *mask ) {
|
|
281
|
+ return arbel_cmd ( arbel,
|
|
282
|
+ ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_EQ,
|
|
283
|
+ 0, sizeof ( *mask ) ),
|
|
284
|
+ 0, mask, index_map, NULL );
|
|
285
|
+}
|
|
286
|
+
|
278
|
287
|
static inline int
|
279
|
288
|
arbel_cmd_sw2hw_eq ( struct arbel *arbel, unsigned int index,
|
280
|
|
- const struct arbelprm_eqc *eqc ) {
|
|
289
|
+ const struct arbelprm_eqc *eqctx ) {
|
281
|
290
|
return arbel_cmd ( arbel,
|
282
|
291
|
ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_EQ,
|
283
|
|
- 1, sizeof ( *eqc ) ),
|
284
|
|
- 0, eqc, index, NULL );
|
|
292
|
+ 1, sizeof ( *eqctx ) ),
|
|
293
|
+ 0, eqctx, index, NULL );
|
285
|
294
|
}
|
286
|
295
|
|
287
|
296
|
static inline int
|
288
|
|
-arbel_cmd_hw2sw_eq ( struct arbel *arbel, unsigned int index ) {
|
|
297
|
+arbel_cmd_hw2sw_eq ( struct arbel *arbel, unsigned int index,
|
|
298
|
+ struct arbelprm_eqc *eqctx ) {
|
289
|
299
|
return arbel_cmd ( arbel,
|
290
|
|
- ARBEL_HCR_VOID_CMD ( ARBEL_HCR_HW2SW_EQ ),
|
291
|
|
- 1, NULL, index, NULL );
|
|
300
|
+ ARBEL_HCR_OUT_CMD ( ARBEL_HCR_HW2SW_EQ,
|
|
301
|
+ 1, sizeof ( *eqctx ) ),
|
|
302
|
+ 1, NULL, index, eqctx );
|
292
|
303
|
}
|
293
|
304
|
|
294
|
305
|
static inline int
|
|
@@ -336,6 +347,15 @@ arbel_cmd_rtr2rts_qpee ( struct arbel *arbel, unsigned long qpn,
|
336
|
347
|
0, ctx, qpn, NULL );
|
337
|
348
|
}
|
338
|
349
|
|
|
350
|
+static inline int
|
|
351
|
+arbel_cmd_rts2rts_qp ( struct arbel *arbel, unsigned long qpn,
|
|
352
|
+ const struct arbelprm_qp_ee_state_transitions *ctx ) {
|
|
353
|
+ return arbel_cmd ( arbel,
|
|
354
|
+ ARBEL_HCR_IN_CMD ( ARBEL_HCR_RTS2RTS_QPEE,
|
|
355
|
+ 1, sizeof ( *ctx ) ),
|
|
356
|
+ 0, ctx, qpn, NULL );
|
|
357
|
+}
|
|
358
|
+
|
339
|
359
|
static inline int
|
340
|
360
|
arbel_cmd_2rst_qpee ( struct arbel *arbel, unsigned long qpn ) {
|
341
|
361
|
return arbel_cmd ( arbel,
|
|
@@ -847,13 +867,25 @@ static int arbel_modify_qp ( struct ib_device *ibdev,
|
847
|
867
|
struct ib_queue_pair *qp,
|
848
|
868
|
unsigned long mod_list ) {
|
849
|
869
|
struct arbel *arbel = ib_get_drvdata ( ibdev );
|
|
870
|
+ struct arbelprm_qp_ee_state_transitions qpctx;
|
|
871
|
+ unsigned long optparammask = 0;
|
|
872
|
+ int rc;
|
850
|
873
|
|
851
|
|
- /* TODO */
|
852
|
|
- ( void ) arbel;
|
853
|
|
- ( void ) qp;
|
854
|
|
- ( void ) mod_list;
|
|
874
|
+ /* Construct optparammask */
|
|
875
|
+ if ( mod_list & IB_MODIFY_QKEY )
|
|
876
|
+ optparammask |= ARBEL_QPEE_OPT_PARAM_QKEY;
|
855
|
877
|
|
856
|
|
- return -ENOTSUP;
|
|
878
|
+ /* Issue RTS2RTS_QP */
|
|
879
|
+ memset ( &qpctx, 0, sizeof ( qpctx ) );
|
|
880
|
+ MLX_FILL_1 ( &qpctx, 0, opt_param_mask, optparammask );
|
|
881
|
+ MLX_FILL_1 ( &qpctx, 44, qpc_eec_data.q_key, qp->qkey );
|
|
882
|
+ if ( ( rc = arbel_cmd_rts2rts_qp ( arbel, qp->qpn, &qpctx ) ) != 0 ){
|
|
883
|
+ DBGC ( arbel, "Arbel %p RTS2RTS_QP failed: %s\n",
|
|
884
|
+ arbel, strerror ( rc ) );
|
|
885
|
+ return rc;
|
|
886
|
+ }
|
|
887
|
+
|
|
888
|
+ return 0;
|
857
|
889
|
}
|
858
|
890
|
|
859
|
891
|
/**
|
|
@@ -1230,6 +1262,145 @@ static void arbel_poll_cq ( struct ib_device *ibdev,
|
1230
|
1262
|
***************************************************************************
|
1231
|
1263
|
*/
|
1232
|
1264
|
|
|
1265
|
+/**
|
|
1266
|
+ * Create event queue
|
|
1267
|
+ *
|
|
1268
|
+ * @v arbel Arbel device
|
|
1269
|
+ * @ret rc Return status code
|
|
1270
|
+ */
|
|
1271
|
+static int arbel_create_eq ( struct arbel *arbel ) {
|
|
1272
|
+ struct arbel_event_queue *arbel_eq = &arbel->eq;
|
|
1273
|
+ struct arbelprm_eqc eqctx;
|
|
1274
|
+ struct arbelprm_event_mask mask;
|
|
1275
|
+ unsigned int i;
|
|
1276
|
+ int rc;
|
|
1277
|
+
|
|
1278
|
+ /* Select event queue number */
|
|
1279
|
+ arbel_eq->eqn = arbel->limits.reserved_eqs;
|
|
1280
|
+
|
|
1281
|
+ /* Calculate doorbell address */
|
|
1282
|
+ arbel_eq->doorbell = ( arbel->eq_ci_doorbells +
|
|
1283
|
+ ARBEL_DB_EQ_OFFSET ( arbel_eq->eqn ) );
|
|
1284
|
+
|
|
1285
|
+ /* Allocate event queue itself */
|
|
1286
|
+ arbel_eq->eqe_size =
|
|
1287
|
+ ( ARBEL_NUM_EQES * sizeof ( arbel_eq->eqe[0] ) );
|
|
1288
|
+ arbel_eq->eqe = malloc_dma ( arbel_eq->eqe_size,
|
|
1289
|
+ sizeof ( arbel_eq->eqe[0] ) );
|
|
1290
|
+ if ( ! arbel_eq->eqe ) {
|
|
1291
|
+ rc = -ENOMEM;
|
|
1292
|
+ goto err_eqe;
|
|
1293
|
+ }
|
|
1294
|
+ memset ( arbel_eq->eqe, 0, arbel_eq->eqe_size );
|
|
1295
|
+ for ( i = 0 ; i < ARBEL_NUM_EQES ; i++ ) {
|
|
1296
|
+ MLX_FILL_1 ( &arbel_eq->eqe[i].generic, 7, owner, 1 );
|
|
1297
|
+ }
|
|
1298
|
+ barrier();
|
|
1299
|
+
|
|
1300
|
+ /* Hand queue over to hardware */
|
|
1301
|
+ memset ( &eqctx, 0, sizeof ( eqctx ) );
|
|
1302
|
+ MLX_FILL_1 ( &eqctx, 0, st, 0xa /* "Fired" */ );
|
|
1303
|
+ MLX_FILL_1 ( &eqctx, 2,
|
|
1304
|
+ start_address_l, virt_to_phys ( arbel_eq->eqe ) );
|
|
1305
|
+ MLX_FILL_1 ( &eqctx, 3, log_eq_size, fls ( ARBEL_NUM_EQES - 1 ) );
|
|
1306
|
+ MLX_FILL_1 ( &eqctx, 6, pd, ARBEL_GLOBAL_PD );
|
|
1307
|
+ MLX_FILL_1 ( &eqctx, 7, lkey, arbel->reserved_lkey );
|
|
1308
|
+ if ( ( rc = arbel_cmd_sw2hw_eq ( arbel, arbel_eq->eqn,
|
|
1309
|
+ &eqctx ) ) != 0 ) {
|
|
1310
|
+ DBGC ( arbel, "Arbel %p SW2HW_EQ failed: %s\n",
|
|
1311
|
+ arbel, strerror ( rc ) );
|
|
1312
|
+ goto err_sw2hw_eq;
|
|
1313
|
+ }
|
|
1314
|
+
|
|
1315
|
+ /* Map events to this event queue */
|
|
1316
|
+ memset ( &mask, 0, sizeof ( mask ) );
|
|
1317
|
+ MLX_FILL_1 ( &mask, 1, port_state_change, 1 );
|
|
1318
|
+ if ( ( rc = arbel_cmd_map_eq ( arbel,
|
|
1319
|
+ ( ARBEL_MAP_EQ | arbel_eq->eqn ),
|
|
1320
|
+ &mask ) ) != 0 ) {
|
|
1321
|
+ DBGC ( arbel, "Arbel %p MAP_EQ failed: %s\n",
|
|
1322
|
+ arbel, strerror ( rc ) );
|
|
1323
|
+ goto err_map_eq;
|
|
1324
|
+ }
|
|
1325
|
+
|
|
1326
|
+ DBGC ( arbel, "Arbel %p EQN %#lx ring at [%p,%p])\n",
|
|
1327
|
+ arbel, arbel_eq->eqn, arbel_eq->eqe,
|
|
1328
|
+ ( ( ( void * ) arbel_eq->eqe ) + arbel_eq->eqe_size ) );
|
|
1329
|
+ return 0;
|
|
1330
|
+
|
|
1331
|
+ err_map_eq:
|
|
1332
|
+ arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn, &eqctx );
|
|
1333
|
+ err_sw2hw_eq:
|
|
1334
|
+ free_dma ( arbel_eq->eqe, arbel_eq->eqe_size );
|
|
1335
|
+ err_eqe:
|
|
1336
|
+ memset ( arbel_eq, 0, sizeof ( *arbel_eq ) );
|
|
1337
|
+ return rc;
|
|
1338
|
+}
|
|
1339
|
+
|
|
1340
|
+/**
|
|
1341
|
+ * Destroy event queue
|
|
1342
|
+ *
|
|
1343
|
+ * @v arbel Arbel device
|
|
1344
|
+ */
|
|
1345
|
+static void arbel_destroy_eq ( struct arbel *arbel ) {
|
|
1346
|
+ struct arbel_event_queue *arbel_eq = &arbel->eq;
|
|
1347
|
+ struct arbelprm_eqc eqctx;
|
|
1348
|
+ struct arbelprm_event_mask mask;
|
|
1349
|
+ int rc;
|
|
1350
|
+
|
|
1351
|
+ /* Unmap events from event queue */
|
|
1352
|
+ memset ( &mask, 0, sizeof ( mask ) );
|
|
1353
|
+ MLX_FILL_1 ( &mask, 1, port_state_change, 1 );
|
|
1354
|
+ if ( ( rc = arbel_cmd_map_eq ( arbel,
|
|
1355
|
+ ( ARBEL_UNMAP_EQ | arbel_eq->eqn ),
|
|
1356
|
+ &mask ) ) != 0 ) {
|
|
1357
|
+ DBGC ( arbel, "Arbel %p FATAL MAP_EQ failed to unmap: %s\n",
|
|
1358
|
+ arbel, strerror ( rc ) );
|
|
1359
|
+ /* Continue; HCA may die but system should survive */
|
|
1360
|
+ }
|
|
1361
|
+
|
|
1362
|
+ /* Take ownership back from hardware */
|
|
1363
|
+ if ( ( rc = arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn,
|
|
1364
|
+ &eqctx ) ) != 0 ) {
|
|
1365
|
+ DBGC ( arbel, "Arbel %p FATAL HW2SW_EQ failed: %s\n",
|
|
1366
|
+ arbel, strerror ( rc ) );
|
|
1367
|
+ /* Leak memory and return; at least we avoid corruption */
|
|
1368
|
+ return;
|
|
1369
|
+ }
|
|
1370
|
+
|
|
1371
|
+ /* Free memory */
|
|
1372
|
+ free_dma ( arbel_eq->eqe, arbel_eq->eqe_size );
|
|
1373
|
+ memset ( arbel_eq, 0, sizeof ( *arbel_eq ) );
|
|
1374
|
+}
|
|
1375
|
+
|
|
1376
|
+/**
|
|
1377
|
+ * Handle port state event
|
|
1378
|
+ *
|
|
1379
|
+ * @v arbel Arbel device
|
|
1380
|
+ * @v eqe Port state change event queue entry
|
|
1381
|
+ */
|
|
1382
|
+static void arbel_event_port_state_change ( struct arbel *arbel,
|
|
1383
|
+ union arbelprm_event_entry *eqe){
|
|
1384
|
+ unsigned int port;
|
|
1385
|
+ int link_up;
|
|
1386
|
+
|
|
1387
|
+ /* Get port and link status */
|
|
1388
|
+ port = ( MLX_GET ( &eqe->port_state_change, data.p ) - 1 );
|
|
1389
|
+ link_up = ( MLX_GET ( &eqe->generic, event_sub_type ) & 0x04 );
|
|
1390
|
+ DBGC ( arbel, "Arbel %p port %d link %s\n", arbel, ( port + 1 ),
|
|
1391
|
+ ( link_up ? "up" : "down" ) );
|
|
1392
|
+
|
|
1393
|
+ /* Sanity check */
|
|
1394
|
+ if ( port >= ARBEL_NUM_PORTS ) {
|
|
1395
|
+ DBGC ( arbel, "Arbel %p port %d does not exist!\n",
|
|
1396
|
+ arbel, ( port + 1 ) );
|
|
1397
|
+ return;
|
|
1398
|
+ }
|
|
1399
|
+
|
|
1400
|
+ /* Notify Infiniband core of link state change */
|
|
1401
|
+ ib_link_state_changed ( arbel->ibdev[port] );
|
|
1402
|
+}
|
|
1403
|
+
|
1233
|
1404
|
/**
|
1234
|
1405
|
* Poll event queue
|
1235
|
1406
|
*
|
|
@@ -1237,9 +1408,48 @@ static void arbel_poll_cq ( struct ib_device *ibdev,
|
1237
|
1408
|
*/
|
1238
|
1409
|
static void arbel_poll_eq ( struct ib_device *ibdev ) {
|
1239
|
1410
|
struct arbel *arbel = ib_get_drvdata ( ibdev );
|
|
1411
|
+ struct arbel_event_queue *arbel_eq = &arbel->eq;
|
|
1412
|
+ union arbelprm_event_entry *eqe;
|
|
1413
|
+ unsigned int eqe_idx_mask;
|
|
1414
|
+ unsigned int event_type;
|
1240
|
1415
|
|
1241
|
|
- /* TODO */
|
1242
|
|
- ( void ) arbel;
|
|
1416
|
+ while ( 1 ) {
|
|
1417
|
+ /* Look for event entry */
|
|
1418
|
+ eqe_idx_mask = ( ARBEL_NUM_EQES - 1 );
|
|
1419
|
+ eqe = &arbel_eq->eqe[arbel_eq->next_idx & eqe_idx_mask];
|
|
1420
|
+ if ( MLX_GET ( &eqe->generic, owner ) != 0 ) {
|
|
1421
|
+ /* Entry still owned by hardware; end of poll */
|
|
1422
|
+ break;
|
|
1423
|
+ }
|
|
1424
|
+ DBGCP ( arbel, "Arbel %p event:\n", arbel );
|
|
1425
|
+ DBGCP_HD ( arbel, eqe, sizeof ( *eqe ) );
|
|
1426
|
+
|
|
1427
|
+ /* Handle event */
|
|
1428
|
+ event_type = MLX_GET ( &eqe->generic, event_type );
|
|
1429
|
+ switch ( event_type ) {
|
|
1430
|
+ case ARBEL_EV_PORT_STATE_CHANGE:
|
|
1431
|
+ arbel_event_port_state_change ( arbel, eqe );
|
|
1432
|
+ break;
|
|
1433
|
+ default:
|
|
1434
|
+ DBGC ( arbel, "Arbel %p unrecognised event type "
|
|
1435
|
+ "%#x:\n", arbel, event_type );
|
|
1436
|
+ DBGC_HD ( arbel, eqe, sizeof ( *eqe ) );
|
|
1437
|
+ break;
|
|
1438
|
+ }
|
|
1439
|
+
|
|
1440
|
+ /* Return ownership to hardware */
|
|
1441
|
+ MLX_FILL_1 ( &eqe->generic, 7, owner, 1 );
|
|
1442
|
+ barrier();
|
|
1443
|
+
|
|
1444
|
+ /* Update event queue's index */
|
|
1445
|
+ arbel_eq->next_idx++;
|
|
1446
|
+
|
|
1447
|
+ /* Ring doorbell */
|
|
1448
|
+ DBGCP ( arbel, "Ringing doorbell %08lx with %08lx\n",
|
|
1449
|
+ virt_to_phys ( arbel_eq->doorbell ),
|
|
1450
|
+ arbel_eq->next_idx );
|
|
1451
|
+ writel ( arbel_eq->next_idx, arbel_eq->doorbell );
|
|
1452
|
+ }
|
1243
|
1453
|
}
|
1244
|
1454
|
|
1245
|
1455
|
/***************************************************************************
|
|
@@ -1473,6 +1683,7 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
|
1473
|
1683
|
unsigned int log2_fw_pages;
|
1474
|
1684
|
size_t fw_size;
|
1475
|
1685
|
physaddr_t fw_base;
|
|
1686
|
+ uint64_t eq_set_ci_base_addr;
|
1476
|
1687
|
int rc;
|
1477
|
1688
|
|
1478
|
1689
|
/* Get firmware parameters */
|
|
@@ -1489,6 +1700,10 @@ static int arbel_start_firmware ( struct arbel *arbel ) {
|
1489
|
1700
|
fw_pages = ( 1 << log2_fw_pages );
|
1490
|
1701
|
DBGC ( arbel, "Arbel %p requires %d kB for firmware\n",
|
1491
|
1702
|
arbel, ( fw_pages * 4 ) );
|
|
1703
|
+ eq_set_ci_base_addr =
|
|
1704
|
+ ( ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_h ) << 32 ) |
|
|
1705
|
+ ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_l ) ) );
|
|
1706
|
+ arbel->eq_ci_doorbells = ioremap ( eq_set_ci_base_addr, 0x200 );
|
1492
|
1707
|
|
1493
|
1708
|
/* Enable locally-attached memory. Ignore failure; there may
|
1494
|
1709
|
* be no attached memory.
|
|
@@ -1591,6 +1806,7 @@ static int arbel_get_limits ( struct arbel *arbel ) {
|
1591
|
1806
|
arbel->limits.reserved_cqs =
|
1592
|
1807
|
( 1 << MLX_GET ( &dev_lim, log2_rsvd_cqs ) );
|
1593
|
1808
|
arbel->limits.cqc_entry_size = MLX_GET ( &dev_lim, cqc_entry_sz );
|
|
1809
|
+ arbel->limits.reserved_eqs = MLX_GET ( &dev_lim, num_rsvd_eqs );
|
1594
|
1810
|
arbel->limits.reserved_mtts =
|
1595
|
1811
|
( 1 << MLX_GET ( &dev_lim, log2_rsvd_mtts ) );
|
1596
|
1812
|
arbel->limits.mtt_entry_size = MLX_GET ( &dev_lim, mtt_entry_sz );
|
|
@@ -1721,7 +1937,7 @@ static int arbel_alloc_icm ( struct arbel *arbel,
|
1721
|
1937
|
icm_offset += icm_usage ( log_num_rdbs, 32 );
|
1722
|
1938
|
|
1723
|
1939
|
/* Event queue contexts */
|
1724
|
|
- log_num_eqs = 6;
|
|
1940
|
+ log_num_eqs = fls ( arbel->limits.reserved_eqs + ARBEL_MAX_EQS - 1 );
|
1725
|
1941
|
MLX_FILL_2 ( init_hca, 33,
|
1726
|
1942
|
qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l,
|
1727
|
1943
|
( icm_offset >> 6 ),
|
|
@@ -1950,6 +2166,10 @@ static int arbel_probe ( struct pci_device *pci,
|
1950
|
2166
|
if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 )
|
1951
|
2167
|
goto err_setup_mpt;
|
1952
|
2168
|
|
|
2169
|
+ /* Set up event queue */
|
|
2170
|
+ if ( ( rc = arbel_create_eq ( arbel ) ) != 0 )
|
|
2171
|
+ goto err_create_eq;
|
|
2172
|
+
|
1953
|
2173
|
/* Register Infiniband devices */
|
1954
|
2174
|
for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) {
|
1955
|
2175
|
if ( ( rc = register_ibdev ( arbel->ibdev[i] ) ) != 0 ) {
|
|
@@ -1965,6 +2185,8 @@ static int arbel_probe ( struct pci_device *pci,
|
1965
|
2185
|
err_register_ibdev:
|
1966
|
2186
|
for ( ; i >= 0 ; i-- )
|
1967
|
2187
|
unregister_ibdev ( arbel->ibdev[i] );
|
|
2188
|
+ arbel_destroy_eq ( arbel );
|
|
2189
|
+ err_create_eq:
|
1968
|
2190
|
err_setup_mpt:
|
1969
|
2191
|
arbel_cmd_close_hca ( arbel );
|
1970
|
2192
|
err_init_hca:
|
|
@@ -1997,6 +2219,7 @@ static void arbel_remove ( struct pci_device *pci ) {
|
1997
|
2219
|
|
1998
|
2220
|
for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- )
|
1999
|
2221
|
unregister_ibdev ( arbel->ibdev[i] );
|
|
2222
|
+ arbel_destroy_eq ( arbel );
|
2000
|
2223
|
arbel_cmd_close_hca ( arbel );
|
2001
|
2224
|
arbel_free_icm ( arbel );
|
2002
|
2225
|
arbel_stop_firmware ( arbel );
|