> -----Original Message----- > From: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> > Sent: Tuesday, July 23, 2024 7:51 PM > To: Pankaj Gupta <pankaj.gupta@xxxxxxx> > Cc: Jonathan Corbet <corbet@xxxxxxx>; Rob Herring <robh@xxxxxxxxxx>; > Krzysztof Kozlowski <krzk+dt@xxxxxxxxxx>; Conor Dooley > <conor+dt@xxxxxxxxxx>; Shawn Guo <shawnguo@xxxxxxxxxx>; Pengutronix > Kernel Team <kernel@xxxxxxxxxxxxxx>; Fabio Estevam > <festevam@xxxxxxxxx>; Rob Herring <robh+dt@xxxxxxxxxx>; linux- > doc@xxxxxxxxxxxxxxx; linux-kernel@xxxxxxxxxxxxxxx; > devicetree@xxxxxxxxxxxxxxx; imx@xxxxxxxxxxxxxxx; linux-arm- > kernel@xxxxxxxxxxxxxxxxxxx > Subject: [EXT] Re: [PATCH v6 5/5] firmware: imx: adds miscdev > > Caution: This is an external email. Please take care when clicking links or > opening attachments. When in doubt, report the message using the 'Report > this email' button > > > Hi Pankaj, > > On Mon, Jul 22, 2024 at 10:21:40AM +0530, Pankaj Gupta wrote: > > +static int se_ioctl_cmd_snd_rcv_rsp_handler(struct se_if_device_ctx > *dev_ctx, > > + u64 arg) { > > + struct se_if_priv *priv = dev_get_drvdata(dev_ctx->dev); > > + struct se_ioctl_cmd_snd_rcv_rsp_info cmd_snd_rcv_rsp_info; > > + struct se_api_msg *tx_msg __free(kfree) = NULL; > > + struct se_api_msg *rx_msg __free(kfree) = NULL; > > + int err = 0; > > + > > + if (copy_from_user(&cmd_snd_rcv_rsp_info, (u8 *)arg, > > + sizeof(cmd_snd_rcv_rsp_info))) { > > + dev_err(dev_ctx->priv->dev, > > + "%s: Failed to copy cmd_snd_rcv_rsp_info from user\n", > > + dev_ctx->miscdev.name); > > + err = -EFAULT; > > + goto exit; > > + } > > + > > + if (cmd_snd_rcv_rsp_info.tx_buf_sz < SE_MU_HDR_SZ) { > > + dev_err(dev_ctx->priv->dev, > > + "%s: User buffer too small(%d < %d)\n", > > + dev_ctx->miscdev.name, > > + cmd_snd_rcv_rsp_info.tx_buf_sz, > > + SE_MU_HDR_SZ); > > + err = -ENOSPC; > > + goto exit; > > + } > > + > > + rx_msg = kzalloc(cmd_snd_rcv_rsp_info.rx_buf_sz, GFP_KERNEL); > > + if (!rx_msg) { > > + err = -ENOMEM; > > + goto exit; > > + } > > + > > + tx_msg = memdup_user(cmd_snd_rcv_rsp_info.tx_buf, > > + cmd_snd_rcv_rsp_info.tx_buf_sz); > > + if (IS_ERR(tx_msg)) { > > + err = PTR_ERR(tx_msg); > > + goto exit; > > + } > > + > > + if (tx_msg->header.tag != priv->cmd_tag) { > > + err = -EINVAL; > > + goto exit; > > + } > > + > > + guard(mutex)(&priv->se_if_cmd_lock); > > + priv->waiting_rsp_dev = dev_ctx; > > + dev_ctx->temp_resp_size = cmd_snd_rcv_rsp_info.rx_buf_sz; > > + > > + /* Device Context that is assigned to be a > > + * FW's command receiver, has pre-allocated buffer. > > + */ > > + if (dev_ctx != priv->cmd_receiver_dev) > > + dev_ctx->temp_resp = rx_msg; > > + > > + err = ele_miscdev_msg_send(dev_ctx, > > + tx_msg, > > + cmd_snd_rcv_rsp_info.tx_buf_sz); > > + if (err < 0) > > + goto exit; > > + > > + cmd_snd_rcv_rsp_info.tx_buf_sz = err; > > + > > + err = ele_miscdev_msg_rcv(dev_ctx, > > + cmd_snd_rcv_rsp_info.rx_buf, > > + cmd_snd_rcv_rsp_info.rx_buf_sz); > > Ok, here you now have serialized sending and receiving messages, > > With this you no longer need priv->waiting_rsp_dev, dev_ctx->temp_resp and > dev_ctx->temp_resp_size. Drop these for further cleanup. It is very much needed. - priv->waiting_rsp_dev, help identify in the callback function that: - the message is targeted for dev_ctx(user space) or dev(kernel space). - the message is targeted for for which dev_ctx. - dev_ctx->temp_resp, this buffer pointer is needed, to receive the message received in call back. - dev_ctx->temp_resp_size, is needed to compare the size of in-coming message. All the three are needed in callback function. > > > +} > > + > > +static int se_ioctl_get_mu_info(struct se_if_device_ctx *dev_ctx, > > + u64 arg) { > > + struct se_if_priv *priv = dev_get_drvdata(dev_ctx->dev); > > + struct se_if_node_info *if_node_info; > > + struct se_ioctl_get_if_info info; > > + int err = 0; > > + > > + if_node_info = (struct se_if_node_info *)priv->info; > > + > > + info.se_if_id = if_node_info->se_if_id; > > + info.interrupt_idx = 0; > > + info.tz = 0; > > + info.did = if_node_info->se_if_did; > > + info.cmd_tag = if_node_info->cmd_tag; > > + info.rsp_tag = if_node_info->rsp_tag; > > + info.success_tag = if_node_info->success_tag; > > + info.base_api_ver = if_node_info->base_api_ver; > > + info.fw_api_ver = if_node_info->fw_api_ver; > > This really shouldn't be here. You pass cmd_tag and rsp_tag to userspace just > to guide userspace how to construct a message. > > This shows that the messages should be constructed in the Kernel rather than > in userspace. Just pass the message content from userspace to the kernel and > let the kernel build the message on the sender side. This will help collecting user-space application logs, with correct tags. This is already used by the customers, for debug. > > > +/* IOCTL entry point of a character device */ static long > > +se_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { > > + struct se_if_device_ctx *dev_ctx = container_of(fp->private_data, > > + struct se_if_device_ctx, > > + miscdev); > > + struct se_if_priv *se_if_priv = dev_ctx->priv; > > + int err = -EINVAL; > > + > > + /* Prevent race during change of device context */ > > + if (down_interruptible(&dev_ctx->fops_lock)) > > + return -EBUSY; > > + > > + switch (cmd) { > > + case SE_IOCTL_ENABLE_CMD_RCV: > > + if (!se_if_priv->cmd_receiver_dev) { > > + err = 0; > > + se_if_priv->cmd_receiver_dev = dev_ctx; > > + dev_ctx->temp_resp = kzalloc(MAX_NVM_MSG_LEN, > GFP_KERNEL); > > + if (!dev_ctx->temp_resp) > > + err = -ENOMEM; > > + } > > cmd_receiver_dev isn't locked by anything, still it can be accessed by different > userspace processes. It is not accessed by different Userspace processes. It is a slave to FW. FW interacts with it when FW receive a command to do any action, from userspace. Hence, it will be executed under command-lock. > > Besides, when already another instance is configured for receiving commands I > would expect an -EBUSY here instead of silently ignoring the ioctl. Ok. Accepted. > > > + break; > > + case SE_IOCTL_GET_MU_INFO: > > + err = se_ioctl_get_mu_info(dev_ctx, arg); > > + break; > > + case SE_IOCTL_SETUP_IOBUF: > > + err = se_ioctl_setup_iobuf_handler(dev_ctx, arg); > > + break; > > + case SE_IOCTL_GET_SOC_INFO: > > + err = se_ioctl_get_se_soc_info_handler(dev_ctx, arg); > > + break; > > + case SE_IOCTL_CMD_SEND_RCV_RSP: > > + err = se_ioctl_cmd_snd_rcv_rsp_handler(dev_ctx, arg); > > + break; > > + > > + default: > > + err = -EINVAL; > > + dev_dbg(se_if_priv->dev, > > + "%s: IOCTL %.8x not supported\n", > > + dev_ctx->miscdev.name, > > + cmd); > > + } > > + > > + up(&dev_ctx->fops_lock); > > + return (long)err; > > +} > > + > > ... > > > +static int init_device_context(struct se_if_priv *priv) { > > + const struct se_if_node_info *info = priv->info; > > + struct se_if_device_ctx *dev_ctx; > > + u8 *devname; > > + int ret = 0; > > + int i; > > + > > + priv->ctxs = devm_kzalloc(priv->dev, sizeof(dev_ctx) * priv- > >max_dev_ctx, > > + GFP_KERNEL); > > + > > + if (!priv->ctxs) { > > + ret = -ENOMEM; > > + return ret; > > + } > > + > > + /* Create users */ > > + for (i = 0; i < priv->max_dev_ctx; i++) { > > + dev_ctx = devm_kzalloc(priv->dev, sizeof(*dev_ctx), GFP_KERNEL); > > + if (!dev_ctx) { > > + ret = -ENOMEM; > > + return ret; > > + } > > + > > + dev_ctx->dev = priv->dev; > > + dev_ctx->status = SE_IF_CTX_FREE; > > + dev_ctx->priv = priv; > > + > > + priv->ctxs[i] = dev_ctx; > > + > > + /* Default value invalid for an header. */ > > + init_waitqueue_head(&dev_ctx->wq); > > + > > + INIT_LIST_HEAD(&dev_ctx->pending_out); > > + INIT_LIST_HEAD(&dev_ctx->pending_in); > > + sema_init(&dev_ctx->fops_lock, 1); > > + > > + devname = devm_kasprintf(priv->dev, GFP_KERNEL, "%s_ch%d", > > + info->se_name, i); > > + if (!devname) { > > + ret = -ENOMEM; > > + return ret; > > + } > > + > > + dev_ctx->miscdev.name = devname; > > + dev_ctx->miscdev.minor = MISC_DYNAMIC_MINOR; > > + dev_ctx->miscdev.fops = &se_if_fops; > > + dev_ctx->miscdev.parent = priv->dev; > > + ret = misc_register(&dev_ctx->miscdev); > > + if (ret) { > > + dev_err(priv->dev, "failed to register misc device %d\n", > > + ret); > > + return ret; > > + } > > Here you register four character devices which all allow a single open. > > There's no need to artificially limit the number of users. Just register a single > character device, allow it to be opened multiple times and allocate the instance > specific context as necessary in se_if_fops_open(). Accepted. > > Sascha > > -- > Pengutronix e.K. | | > Steuerwalder Str. 21 | > https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww. > pengutronix.de%2F&data=05%7C02%7Cpankaj.gupta%40nxp.com%7C5bb7 > 0a0c3bcb437e2e3808dcab229d77%7C686ea1d3bc2b4c6fa92cd99c5c3016 > 35%7C0%7C0%7C638573412358069325%7CUnknown%7CTWFpbGZsb3d8 > eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3 > D%7C0%7C%7C%7C&sdata=97GKp2ydNvQz0oOwGp0dM3eez3L8IAE1sOqC > 3bhAxd8%3D&reserved=0 | > 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | > Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |