static void cmd_phone_start_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod = NULL; mif_info("%s: Recv 0xC8 (CP_START)\n", ld->name); dpram_init_ipc(dpld); iod = link_get_iod_with_format(ld, IPC_FMT); if (!iod) { mif_info("%s: ERR! no iod\n", ld->name); return; } if (dpld->ext_op && dpld->ext_op->cp_start_handler) dpld->ext_op->cp_start_handler(dpld); if (ld->mc->phone_state != STATE_ONLINE) { mif_info("%s: phone_state: %d -> ONLINE\n", ld->name, ld->mc->phone_state); iod->modem_state_changed(iod, STATE_ONLINE); } mif_info("%s: Send 0xC2 (INIT_END)\n", ld->name); send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); }
static int dpram_init_ipc(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; int i; if (ld->mode == LINK_MODE_IPC && get_magic(dpld) == DPRAM_MAGIC_CODE && get_access(dpld) == 1) mif_info("%s: IPC already initialized\n", ld->name); /* Clear pointers in every circular queue */ for (i = 0; i < dpld->max_ipc_dev; i++) { set_tx_head(dpld, i, 0); set_tx_tail(dpld, i, 0); set_rx_head(dpld, i, 0); set_rx_tail(dpld, i, 0); } /* Initialize variables for efficient TX/RX processing */ for (i = 0; i < dpld->max_ipc_dev; i++) dpld->iod[i] = link_get_iod_with_format(ld, i); dpld->iod[IPC_RAW] = link_get_iod_with_format(ld, IPC_MULTI_RAW); if (dpld->iod[IPC_RAW]->recv_skb) dpld->use_skb = true; for (i = 0; i < dpld->max_ipc_dev; i++) { spin_lock_init(&dpld->tx_lock[i]); atomic_set(&dpld->res_required[i], 0); skb_queue_purge(&dpld->skb_rxq[i]); } /* Enable IPC */ atomic_set(&dpld->accessing, 0); set_magic(dpld, DPRAM_MAGIC_CODE); set_access(dpld, 1); if (get_magic(dpld) != DPRAM_MAGIC_CODE || get_access(dpld) != 1) return -EACCES; ld->mode = LINK_MODE_IPC; if (wake_lock_active(&dpld->wlock)) wake_unlock(&dpld->wlock); return 0; }
static void usb_change_modem_state(struct usb_link_device *usb_ld, enum modem_state state) { struct io_device *iod; iod = link_get_iod_with_format(&usb_ld->ld, IPC_FMT); if (iod) iod->modem_state_changed(iod, state); }
static void set_modem_state(struct mem_link_device *mld, enum modem_state state) { struct link_device *ld = &mld->link_dev; struct io_device *iod; /* Change the modem state to STATE_CRASH_EXIT for the FMT IO device */ iod = link_get_iod_with_format(ld, IPC_FMT); if (iod) iod->modem_state_changed(iod, state); /* time margin for taking state changes by rild */ mdelay(100); /* Change the modem state to STATE_CRASH_EXIT for the BOOT IO device */ iod = link_get_iod_with_format(ld, IPC_BOOT); if (iod) iod->modem_state_changed(iod, state); }
static void cmd_crash_reset_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod = NULL; ld->mode = LINK_MODE_ULOAD; if (!wake_lock_active(&dpld->wlock)) wake_lock(&dpld->wlock); mif_info("%s: Recv 0xC7 (CRASH_RESET)\n", ld->name); iod = link_get_iod_with_format(ld, IPC_FMT); iod->modem_state_changed(iod, STATE_CRASH_RESET); iod = link_get_iod_with_format(ld, IPC_BOOT); iod->modem_state_changed(iod, STATE_CRASH_RESET); }
static void s5p_idpram_try_resume(struct work_struct *work) { struct idpram_pm_data *pm_data; struct dpram_link_device *dpld; struct link_device *ld; unsigned long delay; u16 cmd; mif_info("+++\n"); pm_data = container_of(work, struct idpram_pm_data, resume_dwork.work); dpld = container_of(pm_data, struct dpram_link_device, pm_data); ld = &dpld->ld; if (pm_data->last_msg == INT_CMD(INT_CMD_IDPRAM_RESUME_REQ)) { pm_data->last_msg = 0; s5p_idpram_set_pm_lock(dpld, 0); wake_unlock(&pm_data->hold_wlock); delay = msecs_to_jiffies(10); schedule_delayed_work(&pm_data->tx_dwork, delay); mif_info("%s resumed\n", ld->name); goto exit; } if (pm_data->resume_try_cnt++ < MAX_RESUME_TRY_CNT) { mif_info("%s not resumed yet\n", ld->name); cmd = INT_CMD(INT_CMD_IDPRAM_RESUME_REQ); mif_info("send IDPRAM_RESUME_REQ (0x%X)\n", cmd); dpld->send_intr(dpld, cmd); delay = msecs_to_jiffies(200); schedule_delayed_work(&pm_data->resume_dwork, delay); } else { struct io_device *iod; mif_err("ERR! %s resume T-I-M-E-O-U-T\n", ld->name); iod = link_get_iod_with_format(ld, IPC_FMT); if (iod) iod->modem_state_changed(iod, STATE_CRASH_EXIT); wake_unlock(&pm_data->hold_wlock); /* hold wakelock until uevnet sent to rild */ wake_lock_timeout(&pm_data->hold_wlock, HZ*7); s5p_idpram_set_pm_lock(dpld, 0); } exit: mif_info("---\n"); }
static void qsc6085_error_display_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod; mif_err("recv 0xC9 (CRASH_EXIT)\n"); mif_err("CP Crash: %s\n", dpld->get_rxq_buff(dpld, IPC_FMT)); iod = link_get_iod_with_format(ld, IPC_FMT); if (iod) iod->modem_state_changed(iod, STATE_CRASH_EXIT); }
static void dpram_trigger_crash(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod; int i; for (i = 0; i < dpld->max_ipc_dev; i++) { mif_info("%s: purging %s_skb_txq\b", ld->name, get_dev_name(i)); skb_queue_purge(ld->skb_txq[i]); } iod = link_get_iod_with_format(ld, IPC_FMT); iod->modem_state_changed(iod, STATE_CRASH_EXIT); iod = link_get_iod_with_format(ld, IPC_BOOT); iod->modem_state_changed(iod, STATE_CRASH_EXIT); iod = link_get_iod_with_channel(ld, PS_DATA_CH_0); if (iod) iodevs_for_each(iod->msd, iodev_netif_stop, 0); }
static void dpram_ipc_rx_task(unsigned long data) { struct dpram_link_device *dpld = (struct dpram_link_device *)data; struct link_device *ld = &dpld->ld; struct io_device *iod; struct dpram_rxb *rxb; unsigned qlen; int i; for (i = 0; i < dpld->max_ipc_dev; i++) { if (i == IPC_RAW) iod = link_get_iod_with_format(ld, IPC_MULTI_RAW); else iod = link_get_iod_with_format(ld, i); qlen = rxbq_size(&dpld->rxbq[i]); while (qlen > 0) { rxb = rxbq_get_data_rxb(&dpld->rxbq[i]); iod->recv(iod, ld, rxb->data, rxb->len); rxb_clear(rxb); qlen--; } } }
static int qsc6085_dump_update(struct dpram_link_device *dpld, unsigned long arg) { int ret; struct link_device *ld = &dpld->ld; struct io_device *iod = link_get_iod_with_format(ld, IPC_RAMDUMP); struct memif_uload_map *ul_map = &dpld->ul_map; struct cp_ramdump_status *dump_stat = &ld->msd->dump_stat; char *buff = dpld->buff; struct qsc6085_dump_command dump_cmd; while (iod->sk_rx_q.qlen > 0) usleep_range(1000, 1100); memset(&dump_cmd, 0, sizeof(dump_cmd)); dump_cmd.addr = dump_stat->addr; dump_cmd.size = min(dump_stat->rest, ul_map->space); dump_cmd.copyto_offset = 0x38000010; memcpy_toio(ul_map->cmd, &dump_cmd, ul_map->cmd_size); dpld->send_intr(dpld, CMD_CP_RAMDUMP_SEND_REQ); ret = wait_for_completion_interruptible_timeout(&dpld->crash_cmpl, RAMDUMP_CMD_TIMEOUT); if (!ret) { dump_stat->dump_size = 0; mif_err("ERR! no response to CP_RAMDUMP_SEND_REQ\n"); ret = -EIO; goto exit; } memcpy_fromio(buff, ul_map->buff, dump_cmd.size); ret = iod->recv(iod, ld, buff, dump_cmd.size); if (ret < 0) goto exit; dump_stat->addr += dump_cmd.size; dump_stat->rcvd += dump_cmd.size; dump_stat->rest -= dump_cmd.size; mif_info("rest = %u bytes\n", dump_stat->rest); ret = dump_cmd.size; exit: return ret; }
static void qsc6085_start_handler(struct dpram_link_device *dpld) { struct link_device *ld = &dpld->ld; struct io_device *iod; mif_info("recv 0xC8 (CP_START)\n"); mif_info("send 0xC1 (INIT_START)\n"); dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_START)); dpld->reset_dpram_ipc(dpld); iod = link_get_iod_with_format(ld, IPC_FMT); if (!iod) { mif_err("ERR! no iod\n"); return; } iod->modem_state_changed(iod, STATE_ONLINE); mif_info("send 0xC2 (INIT_END)\n"); dpld->send_intr(dpld, INT_CMD(INT_CMD_INIT_END)); }
static void usb_rx_complete(struct urb *urb) { struct if_usb_devdata *pipe_data = urb->context; struct usb_link_device *usb_ld = usb_get_intfdata(pipe_data->data_intf); struct io_device *iod; int iod_format = IPC_FMT; int ret; usb_mark_last_busy(urb->dev); switch (urb->status) { case 0: case -ENOENT: if (!urb->actual_length) goto re_submit; /* call iod recv */ /* how we can distinguish boot ch with fmt ch ?? */ switch (pipe_data->format) { case IF_USB_FMT_EP: iod_format = IPC_FMT; pr_buffer("rx", (char *)urb->transfer_buffer, (size_t)urb->actual_length, 16); break; case IF_USB_RAW_EP: iod_format = IPC_MULTI_RAW; break; case IF_USB_RFS_EP: iod_format = IPC_RFS; break; default: break; } /* during boot stage fmt end point */ /* shared with boot io device */ /* when we use fmt device only, at boot and ipc exchange it can be reduced to 1 device */ if (iod_format == IPC_FMT && usb_ld->ld.com_state == COM_BOOT) iod_format = IPC_BOOT; if (iod_format == IPC_FMT && usb_ld->ld.com_state == COM_CRASH) iod_format = IPC_RAMDUMP; iod = link_get_iod_with_format(&usb_ld->ld, iod_format); if (iod) { ret = iod->recv(iod, &usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret < 0) mif_err("io device recv error :%d\n", ret); } re_submit: if (urb->status || atomic_read(&usb_ld->suspend_count)) break; usb_mark_last_busy(urb->dev); usb_rx_submit(pipe_data, urb, GFP_ATOMIC); return; case -ESHUTDOWN: case -EPROTO: break; case -EOVERFLOW: mif_err("RX overflow\n"); break; default: mif_err("RX complete Status (%d)\n", urb->status); break; } usb_anchor_urb(urb, &pipe_data->urbs); }
static void usb_rx_complete(struct urb *urb) { struct if_usb_devdata *pipe_data = urb->context; struct usb_link_device *usb_ld = pipe_data->usb_ld; struct io_device *iod; int iod_format; int ret; if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); switch (urb->status) { case -ENOENT: /* case for 'link pm suspended but rx data had remained' */ mif_debug("urb->status = -ENOENT\n"); case 0: if (!urb->actual_length) { mif_debug("urb has zero length!\n"); goto rx_submit; } usb_ld->link_pm_data->rx_cnt++; /* call iod recv */ /* how we can distinguish boot ch with fmt ch ?? */ switch (pipe_data->format) { case IF_USB_FMT_EP: if (usb_ld->if_usb_is_main) { //pr_urb("IPC-RX", urb); iod_format = IPC_FMT; } else { iod_format = IPC_BOOT; } break; case IF_USB_RAW_EP: iod_format = IPC_MULTI_RAW; break; case IF_USB_RFS_EP: iod_format = IPC_RFS; break; case IF_USB_CMD_EP: iod_format = IPC_CMD; break; default: iod_format = -1; break; } /* flow control CMD by CP, not use io device */ if (unlikely(iod_format == IPC_CMD)) { ret = link_rx_flowctl_cmd(&usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret < 0) mif_err("no multi raw device (%d)\n", ret); goto rx_submit; } iod = link_get_iod_with_format(&usb_ld->ld, iod_format); if (iod) { ret = iod->recv(iod, &usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret == -ENOMEM) { /* retry the delay work and resubit*/ mif_err("ENOMEM, retry\n"); if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_ld->retry_urb = urb; queue_delayed_work(usb_ld->ld.tx_wq, &usb_ld->rx_retry_work, 0); return; } if (ret < 0) mif_err("io device recv error (%d)\n", ret); } rx_submit: if (urb->status == 0) { if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_rx_submit(usb_ld, pipe_data, GFP_ATOMIC); } break; default: mif_err("urb err status = %d\n", urb->status); break; } }
static void usb_rx_retry_work(struct work_struct *work) { int ret = 0; struct usb_link_device *usb_ld = container_of(work, struct usb_link_device, rx_retry_work.work); struct urb *urb = usb_ld->retry_urb; struct if_usb_devdata *pipe_data = urb->context; struct io_device *iod; int iod_format; if (!usb_ld->if_usb_connected || !usb_ld->usbdev) return; if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); switch (pipe_data->format) { case IF_USB_FMT_EP: if (usb_ld->if_usb_is_main) { pr_urb("IPC-RX, retry", urb); iod_format = IPC_FMT; } else { iod_format = IPC_BOOT; } break; case IF_USB_RAW_EP: iod_format = IPC_MULTI_RAW; break; case IF_USB_RFS_EP: iod_format = IPC_RFS; pr_urb("RFS-RX, retry", urb); break; case IF_USB_CMD_EP: iod_format = IPC_CMD; break; default: iod_format = -1; break; } iod = link_get_iod_with_format(&usb_ld->ld, iod_format); if (iod) { ret = iod->recv(iod, &usb_ld->ld, (char *)urb->transfer_buffer, urb->actual_length); if (ret == -ENOMEM) { /* TODO: check the retry count */ /* retry the delay work after 20ms and resubit*/ mif_err("ENOMEM, +retry 20ms\n"); if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_ld->retry_urb = urb; if (usb_ld->rx_retry_cnt++ < 10) queue_delayed_work(usb_ld->ld.tx_wq, &usb_ld->rx_retry_work, 10); return; } if (ret < 0) mif_err("io device recv error (%d)\n", ret); usb_ld->rx_retry_cnt = 0; } if (usb_ld->usbdev) usb_mark_last_busy(usb_ld->usbdev); usb_rx_submit(usb_ld, pipe_data, GFP_ATOMIC); }