brintos

brintos / linux-shallow public Read only

0
0
Text · 19.4 KiB · a08dab7 Raw
829 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2#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. Define305 * a generic format which covers all the current and hopefully future306 * mv88e6xxx generations307 */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 entry422 * @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, the430 * descriptions above represent the superset of all possible431 * information, not all fields are valid on all devices. Since this is432 * a low-level debug interface, copy all data verbatim and defer433 * 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 entry508 * @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. Peridot514 * and Amethyst packs the STU data into Global1/7-8. Older silicon515 * spreads the information across all three VTU data registers -516 * inheriting the layout of even older hardware that had no STU at517 * all. Since this is a low-level debug interface, copy all data518 * 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_ops722	  /* calculated at runtime */723	},724	[MV88E6XXX_REGION_VTU] = {725		.ops = &mv88e6xxx_region_vtu_ops726	  /* 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 825	return devlink_info_version_fixed_put(req,826					      DEVLINK_INFO_VERSION_GENERIC_ASIC_ID,827					      chip->info->name);828}829