/** * rpmsg_rdev_init_channels * * This function is only applicable to RPMSG remote. It obtains channel IDs * from the HIL and creates RPMSG channels corresponding to each ID. * * @param rdev - pointer to remote device * * @return - status of function execution * */ int rpmsg_rdev_init_channels(struct remote_device *rdev) { struct rpmsg_channel *rp_chnl; struct proc_chnl *chnl_info; int num_chnls, idx; if (rdev->role == RPMSG_MASTER) { chnl_info = hil_get_chnl_info(rdev->proc, &num_chnls); for (idx = 0; idx < num_chnls; idx++) { rp_chnl = _rpmsg_create_channel(rdev, chnl_info[idx].name, 0x00, RPMSG_NS_EPT_ADDR); if (!rp_chnl) { return RPMSG_ERR_NO_MEM; } rp_chnl->rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev, RPMSG_ADDR_ANY); if (!rp_chnl->rp_ept) { return RPMSG_ERR_NO_MEM; } rp_chnl->src = rp_chnl->rp_ept->addr; } } return RPMSG_SUCCESS; }
int alloc_rpmsg_instance(struct rpmsg_channel *rpdev, struct rpmsg_instance **pInstance) { int ret = 0; struct rpmsg_instance *instance; dev_info(&rpdev->dev, "Allocating rpmsg_instance\n"); instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { ret = -ENOMEM; dev_err(&rpdev->dev, "kzalloc rpmsg_instance failed\n"); goto alloc_out; } instance->rpdev = rpdev; instance->tx_msg = kzalloc(sizeof(struct tx_ipc_msg), GFP_KERNEL); if (!instance->tx_msg) { ret = -ENOMEM; dev_err(&rpdev->dev, "kzalloc instance tx_msg failed\n"); goto error_tx_msg_create; } instance->rx_msg = kzalloc(sizeof(struct rx_ipc_msg), GFP_KERNEL); if (!instance->rx_msg) { ret = -ENOMEM; dev_err(&rpdev->dev, "kzalloc instance rx_msg failed\n"); goto error_rx_msg_create; } instance->endpoint = rpmsg_create_ept(rpdev, rpmsg_recv_cb, instance, RPMSG_ADDR_ANY); if (!instance->endpoint) { dev_err(&rpdev->dev, "create instance endpoint failed\n"); ret = -ENOMEM; goto error_endpoint_create; } goto alloc_out; error_endpoint_create: kfree(instance->rx_msg); instance->rx_msg = NULL; error_rx_msg_create: kfree(instance->tx_msg); instance->tx_msg = NULL; error_tx_msg_create: kfree(instance); instance = NULL; alloc_out: *pInstance = instance; return ret; }
/** * rpmsg_ns_callback * * This callback handles name service announcement from the remote device * and creates/deletes rpmsg channels. * * @param server_chnl - pointer to server channel control block. * @param data - pointer to received messages * @param len - length of received data * @param priv - any private data * @param src - source address * * @return void */ void rpmsg_ns_callback(struct rpmsg_channel *server_chnl, void *data, int len, void *priv, unsigned long src) { struct remote_device *rdev; struct rpmsg_channel *rp_chnl; struct rpmsg_ns_msg *ns_msg; struct llist *node; rdev = (struct remote_device *) priv; //FIXME: This assumes same name string size for channel name both on master //and remote. If this is not the case then we will have to parse the //message contents. ns_msg = (struct rpmsg_ns_msg *) data; ns_msg->name[len - 1] = '\0'; if (ns_msg->flags & RPMSG_NS_DESTROY) { node = rpmsg_rdev_get_chnl_node_from_id(rdev, ns_msg->name); if (node) { rp_chnl = (struct rpmsg_channel *) node->data; if (rdev->channel_destroyed) { rdev->channel_destroyed(rp_chnl); } rpmsg_destroy_ept(rp_chnl->rp_ept); _rpmsg_delete_channel(rp_chnl); } } else { rp_chnl = _rpmsg_create_channel(rdev, ns_msg->name, 0x00, ns_msg->addr); if (rp_chnl) { rp_chnl->state = RPMSG_CHNL_STATE_ACTIVE; /* Create default endpoint for channel */ rp_chnl->rp_ept = rpmsg_create_ept(rp_chnl, rdev->default_cb, rdev, RPMSG_ADDR_ANY); if (rp_chnl->rp_ept) { rp_chnl->src = rp_chnl->rp_ept->addr; /* * Echo back the NS message to remote in order to * complete the connection stage. Remote will know the endpoint * address from this point onward which will enable it to send * message without waiting for any application level message from * master. */ rpmsg_send(rp_chnl,data,len); if (rdev->channel_created) { rdev->channel_created(rp_chnl); } } } } }
static int init_neo_proxy(struct _rpmsg_params *local, struct rpmsg_channel *rpmsg_chnl) { int status =0; /* Initialize mutex */ mutex_init(&local->sync_lock); /* Initialize wait queue head that provides blocking rx for userspace */ init_waitqueue_head(&local->usr_wait_q); /* Allocate kfifo for rpmsg */ status = kfifo_alloc(&local->rpmsg_kfifo, RPMSG_KFIFO_SIZE, GFP_KERNEL); kfifo_reset(&local->rpmsg_kfifo); if (status) { pr_err("ERROR: %s %d Failed to run kfifo_alloc. rc=%d\n", __FUNCTION__, __LINE__,status); goto error0; } local->rpmsg_chnl = rpmsg_chnl; local->block_flag = 0; local->ept = rpmsg_create_ept(local->rpmsg_chnl, rpmsg_proxy_dev_ept_cb, local, local->endpt); if (!local->ept) { pr_err("ERROR: %s %d Failed to create endpoint.\n", __FUNCTION__, __LINE__); goto error1; } goto out; //TCM rpmsg_destroy_ept(local->ept); error1: kfifo_free(&local->rpmsg_kfifo); error0: pr_err("ERROR: %s %d\n", __FUNCTION__, __LINE__); return -ENODEV; out: pr_info("%s %d\n", __FUNCTION__, __LINE__); return 0; }
static int rpmsg_dev_probe(struct device *dev) { struct rpmsg_channel *rpdev = to_rpmsg_channel(dev); struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); struct virtproc_info *vrp = rpdev->vrp; struct rpmsg_endpoint *ept; int err; ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, rpdev->src); if (!ept) { dev_err(dev, "failed to create endpoint\n"); err = -ENOMEM; goto out; } rpdev->ept = ept; rpdev->src = ept->addr; err = rpdrv->probe(rpdev); if (err) { dev_err(dev, "%s: failed: %d\n", __func__, err); rpmsg_destroy_ept(ept); goto out; } /* need to tell remote processor's name service about this channel ? */ if (rpdev->announce && virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) { struct rpmsg_ns_msg nsm; strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE); nsm.addr = rpdev->src; nsm.flags = RPMSG_NS_CREATE; err = rpmsg_sendto(rpdev, &nsm, sizeof(nsm), RPMSG_NS_ADDR); if (err) dev_err(dev, "failed to announce service %d\n", err); } out: return err; }
/** * rpmsg_create_channel * * This function provides facility to create channel dynamically. It sends * Name Service announcement to remote device to let it know about the channel * creation. There must be an active communication among the cores (or atleast * one rpmsg channel must already exist) before using this API to create new * channels. * * @param rdev - pointer to remote device * @param name - channel name * * @return - pointer to new rpmsg channel * */ struct rpmsg_channel *rpmsg_create_channel(struct remote_device *rdev, char *name) { struct rpmsg_channel *rp_chnl; struct rpmsg_endpoint *rp_ept; if (!rdev || !name) { return RPMSG_NULL ; } /* Create channel instance */ rp_chnl = _rpmsg_create_channel(rdev, name, RPMSG_NS_EPT_ADDR, RPMSG_NS_EPT_ADDR); if (!rp_chnl) { return RPMSG_NULL ; } /* Create default endpoint for the channel */ rp_ept = rpmsg_create_ept(rp_chnl , rdev->default_cb, rdev, RPMSG_ADDR_ANY); if (!rp_ept) { _rpmsg_delete_channel(rp_chnl); return RPMSG_NULL; } rp_chnl->rp_ept = rp_ept; rp_chnl->src = rp_ept->addr; rp_chnl->state = RPMSG_CHNL_STATE_NS; /* Notify the application of channel creation event */ if (rdev->channel_created) { rdev->channel_created(rp_chnl); } /* Send NS announcement to remote processor */ rpmsg_send_ns_message(rdev, rp_chnl, RPMSG_NS_CREATE); return rp_chnl; }
int rpmsg_retarget_init(struct rpmsg_channel *rp_chnl, rpc_shutdown_cb cb) { int status; /* Allocate memory for rpc control block */ rpc_data = (struct _rpc_data*) env_allocate_memory( sizeof(struct _rpc_data)); /* Create a mutex for synchronization */ status = env_create_mutex(&rpc_data->rpc_lock, 1); /* Create a mutex for synchronization */ status = env_create_sync_lock(&rpc_data->sync_lock, LOCKED); /* Create a endpoint to handle rpc response from master */ rpc_data->rpmsg_chnl = rp_chnl; rpc_data->rp_ept = rpmsg_create_ept(rpc_data->rpmsg_chnl, rpc_cb, RPMSG_NULL, PROXY_ENDPOINT); rpc_data->rpc = env_allocate_memory(RPC_BUFF_SIZE); rpc_data->rpc_response = env_allocate_memory(RPC_BUFF_SIZE); rpc_data->shutdown_cb = cb; return status; }
/* * when an rpmsg driver is probed with a channel, we seamlessly create * it an endpoint, binding its rx callback to a unique local rpmsg * address. * * if we need to, we also announce about this channel to the remote * processor (needed in case the driver is exposing an rpmsg service). */ static int rpmsg_dev_probe(struct device *dev) { struct rpmsg_device *rpdev = to_rpmsg_device(dev); struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); struct rpmsg_channel_info chinfo = {}; struct rpmsg_endpoint *ept = NULL; int err; if (rpdrv->callback) { strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); chinfo.src = rpdev->src; chinfo.dst = RPMSG_ADDR_ANY; ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo); if (!ept) { dev_err(dev, "failed to create endpoint\n"); err = -ENOMEM; goto out; } rpdev->ept = ept; rpdev->src = ept->addr; } err = rpdrv->probe(rpdev); if (err) { dev_err(dev, "%s: failed: %d\n", __func__, err); if (ept) rpmsg_destroy_ept(ept); goto out; } if (ept && rpdev->ops->announce_create) err = rpdev->ops->announce_create(rpdev); out: return err; }
static void rpmsg_channel_created(struct rpmsg_channel *rp_chnl) { app_rp_chnl = rp_chnl; rp_ept = rpmsg_create_ept(rp_chnl, rpmsg_read_cb, RPMSG_NULL, RPMSG_ADDR_ANY); }
static int rpmsg_func_test_kern_app_probe(struct rpmsg_channel *rpdev) { int err; int uninit = 0; struct ept_cmd_data *ept_data; struct command *cmd; pr_err("\r\nFunc Test Suite Start! \r\n"); /* Create endpoint for remote channel and register rx callabck */ ept = rpmsg_create_ept(rpdev, rpmsg_func_test_default_rx_cb, 0, RPMSG_ADDR_ANY); if (!ept) { pr_err(" Endpoint creation for failed!\r\n"); return -ENOMEM; } /* Send init message to complete the connection loop */ err = rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, init_msg, sizeof(init_msg)); if (err) { pr_err(" Init message send failed!\r\n"); return err; } /* Send a message to start tests */ err = rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, start_test, sizeof(start_test)); if (err) { pr_err("Test start command failed!\r\n"); return err; } while (1) { /* Wait till the data is echoed back. */ wait_event_interruptible(wait_queue, flag != 0); flag = 0; cmd = (struct command *)r_buffer; if (cmd->comm_start == CMD_START) { unsigned int cm_code = cmd->comm_code; void *data = cmd->data; switch (cm_code) { case CREATE_EPT: ept_data = (struct ept_cmd_data *)data; rp_ept = rpmsg_create_ept(rpdev, rpmsg_func_test_ept_rx_cb, 0, ept_data->dst); if (rp_ept) /* Send data back to ack. */ rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, r_buffer, data_length); break; case DELETE_EPT: rpmsg_destroy_ept(rp_ept); rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, r_buffer, data_length); break; case CREATE_CHNL: break; case DELETE_CHNL: rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, r_buffer, data_length); uninit = 1; break; case QUERY_FW_NAME: rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, &firmware_name[0], strlen(firmware_name)+1); break; case PRINT_RESULT: pr_err("%s", data); rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, r_buffer, data_length); break; default: rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, r_buffer, data_length); break; } } else rpmsg_send_offchannel(rpdev, ept->addr, rpdev->dst, r_buffer, data_length); if (uninit) break; } call_usermodehelper(shutdown_argv[0], shutdown_argv, NULL, UMH_NO_WAIT); return 0; }
int rpmsg_neo_tty(struct rpmsg_channel *rpmsg_chnl,rpmsg_neo_remove_t *remove_func ) { int err = 0; struct rpmsgtty_port *cport = &rpmsg_tty_port; *remove_func = rpmsg_neo_tty_remove; memset(cport, 0, sizeof(rpmsg_tty_port)); cport->rpmsg_chnl = rpmsg_chnl; cport->endpt = RPMSG_TTY_ENPT; cport->ept = rpmsg_create_ept(cport->rpmsg_chnl, rpmsg_tty_cb, cport, cport->endpt); if (!cport->ept) { pr_err("ERROR: %s %s %d Failed to create proxy service endpoint.\n", __FILE__, __FUNCTION__, __LINE__); err = -1; goto error0; } rpmsgtty_driver = tty_alloc_driver(1, TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW | TTY_DRIVER_UNNUMBERED_NODE); if (IS_ERR(rpmsgtty_driver)) { pr_err("ERROR:%s %d Failed to alloc tty\n", __FUNCTION__, __LINE__); rpmsg_destroy_ept(cport->ept); return PTR_ERR(rpmsgtty_driver); } spin_lock_init(&cport->rx_lock); cport->port.low_latency = cport->port.flags | ASYNC_LOW_LATENCY; tty_port_init(&cport->port); cport->port.ops = &rpmsgtty_port_ops; rpmsgtty_driver->driver_name = "ttyrpmsg"; rpmsgtty_driver->name = "ttyrpmsg"; rpmsgtty_driver->major = TTYAUX_MAJOR; rpmsgtty_driver->minor_start = 4; rpmsgtty_driver->type = TTY_DRIVER_TYPE_CONSOLE; rpmsgtty_driver->init_termios = tty_std_termios; // rpmsgtty_driver->init_termios.c_oflag = OPOST | OCRNL | ONOCR | ONLRET; rpmsgtty_driver->init_termios.c_cflag |= CLOCAL; tty_set_operations(rpmsgtty_driver, &imxrpmsgtty_ops); tty_port_link_device(&cport->port, rpmsgtty_driver, 0); err = tty_register_driver(rpmsgtty_driver); if (err < 0) { pr_err("Couldn't install rpmsg tty driver: err %d\n", err); goto error; } else { pr_info("Install rpmsg tty driver!\n"); } return 0; error: put_tty_driver(rpmsgtty_driver); tty_port_destroy(&cport->port); rpmsgtty_driver = NULL; rpmsg_destroy_ept(cport->ept); error0: return err; }
int main() { struct remote_proc *proc; int uninit = 0; struct ept_cmd_data *ept_data; #ifdef ZYNQ7_BAREMETAL /* Switch to System Mode */ SWITCH_TO_SYS_MODE(); #endif /* Initialize HW system components */ init_system(); rsc_info.rsc_tab = (struct resource_table *)&resources; rsc_info.size = sizeof(resources); /* This API creates the virtio devices for this remote node and initializes other relevant resources defined in the resource table */ remoteproc_resource_init(&rsc_info, rpmsg_channel_created, rpmsg_channel_deleted, rpmsg_read_default_cb, &proc); for (;;) { if (intr_flag) { struct command *cmd = (struct command *)r_buffer; if (cmd->comm_start == CMD_START) { unsigned int cm_code = cmd->comm_code; void *data = cmd->data; switch (cm_code) { case CREATE_EPT: ept_data = (struct ept_cmd_data *)data; rp_ept = rpmsg_create_ept(app_rp_chnl, rpmsg_read_ept_cb, RPMSG_NULL, ept_data->dst); if (rp_ept) { /* Send data back to ack. */ rpmsg_sendto(app_rp_chnl, r_buffer, Len, Src); } break; case DELETE_EPT: rpmsg_destroy_ept(rp_ept); rpmsg_sendto(app_rp_chnl, r_buffer, Len, Src); break; case CREATE_CHNL: break; case DELETE_CHNL: rpmsg_sendto(app_rp_chnl, r_buffer, Len, Src); remoteproc_resource_deinit(proc); uninit = 1; break; case QUERY_FW_NAME: rpmsg_send(app_rp_chnl, &firmware_name[0], strlen(firmware_name) + 1); break; default: rpmsg_sendto(app_rp_chnl, r_buffer, Len, Src); break; } } else { rpmsg_sendto(app_rp_chnl, r_buffer, Len, Src); } intr_flag = 0; if (uninit) break; } sleep(); } return 0; }
int rpmsg_neo_ethernet(struct rpmsg_channel *rpmsg_chnl, rpmsg_neo_remove_t *remove_func ) { int result, ret = -ENOMEM; struct _rpmsg_dev_params *priv; pr_info("INFO:%s %d\n", __FUNCTION__, __LINE__); *remove_func = rpmsg_neo_ethernet_remove; rpmsg_netdev = alloc_etherdev(sizeof(struct _rpmsg_dev_params)); if (rpmsg_netdev ==NULL) { pr_err("ERROR: %s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return ret; } rpmsg_netdev->ethtool_ops = &rpmsg_ethtool_ops; rpmsg_netdev->netdev_ops = &rpmsg_netdev_ops; rpmsg_netdev->mtu = ETHERNET_MTU_SIZE; priv = netdev_priv(rpmsg_netdev); memset(priv, 0, sizeof(*priv)); pr_info("INFO: %s %s %d\n", __FILE__, __FUNCTION__, __LINE__); priv->dev = rpmsg_netdev; rpmsg_read_mac_addr(rpmsg_netdev); // call priv->rpmsg_chnl = rpmsg_chnl; priv->endpt = ETHERNET_ENDPOINT; spin_lock_init(&priv->lock); priv->ept = rpmsg_create_ept(priv->rpmsg_chnl, rpmsg_ethernet_dev_ept_cb, priv, priv->endpt); if (!priv->ept) { pr_err("ERROR: %s %d Failed to create endpoint.\n", __FUNCTION__, __LINE__); goto out; } result = register_netdev(rpmsg_netdev); if (result) { pr_err("ERROR: %s %s %d\n", __FILE__, __FUNCTION__, __LINE__); } else { ret = 0; pr_info("INFO: %s %s %d\n", __FILE__, __FUNCTION__, __LINE__); } return 0; out: if(rpmsg_netdev) { pr_err("ERROR: %s %s %d\n", __FILE__, __FUNCTION__, __LINE__); return -1; } return ret; }