diff options
author | Xue Chaojing <xuechaojing@huawei.com> | 2019-06-18 06:20:51 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-06-18 21:52:27 -0400 |
commit | 421e9526288b6ec241b46153493884277cbb533f (patch) | |
tree | 9927d167d971dd3eefef1845c899f4c2920c9e5d /drivers/net/ethernet/huawei/hinic/hinic_port.c | |
parent | net: stmmac: add sanity check to device_property_read_u32_array call (diff) | |
download | linux-421e9526288b6ec241b46153493884277cbb533f.tar.gz linux-421e9526288b6ec241b46153493884277cbb533f.tar.bz2 linux-421e9526288b6ec241b46153493884277cbb533f.zip |
hinic: add rss support
This patch adds rss support for the HINIC driver.
Signed-off-by: Xue Chaojing <xuechaojing@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/huawei/hinic/hinic_port.c')
-rw-r--r-- | drivers/net/ethernet/huawei/hinic/hinic_port.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/drivers/net/ethernet/huawei/hinic/hinic_port.c b/drivers/net/ethernet/huawei/hinic/hinic_port.c index 18a356db8b9c..1af18e4a9b17 100644 --- a/drivers/net/ethernet/huawei/hinic/hinic_port.c +++ b/drivers/net/ethernet/huawei/hinic/hinic_port.c @@ -544,3 +544,266 @@ int hinic_set_rx_lro_state(struct hinic_dev *nic_dev, u8 lro_en, return 0; } + +int hinic_rss_set_indir_tbl(struct hinic_dev *nic_dev, u32 tmpl_idx, + const u32 *indir_table) +{ + struct hinic_rss_indirect_tbl *indir_tbl; + struct hinic_func_to_io *func_to_io; + struct hinic_cmdq_buf cmd_buf; + struct hinic_hwdev *hwdev; + struct hinic_hwif *hwif; + struct pci_dev *pdev; + u32 indir_size; + u64 out_param; + int err, i; + u32 *temp; + + hwdev = nic_dev->hwdev; + func_to_io = &hwdev->func_to_io; + hwif = hwdev->hwif; + pdev = hwif->pdev; + + err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmd_buf); + if (err) { + dev_err(&pdev->dev, "Failed to allocate cmdq buf\n"); + return err; + } + + cmd_buf.size = sizeof(*indir_tbl); + + indir_tbl = cmd_buf.buf; + indir_tbl->group_index = cpu_to_be32(tmpl_idx); + + for (i = 0; i < HINIC_RSS_INDIR_SIZE; i++) { + indir_tbl->entry[i] = indir_table[i]; + + if (0x3 == (i & 0x3)) { + temp = (u32 *)&indir_tbl->entry[i - 3]; + *temp = cpu_to_be32(*temp); + } + } + + /* cfg the rss indirect table by command queue */ + indir_size = HINIC_RSS_INDIR_SIZE / 2; + indir_tbl->offset = 0; + indir_tbl->size = cpu_to_be32(indir_size); + + err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC, + HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE, + &cmd_buf, &out_param); + if (err || out_param != 0) { + dev_err(&pdev->dev, "Failed to set rss indir table\n"); + err = -EFAULT; + goto free_buf; + } + + indir_tbl->offset = cpu_to_be32(indir_size); + indir_tbl->size = cpu_to_be32(indir_size); + memcpy(&indir_tbl->entry[0], &indir_tbl->entry[indir_size], indir_size); + + err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC, + HINIC_UCODE_CMD_SET_RSS_INDIR_TABLE, + &cmd_buf, &out_param); + if (err || out_param != 0) { + dev_err(&pdev->dev, "Failed to set rss indir table\n"); + err = -EFAULT; + } + +free_buf: + hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmd_buf); + + return err; +} + +int hinic_set_rss_type(struct hinic_dev *nic_dev, u32 tmpl_idx, + struct hinic_rss_type rss_type) +{ + struct hinic_rss_context_tbl *ctx_tbl; + struct hinic_func_to_io *func_to_io; + struct hinic_cmdq_buf cmd_buf; + struct hinic_hwdev *hwdev; + struct hinic_hwif *hwif; + struct pci_dev *pdev; + u64 out_param; + u32 ctx = 0; + int err; + + hwdev = nic_dev->hwdev; + func_to_io = &hwdev->func_to_io; + hwif = hwdev->hwif; + pdev = hwif->pdev; + + err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmd_buf); + if (err) { + dev_err(&pdev->dev, "Failed to allocate cmd buf\n"); + return -ENOMEM; + } + + ctx |= HINIC_RSS_TYPE_SET(1, VALID) | + HINIC_RSS_TYPE_SET(rss_type.ipv4, IPV4) | + HINIC_RSS_TYPE_SET(rss_type.ipv6, IPV6) | + HINIC_RSS_TYPE_SET(rss_type.ipv6_ext, IPV6_EXT) | + HINIC_RSS_TYPE_SET(rss_type.tcp_ipv4, TCP_IPV4) | + HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6, TCP_IPV6) | + HINIC_RSS_TYPE_SET(rss_type.tcp_ipv6_ext, TCP_IPV6_EXT) | + HINIC_RSS_TYPE_SET(rss_type.udp_ipv4, UDP_IPV4) | + HINIC_RSS_TYPE_SET(rss_type.udp_ipv6, UDP_IPV6); + + cmd_buf.size = sizeof(struct hinic_rss_context_tbl); + + ctx_tbl = (struct hinic_rss_context_tbl *)cmd_buf.buf; + ctx_tbl->group_index = cpu_to_be32(tmpl_idx); + ctx_tbl->offset = 0; + ctx_tbl->size = sizeof(u32); + ctx_tbl->size = cpu_to_be32(ctx_tbl->size); + ctx_tbl->rsvd = 0; + ctx_tbl->ctx = cpu_to_be32(ctx); + + /* cfg the rss context table by command queue */ + err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC, + HINIC_UCODE_CMD_SET_RSS_CONTEXT_TABLE, + &cmd_buf, &out_param); + + hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmd_buf); + + if (err || out_param != 0) { + dev_err(&pdev->dev, "Failed to set rss context table, err: %d\n", + err); + return -EFAULT; + } + + return 0; +} + +int hinic_rss_set_template_tbl(struct hinic_dev *nic_dev, u32 template_id, + const u8 *temp) +{ + struct hinic_hwdev *hwdev = nic_dev->hwdev; + struct hinic_hwif *hwif = hwdev->hwif; + struct hinic_rss_key rss_key = { 0 }; + struct pci_dev *pdev = hwif->pdev; + u16 out_size; + int err; + + rss_key.func_id = HINIC_HWIF_FUNC_IDX(hwif); + rss_key.template_id = template_id; + memcpy(rss_key.key, temp, HINIC_RSS_KEY_SIZE); + + err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RSS_TEMPLATE_TBL, + &rss_key, sizeof(rss_key), + &rss_key, &out_size); + if (err || !out_size || rss_key.status) { + dev_err(&pdev->dev, + "Failed to set rss hash key, err: %d, status: 0x%x, out size: 0x%x\n", + err, rss_key.status, out_size); + return -EINVAL; + } + + return 0; +} + +int hinic_rss_set_hash_engine(struct hinic_dev *nic_dev, u8 template_id, + u8 type) +{ + struct hinic_rss_engine_type rss_engine = { 0 }; + struct hinic_hwdev *hwdev = nic_dev->hwdev; + struct hinic_hwif *hwif = hwdev->hwif; + struct pci_dev *pdev = hwif->pdev; + u16 out_size; + int err; + + rss_engine.func_id = HINIC_HWIF_FUNC_IDX(hwif); + rss_engine.hash_engine = type; + rss_engine.template_id = template_id; + + err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_SET_RSS_HASH_ENGINE, + &rss_engine, sizeof(rss_engine), + &rss_engine, &out_size); + if (err || !out_size || rss_engine.status) { + dev_err(&pdev->dev, + "Failed to set hash engine, err: %d, status: 0x%x, out size: 0x%x\n", + err, rss_engine.status, out_size); + return -EINVAL; + } + + return 0; +} + +int hinic_rss_cfg(struct hinic_dev *nic_dev, u8 rss_en, u8 template_id) +{ + struct hinic_hwdev *hwdev = nic_dev->hwdev; + struct hinic_rss_config rss_cfg = { 0 }; + struct hinic_hwif *hwif = hwdev->hwif; + struct pci_dev *pdev = hwif->pdev; + u16 out_size; + int err; + + rss_cfg.func_id = HINIC_HWIF_FUNC_IDX(hwif); + rss_cfg.rss_en = rss_en; + rss_cfg.template_id = template_id; + rss_cfg.rq_priority_number = 0; + + err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_CFG, + &rss_cfg, sizeof(rss_cfg), + &rss_cfg, &out_size); + if (err || !out_size || rss_cfg.status) { + dev_err(&pdev->dev, + "Failed to set rss cfg, err: %d, status: 0x%x, out size: 0x%x\n", + err, rss_cfg.status, out_size); + return -EINVAL; + } + + return 0; +} + +int hinic_rss_template_alloc(struct hinic_dev *nic_dev, u8 *tmpl_idx) +{ + struct hinic_rss_template_mgmt template_mgmt = { 0 }; + struct hinic_hwdev *hwdev = nic_dev->hwdev; + struct hinic_hwif *hwif = hwdev->hwif; + struct pci_dev *pdev = hwif->pdev; + u16 out_size; + int err; + + template_mgmt.func_id = HINIC_HWIF_FUNC_IDX(hwif); + template_mgmt.cmd = NIC_RSS_CMD_TEMP_ALLOC; + + err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR, + &template_mgmt, sizeof(template_mgmt), + &template_mgmt, &out_size); + if (err || !out_size || template_mgmt.status) { + dev_err(&pdev->dev, "Failed to alloc rss template, err: %d, status: 0x%x, out size: 0x%x\n", + err, template_mgmt.status, out_size); + return -EINVAL; + } + + *tmpl_idx = template_mgmt.template_id; + + return 0; +} + +int hinic_rss_template_free(struct hinic_dev *nic_dev, u8 tmpl_idx) +{ + struct hinic_rss_template_mgmt template_mgmt = { 0 }; + struct hinic_hwdev *hwdev = nic_dev->hwdev; + struct hinic_hwif *hwif = hwdev->hwif; + struct pci_dev *pdev = hwif->pdev; + u16 out_size; + int err; + + template_mgmt.func_id = HINIC_HWIF_FUNC_IDX(hwif); + template_mgmt.template_id = tmpl_idx; + template_mgmt.cmd = NIC_RSS_CMD_TEMP_FREE; + + err = hinic_port_msg_cmd(hwdev, HINIC_PORT_CMD_RSS_TEMP_MGR, + &template_mgmt, sizeof(template_mgmt), + &template_mgmt, &out_size); + if (err || !out_size || template_mgmt.status) { + dev_err(&pdev->dev, "Failed to free rss template, err: %d, status: 0x%x, out size: 0x%x\n", + err, template_mgmt.status, out_size); + return -EINVAL; + } + + return 0; +} |