162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Management Complex (MC) userspace support
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2021 NXP
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/slab.h>
1062306a36Sopenharmony_ci#include <linux/fs.h>
1162306a36Sopenharmony_ci#include <linux/uaccess.h>
1262306a36Sopenharmony_ci#include <linux/miscdevice.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "fsl-mc-private.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistruct uapi_priv_data {
1762306a36Sopenharmony_ci	struct fsl_mc_uapi *uapi;
1862306a36Sopenharmony_ci	struct fsl_mc_io *mc_io;
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistruct fsl_mc_cmd_desc {
2262306a36Sopenharmony_ci	u16 cmdid_value;
2362306a36Sopenharmony_ci	u16 cmdid_mask;
2462306a36Sopenharmony_ci	int size;
2562306a36Sopenharmony_ci	bool token;
2662306a36Sopenharmony_ci	int flags;
2762306a36Sopenharmony_ci};
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#define FSL_MC_CHECK_MODULE_ID		BIT(0)
3062306a36Sopenharmony_ci#define FSL_MC_CAP_NET_ADMIN_NEEDED	BIT(1)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_cienum fsl_mc_cmd_index {
3362306a36Sopenharmony_ci	DPDBG_DUMP = 0,
3462306a36Sopenharmony_ci	DPDBG_SET,
3562306a36Sopenharmony_ci	DPRC_GET_CONTAINER_ID,
3662306a36Sopenharmony_ci	DPRC_CREATE_CONT,
3762306a36Sopenharmony_ci	DPRC_DESTROY_CONT,
3862306a36Sopenharmony_ci	DPRC_ASSIGN,
3962306a36Sopenharmony_ci	DPRC_UNASSIGN,
4062306a36Sopenharmony_ci	DPRC_GET_OBJ_COUNT,
4162306a36Sopenharmony_ci	DPRC_GET_OBJ,
4262306a36Sopenharmony_ci	DPRC_GET_RES_COUNT,
4362306a36Sopenharmony_ci	DPRC_GET_RES_IDS,
4462306a36Sopenharmony_ci	DPRC_SET_OBJ_LABEL,
4562306a36Sopenharmony_ci	DPRC_SET_LOCKED,
4662306a36Sopenharmony_ci	DPRC_CONNECT,
4762306a36Sopenharmony_ci	DPRC_DISCONNECT,
4862306a36Sopenharmony_ci	DPRC_GET_POOL,
4962306a36Sopenharmony_ci	DPRC_GET_POOL_COUNT,
5062306a36Sopenharmony_ci	DPRC_GET_CONNECTION,
5162306a36Sopenharmony_ci	DPCI_GET_LINK_STATE,
5262306a36Sopenharmony_ci	DPCI_GET_PEER_ATTR,
5362306a36Sopenharmony_ci	DPAIOP_GET_SL_VERSION,
5462306a36Sopenharmony_ci	DPAIOP_GET_STATE,
5562306a36Sopenharmony_ci	DPMNG_GET_VERSION,
5662306a36Sopenharmony_ci	DPSECI_GET_TX_QUEUE,
5762306a36Sopenharmony_ci	DPMAC_GET_COUNTER,
5862306a36Sopenharmony_ci	DPMAC_GET_MAC_ADDR,
5962306a36Sopenharmony_ci	DPNI_SET_PRIM_MAC,
6062306a36Sopenharmony_ci	DPNI_GET_PRIM_MAC,
6162306a36Sopenharmony_ci	DPNI_GET_STATISTICS,
6262306a36Sopenharmony_ci	DPNI_GET_LINK_STATE,
6362306a36Sopenharmony_ci	DPNI_GET_MAX_FRAME_LENGTH,
6462306a36Sopenharmony_ci	DPSW_GET_TAILDROP,
6562306a36Sopenharmony_ci	DPSW_SET_TAILDROP,
6662306a36Sopenharmony_ci	DPSW_IF_GET_COUNTER,
6762306a36Sopenharmony_ci	DPSW_IF_GET_MAX_FRAME_LENGTH,
6862306a36Sopenharmony_ci	DPDMUX_GET_COUNTER,
6962306a36Sopenharmony_ci	DPDMUX_IF_GET_MAX_FRAME_LENGTH,
7062306a36Sopenharmony_ci	GET_ATTR,
7162306a36Sopenharmony_ci	GET_IRQ_MASK,
7262306a36Sopenharmony_ci	GET_IRQ_STATUS,
7362306a36Sopenharmony_ci	CLOSE,
7462306a36Sopenharmony_ci	OPEN,
7562306a36Sopenharmony_ci	GET_API_VERSION,
7662306a36Sopenharmony_ci	DESTROY,
7762306a36Sopenharmony_ci	CREATE,
7862306a36Sopenharmony_ci};
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
8162306a36Sopenharmony_ci	[DPDBG_DUMP] = {
8262306a36Sopenharmony_ci		.cmdid_value = 0x1300,
8362306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
8462306a36Sopenharmony_ci		.token = true,
8562306a36Sopenharmony_ci		.size = 28,
8662306a36Sopenharmony_ci	},
8762306a36Sopenharmony_ci	[DPDBG_SET] = {
8862306a36Sopenharmony_ci		.cmdid_value = 0x1400,
8962306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
9062306a36Sopenharmony_ci		.token = true,
9162306a36Sopenharmony_ci		.size = 28,
9262306a36Sopenharmony_ci	},
9362306a36Sopenharmony_ci	[DPRC_GET_CONTAINER_ID] = {
9462306a36Sopenharmony_ci		.cmdid_value = 0x8300,
9562306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
9662306a36Sopenharmony_ci		.token = false,
9762306a36Sopenharmony_ci		.size = 8,
9862306a36Sopenharmony_ci	},
9962306a36Sopenharmony_ci	[DPRC_CREATE_CONT] = {
10062306a36Sopenharmony_ci		.cmdid_value = 0x1510,
10162306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
10262306a36Sopenharmony_ci		.token = true,
10362306a36Sopenharmony_ci		.size = 40,
10462306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
10562306a36Sopenharmony_ci	},
10662306a36Sopenharmony_ci	[DPRC_DESTROY_CONT] = {
10762306a36Sopenharmony_ci		.cmdid_value = 0x1520,
10862306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
10962306a36Sopenharmony_ci		.token = true,
11062306a36Sopenharmony_ci		.size = 12,
11162306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
11262306a36Sopenharmony_ci	},
11362306a36Sopenharmony_ci	[DPRC_ASSIGN] = {
11462306a36Sopenharmony_ci		.cmdid_value = 0x1570,
11562306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
11662306a36Sopenharmony_ci		.token = true,
11762306a36Sopenharmony_ci		.size = 40,
11862306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
11962306a36Sopenharmony_ci	},
12062306a36Sopenharmony_ci	[DPRC_UNASSIGN] = {
12162306a36Sopenharmony_ci		.cmdid_value = 0x1580,
12262306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
12362306a36Sopenharmony_ci		.token = true,
12462306a36Sopenharmony_ci		.size = 40,
12562306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
12662306a36Sopenharmony_ci	},
12762306a36Sopenharmony_ci	[DPRC_GET_OBJ_COUNT] = {
12862306a36Sopenharmony_ci		.cmdid_value = 0x1590,
12962306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
13062306a36Sopenharmony_ci		.token = true,
13162306a36Sopenharmony_ci		.size = 16,
13262306a36Sopenharmony_ci	},
13362306a36Sopenharmony_ci	[DPRC_GET_OBJ] = {
13462306a36Sopenharmony_ci		.cmdid_value = 0x15A0,
13562306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
13662306a36Sopenharmony_ci		.token = true,
13762306a36Sopenharmony_ci		.size = 12,
13862306a36Sopenharmony_ci	},
13962306a36Sopenharmony_ci	[DPRC_GET_RES_COUNT] = {
14062306a36Sopenharmony_ci		.cmdid_value = 0x15B0,
14162306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
14262306a36Sopenharmony_ci		.token = true,
14362306a36Sopenharmony_ci		.size = 32,
14462306a36Sopenharmony_ci	},
14562306a36Sopenharmony_ci	[DPRC_GET_RES_IDS] = {
14662306a36Sopenharmony_ci		.cmdid_value = 0x15C0,
14762306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
14862306a36Sopenharmony_ci		.token = true,
14962306a36Sopenharmony_ci		.size = 40,
15062306a36Sopenharmony_ci	},
15162306a36Sopenharmony_ci	[DPRC_SET_OBJ_LABEL] = {
15262306a36Sopenharmony_ci		.cmdid_value = 0x1610,
15362306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
15462306a36Sopenharmony_ci		.token = true,
15562306a36Sopenharmony_ci		.size = 48,
15662306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
15762306a36Sopenharmony_ci	},
15862306a36Sopenharmony_ci	[DPRC_SET_LOCKED] = {
15962306a36Sopenharmony_ci		.cmdid_value = 0x16B0,
16062306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
16162306a36Sopenharmony_ci		.token = true,
16262306a36Sopenharmony_ci		.size = 16,
16362306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
16462306a36Sopenharmony_ci	},
16562306a36Sopenharmony_ci	[DPRC_CONNECT] = {
16662306a36Sopenharmony_ci		.cmdid_value = 0x1670,
16762306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
16862306a36Sopenharmony_ci		.token = true,
16962306a36Sopenharmony_ci		.size = 56,
17062306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
17162306a36Sopenharmony_ci	},
17262306a36Sopenharmony_ci	[DPRC_DISCONNECT] = {
17362306a36Sopenharmony_ci		.cmdid_value = 0x1680,
17462306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
17562306a36Sopenharmony_ci		.token = true,
17662306a36Sopenharmony_ci		.size = 32,
17762306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
17862306a36Sopenharmony_ci	},
17962306a36Sopenharmony_ci	[DPRC_GET_POOL] = {
18062306a36Sopenharmony_ci		.cmdid_value = 0x1690,
18162306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
18262306a36Sopenharmony_ci		.token = true,
18362306a36Sopenharmony_ci		.size = 12,
18462306a36Sopenharmony_ci	},
18562306a36Sopenharmony_ci	[DPRC_GET_POOL_COUNT] = {
18662306a36Sopenharmony_ci		.cmdid_value = 0x16A0,
18762306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
18862306a36Sopenharmony_ci		.token = true,
18962306a36Sopenharmony_ci		.size = 8,
19062306a36Sopenharmony_ci	},
19162306a36Sopenharmony_ci	[DPRC_GET_CONNECTION] = {
19262306a36Sopenharmony_ci		.cmdid_value = 0x16C0,
19362306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
19462306a36Sopenharmony_ci		.token = true,
19562306a36Sopenharmony_ci		.size = 32,
19662306a36Sopenharmony_ci	},
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	[DPCI_GET_LINK_STATE] = {
19962306a36Sopenharmony_ci		.cmdid_value = 0x0E10,
20062306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
20162306a36Sopenharmony_ci		.token = true,
20262306a36Sopenharmony_ci		.size = 8,
20362306a36Sopenharmony_ci	},
20462306a36Sopenharmony_ci	[DPCI_GET_PEER_ATTR] = {
20562306a36Sopenharmony_ci		.cmdid_value = 0x0E20,
20662306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
20762306a36Sopenharmony_ci		.token = true,
20862306a36Sopenharmony_ci		.size = 8,
20962306a36Sopenharmony_ci	},
21062306a36Sopenharmony_ci	[DPAIOP_GET_SL_VERSION] = {
21162306a36Sopenharmony_ci		.cmdid_value = 0x2820,
21262306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
21362306a36Sopenharmony_ci		.token = true,
21462306a36Sopenharmony_ci		.size = 8,
21562306a36Sopenharmony_ci	},
21662306a36Sopenharmony_ci	[DPAIOP_GET_STATE] = {
21762306a36Sopenharmony_ci		.cmdid_value = 0x2830,
21862306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
21962306a36Sopenharmony_ci		.token = true,
22062306a36Sopenharmony_ci		.size = 8,
22162306a36Sopenharmony_ci	},
22262306a36Sopenharmony_ci	[DPMNG_GET_VERSION] = {
22362306a36Sopenharmony_ci		.cmdid_value = 0x8310,
22462306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
22562306a36Sopenharmony_ci		.token = false,
22662306a36Sopenharmony_ci		.size = 8,
22762306a36Sopenharmony_ci	},
22862306a36Sopenharmony_ci	[DPSECI_GET_TX_QUEUE] = {
22962306a36Sopenharmony_ci		.cmdid_value = 0x1970,
23062306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
23162306a36Sopenharmony_ci		.token = true,
23262306a36Sopenharmony_ci		.size = 14,
23362306a36Sopenharmony_ci	},
23462306a36Sopenharmony_ci	[DPMAC_GET_COUNTER] = {
23562306a36Sopenharmony_ci		.cmdid_value = 0x0c40,
23662306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
23762306a36Sopenharmony_ci		.token = true,
23862306a36Sopenharmony_ci		.size = 9,
23962306a36Sopenharmony_ci	},
24062306a36Sopenharmony_ci	[DPMAC_GET_MAC_ADDR] = {
24162306a36Sopenharmony_ci		.cmdid_value = 0x0c50,
24262306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
24362306a36Sopenharmony_ci		.token = true,
24462306a36Sopenharmony_ci		.size = 8,
24562306a36Sopenharmony_ci	},
24662306a36Sopenharmony_ci	[DPNI_SET_PRIM_MAC] = {
24762306a36Sopenharmony_ci		.cmdid_value = 0x2240,
24862306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
24962306a36Sopenharmony_ci		.token = true,
25062306a36Sopenharmony_ci		.size = 16,
25162306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
25262306a36Sopenharmony_ci	},
25362306a36Sopenharmony_ci	[DPNI_GET_PRIM_MAC] = {
25462306a36Sopenharmony_ci		.cmdid_value = 0x2250,
25562306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
25662306a36Sopenharmony_ci		.token = true,
25762306a36Sopenharmony_ci		.size = 8,
25862306a36Sopenharmony_ci	},
25962306a36Sopenharmony_ci	[DPNI_GET_STATISTICS] = {
26062306a36Sopenharmony_ci		.cmdid_value = 0x25D0,
26162306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
26262306a36Sopenharmony_ci		.token = true,
26362306a36Sopenharmony_ci		.size = 10,
26462306a36Sopenharmony_ci	},
26562306a36Sopenharmony_ci	[DPNI_GET_LINK_STATE] = {
26662306a36Sopenharmony_ci		.cmdid_value = 0x2150,
26762306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
26862306a36Sopenharmony_ci		.token = true,
26962306a36Sopenharmony_ci		.size = 8,
27062306a36Sopenharmony_ci	},
27162306a36Sopenharmony_ci	[DPNI_GET_MAX_FRAME_LENGTH] = {
27262306a36Sopenharmony_ci		.cmdid_value = 0x2170,
27362306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
27462306a36Sopenharmony_ci		.token = true,
27562306a36Sopenharmony_ci		.size = 8,
27662306a36Sopenharmony_ci	},
27762306a36Sopenharmony_ci	[DPSW_GET_TAILDROP] = {
27862306a36Sopenharmony_ci		.cmdid_value = 0x0A80,
27962306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
28062306a36Sopenharmony_ci		.token = true,
28162306a36Sopenharmony_ci		.size = 14,
28262306a36Sopenharmony_ci	},
28362306a36Sopenharmony_ci	[DPSW_SET_TAILDROP] = {
28462306a36Sopenharmony_ci		.cmdid_value = 0x0A90,
28562306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
28662306a36Sopenharmony_ci		.token = true,
28762306a36Sopenharmony_ci		.size = 24,
28862306a36Sopenharmony_ci		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
28962306a36Sopenharmony_ci	},
29062306a36Sopenharmony_ci	[DPSW_IF_GET_COUNTER] = {
29162306a36Sopenharmony_ci		.cmdid_value = 0x0340,
29262306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
29362306a36Sopenharmony_ci		.token = true,
29462306a36Sopenharmony_ci		.size = 11,
29562306a36Sopenharmony_ci	},
29662306a36Sopenharmony_ci	[DPSW_IF_GET_MAX_FRAME_LENGTH] = {
29762306a36Sopenharmony_ci		.cmdid_value = 0x0450,
29862306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
29962306a36Sopenharmony_ci		.token = true,
30062306a36Sopenharmony_ci		.size = 10,
30162306a36Sopenharmony_ci	},
30262306a36Sopenharmony_ci	[DPDMUX_GET_COUNTER] = {
30362306a36Sopenharmony_ci		.cmdid_value = 0x0b20,
30462306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
30562306a36Sopenharmony_ci		.token = true,
30662306a36Sopenharmony_ci		.size = 11,
30762306a36Sopenharmony_ci	},
30862306a36Sopenharmony_ci	[DPDMUX_IF_GET_MAX_FRAME_LENGTH] = {
30962306a36Sopenharmony_ci		.cmdid_value = 0x0a20,
31062306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
31162306a36Sopenharmony_ci		.token = true,
31262306a36Sopenharmony_ci		.size = 10,
31362306a36Sopenharmony_ci	},
31462306a36Sopenharmony_ci	[GET_ATTR] = {
31562306a36Sopenharmony_ci		.cmdid_value = 0x0040,
31662306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
31762306a36Sopenharmony_ci		.token = true,
31862306a36Sopenharmony_ci		.size = 8,
31962306a36Sopenharmony_ci	},
32062306a36Sopenharmony_ci	[GET_IRQ_MASK] = {
32162306a36Sopenharmony_ci		.cmdid_value = 0x0150,
32262306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
32362306a36Sopenharmony_ci		.token = true,
32462306a36Sopenharmony_ci		.size = 13,
32562306a36Sopenharmony_ci	},
32662306a36Sopenharmony_ci	[GET_IRQ_STATUS] = {
32762306a36Sopenharmony_ci		.cmdid_value = 0x0160,
32862306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
32962306a36Sopenharmony_ci		.token = true,
33062306a36Sopenharmony_ci		.size = 13,
33162306a36Sopenharmony_ci	},
33262306a36Sopenharmony_ci	[CLOSE] = {
33362306a36Sopenharmony_ci		.cmdid_value = 0x8000,
33462306a36Sopenharmony_ci		.cmdid_mask = 0xFFF0,
33562306a36Sopenharmony_ci		.token = true,
33662306a36Sopenharmony_ci		.size = 8,
33762306a36Sopenharmony_ci	},
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/* Common commands amongst all types of objects. Must be checked last. */
34062306a36Sopenharmony_ci	[OPEN] = {
34162306a36Sopenharmony_ci		.cmdid_value = 0x8000,
34262306a36Sopenharmony_ci		.cmdid_mask = 0xFC00,
34362306a36Sopenharmony_ci		.token = false,
34462306a36Sopenharmony_ci		.size = 12,
34562306a36Sopenharmony_ci		.flags = FSL_MC_CHECK_MODULE_ID,
34662306a36Sopenharmony_ci	},
34762306a36Sopenharmony_ci	[GET_API_VERSION] = {
34862306a36Sopenharmony_ci		.cmdid_value = 0xA000,
34962306a36Sopenharmony_ci		.cmdid_mask = 0xFC00,
35062306a36Sopenharmony_ci		.token = false,
35162306a36Sopenharmony_ci		.size = 8,
35262306a36Sopenharmony_ci		.flags = FSL_MC_CHECK_MODULE_ID,
35362306a36Sopenharmony_ci	},
35462306a36Sopenharmony_ci	[DESTROY] = {
35562306a36Sopenharmony_ci		.cmdid_value = 0x9800,
35662306a36Sopenharmony_ci		.cmdid_mask = 0xFC00,
35762306a36Sopenharmony_ci		.token = true,
35862306a36Sopenharmony_ci		.size = 12,
35962306a36Sopenharmony_ci		.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
36062306a36Sopenharmony_ci	},
36162306a36Sopenharmony_ci	[CREATE] = {
36262306a36Sopenharmony_ci		.cmdid_value = 0x9000,
36362306a36Sopenharmony_ci		.cmdid_mask = 0xFC00,
36462306a36Sopenharmony_ci		.token = true,
36562306a36Sopenharmony_ci		.size = 64,
36662306a36Sopenharmony_ci		.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
36762306a36Sopenharmony_ci	},
36862306a36Sopenharmony_ci};
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci#define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds)
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci#define FSL_MC_MAX_MODULE_ID 0x10
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_cistatic int fsl_mc_command_check(struct fsl_mc_device *mc_dev,
37562306a36Sopenharmony_ci				struct fsl_mc_command *mc_cmd)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	struct fsl_mc_cmd_desc *desc = NULL;
37862306a36Sopenharmony_ci	int mc_cmd_max_size, i;
37962306a36Sopenharmony_ci	bool token_provided;
38062306a36Sopenharmony_ci	u16 cmdid, module_id;
38162306a36Sopenharmony_ci	char *mc_cmd_end;
38262306a36Sopenharmony_ci	char sum = 0;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	/* Check if this is an accepted MC command */
38562306a36Sopenharmony_ci	cmdid = mc_cmd_hdr_read_cmdid(mc_cmd);
38662306a36Sopenharmony_ci	for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) {
38762306a36Sopenharmony_ci		desc = &fsl_mc_accepted_cmds[i];
38862306a36Sopenharmony_ci		if ((cmdid & desc->cmdid_mask) == desc->cmdid_value)
38962306a36Sopenharmony_ci			break;
39062306a36Sopenharmony_ci	}
39162306a36Sopenharmony_ci	if (i == FSL_MC_NUM_ACCEPTED_CMDS) {
39262306a36Sopenharmony_ci		dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid);
39362306a36Sopenharmony_ci		return -EACCES;
39462306a36Sopenharmony_ci	}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	/* Check if the size of the command is honored. Anything beyond the
39762306a36Sopenharmony_ci	 * last valid byte of the command should be zeroed.
39862306a36Sopenharmony_ci	 */
39962306a36Sopenharmony_ci	mc_cmd_max_size = sizeof(*mc_cmd);
40062306a36Sopenharmony_ci	mc_cmd_end = ((char *)mc_cmd) + desc->size;
40162306a36Sopenharmony_ci	for (i = desc->size; i < mc_cmd_max_size; i++)
40262306a36Sopenharmony_ci		sum |= *mc_cmd_end++;
40362306a36Sopenharmony_ci	if (sum) {
40462306a36Sopenharmony_ci		dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n",
40562306a36Sopenharmony_ci			cmdid, desc->size);
40662306a36Sopenharmony_ci		return -EACCES;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/* Some MC commands request a token to be passed so that object
41062306a36Sopenharmony_ci	 * identification is possible. Check if the token passed in the command
41162306a36Sopenharmony_ci	 * is as expected.
41262306a36Sopenharmony_ci	 */
41362306a36Sopenharmony_ci	token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false;
41462306a36Sopenharmony_ci	if (token_provided != desc->token) {
41562306a36Sopenharmony_ci		dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n",
41662306a36Sopenharmony_ci			cmdid, mc_cmd_hdr_read_token(mc_cmd));
41762306a36Sopenharmony_ci		return -EACCES;
41862306a36Sopenharmony_ci	}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci	/* If needed, check if the module ID passed is valid */
42162306a36Sopenharmony_ci	if (desc->flags & FSL_MC_CHECK_MODULE_ID) {
42262306a36Sopenharmony_ci		/* The module ID is represented by bits [4:9] from the cmdid */
42362306a36Sopenharmony_ci		module_id = (cmdid & GENMASK(9, 4)) >> 4;
42462306a36Sopenharmony_ci		if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) {
42562306a36Sopenharmony_ci			dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n",
42662306a36Sopenharmony_ci				cmdid, module_id);
42762306a36Sopenharmony_ci			return -EACCES;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/* Some commands alter how hardware resources are managed. For these
43262306a36Sopenharmony_ci	 * commands, check for CAP_NET_ADMIN.
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci	if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) {
43562306a36Sopenharmony_ci		if (!capable(CAP_NET_ADMIN)) {
43662306a36Sopenharmony_ci			dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n",
43762306a36Sopenharmony_ci				cmdid);
43862306a36Sopenharmony_ci			return -EPERM;
43962306a36Sopenharmony_ci		}
44062306a36Sopenharmony_ci	}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	return 0;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cistatic int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg,
44662306a36Sopenharmony_ci				    struct fsl_mc_io *mc_io)
44762306a36Sopenharmony_ci{
44862306a36Sopenharmony_ci	struct fsl_mc_command mc_cmd;
44962306a36Sopenharmony_ci	int error;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
45262306a36Sopenharmony_ci	if (error)
45362306a36Sopenharmony_ci		return -EFAULT;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	error = fsl_mc_command_check(mc_dev, &mc_cmd);
45662306a36Sopenharmony_ci	if (error)
45762306a36Sopenharmony_ci		return error;
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	error = mc_send_command(mc_io, &mc_cmd);
46062306a36Sopenharmony_ci	if (error)
46162306a36Sopenharmony_ci		return error;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
46462306a36Sopenharmony_ci	if (error)
46562306a36Sopenharmony_ci		return -EFAULT;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	return 0;
46862306a36Sopenharmony_ci}
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_cistatic int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
47162306a36Sopenharmony_ci{
47262306a36Sopenharmony_ci	struct fsl_mc_device *root_mc_device;
47362306a36Sopenharmony_ci	struct uapi_priv_data *priv_data;
47462306a36Sopenharmony_ci	struct fsl_mc_io *dynamic_mc_io;
47562306a36Sopenharmony_ci	struct fsl_mc_uapi *mc_uapi;
47662306a36Sopenharmony_ci	struct fsl_mc_bus *mc_bus;
47762306a36Sopenharmony_ci	int error;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
48062306a36Sopenharmony_ci	if (!priv_data)
48162306a36Sopenharmony_ci		return -ENOMEM;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
48462306a36Sopenharmony_ci	mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
48562306a36Sopenharmony_ci	root_mc_device = &mc_bus->mc_dev;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	mutex_lock(&mc_uapi->mutex);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci	if (!mc_uapi->local_instance_in_use) {
49062306a36Sopenharmony_ci		priv_data->mc_io = mc_uapi->static_mc_io;
49162306a36Sopenharmony_ci		mc_uapi->local_instance_in_use = 1;
49262306a36Sopenharmony_ci	} else {
49362306a36Sopenharmony_ci		error = fsl_mc_portal_allocate(root_mc_device, 0,
49462306a36Sopenharmony_ci					       &dynamic_mc_io);
49562306a36Sopenharmony_ci		if (error) {
49662306a36Sopenharmony_ci			dev_dbg(&root_mc_device->dev,
49762306a36Sopenharmony_ci				"Could not allocate MC portal\n");
49862306a36Sopenharmony_ci			goto error_portal_allocate;
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci		priv_data->mc_io = dynamic_mc_io;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci	priv_data->uapi = mc_uapi;
50462306a36Sopenharmony_ci	filep->private_data = priv_data;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci	mutex_unlock(&mc_uapi->mutex);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci	return 0;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_cierror_portal_allocate:
51162306a36Sopenharmony_ci	mutex_unlock(&mc_uapi->mutex);
51262306a36Sopenharmony_ci	kfree(priv_data);
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return error;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cistatic int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct uapi_priv_data *priv_data;
52062306a36Sopenharmony_ci	struct fsl_mc_uapi *mc_uapi;
52162306a36Sopenharmony_ci	struct fsl_mc_io *mc_io;
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	priv_data = filep->private_data;
52462306a36Sopenharmony_ci	mc_uapi = priv_data->uapi;
52562306a36Sopenharmony_ci	mc_io = priv_data->mc_io;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	mutex_lock(&mc_uapi->mutex);
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (mc_io == mc_uapi->static_mc_io)
53062306a36Sopenharmony_ci		mc_uapi->local_instance_in_use = 0;
53162306a36Sopenharmony_ci	else
53262306a36Sopenharmony_ci		fsl_mc_portal_free(mc_io);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	kfree(filep->private_data);
53562306a36Sopenharmony_ci	filep->private_data =  NULL;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	mutex_unlock(&mc_uapi->mutex);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	return 0;
54062306a36Sopenharmony_ci}
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic long fsl_mc_uapi_dev_ioctl(struct file *file,
54362306a36Sopenharmony_ci				  unsigned int cmd,
54462306a36Sopenharmony_ci				  unsigned long arg)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct uapi_priv_data *priv_data = file->private_data;
54762306a36Sopenharmony_ci	struct fsl_mc_device *root_mc_device;
54862306a36Sopenharmony_ci	struct fsl_mc_bus *mc_bus;
54962306a36Sopenharmony_ci	int error;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
55262306a36Sopenharmony_ci	root_mc_device = &mc_bus->mc_dev;
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	switch (cmd) {
55562306a36Sopenharmony_ci	case FSL_MC_SEND_MC_COMMAND:
55662306a36Sopenharmony_ci		error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io);
55762306a36Sopenharmony_ci		break;
55862306a36Sopenharmony_ci	default:
55962306a36Sopenharmony_ci		dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
56062306a36Sopenharmony_ci		error = -EINVAL;
56162306a36Sopenharmony_ci	}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	return error;
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic const struct file_operations fsl_mc_uapi_dev_fops = {
56762306a36Sopenharmony_ci	.owner = THIS_MODULE,
56862306a36Sopenharmony_ci	.open = fsl_mc_uapi_dev_open,
56962306a36Sopenharmony_ci	.release = fsl_mc_uapi_dev_release,
57062306a36Sopenharmony_ci	.unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
57162306a36Sopenharmony_ci};
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ciint fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
57662306a36Sopenharmony_ci	struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
57762306a36Sopenharmony_ci	int error;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
58062306a36Sopenharmony_ci	mc_uapi->misc.name = dev_name(&mc_dev->dev);
58162306a36Sopenharmony_ci	mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	error = misc_register(&mc_uapi->misc);
58462306a36Sopenharmony_ci	if (error)
58562306a36Sopenharmony_ci		return error;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	mutex_init(&mc_uapi->mutex);
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	return 0;
59262306a36Sopenharmony_ci}
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_civoid fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
59562306a36Sopenharmony_ci{
59662306a36Sopenharmony_ci	misc_deregister(&mc_bus->uapi_misc.misc);
59762306a36Sopenharmony_ci}
598