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

devlink.c (19996B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2#include <net/dsa.h>
      3
      4#include "chip.h"
      5#include "devlink.h"
      6#include "global1.h"
      7#include "global2.h"
      8#include "port.h"
      9
     10static int mv88e6xxx_atu_get_hash(struct mv88e6xxx_chip *chip, u8 *hash)
     11{
     12	if (chip->info->ops->atu_get_hash)
     13		return chip->info->ops->atu_get_hash(chip, hash);
     14
     15	return -EOPNOTSUPP;
     16}
     17
     18static int mv88e6xxx_atu_set_hash(struct mv88e6xxx_chip *chip, u8 hash)
     19{
     20	if (chip->info->ops->atu_set_hash)
     21		return chip->info->ops->atu_set_hash(chip, hash);
     22
     23	return -EOPNOTSUPP;
     24}
     25
     26enum mv88e6xxx_devlink_param_id {
     27	MV88E6XXX_DEVLINK_PARAM_ID_BASE = DEVLINK_PARAM_GENERIC_ID_MAX,
     28	MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
     29};
     30
     31int mv88e6xxx_devlink_param_get(struct dsa_switch *ds, u32 id,
     32				struct devlink_param_gset_ctx *ctx)
     33{
     34	struct mv88e6xxx_chip *chip = ds->priv;
     35	int err;
     36
     37	mv88e6xxx_reg_lock(chip);
     38
     39	switch (id) {
     40	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
     41		err = mv88e6xxx_atu_get_hash(chip, &ctx->val.vu8);
     42		break;
     43	default:
     44		err = -EOPNOTSUPP;
     45		break;
     46	}
     47
     48	mv88e6xxx_reg_unlock(chip);
     49
     50	return err;
     51}
     52
     53int mv88e6xxx_devlink_param_set(struct dsa_switch *ds, u32 id,
     54				struct devlink_param_gset_ctx *ctx)
     55{
     56	struct mv88e6xxx_chip *chip = ds->priv;
     57	int err;
     58
     59	mv88e6xxx_reg_lock(chip);
     60
     61	switch (id) {
     62	case MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH:
     63		err = mv88e6xxx_atu_set_hash(chip, ctx->val.vu8);
     64		break;
     65	default:
     66		err = -EOPNOTSUPP;
     67		break;
     68	}
     69
     70	mv88e6xxx_reg_unlock(chip);
     71
     72	return err;
     73}
     74
     75static const struct devlink_param mv88e6xxx_devlink_params[] = {
     76	DSA_DEVLINK_PARAM_DRIVER(MV88E6XXX_DEVLINK_PARAM_ID_ATU_HASH,
     77				 "ATU_hash", DEVLINK_PARAM_TYPE_U8,
     78				 BIT(DEVLINK_PARAM_CMODE_RUNTIME)),
     79};
     80
     81int mv88e6xxx_setup_devlink_params(struct dsa_switch *ds)
     82{
     83	return dsa_devlink_params_register(ds, mv88e6xxx_devlink_params,
     84					   ARRAY_SIZE(mv88e6xxx_devlink_params));
     85}
     86
     87void mv88e6xxx_teardown_devlink_params(struct dsa_switch *ds)
     88{
     89	dsa_devlink_params_unregister(ds, mv88e6xxx_devlink_params,
     90				      ARRAY_SIZE(mv88e6xxx_devlink_params));
     91}
     92
     93enum mv88e6xxx_devlink_resource_id {
     94	MV88E6XXX_RESOURCE_ID_ATU,
     95	MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
     96	MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
     97	MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
     98	MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
     99};
    100
    101static u64 mv88e6xxx_devlink_atu_bin_get(struct mv88e6xxx_chip *chip,
    102					 u16 bin)
    103{
    104	u16 occupancy = 0;
    105	int err;
    106
    107	mv88e6xxx_reg_lock(chip);
    108
    109	err = mv88e6xxx_g2_atu_stats_set(chip, MV88E6XXX_G2_ATU_STATS_MODE_ALL,
    110					 bin);
    111	if (err) {
    112		dev_err(chip->dev, "failed to set ATU stats kind/bin\n");
    113		goto unlock;
    114	}
    115
    116	err = mv88e6xxx_g1_atu_get_next(chip, 0);
    117	if (err) {
    118		dev_err(chip->dev, "failed to perform ATU get next\n");
    119		goto unlock;
    120	}
    121
    122	err = mv88e6xxx_g2_atu_stats_get(chip, &occupancy);
    123	if (err) {
    124		dev_err(chip->dev, "failed to get ATU stats\n");
    125		goto unlock;
    126	}
    127
    128	occupancy &= MV88E6XXX_G2_ATU_STATS_MASK;
    129
    130unlock:
    131	mv88e6xxx_reg_unlock(chip);
    132
    133	return occupancy;
    134}
    135
    136static u64 mv88e6xxx_devlink_atu_bin_0_get(void *priv)
    137{
    138	struct mv88e6xxx_chip *chip = priv;
    139
    140	return mv88e6xxx_devlink_atu_bin_get(chip,
    141					     MV88E6XXX_G2_ATU_STATS_BIN_0);
    142}
    143
    144static u64 mv88e6xxx_devlink_atu_bin_1_get(void *priv)
    145{
    146	struct mv88e6xxx_chip *chip = priv;
    147
    148	return mv88e6xxx_devlink_atu_bin_get(chip,
    149					     MV88E6XXX_G2_ATU_STATS_BIN_1);
    150}
    151
    152static u64 mv88e6xxx_devlink_atu_bin_2_get(void *priv)
    153{
    154	struct mv88e6xxx_chip *chip = priv;
    155
    156	return mv88e6xxx_devlink_atu_bin_get(chip,
    157					     MV88E6XXX_G2_ATU_STATS_BIN_2);
    158}
    159
    160static u64 mv88e6xxx_devlink_atu_bin_3_get(void *priv)
    161{
    162	struct mv88e6xxx_chip *chip = priv;
    163
    164	return mv88e6xxx_devlink_atu_bin_get(chip,
    165					     MV88E6XXX_G2_ATU_STATS_BIN_3);
    166}
    167
    168static u64 mv88e6xxx_devlink_atu_get(void *priv)
    169{
    170	return mv88e6xxx_devlink_atu_bin_0_get(priv) +
    171		mv88e6xxx_devlink_atu_bin_1_get(priv) +
    172		mv88e6xxx_devlink_atu_bin_2_get(priv) +
    173		mv88e6xxx_devlink_atu_bin_3_get(priv);
    174}
    175
    176int mv88e6xxx_setup_devlink_resources(struct dsa_switch *ds)
    177{
    178	struct devlink_resource_size_params size_params;
    179	struct mv88e6xxx_chip *chip = ds->priv;
    180	int err;
    181
    182	devlink_resource_size_params_init(&size_params,
    183					  mv88e6xxx_num_macs(chip),
    184					  mv88e6xxx_num_macs(chip),
    185					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
    186
    187	err = dsa_devlink_resource_register(ds, "ATU",
    188					    mv88e6xxx_num_macs(chip),
    189					    MV88E6XXX_RESOURCE_ID_ATU,
    190					    DEVLINK_RESOURCE_ID_PARENT_TOP,
    191					    &size_params);
    192	if (err)
    193		goto out;
    194
    195	devlink_resource_size_params_init(&size_params,
    196					  mv88e6xxx_num_macs(chip) / 4,
    197					  mv88e6xxx_num_macs(chip) / 4,
    198					  1, DEVLINK_RESOURCE_UNIT_ENTRY);
    199
    200	err = dsa_devlink_resource_register(ds, "ATU_bin_0",
    201					    mv88e6xxx_num_macs(chip) / 4,
    202					    MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
    203					    MV88E6XXX_RESOURCE_ID_ATU,
    204					    &size_params);
    205	if (err)
    206		goto out;
    207
    208	err = dsa_devlink_resource_register(ds, "ATU_bin_1",
    209					    mv88e6xxx_num_macs(chip) / 4,
    210					    MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
    211					    MV88E6XXX_RESOURCE_ID_ATU,
    212					    &size_params);
    213	if (err)
    214		goto out;
    215
    216	err = dsa_devlink_resource_register(ds, "ATU_bin_2",
    217					    mv88e6xxx_num_macs(chip) / 4,
    218					    MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
    219					    MV88E6XXX_RESOURCE_ID_ATU,
    220					    &size_params);
    221	if (err)
    222		goto out;
    223
    224	err = dsa_devlink_resource_register(ds, "ATU_bin_3",
    225					    mv88e6xxx_num_macs(chip) / 4,
    226					    MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
    227					    MV88E6XXX_RESOURCE_ID_ATU,
    228					    &size_params);
    229	if (err)
    230		goto out;
    231
    232	dsa_devlink_resource_occ_get_register(ds,
    233					      MV88E6XXX_RESOURCE_ID_ATU,
    234					      mv88e6xxx_devlink_atu_get,
    235					      chip);
    236
    237	dsa_devlink_resource_occ_get_register(ds,
    238					      MV88E6XXX_RESOURCE_ID_ATU_BIN_0,
    239					      mv88e6xxx_devlink_atu_bin_0_get,
    240					      chip);
    241
    242	dsa_devlink_resource_occ_get_register(ds,
    243					      MV88E6XXX_RESOURCE_ID_ATU_BIN_1,
    244					      mv88e6xxx_devlink_atu_bin_1_get,
    245					      chip);
    246
    247	dsa_devlink_resource_occ_get_register(ds,
    248					      MV88E6XXX_RESOURCE_ID_ATU_BIN_2,
    249					      mv88e6xxx_devlink_atu_bin_2_get,
    250					      chip);
    251
    252	dsa_devlink_resource_occ_get_register(ds,
    253					      MV88E6XXX_RESOURCE_ID_ATU_BIN_3,
    254					      mv88e6xxx_devlink_atu_bin_3_get,
    255					      chip);
    256
    257	return 0;
    258
    259out:
    260	dsa_devlink_resources_unregister(ds);
    261	return err;
    262}
    263
    264static int mv88e6xxx_region_global_snapshot(struct devlink *dl,
    265					    const struct devlink_region_ops *ops,
    266					    struct netlink_ext_ack *extack,
    267					    u8 **data)
    268{
    269	struct mv88e6xxx_region_priv *region_priv = ops->priv;
    270	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
    271	struct mv88e6xxx_chip *chip = ds->priv;
    272	u16 *registers;
    273	int i, err;
    274
    275	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
    276	if (!registers)
    277		return -ENOMEM;
    278
    279	mv88e6xxx_reg_lock(chip);
    280	for (i = 0; i < 32; i++) {
    281		switch (region_priv->id) {
    282		case MV88E6XXX_REGION_GLOBAL1:
    283			err = mv88e6xxx_g1_read(chip, i, &registers[i]);
    284			break;
    285		case MV88E6XXX_REGION_GLOBAL2:
    286			err = mv88e6xxx_g2_read(chip, i, &registers[i]);
    287			break;
    288		default:
    289			err = -EOPNOTSUPP;
    290		}
    291
    292		if (err) {
    293			kfree(registers);
    294			goto out;
    295		}
    296	}
    297	*data = (u8 *)registers;
    298out:
    299	mv88e6xxx_reg_unlock(chip);
    300
    301	return err;
    302}
    303
    304/* The ATU entry varies between mv88e6xxx chipset generations. Define
    305 * a generic format which covers all the current and hopefully future
    306 * mv88e6xxx generations
    307 */
    308
    309struct mv88e6xxx_devlink_atu_entry {
    310	/* The FID is scattered over multiple registers. */
    311	u16 fid;
    312	u16 atu_op;
    313	u16 atu_data;
    314	u16 atu_01;
    315	u16 atu_23;
    316	u16 atu_45;
    317};
    318
    319static int mv88e6xxx_region_atu_snapshot_fid(struct mv88e6xxx_chip *chip,
    320					     int fid,
    321					     struct mv88e6xxx_devlink_atu_entry *table,
    322					     int *count)
    323{
    324	u16 atu_op, atu_data, atu_01, atu_23, atu_45;
    325	struct mv88e6xxx_atu_entry addr;
    326	int err;
    327
    328	addr.state = 0;
    329	eth_broadcast_addr(addr.mac);
    330
    331	do {
    332		err = mv88e6xxx_g1_atu_getnext(chip, fid, &addr);
    333		if (err)
    334			return err;
    335
    336		if (!addr.state)
    337			break;
    338
    339		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_OP, &atu_op);
    340		if (err)
    341			return err;
    342
    343		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_DATA, &atu_data);
    344		if (err)
    345			return err;
    346
    347		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC01, &atu_01);
    348		if (err)
    349			return err;
    350
    351		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC23, &atu_23);
    352		if (err)
    353			return err;
    354
    355		err = mv88e6xxx_g1_read(chip, MV88E6XXX_G1_ATU_MAC45, &atu_45);
    356		if (err)
    357			return err;
    358
    359		table[*count].fid = fid;
    360		table[*count].atu_op = atu_op;
    361		table[*count].atu_data = atu_data;
    362		table[*count].atu_01 = atu_01;
    363		table[*count].atu_23 = atu_23;
    364		table[*count].atu_45 = atu_45;
    365		(*count)++;
    366	} while (!is_broadcast_ether_addr(addr.mac));
    367
    368	return 0;
    369}
    370
    371static int mv88e6xxx_region_atu_snapshot(struct devlink *dl,
    372					 const struct devlink_region_ops *ops,
    373					 struct netlink_ext_ack *extack,
    374					 u8 **data)
    375{
    376	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
    377	DECLARE_BITMAP(fid_bitmap, MV88E6XXX_N_FID);
    378	struct mv88e6xxx_devlink_atu_entry *table;
    379	struct mv88e6xxx_chip *chip = ds->priv;
    380	int fid = -1, count, err;
    381
    382	table = kmalloc_array(mv88e6xxx_num_databases(chip),
    383			      sizeof(struct mv88e6xxx_devlink_atu_entry),
    384			      GFP_KERNEL);
    385	if (!table)
    386		return -ENOMEM;
    387
    388	memset(table, 0, mv88e6xxx_num_databases(chip) *
    389	       sizeof(struct mv88e6xxx_devlink_atu_entry));
    390
    391	count = 0;
    392
    393	mv88e6xxx_reg_lock(chip);
    394
    395	err = mv88e6xxx_fid_map(chip, fid_bitmap);
    396	if (err) {
    397		kfree(table);
    398		goto out;
    399	}
    400
    401	while (1) {
    402		fid = find_next_bit(fid_bitmap, MV88E6XXX_N_FID, fid + 1);
    403		if (fid == MV88E6XXX_N_FID)
    404			break;
    405
    406		err =  mv88e6xxx_region_atu_snapshot_fid(chip, fid, table,
    407							 &count);
    408		if (err) {
    409			kfree(table);
    410			goto out;
    411		}
    412	}
    413	*data = (u8 *)table;
    414out:
    415	mv88e6xxx_reg_unlock(chip);
    416
    417	return err;
    418}
    419
    420/**
    421 * struct mv88e6xxx_devlink_vtu_entry - Devlink VTU entry
    422 * @fid:   Global1/2:   FID and VLAN policy.
    423 * @sid:   Global1/3:   SID, unknown filters and learning.
    424 * @op:    Global1/5:   FID (old chipsets).
    425 * @vid:   Global1/6:   VID, valid, and page.
    426 * @data:  Global1/7-9: Membership data and priority override.
    427 * @resvd: Reserved. Also happens to align the size to 16B.
    428 *
    429 * The VTU entry format varies between chipset generations, the
    430 * descriptions above represent the superset of all possible
    431 * information, not all fields are valid on all devices. Since this is
    432 * a low-level debug interface, copy all data verbatim and defer
    433 * parsing to the consumer.
    434 */
    435struct mv88e6xxx_devlink_vtu_entry {
    436	u16 fid;
    437	u16 sid;
    438	u16 op;
    439	u16 vid;
    440	u16 data[3];
    441	u16 resvd;
    442};
    443
    444static int mv88e6xxx_region_vtu_snapshot(struct devlink *dl,
    445					 const struct devlink_region_ops *ops,
    446					 struct netlink_ext_ack *extack,
    447					 u8 **data)
    448{
    449	struct mv88e6xxx_devlink_vtu_entry *table, *entry;
    450	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
    451	struct mv88e6xxx_chip *chip = ds->priv;
    452	struct mv88e6xxx_vtu_entry vlan;
    453	int err;
    454
    455	table = kcalloc(mv88e6xxx_max_vid(chip) + 1,
    456			sizeof(struct mv88e6xxx_devlink_vtu_entry),
    457			GFP_KERNEL);
    458	if (!table)
    459		return -ENOMEM;
    460
    461	entry = table;
    462	vlan.vid = mv88e6xxx_max_vid(chip);
    463	vlan.valid = false;
    464
    465	mv88e6xxx_reg_lock(chip);
    466
    467	do {
    468		err = mv88e6xxx_g1_vtu_getnext(chip, &vlan);
    469		if (err)
    470			break;
    471
    472		if (!vlan.valid)
    473			break;
    474
    475		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_FID,
    476						&entry->fid);
    477		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
    478						&entry->sid);
    479		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_OP,
    480						&entry->op);
    481		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
    482						&entry->vid);
    483		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
    484						&entry->data[0]);
    485		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
    486						&entry->data[1]);
    487		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
    488						&entry->data[2]);
    489		if (err)
    490			break;
    491
    492		entry++;
    493	} while (vlan.vid < mv88e6xxx_max_vid(chip));
    494
    495	mv88e6xxx_reg_unlock(chip);
    496
    497	if (err) {
    498		kfree(table);
    499		return err;
    500	}
    501
    502	*data = (u8 *)table;
    503	return 0;
    504}
    505
    506/**
    507 * struct mv88e6xxx_devlink_stu_entry - Devlink STU entry
    508 * @sid:   Global1/3:   SID, unknown filters and learning.
    509 * @vid:   Global1/6:   Valid bit.
    510 * @data:  Global1/7-9: Membership data and priority override.
    511 * @resvd: Reserved. In case we forgot something.
    512 *
    513 * The STU entry format varies between chipset generations. Peridot
    514 * and Amethyst packs the STU data into Global1/7-8. Older silicon
    515 * spreads the information across all three VTU data registers -
    516 * inheriting the layout of even older hardware that had no STU at
    517 * all. Since this is a low-level debug interface, copy all data
    518 * verbatim and defer parsing to the consumer.
    519 */
    520struct mv88e6xxx_devlink_stu_entry {
    521	u16 sid;
    522	u16 vid;
    523	u16 data[3];
    524	u16 resvd;
    525};
    526
    527static int mv88e6xxx_region_stu_snapshot(struct devlink *dl,
    528					 const struct devlink_region_ops *ops,
    529					 struct netlink_ext_ack *extack,
    530					 u8 **data)
    531{
    532	struct mv88e6xxx_devlink_stu_entry *table, *entry;
    533	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
    534	struct mv88e6xxx_chip *chip = ds->priv;
    535	struct mv88e6xxx_stu_entry stu;
    536	int err;
    537
    538	table = kcalloc(mv88e6xxx_max_sid(chip) + 1,
    539			sizeof(struct mv88e6xxx_devlink_stu_entry),
    540			GFP_KERNEL);
    541	if (!table)
    542		return -ENOMEM;
    543
    544	entry = table;
    545	stu.sid = mv88e6xxx_max_sid(chip);
    546	stu.valid = false;
    547
    548	mv88e6xxx_reg_lock(chip);
    549
    550	do {
    551		err = mv88e6xxx_g1_stu_getnext(chip, &stu);
    552		if (err)
    553			break;
    554
    555		if (!stu.valid)
    556			break;
    557
    558		err = err ? : mv88e6xxx_g1_read(chip, MV88E6352_G1_VTU_SID,
    559						&entry->sid);
    560		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_VID,
    561						&entry->vid);
    562		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA1,
    563						&entry->data[0]);
    564		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA2,
    565						&entry->data[1]);
    566		err = err ? : mv88e6xxx_g1_read(chip, MV88E6XXX_G1_VTU_DATA3,
    567						&entry->data[2]);
    568		if (err)
    569			break;
    570
    571		entry++;
    572	} while (stu.sid < mv88e6xxx_max_sid(chip));
    573
    574	mv88e6xxx_reg_unlock(chip);
    575
    576	if (err) {
    577		kfree(table);
    578		return err;
    579	}
    580
    581	*data = (u8 *)table;
    582	return 0;
    583}
    584
    585static int mv88e6xxx_region_pvt_snapshot(struct devlink *dl,
    586					 const struct devlink_region_ops *ops,
    587					 struct netlink_ext_ack *extack,
    588					 u8 **data)
    589{
    590	struct dsa_switch *ds = dsa_devlink_to_ds(dl);
    591	struct mv88e6xxx_chip *chip = ds->priv;
    592	int dev, port, err;
    593	u16 *pvt, *cur;
    594
    595	pvt = kcalloc(MV88E6XXX_MAX_PVT_ENTRIES, sizeof(*pvt), GFP_KERNEL);
    596	if (!pvt)
    597		return -ENOMEM;
    598
    599	mv88e6xxx_reg_lock(chip);
    600
    601	cur = pvt;
    602	for (dev = 0; dev < MV88E6XXX_MAX_PVT_SWITCHES; dev++) {
    603		for (port = 0; port < MV88E6XXX_MAX_PVT_PORTS; port++) {
    604			err = mv88e6xxx_g2_pvt_read(chip, dev, port, cur);
    605			if (err)
    606				break;
    607
    608			cur++;
    609		}
    610	}
    611
    612	mv88e6xxx_reg_unlock(chip);
    613
    614	if (err) {
    615		kfree(pvt);
    616		return err;
    617	}
    618
    619	*data = (u8 *)pvt;
    620	return 0;
    621}
    622
    623static int mv88e6xxx_region_port_snapshot(struct devlink_port *devlink_port,
    624					  const struct devlink_port_region_ops *ops,
    625					  struct netlink_ext_ack *extack,
    626					  u8 **data)
    627{
    628	struct dsa_switch *ds = dsa_devlink_port_to_ds(devlink_port);
    629	int port = dsa_devlink_port_to_port(devlink_port);
    630	struct mv88e6xxx_chip *chip = ds->priv;
    631	u16 *registers;
    632	int i, err;
    633
    634	registers = kmalloc_array(32, sizeof(u16), GFP_KERNEL);
    635	if (!registers)
    636		return -ENOMEM;
    637
    638	mv88e6xxx_reg_lock(chip);
    639	for (i = 0; i < 32; i++) {
    640		err = mv88e6xxx_port_read(chip, port, i, &registers[i]);
    641		if (err) {
    642			kfree(registers);
    643			goto out;
    644		}
    645	}
    646	*data = (u8 *)registers;
    647out:
    648	mv88e6xxx_reg_unlock(chip);
    649
    650	return err;
    651}
    652
    653static struct mv88e6xxx_region_priv mv88e6xxx_region_global1_priv = {
    654	.id = MV88E6XXX_REGION_GLOBAL1,
    655};
    656
    657static struct devlink_region_ops mv88e6xxx_region_global1_ops = {
    658	.name = "global1",
    659	.snapshot = mv88e6xxx_region_global_snapshot,
    660	.destructor = kfree,
    661	.priv = &mv88e6xxx_region_global1_priv,
    662};
    663
    664static struct mv88e6xxx_region_priv mv88e6xxx_region_global2_priv = {
    665	.id = MV88E6XXX_REGION_GLOBAL2,
    666};
    667
    668static struct devlink_region_ops mv88e6xxx_region_global2_ops = {
    669	.name = "global2",
    670	.snapshot = mv88e6xxx_region_global_snapshot,
    671	.destructor = kfree,
    672	.priv = &mv88e6xxx_region_global2_priv,
    673};
    674
    675static struct devlink_region_ops mv88e6xxx_region_atu_ops = {
    676	.name = "atu",
    677	.snapshot = mv88e6xxx_region_atu_snapshot,
    678	.destructor = kfree,
    679};
    680
    681static struct devlink_region_ops mv88e6xxx_region_vtu_ops = {
    682	.name = "vtu",
    683	.snapshot = mv88e6xxx_region_vtu_snapshot,
    684	.destructor = kfree,
    685};
    686
    687static struct devlink_region_ops mv88e6xxx_region_stu_ops = {
    688	.name = "stu",
    689	.snapshot = mv88e6xxx_region_stu_snapshot,
    690	.destructor = kfree,
    691};
    692
    693static struct devlink_region_ops mv88e6xxx_region_pvt_ops = {
    694	.name = "pvt",
    695	.snapshot = mv88e6xxx_region_pvt_snapshot,
    696	.destructor = kfree,
    697};
    698
    699static const struct devlink_port_region_ops mv88e6xxx_region_port_ops = {
    700	.name = "port",
    701	.snapshot = mv88e6xxx_region_port_snapshot,
    702	.destructor = kfree,
    703};
    704
    705struct mv88e6xxx_region {
    706	struct devlink_region_ops *ops;
    707	u64 size;
    708
    709	bool (*cond)(struct mv88e6xxx_chip *chip);
    710};
    711
    712static struct mv88e6xxx_region mv88e6xxx_regions[] = {
    713	[MV88E6XXX_REGION_GLOBAL1] = {
    714		.ops = &mv88e6xxx_region_global1_ops,
    715		.size = 32 * sizeof(u16)
    716	},
    717	[MV88E6XXX_REGION_GLOBAL2] = {
    718		.ops = &mv88e6xxx_region_global2_ops,
    719		.size = 32 * sizeof(u16) },
    720	[MV88E6XXX_REGION_ATU] = {
    721		.ops = &mv88e6xxx_region_atu_ops
    722	  /* calculated at runtime */
    723	},
    724	[MV88E6XXX_REGION_VTU] = {
    725		.ops = &mv88e6xxx_region_vtu_ops
    726	  /* calculated at runtime */
    727	},
    728	[MV88E6XXX_REGION_STU] = {
    729		.ops = &mv88e6xxx_region_stu_ops,
    730		.cond = mv88e6xxx_has_stu,
    731	  /* calculated at runtime */
    732	},
    733	[MV88E6XXX_REGION_PVT] = {
    734		.ops = &mv88e6xxx_region_pvt_ops,
    735		.size = MV88E6XXX_MAX_PVT_ENTRIES * sizeof(u16),
    736		.cond = mv88e6xxx_has_pvt,
    737	},
    738};
    739
    740void mv88e6xxx_teardown_devlink_regions_global(struct dsa_switch *ds)
    741{
    742	struct mv88e6xxx_chip *chip = ds->priv;
    743	int i;
    744
    745	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++)
    746		dsa_devlink_region_destroy(chip->regions[i]);
    747}
    748
    749void mv88e6xxx_teardown_devlink_regions_port(struct dsa_switch *ds, int port)
    750{
    751	struct mv88e6xxx_chip *chip = ds->priv;
    752
    753	dsa_devlink_region_destroy(chip->ports[port].region);
    754}
    755
    756int mv88e6xxx_setup_devlink_regions_port(struct dsa_switch *ds, int port)
    757{
    758	struct mv88e6xxx_chip *chip = ds->priv;
    759	struct devlink_region *region;
    760
    761	region = dsa_devlink_port_region_create(ds,
    762						port,
    763						&mv88e6xxx_region_port_ops, 1,
    764						32 * sizeof(u16));
    765	if (IS_ERR(region))
    766		return PTR_ERR(region);
    767
    768	chip->ports[port].region = region;
    769
    770	return 0;
    771}
    772
    773int mv88e6xxx_setup_devlink_regions_global(struct dsa_switch *ds)
    774{
    775	bool (*cond)(struct mv88e6xxx_chip *chip);
    776	struct mv88e6xxx_chip *chip = ds->priv;
    777	struct devlink_region_ops *ops;
    778	struct devlink_region *region;
    779	u64 size;
    780	int i, j;
    781
    782	for (i = 0; i < ARRAY_SIZE(mv88e6xxx_regions); i++) {
    783		ops = mv88e6xxx_regions[i].ops;
    784		size = mv88e6xxx_regions[i].size;
    785		cond = mv88e6xxx_regions[i].cond;
    786
    787		if (cond && !cond(chip))
    788			continue;
    789
    790		switch (i) {
    791		case MV88E6XXX_REGION_ATU:
    792			size = mv88e6xxx_num_databases(chip) *
    793				sizeof(struct mv88e6xxx_devlink_atu_entry);
    794			break;
    795		case MV88E6XXX_REGION_VTU:
    796			size = (mv88e6xxx_max_vid(chip) + 1) *
    797				sizeof(struct mv88e6xxx_devlink_vtu_entry);
    798			break;
    799		case MV88E6XXX_REGION_STU:
    800			size = (mv88e6xxx_max_sid(chip) + 1) *
    801				sizeof(struct mv88e6xxx_devlink_stu_entry);
    802			break;
    803		}
    804
    805		region = dsa_devlink_region_create(ds, ops, 1, size);
    806		if (IS_ERR(region))
    807			goto out;
    808		chip->regions[i] = region;
    809	}
    810	return 0;
    811
    812out:
    813	for (j = 0; j < i; j++)
    814		dsa_devlink_region_destroy(chip->regions[j]);
    815
    816	return PTR_ERR(region);
    817}
    818
    819int mv88e6xxx_devlink_info_get(struct dsa_switch *ds,
    820			       struct devlink_info_req *req,
    821			       struct netlink_ext_ack *extack)
    822{
    823	struct mv88e6xxx_chip *chip = ds->priv;
    824	int err;
    825
    826	err = devlink_info_driver_name_put(req, "mv88e6xxx");
    827	if (err)
    828		return err;
    829
    830	return devlink_info_version_fixed_put(req,
    831					      DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,
    832					      chip->info->name);
    833}