Loading drivers/usb/gadget/function/f_gsi.c +183 −47 Original line number Original line Diff line number Diff line Loading @@ -19,7 +19,14 @@ module_param(qti_packet_debug, bool, 0644); MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); static struct workqueue_struct *ipa_usb_wq; static struct workqueue_struct *ipa_usb_wq; static struct gsi_inst_status { struct mutex gsi_lock; bool inst_exist; struct gsi_opts *opts; } inst_status[IPA_USB_MAX_TETH_PROT_SIZE]; /* Deregister misc device and free instance structures */ static void gsi_inst_clean(struct gsi_opts *opts); static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port); static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi); static int gsi_ctrl_send_notification(struct f_gsi *gsi); Loading Loading @@ -919,40 +926,69 @@ static int gsi_ctrl_dev_open(struct inode *ip, struct file *fp) struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port, struct gsi_ctrl_port, ctrl_device); ctrl_device); struct f_gsi *gsi = c_port_to_gsi(c_port); struct f_gsi *gsi; struct gsi_inst_status *inst_cur; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); pr_err_ratelimited("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; } } gsi = container_of(c_port, struct f_gsi, c_port); inst_cur = &inst_status[gsi->prot_id]; log_event_dbg("%s: open ctrl dev %s", __func__, c_port->name); log_event_dbg("%s: open ctrl dev %s", __func__, c_port->name); mutex_lock(&inst_cur->gsi_lock); fp->private_data = &gsi->prot_id; if (!inst_cur->inst_exist) { mutex_unlock(&inst_cur->gsi_lock); log_event_err("%s: [prot_id = %d], GSI instance freed already\n", __func__, gsi->prot_id); return -ENODEV; } if (c_port->is_open) { if (c_port->is_open) { log_event_err("%s: Already opened", __func__); mutex_unlock(&inst_cur->gsi_lock); log_event_err("%s: Already opened\n", __func__); return -EBUSY; return -EBUSY; } } c_port->is_open = true; c_port->is_open = true; mutex_unlock(&inst_cur->gsi_lock); return 0; return 0; } } static int gsi_ctrl_dev_release(struct inode *ip, struct file *fp) static int gsi_ctrl_dev_release(struct inode *ip, struct file *fp) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, enum ipa_usb_teth_prot prot_id = struct gsi_ctrl_port, *(enum ipa_usb_teth_prot *)(fp->private_data); ctrl_device); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi = c_port_to_gsi(c_port); struct f_gsi *gsi; if (!c_port) { mutex_lock(&inst_cur->gsi_lock); log_event_err("%s: gsi ctrl port %p", __func__, c_port); if (unlikely(inst_cur->inst_exist == false)) { if (inst_cur->opts) { /* GSI instance clean up */ gsi_inst_clean(inst_cur->opts); inst_cur->opts = NULL; } mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: prot_id:%d: delayed free memory\n", __func__, prot_id); return -ENODEV; return -ENODEV; } } log_event_dbg("close ctrl dev %s", c_port->name); inst_cur->opts->gsi->c_port.is_open = false; gsi = inst_cur->opts->gsi; mutex_unlock(&inst_cur->gsi_lock); c_port->is_open = false; log_event_dbg("close ctrl dev %s\n", inst_cur->opts->gsi->c_port.name); return 0; return 0; } } Loading @@ -960,16 +996,28 @@ static int gsi_ctrl_dev_release(struct inode *ip, struct file *fp) static ssize_t static ssize_t gsi_ctrl_dev_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) gsi_ctrl_dev_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, ctrl_device); struct f_gsi *gsi = c_port_to_gsi(c_port); struct gsi_ctrl_pkt *cpkt = NULL; struct gsi_ctrl_pkt *cpkt = NULL; enum ipa_usb_teth_prot prot_id = *(enum ipa_usb_teth_prot *)(fp->private_data); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi; unsigned long flags; unsigned long flags; int ret = 0; int ret = 0; log_event_dbg("%s: Enter %zu", __func__, count); pr_debug("%s: Enter %zu", __func__, count); mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &inst_cur->opts->gsi->c_port; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); log_event_err("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; Loading Loading @@ -1037,13 +1085,27 @@ static ssize_t gsi_ctrl_dev_write(struct file *fp, const char __user *buf, int ret = 0; int ret = 0; unsigned long flags; unsigned long flags; struct gsi_ctrl_pkt *cpkt; struct gsi_ctrl_pkt *cpkt; struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, struct usb_request *req; ctrl_device); enum ipa_usb_teth_prot prot_id = struct f_gsi *gsi = c_port_to_gsi(c_port); *(enum ipa_usb_teth_prot *)(fp->private_data); struct usb_request *req = c_port->notify_req; struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi; log_event_dbg("Enter %zu", count); pr_debug("Enter %zu", count); mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &gsi->c_port; req = c_port->notify_req; if (!c_port || !req || !req->buf) { if (!c_port || !req || !req->buf) { log_event_err("%s: c_port %p req %p req->buf %p", log_event_err("%s: c_port %p req %p req->buf %p", Loading Loading @@ -1101,15 +1163,28 @@ static ssize_t gsi_ctrl_dev_write(struct file *fp, const char __user *buf, static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) unsigned long arg) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, struct f_gsi *gsi; ctrl_device); struct f_gsi *gsi = c_port_to_gsi(c_port); struct gsi_ctrl_pkt *cpkt; struct gsi_ctrl_pkt *cpkt; struct ep_info info; struct ep_info info; enum ipa_usb_teth_prot prot_id = *(enum ipa_usb_teth_prot *)(fp->private_data); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; int val, ret = 0; int val, ret = 0; unsigned long flags; unsigned long flags; mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &gsi->c_port; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); log_event_err("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; Loading Loading @@ -1230,13 +1305,25 @@ static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, static unsigned int gsi_ctrl_dev_poll(struct file *fp, poll_table *wait) static unsigned int gsi_ctrl_dev_poll(struct file *fp, poll_table *wait) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, enum ipa_usb_teth_prot prot_id = ctrl_device); *(enum ipa_usb_teth_prot *)(fp->private_data); struct f_gsi *gsi = c_port_to_gsi(c_port); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi; unsigned long flags; unsigned long flags; unsigned int mask = 0; unsigned int mask = 0; mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &inst_cur->opts->gsi->c_port; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); log_event_err("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; Loading Loading @@ -2827,7 +2914,11 @@ static struct f_gsi *gsi_function_init(enum ipa_usb_teth_prot prot_id) static void gsi_opts_release(struct config_item *item) static void gsi_opts_release(struct config_item *item) { { struct gsi_opts *opts = to_gsi_opts(item); struct gsi_opts *opts = to_gsi_opts(item); struct f_gsi *gsi; gsi = opts->gsi; log_event_dbg("%s: releasing %s instance\n", __func__, gsi->function.name); usb_put_function_instance(&opts->func_inst); usb_put_function_instance(&opts->func_inst); } } Loading Loading @@ -2991,26 +3082,52 @@ static struct config_item_type gsi_func_type = { .ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE, }; }; static void gsi_inst_clean(struct gsi_opts *opts) { if (opts->gsi->c_port.ctrl_device.fops) misc_deregister(&opts->gsi->c_port.ctrl_device); kfree(opts->gsi); kfree(opts); } static int gsi_set_inst_name(struct usb_function_instance *fi, static int gsi_set_inst_name(struct usb_function_instance *fi, const char *name) const char *name) { { int ret, name_len; int prot_id, name_len; struct f_gsi *gsi; struct f_gsi *gsi; char gsi_inst_name[MAX_INST_NAME_LEN + sizeof("gsi.") + 1]; char gsi_inst_name[MAX_INST_NAME_LEN + sizeof("gsi.") + 1]; struct gsi_opts *opts = container_of(fi, struct gsi_opts, func_inst); void *ipc_log_ctxt; void *ipc_log_ctxt; struct gsi_opts *opts, *opts_prev; opts = container_of(fi, struct gsi_opts, func_inst); name_len = strlen(name) + 1; name_len = strlen(name) + 1; if (name_len > MAX_INST_NAME_LEN) if (name_len > MAX_INST_NAME_LEN) return -ENAMETOOLONG; return -ENAMETOOLONG; ret = name_to_prot_id(name); prot_id = name_to_prot_id(name); if (ret < 0) { if (prot_id < 0) { pr_err("%s: failed to find prot id for %s instance\n", pr_err("%s: failed to find prot id for %s instance\n", __func__, name); __func__, name); return -EINVAL; return -EINVAL; } } mutex_lock(&inst_status[prot_id].gsi_lock); opts_prev = inst_status[prot_id].opts; if (opts_prev) { mutex_unlock(&inst_status[prot_id].gsi_lock); pr_err("%s: prot_id = %d, prev inst do not freed yet\n", __func__, prot_id); return -EBUSY; } mutex_unlock(&inst_status[prot_id].gsi_lock); gsi = gsi_function_init(prot_id); if (IS_ERR(gsi)) return PTR_ERR(gsi); opts->gsi = gsi; /* /* * create instance name with prefixing "gsi." to differentiate * create instance name with prefixing "gsi." to differentiate * ipc log debugfs entry * ipc log debugfs entry Loading @@ -3020,31 +3137,45 @@ static int gsi_set_inst_name(struct usb_function_instance *fi, if (!ipc_log_ctxt) if (!ipc_log_ctxt) pr_err("%s: Err allocating ipc_log_ctxt for prot:%s\n", pr_err("%s: Err allocating ipc_log_ctxt for prot:%s\n", __func__, gsi_inst_name); __func__, gsi_inst_name); opts->gsi->ipc_log_ctxt = ipc_log_ctxt; gsi = gsi_function_init(ret); /* Set instance status */ if (IS_ERR(gsi)) { mutex_lock(&inst_status[prot_id].gsi_lock); ipc_log_context_destroy(ipc_log_ctxt); inst_status[prot_id].inst_exist = true; return PTR_ERR(gsi); inst_status[prot_id].opts = opts; } mutex_unlock(&inst_status[prot_id].gsi_lock); opts->gsi = gsi; opts->gsi->ipc_log_ctxt = ipc_log_ctxt; return 0; return 0; } } static void gsi_free_inst(struct usb_function_instance *f) static void gsi_free_inst(struct usb_function_instance *f) { { struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst); struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst); enum ipa_usb_teth_prot prot_id; struct f_gsi *gsi; if (!opts->gsi) if (!opts->gsi) return; return; if (opts->gsi->c_port.ctrl_device.fops) prot_id = opts->gsi->prot_id; misc_deregister(&opts->gsi->c_port.ctrl_device); gsi = opts->gsi; mutex_lock(&inst_status[prot_id].gsi_lock); if (opts->gsi->c_port.is_open) { /* Mark instance exist as false */ inst_status[prot_id].inst_exist = false; mutex_unlock(&inst_status[prot_id].gsi_lock); log_event_err( "%s: [prot_id = %d] Dev is open, free mem when dev close\n", __func__, prot_id); return; } ipc_log_context_destroy(opts->gsi->ipc_log_ctxt); ipc_log_context_destroy(opts->gsi->ipc_log_ctxt); kfree(opts->gsi); /* Clear instance status */ kfree(opts); gsi_inst_clean(opts); inst_status[prot_id].inst_exist = false; inst_status[prot_id].opts = NULL; mutex_unlock(&inst_status[prot_id].gsi_lock); } } static struct usb_function_instance *gsi_alloc_inst(void) static struct usb_function_instance *gsi_alloc_inst(void) Loading Loading @@ -3083,6 +3214,8 @@ MODULE_DESCRIPTION("GSI function driver"); static int fgsi_init(void) static int fgsi_init(void) { { int i; ipa_usb_wq = alloc_workqueue("k_ipa_usb", ipa_usb_wq = alloc_workqueue("k_ipa_usb", WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE, 1); WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE, 1); if (!ipa_usb_wq) { if (!ipa_usb_wq) { Loading @@ -3090,6 +3223,9 @@ static int fgsi_init(void) return -ENOMEM; return -ENOMEM; } } for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++) mutex_init(&inst_status[i].gsi_lock); return usb_function_register(&gsiusb_func); return usb_function_register(&gsiusb_func); } } module_init(fgsi_init); module_init(fgsi_init); Loading Loading
drivers/usb/gadget/function/f_gsi.c +183 −47 Original line number Original line Diff line number Diff line Loading @@ -19,7 +19,14 @@ module_param(qti_packet_debug, bool, 0644); MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); MODULE_PARM_DESC(qti_packet_debug, "Print QTI Packet's Raw Data"); static struct workqueue_struct *ipa_usb_wq; static struct workqueue_struct *ipa_usb_wq; static struct gsi_inst_status { struct mutex gsi_lock; bool inst_exist; struct gsi_opts *opts; } inst_status[IPA_USB_MAX_TETH_PROT_SIZE]; /* Deregister misc device and free instance structures */ static void gsi_inst_clean(struct gsi_opts *opts); static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port); static void gsi_rndis_ipa_reset_trigger(struct gsi_data_port *d_port); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static void ipa_disconnect_handler(struct gsi_data_port *d_port); static int gsi_ctrl_send_notification(struct f_gsi *gsi); static int gsi_ctrl_send_notification(struct f_gsi *gsi); Loading Loading @@ -919,40 +926,69 @@ static int gsi_ctrl_dev_open(struct inode *ip, struct file *fp) struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port, struct gsi_ctrl_port, ctrl_device); ctrl_device); struct f_gsi *gsi = c_port_to_gsi(c_port); struct f_gsi *gsi; struct gsi_inst_status *inst_cur; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); pr_err_ratelimited("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; } } gsi = container_of(c_port, struct f_gsi, c_port); inst_cur = &inst_status[gsi->prot_id]; log_event_dbg("%s: open ctrl dev %s", __func__, c_port->name); log_event_dbg("%s: open ctrl dev %s", __func__, c_port->name); mutex_lock(&inst_cur->gsi_lock); fp->private_data = &gsi->prot_id; if (!inst_cur->inst_exist) { mutex_unlock(&inst_cur->gsi_lock); log_event_err("%s: [prot_id = %d], GSI instance freed already\n", __func__, gsi->prot_id); return -ENODEV; } if (c_port->is_open) { if (c_port->is_open) { log_event_err("%s: Already opened", __func__); mutex_unlock(&inst_cur->gsi_lock); log_event_err("%s: Already opened\n", __func__); return -EBUSY; return -EBUSY; } } c_port->is_open = true; c_port->is_open = true; mutex_unlock(&inst_cur->gsi_lock); return 0; return 0; } } static int gsi_ctrl_dev_release(struct inode *ip, struct file *fp) static int gsi_ctrl_dev_release(struct inode *ip, struct file *fp) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, enum ipa_usb_teth_prot prot_id = struct gsi_ctrl_port, *(enum ipa_usb_teth_prot *)(fp->private_data); ctrl_device); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi = c_port_to_gsi(c_port); struct f_gsi *gsi; if (!c_port) { mutex_lock(&inst_cur->gsi_lock); log_event_err("%s: gsi ctrl port %p", __func__, c_port); if (unlikely(inst_cur->inst_exist == false)) { if (inst_cur->opts) { /* GSI instance clean up */ gsi_inst_clean(inst_cur->opts); inst_cur->opts = NULL; } mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: prot_id:%d: delayed free memory\n", __func__, prot_id); return -ENODEV; return -ENODEV; } } log_event_dbg("close ctrl dev %s", c_port->name); inst_cur->opts->gsi->c_port.is_open = false; gsi = inst_cur->opts->gsi; mutex_unlock(&inst_cur->gsi_lock); c_port->is_open = false; log_event_dbg("close ctrl dev %s\n", inst_cur->opts->gsi->c_port.name); return 0; return 0; } } Loading @@ -960,16 +996,28 @@ static int gsi_ctrl_dev_release(struct inode *ip, struct file *fp) static ssize_t static ssize_t gsi_ctrl_dev_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) gsi_ctrl_dev_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, ctrl_device); struct f_gsi *gsi = c_port_to_gsi(c_port); struct gsi_ctrl_pkt *cpkt = NULL; struct gsi_ctrl_pkt *cpkt = NULL; enum ipa_usb_teth_prot prot_id = *(enum ipa_usb_teth_prot *)(fp->private_data); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi; unsigned long flags; unsigned long flags; int ret = 0; int ret = 0; log_event_dbg("%s: Enter %zu", __func__, count); pr_debug("%s: Enter %zu", __func__, count); mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &inst_cur->opts->gsi->c_port; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); log_event_err("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; Loading Loading @@ -1037,13 +1085,27 @@ static ssize_t gsi_ctrl_dev_write(struct file *fp, const char __user *buf, int ret = 0; int ret = 0; unsigned long flags; unsigned long flags; struct gsi_ctrl_pkt *cpkt; struct gsi_ctrl_pkt *cpkt; struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, struct usb_request *req; ctrl_device); enum ipa_usb_teth_prot prot_id = struct f_gsi *gsi = c_port_to_gsi(c_port); *(enum ipa_usb_teth_prot *)(fp->private_data); struct usb_request *req = c_port->notify_req; struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi; log_event_dbg("Enter %zu", count); pr_debug("Enter %zu", count); mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &gsi->c_port; req = c_port->notify_req; if (!c_port || !req || !req->buf) { if (!c_port || !req || !req->buf) { log_event_err("%s: c_port %p req %p req->buf %p", log_event_err("%s: c_port %p req %p req->buf %p", Loading Loading @@ -1101,15 +1163,28 @@ static ssize_t gsi_ctrl_dev_write(struct file *fp, const char __user *buf, static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) unsigned long arg) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, struct f_gsi *gsi; ctrl_device); struct f_gsi *gsi = c_port_to_gsi(c_port); struct gsi_ctrl_pkt *cpkt; struct gsi_ctrl_pkt *cpkt; struct ep_info info; struct ep_info info; enum ipa_usb_teth_prot prot_id = *(enum ipa_usb_teth_prot *)(fp->private_data); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; int val, ret = 0; int val, ret = 0; unsigned long flags; unsigned long flags; mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &gsi->c_port; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); log_event_err("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; Loading Loading @@ -1230,13 +1305,25 @@ static long gsi_ctrl_dev_ioctl(struct file *fp, unsigned int cmd, static unsigned int gsi_ctrl_dev_poll(struct file *fp, poll_table *wait) static unsigned int gsi_ctrl_dev_poll(struct file *fp, poll_table *wait) { { struct gsi_ctrl_port *c_port = container_of(fp->private_data, struct gsi_ctrl_port *c_port; struct gsi_ctrl_port, enum ipa_usb_teth_prot prot_id = ctrl_device); *(enum ipa_usb_teth_prot *)(fp->private_data); struct f_gsi *gsi = c_port_to_gsi(c_port); struct gsi_inst_status *inst_cur = &inst_status[prot_id]; struct f_gsi *gsi; unsigned long flags; unsigned long flags; unsigned int mask = 0; unsigned int mask = 0; mutex_lock(&inst_cur->gsi_lock); if (unlikely(inst_cur->inst_exist == false)) { mutex_unlock(&inst_cur->gsi_lock); pr_err_ratelimited("%s: free_inst is called and being freed\n", __func__); return -ENODEV; } mutex_unlock(&inst_cur->gsi_lock); gsi = inst_cur->opts->gsi; c_port = &inst_cur->opts->gsi->c_port; if (!c_port) { if (!c_port) { log_event_err("%s: gsi ctrl port %p", __func__, c_port); log_event_err("%s: gsi ctrl port %p", __func__, c_port); return -ENODEV; return -ENODEV; Loading Loading @@ -2827,7 +2914,11 @@ static struct f_gsi *gsi_function_init(enum ipa_usb_teth_prot prot_id) static void gsi_opts_release(struct config_item *item) static void gsi_opts_release(struct config_item *item) { { struct gsi_opts *opts = to_gsi_opts(item); struct gsi_opts *opts = to_gsi_opts(item); struct f_gsi *gsi; gsi = opts->gsi; log_event_dbg("%s: releasing %s instance\n", __func__, gsi->function.name); usb_put_function_instance(&opts->func_inst); usb_put_function_instance(&opts->func_inst); } } Loading Loading @@ -2991,26 +3082,52 @@ static struct config_item_type gsi_func_type = { .ct_owner = THIS_MODULE, .ct_owner = THIS_MODULE, }; }; static void gsi_inst_clean(struct gsi_opts *opts) { if (opts->gsi->c_port.ctrl_device.fops) misc_deregister(&opts->gsi->c_port.ctrl_device); kfree(opts->gsi); kfree(opts); } static int gsi_set_inst_name(struct usb_function_instance *fi, static int gsi_set_inst_name(struct usb_function_instance *fi, const char *name) const char *name) { { int ret, name_len; int prot_id, name_len; struct f_gsi *gsi; struct f_gsi *gsi; char gsi_inst_name[MAX_INST_NAME_LEN + sizeof("gsi.") + 1]; char gsi_inst_name[MAX_INST_NAME_LEN + sizeof("gsi.") + 1]; struct gsi_opts *opts = container_of(fi, struct gsi_opts, func_inst); void *ipc_log_ctxt; void *ipc_log_ctxt; struct gsi_opts *opts, *opts_prev; opts = container_of(fi, struct gsi_opts, func_inst); name_len = strlen(name) + 1; name_len = strlen(name) + 1; if (name_len > MAX_INST_NAME_LEN) if (name_len > MAX_INST_NAME_LEN) return -ENAMETOOLONG; return -ENAMETOOLONG; ret = name_to_prot_id(name); prot_id = name_to_prot_id(name); if (ret < 0) { if (prot_id < 0) { pr_err("%s: failed to find prot id for %s instance\n", pr_err("%s: failed to find prot id for %s instance\n", __func__, name); __func__, name); return -EINVAL; return -EINVAL; } } mutex_lock(&inst_status[prot_id].gsi_lock); opts_prev = inst_status[prot_id].opts; if (opts_prev) { mutex_unlock(&inst_status[prot_id].gsi_lock); pr_err("%s: prot_id = %d, prev inst do not freed yet\n", __func__, prot_id); return -EBUSY; } mutex_unlock(&inst_status[prot_id].gsi_lock); gsi = gsi_function_init(prot_id); if (IS_ERR(gsi)) return PTR_ERR(gsi); opts->gsi = gsi; /* /* * create instance name with prefixing "gsi." to differentiate * create instance name with prefixing "gsi." to differentiate * ipc log debugfs entry * ipc log debugfs entry Loading @@ -3020,31 +3137,45 @@ static int gsi_set_inst_name(struct usb_function_instance *fi, if (!ipc_log_ctxt) if (!ipc_log_ctxt) pr_err("%s: Err allocating ipc_log_ctxt for prot:%s\n", pr_err("%s: Err allocating ipc_log_ctxt for prot:%s\n", __func__, gsi_inst_name); __func__, gsi_inst_name); opts->gsi->ipc_log_ctxt = ipc_log_ctxt; gsi = gsi_function_init(ret); /* Set instance status */ if (IS_ERR(gsi)) { mutex_lock(&inst_status[prot_id].gsi_lock); ipc_log_context_destroy(ipc_log_ctxt); inst_status[prot_id].inst_exist = true; return PTR_ERR(gsi); inst_status[prot_id].opts = opts; } mutex_unlock(&inst_status[prot_id].gsi_lock); opts->gsi = gsi; opts->gsi->ipc_log_ctxt = ipc_log_ctxt; return 0; return 0; } } static void gsi_free_inst(struct usb_function_instance *f) static void gsi_free_inst(struct usb_function_instance *f) { { struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst); struct gsi_opts *opts = container_of(f, struct gsi_opts, func_inst); enum ipa_usb_teth_prot prot_id; struct f_gsi *gsi; if (!opts->gsi) if (!opts->gsi) return; return; if (opts->gsi->c_port.ctrl_device.fops) prot_id = opts->gsi->prot_id; misc_deregister(&opts->gsi->c_port.ctrl_device); gsi = opts->gsi; mutex_lock(&inst_status[prot_id].gsi_lock); if (opts->gsi->c_port.is_open) { /* Mark instance exist as false */ inst_status[prot_id].inst_exist = false; mutex_unlock(&inst_status[prot_id].gsi_lock); log_event_err( "%s: [prot_id = %d] Dev is open, free mem when dev close\n", __func__, prot_id); return; } ipc_log_context_destroy(opts->gsi->ipc_log_ctxt); ipc_log_context_destroy(opts->gsi->ipc_log_ctxt); kfree(opts->gsi); /* Clear instance status */ kfree(opts); gsi_inst_clean(opts); inst_status[prot_id].inst_exist = false; inst_status[prot_id].opts = NULL; mutex_unlock(&inst_status[prot_id].gsi_lock); } } static struct usb_function_instance *gsi_alloc_inst(void) static struct usb_function_instance *gsi_alloc_inst(void) Loading Loading @@ -3083,6 +3214,8 @@ MODULE_DESCRIPTION("GSI function driver"); static int fgsi_init(void) static int fgsi_init(void) { { int i; ipa_usb_wq = alloc_workqueue("k_ipa_usb", ipa_usb_wq = alloc_workqueue("k_ipa_usb", WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE, 1); WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_FREEZABLE, 1); if (!ipa_usb_wq) { if (!ipa_usb_wq) { Loading @@ -3090,6 +3223,9 @@ static int fgsi_init(void) return -ENOMEM; return -ENOMEM; } } for (i = 0; i < IPA_USB_MAX_TETH_PROT_SIZE; i++) mutex_init(&inst_status[i].gsi_lock); return usb_function_register(&gsiusb_func); return usb_function_register(&gsiusb_func); } } module_init(fgsi_init); module_init(fgsi_init); Loading