1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2/* Copyright (c) 2019 Mellanox Technologies */
3
4#include <linux/mlx5/vport.h>
5#include <rdma/ib_verbs.h>
6#include <net/addrconf.h>
7
8#include "lib/mlx5.h"
9#include "eswitch.h"
10#include "fs_core.h"
11#include "rdma.h"
12
13static void mlx5_rdma_disable_roce_steering(struct mlx5_core_dev *dev)
14{
15 struct mlx5_core_roce *roce = &dev->priv.roce;
16
17 mlx5_del_flow_rules(fr: roce->allow_rule);
18 mlx5_destroy_flow_group(fg: roce->fg);
19 mlx5_destroy_flow_table(ft: roce->ft);
20}
21
22static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev)
23{
24 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
25 struct mlx5_core_roce *roce = &dev->priv.roce;
26 struct mlx5_flow_handle *flow_rule = NULL;
27 struct mlx5_flow_table_attr ft_attr = {};
28 struct mlx5_flow_namespace *ns = NULL;
29 struct mlx5_flow_act flow_act = {};
30 struct mlx5_flow_spec *spec;
31 struct mlx5_flow_table *ft;
32 struct mlx5_flow_group *fg;
33 struct mlx5_eswitch *esw;
34 u32 *flow_group_in;
35 int err;
36
37 if (!(MLX5_CAP_FLOWTABLE_RDMA_RX(dev, ft_support) &&
38 MLX5_CAP_FLOWTABLE_RDMA_RX(dev, table_miss_action_domain)))
39 return -EOPNOTSUPP;
40
41 flow_group_in = kvzalloc(size: inlen, GFP_KERNEL);
42 if (!flow_group_in)
43 return -ENOMEM;
44 spec = kvzalloc(size: sizeof(*spec), GFP_KERNEL);
45 if (!spec) {
46 kvfree(addr: flow_group_in);
47 return -ENOMEM;
48 }
49
50 ns = mlx5_get_flow_namespace(dev, type: MLX5_FLOW_NAMESPACE_RDMA_RX_KERNEL);
51 if (!ns) {
52 mlx5_core_err(dev, "Failed to get RDMA RX namespace");
53 err = -EOPNOTSUPP;
54 goto free;
55 }
56
57 ft_attr.max_fte = 1;
58 ft = mlx5_create_flow_table(ns, ft_attr: &ft_attr);
59 if (IS_ERR(ptr: ft)) {
60 mlx5_core_err(dev, "Failed to create RDMA RX flow table");
61 err = PTR_ERR(ptr: ft);
62 goto free;
63 }
64
65 esw = dev->priv.eswitch;
66 mlx5_esw_set_flow_group_source_port(esw, flow_group_in, match_params: 0);
67
68 fg = mlx5_create_flow_group(ft, in: flow_group_in);
69 if (IS_ERR(ptr: fg)) {
70 err = PTR_ERR(ptr: fg);
71 mlx5_core_err(dev, "Failed to create RDMA RX flow group err(%d)\n", err);
72 goto destroy_flow_table;
73 }
74
75 mlx5_esw_set_spec_source_port(esw, vport: esw->manager_vport, spec);
76
77 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
78 flow_rule = mlx5_add_flow_rules(ft, spec, flow_act: &flow_act, NULL, num_dest: 0);
79 if (IS_ERR(ptr: flow_rule)) {
80 err = PTR_ERR(ptr: flow_rule);
81 mlx5_core_err(dev, "Failed to add RoCE allow rule, err=%d\n",
82 err);
83 goto destroy_flow_group;
84 }
85
86 kvfree(addr: spec);
87 kvfree(addr: flow_group_in);
88 roce->ft = ft;
89 roce->fg = fg;
90 roce->allow_rule = flow_rule;
91
92 return 0;
93
94destroy_flow_group:
95 mlx5_destroy_flow_group(fg);
96destroy_flow_table:
97 mlx5_destroy_flow_table(ft);
98free:
99 kvfree(addr: spec);
100 kvfree(addr: flow_group_in);
101 return err;
102}
103
104static void mlx5_rdma_del_roce_addr(struct mlx5_core_dev *dev)
105{
106 mlx5_core_roce_gid_set(dev, index: 0, roce_version: MLX5_ROCE_VERSION_2, roce_l3_type: 0,
107 NULL, NULL, vlan: false, vlan_id: 0, port_num: 1);
108}
109
110static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid *gid)
111{
112 u8 hw_id[ETH_ALEN];
113
114 mlx5_query_mac_address(mdev: dev, addr: hw_id);
115 gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
116 addrconf_addr_eui48(eui: &gid->raw[8], addr: hw_id);
117}
118
119static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev)
120{
121 union ib_gid gid;
122 u8 mac[ETH_ALEN];
123
124 mlx5_rdma_make_default_gid(dev, gid: &gid);
125 return mlx5_core_roce_gid_set(dev, index: 0,
126 roce_version: MLX5_ROCE_VERSION_2,
127 roce_l3_type: 0, gid: gid.raw, mac,
128 vlan: false, vlan_id: 0, port_num: 1);
129}
130
131void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev)
132{
133 struct mlx5_core_roce *roce = &dev->priv.roce;
134
135 if (!roce->ft)
136 return;
137
138 mlx5_rdma_disable_roce_steering(dev);
139 mlx5_rdma_del_roce_addr(dev);
140 mlx5_nic_vport_disable_roce(mdev: dev);
141}
142
143void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev)
144{
145 int err;
146
147 if (!MLX5_CAP_GEN(dev, roce))
148 return;
149
150 err = mlx5_nic_vport_enable_roce(mdev: dev);
151 if (err) {
152 mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err);
153 return;
154 }
155
156 err = mlx5_rdma_add_roce_addr(dev);
157 if (err) {
158 mlx5_core_err(dev, "Failed to add RoCE address: %d\n", err);
159 goto disable_roce;
160 }
161
162 err = mlx5_rdma_enable_roce_steering(dev);
163 if (err) {
164 mlx5_core_err(dev, "Failed to enable RoCE steering: %d\n", err);
165 goto del_roce_addr;
166 }
167
168 return;
169
170del_roce_addr:
171 mlx5_rdma_del_roce_addr(dev);
172disable_roce:
173 mlx5_nic_vport_disable_roce(mdev: dev);
174}
175

source code of linux/drivers/net/ethernet/mellanox/mlx5/core/rdma.c