#include "sv6621s_mem_map.h" #include "skw_log_to_file.h" struct memory_segment { const char *name; uint32_t address; uint32_t size; }; struct memory_segment cp_mem_seg[] = { { "CODE", CODE_MEM_BASE_ADDR, CODE_MEM_SIZE}, { "DATA", DATA_MEM_BASE_ADDR, DATA_MEM_SIZE}, { "AHBR", AHB_REG_BASE_ADDR, AHB_REG_SIZE}, { "PPBM", UMEM_MEM_BASE_ADDR, UMEM_MEM_SIZE}, { "SMEM", SMEM_MEM_BASE_ADDR, SMEM_MEM_SIZE}, { "WFRF", 0x40140000, 0x4000}, { "CSCB", 0xE000E000, 0x1000}, { "WREG", WREG_MEM_BASE_ADDR, WREG_MEM_SIZE}, { "PHYR", PHYR_MEM_BASE_ADDR, PHYR_MEM_SIZE}, { "SDIO", SDIO_MEM_BASE_ADDR, SDIO_MEM_SIZE}, { "BTRG", BTDM_MEM_BASE_ADDR, BTDM_MEM_SIZE}, { "BTEM", BTEM_MEM_BASE_ADDR, BTEM_MEM_SIZE}, { "BTGB", BTGB_MEM_BASE_ADDR, BTGB_MEM_SIZE}, { "BTRF", BTRF_MEM_BASE_ADDR, BTRF_MEM_SIZE}, { "RFTOP", RFTOP_MEM_BASE_ADDR, RFTOP_MEM_SIZE}, { "RCLK", RCLK_MEM_BASE_ADDR, RCLK_MEM_SIZE}, { "BBPLL", BBPLL_MEM_BASE_ADDR, BBPLL_MEM_SIZE} }; static uint32_t skw_checksum(void *data, int data_len) { uint32_t *d32 = data; uint32_t checksum=0; int i; data_len = data_len >> 2; for (i=0; ipdata || !ucom->pdata->skw_dump_mem) return 0; sg_count = sizeof(cp_mem_seg)/sizeof(cp_mem_seg[0]); if (sg_count==0) return 0; packet_len = 0x800; read_buf = kmalloc(packet_len, GFP_KERNEL); if (read_buf==NULL) return 0; buffer[offset] = sg_count; //save total segment count offset++; do { uint32_t source_addr; sg_size = mem_sg->size; memcpy(&buffer[offset], mem_sg->name, 5); //save segment name offset += 5; memcpy(&buffer[offset], &mem_sg->address, 4); //save segment base addrss offset += 4; memcpy(&buffer[offset], &mem_sg->size, 4); //save segment size offset += 4; memcpy(&buffer[offset], &packet_len, 2); //save segment size offset += 2; skwlog_log("%s %s:%d 0x%x 0x%x\n", __func__, mem_sg->name, offset, mem_sg->address, mem_sg->size); seq = 0; source_addr = mem_sg->address; do { int read_len; uint32_t sum; memcpy(&buffer[offset], &seq, 2); //save segment size seq++; offset += 2; if (sg_size > packet_len) read_len = packet_len; else read_len = sg_size; ret = ucom->pdata->skw_dump_mem(source_addr,(void *)read_buf,read_len); if (ret != 0) { skwlog_err("%s dump memory fail :%d \n", __func__, ret); break; } source_addr += read_len; memcpy(buffer+offset, read_buf, read_len); //save packet payload offset += read_len; sum = skw_checksum(read_buf, read_len); memcpy (buffer+offset, &sum, 4); //save checksum offset += 4; sg_size -= read_len; } while (sg_size); mem_sg++; sg_count--; } while (sg_count && (!ret)); kfree(read_buf); return offset; } static int skw_ucom_dump_from_buffer(char __user *buf, size_t count, loff_t *pos) { int len; int ret; len = 0; ret = 0; if (dump_log_size) { if (*pos + count < dump_log_size) len = count; else if (*pos < dump_log_size) len = dump_log_size - *pos; if (len) ret = copy_to_user(buf, &dump_memory_buffer[*pos], len); if (ret ==0) ret = len; } else if (*pos == 0){ char assert_info[32]={0}; sprintf(assert_info,"modem_status=%d\n", cp_exception_sts); ret = copy_to_user(buf, assert_info, strlen(assert_info)); len = strlen(assert_info); } *pos = *pos+len; if (len==0) skwboot_log("dump_log_size: %d offset %d count %d %p ret=%d\n", dump_log_size, (int)*pos, (int)count, dump_memory_buffer, ret); return ret; } static int user_dump_open(struct inode *ip, struct file *fp) { if (dump_buffer_size) return 0; return 0; } static ssize_t user_dump_read(struct file *fp, char __user *buf, size_t count, loff_t *pos) { ssize_t ret = skw_ucom_dump_from_buffer(buf, count, pos); if (ret == 0) dump_log_size = 0; return ret; } static int user_dump_release(struct inode *ip, struct file *fp) { return 0; } static ssize_t user_dump_write(struct file *fp, const char __user *buf, size_t count, loff_t *pos) { return 0; } static long user_dump_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) { return 0; } static const struct file_operations skw_dump_ops = { .owner = THIS_MODULE, .open = user_dump_open, .read = user_dump_read, .write = user_dump_write, .unlocked_ioctl = user_dump_ioctl, .release= user_dump_release, }; static int bt_state_event_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct ucom_dev *ucom = container_of(nb, struct ucom_dev, notifier); //int status = cp_exception_sts; switch(action) { case DEVICE_ASSERT_EVENT: { skwboot_log("BT BSPASSERT EVENT received!!!!\n"); cp_exception_sts = 1; ucom = ucoms[log_portno]; if (dump_log_size){ skwboot_log(" dump done ,mem size: %d\n", dump_log_size); return NOTIFY_OK; } if (!dump_memory_buffer && !atomic_read(&ucom->open) && SKW_DUMP_BUFFER_SIZE!=0) dump_memory_buffer = kzalloc(SKW_DUMP_BUFFER_SIZE, GFP_KERNEL); if(ucom->pdata && ucom->pdata->dump_modem_memory) { dump_log_size = 0; if (dump_memory_buffer) { dump_buffer_size = SKW_DUMP_BUFFER_SIZE; ucom->pdata->dump_modem_memory(dump_memory_buffer, dump_buffer_size, &dump_log_size); } } else if (dump_memory_buffer) { dump_buffer_size = SKW_DUMP_BUFFER_SIZE; if (!atomic_read(&ucom->open)) dump_log_size = skw_dump_memory_into_buffer(ucom, dump_memory_buffer,dump_buffer_size); } } break; case DEVICE_BSPREADY_EVENT: { cp_exception_sts = 0; skwboot_log("BT BSPREADY EVENT Comming in !!!!\n"); } break; case DEVICE_DUMPDONE_EVENT: { cp_exception_sts = 2; skwboot_log("BT DUMPDONE EVENT Comming in !!!!\n"); } break; case DEVICE_BLOCKED_EVENT: { cp_exception_sts = 3; skwboot_log("BT BLOCKED EVENT Comming in !!!!\n"); if (dump_log_size){ skwboot_log(" dump done ,mem size: %d\n", dump_log_size); return NOTIFY_OK; } if (!dump_memory_buffer) dump_memory_buffer = kzalloc(SKW_DUMP_BUFFER_SIZE, GFP_KERNEL); if (dump_memory_buffer) { dump_buffer_size = SKW_DUMP_BUFFER_SIZE; dump_log_size = skw_dump_memory_into_buffer(ucom, dump_memory_buffer,dump_buffer_size); } } break; case DEVICE_DISCONNECT_EVENT: { cp_exception_sts = action; } break; default: break; } return NOTIFY_OK; } static int skw_bt_state_event_init(struct ucom_dev *ucom) { int ret = 0; int devno; if (ucom->pdata->modem_register_notify && ucom->notifier.notifier_call == NULL) { ucom->notifier.notifier_call = bt_state_event_notifier; ucom->pdata->modem_register_notify(&ucom->notifier); } ret =__register_chrdev(skw_major, UCOM_PORTNO_MAX+1, 1, "SKWDUMP", &skw_dump_ops); devno = MKDEV(skw_major, UCOM_PORTNO_MAX+1); if (ret==0) device_create(skw_com_class, NULL, devno, NULL, "%s", "SKWDUMP"); skwlog_log("%s enter ret=%d\n",__func__, ret); return ret; } static int skw_bt_state_event_deinit(struct ucom_dev *ucom) { int ret = 0; int devno; if(ucom) { if((ucom->notifier.notifier_call)){ skwboot_log("%s :%d release the notifier \n", __func__,__LINE__); ucom->notifier.notifier_call = NULL; ucom->pdata->modem_unregister_notify(&ucom->notifier); } devno = MKDEV(skw_major, UCOM_PORTNO_MAX+1); __unregister_chrdev(skw_major, MINOR(devno), 1, "SKWDUMP"); device_destroy(skw_com_class, devno); } return ret; }