xref: /openbmc/linux/drivers/bus/fsl-mc/fsl-mc-uapi.c (revision d67cc29e)
12cf1e703SIoana Ciornei // SPDX-License-Identifier: GPL-2.0
22cf1e703SIoana Ciornei /*
32cf1e703SIoana Ciornei  * Management Complex (MC) userspace support
42cf1e703SIoana Ciornei  *
52cf1e703SIoana Ciornei  * Copyright 2021 NXP
62cf1e703SIoana Ciornei  *
72cf1e703SIoana Ciornei  */
82cf1e703SIoana Ciornei 
92cf1e703SIoana Ciornei #include <linux/slab.h>
102cf1e703SIoana Ciornei #include <linux/fs.h>
112cf1e703SIoana Ciornei #include <linux/uaccess.h>
122cf1e703SIoana Ciornei #include <linux/miscdevice.h>
132cf1e703SIoana Ciornei 
142cf1e703SIoana Ciornei #include "fsl-mc-private.h"
152cf1e703SIoana Ciornei 
162cf1e703SIoana Ciornei struct uapi_priv_data {
172cf1e703SIoana Ciornei 	struct fsl_mc_uapi *uapi;
182cf1e703SIoana Ciornei 	struct fsl_mc_io *mc_io;
192cf1e703SIoana Ciornei };
202cf1e703SIoana Ciornei 
212cf1e703SIoana Ciornei struct fsl_mc_cmd_desc {
222cf1e703SIoana Ciornei 	u16 cmdid_value;
232cf1e703SIoana Ciornei 	u16 cmdid_mask;
242cf1e703SIoana Ciornei 	int size;
252cf1e703SIoana Ciornei 	bool token;
262cf1e703SIoana Ciornei 	int flags;
272cf1e703SIoana Ciornei };
282cf1e703SIoana Ciornei 
292cf1e703SIoana Ciornei #define FSL_MC_CHECK_MODULE_ID		BIT(0)
302cf1e703SIoana Ciornei #define FSL_MC_CAP_NET_ADMIN_NEEDED	BIT(1)
312cf1e703SIoana Ciornei 
322cf1e703SIoana Ciornei enum fsl_mc_cmd_index {
332cf1e703SIoana Ciornei 	DPDBG_DUMP = 0,
342cf1e703SIoana Ciornei 	DPDBG_SET,
352cf1e703SIoana Ciornei 	DPRC_GET_CONTAINER_ID,
362cf1e703SIoana Ciornei 	DPRC_CREATE_CONT,
372cf1e703SIoana Ciornei 	DPRC_DESTROY_CONT,
382cf1e703SIoana Ciornei 	DPRC_ASSIGN,
392cf1e703SIoana Ciornei 	DPRC_UNASSIGN,
402cf1e703SIoana Ciornei 	DPRC_GET_OBJ_COUNT,
412cf1e703SIoana Ciornei 	DPRC_GET_OBJ,
422cf1e703SIoana Ciornei 	DPRC_GET_RES_COUNT,
432cf1e703SIoana Ciornei 	DPRC_GET_RES_IDS,
442cf1e703SIoana Ciornei 	DPRC_SET_OBJ_LABEL,
452cf1e703SIoana Ciornei 	DPRC_SET_LOCKED,
462cf1e703SIoana Ciornei 	DPRC_CONNECT,
472cf1e703SIoana Ciornei 	DPRC_DISCONNECT,
482cf1e703SIoana Ciornei 	DPRC_GET_POOL,
492cf1e703SIoana Ciornei 	DPRC_GET_POOL_COUNT,
502cf1e703SIoana Ciornei 	DPRC_GET_CONNECTION,
512cf1e703SIoana Ciornei 	DPCI_GET_LINK_STATE,
522cf1e703SIoana Ciornei 	DPCI_GET_PEER_ATTR,
532cf1e703SIoana Ciornei 	DPAIOP_GET_SL_VERSION,
542cf1e703SIoana Ciornei 	DPAIOP_GET_STATE,
552cf1e703SIoana Ciornei 	DPMNG_GET_VERSION,
562cf1e703SIoana Ciornei 	DPSECI_GET_TX_QUEUE,
572cf1e703SIoana Ciornei 	DPMAC_GET_COUNTER,
582cf1e703SIoana Ciornei 	DPMAC_GET_MAC_ADDR,
592cf1e703SIoana Ciornei 	DPNI_SET_PRIM_MAC,
602cf1e703SIoana Ciornei 	DPNI_GET_PRIM_MAC,
612cf1e703SIoana Ciornei 	DPNI_GET_STATISTICS,
622cf1e703SIoana Ciornei 	DPNI_GET_LINK_STATE,
63*d67cc29eSIoana Ciornei 	DPNI_GET_MAX_FRAME_LENGTH,
64*d67cc29eSIoana Ciornei 	DPSW_GET_TAILDROP,
65*d67cc29eSIoana Ciornei 	DPSW_SET_TAILDROP,
66*d67cc29eSIoana Ciornei 	DPSW_IF_GET_COUNTER,
67*d67cc29eSIoana Ciornei 	DPSW_IF_GET_MAX_FRAME_LENGTH,
68*d67cc29eSIoana Ciornei 	DPDMUX_GET_COUNTER,
69*d67cc29eSIoana Ciornei 	DPDMUX_IF_GET_MAX_FRAME_LENGTH,
702cf1e703SIoana Ciornei 	GET_ATTR,
712cf1e703SIoana Ciornei 	GET_IRQ_MASK,
722cf1e703SIoana Ciornei 	GET_IRQ_STATUS,
732cf1e703SIoana Ciornei 	CLOSE,
742cf1e703SIoana Ciornei 	OPEN,
752cf1e703SIoana Ciornei 	GET_API_VERSION,
762cf1e703SIoana Ciornei 	DESTROY,
772cf1e703SIoana Ciornei 	CREATE,
782cf1e703SIoana Ciornei };
792cf1e703SIoana Ciornei 
802cf1e703SIoana Ciornei static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
812cf1e703SIoana Ciornei 	[DPDBG_DUMP] = {
822cf1e703SIoana Ciornei 		.cmdid_value = 0x1300,
832cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
842cf1e703SIoana Ciornei 		.token = true,
852cf1e703SIoana Ciornei 		.size = 28,
862cf1e703SIoana Ciornei 	},
872cf1e703SIoana Ciornei 	[DPDBG_SET] = {
882cf1e703SIoana Ciornei 		.cmdid_value = 0x1400,
892cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
902cf1e703SIoana Ciornei 		.token = true,
912cf1e703SIoana Ciornei 		.size = 28,
922cf1e703SIoana Ciornei 	},
932cf1e703SIoana Ciornei 	[DPRC_GET_CONTAINER_ID] = {
942cf1e703SIoana Ciornei 		.cmdid_value = 0x8300,
952cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
962cf1e703SIoana Ciornei 		.token = false,
972cf1e703SIoana Ciornei 		.size = 8,
982cf1e703SIoana Ciornei 	},
992cf1e703SIoana Ciornei 	[DPRC_CREATE_CONT] = {
1002cf1e703SIoana Ciornei 		.cmdid_value = 0x1510,
1012cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1022cf1e703SIoana Ciornei 		.token = true,
1032cf1e703SIoana Ciornei 		.size = 40,
1042cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1052cf1e703SIoana Ciornei 	},
1062cf1e703SIoana Ciornei 	[DPRC_DESTROY_CONT] = {
1072cf1e703SIoana Ciornei 		.cmdid_value = 0x1520,
1082cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1092cf1e703SIoana Ciornei 		.token = true,
1102cf1e703SIoana Ciornei 		.size = 12,
1112cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1122cf1e703SIoana Ciornei 	},
1132cf1e703SIoana Ciornei 	[DPRC_ASSIGN] = {
1142cf1e703SIoana Ciornei 		.cmdid_value = 0x1570,
1152cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1162cf1e703SIoana Ciornei 		.token = true,
1172cf1e703SIoana Ciornei 		.size = 40,
1182cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1192cf1e703SIoana Ciornei 	},
1202cf1e703SIoana Ciornei 	[DPRC_UNASSIGN] = {
1212cf1e703SIoana Ciornei 		.cmdid_value = 0x1580,
1222cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1232cf1e703SIoana Ciornei 		.token = true,
1242cf1e703SIoana Ciornei 		.size = 40,
1252cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1262cf1e703SIoana Ciornei 	},
1272cf1e703SIoana Ciornei 	[DPRC_GET_OBJ_COUNT] = {
1282cf1e703SIoana Ciornei 		.cmdid_value = 0x1590,
1292cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1302cf1e703SIoana Ciornei 		.token = true,
1312cf1e703SIoana Ciornei 		.size = 16,
1322cf1e703SIoana Ciornei 	},
1332cf1e703SIoana Ciornei 	[DPRC_GET_OBJ] = {
1342cf1e703SIoana Ciornei 		.cmdid_value = 0x15A0,
1352cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1362cf1e703SIoana Ciornei 		.token = true,
1372cf1e703SIoana Ciornei 		.size = 12,
1382cf1e703SIoana Ciornei 	},
1392cf1e703SIoana Ciornei 	[DPRC_GET_RES_COUNT] = {
1402cf1e703SIoana Ciornei 		.cmdid_value = 0x15B0,
1412cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1422cf1e703SIoana Ciornei 		.token = true,
1432cf1e703SIoana Ciornei 		.size = 32,
1442cf1e703SIoana Ciornei 	},
1452cf1e703SIoana Ciornei 	[DPRC_GET_RES_IDS] = {
1462cf1e703SIoana Ciornei 		.cmdid_value = 0x15C0,
1472cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1482cf1e703SIoana Ciornei 		.token = true,
1492cf1e703SIoana Ciornei 		.size = 40,
1502cf1e703SIoana Ciornei 	},
1512cf1e703SIoana Ciornei 	[DPRC_SET_OBJ_LABEL] = {
1522cf1e703SIoana Ciornei 		.cmdid_value = 0x1610,
1532cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1542cf1e703SIoana Ciornei 		.token = true,
1552cf1e703SIoana Ciornei 		.size = 48,
1562cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1572cf1e703SIoana Ciornei 	},
1582cf1e703SIoana Ciornei 	[DPRC_SET_LOCKED] = {
1592cf1e703SIoana Ciornei 		.cmdid_value = 0x16B0,
1602cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1612cf1e703SIoana Ciornei 		.token = true,
1622cf1e703SIoana Ciornei 		.size = 16,
1632cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1642cf1e703SIoana Ciornei 	},
1652cf1e703SIoana Ciornei 	[DPRC_CONNECT] = {
1662cf1e703SIoana Ciornei 		.cmdid_value = 0x1670,
1672cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1682cf1e703SIoana Ciornei 		.token = true,
1692cf1e703SIoana Ciornei 		.size = 56,
1702cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1712cf1e703SIoana Ciornei 	},
1722cf1e703SIoana Ciornei 	[DPRC_DISCONNECT] = {
1732cf1e703SIoana Ciornei 		.cmdid_value = 0x1680,
1742cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1752cf1e703SIoana Ciornei 		.token = true,
1762cf1e703SIoana Ciornei 		.size = 32,
1772cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
1782cf1e703SIoana Ciornei 	},
1792cf1e703SIoana Ciornei 	[DPRC_GET_POOL] = {
1802cf1e703SIoana Ciornei 		.cmdid_value = 0x1690,
1812cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1822cf1e703SIoana Ciornei 		.token = true,
1832cf1e703SIoana Ciornei 		.size = 12,
1842cf1e703SIoana Ciornei 	},
1852cf1e703SIoana Ciornei 	[DPRC_GET_POOL_COUNT] = {
1862cf1e703SIoana Ciornei 		.cmdid_value = 0x16A0,
1872cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1882cf1e703SIoana Ciornei 		.token = true,
1892cf1e703SIoana Ciornei 		.size = 8,
1902cf1e703SIoana Ciornei 	},
1912cf1e703SIoana Ciornei 	[DPRC_GET_CONNECTION] = {
1922cf1e703SIoana Ciornei 		.cmdid_value = 0x16C0,
1932cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
1942cf1e703SIoana Ciornei 		.token = true,
1952cf1e703SIoana Ciornei 		.size = 32,
1962cf1e703SIoana Ciornei 	},
1972cf1e703SIoana Ciornei 
1982cf1e703SIoana Ciornei 	[DPCI_GET_LINK_STATE] = {
1992cf1e703SIoana Ciornei 		.cmdid_value = 0x0E10,
2002cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2012cf1e703SIoana Ciornei 		.token = true,
2022cf1e703SIoana Ciornei 		.size = 8,
2032cf1e703SIoana Ciornei 	},
2042cf1e703SIoana Ciornei 	[DPCI_GET_PEER_ATTR] = {
2052cf1e703SIoana Ciornei 		.cmdid_value = 0x0E20,
2062cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2072cf1e703SIoana Ciornei 		.token = true,
2082cf1e703SIoana Ciornei 		.size = 8,
2092cf1e703SIoana Ciornei 	},
2102cf1e703SIoana Ciornei 	[DPAIOP_GET_SL_VERSION] = {
2112cf1e703SIoana Ciornei 		.cmdid_value = 0x2820,
2122cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2132cf1e703SIoana Ciornei 		.token = true,
2142cf1e703SIoana Ciornei 		.size = 8,
2152cf1e703SIoana Ciornei 	},
2162cf1e703SIoana Ciornei 	[DPAIOP_GET_STATE] = {
2172cf1e703SIoana Ciornei 		.cmdid_value = 0x2830,
2182cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2192cf1e703SIoana Ciornei 		.token = true,
2202cf1e703SIoana Ciornei 		.size = 8,
2212cf1e703SIoana Ciornei 	},
2222cf1e703SIoana Ciornei 	[DPMNG_GET_VERSION] = {
2232cf1e703SIoana Ciornei 		.cmdid_value = 0x8310,
2242cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2252cf1e703SIoana Ciornei 		.token = false,
2262cf1e703SIoana Ciornei 		.size = 8,
2272cf1e703SIoana Ciornei 	},
2282cf1e703SIoana Ciornei 	[DPSECI_GET_TX_QUEUE] = {
2292cf1e703SIoana Ciornei 		.cmdid_value = 0x1970,
2302cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2312cf1e703SIoana Ciornei 		.token = true,
2322cf1e703SIoana Ciornei 		.size = 14,
2332cf1e703SIoana Ciornei 	},
2342cf1e703SIoana Ciornei 	[DPMAC_GET_COUNTER] = {
2352cf1e703SIoana Ciornei 		.cmdid_value = 0x0c40,
2362cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2372cf1e703SIoana Ciornei 		.token = true,
2382cf1e703SIoana Ciornei 		.size = 9,
2392cf1e703SIoana Ciornei 	},
2402cf1e703SIoana Ciornei 	[DPMAC_GET_MAC_ADDR] = {
2412cf1e703SIoana Ciornei 		.cmdid_value = 0x0c50,
2422cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2432cf1e703SIoana Ciornei 		.token = true,
2442cf1e703SIoana Ciornei 		.size = 8,
2452cf1e703SIoana Ciornei 	},
2462cf1e703SIoana Ciornei 	[DPNI_SET_PRIM_MAC] = {
2472cf1e703SIoana Ciornei 		.cmdid_value = 0x2240,
2482cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2492cf1e703SIoana Ciornei 		.token = true,
2502cf1e703SIoana Ciornei 		.size = 16,
2512cf1e703SIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
2522cf1e703SIoana Ciornei 	},
2532cf1e703SIoana Ciornei 	[DPNI_GET_PRIM_MAC] = {
2542cf1e703SIoana Ciornei 		.cmdid_value = 0x2250,
2552cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2562cf1e703SIoana Ciornei 		.token = true,
2572cf1e703SIoana Ciornei 		.size = 8,
2582cf1e703SIoana Ciornei 	},
2592cf1e703SIoana Ciornei 	[DPNI_GET_STATISTICS] = {
2602cf1e703SIoana Ciornei 		.cmdid_value = 0x25D0,
2612cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2622cf1e703SIoana Ciornei 		.token = true,
2632cf1e703SIoana Ciornei 		.size = 10,
2642cf1e703SIoana Ciornei 	},
2652cf1e703SIoana Ciornei 	[DPNI_GET_LINK_STATE] = {
2662cf1e703SIoana Ciornei 		.cmdid_value = 0x2150,
2672cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
2682cf1e703SIoana Ciornei 		.token = true,
2692cf1e703SIoana Ciornei 		.size = 8,
2702cf1e703SIoana Ciornei 	},
271*d67cc29eSIoana Ciornei 	[DPNI_GET_MAX_FRAME_LENGTH] = {
272*d67cc29eSIoana Ciornei 		.cmdid_value = 0x2170,
273*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
274*d67cc29eSIoana Ciornei 		.token = true,
275*d67cc29eSIoana Ciornei 		.size = 8,
276*d67cc29eSIoana Ciornei 	},
277*d67cc29eSIoana Ciornei 	[DPSW_GET_TAILDROP] = {
278*d67cc29eSIoana Ciornei 		.cmdid_value = 0x0A80,
279*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
280*d67cc29eSIoana Ciornei 		.token = true,
281*d67cc29eSIoana Ciornei 		.size = 14,
282*d67cc29eSIoana Ciornei 	},
283*d67cc29eSIoana Ciornei 	[DPSW_SET_TAILDROP] = {
284*d67cc29eSIoana Ciornei 		.cmdid_value = 0x0A90,
285*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
286*d67cc29eSIoana Ciornei 		.token = true,
287*d67cc29eSIoana Ciornei 		.size = 24,
288*d67cc29eSIoana Ciornei 		.flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
289*d67cc29eSIoana Ciornei 	},
290*d67cc29eSIoana Ciornei 	[DPSW_IF_GET_COUNTER] = {
291*d67cc29eSIoana Ciornei 		.cmdid_value = 0x0340,
292*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
293*d67cc29eSIoana Ciornei 		.token = true,
294*d67cc29eSIoana Ciornei 		.size = 11,
295*d67cc29eSIoana Ciornei 	},
296*d67cc29eSIoana Ciornei 	[DPSW_IF_GET_MAX_FRAME_LENGTH] = {
297*d67cc29eSIoana Ciornei 		.cmdid_value = 0x0450,
298*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
299*d67cc29eSIoana Ciornei 		.token = true,
300*d67cc29eSIoana Ciornei 		.size = 10,
301*d67cc29eSIoana Ciornei 	},
302*d67cc29eSIoana Ciornei 	[DPDMUX_GET_COUNTER] = {
303*d67cc29eSIoana Ciornei 		.cmdid_value = 0x0b20,
304*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
305*d67cc29eSIoana Ciornei 		.token = true,
306*d67cc29eSIoana Ciornei 		.size = 11,
307*d67cc29eSIoana Ciornei 	},
308*d67cc29eSIoana Ciornei 	[DPDMUX_IF_GET_MAX_FRAME_LENGTH] = {
309*d67cc29eSIoana Ciornei 		.cmdid_value = 0x0a20,
310*d67cc29eSIoana Ciornei 		.cmdid_mask = 0xFFF0,
311*d67cc29eSIoana Ciornei 		.token = true,
312*d67cc29eSIoana Ciornei 		.size = 10,
313*d67cc29eSIoana Ciornei 	},
3142cf1e703SIoana Ciornei 	[GET_ATTR] = {
3152cf1e703SIoana Ciornei 		.cmdid_value = 0x0040,
3162cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
3172cf1e703SIoana Ciornei 		.token = true,
3182cf1e703SIoana Ciornei 		.size = 8,
3192cf1e703SIoana Ciornei 	},
3202cf1e703SIoana Ciornei 	[GET_IRQ_MASK] = {
3212cf1e703SIoana Ciornei 		.cmdid_value = 0x0150,
3222cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
3232cf1e703SIoana Ciornei 		.token = true,
3242cf1e703SIoana Ciornei 		.size = 13,
3252cf1e703SIoana Ciornei 	},
3262cf1e703SIoana Ciornei 	[GET_IRQ_STATUS] = {
3272cf1e703SIoana Ciornei 		.cmdid_value = 0x0160,
3282cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
3292cf1e703SIoana Ciornei 		.token = true,
3302cf1e703SIoana Ciornei 		.size = 13,
3312cf1e703SIoana Ciornei 	},
3322cf1e703SIoana Ciornei 	[CLOSE] = {
3332cf1e703SIoana Ciornei 		.cmdid_value = 0x8000,
3342cf1e703SIoana Ciornei 		.cmdid_mask = 0xFFF0,
3352cf1e703SIoana Ciornei 		.token = true,
3362cf1e703SIoana Ciornei 		.size = 8,
3372cf1e703SIoana Ciornei 	},
3382cf1e703SIoana Ciornei 
3392cf1e703SIoana Ciornei 	/* Common commands amongst all types of objects. Must be checked last. */
3402cf1e703SIoana Ciornei 	[OPEN] = {
3412cf1e703SIoana Ciornei 		.cmdid_value = 0x8000,
3422cf1e703SIoana Ciornei 		.cmdid_mask = 0xFC00,
3432cf1e703SIoana Ciornei 		.token = false,
3442cf1e703SIoana Ciornei 		.size = 12,
3452cf1e703SIoana Ciornei 		.flags = FSL_MC_CHECK_MODULE_ID,
3462cf1e703SIoana Ciornei 	},
3472cf1e703SIoana Ciornei 	[GET_API_VERSION] = {
3482cf1e703SIoana Ciornei 		.cmdid_value = 0xA000,
3492cf1e703SIoana Ciornei 		.cmdid_mask = 0xFC00,
3502cf1e703SIoana Ciornei 		.token = false,
3512cf1e703SIoana Ciornei 		.size = 8,
3522cf1e703SIoana Ciornei 		.flags = FSL_MC_CHECK_MODULE_ID,
3532cf1e703SIoana Ciornei 	},
3542cf1e703SIoana Ciornei 	[DESTROY] = {
3552cf1e703SIoana Ciornei 		.cmdid_value = 0x9800,
3562cf1e703SIoana Ciornei 		.cmdid_mask = 0xFC00,
3572cf1e703SIoana Ciornei 		.token = true,
3582cf1e703SIoana Ciornei 		.size = 12,
3592cf1e703SIoana Ciornei 		.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
3602cf1e703SIoana Ciornei 	},
3612cf1e703SIoana Ciornei 	[CREATE] = {
3622cf1e703SIoana Ciornei 		.cmdid_value = 0x9000,
3632cf1e703SIoana Ciornei 		.cmdid_mask = 0xFC00,
3642cf1e703SIoana Ciornei 		.token = true,
3652cf1e703SIoana Ciornei 		.size = 64,
3662cf1e703SIoana Ciornei 		.flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
3672cf1e703SIoana Ciornei 	},
3682cf1e703SIoana Ciornei };
3692cf1e703SIoana Ciornei 
3702cf1e703SIoana Ciornei #define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds)
3712cf1e703SIoana Ciornei 
3722cf1e703SIoana Ciornei #define FSL_MC_MAX_MODULE_ID 0x10
3732cf1e703SIoana Ciornei 
fsl_mc_command_check(struct fsl_mc_device * mc_dev,struct fsl_mc_command * mc_cmd)3742cf1e703SIoana Ciornei static int fsl_mc_command_check(struct fsl_mc_device *mc_dev,
3752cf1e703SIoana Ciornei 				struct fsl_mc_command *mc_cmd)
3762cf1e703SIoana Ciornei {
3772cf1e703SIoana Ciornei 	struct fsl_mc_cmd_desc *desc = NULL;
3782cf1e703SIoana Ciornei 	int mc_cmd_max_size, i;
3792cf1e703SIoana Ciornei 	bool token_provided;
3802cf1e703SIoana Ciornei 	u16 cmdid, module_id;
3812cf1e703SIoana Ciornei 	char *mc_cmd_end;
3822cf1e703SIoana Ciornei 	char sum = 0;
3832cf1e703SIoana Ciornei 
3842cf1e703SIoana Ciornei 	/* Check if this is an accepted MC command */
3852cf1e703SIoana Ciornei 	cmdid = mc_cmd_hdr_read_cmdid(mc_cmd);
3862cf1e703SIoana Ciornei 	for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) {
3872cf1e703SIoana Ciornei 		desc = &fsl_mc_accepted_cmds[i];
3882cf1e703SIoana Ciornei 		if ((cmdid & desc->cmdid_mask) == desc->cmdid_value)
3892cf1e703SIoana Ciornei 			break;
3902cf1e703SIoana Ciornei 	}
391ef0fec22SDan Carpenter 	if (i == FSL_MC_NUM_ACCEPTED_CMDS) {
3922cf1e703SIoana Ciornei 		dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid);
3932cf1e703SIoana Ciornei 		return -EACCES;
3942cf1e703SIoana Ciornei 	}
3952cf1e703SIoana Ciornei 
3962cf1e703SIoana Ciornei 	/* Check if the size of the command is honored. Anything beyond the
3972cf1e703SIoana Ciornei 	 * last valid byte of the command should be zeroed.
3982cf1e703SIoana Ciornei 	 */
3992cf1e703SIoana Ciornei 	mc_cmd_max_size = sizeof(*mc_cmd);
4002cf1e703SIoana Ciornei 	mc_cmd_end = ((char *)mc_cmd) + desc->size;
4012cf1e703SIoana Ciornei 	for (i = desc->size; i < mc_cmd_max_size; i++)
4022cf1e703SIoana Ciornei 		sum |= *mc_cmd_end++;
4032cf1e703SIoana Ciornei 	if (sum) {
4042cf1e703SIoana Ciornei 		dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n",
4052cf1e703SIoana Ciornei 			cmdid, desc->size);
4062cf1e703SIoana Ciornei 		return -EACCES;
4072cf1e703SIoana Ciornei 	}
4082cf1e703SIoana Ciornei 
4092cf1e703SIoana Ciornei 	/* Some MC commands request a token to be passed so that object
4102cf1e703SIoana Ciornei 	 * identification is possible. Check if the token passed in the command
4112cf1e703SIoana Ciornei 	 * is as expected.
4122cf1e703SIoana Ciornei 	 */
4132cf1e703SIoana Ciornei 	token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false;
4142cf1e703SIoana Ciornei 	if (token_provided != desc->token) {
4152cf1e703SIoana Ciornei 		dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n",
4162cf1e703SIoana Ciornei 			cmdid, mc_cmd_hdr_read_token(mc_cmd));
4172cf1e703SIoana Ciornei 		return -EACCES;
4182cf1e703SIoana Ciornei 	}
4192cf1e703SIoana Ciornei 
4202cf1e703SIoana Ciornei 	/* If needed, check if the module ID passed is valid */
4212cf1e703SIoana Ciornei 	if (desc->flags & FSL_MC_CHECK_MODULE_ID) {
4222cf1e703SIoana Ciornei 		/* The module ID is represented by bits [4:9] from the cmdid */
4232cf1e703SIoana Ciornei 		module_id = (cmdid & GENMASK(9, 4)) >> 4;
4242cf1e703SIoana Ciornei 		if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) {
4252cf1e703SIoana Ciornei 			dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n",
4262cf1e703SIoana Ciornei 				cmdid, module_id);
4272cf1e703SIoana Ciornei 			return -EACCES;
4282cf1e703SIoana Ciornei 		}
4292cf1e703SIoana Ciornei 	}
4302cf1e703SIoana Ciornei 
4312cf1e703SIoana Ciornei 	/* Some commands alter how hardware resources are managed. For these
4322cf1e703SIoana Ciornei 	 * commands, check for CAP_NET_ADMIN.
4332cf1e703SIoana Ciornei 	 */
4342cf1e703SIoana Ciornei 	if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) {
4352cf1e703SIoana Ciornei 		if (!capable(CAP_NET_ADMIN)) {
4362cf1e703SIoana Ciornei 			dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n",
4372cf1e703SIoana Ciornei 				cmdid);
4382cf1e703SIoana Ciornei 			return -EPERM;
4392cf1e703SIoana Ciornei 		}
4402cf1e703SIoana Ciornei 	}
4412cf1e703SIoana Ciornei 
4422cf1e703SIoana Ciornei 	return 0;
4432cf1e703SIoana Ciornei }
4442cf1e703SIoana Ciornei 
fsl_mc_uapi_send_command(struct fsl_mc_device * mc_dev,unsigned long arg,struct fsl_mc_io * mc_io)4452cf1e703SIoana Ciornei static int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg,
4462cf1e703SIoana Ciornei 				    struct fsl_mc_io *mc_io)
4472cf1e703SIoana Ciornei {
4482cf1e703SIoana Ciornei 	struct fsl_mc_command mc_cmd;
4492cf1e703SIoana Ciornei 	int error;
4502cf1e703SIoana Ciornei 
4512cf1e703SIoana Ciornei 	error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
4522cf1e703SIoana Ciornei 	if (error)
4532cf1e703SIoana Ciornei 		return -EFAULT;
4542cf1e703SIoana Ciornei 
4552cf1e703SIoana Ciornei 	error = fsl_mc_command_check(mc_dev, &mc_cmd);
4562cf1e703SIoana Ciornei 	if (error)
4572cf1e703SIoana Ciornei 		return error;
4582cf1e703SIoana Ciornei 
4592cf1e703SIoana Ciornei 	error = mc_send_command(mc_io, &mc_cmd);
4602cf1e703SIoana Ciornei 	if (error)
4612cf1e703SIoana Ciornei 		return error;
4622cf1e703SIoana Ciornei 
4632cf1e703SIoana Ciornei 	error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
4642cf1e703SIoana Ciornei 	if (error)
4652cf1e703SIoana Ciornei 		return -EFAULT;
4662cf1e703SIoana Ciornei 
4672cf1e703SIoana Ciornei 	return 0;
4682cf1e703SIoana Ciornei }
4692cf1e703SIoana Ciornei 
fsl_mc_uapi_dev_open(struct inode * inode,struct file * filep)4702cf1e703SIoana Ciornei static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
4712cf1e703SIoana Ciornei {
4722cf1e703SIoana Ciornei 	struct fsl_mc_device *root_mc_device;
4732cf1e703SIoana Ciornei 	struct uapi_priv_data *priv_data;
4742cf1e703SIoana Ciornei 	struct fsl_mc_io *dynamic_mc_io;
4752cf1e703SIoana Ciornei 	struct fsl_mc_uapi *mc_uapi;
4762cf1e703SIoana Ciornei 	struct fsl_mc_bus *mc_bus;
4772cf1e703SIoana Ciornei 	int error;
4782cf1e703SIoana Ciornei 
4792cf1e703SIoana Ciornei 	priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
4802cf1e703SIoana Ciornei 	if (!priv_data)
4812cf1e703SIoana Ciornei 		return -ENOMEM;
4822cf1e703SIoana Ciornei 
4832cf1e703SIoana Ciornei 	mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
4842cf1e703SIoana Ciornei 	mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
4852cf1e703SIoana Ciornei 	root_mc_device = &mc_bus->mc_dev;
4862cf1e703SIoana Ciornei 
4872cf1e703SIoana Ciornei 	mutex_lock(&mc_uapi->mutex);
4882cf1e703SIoana Ciornei 
4892cf1e703SIoana Ciornei 	if (!mc_uapi->local_instance_in_use) {
4902cf1e703SIoana Ciornei 		priv_data->mc_io = mc_uapi->static_mc_io;
4912cf1e703SIoana Ciornei 		mc_uapi->local_instance_in_use = 1;
4922cf1e703SIoana Ciornei 	} else {
4932cf1e703SIoana Ciornei 		error = fsl_mc_portal_allocate(root_mc_device, 0,
4942cf1e703SIoana Ciornei 					       &dynamic_mc_io);
4952cf1e703SIoana Ciornei 		if (error) {
4962cf1e703SIoana Ciornei 			dev_dbg(&root_mc_device->dev,
4972cf1e703SIoana Ciornei 				"Could not allocate MC portal\n");
4982cf1e703SIoana Ciornei 			goto error_portal_allocate;
4992cf1e703SIoana Ciornei 		}
5002cf1e703SIoana Ciornei 
5012cf1e703SIoana Ciornei 		priv_data->mc_io = dynamic_mc_io;
5022cf1e703SIoana Ciornei 	}
5032cf1e703SIoana Ciornei 	priv_data->uapi = mc_uapi;
5042cf1e703SIoana Ciornei 	filep->private_data = priv_data;
5052cf1e703SIoana Ciornei 
5062cf1e703SIoana Ciornei 	mutex_unlock(&mc_uapi->mutex);
5072cf1e703SIoana Ciornei 
5082cf1e703SIoana Ciornei 	return 0;
5092cf1e703SIoana Ciornei 
5102cf1e703SIoana Ciornei error_portal_allocate:
5112cf1e703SIoana Ciornei 	mutex_unlock(&mc_uapi->mutex);
5122cf1e703SIoana Ciornei 	kfree(priv_data);
5132cf1e703SIoana Ciornei 
5142cf1e703SIoana Ciornei 	return error;
5152cf1e703SIoana Ciornei }
5162cf1e703SIoana Ciornei 
fsl_mc_uapi_dev_release(struct inode * inode,struct file * filep)5172cf1e703SIoana Ciornei static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
5182cf1e703SIoana Ciornei {
5192cf1e703SIoana Ciornei 	struct uapi_priv_data *priv_data;
5202cf1e703SIoana Ciornei 	struct fsl_mc_uapi *mc_uapi;
5212cf1e703SIoana Ciornei 	struct fsl_mc_io *mc_io;
5222cf1e703SIoana Ciornei 
5232cf1e703SIoana Ciornei 	priv_data = filep->private_data;
5242cf1e703SIoana Ciornei 	mc_uapi = priv_data->uapi;
5252cf1e703SIoana Ciornei 	mc_io = priv_data->mc_io;
5262cf1e703SIoana Ciornei 
5272cf1e703SIoana Ciornei 	mutex_lock(&mc_uapi->mutex);
5282cf1e703SIoana Ciornei 
5292cf1e703SIoana Ciornei 	if (mc_io == mc_uapi->static_mc_io)
5302cf1e703SIoana Ciornei 		mc_uapi->local_instance_in_use = 0;
5312cf1e703SIoana Ciornei 	else
5322cf1e703SIoana Ciornei 		fsl_mc_portal_free(mc_io);
5332cf1e703SIoana Ciornei 
5342cf1e703SIoana Ciornei 	kfree(filep->private_data);
5352cf1e703SIoana Ciornei 	filep->private_data =  NULL;
5362cf1e703SIoana Ciornei 
5372cf1e703SIoana Ciornei 	mutex_unlock(&mc_uapi->mutex);
5382cf1e703SIoana Ciornei 
5392cf1e703SIoana Ciornei 	return 0;
5402cf1e703SIoana Ciornei }
5412cf1e703SIoana Ciornei 
fsl_mc_uapi_dev_ioctl(struct file * file,unsigned int cmd,unsigned long arg)5422cf1e703SIoana Ciornei static long fsl_mc_uapi_dev_ioctl(struct file *file,
5432cf1e703SIoana Ciornei 				  unsigned int cmd,
5442cf1e703SIoana Ciornei 				  unsigned long arg)
5452cf1e703SIoana Ciornei {
5462cf1e703SIoana Ciornei 	struct uapi_priv_data *priv_data = file->private_data;
5472cf1e703SIoana Ciornei 	struct fsl_mc_device *root_mc_device;
5482cf1e703SIoana Ciornei 	struct fsl_mc_bus *mc_bus;
5492cf1e703SIoana Ciornei 	int error;
5502cf1e703SIoana Ciornei 
5512cf1e703SIoana Ciornei 	mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
5522cf1e703SIoana Ciornei 	root_mc_device = &mc_bus->mc_dev;
5532cf1e703SIoana Ciornei 
5542cf1e703SIoana Ciornei 	switch (cmd) {
5552cf1e703SIoana Ciornei 	case FSL_MC_SEND_MC_COMMAND:
5562cf1e703SIoana Ciornei 		error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io);
5572cf1e703SIoana Ciornei 		break;
5582cf1e703SIoana Ciornei 	default:
5592cf1e703SIoana Ciornei 		dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
5602cf1e703SIoana Ciornei 		error = -EINVAL;
5612cf1e703SIoana Ciornei 	}
5622cf1e703SIoana Ciornei 
5632cf1e703SIoana Ciornei 	return error;
5642cf1e703SIoana Ciornei }
5652cf1e703SIoana Ciornei 
5662cf1e703SIoana Ciornei static const struct file_operations fsl_mc_uapi_dev_fops = {
5672cf1e703SIoana Ciornei 	.owner = THIS_MODULE,
5682cf1e703SIoana Ciornei 	.open = fsl_mc_uapi_dev_open,
5692cf1e703SIoana Ciornei 	.release = fsl_mc_uapi_dev_release,
5702cf1e703SIoana Ciornei 	.unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
5712cf1e703SIoana Ciornei };
5722cf1e703SIoana Ciornei 
fsl_mc_uapi_create_device_file(struct fsl_mc_bus * mc_bus)5732cf1e703SIoana Ciornei int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
5742cf1e703SIoana Ciornei {
5752cf1e703SIoana Ciornei 	struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
5762cf1e703SIoana Ciornei 	struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
5772cf1e703SIoana Ciornei 	int error;
5782cf1e703SIoana Ciornei 
5792cf1e703SIoana Ciornei 	mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
5802cf1e703SIoana Ciornei 	mc_uapi->misc.name = dev_name(&mc_dev->dev);
5812cf1e703SIoana Ciornei 	mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;
5822cf1e703SIoana Ciornei 
5832cf1e703SIoana Ciornei 	error = misc_register(&mc_uapi->misc);
5842cf1e703SIoana Ciornei 	if (error)
5852cf1e703SIoana Ciornei 		return error;
5862cf1e703SIoana Ciornei 
5872cf1e703SIoana Ciornei 	mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;
5882cf1e703SIoana Ciornei 
5892cf1e703SIoana Ciornei 	mutex_init(&mc_uapi->mutex);
5902cf1e703SIoana Ciornei 
5912cf1e703SIoana Ciornei 	return 0;
5922cf1e703SIoana Ciornei }
5932cf1e703SIoana Ciornei 
fsl_mc_uapi_remove_device_file(struct fsl_mc_bus * mc_bus)5942cf1e703SIoana Ciornei void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
5952cf1e703SIoana Ciornei {
5962cf1e703SIoana Ciornei 	misc_deregister(&mc_bus->uapi_misc.misc);
5972cf1e703SIoana Ciornei }
598