summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Peng <robinpeng@google.com>2022-01-03 20:37:41 +0800
committerRobin Peng <robinpeng@google.com>2022-01-03 20:37:41 +0800
commitd474bf434118bad9b1a50443f83903855e957cf9 (patch)
treeb6260b143585757cd228299cb528615702efc40a
parent37ee17be9f111fdfec7ac7b78dcad3f443bdd3f5 (diff)
parent5fed2939baec67591b027360fe409fea7335fe20 (diff)
downloaduwb-android-gs-raviole-5.10-t-preview-2.tar.gz
Bug: 211546634 Signed-off-by: Robin Peng <robinpeng@google.com> Change-Id: If50ae8cb59800e03bc11ab41ca01c90db3b9cc63
-rw-r--r--kernel/drivers/net/ieee802154/dw3000.h32
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_core.c292
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_core.h8
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_mcps.c54
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_nfcc_coex.h4
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.c110
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_nfcc_coex_core.h4
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_nfcc_coex_mcps.c32
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_spi.c8
-rw-r--r--kernel/drivers/net/ieee802154/dw3000_trc.h132
l---------kernel/net/mcps802154/mcps802154_qorvo.h1
-rw-r--r--kernel/net/mcps802154/nfcc_coex_trace.h189
-rw-r--r--kernel/net/mcps802154/trace.h21
-rw-r--r--mac/fproc_vendor.c7
-rw-r--r--mac/llhw-ops.h5
-rw-r--r--mac/mcps802154_qorvo.h32
-rw-r--r--mac/mcps_main.c9
-rw-r--r--mac/nfcc_coex_access.c83
-rw-r--r--mac/nfcc_coex_region.c43
-rw-r--r--mac/nfcc_coex_region.h30
-rw-r--r--mac/nfcc_coex_region_call.c41
-rw-r--r--mac/nfcc_coex_session.c26
-rw-r--r--mac/nfcc_coex_session.h34
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 */