1
2
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 if (!roce->ft)
18 return;
19
20 mlx5_del_flow_rules(roce->allow_rule);
21 mlx5_destroy_flow_group(roce->fg);
22 mlx5_destroy_flow_table(roce->ft);
23}
24
25static int mlx5_rdma_enable_roce_steering(struct mlx5_core_dev *dev)
26{
27 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
28 struct mlx5_core_roce *roce = &dev->priv.roce;
29 struct mlx5_flow_handle *flow_rule = NULL;
30 struct mlx5_flow_table_attr ft_attr = {};
31 struct mlx5_flow_namespace *ns = NULL;
32 struct mlx5_flow_act flow_act = {};
33 struct mlx5_flow_spec *spec;
34 struct mlx5_flow_table *ft;
35 struct mlx5_flow_group *fg;
36 void *match_criteria;
37 u32 *flow_group_in;
38 void *misc;
39 int err;
40
41 if (!(MLX5_CAP_FLOWTABLE_RDMA_RX(dev, ft_support) &&
42 MLX5_CAP_FLOWTABLE_RDMA_RX(dev, table_miss_action_domain)))
43 return -EOPNOTSUPP;
44
45 flow_group_in = kvzalloc(inlen, GFP_KERNEL);
46 if (!flow_group_in)
47 return -ENOMEM;
48 spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
49 if (!spec) {
50 kvfree(flow_group_in);
51 return -ENOMEM;
52 }
53
54 ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_RDMA_RX);
55 if (!ns) {
56 mlx5_core_err(dev, "Failed to get RDMA RX namespace");
57 err = -EOPNOTSUPP;
58 goto free;
59 }
60
61 ft_attr.max_fte = 1;
62 ft = mlx5_create_flow_table(ns, &ft_attr);
63 if (IS_ERR(ft)) {
64 mlx5_core_err(dev, "Failed to create RDMA RX flow table");
65 err = PTR_ERR(ft);
66 goto free;
67 }
68
69 MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
70 MLX5_MATCH_MISC_PARAMETERS);
71 match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in,
72 match_criteria);
73 MLX5_SET_TO_ONES(fte_match_param, match_criteria,
74 misc_parameters.source_port);
75
76 fg = mlx5_create_flow_group(ft, flow_group_in);
77 if (IS_ERR(fg)) {
78 err = PTR_ERR(fg);
79 mlx5_core_err(dev, "Failed to create RDMA RX flow group err(%d)\n", err);
80 goto destroy_flow_table;
81 }
82
83 spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
84 misc = MLX5_ADDR_OF(fte_match_param, spec->match_value,
85 misc_parameters);
86 MLX5_SET(fte_match_set_misc, misc, source_port,
87 dev->priv.eswitch->manager_vport);
88 misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
89 misc_parameters);
90 MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
91
92 flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
93 flow_rule = mlx5_add_flow_rules(ft, spec, &flow_act, NULL, 0);
94 if (IS_ERR(flow_rule)) {
95 err = PTR_ERR(flow_rule);
96 mlx5_core_err(dev, "Failed to add RoCE allow rule, err=%d\n",
97 err);
98 goto destroy_flow_group;
99 }
100
101 kvfree(spec);
102 kvfree(flow_group_in);
103 roce->ft = ft;
104 roce->fg = fg;
105 roce->allow_rule = flow_rule;
106
107 return 0;
108
109destroy_flow_group:
110 mlx5_destroy_flow_group(fg);
111destroy_flow_table:
112 mlx5_destroy_flow_table(ft);
113free:
114 kvfree(spec);
115 kvfree(flow_group_in);
116 return err;
117}
118
119static void mlx5_rdma_del_roce_addr(struct mlx5_core_dev *dev)
120{
121 mlx5_core_roce_gid_set(dev, 0, 0, 0,
122 NULL, NULL, false, 0, 0);
123}
124
125static void mlx5_rdma_make_default_gid(struct mlx5_core_dev *dev, union ib_gid *gid)
126{
127 u8 hw_id[ETH_ALEN];
128
129 mlx5_query_mac_address(dev, hw_id);
130 gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL);
131 addrconf_addr_eui48(&gid->raw[8], hw_id);
132}
133
134static int mlx5_rdma_add_roce_addr(struct mlx5_core_dev *dev)
135{
136 union ib_gid gid;
137 u8 mac[ETH_ALEN];
138
139 mlx5_rdma_make_default_gid(dev, &gid);
140 return mlx5_core_roce_gid_set(dev, 0,
141 MLX5_ROCE_VERSION_1,
142 0, gid.raw, mac,
143 false, 0, 1);
144}
145
146void mlx5_rdma_disable_roce(struct mlx5_core_dev *dev)
147{
148 mlx5_rdma_disable_roce_steering(dev);
149 mlx5_rdma_del_roce_addr(dev);
150 mlx5_nic_vport_disable_roce(dev);
151}
152
153void mlx5_rdma_enable_roce(struct mlx5_core_dev *dev)
154{
155 int err;
156
157 err = mlx5_nic_vport_enable_roce(dev);
158 if (err) {
159 mlx5_core_err(dev, "Failed to enable RoCE: %d\n", err);
160 return;
161 }
162
163 err = mlx5_rdma_add_roce_addr(dev);
164 if (err) {
165 mlx5_core_err(dev, "Failed to add RoCE address: %d\n", err);
166 goto disable_roce;
167 }
168
169 err = mlx5_rdma_enable_roce_steering(dev);
170 if (err) {
171 mlx5_core_err(dev, "Failed to enable RoCE steering: %d\n", err);
172 goto del_roce_addr;
173 }
174
175 return;
176
177del_roce_addr:
178 mlx5_rdma_del_roce_addr(dev);
179disable_roce:
180 mlx5_nic_vport_disable_roce(dev);
181 return;
182}
183