diff options
author | Robin Peng <robinpeng@google.com> | 2022-01-03 20:37:41 +0800 |
---|---|---|
committer | Robin Peng <robinpeng@google.com> | 2022-01-03 20:37:41 +0800 |
commit | d474bf434118bad9b1a50443f83903855e957cf9 (patch) | |
tree | b6260b143585757cd228299cb528615702efc40a | |
parent | 37ee17be9f111fdfec7ac7b78dcad3f443bdd3f5 (diff) | |
parent | 5fed2939baec67591b027360fe409fea7335fe20 (diff) | |
download | uwb-android-gs-raviole-5.10-t-preview-2.tar.gz |
Merge android12-gs-pixel-5.10-sc-v2 into android13-gs-pixel-5.10android-t-preview-2_r0.4android-t-preview-1_r0.4android-gs-raviole-5.10-t-preview-2android-gs-raviole-5.10-t-preview-1
Bug: 211546634
Signed-off-by: Robin Peng <robinpeng@google.com>
Change-Id: If50ae8cb59800e03bc11ab41ca01c90db3b9cc63
23 files changed, 844 insertions, 353 deletions
diff --git a/kernel/drivers/net/ieee802154/dw3000.h b/kernel/drivers/net/ieee802154/dw3000.h index e29ab03..97bd33f 100644 --- a/kernel/drivers/net/ieee802154/dw3000.h +++ b/kernel/drivers/net/ieee802154/dw3000.h @@ -100,6 +100,22 @@ struct dw3000_isr_data { DW3000_CHIP_PER_DTU) /** + * typedef dw3000_wakeup_done_cb - Wake up done handler. + * @dw: Driver context. + * + * Return: 0 on success, else an error. + */ +typedef int (*dw3000_wakeup_done_cb)(struct dw3000 *dw); + +/** + * typedef dw3000_idle_timeout_cb - Idle timeout handler. + * @dw: Driver context. + * + * Return: 0 on success, else an error. + */ +typedef int (*dw3000_idle_timeout_cb)(struct dw3000 *dw); + +/** * struct dw3000_otp_data - data read from OTP memory of DW3000 device * @partID: device part ID * @lotID: device lot ID @@ -469,9 +485,12 @@ struct dw3000_rctu_conv { * @sys_time_sync: device SYS_TIME immediately after wakeup * @sleep_enter_dtu: DTU when entered sleep * @deep_sleep_state: state related to the deep sleep - * @deep_sleep_timer: timer to wake up the chip after deep sleep - * @timer_expired_work: work to call timer expired callback - * @call_timer_expired: should mcps802154_timer_expired be called? + * @idle_timeout: true when idle_timeout_dtu is a valid date. + * @idle_timeout_dtu: timestamp requested to leave idle mode. + * @idle_timer: timer to exiting after an idle call. + * @timer_expired_work: call mcps802154_timer_expired outside driver kthread. + * @wakeup_done_cb: callback called on wakeup done. + * @idle_timeout_cb: callback when idle timer expired * @auto_sleep_margin_us: configurable automatic deep sleep margin * @need_ranging_clock: true if next operation need ranging clock * and deep sleep cannot be used @@ -552,9 +571,12 @@ struct dw3000 { u32 sleep_enter_dtu; /* Deep Sleep & MCPS Idle management */ struct dw3000_deep_sleep_state deep_sleep_state; - struct hrtimer deep_sleep_timer; + bool idle_timeout; + u32 idle_timeout_dtu; + struct hrtimer idle_timer; struct work_struct timer_expired_work; - bool call_timer_expired; + dw3000_wakeup_done_cb wakeup_done_cb; + dw3000_idle_timeout_cb idle_timeout_cb; bool need_ranging_clock; int auto_sleep_margin_us; /* NFCC coexistence specific context. */ diff --git a/kernel/drivers/net/ieee802154/dw3000_core.c b/kernel/drivers/net/ieee802154/dw3000_core.c index f840c02..1710562 100644 --- a/kernel/drivers/net/ieee802154/dw3000_core.c +++ b/kernel/drivers/net/ieee802154/dw3000_core.c @@ -366,6 +366,8 @@ static const struct dw3000_ciadiag_reg_info _ciadiag_reg_info[] = { }, }; +static int dw3000_wakeup_done_to_tx(struct dw3000 *dw); +static int dw3000_wakeup_done_to_rx(struct dw3000 *dw); /* sysfs variables handling */ static ssize_t dw3000_sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf); @@ -1971,7 +1973,7 @@ static int dw3000_wakeup(struct dw3000 *dw) int rc; /* Avoid race condition with dw3000_poweroff while chip is stopped just - when dw3000_wakeup_timer() HR timer callback is executed. Do nothing + when dw3000_idle_timeout() HR timer callback is executed. Do nothing if not in DEEP-SLEEP state. */ if (dw->current_operational_state != DW3000_OP_STATE_DEEP_SLEEP) return 0; @@ -2002,27 +2004,55 @@ static int do_wakeup(struct dw3000 *dw, const void *in, void *out) return dw3000_wakeup(dw); } -static void dw3000_timer_expired(struct work_struct *work) +int dw3000_deepsleep_wakeup_now(struct dw3000 *dw, + dw3000_idle_timeout_cb idle_timeout_cb, + enum operational_state next_operational_state) { - struct dw3000 *dw = - container_of(work, struct dw3000, timer_expired_work); - /* Entered DEEP SLEEP from mcps802154_ops.idle() */ - mcps802154_timer_expired(dw->llhw); + struct dw3000_deep_sleep_state *dss = &dw->deep_sleep_state; + int r; + + r = dw3000_wakeup(dw); + if (r) + return r; + + dss->next_operational_state = next_operational_state; + dw->idle_timeout_cb = idle_timeout_cb; + return 0; } /** - * dw3000_wakeup_timer() - wake-up timer handler - * @timer: the deep_sleep_timer field in struct dw3000 + * dw3000_handle_idle_timeout() - Idle expired handler + * @dw: the DW device. + * @in: ignored input. + * @out: ignored output. * - * Return: 0 on success, else a negative error code. + * Return: 0 on success, -errno otherwise. */ -enum hrtimer_restart dw3000_wakeup_timer(struct hrtimer *timer) +static int dw3000_handle_idle_timeout(struct dw3000 *dw, const void *in, + void *out) { - struct dw3000 *dw = - container_of(timer, struct dw3000, deep_sleep_timer); - if (dw->nfcc_coex.enabled || - (dw->deep_sleep_state.next_operational_state > - DW3000_OP_STATE_IDLE_PLL)) { + dw3000_idle_timeout_cb idle_timeout_cb = dw->idle_timeout_cb; + + /* Consume/remove registered handler before call it.*/ + dw->idle_timeout_cb = NULL; + /* Call handler registered. */ + if (idle_timeout_cb) + return idle_timeout_cb(dw); + return 0; +} + +/** + * dw3000_deepsleep_wakeup() - Handle wake-up. + * @dw: the DW device. + * + * Return: True when the wakeup is started, false otherwise. + */ +bool dw3000_deepsleep_wakeup(struct dw3000 *dw) +{ + trace_dw3000_deepsleep_wakeup(dw); + if (dw->current_operational_state == DW3000_OP_STATE_DEEP_SLEEP && + dw->deep_sleep_state.next_operational_state > + DW3000_OP_STATE_IDLE_PLL) { struct dw3000_stm_command cmd = { do_wakeup, NULL, NULL }; /* The chip is about to wake up, let's request the best QoS latency early */ @@ -2030,21 +2060,42 @@ enum hrtimer_restart dw3000_wakeup_timer(struct hrtimer *timer) /* Must wakeup to execute stored operation, so run the wake up function in state machine thread. */ dw3000_enqueue_timer(dw, &cmd); - } else if (dw->call_timer_expired) { - /* Timer launched by idle(), just inform MCPS timer has expired */ - schedule_work(&dw->timer_expired_work); + return true; + } + return false; +} + +/** + * dw3000_idle_timeout() - idle timeout handler + * @timer: the idle_timer field in struct dw3000 + * + * Return: always timer not restarted. + */ +enum hrtimer_restart dw3000_idle_timeout(struct hrtimer *timer) +{ + struct dw3000 *dw = container_of(timer, struct dw3000, idle_timer); + bool wakeup_started; + + trace_dw3000_idle_timeout(dw); + wakeup_started = dw3000_deepsleep_wakeup(dw); + if (!wakeup_started && dw->idle_timeout_cb) { + struct dw3000_stm_command cmd = { dw3000_handle_idle_timeout, + NULL, NULL }; + dw3000_enqueue_timer(dw, &cmd); } - hrtimer_try_to_cancel(timer); return HRTIMER_NORESTART; } /** - * dw3000_wakeup_cancel() - Cancel wake-up timer + * dw3000_idle_cancel_timer() - Cancel idle timer. * @dw: the DW device */ -void dw3000_wakeup_cancel(struct dw3000 *dw) +static void dw3000_idle_cancel_timer(struct dw3000 *dw) { - hrtimer_try_to_cancel(&dw->deep_sleep_timer); + trace_dw3000_idle_cancel_timer(dw); + hrtimer_try_to_cancel(&dw->idle_timer); + /* Ensure wakeup ISR don't call the mcps802154_timer_expired() */ + dw->idle_timeout_cb = NULL; } /** @@ -2056,15 +2107,16 @@ void dw3000_wakeup_cancel(struct dw3000 *dw) */ void dw3000_wakeup_and_wait(struct dw3000 *dw) { + trace_dw3000_wakeup_and_wait(dw, dw->current_operational_state); if (dw->current_operational_state >= DW3000_OP_STATE_IDLE_PLL) return; /* Ensure wakeup ISR don't call the mcps802154_timer_expired() since this will result in dead lock! */ - dw->call_timer_expired = false; + dw3000_idle_cancel_timer(dw); /* Ensure force call to dw3000_wakeup() is made. */ dw->deep_sleep_state.next_operational_state = DW3000_OP_STATE_MAX; /* Now wakeup device, and stop timer if running */ - dw3000_wakeup_timer(&dw->deep_sleep_timer); + dw3000_deepsleep_wakeup(dw); dw->deep_sleep_state.next_operational_state = DW3000_OP_STATE_IDLE_PLL; /* And wait for good state */ if (current != dw->stm.mthread) @@ -2121,7 +2173,9 @@ int dw3000_check_operational_state(struct dw3000 *dw, int delay_dtu, } /* The chip is about to wake up, request the best QoS latency */ dw3000_pm_qos_update_request(dw, dw3000_qos_latency); - /* Wakeup now since delay isn't enough. */ + /* Cancel wakeup timer launch by idle() */ + dw3000_idle_cancel_timer(dw); + /* Wakeup now since delay isn't enough */ rc = dw3000_wakeup(dw); if (unlikely(rc)) return rc; @@ -2145,6 +2199,8 @@ int dw3000_check_operational_state(struct dw3000 *dw, int delay_dtu, /* Failure to enter deep sleep, continue without it */ break; } + /* Cancel wakeup timer launch by idle() */ + dw3000_idle_cancel_timer(dw); return 0; } @@ -2329,6 +2385,8 @@ int dw3000_do_rx_enable(struct dw3000 *dw, return rc; /* Save parameters to activate RX delayed when wakeup later */ + + dw->wakeup_done_cb = dw3000_wakeup_done_to_rx; dss->next_operational_state = DW3000_OP_STATE_RX; dss->rx_info = *info; dss->frame_idx = frame_idx; @@ -3111,6 +3169,7 @@ int dw3000_do_tx_frame(struct dw3000 *dw, return rc; /* Save parameters to activate TX delayed when wakeup later */ + dw->wakeup_done_cb = dw3000_wakeup_done_to_tx; dss->next_operational_state = DW3000_OP_STATE_TX; dss->tx_info = *info; dss->tx_skb = skb; @@ -4128,9 +4187,8 @@ static int dw3000_backup_registers(struct dw3000 *dw, bool after) */ void dw3000_wakeup_timer_start(struct dw3000 *dw, int delay_us) { - hrtimer_start(&dw->deep_sleep_timer, ns_to_ktime(delay_us * 1000ull), + hrtimer_start(&dw->idle_timer, ns_to_ktime(delay_us * 1000ull), HRTIMER_MODE_REL); - dw->call_timer_expired = true; trace_dw3000_wakeup_timer_start(dw, delay_us); } @@ -4167,6 +4225,153 @@ int dw3000_deep_sleep_and_wakeup(struct dw3000 *dw, int delay_us) } /** + * dw3000_wakeup_done_to_tx() - Wakeup done, continue to program TX. + * @dw: Driver context. + * + * Return: 0 on success, else an error. + */ +static int dw3000_wakeup_done_to_tx(struct dw3000 *dw) +{ + struct dw3000_deep_sleep_state *dss = &dw->deep_sleep_state; + + trace_dw3000_wakeup_done_to_tx(dw); + dss->next_operational_state = dw->current_operational_state; + return dw3000_do_tx_frame(dw, &dss->tx_info, dss->tx_skb, + dss->frame_idx); +} + +/** + * dw3000_wakeup_done_to_rx() - Wakeup done, continue to program RX. + * @dw: Driver context. + * + * Return: 0 on success, else an error. + */ +static int dw3000_wakeup_done_to_rx(struct dw3000 *dw) +{ + struct dw3000_deep_sleep_state *dss = &dw->deep_sleep_state; + + trace_dw3000_wakeup_done_to_rx(dw); + dss->next_operational_state = dw->current_operational_state; + return dw3000_do_rx_enable(dw, &dss->rx_info, dss->frame_idx); +} + +/** + * dw3000_wakeup_done_to_idle() - Wakeup done, continue on idle timeout. + * @dw: Driver context. + * + * Return: 0 on success, else an error. + */ +static int dw3000_wakeup_done_to_idle(struct dw3000 *dw) +{ + struct dw3000_stm_command cmd = { dw3000_handle_idle_timeout, NULL, + NULL }; + + trace_dw3000_wakeup_done_to_idle(dw); + if (dw->idle_timeout) { + u32 now_dtu = dw3000_get_dtu_time(dw); + int idle_duration_us = + DTU_TO_US(dw->idle_timeout_dtu - now_dtu); + + /* TODO: + * 2 timers implemented (idle, deep_sleep), + * or a better FSM (enter, leave, events, state) + * should help to follow/repect timestamps expected. */ + dw3000_wakeup_timer_start(dw, idle_duration_us); + return 0; + } + return dw3000_enqueue_generic(dw, &cmd); +} + +/** + * dw3000_idle() - Go into idle. + * @dw: Driver context. + * @timestamp: Idle duration have a end date (timestamp_dtu). + * @timestamp_dtu: End date for this idle duration. + * @idle_timeout_cb: idle timeout callback. + * @next_operational_state: next operation state wanted. + * + * Return: 0 on success, else an error. + */ +int dw3000_idle(struct dw3000 *dw, bool timestamp, u32 timestamp_dtu, + dw3000_idle_timeout_cb idle_timeout_cb, + enum operational_state next_operational_state) +{ + struct dw3000_deep_sleep_state *dss = &dw->deep_sleep_state; + u32 cur_time_dtu = 0; + int delay_us = 0, rc; + + trace_dw3000_idle(dw, timestamp, timestamp_dtu, next_operational_state); + + if (WARN_ON(next_operational_state < DW3000_OP_STATE_IDLE_PLL)) + return -EINVAL; + + dw->wakeup_done_cb = dw3000_wakeup_done_to_idle; + /* Reset ranging clock requirement */ + dw->need_ranging_clock = false; + dw3000_reset_rctu_conv_state(dw); + /* Ensure dw3000_idle_timeout() handler does the right thing. */ + dss->next_operational_state = next_operational_state; + + /* Release Wifi coexistence. */ + dw3000_coex_stop(dw); + /* Check if enough idle time to enter DEEP SLEEP */ + dw->idle_timeout = timestamp; + dw->idle_timeout_dtu = timestamp_dtu; + if (timestamp) { + int deepsleep_delay_us; + int idle_delay_us; + bool is_sleeping = dw->current_operational_state == + DW3000_OP_STATE_DEEP_SLEEP; + + cur_time_dtu = dw3000_get_dtu_time(dw); + idle_delay_us = DTU_TO_US(timestamp_dtu - cur_time_dtu); + if (idle_delay_us < 0) { + rc = -ETIME; + goto eof; + } + /* Warning: timestamp_dtu have already taken in consideration + * WakeUp latency! */ + deepsleep_delay_us = idle_delay_us; + if (is_sleeping) + deepsleep_delay_us -= DW3000_WAKEUP_LATENCY_US; + + /* TODO/FIXME: + * Timer is used for idle timeout and deepsleep timeout, + * which haven't the same timeout_dtu! */ + if (deepsleep_delay_us < 0) { + dw3000_deepsleep_wakeup_now(dw, idle_timeout_cb, + DW3000_OP_STATE_MAX); + rc = 0; + goto eof; + } + + delay_us = dw3000_can_deep_sleep(dw, deepsleep_delay_us); + if (!delay_us) { + u32 timer_duration_dtu = is_sleeping ? + deepsleep_delay_us : + idle_delay_us; + /* Provided date isn't far enough to enter deep-sleep, + just launch the timer to have it call the MCPS timer + expired event function. */ + dw->idle_timeout_cb = idle_timeout_cb; + dw3000_wakeup_timer_start(dw, timer_duration_dtu); + rc = 0; + goto eof; + } + } else if (dw->auto_sleep_margin_us < 0) { + /* Deep-sleep is completly disable, so do nothing here! */ + rc = 0; + goto eof; + } + /* Enter DEEP SLEEP */ + rc = dw3000_deep_sleep_and_wakeup(dw, delay_us); + if (!rc) + dw->idle_timeout_cb = idle_timeout_cb; +eof: + return rc; +} + +/** * dw3000_lock_pll() - Auto calibrate the PLL and change to IDLE_PLL state * @dw: the DW device on which the SPI transfer will occurs * @sys_status: the last known sys_status register LSB value @@ -5620,6 +5825,13 @@ int dw3000_set_rx_antennas(struct dw3000 *dw, int ant_pair, bool pdoa_enabled) return rc; } +static void dw3000_mcps_timer_expired(struct work_struct *work) +{ + struct dw3000 *dw = + container_of(work, struct dw3000, timer_expired_work); + mcps802154_timer_expired(dw->llhw); +} + /** * dw3000_initialise() - Initialise the DW local data. * @dw: The DW device. @@ -5645,8 +5857,8 @@ static void dw3000_initialise(struct dw3000 *dw) * parameter on load, or via testmode */ stats->enabled = dw3000_stats_enabled; memset(stats->count, 0, sizeof(stats->count)); - /* Reset Deep Sleep state */ - INIT_WORK(&dw->timer_expired_work, dw3000_timer_expired); + INIT_WORK(&dw->timer_expired_work, dw3000_mcps_timer_expired); + #ifdef CONFIG_DW3000_DEBUG if (dss->regbackup) kfree(dss->regbackup); @@ -5959,7 +6171,7 @@ int dw3000_disable(struct dw3000 *dw) if (dw->current_operational_state < DW3000_OP_STATE_INIT_RC) { /* Seems chip is sleeping or already power-off. Just ensure wake-up timer will not fire since not required anymore. */ - dw3000_wakeup_cancel(dw); + dw3000_idle_cancel_timer(dw); /* No need to call disable_irq() since already called and this will require calling two times enable_irq() later because enable/disable_irq are nested! */ @@ -6060,6 +6272,7 @@ static inline int dw3000_isr_handle_spi_ready(struct dw3000 *dw, struct dw3000_isr_data *isr) { struct dw3000_deep_sleep_state *dss = &dw->deep_sleep_state; + const dw3000_wakeup_done_cb wakeup_done_cb = dw->wakeup_done_cb; int rc; if (dw->current_operational_state != DW3000_OP_STATE_WAKE_UP) { @@ -6203,21 +6416,10 @@ setuperror: if (rc) return rc; #endif - /* Do the required operation after wakeup according states */ - if (dw->nfcc_coex.enabled) { - rc = dw3000_nfcc_coex_handle_spi1_ready_isr(dw); - } else if (dss->next_operational_state == DW3000_OP_STATE_RX) { - /* Entered DEEP SLEEP from dw3000_do_rx_enable() */ - dss->next_operational_state = dw->current_operational_state; - rc = dw3000_do_rx_enable(dw, &dss->rx_info, dss->frame_idx); - } else if (dss->next_operational_state == DW3000_OP_STATE_TX) { - /* Entered DEEP SLEEP from dw3000_do_tx_frame() */ - dss->next_operational_state = dw->current_operational_state; - rc = dw3000_do_tx_frame(dw, &dss->tx_info, dss->tx_skb, - dss->frame_idx); - } else if (dw->call_timer_expired) { - /* Entered DEEP SLEEP from do_idle() */ - schedule_work(&dw->timer_expired_work); + if (wakeup_done_cb) { + /* Consume the callback handler before execution. */ + dw->wakeup_done_cb = NULL; + rc = wakeup_done_cb(dw); } return rc; } diff --git a/kernel/drivers/net/ieee802154/dw3000_core.h b/kernel/drivers/net/ieee802154/dw3000_core.h index e8c7dbd..d6d6efa 100644 --- a/kernel/drivers/net/ieee802154/dw3000_core.h +++ b/kernel/drivers/net/ieee802154/dw3000_core.h @@ -359,10 +359,16 @@ void dw3000_sysfs_init(struct dw3000 *dw); void dw3000_sysfs_remove(struct dw3000 *dw); void dw3000_isr(struct dw3000 *dw); -enum hrtimer_restart dw3000_wakeup_timer(struct hrtimer *timer); +enum hrtimer_restart dw3000_idle_timeout(struct hrtimer *timer); void dw3000_wakeup_timer_start(struct dw3000 *dw, int delay_us); void dw3000_wakeup_and_wait(struct dw3000 *dw); int dw3000_deep_sleep_and_wakeup(struct dw3000 *dw, int delay_us); +int dw3000_idle(struct dw3000 *dw, bool timestamp, u32 timestamp_dtu, + dw3000_idle_timeout_cb idle_timeout_cb, + enum operational_state next_operational_state); +int dw3000_deepsleep_wakeup_now(struct dw3000 *dw, + dw3000_idle_timeout_cb idle_timeout_cb, + enum operational_state next_operational_state); int dw3000_can_deep_sleep(struct dw3000 *dw, int delay_us); int dw3000_trace_rssi_info(struct dw3000 *dw, u32 regid, char *chipver); diff --git a/kernel/drivers/net/ieee802154/dw3000_mcps.c b/kernel/drivers/net/ieee802154/dw3000_mcps.c index 133d5b2..e46b1c3 100644 --- a/kernel/drivers/net/ieee802154/dw3000_mcps.c +++ b/kernel/drivers/net/ieee802154/dw3000_mcps.c @@ -478,47 +478,23 @@ error: return ret; } -static int do_idle(struct dw3000 *dw, const void *in, void *out) +static int dw3000_handle_idle_timeout(struct dw3000 *dw) { - struct dw3000_deep_sleep_state *dss = &dw->deep_sleep_state; - u32 cur_time_dtu = 0; - int delay_us = 0, rc; - - trace_dw3000_mcps_idle(dw, in != NULL, in ? *(const u32 *)in : 0); + /* MCPS feeback must be done outside driver kthread. */ + schedule_work(&dw->timer_expired_work); + return 0; +} - /* Reset ranging clock requirement */ - dw->need_ranging_clock = false; - dw3000_reset_rctu_conv_state(dw); - /* Ensure dw3000_wakeup_timer() handler does the right thing */ - dss->next_operational_state = DW3000_OP_STATE_IDLE_PLL; - - /* Release Wifi coexistence. */ - dw3000_coex_stop(dw); - /* Check if enough idle time to enter DEEP SLEEP */ - if (in) { - u32 date_dtu = *(const u32 *)in; - int effective_delay_us; - cur_time_dtu = dw3000_get_dtu_time(dw); - effective_delay_us = DTU_TO_US(date_dtu - cur_time_dtu); - delay_us = dw3000_can_deep_sleep(dw, effective_delay_us); - if (!delay_us) { - /* Provided date isn't far enough to enter deep-sleep, - just launch the timer to have it call the MCPS timer - expired event function. */ - dw3000_wakeup_timer_start(dw, effective_delay_us); - rc = 0; - goto eof; - } - } else if (dw->auto_sleep_margin_us < 0) { - /* Deep-sleep is completly disable, so do nothing here! */ - rc = 0; - goto eof; - } - /* Enter DEEP SLEEP */ - rc = dw3000_deep_sleep_and_wakeup(dw, delay_us); -eof: - trace_dw3000_return_int(dw, rc); - return rc; +static int do_idle(struct dw3000 *dw, const void *in, void *out) +{ + bool timestamp = !!in; + u32 timestamp_dtu = timestamp ? *(const u32 *)in : 0; + + int r = dw3000_idle(dw, timestamp, timestamp_dtu, + dw3000_handle_idle_timeout, + DW3000_OP_STATE_IDLE_PLL); + trace_dw3000_return_int(dw, r); + return r; } static int idle(struct mcps802154_llhw *llhw, bool timestamp, u32 timestamp_dtu) diff --git a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex.h b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex.h index 682c7bd..98107c5 100644 --- a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex.h +++ b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex.h @@ -169,6 +169,10 @@ struct dw3000_nfcc_coex { */ bool enabled; /** + * @configured: True when nfcc coex is configured. + */ + bool configured; + /** * @sync_time_needed: True when clock_sync frame must be send. */ bool sync_time_needed; diff --git a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.c b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.c index 2fa642f..0cb475f 100644 --- a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.c +++ b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.c @@ -136,6 +136,41 @@ static int dw3000_nfcc_coex_disable_SPIxMAVAIL_interrupts(struct dw3000 *dw) } /** + * dw3000_nfcc_coex_configure() - Configure the nfcc_coex. + * @dw: Driver context. + * + * Return: 0 on success, else an error. + */ +int dw3000_nfcc_coex_configure(struct dw3000 *dw) +{ + int r; + + if (dw->nfcc_coex.configured) + return 0; + + trace_dw3000_nfcc_coex_configure(dw); + r = dw3000_configure_chan(dw); + if (r) { + trace_dw3000_nfcc_coex_err(dw, "configure channel fails"); + return r; + } + r = dw3000_rx_disable(dw); + if (r) { + trace_dw3000_nfcc_coex_warn(dw, "rx disable failed"); + return r; + } + r = dw3000_nfcc_coex_enable_SPIxMAVAIL_interrupts(dw); + if (r) { + trace_dw3000_nfcc_coex_err( + dw, "SPIxMAVAIL interrupts enable failed"); + return r; + } + + dw->nfcc_coex.configured = true; + return 0; +} + +/** * dw3000_nfcc_coex_do_watchdog_timeout() - Do watchdog timeout event in workqueue. * @dw: Driver context. * @in: Data to read. @@ -215,24 +250,40 @@ int dw3000_nfcc_coex_handle_spi1_avail_isr(struct dw3000 *dw) } /** - * dw3000_nfcc_coex_handle_spi1_ready_isr() - Handle SPI ready interrupt. + * dw3000_nfcc_coex_idle_timeout() - Idle expired. * @dw: Driver context. * * Return: 0 on success, else an error. */ -int dw3000_nfcc_coex_handle_spi1_ready_isr(struct dw3000 *dw) +int dw3000_nfcc_coex_idle_timeout(struct dw3000 *dw) { int r; - if (__dw3000_chip_version == DW3000_C0_VERSION) - return -EOPNOTSUPP; - + trace_dw3000_nfcc_coex_idle_timeout(dw); + if (!dw->nfcc_coex.configured) { + r = dw3000_nfcc_coex_configure(dw); + if (r) { + trace_dw3000_nfcc_coex_err( + dw, "dw3000_nfcc_coex_configured failed"); + return r; + } + } /* NFCC was enabled before sleeping. Enable the NFCC mailbox * interrupt and send the right message to the NFCC. */ r = dw3000_nfcc_coex_enable_SPIxMAVAIL_interrupts(dw); if (r) - return r; - return dw3000_nfcc_coex_message_send(dw); + goto idle_timeout_failure; + r = dw3000_nfcc_coex_message_send(dw); + if (r) { + trace_dw3000_nfcc_coex_err(dw, "nfcc_coex_message_send failed"); + goto idle_timeout_failure; + } + + return 0; + +idle_timeout_failure: + // Call mcps802154_broken(dw->llhw) in wq ? + return r; } /** @@ -259,8 +310,6 @@ void dw3000_nfcc_coex_init(struct dw3000 *dw) int dw3000_nfcc_coex_enable(struct dw3000 *dw, u8 channel, dw3000_nfcc_coex_spi_avail_cb cb) { - int rc; - trace_dw3000_nfcc_coex_enable(dw, channel); /* NFCC needs a D0 chip or above. C0 does not have 2 SPI interfaces. */ @@ -268,34 +317,17 @@ int dw3000_nfcc_coex_enable(struct dw3000 *dw, u8 channel, trace_dw3000_nfcc_coex_err(dw, "C0 chip is not supported"); return -EOPNOTSUPP; } - - /* Need to wake-up device and wait it before continuing. */ - dw3000_wakeup_and_wait(dw); + if (dw->nfcc_coex.enabled) + return -EBUSY; /* Set the channel for NFCC and save current config. */ - /* FIXME: original_channel lost on second call. */ dw->nfcc_coex.original_channel = dw->config.chan; dw->nfcc_coex.sync_time_needed = true; dw->config.chan = channel; - rc = dw3000_configure_chan(dw); - if (rc) { - trace_dw3000_nfcc_coex_err(dw, "configure channel fails"); - return rc; - } - - /* Disable rx during NFCC. */ - rc = dw3000_rx_disable(dw); - if (rc) - trace_dw3000_nfcc_coex_warn(dw, "rx disable failed"); - - rc = dw3000_nfcc_coex_enable_SPIxMAVAIL_interrupts(dw); - if (rc) - trace_dw3000_nfcc_coex_err( - dw, "SPIxMAVAIL interrupts enable failed"); - + dw->nfcc_coex.configured = false; dw->nfcc_coex.enabled = true; dw->nfcc_coex.spi_avail_cb = cb; - return rc; + return 0; } /** @@ -309,6 +341,9 @@ int dw3000_nfcc_coex_disable(struct dw3000 *dw) int rc; bool val = false; + if (!dw->nfcc_coex.configured) + return 0; + trace_dw3000_nfcc_coex_disable(dw); if (__dw3000_chip_version == DW3000_C0_VERSION) @@ -341,22 +376,9 @@ int dw3000_nfcc_coex_disable(struct dw3000 *dw) } } + dw->nfcc_coex.configured = false; /* TODO: Inform HAL that NFCC session is complete. */ dw->nfcc_coex.enabled = false; dw->nfcc_coex.spi_avail_cb = NULL; return rc; } - -/** - * dw3000_nfcc_coex_sleep() - Entering in deep sleep. - * @dw: Driver context. - * @sleep_dtu: Sleep duration in dtu. - * - * Return: 0 on success, else an error. - */ -int dw3000_nfcc_coex_sleep(struct dw3000 *dw, u32 sleep_dtu) -{ - trace_dw3000_nfcc_coex_sleep(dw, sleep_dtu); - dw->deep_sleep_state.next_operational_state = DW3000_OP_STATE_IDLE_PLL; - return dw3000_deep_sleep_and_wakeup(dw, DTU_TO_US(sleep_dtu)); -} diff --git a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.h b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.h index 1970817..b233fdc 100644 --- a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.h +++ b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.h @@ -32,12 +32,12 @@ struct dw3000; extern unsigned dw3000_nfcc_coex_margin_dtu; -int dw3000_nfcc_coex_handle_spi1_ready_isr(struct dw3000 *dw); int dw3000_nfcc_coex_handle_spi1_avail_isr(struct dw3000 *dw); +int dw3000_nfcc_coex_idle_timeout(struct dw3000 *dw); void dw3000_nfcc_coex_init(struct dw3000 *dw); int dw3000_nfcc_coex_enable(struct dw3000 *dw, u8 channel, dw3000_nfcc_coex_spi_avail_cb cb); int dw3000_nfcc_coex_disable(struct dw3000 *dw); -int dw3000_nfcc_coex_sleep(struct dw3000 *dw, u32 sleep_dtu); +int dw3000_nfcc_coex_configure(struct dw3000 *dw); #endif /* __DW3000_NFCC_COEX_CORE_H */ diff --git a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_mcps.c b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_mcps.c index 17229b9..16d9145 100644 --- a/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_mcps.c +++ b/kernel/drivers/net/ieee802154/dw3000_nfcc_coex_mcps.c @@ -111,7 +111,8 @@ static int dw3000_nfcc_coex_handle_access(struct dw3000 *dw, void *data, const struct dw3000_vendor_cmd_nfcc_coex_handle_access *info = data; struct dw3000_nfcc_coex *nfcc_coex = &dw->nfcc_coex; const u32 dtu_per_ms = dw->llhw->dtu_freq_hz / 1000; - u32 diff_dtu, diff_ms; + u32 now_dtu, message_send_timestamp_dtu; + s32 idle_duration_dtu; int r; if (!info || data_len != sizeof(*info)) @@ -128,22 +129,35 @@ static int dw3000_nfcc_coex_handle_access(struct dw3000 *dw, void *data, if (r) return r; } + now_dtu = dw3000_get_dtu_time(dw); + message_send_timestamp_dtu = + info->timestamp_dtu - dw3000_nfcc_coex_margin_dtu; + idle_duration_dtu = message_send_timestamp_dtu - now_dtu; - trace_dw3000_nfcc_coex_handle_access(dw, info); + trace_dw3000_nfcc_coex_handle_access(dw, info, idle_duration_dtu); /* Save start session date, to retrieve MSB bits lost for next date. */ nfcc_coex->access_start_dtu = info->timestamp_dtu; - /* Setup watchdog timer. */ - diff_dtu = info->timestamp_dtu - dw3000_get_dtu_time(dw); - diff_ms = diff_dtu / dtu_per_ms; + /* Build the when spi must be released. */ nfcc_coex->watchdog_timer.expires = jiffies + - msecs_to_jiffies(diff_ms + + msecs_to_jiffies((info->timestamp_dtu - now_dtu) / dtu_per_ms + DW3000_NFCC_COEX_WATCHDOG_DEFAULT_DURATION_MS); add_timer(&nfcc_coex->watchdog_timer); - if (diff_dtu > dw3000_nfcc_coex_margin_dtu) - return dw3000_nfcc_coex_sleep( - dw, diff_dtu - dw3000_nfcc_coex_margin_dtu); + /* Send message and so release the SPI close to the nfc_coex_margin. */ + message_send_timestamp_dtu = + info->timestamp_dtu - dw3000_nfcc_coex_margin_dtu; + if (idle_duration_dtu > 0) + return dw3000_idle(dw, true, message_send_timestamp_dtu, + dw3000_nfcc_coex_idle_timeout, + DW3000_OP_STATE_MAX); + else if (dw->current_operational_state == DW3000_OP_STATE_DEEP_SLEEP) + return dw3000_deepsleep_wakeup_now( + dw, dw3000_nfcc_coex_idle_timeout, DW3000_OP_STATE_MAX); + + r = dw3000_nfcc_coex_configure(dw); + if (r) + return r; return dw3000_nfcc_coex_message_send(dw); } diff --git a/kernel/drivers/net/ieee802154/dw3000_spi.c b/kernel/drivers/net/ieee802154/dw3000_spi.c index 52f9432..6505db0 100644 --- a/kernel/drivers/net/ieee802154/dw3000_spi.c +++ b/kernel/drivers/net/ieee802154/dw3000_spi.c @@ -113,9 +113,9 @@ static int dw3000_spi_probe(struct spi_device *spi) dw->bw_comp = dw3000_bw_comp; dw->current_operational_state = DW3000_OP_STATE_OFF; init_waitqueue_head(&dw->operational_state_wq); - /* Initialization of the deep sleep timer */ - hrtimer_init(&dw->deep_sleep_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - dw->deep_sleep_timer.function = dw3000_wakeup_timer; + /* Initialization of the idle timer for wakeup. */ + hrtimer_init(&dw->idle_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + dw->idle_timer.function = dw3000_idle_timeout; if (dw3000_sp0_rx_antenna >= ANTMAX) { dev_warn(dw->dev, "sp0 rx antenna is out of antenna range"); @@ -123,7 +123,7 @@ static int dw3000_spi_probe(struct spi_device *spi) } dw->sp0_rx_antenna = dw3000_sp0_rx_antenna; - dev_info(dw->dev, "Loading driver UWBM-2.0.0-21112301"); + dev_info(dw->dev, "Loading driver UWBM-2.0.0-21121401"); dw3000_sysfs_init(dw); /* Setup SPI parameters */ diff --git a/kernel/drivers/net/ieee802154/dw3000_trc.h b/kernel/drivers/net/ieee802154/dw3000_trc.h index a69ab40..5c8d23e 100644 --- a/kernel/drivers/net/ieee802154/dw3000_trc.h +++ b/kernel/drivers/net/ieee802154/dw3000_trc.h @@ -93,7 +93,7 @@ TRACE_DEFINE_ENUM(DW3000_OP_STATE_RX); } /* clang-format off */ -#define DW3000_OP_STATE_FLAGS \ +#define DW3000_OP_STATE_SYMBOLS \ dw3000_op_state_name(OFF), \ dw3000_op_state_name(DEEP_SLEEP), \ dw3000_op_state_name(SLEEP), \ @@ -276,6 +276,18 @@ TRACE_DEFINE_ENUM(DW3000_NFCC_COEX_TLV_TYPE_SLOT_LIST_UUS); #define DW3000_NFCC_COEX_TLV_TYPE_ARG \ __print_symbolic(__entry->type, DW3000_NFCC_COEX_TLV_TYPE_SYMBOLS) +#define dw3000_dss_stats_name(name) \ + { \ + DW3000_DSS_STAT_##name##_BIT_MASK, #name \ + } +/* clang-format off */ +#define DW3000_DSS_STATS_SYMBOLS \ + dw3000_dss_stats_name(SPI1_AVAIL), \ + dw3000_dss_stats_name(SPI2_AVAIL) +/* clang-format on */ +TRACE_DEFINE_ENUM(DW3000_DSS_STAT_SPI1_AVAIL_BIT_MASK); +TRACE_DEFINE_ENUM(DW3000_DSS_STAT_SPI2_AVAIL_BIT_MASK); + /* We don't want clang-format to modify the following events definition! Look at net/wireless/trace.h for the required format. */ /* clang-format off */ @@ -467,21 +479,42 @@ TRACE_EVENT(dw3000_mcps_rx_get_error_frame, DW_PR_ARG, RX_FRAME_INFO_FLAGS_PR_ARG) ); -TRACE_EVENT(dw3000_mcps_idle, - TP_PROTO(struct dw3000 *dw, bool timeout, u32 timeout_dtu), - TP_ARGS(dw, timeout, timeout_dtu), +DEFINE_EVENT(dw_only_evt, dw3000_wakeup_done_to_tx, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + +DEFINE_EVENT(dw_only_evt, dw3000_wakeup_done_to_rx, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + +DEFINE_EVENT(dw_only_evt, dw3000_wakeup_done_to_idle, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + +TRACE_EVENT(dw3000_idle, + TP_PROTO(struct dw3000 *dw, bool timeout, u32 timeout_dtu, + enum operational_state next_operational_state), + TP_ARGS(dw, timeout, timeout_dtu, next_operational_state), TP_STRUCT__entry( DW_ENTRY __field(bool, timeout) __field(u32, timeout_dtu) + __field(enum operational_state, next_operational_state) ), TP_fast_assign( DW_ASSIGN; __entry->timeout = timeout; __entry->timeout_dtu = timeout_dtu; + __entry->next_operational_state = next_operational_state; ), - TP_printk(DW_PR_FMT ", timeout: %s, timeout_dtu: %#x", DW_PR_ARG, - __entry->timeout ? "true" : "false", __entry->timeout_dtu) + TP_printk(DW_PR_FMT ", timeout: %s, timeout_dtu: %#x, " + "next_operational_state: %s" , DW_PR_ARG, + __entry->timeout ? "true" : "false", __entry->timeout_dtu, + __print_symbolic(__entry->next_operational_state, + DW3000_OP_STATE_SYMBOLS)) ); DEFINE_EVENT(dw_only_evt, dw3000_mcps_reset, @@ -651,6 +684,22 @@ TRACE_EVENT(dw3000_check_idlerc, DW_PR_ARG, __entry->low_sys_status) ); +TRACE_EVENT(dw3000_wakeup_and_wait, + TP_PROTO(struct dw3000 *dw, enum operational_state operational_state), + TP_ARGS(dw, operational_state), + TP_STRUCT__entry( + DW_ENTRY + __field(enum operational_state, operational_state) + ), + TP_fast_assign( + DW_ASSIGN; + __entry->operational_state = operational_state; + ), + TP_printk(DW_PR_FMT ", operational_state: %s", DW_PR_ARG, + __print_symbolic(__entry->operational_state, + DW3000_OP_STATE_SYMBOLS)) +); + TRACE_EVENT(dw3000_set_operational_state, TP_PROTO(struct dw3000 *dw, enum operational_state operational_state), TP_ARGS(dw, operational_state), @@ -664,7 +713,22 @@ TRACE_EVENT(dw3000_set_operational_state, ), TP_printk(DW_PR_FMT ", operational_state: %s", DW_PR_ARG, __print_symbolic(__entry->operational_state, - DW3000_OP_STATE_FLAGS)) + DW3000_OP_STATE_SYMBOLS)) +); + +DEFINE_EVENT(dw_only_evt, dw3000_deepsleep_wakeup, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + +DEFINE_EVENT(dw_only_evt, dw3000_idle_timeout, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + +DEFINE_EVENT(dw_only_evt, dw3000_idle_cancel_timer, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) ); TRACE_EVENT(dw3000_check_operational_state, @@ -688,9 +752,9 @@ TRACE_EVENT(dw3000_check_operational_state, TP_printk(DW_PR_FMT ", delay_dtu: %d, current_operational_state: %s, " "next_operational_state: %s", DW_PR_ARG, __entry->delay_dtu, __print_symbolic(__entry->current_operational_state, - DW3000_OP_STATE_FLAGS), + DW3000_OP_STATE_SYMBOLS), __print_symbolic(__entry->next_operational_state, - DW3000_OP_STATE_FLAGS)) + DW3000_OP_STATE_SYMBOLS)) ); DEFINE_EVENT(dw_only_evt, dw3000_read_rx_timestamp, @@ -785,7 +849,7 @@ TRACE_EVENT(dw3000_wakeup_done, "next_op_date: %#x, next_op: %s", DW_PR_ARG, __entry->sleep_time_us, __entry->sleep_enter_dtu, __entry->dtu_next_op, - __print_symbolic(__entry->next_op, DW3000_OP_STATE_FLAGS)) + __print_symbolic(__entry->next_op, DW3000_OP_STATE_SYMBOLS)) ); TRACE_EVENT(dw3000_power_stats, @@ -958,21 +1022,9 @@ TRACE_EVENT(dw3000_nfcc_coex_isr, DW_ASSIGN; __entry->dss_stat = dss_stat; ), - TP_printk(DW_PR_FMT ", dss_stat: 0x%x", DW_PR_ARG, __entry->dss_stat) -); - -TRACE_EVENT(dw3000_nfcc_coex_sleep, - TP_PROTO(struct dw3000 *dw, u32 sleep_dtu), - TP_ARGS(dw, sleep_dtu), - TP_STRUCT__entry( - DW_ENTRY - __field(u32, sleep_dtu) - ), - TP_fast_assign( - DW_ASSIGN; - __entry->sleep_dtu = sleep_dtu; - ), - TP_printk(DW_PR_FMT ", sleep_dtu: 0x%08x", DW_PR_ARG, __entry->sleep_dtu) + TP_printk(DW_PR_FMT ", dss_stat: %s", DW_PR_ARG, + __print_flags(__entry->dss_stat, "|", + DW3000_DSS_STATS_SYMBOLS)) ); TRACE_EVENT(dw3000_nfcc_coex_header_put, @@ -1062,8 +1114,8 @@ TRACE_EVENT(dw3000_nfcc_coex_header_check, ), TP_printk(DW_PR_FMT ", signature: %s, ver_id: %u, seq_num: %u" ", nb_tlv: %u", DW_PR_ARG, - __print_array(__entry->signature, - DW3000_NFCC_COEX_SIGNATURE_LEN, sizeof(u8)), + __print_hex(__entry->signature, + DW3000_NFCC_COEX_SIGNATURE_LEN), __entry->ver_id, __entry->seq_num, __entry->nb_tlv) ); @@ -1088,11 +1140,13 @@ TRACE_EVENT(dw3000_nfcc_coex_tlv_check, ); TRACE_EVENT(dw3000_nfcc_coex_handle_access, - TP_PROTO(struct dw3000 *dw, const struct dw3000_vendor_cmd_nfcc_coex_handle_access *info), - TP_ARGS(dw, info), + TP_PROTO(struct dw3000 *dw, const struct dw3000_vendor_cmd_nfcc_coex_handle_access *info, + s32 idle_duration_dtu), + TP_ARGS(dw, info, idle_duration_dtu), TP_STRUCT__entry( DW_ENTRY __field(bool, start) + __field(s32, idle_duration_dtu) __field(u32, timestamp_dtu) __field(int, duration_dtu) __field(int, chan) @@ -1100,13 +1154,17 @@ TRACE_EVENT(dw3000_nfcc_coex_handle_access, TP_fast_assign( DW_ASSIGN; __entry->start = info->start; + __entry->idle_duration_dtu = idle_duration_dtu; __entry->timestamp_dtu = info->timestamp_dtu; __entry->duration_dtu = info->duration_dtu; __entry->chan = info->chan; ), - TP_printk(DW_PR_FMT ", start: %s, timestamp_dtu: 0x%08x" - ", duration_dtu: 0x%08x, chan: %d", DW_PR_ARG, - __entry->start ? "true" : "false", __entry->timestamp_dtu, + TP_printk(DW_PR_FMT ", start: %s, idle_duration_dtu: 0x%08x" + ", timestamp_dtu: 0x%08x, duration_dtu: 0x%08x," + " chan: %d", DW_PR_ARG, + __entry->start ? "true" : "false", + __entry->idle_duration_dtu, + __entry->timestamp_dtu, __entry->duration_dtu, __entry->chan) ); @@ -1138,11 +1196,21 @@ TRACE_EVENT(dw3000_nfcc_coex_warn, TP_printk(DW_PR_FMT ", warn: \"%s\"", DW_PR_ARG, __get_str(warn)) ); +DEFINE_EVENT(dw_only_evt, dw3000_nfcc_coex_configure, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + DEFINE_EVENT(dw_only_evt, dw3000_nfcc_coex_watchdog, TP_PROTO(struct dw3000 *dw), TP_ARGS(dw) ); +DEFINE_EVENT(dw_only_evt, dw3000_nfcc_coex_idle_timeout, + TP_PROTO(struct dw3000 *dw), + TP_ARGS(dw) +); + TRACE_EVENT(dw3000_nfcc_coex_enable, TP_PROTO(struct dw3000 *dw, int channel), TP_ARGS(dw, channel), diff --git a/kernel/net/mcps802154/mcps802154_qorvo.h b/kernel/net/mcps802154/mcps802154_qorvo.h new file mode 120000 index 0000000..48ea31d --- /dev/null +++ b/kernel/net/mcps802154/mcps802154_qorvo.h @@ -0,0 +1 @@ +../../../mac/mcps802154_qorvo.h
\ No newline at end of file diff --git a/kernel/net/mcps802154/nfcc_coex_trace.h b/kernel/net/mcps802154/nfcc_coex_trace.h index 42f9e7b..7a3a3ef 100644 --- a/kernel/net/mcps802154/nfcc_coex_trace.h +++ b/kernel/net/mcps802154/nfcc_coex_trace.h @@ -28,51 +28,178 @@ #define NFCC_COEX_TRACE_H #include <linux/tracepoint.h> +#include <net/nfcc_coex_region_nl.h> #include "mcps802154_i.h" -#include <net/vendor_cmd.h> +#include "nfcc_coex_region.h" +#include "nfcc_coex_session.h" /* clang-format off */ +#define nfcc_coex_call_name(name) \ + { \ + NFCC_COEX_CALL_##name, #name \ + } +#define NFCC_COEX_CALL_SYMBOLS \ + nfcc_coex_call_name(CCC_SESSION_START), \ + nfcc_coex_call_name(CCC_SESSION_STOP), \ + nfcc_coex_call_name(CCC_SESSION_NOTIFICATION) +TRACE_DEFINE_ENUM(NFCC_COEX_CALL_CCC_SESSION_START); +TRACE_DEFINE_ENUM(NFCC_COEX_CALL_CCC_SESSION_STOP); +TRACE_DEFINE_ENUM(NFCC_COEX_CALL_CCC_SESSION_NOTIFICATION); -#define LOCAL_ENTRY __field(int, hw_idx) -#define LOCAL_ASSIGN __entry->hw_idx = local->hw_idx -#define LOCAL_PR_FMT "hw%d" -#define LOCAL_PR_ARG __entry->hw_idx +#define nfcc_coex_state_name(name) \ + { \ + NFCC_COEX_STATE_##name, #name \ + } +#define NFCC_COEX_STATE_SYMBOLS \ + nfcc_coex_state_name(IDLE), \ + nfcc_coex_state_name(ACCESSING), \ + nfcc_coex_state_name(STOPPING) +TRACE_DEFINE_ENUM(NFCC_COEX_STATE_IDLE); +TRACE_DEFINE_ENUM(NFCC_COEX_STATE_ACCESSING); +TRACE_DEFINE_ENUM(NFCC_COEX_STATE_STOPPING); -TRACE_EVENT(nfcc_coex_llhw_return_int, - TP_PROTO(const struct mcps802154_local *local, int ret), - TP_ARGS(local, ret), +#define NFCC_COEX_LOCAL_ENTRY __field(enum nfcc_coex_state, state) +#define NFCC_COEX_LOCAL_ASSIGN __entry->state = local->session.state +#define NFCC_COEX_LOCAL_PR_FMT "state=%s" +#define NFCC_COEX_LOCAL_PR_ARG \ + __print_symbolic(__entry->state, NFCC_COEX_STATE_SYMBOLS) + +DECLARE_EVENT_CLASS( + local_only_evt, + TP_PROTO(const struct nfcc_coex_local *local), + TP_ARGS(local), + TP_STRUCT__entry( + NFCC_COEX_LOCAL_ENTRY + ), + TP_fast_assign( + NFCC_COEX_LOCAL_ASSIGN; + ), + TP_printk(NFCC_COEX_LOCAL_PR_FMT, NFCC_COEX_LOCAL_PR_ARG) +); + +TRACE_EVENT( + region_nfcc_coex_session_start, + TP_PROTO(const struct nfcc_coex_local *local, + const struct nfcc_coex_session_params *p), + TP_ARGS(local, p), TP_STRUCT__entry( - LOCAL_ENTRY - __field(int, ret) + NFCC_COEX_LOCAL_ENTRY + __field(u64, time0_ns) + __field(u8, channel_number) + ), + TP_fast_assign( + NFCC_COEX_LOCAL_ASSIGN; + __entry->time0_ns = p->time0_ns; + __entry->channel_number = p->channel_number; + ), + TP_printk(NFCC_COEX_LOCAL_PR_FMT " time0_ns=%llu channel_number=%d", + NFCC_COEX_LOCAL_PR_ARG, __entry->time0_ns, + __entry->channel_number) +); + +DEFINE_EVENT( + local_only_evt, region_nfcc_coex_session_stop, + TP_PROTO(const struct nfcc_coex_local *local), + TP_ARGS(local) +); + +DEFINE_EVENT( + local_only_evt, region_nfcc_coex_notify_stop, + TP_PROTO(const struct nfcc_coex_local *local), + TP_ARGS(local) +); + +TRACE_EVENT( + region_nfcc_coex_call, + TP_PROTO(const struct nfcc_coex_local *local, + enum nfcc_coex_call call_id), + TP_ARGS(local, call_id), + TP_STRUCT__entry( + NFCC_COEX_LOCAL_ENTRY + __field(enum nfcc_coex_call, call_id) ), TP_fast_assign( - LOCAL_ASSIGN; - __entry->ret = ret; + NFCC_COEX_LOCAL_ASSIGN; + __entry->call_id = call_id; ), - TP_printk(LOCAL_PR_FMT " returned=%d", LOCAL_PR_ARG, __entry->ret) - ); + TP_printk(NFCC_COEX_LOCAL_PR_FMT " call_id=%s", + NFCC_COEX_LOCAL_PR_ARG, + __print_symbolic(__entry->call_id, NFCC_COEX_CALL_SYMBOLS)) +); -TRACE_EVENT(nfcc_coex_llhw_vendor_cmd, - TP_PROTO(const struct mcps802154_local *local, u32 vendor_id, - u32 subcmd), - TP_ARGS(local, vendor_id, subcmd), +TRACE_EVENT( + region_nfcc_coex_get_demand, + TP_PROTO(const struct nfcc_coex_local *local, + u32 next_timestamp_dtu, + const struct mcps802154_region_demand *rd), + TP_ARGS(local, next_timestamp_dtu, rd), TP_STRUCT__entry( - LOCAL_ENTRY - __field(u32, vendor_id) - __field(u32, subcmd) + NFCC_COEX_LOCAL_ENTRY + __field(u32, next_timestamp_dtu) + __field(u32, timestamp_dtu) + __field(int, duration_dtu) ), TP_fast_assign( - LOCAL_ASSIGN; - __entry->vendor_id = vendor_id; - __entry->subcmd = subcmd; + NFCC_COEX_LOCAL_ASSIGN; + __entry->next_timestamp_dtu = next_timestamp_dtu; + __entry->timestamp_dtu = rd->timestamp_dtu; + __entry->duration_dtu = rd->duration_dtu; ), - TP_printk(LOCAL_PR_FMT " vendor_id=%06x subcmd=%s", LOCAL_PR_ARG, - __entry->vendor_id, - __print_symbolic(__entry->subcmd, - { DW3000_VENDOR_CMD_NFCC_COEX_HANDLE_ACCESS, "HANDLE_ACCESS"}, - { DW3000_VENDOR_CMD_NFCC_COEX_GET_ACCESS_INFORMATION, "GET_ACCESS_INFORMATION"}, - { DW3000_VENDOR_CMD_NFCC_COEX_STOP, "STOP"})) - ); + TP_printk(NFCC_COEX_LOCAL_PR_FMT " next_timestamp_dtu=0x%08x " + "rd.timestamp_dtu=0x%08x rd.duration_dtu=0x%08x", + NFCC_COEX_LOCAL_PR_ARG, + __entry->next_timestamp_dtu, + __entry->timestamp_dtu, + __entry->duration_dtu) +); + +TRACE_EVENT( + region_nfcc_coex_set_state, + TP_PROTO(const struct nfcc_coex_local *local, + enum nfcc_coex_state new_state), + TP_ARGS(local, new_state), + TP_STRUCT__entry( + NFCC_COEX_LOCAL_ENTRY + __field(enum nfcc_coex_state, new_state) + ), + TP_fast_assign( + NFCC_COEX_LOCAL_ASSIGN; + __entry->new_state = new_state; + ), + TP_printk(NFCC_COEX_LOCAL_PR_FMT " new_state=%s", + NFCC_COEX_LOCAL_PR_ARG, + __print_symbolic(__entry->new_state, + NFCC_COEX_STATE_SYMBOLS)) +); + +TRACE_EVENT( + region_nfcc_coex_report, + TP_PROTO(const struct nfcc_coex_local *local, + const struct dw3000_vendor_cmd_nfcc_coex_get_access_info *info), + TP_ARGS(local, info), + TP_STRUCT__entry( + NFCC_COEX_LOCAL_ENTRY + __field(bool, watchdog_timeout) + __field(bool, stop) + ), + TP_fast_assign( + NFCC_COEX_LOCAL_ASSIGN; + __entry->watchdog_timeout = info->watchdog_timeout; + __entry->stop = info->stop; + ), + TP_printk(NFCC_COEX_LOCAL_PR_FMT " watchdog_timeout=%s stop=%s", + NFCC_COEX_LOCAL_PR_ARG, + __entry->watchdog_timeout ? "true": "false", + __entry->stop ? "true": "false") +); + +DEFINE_EVENT( + local_only_evt, region_nfcc_coex_report_nla_put_failure, + TP_PROTO(const struct nfcc_coex_local *local), + TP_ARGS(local) +); + +/* clang-format on */ #endif /* !NFCC_COEX_TRACE_H || TRACE_HEADER_MULTI_READ */ diff --git a/kernel/net/mcps802154/trace.h b/kernel/net/mcps802154/trace.h index 2620675..d618abc 100644 --- a/kernel/net/mcps802154/trace.h +++ b/kernel/net/mcps802154/trace.h @@ -598,6 +598,27 @@ DEFINE_EVENT(local_only_evt, llhw_list_calibration, TP_ARGS(local) ); +TRACE_EVENT(llhw_vendor_cmd, + TP_PROTO(const struct mcps802154_local *local, u32 vendor_id, + u32 subcmd, size_t data_len), + TP_ARGS(local, vendor_id, subcmd, data_len), + TP_STRUCT__entry( + LOCAL_ENTRY + __field(u32, vendor_id) + __field(u32, subcmd) + __field(u32, data_len) + ), + TP_fast_assign( + LOCAL_ASSIGN; + __entry->vendor_id = vendor_id; + __entry->subcmd = subcmd; + __entry->data_len = data_len; + ), + TP_printk(LOCAL_PR_FMT " vendor_id=0x%06x subcmd=0x%x data_len=%d", + LOCAL_PR_ARG, __entry->vendor_id, __entry->subcmd, + __entry->data_len) + ); + TRACE_EVENT(llhw_event_rx_error, TP_PROTO(const struct mcps802154_local *local, enum mcps802154_rx_error_type error), diff --git a/mac/fproc_vendor.c b/mac/fproc_vendor.c index 0875cb5..f4441d7 100644 --- a/mac/fproc_vendor.c +++ b/mac/fproc_vendor.c @@ -34,13 +34,14 @@ mcps802154_fproc_vendor_handle_callback_return(struct mcps802154_local *local, * Avoid usage of access pointer after access done call. */ int duration_dtu = access->duration_dtu; u32 next_access_dtu = access->timestamp_dtu + duration_dtu; + /* Filter-out the 'stop' request as error. */ + int error = r == 1 ? 0 : r; if (!r) - /* TODO_MR : call access_done(false) ?? */ return; - mcps802154_fproc_access_done(local, r); - if (r != 1) { + mcps802154_fproc_access_done(local, error); + if (error) { mcps802154_fproc_broken_handle(local); } else if (duration_dtu) { mcps802154_fproc_access(local, next_access_dtu); diff --git a/mac/llhw-ops.h b/mac/llhw-ops.h index eadb52f..fb6aefe 100644 --- a/mac/llhw-ops.h +++ b/mac/llhw-ops.h @@ -28,7 +28,6 @@ #include "mcps802154_i.h" #include "trace.h" -#include "nfcc_coex_trace.h" static inline int llhw_start(struct mcps802154_local *local) { @@ -311,13 +310,13 @@ static inline int llhw_vendor_cmd(struct mcps802154_local *local, u32 vendor_id, { int r; - trace_nfcc_coex_llhw_vendor_cmd(local, vendor_id, subcmd); + trace_llhw_vendor_cmd(local, vendor_id, subcmd, data_len); if (local->ops->vendor_cmd) r = local->ops->vendor_cmd(&local->llhw, vendor_id, subcmd, data, data_len); else r = -EOPNOTSUPP; - trace_nfcc_coex_llhw_return_int(local, r); + trace_llhw_return_int(local, r); return r; } diff --git a/mac/mcps802154_qorvo.h b/mac/mcps802154_qorvo.h new file mode 100644 index 0000000..170ea06 --- /dev/null +++ b/mac/mcps802154_qorvo.h @@ -0,0 +1,32 @@ +/* + * This file is part of the UWB stack for linux. + * + * Copyright (c) 2021 Qorvo US, Inc. + * + * This software is provided under the GNU General Public License, version 2 + * (GPLv2), as well as under a Qorvo commercial license. + * + * You may choose to use this software under the terms of the GPLv2 License, + * version 2 ("GPLv2"), as published by the Free Software Foundation. + * You should have received a copy of the GPLv2 along with this program. If + * not, see <http://www.gnu.org/licenses/>. + * + * This program is distributed under the GPLv2 in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GPLv2 for more + * details. + * + * If you cannot meet the requirements of the GPLv2, you may not use this + * software for any purpose without first obtaining a commercial license from + * Qorvo. Please contact Qorvo to inquire about licensing terms. + */ + +#ifndef MCPS802154_QORVO_H +#define MCPS802154_QORVO_H + +/* Qorvo OUI in big endian. + * The define can't be declared in include/net/vendor_cmd.h because + * it's not generic to other mac provider. */ +#define VENDOR_QORVO_OUI 0xc8b1ee00 + +#endif /* MCPS802154_QORVO_H */ diff --git a/mac/mcps_main.c b/mac/mcps_main.c index fc09787..cc992b9 100644 --- a/mac/mcps_main.c +++ b/mac/mcps_main.c @@ -227,6 +227,15 @@ s64 mcps802154_difference_timestamp_rctu(struct mcps802154_llhw *llhw, } EXPORT_SYMBOL(mcps802154_difference_timestamp_rctu); +int mcps802154_vendor_cmd(struct mcps802154_llhw *llhw, u32 vendor_id, + u32 subcmd, void *data, size_t data_len) +{ + struct mcps802154_local *local = llhw_to_local(llhw); + + return llhw_vendor_cmd(local, vendor_id, subcmd, data, data_len); +} +EXPORT_SYMBOL(mcps802154_vendor_cmd); + struct mcps802154_local *mcps802154_get_first_by_idx(int hw_idx) { struct mcps802154_local *result = NULL, *local; diff --git a/mac/nfcc_coex_access.c b/mac/nfcc_coex_access.c index bd4f90a..e9617ae 100644 --- a/mac/nfcc_coex_access.c +++ b/mac/nfcc_coex_access.c @@ -24,7 +24,9 @@ #include "nfcc_coex_access.h" #include "nfcc_coex_session.h" #include "nfcc_coex_region.h" +#include "nfcc_coex_trace.h" #include "llhw-ops.h" +#include "mcps802154_qorvo.h" #include <linux/string.h> #include <linux/ieee802154.h> @@ -33,47 +35,38 @@ #include "warn_return.h" -static void nfcc_coex_stop_by_vendor_cmd_failure(struct nfcc_coex_local *local) -{ - static const struct dw3000_vendor_cmd_nfcc_coex_get_access_info error = { - .stop = 1 - }; - - local->session.get_access_info = error; - local->state = NFCC_COEX_STATE_STOPPING; -} - -static int nfcc_coex_vendor_cmd(struct mcps802154_llhw *llhw, - enum dw3000_vendor_cmd subcmd, void *data, - size_t data_len) -{ - struct mcps802154_local *local = llhw_to_local(llhw); - /* Qorvo OUI in big endian. */ - static const u32 qorvo_oui = 0xc8b1ee00; - - return llhw_vendor_cmd(local, qorvo_oui, subcmd, data, data_len); -} - static void nfcc_coex_access_done(struct mcps802154_access *access, int error) { struct nfcc_coex_local *local = access_to_local(access); struct nfcc_coex_session *session = &local->session; - switch (local->state) { + if (error) { + const struct dw3000_vendor_cmd_nfcc_coex_get_access_info stop = { + .stop = true, + }; + + local->session.get_access_info = stop; + nfcc_coex_set_state(local, NFCC_COEX_STATE_STOPPING); + } + + switch (session->state) { case NFCC_COEX_STATE_STOPPING: - nfcc_coex_vendor_cmd(local->llhw, - DW3000_VENDOR_CMD_NFCC_COEX_STOP, NULL, 0); + mcps802154_vendor_cmd(local->llhw, VENDOR_QORVO_OUI, + DW3000_VENDOR_CMD_NFCC_COEX_STOP, NULL, + 0); nfcc_coex_report(local); + session->started = false; break; case NFCC_COEX_STATE_ACCESSING: if (session->get_access_info.stop || session->get_access_info.watchdog_timeout) - local->state = NFCC_COEX_STATE_STOPPING; + session->started = false; nfcc_coex_report(local); break; default: WARN_UNREACHABLE_DEFAULT(); } + nfcc_coex_set_state(local, NFCC_COEX_STATE_IDLE); } static int nfcc_coex_handle(struct mcps802154_access *access) @@ -81,21 +74,18 @@ static int nfcc_coex_handle(struct mcps802154_access *access) struct nfcc_coex_local *local = access_to_local(access); struct nfcc_coex_session *session = &local->session; struct dw3000_vendor_cmd_nfcc_coex_handle_access handle_access = {}; - int r; handle_access.start = session->first_access; handle_access.timestamp_dtu = access->timestamp_dtu; handle_access.duration_dtu = access->duration_dtu; handle_access.chan = session->params.channel_number; + nfcc_coex_set_state(local, NFCC_COEX_STATE_ACCESSING); session->first_access = false; - r = nfcc_coex_vendor_cmd(local->llhw, - DW3000_VENDOR_CMD_NFCC_COEX_HANDLE_ACCESS, - &handle_access, sizeof(handle_access)); - if (r) - nfcc_coex_stop_by_vendor_cmd_failure(local); - return r; + return mcps802154_vendor_cmd(local->llhw, VENDOR_QORVO_OUI, + DW3000_VENDOR_CMD_NFCC_COEX_HANDLE_ACCESS, + &handle_access, sizeof(handle_access)); } static int nfcc_coex_tx_done(struct mcps802154_access *access) @@ -107,17 +97,16 @@ static int nfcc_coex_tx_done(struct mcps802154_access *access) struct mcps802154_region_demand *rd = &session->region_demand; int r; - r = nfcc_coex_vendor_cmd( - local->llhw, DW3000_VENDOR_CMD_NFCC_COEX_GET_ACCESS_INFORMATION, + r = mcps802154_vendor_cmd( + local->llhw, VENDOR_QORVO_OUI, + DW3000_VENDOR_CMD_NFCC_COEX_GET_ACCESS_INFORMATION, get_access_info, sizeof(*get_access_info)); - if (r) { - nfcc_coex_stop_by_vendor_cmd_failure(local); + if (r) return r; - } + /* Update region demand for next access. */ rd->timestamp_dtu = get_access_info->next_timestamp_dtu; rd->duration_dtu = get_access_info->next_duration_dtu; - /* Request end of current access. */ return 1; } @@ -135,11 +124,12 @@ nfcc_coex_access_controller(struct nfcc_coex_local *local, struct nfcc_coex_session *session) { struct mcps802154_access *access = &local->access; + const struct mcps802154_region_demand *rd = &session->region_demand; access->method = MCPS802154_ACCESS_METHOD_VENDOR; access->vendor_ops = &nfcc_coex_ops; - access->duration_dtu = session->region_demand.duration_dtu; - access->timestamp_dtu = session->region_demand.timestamp_dtu; + access->duration_dtu = rd->duration_dtu; + access->timestamp_dtu = rd->timestamp_dtu; access->n_frames = 0; access->frames = NULL; @@ -152,17 +142,12 @@ struct mcps802154_access *nfcc_coex_get_access(struct mcps802154_region *region, int region_duration_dtu) { struct nfcc_coex_local *local = region_to_local(region); - struct nfcc_coex_session *session; + struct nfcc_coex_session *session = &local->session; - /* Get unique session. */ - session = nfcc_coex_session_next(local, next_timestamp_dtu, + if (session->started) { + nfcc_coex_session_update(session, next_timestamp_dtu, region_duration_dtu); - - if (!session) { - local->state = NFCC_COEX_STATE_UNUSED; - return NULL; - } else { - local->state = NFCC_COEX_STATE_ACCESSING; return nfcc_coex_access_controller(local, session); } + return NULL; } diff --git a/mac/nfcc_coex_region.c b/mac/nfcc_coex_region.c index 719b7de..786aa26 100644 --- a/mac/nfcc_coex_region.c +++ b/mac/nfcc_coex_region.c @@ -36,6 +36,7 @@ #include "nfcc_coex_region_call.h" #include "nfcc_coex_access.h" #include "nfcc_coex_session.h" +#include "nfcc_coex_trace.h" static struct mcps802154_region_ops nfcc_coex_region_ops; @@ -43,13 +44,13 @@ static struct mcps802154_region *nfcc_coex_open(struct mcps802154_llhw *llhw) { struct nfcc_coex_local *local; - local = kmalloc(sizeof(*local), GFP_KERNEL); + local = kzalloc(sizeof(*local), GFP_KERNEL); if (!local) return NULL; local->llhw = llhw; local->region.ops = &nfcc_coex_region_ops; - local->state = NFCC_COEX_STATE_UNUSED; + local->session.state = NFCC_COEX_STATE_IDLE; return &local->region; } @@ -64,13 +65,15 @@ static void nfcc_coex_close(struct mcps802154_region *region) static void nfcc_coex_notify_stop(struct mcps802154_region *region) { struct nfcc_coex_local *local = region_to_local(region); + struct nfcc_coex_session *session = &local->session; + trace_region_nfcc_coex_notify_stop(local); nfcc_coex_session_control(local, NFCC_COEX_CALL_CCC_SESSION_STOP, NULL, NULL); - if (local->state != NFCC_COEX_STATE_UNUSED) { + if (session->started) { pr_err("device stopped while nfcc coex not stopped state=%d", - local->state); - local->state = NFCC_COEX_STATE_UNUSED; + local->session.state); + session->started = false; } } @@ -80,6 +83,7 @@ static int nfcc_coex_call(struct mcps802154_region *region, u32 call_id, { struct nfcc_coex_local *local = region_to_local(region); + trace_region_nfcc_coex_call(local, call_id); switch (call_id) { case NFCC_COEX_CALL_CCC_SESSION_START: case NFCC_COEX_CALL_CCC_SESSION_STOP: @@ -95,34 +99,39 @@ static int nfcc_coex_get_demand(struct mcps802154_region *region, { struct nfcc_coex_local *local = region_to_local(region); const struct nfcc_coex_session *session = &local->session; + const struct mcps802154_region_demand *rd = &session->region_demand; - switch (local->state) { - case NFCC_COEX_STATE_UNUSED: - return 0; - default: + trace_region_nfcc_coex_get_demand(local, next_timestamp_dtu, rd); + if (session->started) { if (session->first_access) { /* region_demand have never been set. * Duration is set at 12ms, value catched during test. */ demand->timestamp_dtu = next_timestamp_dtu; demand->duration_dtu = 187200; - } else if (is_before_dtu(session->region_demand.timestamp_dtu, + } else if (is_before_dtu(rd->timestamp_dtu, next_timestamp_dtu)) { /* Date is late. */ - int shift = next_timestamp_dtu - - session->region_demand.timestamp_dtu; - int duration = - session->region_demand.duration_dtu - shift; + int shift = next_timestamp_dtu - rd->timestamp_dtu; + int duration = rd->duration_dtu - shift; demand->timestamp_dtu = next_timestamp_dtu; demand->duration_dtu = duration > 0 ? duration : 1; } else { - memcpy(demand, &session->region_demand, - sizeof(*demand)); + memcpy(demand, rd, sizeof(*demand)); } return 1; } return 0; } +void nfcc_coex_set_state(struct nfcc_coex_local *local, + enum nfcc_coex_state new_state) +{ + struct nfcc_coex_session *session = &local->session; + + trace_region_nfcc_coex_set_state(local, new_state); + session->state = new_state; +} + void nfcc_coex_report(struct nfcc_coex_local *local) { struct nfcc_coex_session *session = &local->session; @@ -131,6 +140,7 @@ void nfcc_coex_report(struct nfcc_coex_local *local) struct sk_buff *msg; int r; + trace_region_nfcc_coex_report(local, get_access_info); msg = mcps802154_region_event_alloc_skb( local->llhw, &local->region, NFCC_COEX_CALL_CCC_SESSION_NOTIFICATION, session->event_portid, @@ -157,6 +167,7 @@ void nfcc_coex_report(struct nfcc_coex_local *local) return; nla_put_failure: + trace_region_nfcc_coex_report_nla_put_failure(local); kfree_skb(msg); } diff --git a/mac/nfcc_coex_region.h b/mac/nfcc_coex_region.h index f39d9a0..b9828df 100644 --- a/mac/nfcc_coex_region.h +++ b/mac/nfcc_coex_region.h @@ -29,24 +29,6 @@ #include "nfcc_coex_session.h" /** - * enum nfcc_coex_state - State of the unique session. - * @NFCC_COEX_STATE_UNUSED: - * Session is unused by access and not started too. - * @NFCC_COEX_STATE_STARTED: - * Session is started but not used by access right now. - * @NFCC_COEX_STATE_ACCESSING: - * Session is currently used on an access. - * @NFCC_COEX_STATE_STOPPING: - * Session is currently used for the last access. - */ -enum nfcc_coex_state { - NFCC_COEX_STATE_UNUSED, - NFCC_COEX_STATE_STARTED, - NFCC_COEX_STATE_ACCESSING, - NFCC_COEX_STATE_STOPPING, -}; - -/** * struct nfcc_coex_local - Local context. */ struct nfcc_coex_local { @@ -66,10 +48,6 @@ struct nfcc_coex_local { * @session: Unique session on the NFCC controller. */ struct nfcc_coex_session session; - /** - * @state: State of the unique session. - */ - enum nfcc_coex_state state; }; static inline struct nfcc_coex_local * @@ -85,6 +63,14 @@ access_to_local(struct mcps802154_access *access) } /** + * nfcc_coex_set_state() - Set the new state. + * @local: NFCC coex context. + * @new_state: New nfcc_coex state. + */ +void nfcc_coex_set_state(struct nfcc_coex_local *local, + enum nfcc_coex_state new_state); + +/** * nfcc_coex_report() - Send notification to upper layer. * @local: Local nfcc coex context. */ diff --git a/mac/nfcc_coex_region_call.c b/mac/nfcc_coex_region_call.c index 5d310d4..f207006 100644 --- a/mac/nfcc_coex_region_call.c +++ b/mac/nfcc_coex_region_call.c @@ -29,6 +29,7 @@ #include "nfcc_coex_session.h" #include "nfcc_coex_region_call.h" +#include "nfcc_coex_trace.h" static const struct nla_policy nfcc_coex_call_nla_policy[NFCC_COEX_CALL_ATTR_MAX + 1] = { @@ -92,27 +93,27 @@ static int nfcc_coex_session_start(struct nfcc_coex_local *local, const struct genl_info *info) { struct nfcc_coex_session *session = &local->session; + const struct nfcc_coex_session_params *p = &session->params; int initiation_time_dtu; u32 now_dtu; int r; - WARN_ON(local->state != NFCC_COEX_STATE_UNUSED); + WARN_ON(session->started); + trace_region_nfcc_coex_session_start(local, p); r = mcps802154_get_current_timestamp_dtu(local->llhw, &now_dtu); if (r) return r; initiation_time_dtu = - (session->params.time0_ns * local->llhw->dtu_freq_hz) / - NS_PER_SECOND; + (p->time0_ns * local->llhw->dtu_freq_hz) / NS_PER_SECOND; session->region_demand.timestamp_dtu = now_dtu + initiation_time_dtu; session->region_demand.duration_dtu = 0; session->event_portid = info->snd_portid; session->first_access = true; - local->state = NFCC_COEX_STATE_STARTED; + session->started = true; mcps802154_reschedule(local->llhw); - return 0; } @@ -139,7 +140,7 @@ static int nfcc_coex_session_start_all(struct nfcc_coex_local *local, if (r) return r; - if (local->state != NFCC_COEX_STATE_UNUSED) + if (local->session.started) return -EBUSY; nfcc_coex_session_init(local); @@ -164,17 +165,23 @@ static int nfcc_coex_session_start_all(struct nfcc_coex_local *local, */ static int nfcc_coex_session_stop(struct nfcc_coex_local *local) { - switch (local->state) { - case NFCC_COEX_STATE_STARTED: - local->state = NFCC_COEX_STATE_UNUSED; - break; - case NFCC_COEX_STATE_ACCESSING: - /* The transition from ACCESSING to UNUSED will be done - * in nfcc_coex_get_access function. */ - local->state = NFCC_COEX_STATE_STOPPING; - break; - default: - break; + struct nfcc_coex_session *session = &local->session; + + trace_region_nfcc_coex_session_stop(local); + + if (session->started) { + switch (session->state) { + case NFCC_COEX_STATE_IDLE: + session->started = false; + break; + case NFCC_COEX_STATE_ACCESSING: + /* The transition from ACCESSING to UNUSED will be done + * in nfcc_coex_get_access function. */ + nfcc_coex_set_state(local, NFCC_COEX_STATE_STOPPING); + break; + default: + break; + } } return 0; diff --git a/mac/nfcc_coex_session.c b/mac/nfcc_coex_session.c index 7f6d9e1..e84ef1c 100644 --- a/mac/nfcc_coex_session.c +++ b/mac/nfcc_coex_session.c @@ -37,9 +37,8 @@ void nfcc_coex_session_init(struct nfcc_coex_local *local) local->llhw->dtu_freq_hz; } -static void nfcc_coex_session_update(struct nfcc_coex_session *session, - u32 next_timestamp_dtu, - int region_duration_dtu) +void nfcc_coex_session_update(struct nfcc_coex_session *session, + u32 next_timestamp_dtu, int region_duration_dtu) { s32 diff_dtu = session->region_demand.timestamp_dtu - next_timestamp_dtu; @@ -63,24 +62,3 @@ static void nfcc_coex_session_update(struct nfcc_coex_session *session, #endif } } - -struct nfcc_coex_session *nfcc_coex_session_next(struct nfcc_coex_local *local, - u32 next_timestamp_dtu, - int region_duration_dtu) -{ - struct nfcc_coex_session *session; - - switch (local->state) { - case NFCC_COEX_STATE_STARTED: - case NFCC_COEX_STATE_ACCESSING: - /* Get unique session. */ - session = &local->session; - - nfcc_coex_session_update(session, next_timestamp_dtu, - region_duration_dtu); - return session; - - default: - return NULL; - } -} diff --git a/mac/nfcc_coex_session.h b/mac/nfcc_coex_session.h index 5106d5f..351b07f 100644 --- a/mac/nfcc_coex_session.h +++ b/mac/nfcc_coex_session.h @@ -45,6 +45,21 @@ struct nfcc_coex_session_params { }; /** + * enum nfcc_coex_state - State of the unique session. + * @NFCC_COEX_STATE_IDLE: + * Session is not used by access right now. + * @NFCC_COEX_STATE_ACCESSING: + * Session is currently used on an access. + * @NFCC_COEX_STATE_STOPPING: + * Session is currently used for the last access. + */ +enum nfcc_coex_state { + NFCC_COEX_STATE_IDLE, + NFCC_COEX_STATE_ACCESSING, + NFCC_COEX_STATE_STOPPING, +}; + +/** * struct nfcc_coex_session - Session information. */ struct nfcc_coex_session { @@ -69,6 +84,14 @@ struct nfcc_coex_session { * @first_access: True on the first access. */ bool first_access; + /** + * @state: State of the unique session. + */ + enum nfcc_coex_state state; + /** + * @started: Session is currently started. + */ + bool started; }; /* Forward declaration. */ @@ -81,15 +104,12 @@ struct nfcc_coex_local; void nfcc_coex_session_init(struct nfcc_coex_local *local); /** - * nfcc_coex_session_next() - Find the next session to use after the given timestamp. - * @local: NFCC coex context. + * nfcc_coex_session_update() - Update session timestamps. + * @session: Session context. * @next_timestamp_dtu: Next start access opportunity. * @region_duration_dtu: Region duration, or 0 for endless region. - * - * Return: The session or NULL if none. */ -struct nfcc_coex_session *nfcc_coex_session_next(struct nfcc_coex_local *local, - u32 next_timestamp_dtu, - int region_duration_dtu); +void nfcc_coex_session_update(struct nfcc_coex_session *session, + u32 next_timestamp_dtu, int region_duration_dtu); #endif /* NET_MCPS802154_NFCC_COEX_SESSION_H */ |