Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/bus/fsl-mc/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 12 kB image not shown  

Quelle  fsl-mc-uapi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Management Complex (MC) userspace support
 *
 * Copyright 2021 NXP
 *
 */


#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>

#include "fsl-mc-private.h"

struct uapi_priv_data {
 struct fsl_mc_uapi *uapi;
 struct fsl_mc_io *mc_io;
};

struct fsl_mc_cmd_desc {
 u16 cmdid_value;
 u16 cmdid_mask;
 int size;
 bool token;
 int flags;
};

#define FSL_MC_CHECK_MODULE_ID  BIT(0)
#define FSL_MC_CAP_NET_ADMIN_NEEDED BIT(1)

enum fsl_mc_cmd_index {
 DPDBG_DUMP = 0,
 DPDBG_SET,
 DPRC_GET_CONTAINER_ID,
 DPRC_CREATE_CONT,
 DPRC_DESTROY_CONT,
 DPRC_ASSIGN,
 DPRC_UNASSIGN,
 DPRC_GET_OBJ_COUNT,
 DPRC_GET_OBJ,
 DPRC_GET_RES_COUNT,
 DPRC_GET_RES_IDS,
 DPRC_SET_OBJ_LABEL,
 DPRC_SET_LOCKED,
 DPRC_CONNECT,
 DPRC_DISCONNECT,
 DPRC_GET_POOL,
 DPRC_GET_POOL_COUNT,
 DPRC_GET_CONNECTION,
 DPRC_GET_MEM,
 DPCI_GET_LINK_STATE,
 DPCI_GET_PEER_ATTR,
 DPAIOP_GET_SL_VERSION,
 DPAIOP_GET_STATE,
 DPMNG_GET_VERSION,
 DPSECI_GET_TX_QUEUE,
 DPMAC_GET_COUNTER,
 DPMAC_GET_MAC_ADDR,
 DPNI_SET_PRIM_MAC,
 DPNI_GET_PRIM_MAC,
 DPNI_GET_STATISTICS,
 DPNI_GET_LINK_STATE,
 DPNI_GET_MAX_FRAME_LENGTH,
 DPSW_GET_TAILDROP,
 DPSW_SET_TAILDROP,
 DPSW_IF_GET_COUNTER,
 DPSW_IF_GET_MAX_FRAME_LENGTH,
 DPDMUX_GET_COUNTER,
 DPDMUX_IF_GET_MAX_FRAME_LENGTH,
 GET_ATTR,
 GET_IRQ_MASK,
 GET_IRQ_STATUS,
 CLOSE,
 OPEN,
 GET_API_VERSION,
 DESTROY,
 CREATE,
};

static struct fsl_mc_cmd_desc fsl_mc_accepted_cmds[] = {
 [DPDBG_DUMP] = {
  .cmdid_value = 0x1300,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 28,
 },
 [DPDBG_SET] = {
  .cmdid_value = 0x1400,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 28,
 },
 [DPRC_GET_CONTAINER_ID] = {
  .cmdid_value = 0x8300,
  .cmdid_mask = 0xFFF0,
  .token = false,
  .size = 8,
 },
 [DPRC_CREATE_CONT] = {
  .cmdid_value = 0x1510,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 40,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_DESTROY_CONT] = {
  .cmdid_value = 0x1520,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 12,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_ASSIGN] = {
  .cmdid_value = 0x1570,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 40,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_UNASSIGN] = {
  .cmdid_value = 0x1580,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 40,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_GET_OBJ_COUNT] = {
  .cmdid_value = 0x1590,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 16,
 },
 [DPRC_GET_OBJ] = {
  .cmdid_value = 0x15A0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 12,
 },
 [DPRC_GET_RES_COUNT] = {
  .cmdid_value = 0x15B0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 32,
 },
 [DPRC_GET_RES_IDS] = {
  .cmdid_value = 0x15C0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 40,
 },
 [DPRC_SET_OBJ_LABEL] = {
  .cmdid_value = 0x1610,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 48,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_SET_LOCKED] = {
  .cmdid_value = 0x16B0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 16,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_CONNECT] = {
  .cmdid_value = 0x1670,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 56,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_DISCONNECT] = {
  .cmdid_value = 0x1680,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 32,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPRC_GET_POOL] = {
  .cmdid_value = 0x1690,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 12,
 },
 [DPRC_GET_POOL_COUNT] = {
  .cmdid_value = 0x16A0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPRC_GET_CONNECTION] = {
  .cmdid_value = 0x16C0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 32,
 },
 [DPRC_GET_MEM] = {
  .cmdid_value = 0x16D0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 12,
 },

 [DPCI_GET_LINK_STATE] = {
  .cmdid_value = 0x0E10,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPCI_GET_PEER_ATTR] = {
  .cmdid_value = 0x0E20,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPAIOP_GET_SL_VERSION] = {
  .cmdid_value = 0x2820,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPAIOP_GET_STATE] = {
  .cmdid_value = 0x2830,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPMNG_GET_VERSION] = {
  .cmdid_value = 0x8310,
  .cmdid_mask = 0xFFF0,
  .token = false,
  .size = 8,
 },
 [DPSECI_GET_TX_QUEUE] = {
  .cmdid_value = 0x1970,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 14,
 },
 [DPMAC_GET_COUNTER] = {
  .cmdid_value = 0x0c40,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 9,
 },
 [DPMAC_GET_MAC_ADDR] = {
  .cmdid_value = 0x0c50,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPNI_SET_PRIM_MAC] = {
  .cmdid_value = 0x2240,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 16,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPNI_GET_PRIM_MAC] = {
  .cmdid_value = 0x2250,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPNI_GET_STATISTICS] = {
  .cmdid_value = 0x25D0,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 10,
 },
 [DPNI_GET_LINK_STATE] = {
  .cmdid_value = 0x2150,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPNI_GET_MAX_FRAME_LENGTH] = {
  .cmdid_value = 0x2170,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [DPSW_GET_TAILDROP] = {
  .cmdid_value = 0x0A90,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 14,
 },
 [DPSW_SET_TAILDROP] = {
  .cmdid_value = 0x0A80,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 24,
  .flags = FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [DPSW_IF_GET_COUNTER] = {
  .cmdid_value = 0x0340,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 11,
 },
 [DPSW_IF_GET_MAX_FRAME_LENGTH] = {
  .cmdid_value = 0x0450,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 10,
 },
 [DPDMUX_GET_COUNTER] = {
  .cmdid_value = 0x0b20,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 11,
 },
 [DPDMUX_IF_GET_MAX_FRAME_LENGTH] = {
  .cmdid_value = 0x0a20,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 10,
 },
 [GET_ATTR] = {
  .cmdid_value = 0x0040,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },
 [GET_IRQ_MASK] = {
  .cmdid_value = 0x0150,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 13,
 },
 [GET_IRQ_STATUS] = {
  .cmdid_value = 0x0160,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 13,
 },
 [CLOSE] = {
  .cmdid_value = 0x8000,
  .cmdid_mask = 0xFFF0,
  .token = true,
  .size = 8,
 },

 /* Common commands amongst all types of objects. Must be checked last. */
 [OPEN] = {
  .cmdid_value = 0x8000,
  .cmdid_mask = 0xFC00,
  .token = false,
  .size = 12,
  .flags = FSL_MC_CHECK_MODULE_ID,
 },
 [GET_API_VERSION] = {
  .cmdid_value = 0xA000,
  .cmdid_mask = 0xFC00,
  .token = false,
  .size = 8,
  .flags = FSL_MC_CHECK_MODULE_ID,
 },
 [DESTROY] = {
  .cmdid_value = 0x9800,
  .cmdid_mask = 0xFC00,
  .token = true,
  .size = 12,
  .flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
 [CREATE] = {
  .cmdid_value = 0x9000,
  .cmdid_mask = 0xFC00,
  .token = true,
  .size = 64,
  .flags = FSL_MC_CHECK_MODULE_ID | FSL_MC_CAP_NET_ADMIN_NEEDED,
 },
};

#define FSL_MC_NUM_ACCEPTED_CMDS ARRAY_SIZE(fsl_mc_accepted_cmds)

#define FSL_MC_MAX_MODULE_ID 0x10

static int fsl_mc_command_check(struct fsl_mc_device *mc_dev,
    struct fsl_mc_command *mc_cmd)
{
 struct fsl_mc_cmd_desc *desc = NULL;
 int mc_cmd_max_size, i;
 bool token_provided;
 u16 cmdid, module_id;
 char *mc_cmd_end;
 char sum = 0;

 /* Check if this is an accepted MC command */
 cmdid = mc_cmd_hdr_read_cmdid(mc_cmd);
 for (i = 0; i < FSL_MC_NUM_ACCEPTED_CMDS; i++) {
  desc = &fsl_mc_accepted_cmds[i];
  if ((cmdid & desc->cmdid_mask) == desc->cmdid_value)
   break;
 }
 if (i == FSL_MC_NUM_ACCEPTED_CMDS) {
  dev_err(&mc_dev->dev, "MC command 0x%04x: cmdid not accepted\n", cmdid);
  return -EACCES;
 }

 /* Check if the size of the command is honored. Anything beyond the
 * last valid byte of the command should be zeroed.
 */

 mc_cmd_max_size = sizeof(*mc_cmd);
 mc_cmd_end = ((char *)mc_cmd) + desc->size;
 for (i = desc->size; i < mc_cmd_max_size; i++)
  sum |= *mc_cmd_end++;
 if (sum) {
  dev_err(&mc_dev->dev, "MC command 0x%04x: garbage beyond max size of %d bytes!\n",
   cmdid, desc->size);
  return -EACCES;
 }

 /* Some MC commands request a token to be passed so that object
 * identification is possible. Check if the token passed in the command
 * is as expected.
 */

 token_provided = mc_cmd_hdr_read_token(mc_cmd) ? true : false;
 if (token_provided != desc->token) {
  dev_err(&mc_dev->dev, "MC command 0x%04x: token 0x%04x is invalid!\n",
   cmdid, mc_cmd_hdr_read_token(mc_cmd));
  return -EACCES;
 }

 /* If needed, check if the module ID passed is valid */
 if (desc->flags & FSL_MC_CHECK_MODULE_ID) {
  /* The module ID is represented by bits [4:9] from the cmdid */
  module_id = (cmdid & GENMASK(9, 4)) >> 4;
  if (module_id == 0 || module_id > FSL_MC_MAX_MODULE_ID) {
   dev_err(&mc_dev->dev, "MC command 0x%04x: unknown module ID 0x%x\n",
    cmdid, module_id);
   return -EACCES;
  }
 }

 /* Some commands alter how hardware resources are managed. For these
 * commands, check for CAP_NET_ADMIN.
 */

 if (desc->flags & FSL_MC_CAP_NET_ADMIN_NEEDED) {
  if (!capable(CAP_NET_ADMIN)) {
   dev_err(&mc_dev->dev, "MC command 0x%04x: needs CAP_NET_ADMIN!\n",
    cmdid);
   return -EPERM;
  }
 }

 return 0;
}

static int fsl_mc_uapi_send_command(struct fsl_mc_device *mc_dev, unsigned long arg,
        struct fsl_mc_io *mc_io)
{
 struct fsl_mc_command mc_cmd;
 int error;

 error = copy_from_user(&mc_cmd, (void __user *)arg, sizeof(mc_cmd));
 if (error)
  return -EFAULT;

 error = fsl_mc_command_check(mc_dev, &mc_cmd);
 if (error)
  return error;

 error = mc_send_command(mc_io, &mc_cmd);
 if (error)
  return error;

 error = copy_to_user((void __user *)arg, &mc_cmd, sizeof(mc_cmd));
 if (error)
  return -EFAULT;

 return 0;
}

static int fsl_mc_uapi_dev_open(struct inode *inode, struct file *filep)
{
 struct fsl_mc_device *root_mc_device;
 struct uapi_priv_data *priv_data;
 struct fsl_mc_io *dynamic_mc_io;
 struct fsl_mc_uapi *mc_uapi;
 struct fsl_mc_bus *mc_bus;
 int error;

 priv_data = kzalloc(sizeof(*priv_data), GFP_KERNEL);
 if (!priv_data)
  return -ENOMEM;

 mc_uapi = container_of(filep->private_data, struct fsl_mc_uapi, misc);
 mc_bus = container_of(mc_uapi, struct fsl_mc_bus, uapi_misc);
 root_mc_device = &mc_bus->mc_dev;

 mutex_lock(&mc_uapi->mutex);

 if (!mc_uapi->local_instance_in_use) {
  priv_data->mc_io = mc_uapi->static_mc_io;
  mc_uapi->local_instance_in_use = 1;
 } else {
  error = fsl_mc_portal_allocate(root_mc_device, 0,
            &dynamic_mc_io);
  if (error) {
   dev_dbg(&root_mc_device->dev,
    "Could not allocate MC portal\n");
   goto error_portal_allocate;
  }

  priv_data->mc_io = dynamic_mc_io;
 }
 priv_data->uapi = mc_uapi;
 filep->private_data = priv_data;

 mutex_unlock(&mc_uapi->mutex);

 return 0;

error_portal_allocate:
 mutex_unlock(&mc_uapi->mutex);
 kfree(priv_data);

 return error;
}

static int fsl_mc_uapi_dev_release(struct inode *inode, struct file *filep)
{
 struct uapi_priv_data *priv_data;
 struct fsl_mc_uapi *mc_uapi;
 struct fsl_mc_io *mc_io;

 priv_data = filep->private_data;
 mc_uapi = priv_data->uapi;
 mc_io = priv_data->mc_io;

 mutex_lock(&mc_uapi->mutex);

 if (mc_io == mc_uapi->static_mc_io)
  mc_uapi->local_instance_in_use = 0;
 else
  fsl_mc_portal_free(mc_io);

 kfree(filep->private_data);
 filep->private_data =  NULL;

 mutex_unlock(&mc_uapi->mutex);

 return 0;
}

static long fsl_mc_uapi_dev_ioctl(struct file *file,
      unsigned int cmd,
      unsigned long arg)
{
 struct uapi_priv_data *priv_data = file->private_data;
 struct fsl_mc_device *root_mc_device;
 struct fsl_mc_bus *mc_bus;
 int error;

 mc_bus = container_of(priv_data->uapi, struct fsl_mc_bus, uapi_misc);
 root_mc_device = &mc_bus->mc_dev;

 switch (cmd) {
 case FSL_MC_SEND_MC_COMMAND:
  error = fsl_mc_uapi_send_command(root_mc_device, arg, priv_data->mc_io);
  break;
 default:
  dev_dbg(&root_mc_device->dev, "unexpected ioctl call number\n");
  error = -EINVAL;
 }

 return error;
}

static const struct file_operations fsl_mc_uapi_dev_fops = {
 .owner = THIS_MODULE,
 .open = fsl_mc_uapi_dev_open,
 .release = fsl_mc_uapi_dev_release,
 .unlocked_ioctl = fsl_mc_uapi_dev_ioctl,
};

int fsl_mc_uapi_create_device_file(struct fsl_mc_bus *mc_bus)
{
 struct fsl_mc_device *mc_dev = &mc_bus->mc_dev;
 struct fsl_mc_uapi *mc_uapi = &mc_bus->uapi_misc;
 int error;

 mc_uapi->misc.minor = MISC_DYNAMIC_MINOR;
 mc_uapi->misc.name = dev_name(&mc_dev->dev);
 mc_uapi->misc.fops = &fsl_mc_uapi_dev_fops;

 error = misc_register(&mc_uapi->misc);
 if (error)
  return error;

 mc_uapi->static_mc_io = mc_bus->mc_dev.mc_io;

 mutex_init(&mc_uapi->mutex);

 return 0;
}

void fsl_mc_uapi_remove_device_file(struct fsl_mc_bus *mc_bus)
{
 misc_deregister(&mc_bus->uapi_misc.misc);
}

Messung V0.5
C=98 H=98 G=97

¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.