static int handle_rpc_call(struct msm_rpc_server *server, struct rpc_request_hdr *req, unsigned len) { struct timespec ts, tv; //20110813 [email protected] add period int64_t period = 0; switch (req->procedure) { case RPC_TIME_REMOTE_MTOA_NULL: return 0; case RPC_TIME_TOD_SET_APPS_BASES: { struct rpc_time_tod_set_apps_bases_args *args; args = (struct rpc_time_tod_set_apps_bases_args *)(req + 1); args->tick = be32_to_cpu(args->tick); args->stamp = be64_to_cpu(args->stamp); printk(KERN_INFO "RPC_TIME_TOD_SET_APPS_BASES:\n" "\ttick = %d\n" "\tstamp = %lld\n", args->tick, args->stamp); getnstimeofday(&ts); if (msmrtc_is_suspended()) { //20110813 [email protected] add period [START] int64_t now, sleep, tick_at_suspend; // LGE_UPDATE_S //now = msm_timer_get_sclk_time(NULL); now = msm_timer_get_sclk_time(&period); // LGE_UPDATE_E tick_at_suspend = msmrtc_get_tickatsuspend(); if (now && tick_at_suspend) { sleep = now - tick_at_suspend; // LGE_UPDATE_S if(sleep<0) sleep+=period; // LGE_UPDATE_E timespec_add_ns(&ts, sleep); } else pr_err("%s: Invalid ticks from SCLK" "now=%lld tick_at_suspend=%lld", __func__, now, tick_at_suspend); //20110813 [email protected] add period [END] } rtc_hctosys(); getnstimeofday(&tv); /* Update the alarm information with the new time info. */ alarm_update_timedelta(ts, tv); return 0; } case RPC_TIME_GET_APPS_USER_TIME: return read_rtc0_time(server, req, len); default: return -ENODEV; } }
/** * read_persistent_clock - Return time from a persistent clock. * * Reads the time from a source which isn't disabled during PM, the * 32k sync timer. Convert the cycles elapsed since last read into * nsecs and adds to a monotonically increasing timespec. */ void read_persistent_clock(struct timespec *ts) { struct omap_32k_sync_device *omap = thecs; unsigned long long nsecs; cycles_t delta; struct timespec *tsp; if (!omap) { ts->tv_sec = 0; ts->tv_nsec = 0; return; } tsp = &omap->persistent_ts; omap->last_cycles = omap->cycles; omap->cycles = omap->cs.read(&omap->cs); delta = omap->cycles - omap->last_cycles; nsecs = clocksource_cyc2ns(delta, omap->cs.mult, omap->cs.shift); timespec_add_ns(tsp, nsecs); *ts = *tsp; }
/** * Blocking read from a cbuf * * This function is compatible to the glip_read_b() function and can be used in * backend implementations using a cbuf for storing incoming data. * * @param[in] buf the buffer to read from * @param[in] size how much data is supposed to be read * @param[out] data the read data * @param[out] size_read how much data has been read * @param[in] timeout the maximum duration the read operation can take * * @return 0 if reading was successful * @return -ETIMEDOUT if the read timeout was hit * @return -ECANCELED if the blocking operation was cancelled * @return any other value indicates failure * * @see glip_read_b() */ int gb_util_cbuf_read_b(struct cbuf *buf, size_t size, uint8_t *data, size_t *size_read, unsigned int timeout) { int rv; int retval = 0; struct timespec ts; *size_read = 0; if (size > cbuf_size(buf)) { /* * This is not a problem for non-blocking reads, but blocking reads will * block forever in this case as the maximum amount of data ever * available is limited by the buffer size. * @todo: This can be solved by loop-reading until timeout */ return -1; } /* * Wait until sufficient data is available to be read. */ if (timeout != 0) { clock_gettime(CLOCK_REALTIME, &ts); timespec_add_ns(&ts, timeout * 1000 * 1000); } size_t level = cbuf_fill_level(buf); while (level < size) { if (timeout == 0) { rv = cbuf_wait_for_level_change(buf, level); } else { rv = cbuf_timedwait_for_level_change(buf, level, &ts); } retval = rv; if (rv == -ETIMEDOUT) { goto read_ret; } else if (rv != 0) { goto ret; } level = cbuf_fill_level(buf); } /* * We read whatever data is available, and assume a timeout if the available * amount of data does not match the requested amount. */ read_ret: rv = gb_util_cbuf_read(buf, size, data, size_read); if (rv == 0 && size != *size_read) { retval = -ETIMEDOUT; } ret: return retval; }
static void process_cb_request(void *buffer) { struct rtc_cb_recv *rtc_cb = buffer; struct timespec ts, tv; rtc_cb->client_cb_id = be32_to_cpu(rtc_cb->client_cb_id); rtc_cb->event = be32_to_cpu(rtc_cb->event); rtc_cb->cb_info_ptr = be32_to_cpu(rtc_cb->cb_info_ptr); if (rtc_cb->event == EVENT_TOD_CHANGE) { /* A TOD update has been received from the Modem */ rtc_cb->cb_info_data.tod_update.tick = be32_to_cpu(rtc_cb->cb_info_data.tod_update.tick); rtc_cb->cb_info_data.tod_update.stamp = be64_to_cpu(rtc_cb->cb_info_data.tod_update.stamp); rtc_cb->cb_info_data.tod_update.freq = be32_to_cpu(rtc_cb->cb_info_data.tod_update.freq); pr_info("RPC CALL -- TOD TIME UPDATE: ttick = %d\n" "stamp=%lld, freq = %d\n", rtc_cb->cb_info_data.tod_update.tick, rtc_cb->cb_info_data.tod_update.stamp, rtc_cb->cb_info_data.tod_update.freq); getnstimeofday(&ts); if (atomic_read(&suspend_state.state)) { int64_t now, sleep, sclk_max; now = msm_timer_get_sclk_time(&sclk_max); if (now && suspend_state.tick_at_suspend) { if (now < suspend_state.tick_at_suspend) { sleep = sclk_max - suspend_state.tick_at_suspend + now; } else { sleep = now - suspend_state.tick_at_suspend; } timespec_add_ns(&ts, sleep); suspend_state.tick_at_suspend = now; } else pr_err("%s: Invalid ticks from SCLK" "now=%lld tick_at_suspend=%lld", __func__, now, suspend_state.tick_at_suspend); } rtc_hctosys(); getnstimeofday(&tv); /* Update the alarm information with the new time info. */ alarm_update_timedelta(ts, tv); } else pr_err("%s: Unknown event EVENT=%x\n", __func__, rtc_cb->event); }
/* * tegra_read_persistent_clock - Return time from a persistent clock. * * Reads the time from a source which isn't disabled during PM, the * 32k sync timer. Convert the cycles elapsed since last read into * nsecs and adds to a monotonically increasing timespec. * Care must be taken that this funciton is not called while the * tegra_rtc driver could be executing to avoid race conditions * on the RTC shadow register */ static void tegra_read_persistent_clock(struct timespec *ts) { u64 delta; struct timespec *tsp = &persistent_ts; last_persistent_ms = persistent_ms; persistent_ms = tegra_rtc_read_ms(); delta = persistent_ms - last_persistent_ms; timespec_add_ns(tsp, delta * NSEC_PER_MSEC); *ts = *tsp; }
static void sprd_read_persistent_clock(struct timespec *ts) { u64 delta; struct timespec *tsp = &persistent_ts; last_persistent_ms = persistent_ms; persistent_ms = get_sys_cnt(); delta = persistent_ms - last_persistent_ms; timespec_add_ns(tsp, delta * NSEC_PER_MSEC); *ts = *tsp; }
void read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; cycles_t delta; struct timespec *tsp = &persistent_ts; last_cycles = cycles; cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; delta = cycles - last_cycles; nsecs = clocksource_cyc2ns(delta, persistent_mult, persistent_shift); timespec_add_ns(tsp, nsecs); *ts = *tsp; }
void msmrtc_updateatsuspend(struct timespec *ts) { int64_t now, sleep; if (atomic_read(&suspend_state.state)) { now = msm_timer_get_sclk_time(NULL); if (now && suspend_state.tick_at_suspend) { sleep = now - suspend_state.tick_at_suspend; timespec_add_ns(ts, sleep); } else pr_err("%s: Invalid ticks from SCLK now=%lld" "tick_at_suspend=%lld", __func__, now, suspend_state.tick_at_suspend); } }
void read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; cycles_t delta; struct timespec *tsp = &persistent_ts; last_cycles = cycles; cycles = clocksource_32k.read(&clocksource_32k); delta = cycles - last_cycles; nsecs = clocksource_cyc2ns(delta, clocksource_32k.mult, clocksource_32k.shift); timespec_add_ns(tsp, nsecs); *ts = *tsp; }
/* * read_persistent_clock - Return time from a persistent clock. * * Reads the time from a source which isn't disabled during PM, the * 32k sync timer. Convert the cycles elapsed since last read into * nsecs and adds to a monotonically increasing timespec. * Care must be taken that this funciton is not called while the * tegra_rtc driver could be executing to avoid race conditions * on the RTC shadow register */ void read_persistent_clock(struct timespec *ts) { u64 delta; struct timespec *tsp = &persistent_ts; unsigned long flags; spin_lock_irqsave(&read_persistent_clock_lock, flags); last_persistent_ms = persistent_ms; persistent_ms = tegra_rtc_read_ms(); delta = persistent_ms - last_persistent_ms; timespec_add_ns(tsp, delta * NSEC_PER_MSEC); *ts = *tsp; spin_unlock_irqrestore(&read_persistent_clock_lock, flags); }
void read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; cycles_t last_cycles; unsigned long flags; spin_lock_irqsave(&read_persistent_clock_lock, flags); last_cycles = cycles; cycles = timer_32k_base ? __raw_readl(timer_32k_base) : 0; nsecs = clocksource_cyc2ns(cycles - last_cycles, persistent_mult, persistent_shift); timespec_add_ns(&persistent_ts, nsecs); *ts = persistent_ts; spin_unlock_irqrestore(&read_persistent_clock_lock, flags); }
void read_persistent_clock(struct timespec *ts) { unsigned long long nsecs; cycles_t delta; struct timespec *tsp = &persistent_ts; last_cycles = cycles; cycles = clocksource_32k.read(&clocksource_32k); delta = cycles - last_cycles; if (unlikely(cycles < last_cycles)) { pr_warning("%s: WRAP\n", __func__); delta = last_cycles - cycles; } nsecs = clocksource_cyc2ns(delta, clocksource_32k.mult, clocksource_32k.shift); timespec_add_ns(tsp, nsecs); *ts = *tsp; }
/** * Blocking write to a cbuf * * This function is compatible to the glip_write_b() function and can be used in * backend implementations using a cbuf for storing outgoing data. * * @param[in] buf the buffer to read from * @param[in] size how much data is supposed to be written * @param[in] data that is supposed to be written * @param[out] size_written how much data has been written * @param[in] timeout the maximum duration the write operation can take * * @return 0 if all data has been written * @return -ETIMEDOUT if the write timeout was hit * @return -ECANCELED if the blocking operation was cancelled * @return any other value indicates failure * * @see glip_write_b() */ int gb_util_cbuf_write_b(struct cbuf *buf, size_t size, uint8_t *data, size_t *size_written, unsigned int timeout) { struct timespec ts; int retval; int rv; if (timeout != 0) { clock_gettime(CLOCK_REALTIME, &ts); timespec_add_ns(&ts, timeout * 1000 * 1000); } size_t size_done = 0; while (1) { size_t size_done_tmp = 0; gb_util_cbuf_write(buf, size - size_done, &data[size_done], &size_done_tmp); size_done += size_done_tmp; if (size_done == size) { retval = 0; goto ret; } if (cbuf_free_level(buf) == 0) { if (timeout == 0) { rv = cbuf_wait_for_level_change(buf, 0); } else { rv = cbuf_timedwait_for_level_change(buf, 0, &ts); } if (rv != 0) { retval = rv; goto ret; } } } ret: *size_written = size_done; return retval; }
void *uei_hwmon_loop(void *m_arg) { struct timespec next; uint64_t periodns = NSEC_PER_SEC; int ret; uint32_t diag_channels[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}; ph_thread_set_name("UEI_HW"); blast_startup("Starting UEI HWMon loop"); clock_gettime(CLOCK_MONOTONIC, &next); while (!shutdown_mcp) { ret = DqAdvDnxpRead(hd_of, CPU_LAYER, sizeof(diag_channels) / sizeof(uint32_t), diag_channels, raw_diag_data, diag_data); if (ret < 0) { blast_err("Could not read CPU Diagnostics: %s", DqTranslateError(ret)); } timespec_add_ns(&next, periodns); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); } return NULL; }
void *uei_508_loop(void *m_arg) { struct timespec next; uint64_t periodns = ((double)(NSEC_PER_SEC) / 10); int ret; int channel_list_508[8] = {0, 1, 2, 3, 4, 5, 6, 7}; uint32_t channel_cfg_508[8] = { CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600), CFG_485(DQ_SL501_BAUD_9600) }; int channel_flags_508[8] = { 0 }; ph_library_init(); ph_thread_set_name("UEI508"); blast_startup("Starting UEI 508 loop"); // set channel configuration for (int i = 0; i < 8; i++) { if ((ret = DqAdv501SetChannelCfg(hd_508, 4, i, channel_cfg_508[i])) < 0) { blast_err("Error in DqAdv501SetChannelCfg()"); } } ret = DqRtVmapAddChannel(hd_508, vmapid_508, 4, DQ_SS0IN, channel_list_508, channel_flags_508, 8); ret = DqRtVmapAddChannel(hd_508, vmapid_508, 4, DQ_SS0OUT, channel_list_508, channel_flags_508, 8); ret = DqRtVmapStart(hd_508, vmapid_508); clock_gettime(CLOCK_MONOTONIC, &next); while (!shutdown_mcp) { for (int i = 0; i < 8; i++) { size_t num_bytes; ph_buf_t *outbuf = NULL; if ((num_bytes = ph_bufq_len(SL508_write_buffer[i]))) { outbuf = ph_bufq_consume_bytes(SL508_write_buffer[i], num_bytes); DqRtVmapWriteOutput(hd_508, vmapid_508, 4, i, num_bytes, ph_buf_mem(outbuf)); ph_buf_delref(outbuf); } DqRtVmapRequestInput(hd_508, vmapid_508, 4, i, 128); } // Write output data to each TX port FIFO and Read each RX port FIFO ret = DqRtVmapRefresh(hd_508, vmapid_508, 0); // Read data received during the last refresh for (int i = 0; i < 8; i++) { uint8_t read_buffer[128]; int read_len; DqRtVmapReadInput(hd_508, vmapid_508, 4, i, sizeof(read_buffer), &read_len, read_buffer); if (read_len > 0) { ph_bufq_append(SL508_read_buffer[i], read_buffer, read_len, NULL); } } timespec_add_ns(&next, periodns); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); } DqRtVmapStop(hd_508, vmapid_508); DqRtVmapClose(hd_508, vmapid_508); return NULL; }
static void event_loop(struct server_state* ss) { msg(1, "Starting event loop\n"); struct timespec tx_ts, rx_ts, next_tx_ts, lost_tx_ts = { 0, 0 }; ss->have_sent = ss->have_tx_ts = ss->have_rx_ts = false; int rc, rx_left = ss->rx_msg_size; unsigned send_i = 0; clock_gettime(CLOCK_REALTIME, &next_tx_ts); timespec_add_ns(&next_tx_ts, ss->inter_tx_gap_ns); while( 1 ) { struct epoll_event e; TRY( rc = epoll_wait(ss->epoll, &e, 1, 0) ); if( rc == 0 ) { struct timespec now; clock_gettime(CLOCK_REALTIME, &now); if( ! timespec_le(next_tx_ts, now) ) continue; timespec_add_ns(&next_tx_ts, ss->inter_tx_gap_ns); if( ++send_i >= cfg_measure_nth && ! ss->have_sent ) { msg(3, "Send message (timed)\n"); TEST( send(ss->udp_sock_ts, ss->tx_buf_ts, ss->tx_msg_size, 0) == ss->tx_msg_size ); if( ! cfg_hw_ts ) { ss->have_tx_ts = true; tx_ts = now; } send_i = 0; ss->have_sent = true; } else { msg(3, "Send message\n"); TEST( send(ss->udp_sock, ss->tx_buf, ss->tx_msg_size, 0) == ss->tx_msg_size ); if( send_i >= cfg_measure_nth ) { /* Not had a reply to last timed message. Try to detect lost * messages. */ if( send_i == cfg_measure_nth ) { lost_tx_ts = now; } else if( ss->have_tx_ts && timespec_diff_ns(now, lost_tx_ts) > 10000000 ) { msg(2, "WARNING: No response to timed message\n"); if( ss->rtt_n > 0 ) ++(ss->n_lost_msgs); ss->have_sent = false; ss->have_tx_ts = false; ss->have_rx_ts = false; } } } } else if( e.data.fd == ss->tcp_sock ) { TEST( e.events & EPOLLIN ); if( cfg_hw_ts ) { rc = recv_ts(ss->tcp_sock, ss->rx_buf, rx_left, MSG_DONTWAIT, &rx_ts); } else { rc = recv(ss->tcp_sock, ss->rx_buf, rx_left, MSG_DONTWAIT); clock_gettime(CLOCK_REALTIME, &rx_ts); } if( rc > 0 ) { msg(3, "Received %d from client at %d.%09d\n", rc, (int) rx_ts.tv_sec, (int) rx_ts.tv_nsec); if( (rx_left -= rc) == 0 ) { send(ss->tcp_sock, ss->rx_buf, 1, MSG_NOSIGNAL); rx_left = ss->rx_msg_size; ss->have_rx_ts = true; if( ss->have_tx_ts ) measured_rtt(ss, tx_ts, rx_ts); } } else if( rc == 0 || errno == ECONNRESET ) { break; } else if( errno == ETIME ) { fprintf(stderr, "ERROR: Did not get H/W timestamp on RX\n"); exit(3); } else { TRY( rc ); } } else if( e.data.fd == ss->udp_sock_ts ) { assert( cfg_hw_ts ); assert( ! ss->have_tx_ts ); TEST( recv_ts(ss->udp_sock_ts, ss->rx_buf, 1, MSG_ERRQUEUE | MSG_DONTWAIT, &tx_ts) == 1 ); msg(3, "TX timestamp %d.%09d\n", (int) tx_ts.tv_sec, (int) tx_ts.tv_nsec); ss->have_tx_ts = true; if( ss->have_rx_ts ) measured_rtt(ss, tx_ts, rx_ts); } } msg(1, "Client disconnected\n"); TRY( close(ss->tcp_sock) ); }
static void mm_fmwk_job_scheduler(struct work_struct *work) { mm_job_status_e status = MM_JOB_STATUS_INVALID; bool is_hw_busy = false; struct dev_job_list *job_list_elem; struct mm_core *core_dev = container_of(work, \ struct mm_core, \ job_scheduler); MM_CORE_HW_IFC *hw_ifc = &core_dev->mm_device; if (plist_head_empty(&core_dev->job_list)) return; job_list_elem = plist_first_entry(\ &(core_dev->job_list), \ struct dev_job_list, core_list); if (mm_core_enable_clock(core_dev)) goto mm_fmwk_job_scheduler_done; is_hw_busy = hw_ifc->mm_get_status(hw_ifc->mm_device_id); if (!is_hw_busy) { if (job_list_elem->job.size) { if (job_list_elem->job.status == MM_JOB_STATUS_READY) clean_cnt++; if (job_list_elem->job.status == MM_JOB_STATUS_DIRTY) { mm_common_cache_clean(); dirty_cnt++; if ((dirty_cnt % 1000) == 0) pr_debug("mm jobs dirty=%d, clean=%d\n", dirty_cnt, clean_cnt); } status = hw_ifc->mm_start_job(\ hw_ifc->mm_device_id, \ &job_list_elem->job, 0); if (status < MM_JOB_STATUS_SUCCESS) { getnstimeofday(&core_dev->sched_time); timespec_add_ns(\ &core_dev->sched_time, \ hw_ifc->mm_timeout * NSEC_PER_MSEC); core_dev->mm_core_idle = false; is_hw_busy = true; pr_debug("job posted "); raw_notifier_call_chain(\ &core_dev->mm_common->notifier_head, \ MM_FMWK_NOTIFY_JOB_STARTED, NULL); } else { core_dev->mm_core_idle = true; job_list_elem->job.status \ = MM_JOB_STATUS_SUCCESS; mm_common_job_completion(\ job_list_elem, core_dev); SCHEDULER_WORK(core_dev, \ &core_dev->job_scheduler); } } else { job_list_elem->job.status \ = MM_JOB_STATUS_SUCCESS; mm_common_job_completion(\ job_list_elem, core_dev); SCHEDULER_WORK(core_dev, \ &core_dev->job_scheduler); } } else { struct timespec cur_time; getnstimeofday(&cur_time); if (timespec_compare(&cur_time, &core_dev->sched_time) > 0) { pr_err("abort hw "); hw_ifc->mm_abort(hw_ifc->mm_device_id, \ &job_list_elem->job); core_dev->mm_core_idle = true; is_hw_busy = false; SCHEDULER_WORK(core_dev, &core_dev->job_scheduler); } } if (is_hw_busy) { mod_timer(&core_dev->dev_timer, \ jiffies + msecs_to_jiffies(hw_ifc->mm_timer)); pr_debug("mod_timer %lx %lx", \ jiffies, \ msecs_to_jiffies(hw_ifc->mm_timer)); return; } mm_fmwk_job_scheduler_done: mm_core_disable_clock(core_dev); }
void *uei_dmap_update_loop(void *m_arg) { int ret; uint32_t chentry; struct timespec next; uint64_t periodns = ((double)(NSEC_PER_SEC) / frequency); ph_thread_set_name("OF_DMP"); blast_startup("Starting UEI OF DMap loop"); /** * Add all channels except those read out through the diagnostic interface */ for (channel_t *ch = channel_list; ch->field[0]; ch++) { /** * Only select out frame UEI channels and ignore any listing board numbers * larger than number of slots available on UEI */ if ((ch->source != SRC_OF_UEI) || ch->board > 5) continue; if (ch->board == 2) { chentry = ch->chan | DQ_LNCL_GAIN(0) | DQ_LNCL_DIFF; } else { chentry = ch->chan | DQ_LNCL_GAIN(0); } uei_of_channels[ch->board][num_of_channels[ch->board]++] = ch; DqRtDmapAddChannel(hd_dmap, dmapid, ch->board, DQ_SS0IN, &chentry, 1); } /** * Add the Digital output channel to the DMAP. WARNING! This is hard-coded * and will need to be changed if the physical order of the UEI boards * change! */ DqRtDmapAddChannel(hd_dmap, dmapid, 3, DQ_SS0OUT, 0, 0); // Start the layers DqRtDmapStart(hd_dmap, dmapid); clock_gettime(CLOCK_MONOTONIC, &next); while (!shutdown_mcp) { DqRtDmapWriteRawData32(hd_dmap, dmapid, 3, &(CommandData.uei_command.uei_of_dio_432_out), 1); ret = DqRtDmapRefresh(hd_dmap, dmapid); if (ret < 0) { blast_err("DqRtDmapRefresh: error %d", ret); } for (int i = 0; i < 6; i++) { if (num_of_channels[i]) { if ((ret = DqRtDmapReadScaledData(hd_dmap, dmapid, i, raw_dmap_input[i], num_of_channels[i])) < 0) { blast_err("Could not read scaled data from DMAP"); continue; } } } timespec_add_ns(&next, periodns); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); } DqRtDmapStop(hd_dmap, dmapid); DqRtDmapClose(hd_dmap, dmapid); DqCloseIOM(hd_dmap); return NULL; }
static void process_cb_request(void *buffer) { struct rtc_cb_recv *rtc_cb = buffer; struct timespec ts, tv; rtc_cb->client_cb_id = be32_to_cpu(rtc_cb->client_cb_id); rtc_cb->event = be32_to_cpu(rtc_cb->event); rtc_cb->cb_info_ptr = be32_to_cpu(rtc_cb->cb_info_ptr); if (rtc_cb->event == EVENT_TOD_CHANGE) { /* A TOD update has been received from the Modem */ rtc_cb->cb_info_data.tod_update.tick = be32_to_cpu(rtc_cb->cb_info_data.tod_update.tick); rtc_cb->cb_info_data.tod_update.stamp = be64_to_cpu(rtc_cb->cb_info_data.tod_update.stamp); rtc_cb->cb_info_data.tod_update.freq = be32_to_cpu(rtc_cb->cb_info_data.tod_update.freq); pr_info("RPC CALL -- TOD TIME UPDATE: ttick = %d\n" "stamp=%lld, freq = %d\n", rtc_cb->cb_info_data.tod_update.tick, rtc_cb->cb_info_data.tod_update.stamp, rtc_cb->cb_info_data.tod_update.freq); getnstimeofday(&ts); /* CR 291540 - Function/Feature Failure (Partial) * system uptime gets corrupted with overflow in slow clock. * * Problem description * During power collapse, APPS sleep time is calculated using slow clock * ticks. The calculation of sleep time does not considers slow clock * overflow and thus If slow clock overflows during suspend state then we * get wrong sleep time and thus system uptime values gets corrupted. * earlier sleep time was calculates as follows: * sleep = current_sclk_tick - suspend_state_sclk_tick * * Failure frequency: Occasionally * Scenario frequency: Uncommon * Change description * Modified the sleep time calculation to include slow clock overflow as follows: * Now sleep time is calculated as: * sleep = Maximum_sclk_tick_val - suspend_state_sclk_tick + current_sclk_tick. * Files affected * kernel/drivers/rtc/rtc-msm.c * kernel/arch/arm/mach-msm/rpc_server_time_remote.c */ if (atomic_read(&suspend_state.state)) { #if 1 //QCT SBA 404016 int64_t now, sleep, sclk_max; now = msm_timer_get_sclk_time(&sclk_max); #else int64_t now, sleep; now = msm_timer_get_sclk_time(NULL); #endif if (now && suspend_state.tick_at_suspend) { #if 1 //QCT SBA 404016 if (now < suspend_state.tick_at_suspend) { sleep = sclk_max - suspend_state.tick_at_suspend + now; } else { sleep = now - suspend_state.tick_at_suspend; } #else sleep = now - suspend_state.tick_at_suspend; #endif timespec_add_ns(&ts, sleep); /* CR 293735 - Function/Feature Failure (Partial) * When system was in suspend, could make invalid "elapsed system time" at AP side. * * Problem description * When system is in suspend mode and if more than one network time update * comes while system is in suspend mode then the uptime gets corrupted. * * Failure frequency: Occasionally * Scenario frequency: Uncommon * Change description * Added change to modify tick_at_suspend (variable that stores time tick * while entering suspend) after each update to the current time tick. * Setting the suspend mode variable in case alarm time expires the current * RTC time as in thic case also system enters suspend mode. * to sdcc irq handlers returning IRQ_NONE without handling the interrupt. * When interrupt is disabled the communication between the SDIO client and * SDCC host controller is stopped while a pending command is in progress * and hence WLAN operation is stuck forever and LOGP recovery cannot be * processed. * Files affected * arch/arm/mach-msm/rpc_server_time_remote.c * drivers/rtc/rtc-msm.c * include/linux/rtc-msm.h */ #if 1 //QCT SBA 404017 suspend_state.tick_at_suspend = now; #endif } else pr_err("%s: Invalid ticks from SCLK" "now=%lld tick_at_suspend=%lld", __func__, now, suspend_state.tick_at_suspend); } rtc_hctosys(); getnstimeofday(&tv); /* Update the alarm information with the new time info. */ alarm_update_timedelta(ts, tv); } else pr_err("%s: Unknown event EVENT=%x\n", __func__, rtc_cb->event); }
int main(int argc, char* argv[]) { int i, count = 0; int ret; uint32_t status; int dmapid; uint32_t last_pps = UINT32_MAX; struct timeval tv1; struct timespec next; long long periodns; uint32_t input32[64]; uint32_t evt_chan = CT650_EVENT_CH0; EV650_CFG event; double input_buffer[64]; size_t num_channels[15] = { 0 }; uint32 chentry; FILE *gps_fp; FILE *analog_fp; FILE *pps_fp; FILE *status_fp; pthread_t async_t; pthread_t gps_t; time_t last_secs = 0; gps_fp = fopen("/mnt/data/gps.dat", "a"); analog_fp = fopen("/mnt/data/analog.dat", "a"); pps_fp = fopen("/mnt/data/pps.dat", "a"); status_fp = fopen("/mnt/data/layer_status.dat", "a"); signal(SIGINT, sighandler); ret = DqInitDAQLib(); if (ret < 0) { printf("Error %d in DqInitDAQLib\n", ret); return ret; } ret = DqOpenIOM("127.0.0.1", DQ_UDP_DAQ_PORT, 1000, &hd, &DQRdCfg); if (ret < 0) { printf("Error %d in DqOpenIOM\n", ret); return ret; } for (i = 0; i < 7; i++) { uint32_t devn; ret = DqGetDevnBySerial(hd, layers[i].serial, &devn, NULL, NULL, NULL); if (ret < 0) { printf("Error %d getting device number\n", ret); goto finish_up; } layers[i].devn = (int)devn; if (DQRdCfg->devmod[layers[i].devn]) { printf("Model: %x Option: %x Dev: %d SN: %u\n", DQRdCfg->devmod[layers[i].devn], DQRdCfg->option[layers[i].devn],layers[i].devn, layers[i].serial); } } /** * Set the initial watchdog timer to 25 seconds. This should be enough time * for us to get into the main routine */ // DqCmdSetWatchDog(hd, DQ_WD_CLEAR_ON_OSTASK, 25000, NULL, NULL); pthread_create(&async_t, NULL, async_thread, NULL); pthread_detach(async_t); pthread_create(&gps_t, NULL, read_GPS_serial_line, NULL); pthread_detach(gps_t); /** * Allow handling of GPS data by the 650 internal interrupts */ ret = DqAdv650EnableGPSTracking(hd, IRIG650_SLOT, true, &status); if (ret < 0) { printf("Error %d in DqAdv650EnableGPSTracking\n", ret); } else { // while (!(status & CT650_GPS_ACC_GPSFIXV)) { // uint32_t status2 =0; // printf("Got GPS Status 0x%X, 0x%X\n", status, status2); // sleep(1); // ret = DqAdv650GetGPSStatus(hd, IRIG650_SLOT, 0, &status, &status2, NULL, NULL); // } } /** * Get the PPS source from the GPS module * Set the flags to automatically continue if source is lost */ uint32 timekeeper_mode, timekeeper_flags; EV650_CFG event_cfg; timekeeper_mode = CT650_TKPPS_GPS; timekeeper_flags = CT650_TKFLG_AUTOFOLLOW | CT650_TKFLG_USENOMINAL; ret = DqAdv650ConfigTimekeeper(hd, IRIG650_SLOT, timekeeper_mode, timekeeper_flags); if (ret < 0) { printf("Error %d in DqAdv650ConfigTimekeeper\n", ret); } /** * Configure the IRIG PPS Clock event */ // memset(&event_cfg, 0, sizeof(event_cfg)); // event_cfg.event_cfg = CT650_EVT_CFG_EN|CT650_EVT_CFG_EV1IRQ|CT650_EVT_CFG_EV0IRQ| // CT650_EVT_CFG_RPT| // CT650_EVT_CFG_EDGE| // CT650_EVT_PPS; // // ret = DqAdv650SetEvents(hd, IRIG650_SLOT, CT650_EVENT_CH0, UINT32_MAX, &event_cfg, NULL); // if (ret < 0) { // printf("Error %d in DqAdv650ConfigEvents (PPS CLK): Errno: %d\n", ret, errno); // } /** * Single buffer mode * TTL0 outputs the GPS PPS * TTL1 outputs the IRIG PPS */ ret = DqAdv650AssignTTLOutputs(hd, IRIG650_SLOT, CT650_OUT_TTLEN1|CT650_OUT_TTLEN0, // mode = enable both TTL drivers/buffers for sharper edges 0, // when 0, use external TTL0..3 to debug CT650_OUT_CFG_SRC_1GPS, // pulse(s) from event2 when it happens (used for trigger) CT650_OUT_CFG_SRC_1PPS, CT650_OUT_CFG_EVENT0, // pulse(s) from event1 (used for timestamp) CT650_OUT_CFG_SRC_1PPS); // DqAdv650AssignTTLOutputs(hd, IRIG650_SLOT, CT650_OUT_TTLEN0, 0, // CT650_OUT_CFG_SRC_1GPS, CT650_OUT_CFG_SRC_1PPS, CT650_OUT_CFG_SRC_0, CT650_OUT_CFG_SRC_0); if (ret < 0) { printf("Error %d in DqAdv650AssignTTLOutputs\n", ret); } // Configure PLL and event module to output 100kHz timetamp clock to event.event_cfg = CT650_EVT_CFG_EN // Enable |CT650_EVT_CFG_RPT // 1 - repeat |CT650_EVT_CFG_EVTPL(0xd) // pulse length 0xD ns |00 << 18 // Internal counter source selector: 00 - 66/100MHz |(CT650_EVT_PPS<<12) // IRSRC = 20<<12 = 1PPS |CT650_EVT_CFG_EDGE // 1 - rising edge, 0 - falling edge |CT650_EVT_CFG_ESRC_DPLL // Event sources and internal counter reset source (ESRC) |0; #define TS_CLOCKRATE 100000 // timestamp rate used to program IRIG-650 PLL event.event_prm = TS_CLOCKRATE; // TS clock frequenecy event.event_sub0_dly = 0; event.event_sub1_dly = 0; event.event_val = 0; DqAdv650SetEvents(hd, IRIG650_SLOT, evt_chan, 0, &event, NULL); /** * Enable the IRIG-650 card */ ret = DqAdv650Enable(hd, IRIG650_SLOT, true); if (ret < 0) { printf("Error %d in DqAdv650Enable\n", ret); } // Use posix timer to tick at the desired frequency periodns = (long long) floor(1000000000.0 / frequency); DqRtDmapInit(hd, &dmapid, 2 * frequency); /** * Add the AI-201, using the first channel as a timestamp */ chentry = DQ_LNCL_TIMESTAMP; DqRtDmapAddChannel(hd, dmapid, AI201_SLOT, DQ_SS0IN, &chentry, 1); num_channels[AI201_SLOT]++; for (i = 0; i < 24; i++) { chentry = i | DQ_AI201_GAIN_1; DqRtDmapAddChannel(hd, dmapid, AI201_SLOT, DQ_SS0IN, &chentry, 1); num_channels[AI201_SLOT]++; } /** * Add the DIO-448. First two channels are for Digital Input but the * remaining channels are single-ended analog */ uint32_t aiCl[DQ_DIO448_LINES]; for (i=0; i<DQ_DIO448_LINES; i++) { aiCl[i] = i; } // Configure hysteresis on all 48 input lines DqAdv448SetLevels(hd, DI448_SLOT, DQ_DIO448_LINES, aiCl, 1.0, 3.0); // Set debouncer time interval for all channels // interval is set in 100usecs increment DqAdv448SetDebouncer(hd, DI448_SLOT, DQ_DIO448_LINES, aiCl, 10); chentry = DQ_LNCL_TIMESTAMP; DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DI448_SLOT]++; // Get the first de-bounced channel chentry = 2; DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DI448_SLOT]++; // Get the second de-bounced channel chentry = 3; DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DI448_SLOT]++; chentry = DQL_CHAN448_STATUS; DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DI448_SLOT]++; for (i = DQL_CHAN448_CHSE(0); i < DQL_CHAN448_CHSE(48); i++) { chentry = i; DqRtDmapAddChannel(hd, dmapid, DI448_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DI448_SLOT]++; } /** * Add the DO-432 analog input channels (single ended) */ chentry = DQ_LNCL_TIMESTAMP; DqRtDmapAddChannel(hd, dmapid, DO432_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DO432_SLOT]++; for (i = 32; i < 64; i++) { chentry = i; DqRtDmapAddChannel(hd, dmapid, DO432_SLOT, DQ_SS0IN, &chentry, 1); num_channels[DO432_SLOT]++; } /** * Add the AI-225 analog input channels (single ended) */ chentry = DQ_LNCL_TIMESTAMP; DqRtDmapAddChannel(hd, dmapid, AI225_SLOT, DQ_SS0IN, &chentry, 1); num_channels[AI225_SLOT]++; for (i = 0; i < 25; i++) { chentry = i; DqRtDmapAddChannel(hd, dmapid, AI225_SLOT, DQ_SS0IN, &chentry, 1); num_channels[AI225_SLOT]++; } // Start the layers DqRtDmapStart(hd, dmapid); gettimeofday(&tv1, NULL); clock_gettime(CLOCK_MONOTONIC, &next); fprintf(gps_fp, "%ld.%ld:\tRestart GPS Stream\n", (long) next.tv_sec, (long) next.tv_nsec); fprintf(analog_fp, "%ld.%ld:\tRestart Analog Stream\n", (long) next.tv_sec, (long) next.tv_nsec); printf("Starting loop\n"); while (!stop) { DqRtDmapRefresh(hd, dmapid); DqRtDmapReadRawData32(hd, dmapid, DI448_SLOT, input32, num_channels[DI448_SLOT]); // printf("0x%0.8X, 0x%0.8X, 0x%0.8X, 0x%0.8X\n", input32[0], input32[1], input32[2], input32[3]); if ((input32[1] & 0x7) != last_pps) { last_pps = input32[1] & 0x7; fprintf(pps_fp, "%ld.%ld, 0x%02X\n", (long) next.tv_sec, (long) next.tv_nsec, last_pps); } /** * Reset the watchdog timer for 10 seconds */ //DqCmdSetWatchDog(hd, DQ_WD_CLEAR_ON_OSTASK, 10000, NULL, NULL); // read inputs retrieved by the last refresh once every 10 seconds if ((last_secs != next.tv_sec) && ((next.tv_sec % 10) == 0)) { last_secs = next.tv_sec; for (i = 0; i < 15; i++) { if (num_channels[i] <= 0) continue; DqRtDmapReadScaledData(hd, dmapid, i, input_buffer, num_channels[i]); fprintf(analog_fp, "Board %x, %ld.%ld, ", DQRdCfg->devmod[i], (long) next.tv_sec, (long) next.tv_nsec); for (int j = 0; j < num_channels[i]; j++) { fprintf(analog_fp, "%0.8f, ", input_buffer[j]); } fprintf(analog_fp, "\n"); } { uint32_t diag_channels[13] = { 0, 1, 2, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15 }; uint32_t bdata[13]; ret = DqAdvDnxpRead(hd, BASE_SLOT, 13, diag_channels, bdata, input_buffer); if (ret < 0) { printf("Error %d in DqAdvDnxpRead\n", ret); } fprintf(analog_fp, "Diag Layer, %ld.%ld, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f, %0.8f\n", (long) next.tv_sec, (long) next.tv_nsec, input_buffer[0], input_buffer[1], input_buffer[2], input_buffer[3], input_buffer[4], input_buffer[5], input_buffer[6], input_buffer[7], input_buffer[8], input_buffer[9], input_buffer[10], input_buffer[11], input_buffer[12]); } read_GPS_IRIG(gps_fp); get_status(status_fp); } count++; timespec_add_ns(&next, periodns); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); } /** * Turn off the watchdog timer now that we have called the exit */ // DqCmdSetWatchDog(hd, DQ_WD_CLEAR_DISABLED, 0, NULL, NULL); DqRtDmapStop(hd, dmapid); DqRtDmapClose(hd, dmapid); finish_up: DqCloseIOM(hd); DqCleanUpDAQLib(); fclose(gps_fp); fclose(status_fp); fclose(analog_fp); fclose(pps_fp); return 0; }
void* read_GPS_serial_line(void *arg) { int ret = DQ_SUCCESS; sigset_t set; char buffer[DQ_MAX_UDP_PAYLOAD_100]; uint8_t term[2] = {0x0D, 0x0A}; FILE *fp; char *filename = "/mnt/data/gps_serial.dat"; struct timeval tv1; struct timespec next; long long periodns = 10LL * NSECS_PER_SEC; sigemptyset(&set); sigaddset(&set, SIGINT); pthread_sigmask(SIG_BLOCK, &set, NULL); fp = fopen(filename, "a"); // Set channel configuration if ((ret = DqAdv501SetChannelCfg(hd, SL508_SLOT, 0, DQCFG_501(DQ_SL501_OPER_NORM, DQ_SL501_MODE_232, DQ_SL501_BAUD_4800, DQ_SL501_WIDTH_8, DQ_SL501_STOP_1, DQ_SL501_PARITY_NONE))) < 0) { printf("error %d in DqAdv501SetChannelCfg()\n", ret); } // Specifies how long the SL-50x waits for the requested amount of bytes to be // received before only returning the bytes received so far if ((ret = DqAdv501SetTimeout(hd, SL508_SLOT, 0, 10000)) < 0) { printf("error %d in DqAdv501SetTimeout\n", ret); } // Specifies the maximum of bytes to keep in the FIFO before returning them to // the user if ((ret = DqAdv501SetTermLength(hd, SL508_SLOT, 0, 1)) < 0) { printf("error %d in DqAdv501SetTermLength\n", ret); } if ((ret = DqAdv501SetTermString(hd, SL508_SLOT, 0, 2, term)) < 0) { printf("error %d in DqAdv501SetTermString\n", ret); } if ((ret = DqAdv501Enable(hd, SL508_SLOT, TRUE)) < 0) { printf("Error %d in DqAdv501Enable()\n", ret); } gettimeofday(&tv1, NULL); clock_gettime(CLOCK_MONOTONIC, &next); while(!stop) { uint16_t buffer_length = DQ_MAX_UDP_PAYLOAD_100; uint16_t received = 0; int success; int has_more = 1; uint8_t error_code; uint8_t *bufp = (uint8_t*)buffer; while (received < MINMEA_MAX_LENGTH + 3) { buffer_length = DQ_MAX_UDP_PAYLOAD_100 - received; ret = DqAdv501RecvMessage(hd, SL508_SLOT, 0, bufp, &buffer_length, &success, &error_code, &has_more); received += buffer_length; /** * Check to ensure our line starts with a valid character for the GPS read */ if (buffer[0] != '$') received = 0; bufp = (uint8_t*)buffer + received; if(ret < 0) { printf("Error %d receiving from serial port\n", ret); break; } if ((received > 4) && (*(bufp - 1) == 0x0A) && (*(bufp - 2) == 0x0D)) break; } *bufp = '\0'; if (success) decode_NMEA(buffer, fp); if (!has_more) { timespec_add_ns(&next, periodns); clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &next, NULL); } } fclose(fp); return NULL; }