1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Marvell 88E6xxx Address Translation Unit (ATU) support
5 * Copyright (c) 2008 Marvell Semiconductor
6 * Copyright (c) 2017 Savoir-faire Linux, Inc.
9 #include <linux/bitfield.h>
10 #include <linux/interrupt.h>
11 #include <linux/irqdomain.h>
16 /* Offset 0x01: ATU FID Register */
18 static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip
*chip
, u16 fid
)
20 return mv88e6xxx_g1_write(chip
, MV88E6352_G1_ATU_FID
, fid
& 0xfff);
23 /* Offset 0x0A: ATU Control Register */
25 int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip
*chip
, bool learn2all
)
30 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_CTL
, &val
);
35 val
|= MV88E6XXX_G1_ATU_CTL_LEARN2ALL
;
37 val
&= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL
;
39 return mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_CTL
, val
);
42 int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip
*chip
,
45 const unsigned int coeff
= chip
->info
->age_time_coeff
;
46 const unsigned int min
= 0x01 * coeff
;
47 const unsigned int max
= 0xff * coeff
;
52 if (msecs
< min
|| msecs
> max
)
55 /* Round to nearest multiple of coeff */
56 age_time
= (msecs
+ coeff
/ 2) / coeff
;
58 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_CTL
, &val
);
62 /* AgeTime is 11:4 bits */
66 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_CTL
, val
);
70 dev_dbg(chip
->dev
, "AgeTime set to 0x%02x (%d ms)\n", age_time
,
76 int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip
*chip
, u8
*hash
)
81 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_CTL
, &val
);
85 *hash
= val
& MV88E6161_G1_ATU_CTL_HASH_MASK
;
90 int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip
*chip
, u8 hash
)
95 if (hash
& ~MV88E6161_G1_ATU_CTL_HASH_MASK
)
98 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_CTL
, &val
);
102 val
&= ~MV88E6161_G1_ATU_CTL_HASH_MASK
;
105 return mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_CTL
, val
);
108 /* Offset 0x0B: ATU Operation Register */
110 static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip
*chip
)
112 int bit
= __bf_shf(MV88E6XXX_G1_ATU_OP_BUSY
);
114 return mv88e6xxx_g1_wait_bit(chip
, MV88E6XXX_G1_ATU_OP
, bit
, 0);
117 static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip
*chip
, u16 fid
, u16 op
)
122 /* FID bits are dispatched all around gradually as more are supported */
123 if (mv88e6xxx_num_databases(chip
) > 256) {
124 err
= mv88e6xxx_g1_atu_fid_write(chip
, fid
);
128 if (mv88e6xxx_num_databases(chip
) > 64) {
129 /* ATU DBNum[7:4] are located in ATU Control 15:12 */
130 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_CTL
,
135 val
= (val
& 0x0fff) | ((fid
<< 8) & 0xf000);
136 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_CTL
,
140 } else if (mv88e6xxx_num_databases(chip
) > 16) {
141 /* ATU DBNum[5:4] are located in ATU Operation 9:8 */
142 op
|= (fid
& 0x30) << 4;
145 /* ATU DBNum[3:0] are located in ATU Operation 3:0 */
149 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_OP
,
150 MV88E6XXX_G1_ATU_OP_BUSY
| op
);
154 return mv88e6xxx_g1_atu_op_wait(chip
);
157 int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip
*chip
, u16 fid
)
159 return mv88e6xxx_g1_atu_op(chip
, fid
, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB
);
162 /* Offset 0x0C: ATU Data Register */
164 static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip
*chip
,
165 struct mv88e6xxx_atu_entry
*entry
)
170 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_DATA
, &val
);
174 entry
->state
= val
& 0xf;
176 entry
->trunk
= !!(val
& MV88E6XXX_G1_ATU_DATA_TRUNK
);
177 entry
->portvec
= (val
>> 4) & mv88e6xxx_port_mask(chip
);
183 static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip
*chip
,
184 struct mv88e6xxx_atu_entry
*entry
)
186 u16 data
= entry
->state
& 0xf;
190 data
|= MV88E6XXX_G1_ATU_DATA_TRUNK
;
192 data
|= (entry
->portvec
& mv88e6xxx_port_mask(chip
)) << 4;
195 return mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_DATA
, data
);
198 /* Offset 0x0D: ATU MAC Address Register Bytes 0 & 1
199 * Offset 0x0E: ATU MAC Address Register Bytes 2 & 3
200 * Offset 0x0F: ATU MAC Address Register Bytes 4 & 5
203 static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip
*chip
,
204 struct mv88e6xxx_atu_entry
*entry
)
209 for (i
= 0; i
< 3; i
++) {
210 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_MAC01
+ i
, &val
);
214 entry
->mac
[i
* 2] = val
>> 8;
215 entry
->mac
[i
* 2 + 1] = val
& 0xff;
221 static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip
*chip
,
222 struct mv88e6xxx_atu_entry
*entry
)
227 for (i
= 0; i
< 3; i
++) {
228 val
= (entry
->mac
[i
* 2] << 8) | entry
->mac
[i
* 2 + 1];
229 err
= mv88e6xxx_g1_write(chip
, MV88E6XXX_G1_ATU_MAC01
+ i
, val
);
237 /* Address Translation Unit operations */
239 int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip
*chip
, u16 fid
,
240 struct mv88e6xxx_atu_entry
*entry
)
244 err
= mv88e6xxx_g1_atu_op_wait(chip
);
248 /* Write the MAC address to iterate from only once */
250 err
= mv88e6xxx_g1_atu_mac_write(chip
, entry
);
255 err
= mv88e6xxx_g1_atu_op(chip
, fid
, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB
);
259 err
= mv88e6xxx_g1_atu_data_read(chip
, entry
);
263 return mv88e6xxx_g1_atu_mac_read(chip
, entry
);
266 int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip
*chip
, u16 fid
,
267 struct mv88e6xxx_atu_entry
*entry
)
271 err
= mv88e6xxx_g1_atu_op_wait(chip
);
275 err
= mv88e6xxx_g1_atu_mac_write(chip
, entry
);
279 err
= mv88e6xxx_g1_atu_data_write(chip
, entry
);
283 return mv88e6xxx_g1_atu_op(chip
, fid
, MV88E6XXX_G1_ATU_OP_LOAD_DB
);
286 static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip
*chip
, u16 fid
,
287 struct mv88e6xxx_atu_entry
*entry
,
293 err
= mv88e6xxx_g1_atu_op_wait(chip
);
297 err
= mv88e6xxx_g1_atu_data_write(chip
, entry
);
301 /* Flush/Move all or non-static entries from all or a given database */
303 op
= MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB
;
305 op
= MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB
;
307 op
= MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL
;
309 op
= MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC
;
311 return mv88e6xxx_g1_atu_op(chip
, fid
, op
);
314 int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip
*chip
, u16 fid
, bool all
)
316 struct mv88e6xxx_atu_entry entry
= {
317 .state
= 0, /* Null EntryState means Flush */
320 return mv88e6xxx_g1_atu_flushmove(chip
, fid
, &entry
, all
);
323 static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip
*chip
, u16 fid
,
324 int from_port
, int to_port
, bool all
)
326 struct mv88e6xxx_atu_entry entry
= { 0 };
330 if (!chip
->info
->atu_move_port_mask
)
333 mask
= chip
->info
->atu_move_port_mask
;
334 shift
= bitmap_weight(&mask
, 16);
336 entry
.state
= 0xf, /* Full EntryState means Move */
337 entry
.portvec
= from_port
& mask
;
338 entry
.portvec
|= (to_port
& mask
) << shift
;
340 return mv88e6xxx_g1_atu_flushmove(chip
, fid
, &entry
, all
);
343 int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip
*chip
, u16 fid
, int port
,
346 int from_port
= port
;
347 int to_port
= chip
->info
->atu_move_port_mask
;
349 return mv88e6xxx_g1_atu_move(chip
, fid
, from_port
, to_port
, all
);
352 static irqreturn_t
mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq
, void *dev_id
)
354 struct mv88e6xxx_chip
*chip
= dev_id
;
355 struct mv88e6xxx_atu_entry entry
;
360 mv88e6xxx_reg_lock(chip
);
362 err
= mv88e6xxx_g1_atu_op(chip
, 0,
363 MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION
);
367 err
= mv88e6xxx_g1_read(chip
, MV88E6XXX_G1_ATU_OP
, &val
);
371 err
= mv88e6xxx_g1_atu_data_read(chip
, &entry
);
375 err
= mv88e6xxx_g1_atu_mac_read(chip
, &entry
);
381 if (val
& MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION
) {
382 dev_err_ratelimited(chip
->dev
,
383 "ATU age out violation for %pM\n",
387 if (val
& MV88E6XXX_G1_ATU_OP_MEMBER_VIOLATION
) {
388 dev_err_ratelimited(chip
->dev
,
389 "ATU member violation for %pM portvec %x spid %d\n",
390 entry
.mac
, entry
.portvec
, spid
);
391 chip
->ports
[spid
].atu_member_violation
++;
394 if (val
& MV88E6XXX_G1_ATU_OP_MISS_VIOLATION
) {
395 dev_err_ratelimited(chip
->dev
,
396 "ATU miss violation for %pM portvec %x spid %d\n",
397 entry
.mac
, entry
.portvec
, spid
);
398 chip
->ports
[spid
].atu_miss_violation
++;
401 if (val
& MV88E6XXX_G1_ATU_OP_FULL_VIOLATION
) {
402 dev_err_ratelimited(chip
->dev
,
403 "ATU full violation for %pM portvec %x spid %d\n",
404 entry
.mac
, entry
.portvec
, spid
);
405 chip
->ports
[spid
].atu_full_violation
++;
407 mv88e6xxx_reg_unlock(chip
);
412 mv88e6xxx_reg_unlock(chip
);
414 dev_err(chip
->dev
, "ATU problem: error %d while handling interrupt\n",
419 int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip
*chip
)
423 chip
->atu_prob_irq
= irq_find_mapping(chip
->g1_irq
.domain
,
424 MV88E6XXX_G1_STS_IRQ_ATU_PROB
);
425 if (chip
->atu_prob_irq
< 0)
426 return chip
->atu_prob_irq
;
428 err
= request_threaded_irq(chip
->atu_prob_irq
, NULL
,
429 mv88e6xxx_g1_atu_prob_irq_thread_fn
,
430 IRQF_ONESHOT
, "mv88e6xxx-g1-atu-prob",
433 irq_dispose_mapping(chip
->atu_prob_irq
);
438 void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip
*chip
)
440 free_irq(chip
->atu_prob_irq
, chip
);
441 irq_dispose_mapping(chip
->atu_prob_irq
);