cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

global1_atu.c (10309B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Marvell 88E6xxx Address Translation Unit (ATU) support
      4 *
      5 * Copyright (c) 2008 Marvell Semiconductor
      6 * Copyright (c) 2017 Savoir-faire Linux, Inc.
      7 */
      8
      9#include <linux/bitfield.h>
     10#include <linux/interrupt.h>
     11#include <linux/irqdomain.h>
     12
     13#include "chip.h"
     14#include "global1.h"
     15
     16/* Offset 0x01: ATU FID Register */
     17
     18static int mv88e6xxx_g1_atu_fid_write(struct mv88e6xxx_chip *chip, u16 fid)
     19{
     20	return mv88e6xxx_g1_write(chip, MV88E6352_G1_ATU_FID, fid & 0xfff);
     21}
     22
     23/* Offset 0x0A: ATU Control Register */
     24
     25int mv88e6xxx_g1_atu_set_learn2all(struct mv88e6xxx_chip *chip, bool learn2all)
     26{
     27	u16 val;
     28	int err;
     29
     30	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
     31	if (err)
     32		return err;
     33
     34	if (learn2all)
     35		val |= MV88E6XXX_G1_ATU_CTL_LEARN2ALL;
     36	else
     37		val &= ~MV88E6XXX_G1_ATU_CTL_LEARN2ALL;
     38
     39	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val);
     40}
     41
     42int mv88e6xxx_g1_atu_set_age_time(struct mv88e6xxx_chip *chip,
     43				  unsigned int msecs)
     44{
     45	const unsigned int coeff = chip->info->age_time_coeff;
     46	const unsigned int min = 0x01 * coeff;
     47	const unsigned int max = 0xff * coeff;
     48	u8 age_time;
     49	u16 val;
     50	int err;
     51
     52	if (msecs < min || msecs > max)
     53		return -ERANGE;
     54
     55	/* Round to nearest multiple of coeff */
     56	age_time = (msecs + coeff / 2) / coeff;
     57
     58	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
     59	if (err)
     60		return err;
     61
     62	/* AgeTime is 11:4 bits */
     63	val &= ~0xff0;
     64	val |= age_time << 4;
     65
     66	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val);
     67	if (err)
     68		return err;
     69
     70	dev_dbg(chip->dev, "AgeTime set to 0x%02x (%d ms)\n", age_time,
     71		age_time * coeff);
     72
     73	return 0;
     74}
     75
     76int mv88e6165_g1_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
     77{
     78	int err;
     79	u16 val;
     80
     81	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
     82	if (err)
     83		return err;
     84
     85	*hash = val & MV88E6161_G1_ATU_CTL_HASH_MASK;
     86
     87	return 0;
     88}
     89
     90int mv88e6165_g1_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
     91{
     92	int err;
     93	u16 val;
     94
     95	if (hash & ~MV88E6161_G1_ATU_CTL_HASH_MASK)
     96		return -EINVAL;
     97
     98	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_CTL, &val);
     99	if (err)
    100		return err;
    101
    102	val &= ~MV88E6161_G1_ATU_CTL_HASH_MASK;
    103	val |= hash;
    104
    105	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL, val);
    106}
    107
    108/* Offset 0x0B: ATU Operation Register */
    109
    110static int mv88e6xxx_g1_atu_op_wait(struct mv88e6xxx_chip *chip)
    111{
    112	int bit = __bf_shf(MV88E6XXX_G1_ATU_OP_BUSY);
    113
    114	return mv88e6xxx_g1_wait_bit(chip, MV88E6XXX_G1_ATU_OP, bit, 0);
    115}
    116
    117static int mv88e6xxx_g1_atu_op(struct mv88e6xxx_chip *chip, u16 fid, u16 op)
    118{
    119	u16 val;
    120	int err;
    121
    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);
    125		if (err)
    126			return err;
    127	} else {
    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,
    131						&val);
    132			if (err)
    133				return err;
    134
    135			val = (val & 0x0fff) | ((fid << 8) & 0xf000);
    136			err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_CTL,
    137						 val);
    138			if (err)
    139				return err;
    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;
    143		}
    144
    145		/* ATU DBNum[3:0] are located in ATU Operation 3:0 */
    146		op |= fid & 0xf;
    147	}
    148
    149	err = mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_OP,
    150				 MV88E6XXX_G1_ATU_OP_BUSY | op);
    151	if (err)
    152		return err;
    153
    154	return mv88e6xxx_g1_atu_op_wait(chip);
    155}
    156
    157int mv88e6xxx_g1_atu_get_next(struct mv88e6xxx_chip *chip, u16 fid)
    158{
    159	return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
    160}
    161
    162/* Offset 0x0C: ATU Data Register */
    163
    164static int mv88e6xxx_g1_atu_data_read(struct mv88e6xxx_chip *chip,
    165				      struct mv88e6xxx_atu_entry *entry)
    166{
    167	u16 val;
    168	int err;
    169
    170	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &val);
    171	if (err)
    172		return err;
    173
    174	entry->state = val & 0xf;
    175	if (entry->state) {
    176		entry->trunk = !!(val & MV88E6XXX_G1_ATU_DATA_TRUNK);
    177		entry->portvec = (val >> 4) & mv88e6xxx_port_mask(chip);
    178	}
    179
    180	return 0;
    181}
    182
    183static int mv88e6xxx_g1_atu_data_write(struct mv88e6xxx_chip *chip,
    184				       struct mv88e6xxx_atu_entry *entry)
    185{
    186	u16 data = entry->state & 0xf;
    187
    188	if (entry->state) {
    189		if (entry->trunk)
    190			data |= MV88E6XXX_G1_ATU_DATA_TRUNK;
    191
    192		data |= (entry->portvec & mv88e6xxx_port_mask(chip)) << 4;
    193	}
    194
    195	return mv88e6xxx_g1_write(chip, MV88E6XXX_G1_ATU_DATA, data);
    196}
    197
    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
    201 */
    202
    203static int mv88e6xxx_g1_atu_mac_read(struct mv88e6xxx_chip *chip,
    204				     struct mv88e6xxx_atu_entry *entry)
    205{
    206	u16 val;
    207	int i, err;
    208
    209	for (i = 0; i < 3; i++) {
    210		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01 + i, &val);
    211		if (err)
    212			return err;
    213
    214		entry->mac[i * 2] = val >> 8;
    215		entry->mac[i * 2 + 1] = val & 0xff;
    216	}
    217
    218	return 0;
    219}
    220
    221static int mv88e6xxx_g1_atu_mac_write(struct mv88e6xxx_chip *chip,
    222				      struct mv88e6xxx_atu_entry *entry)
    223{
    224	u16 val;
    225	int i, err;
    226
    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);
    230		if (err)
    231			return err;
    232	}
    233
    234	return 0;
    235}
    236
    237/* Address Translation Unit operations */
    238
    239int mv88e6xxx_g1_atu_getnext(struct mv88e6xxx_chip *chip, u16 fid,
    240			     struct mv88e6xxx_atu_entry *entry)
    241{
    242	int err;
    243
    244	err = mv88e6xxx_g1_atu_op_wait(chip);
    245	if (err)
    246		return err;
    247
    248	/* Write the MAC address to iterate from only once */
    249	if (!entry->state) {
    250		err = mv88e6xxx_g1_atu_mac_write(chip, entry);
    251		if (err)
    252			return err;
    253	}
    254
    255	err = mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_GET_NEXT_DB);
    256	if (err)
    257		return err;
    258
    259	err = mv88e6xxx_g1_atu_data_read(chip, entry);
    260	if (err)
    261		return err;
    262
    263	return mv88e6xxx_g1_atu_mac_read(chip, entry);
    264}
    265
    266int mv88e6xxx_g1_atu_loadpurge(struct mv88e6xxx_chip *chip, u16 fid,
    267			       struct mv88e6xxx_atu_entry *entry)
    268{
    269	int err;
    270
    271	err = mv88e6xxx_g1_atu_op_wait(chip);
    272	if (err)
    273		return err;
    274
    275	err = mv88e6xxx_g1_atu_mac_write(chip, entry);
    276	if (err)
    277		return err;
    278
    279	err = mv88e6xxx_g1_atu_data_write(chip, entry);
    280	if (err)
    281		return err;
    282
    283	return mv88e6xxx_g1_atu_op(chip, fid, MV88E6XXX_G1_ATU_OP_LOAD_DB);
    284}
    285
    286static int mv88e6xxx_g1_atu_flushmove(struct mv88e6xxx_chip *chip, u16 fid,
    287				      struct mv88e6xxx_atu_entry *entry,
    288				      bool all)
    289{
    290	u16 op;
    291	int err;
    292
    293	err = mv88e6xxx_g1_atu_op_wait(chip);
    294	if (err)
    295		return err;
    296
    297	err = mv88e6xxx_g1_atu_data_write(chip, entry);
    298	if (err)
    299		return err;
    300
    301	/* Flush/Move all or non-static entries from all or a given database */
    302	if (all && fid)
    303		op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL_DB;
    304	else if (fid)
    305		op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
    306	else if (all)
    307		op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_ALL;
    308	else
    309		op = MV88E6XXX_G1_ATU_OP_FLUSH_MOVE_NON_STATIC;
    310
    311	return mv88e6xxx_g1_atu_op(chip, fid, op);
    312}
    313
    314int mv88e6xxx_g1_atu_flush(struct mv88e6xxx_chip *chip, u16 fid, bool all)
    315{
    316	struct mv88e6xxx_atu_entry entry = {
    317		.state = 0, /* Null EntryState means Flush */
    318	};
    319
    320	return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
    321}
    322
    323static int mv88e6xxx_g1_atu_move(struct mv88e6xxx_chip *chip, u16 fid,
    324				 int from_port, int to_port, bool all)
    325{
    326	struct mv88e6xxx_atu_entry entry = { 0 };
    327	unsigned long mask;
    328	int shift;
    329
    330	if (!chip->info->atu_move_port_mask)
    331		return -EOPNOTSUPP;
    332
    333	mask = chip->info->atu_move_port_mask;
    334	shift = bitmap_weight(&mask, 16);
    335
    336	entry.state = 0xf; /* Full EntryState means Move */
    337	entry.portvec = from_port & mask;
    338	entry.portvec |= (to_port & mask) << shift;
    339
    340	return mv88e6xxx_g1_atu_flushmove(chip, fid, &entry, all);
    341}
    342
    343int mv88e6xxx_g1_atu_remove(struct mv88e6xxx_chip *chip, u16 fid, int port,
    344			    bool all)
    345{
    346	int from_port = port;
    347	int to_port = chip->info->atu_move_port_mask;
    348
    349	return mv88e6xxx_g1_atu_move(chip, fid, from_port, to_port, all);
    350}
    351
    352static irqreturn_t mv88e6xxx_g1_atu_prob_irq_thread_fn(int irq, void *dev_id)
    353{
    354	struct mv88e6xxx_chip *chip = dev_id;
    355	struct mv88e6xxx_atu_entry entry;
    356	int spid;
    357	int err;
    358	u16 val;
    359
    360	mv88e6xxx_reg_lock(chip);
    361
    362	err = mv88e6xxx_g1_atu_op(chip, 0,
    363				  MV88E6XXX_G1_ATU_OP_GET_CLR_VIOLATION);
    364	if (err)
    365		goto out;
    366
    367	err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &val);
    368	if (err)
    369		goto out;
    370
    371	err = mv88e6xxx_g1_atu_data_read(chip, &entry);
    372	if (err)
    373		goto out;
    374
    375	err = mv88e6xxx_g1_atu_mac_read(chip, &entry);
    376	if (err)
    377		goto out;
    378
    379	spid = entry.state;
    380
    381	if (val & MV88E6XXX_G1_ATU_OP_AGE_OUT_VIOLATION) {
    382		dev_err_ratelimited(chip->dev,
    383				    "ATU age out violation for %pM\n",
    384				    entry.mac);
    385	}
    386
    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++;
    392	}
    393
    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++;
    399	}
    400
    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++;
    406	}
    407	mv88e6xxx_reg_unlock(chip);
    408
    409	return IRQ_HANDLED;
    410
    411out:
    412	mv88e6xxx_reg_unlock(chip);
    413
    414	dev_err(chip->dev, "ATU problem: error %d while handling interrupt\n",
    415		err);
    416	return IRQ_HANDLED;
    417}
    418
    419int mv88e6xxx_g1_atu_prob_irq_setup(struct mv88e6xxx_chip *chip)
    420{
    421	int err;
    422
    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;
    427
    428	snprintf(chip->atu_prob_irq_name, sizeof(chip->atu_prob_irq_name),
    429		 "mv88e6xxx-%s-g1-atu-prob", dev_name(chip->dev));
    430
    431	err = request_threaded_irq(chip->atu_prob_irq, NULL,
    432				   mv88e6xxx_g1_atu_prob_irq_thread_fn,
    433				   IRQF_ONESHOT, chip->atu_prob_irq_name,
    434				   chip);
    435	if (err)
    436		irq_dispose_mapping(chip->atu_prob_irq);
    437
    438	return err;
    439}
    440
    441void mv88e6xxx_g1_atu_prob_irq_free(struct mv88e6xxx_chip *chip)
    442{
    443	free_irq(chip->atu_prob_irq, chip);
    444	irq_dispose_mapping(chip->atu_prob_irq);
    445}