Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sfc: Add use of shared RSS contexts.

Allow PFs to allocate shared RSS contexts if we exhaust our
exclusive RSS contexts. Make VFs use shared RSS contexts in
all cases.
Spruce up error handling so that the shadow copy of the RSS
table is updated after successful update, rather than in all
cases, so that we report the actual contents of the RSS table
after a failure to set it, rather than what we'd like it to be.

Populate context_size parameter when vacuously allocating RSS
context of size 1.

Signed-off-by: Shradha Shah <sshah@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Jon Cooper and committed by
David S. Miller
267c0157 267d9d73

+177 -36
+135 -22
drivers/net/ethernet/sfc/ef10.c
··· 31 31 32 32 /* The reserved RSS context value */ 33 33 #define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff 34 + /* The maximum size of a shared RSS context */ 35 + /* TODO: this should really be from the mcdi protocol export */ 36 + #define EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE 64UL 34 37 35 38 /* The filter table(s) are managed by firmware and we have write-only 36 39 * access. When removing filters we must identify them to the ··· 81 78 /* An arbitrary search limit for the software hash table */ 82 79 #define EFX_EF10_FILTER_SEARCH_LIMIT 200 83 80 84 - static void efx_ef10_rx_push_rss_config(struct efx_nic *efx); 85 81 static void efx_ef10_rx_free_indir_table(struct efx_nic *efx); 86 82 static void efx_ef10_filter_table_remove(struct efx_nic *efx); 87 83 ··· 753 751 nic_data->must_restore_piobufs = false; 754 752 } 755 753 756 - efx_ef10_rx_push_rss_config(efx); 754 + /* don't fail init if RSS setup doesn't work */ 755 + efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table); 756 + 757 757 return 0; 758 758 } 759 759 ··· 1459 1455 } 1460 1456 } 1461 1457 1462 - static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context) 1458 + static int efx_ef10_alloc_rss_context(struct efx_nic *efx, u32 *context, 1459 + bool exclusive, unsigned *context_size) 1463 1460 { 1464 1461 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN); 1465 1462 MCDI_DECLARE_BUF(outbuf, MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN); 1466 1463 struct efx_ef10_nic_data *nic_data = efx->nic_data; 1467 1464 size_t outlen; 1468 1465 int rc; 1466 + u32 alloc_type = exclusive ? 1467 + MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE : 1468 + MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_SHARED; 1469 + unsigned rss_spread = exclusive ? 1470 + efx->rss_spread : 1471 + min(rounddown_pow_of_two(efx->rss_spread), 1472 + EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE); 1473 + 1474 + if (!exclusive && rss_spread == 1) { 1475 + *context = EFX_EF10_RSS_CONTEXT_INVALID; 1476 + if (context_size) 1477 + *context_size = 1; 1478 + return 0; 1479 + } 1469 1480 1470 1481 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_UPSTREAM_PORT_ID, 1471 1482 nic_data->vport_id); 1472 - MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE, 1473 - MC_CMD_RSS_CONTEXT_ALLOC_IN_TYPE_EXCLUSIVE); 1474 - MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, 1475 - EFX_MAX_CHANNELS); 1483 + MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_TYPE, alloc_type); 1484 + MCDI_SET_DWORD(inbuf, RSS_CONTEXT_ALLOC_IN_NUM_QUEUES, rss_spread); 1476 1485 1477 1486 rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_ALLOC, inbuf, sizeof(inbuf), 1478 1487 outbuf, sizeof(outbuf), &outlen); ··· 1496 1479 return -EIO; 1497 1480 1498 1481 *context = MCDI_DWORD(outbuf, RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID); 1482 + 1483 + if (context_size) 1484 + *context_size = rss_spread; 1499 1485 1500 1486 return 0; 1501 1487 } ··· 1516 1496 WARN_ON(rc != 0); 1517 1497 } 1518 1498 1519 - static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context) 1499 + static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context, 1500 + const u32 *rx_indir_table) 1520 1501 { 1521 1502 MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN); 1522 1503 MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN); ··· 1531 1510 for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i) 1532 1511 MCDI_PTR(tablebuf, 1533 1512 RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] = 1534 - (u8) efx->rx_indir_table[i]; 1513 + (u8) rx_indir_table[i]; 1535 1514 1536 1515 rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_TABLE, tablebuf, 1537 1516 sizeof(tablebuf), NULL, 0, NULL); ··· 1559 1538 nic_data->rx_rss_context = EFX_EF10_RSS_CONTEXT_INVALID; 1560 1539 } 1561 1540 1562 - static void efx_ef10_rx_push_rss_config(struct efx_nic *efx) 1541 + static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx, 1542 + unsigned *context_size) 1543 + { 1544 + u32 new_rx_rss_context; 1545 + struct efx_ef10_nic_data *nic_data = efx->nic_data; 1546 + int rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context, 1547 + false, context_size); 1548 + 1549 + if (rc != 0) 1550 + return rc; 1551 + 1552 + nic_data->rx_rss_context = new_rx_rss_context; 1553 + nic_data->rx_rss_context_exclusive = false; 1554 + efx_set_default_rx_indir_table(efx); 1555 + return 0; 1556 + } 1557 + 1558 + static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx, 1559 + const u32 *rx_indir_table) 1563 1560 { 1564 1561 struct efx_ef10_nic_data *nic_data = efx->nic_data; 1565 1562 int rc; 1563 + u32 new_rx_rss_context; 1566 1564 1567 - netif_dbg(efx, drv, efx->net_dev, "pushing RSS config\n"); 1568 - 1569 - if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID) { 1570 - rc = efx_ef10_alloc_rss_context(efx, &nic_data->rx_rss_context); 1571 - if (rc != 0) 1572 - goto fail; 1565 + if (nic_data->rx_rss_context == EFX_EF10_RSS_CONTEXT_INVALID || 1566 + !nic_data->rx_rss_context_exclusive) { 1567 + rc = efx_ef10_alloc_rss_context(efx, &new_rx_rss_context, 1568 + true, NULL); 1569 + if (rc == -EOPNOTSUPP) 1570 + return rc; 1571 + else if (rc != 0) 1572 + goto fail1; 1573 + } else { 1574 + new_rx_rss_context = nic_data->rx_rss_context; 1573 1575 } 1574 1576 1575 - rc = efx_ef10_populate_rss_table(efx, nic_data->rx_rss_context); 1577 + rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context, 1578 + rx_indir_table); 1576 1579 if (rc != 0) 1577 - goto fail; 1580 + goto fail2; 1578 1581 1579 - return; 1582 + if (nic_data->rx_rss_context != new_rx_rss_context) 1583 + efx_ef10_rx_free_indir_table(efx); 1584 + nic_data->rx_rss_context = new_rx_rss_context; 1585 + nic_data->rx_rss_context_exclusive = true; 1586 + if (rx_indir_table != efx->rx_indir_table) 1587 + memcpy(efx->rx_indir_table, rx_indir_table, 1588 + sizeof(efx->rx_indir_table)); 1589 + return 0; 1580 1590 1581 - fail: 1591 + fail2: 1592 + if (new_rx_rss_context != nic_data->rx_rss_context) 1593 + efx_ef10_free_rss_context(efx, new_rx_rss_context); 1594 + fail1: 1582 1595 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); 1596 + return rc; 1597 + } 1598 + 1599 + static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user, 1600 + const u32 *rx_indir_table) 1601 + { 1602 + int rc; 1603 + 1604 + if (efx->rss_spread == 1) 1605 + return 0; 1606 + 1607 + rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table); 1608 + 1609 + if (rc == -ENOBUFS && !user) { 1610 + unsigned context_size; 1611 + bool mismatch = false; 1612 + size_t i; 1613 + 1614 + for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table) && !mismatch; 1615 + i++) 1616 + mismatch = rx_indir_table[i] != 1617 + ethtool_rxfh_indir_default(i, efx->rss_spread); 1618 + 1619 + rc = efx_ef10_rx_push_shared_rss_config(efx, &context_size); 1620 + if (rc == 0) { 1621 + if (context_size != efx->rss_spread) 1622 + netif_warn(efx, probe, efx->net_dev, 1623 + "Could not allocate an exclusive RSS" 1624 + " context; allocated a shared one of" 1625 + " different size." 1626 + " Wanted %u, got %u.\n", 1627 + efx->rss_spread, context_size); 1628 + else if (mismatch) 1629 + netif_warn(efx, probe, efx->net_dev, 1630 + "Could not allocate an exclusive RSS" 1631 + " context; allocated a shared one but" 1632 + " could not apply custom" 1633 + " indirection.\n"); 1634 + else 1635 + netif_info(efx, probe, efx->net_dev, 1636 + "Could not allocate an exclusive RSS" 1637 + " context; allocated a shared one.\n"); 1638 + } 1639 + } 1640 + return rc; 1641 + } 1642 + 1643 + static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user, 1644 + const u32 *rx_indir_table 1645 + __attribute__ ((unused))) 1646 + { 1647 + struct efx_ef10_nic_data *nic_data = efx->nic_data; 1648 + 1649 + if (user) 1650 + return -EOPNOTSUPP; 1651 + if (nic_data->rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID) 1652 + return 0; 1653 + return efx_ef10_rx_push_shared_rss_config(efx, NULL); 1583 1654 } 1584 1655 1585 1656 static int efx_ef10_rx_probe(struct efx_rx_queue *rx_queue) ··· 3851 3738 .tx_init = efx_ef10_tx_init, 3852 3739 .tx_remove = efx_ef10_tx_remove, 3853 3740 .tx_write = efx_ef10_tx_write, 3854 - .rx_push_rss_config = efx_ef10_rx_push_rss_config, 3741 + .rx_push_rss_config = efx_ef10_vf_rx_push_rss_config, 3855 3742 .rx_probe = efx_ef10_rx_probe, 3856 3743 .rx_init = efx_ef10_rx_init, 3857 3744 .rx_remove = efx_ef10_rx_remove, ··· 3950 3837 .tx_init = efx_ef10_tx_init, 3951 3838 .tx_remove = efx_ef10_tx_remove, 3952 3839 .tx_write = efx_ef10_tx_write, 3953 - .rx_push_rss_config = efx_ef10_rx_push_rss_config, 3840 + .rx_push_rss_config = efx_ef10_pf_rx_push_rss_config, 3954 3841 .rx_probe = efx_ef10_rx_probe, 3955 3842 .rx_init = efx_ef10_rx_init, 3956 3843 .rx_remove = efx_ef10_rx_remove,
+12 -5
drivers/net/ethernet/sfc/efx.c
··· 1290 1290 pci_disable_device(efx->pci_dev); 1291 1291 } 1292 1292 1293 + void efx_set_default_rx_indir_table(struct efx_nic *efx) 1294 + { 1295 + size_t i; 1296 + 1297 + for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) 1298 + efx->rx_indir_table[i] = 1299 + ethtool_rxfh_indir_default(i, efx->rss_spread); 1300 + } 1301 + 1293 1302 static unsigned int efx_wanted_parallelism(struct efx_nic *efx) 1294 1303 { 1295 1304 cpumask_var_t thread_mask; ··· 1616 1607 1617 1608 static int efx_probe_nic(struct efx_nic *efx) 1618 1609 { 1619 - size_t i; 1620 1610 int rc; 1621 1611 1622 1612 netif_dbg(efx, probe, efx->net_dev, "creating NIC\n"); ··· 1638 1630 goto fail2; 1639 1631 1640 1632 if (efx->n_channels > 1) 1641 - netdev_rss_key_fill(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); 1642 - for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) 1643 - efx->rx_indir_table[i] = 1644 - ethtool_rxfh_indir_default(i, efx->rss_spread); 1633 + netdev_rss_key_fill(&efx->rx_hash_key, 1634 + sizeof(efx->rx_hash_key)); 1635 + efx_set_default_rx_indir_table(efx); 1645 1636 1646 1637 netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); 1647 1638 netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
+1
drivers/net/ethernet/sfc/efx.h
··· 34 34 extern unsigned int efx_piobuf_size; 35 35 36 36 /* RX */ 37 + void efx_set_default_rx_indir_table(struct efx_nic *efx); 37 38 void efx_rx_config_page_split(struct efx_nic *efx); 38 39 int efx_probe_rx_queue(struct efx_rx_queue *rx_queue); 39 40 void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
+2 -3
drivers/net/ethernet/sfc/ethtool.c
··· 1109 1109 return -EOPNOTSUPP; 1110 1110 if (!indir) 1111 1111 return 0; 1112 - memcpy(efx->rx_indir_table, indir, sizeof(efx->rx_indir_table)); 1113 - efx->type->rx_push_rss_config(efx); 1114 - return 0; 1112 + 1113 + return efx->type->rx_push_rss_config(efx, true, indir); 1115 1114 } 1116 1115 1117 1116 static int efx_ethtool_get_ts_info(struct net_device *net_dev,
+16 -3
drivers/net/ethernet/sfc/falcon.c
··· 477 477 * 478 478 ************************************************************************** 479 479 */ 480 + static int dummy_rx_push_rss_config(struct efx_nic *efx, bool user, 481 + const u32 *rx_indir_table) 482 + { 483 + (void) efx; 484 + (void) user; 485 + (void) rx_indir_table; 486 + return -ENOSYS; 487 + } 480 488 481 - static void falcon_b0_rx_push_rss_config(struct efx_nic *efx) 489 + static int falcon_b0_rx_push_rss_config(struct efx_nic *efx, bool user, 490 + const u32 *rx_indir_table) 482 491 { 483 492 efx_oword_t temp; 484 493 494 + (void) user; 485 495 /* Set hash key for IPv4 */ 486 496 memcpy(&temp, efx->rx_hash_key, sizeof(temp)); 487 497 efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); 488 498 499 + memcpy(efx->rx_indir_table, rx_indir_table, 500 + sizeof(efx->rx_indir_table)); 489 501 efx_farch_rx_push_indir_table(efx); 502 + return 0; 490 503 } 491 504 492 505 /************************************************************************** ··· 2520 2507 falcon_init_rx_cfg(efx); 2521 2508 2522 2509 if (efx_nic_rev(efx) >= EFX_REV_FALCON_B0) { 2523 - falcon_b0_rx_push_rss_config(efx); 2510 + falcon_b0_rx_push_rss_config(efx, false, efx->rx_indir_table); 2524 2511 2525 2512 /* Set destination of both TX and RX Flush events */ 2526 2513 EFX_POPULATE_OWORD_1(temp, FRF_BZ_FLS_EVQ_ID, 0); ··· 2743 2730 .tx_init = efx_farch_tx_init, 2744 2731 .tx_remove = efx_farch_tx_remove, 2745 2732 .tx_write = efx_farch_tx_write, 2746 - .rx_push_rss_config = efx_port_dummy_op_void, 2733 + .rx_push_rss_config = dummy_rx_push_rss_config, 2747 2734 .rx_probe = efx_farch_rx_probe, 2748 2735 .rx_init = efx_farch_rx_init, 2749 2736 .rx_remove = efx_farch_rx_remove,
+2 -1
drivers/net/ethernet/sfc/net_driver.h
··· 1276 1276 void (*tx_init)(struct efx_tx_queue *tx_queue); 1277 1277 void (*tx_remove)(struct efx_tx_queue *tx_queue); 1278 1278 void (*tx_write)(struct efx_tx_queue *tx_queue); 1279 - void (*rx_push_rss_config)(struct efx_nic *efx); 1279 + int (*rx_push_rss_config)(struct efx_nic *efx, bool user, 1280 + const u32 *rx_indir_table); 1280 1281 int (*rx_probe)(struct efx_rx_queue *rx_queue); 1281 1282 void (*rx_init)(struct efx_rx_queue *rx_queue); 1282 1283 void (*rx_remove)(struct efx_rx_queue *rx_queue);
+2
drivers/net/ethernet/sfc/nic.h
··· 485 485 * @must_restore_piobufs: Flag: PIO buffers have yet to be restored after MC 486 486 * reboot 487 487 * @rx_rss_context: Firmware handle for our RSS context 488 + * @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared 488 489 * @stats: Hardware statistics 489 490 * @workaround_35388: Flag: firmware supports workaround for bug 35388 490 491 * @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated ··· 514 513 unsigned int piobuf_handle[EF10_TX_PIOBUF_COUNT]; 515 514 bool must_restore_piobufs; 516 515 u32 rx_rss_context; 516 + bool rx_rss_context_exclusive; 517 517 u64 stats[EF10_STAT_COUNT]; 518 518 bool workaround_35388; 519 519 bool must_check_datapath_caps;
+7 -2
drivers/net/ethernet/sfc/siena.c
··· 324 324 return rc; 325 325 } 326 326 327 - static void siena_rx_push_rss_config(struct efx_nic *efx) 327 + static int siena_rx_push_rss_config(struct efx_nic *efx, bool user, 328 + const u32 *rx_indir_table) 328 329 { 329 330 efx_oword_t temp; 330 331 ··· 347 346 FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8); 348 347 efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3); 349 348 349 + memcpy(efx->rx_indir_table, rx_indir_table, 350 + sizeof(efx->rx_indir_table)); 350 351 efx_farch_rx_push_indir_table(efx); 352 + 353 + return 0; 351 354 } 352 355 353 356 /* This call performs hardware-specific global initialisation, such as ··· 394 389 EFX_RX_USR_BUF_SIZE >> 5); 395 390 efx_writeo(efx, &temp, FR_AZ_RX_CFG); 396 391 397 - siena_rx_push_rss_config(efx); 392 + siena_rx_push_rss_config(efx, false, efx->rx_indir_table); 398 393 399 394 /* Enable event logging */ 400 395 rc = efx_mcdi_log_ctrl(efx, true, false, 0);