aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/mlx4/port.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/mlx4/port.c')
-rw-r--r--drivers/net/mlx4/port.c165
1 files changed, 151 insertions, 14 deletions
diff --git a/drivers/net/mlx4/port.c b/drivers/net/mlx4/port.c
index 451339559bd..eca7d8596f8 100644
--- a/drivers/net/mlx4/port.c
+++ b/drivers/net/mlx4/port.c
@@ -90,12 +90,79 @@ static int mlx4_set_port_mac_table(struct mlx4_dev *dev, u8 port,
90 return err; 90 return err;
91} 91}
92 92
93int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index) 93static int mlx4_uc_steer_add(struct mlx4_dev *dev, u8 port,
94 u64 mac, int *qpn, u8 reserve)
94{ 95{
95 struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; 96 struct mlx4_qp qp;
97 u8 gid[16] = {0};
98 int err;
99
100 if (reserve) {
101 err = mlx4_qp_reserve_range(dev, 1, 1, qpn);
102 if (err) {
103 mlx4_err(dev, "Failed to reserve qp for mac registration\n");
104 return err;
105 }
106 }
107 qp.qpn = *qpn;
108
109 mac &= 0xffffffffffffULL;
110 mac = cpu_to_be64(mac << 16);
111 memcpy(&gid[10], &mac, ETH_ALEN);
112 gid[5] = port;
113 gid[7] = MLX4_UC_STEER << 1;
114
115 err = mlx4_qp_attach_common(dev, &qp, gid, 0,
116 MLX4_PROT_ETH, MLX4_UC_STEER);
117 if (err && reserve)
118 mlx4_qp_release_range(dev, *qpn, 1);
119
120 return err;
121}
122
123static void mlx4_uc_steer_release(struct mlx4_dev *dev, u8 port,
124 u64 mac, int qpn, u8 free)
125{
126 struct mlx4_qp qp;
127 u8 gid[16] = {0};
128
129 qp.qpn = qpn;
130 mac &= 0xffffffffffffULL;
131 mac = cpu_to_be64(mac << 16);
132 memcpy(&gid[10], &mac, ETH_ALEN);
133 gid[5] = port;
134 gid[7] = MLX4_UC_STEER << 1;
135
136 mlx4_qp_detach_common(dev, &qp, gid, MLX4_PROT_ETH, MLX4_UC_STEER);
137 if (free)
138 mlx4_qp_release_range(dev, qpn, 1);
139}
140
141int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *qpn, u8 wrap)
142{
143 struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
144 struct mlx4_mac_table *table = &info->mac_table;
145 struct mlx4_mac_entry *entry;
96 int i, err = 0; 146 int i, err = 0;
97 int free = -1; 147 int free = -1;
98 148
149 if (dev->caps.vep_uc_steering) {
150 err = mlx4_uc_steer_add(dev, port, mac, qpn, 1);
151 if (!err) {
152 entry = kmalloc(sizeof *entry, GFP_KERNEL);
153 if (!entry) {
154 mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
155 return -ENOMEM;
156 }
157 entry->mac = mac;
158 err = radix_tree_insert(&info->mac_tree, *qpn, entry);
159 if (err) {
160 mlx4_uc_steer_release(dev, port, mac, *qpn, 1);
161 return err;
162 }
163 } else
164 return err;
165 }
99 mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac); 166 mlx4_dbg(dev, "Registering MAC: 0x%llx\n", (unsigned long long) mac);
100 mutex_lock(&table->mutex); 167 mutex_lock(&table->mutex);
101 for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) { 168 for (i = 0; i < MLX4_MAX_MAC_NUM - 1; i++) {
@@ -106,7 +173,6 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index)
106 173
107 if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) { 174 if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i]))) {
108 /* MAC already registered, increase refernce count */ 175 /* MAC already registered, increase refernce count */
109 *index = i;
110 ++table->refs[i]; 176 ++table->refs[i];
111 goto out; 177 goto out;
112 } 178 }
@@ -137,7 +203,8 @@ int mlx4_register_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *index)
137 goto out; 203 goto out;
138 } 204 }
139 205
140 *index = free; 206 if (!dev->caps.vep_uc_steering)
207 *qpn = info->base_qpn + free;
141 ++table->total; 208 ++table->total;
142out: 209out:
143 mutex_unlock(&table->mutex); 210 mutex_unlock(&table->mutex);
@@ -145,20 +212,52 @@ out:
145} 212}
146EXPORT_SYMBOL_GPL(mlx4_register_mac); 213EXPORT_SYMBOL_GPL(mlx4_register_mac);
147 214
148void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int index) 215static int validate_index(struct mlx4_dev *dev,
216 struct mlx4_mac_table *table, int index)
149{ 217{
150 struct mlx4_mac_table *table = &mlx4_priv(dev)->port[port].mac_table; 218 int err = 0;
151 219
152 mutex_lock(&table->mutex); 220 if (index < 0 || index >= table->max || !table->entries[index]) {
153 if (!table->refs[index]) { 221 mlx4_warn(dev, "No valid Mac entry for the given index\n");
154 mlx4_warn(dev, "No MAC entry for index %d\n", index); 222 err = -EINVAL;
155 goto out;
156 } 223 }
157 if (--table->refs[index]) { 224 return err;
158 mlx4_warn(dev, "Have more references for index %d," 225}
159 "no need to modify MAC table\n", index); 226
160 goto out; 227static int find_index(struct mlx4_dev *dev,
228 struct mlx4_mac_table *table, u64 mac)
229{
230 int i;
231 for (i = 0; i < MLX4_MAX_MAC_NUM; i++) {
232 if (mac == (MLX4_MAC_MASK & be64_to_cpu(table->entries[i])))
233 return i;
161 } 234 }
235 /* Mac not found */
236 return -EINVAL;
237}
238
239void mlx4_unregister_mac(struct mlx4_dev *dev, u8 port, int qpn)
240{
241 struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
242 struct mlx4_mac_table *table = &info->mac_table;
243 int index = qpn - info->base_qpn;
244 struct mlx4_mac_entry *entry;
245
246 if (dev->caps.vep_uc_steering) {
247 entry = radix_tree_lookup(&info->mac_tree, qpn);
248 if (entry) {
249 mlx4_uc_steer_release(dev, port, entry->mac, qpn, 1);
250 radix_tree_delete(&info->mac_tree, qpn);
251 index = find_index(dev, table, entry->mac);
252 kfree(entry);
253 }
254 }
255
256 mutex_lock(&table->mutex);
257
258 if (validate_index(dev, table, index))
259 goto out;
260
162 table->entries[index] = 0; 261 table->entries[index] = 0;
163 mlx4_set_port_mac_table(dev, port, table->entries); 262 mlx4_set_port_mac_table(dev, port, table->entries);
164 --table->total; 263 --table->total;
@@ -167,6 +266,44 @@ out:
167} 266}
168EXPORT_SYMBOL_GPL(mlx4_unregister_mac); 267EXPORT_SYMBOL_GPL(mlx4_unregister_mac);
169 268
269int mlx4_replace_mac(struct mlx4_dev *dev, u8 port, int qpn, u64 new_mac, u8 wrap)
270{
271 struct mlx4_port_info *info = &mlx4_priv(dev)->port[port];
272 struct mlx4_mac_table *table = &info->mac_table;
273 int index = qpn - info->base_qpn;
274 struct mlx4_mac_entry *entry;
275 int err;
276
277 if (dev->caps.vep_uc_steering) {
278 entry = radix_tree_lookup(&info->mac_tree, qpn);
279 if (!entry)
280 return -EINVAL;
281 index = find_index(dev, table, entry->mac);
282 mlx4_uc_steer_release(dev, port, entry->mac, qpn, 0);
283 entry->mac = new_mac;
284 err = mlx4_uc_steer_add(dev, port, entry->mac, &qpn, 0);
285 if (err || index < 0)
286 return err;
287 }
288
289 mutex_lock(&table->mutex);
290
291 err = validate_index(dev, table, index);
292 if (err)
293 goto out;
294
295 table->entries[index] = cpu_to_be64(new_mac | MLX4_MAC_VALID);
296
297 err = mlx4_set_port_mac_table(dev, port, table->entries);
298 if (unlikely(err)) {
299 mlx4_err(dev, "Failed adding MAC: 0x%llx\n", (unsigned long long) new_mac);
300 table->entries[index] = 0;
301 }
302out:
303 mutex_unlock(&table->mutex);
304 return err;
305}
306EXPORT_SYMBOL_GPL(mlx4_replace_mac);
170static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port, 307static int mlx4_set_port_vlan_table(struct mlx4_dev *dev, u8 port,
171 __be32 *entries) 308 __be32 *entries)
172{ 309{