blob: 6038d094bbfe16b9a20b023c01aeebbdc4ee35dc [file] [log] [blame]
/*
* This file is part of the UWB stack for linux.
*
* Copyright (c) 2020-2022 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 NET_FIRA_REGION_H
#define NET_FIRA_REGION_H
#include <linux/kernel.h>
#include <linux/workqueue.h>
#include <linux/math64.h>
#include <net/mcps802154_schedule.h>
#include "net/fira_region_params.h"
#define FIRA_SLOT_DURATION_RSTU_DEFAULT 2400
#define FIRA_BLOCK_DURATION_MS_DEFAULT 200
#define FIRA_ROUND_DURATION_SLOTS_DEFAULT 30
#define FIRA_MAX_RR_RETRY_DEFAULT 0
#define FIRA_PRIORITY_MAX 100
#define FIRA_PRIORITY_DEFAULT 50
#define FIRA_IN_BAND_TERMINATION_ATTEMPT_COUNT_MAX 10
#define FIRA_IN_BAND_TERMINATION_ATTEMPT_COUNT_MIN 1
#define FIRA_BOOLEAN_MAX 1
#define FIRA_BLOCK_STRIDE_LEN_MAX 255
#define FIRA_FRAMES_MAX (3 + 3 * FIRA_CONTROLEES_MAX)
#define FIRA_CONTROLEE_FRAMES_MAX (3 + 3 + 1)
/* IEEE 802.15.4z 2020 section 6.9.7.2 */
#define UWB_BLOCK_DURATION_MARGIN_PPM 100
/* FiRa Tx should arrive between 0 and 10 us, always add 2 us. */
#define FIRA_TX_MARGIN_US 2
/*
* FIRA_SESSION_DATA_NTF_LOWER_/UPPER_BOUND_AOA min/max :
* Azimuth in rad_2pi_q16 : -32768 / 32767 (equal to -180 / ~180 degrees)
* Elevation in rad_2pi_q16 : -16384 / 16384 (equal to -90 / 90 degrees)
*/
#define FIRA_SESSION_DATA_NTF_LOWER_BOUND_AOA_AZIMUTH_2PI_MIN -32768
#define FIRA_SESSION_DATA_NTF_LOWER_BOUND_AOA_AZIMUTH_2PI_MAX 32767
#define FIRA_SESSION_DATA_NTF_UPPER_BOUND_AOA_AZIMUTH_2PI_MIN -32768
#define FIRA_SESSION_DATA_NTF_UPPER_BOUND_AOA_AZIMUTH_2PI_MAX 32767
#define FIRA_SESSION_DATA_NTF_LOWER_BOUND_AOA_ELEVATION_2PI_MIN -16384
#define FIRA_SESSION_DATA_NTF_LOWER_BOUND_AOA_ELEVATION_2PI_MAX 16384
#define FIRA_SESSION_DATA_NTF_UPPER_BOUND_AOA_ELEVATION_2PI_MIN -16384
#define FIRA_SESSION_DATA_NTF_UPPER_BOUND_AOA_ELEVATION_2PI_MAX 16384
/**
* enum fira_message_id - Message identifiers, used in internal state and in
* messages.
* @FIRA_MESSAGE_ID_RANGING_INITIATION: Initial ranging message.
* @FIRA_MESSAGE_ID_RANGING_RESPONSE: Response ranging message.
* @FIRA_MESSAGE_ID_RANGING_FINAL: Final ranging message, only for DS-TWR.
* @FIRA_MESSAGE_ID_CONTROL: Control message, sent by the controller.
* @FIRA_MESSAGE_ID_MEASUREMENT_REPORT: Deferred report of ranging measures.
* @FIRA_MESSAGE_ID_RESULT_REPORT: Report computed ranging result.
* @FIRA_MESSAGE_ID_CONTROL_UPDATE: Message to change hopping.
* @FIRA_MESSAGE_ID_RFRAME_MAX: Maximum identifier of message transmitted using
* an RFRAME.
* @FIRA_MESSAGE_ID_MAX: Maximum message identifier.
*/
enum fira_message_id {
FIRA_MESSAGE_ID_RANGING_INITIATION = 0,
FIRA_MESSAGE_ID_RANGING_RESPONSE = 1,
FIRA_MESSAGE_ID_RANGING_FINAL = 2,
FIRA_MESSAGE_ID_CONTROL = 3,
FIRA_MESSAGE_ID_MEASUREMENT_REPORT = 4,
FIRA_MESSAGE_ID_RESULT_REPORT = 5,
FIRA_MESSAGE_ID_CONTROL_UPDATE = 6,
FIRA_MESSAGE_ID_RFRAME_MAX = FIRA_MESSAGE_ID_RANGING_FINAL,
FIRA_MESSAGE_ID_MAX = FIRA_MESSAGE_ID_CONTROL_UPDATE,
};
/**
* struct fira_diagnostic - Diagnostic result.
*/
struct fira_diagnostic {
/**
* @rssis_q1: Received signal strength indication (RSSI), absolute value
* in Q1 fixed point format, unit is dBm.
*/
u8 rssis_q1[MCPS802154_RSSIS_N_MAX];
/**
* @n_rssis: The number of RSSI in the array below.
*/
size_t n_rssis;
/**
* @aoas: Angle of arrival, ordered by increasing measurement type.
*/
struct mcps802154_rx_aoa_measurements
aoas[MCPS802154_RX_AOA_MEASUREMENTS_MAX];
/**
* @n_aoas: Number of angle of arrival.
*/
size_t n_aoas;
/**
* @cirs: CIR for different parts of the frame.
*
* Set by low-level driver, must be kept valid until next received
* frame.
*/
struct mcps802154_rx_cir *cirs;
/**
* @n_cirs: Number of parts of CIR.
*/
size_t n_cirs;
};
/**
* struct fira_slot - Information on an active slot.
*/
struct fira_slot {
/**
* @index: Index of this slot, add it to the block STS index to get the
* slot STS index. Note: there can be holes for a controlee as only
* relevant slots are recorded.
*/
int index;
/**
* @controller_tx: True if Tx is performed by the controller.
*/
bool controller_tx;
/**
* @ranging_index: Index of the ranging in the ranging information
* table, -1 if none.
*/
int ranging_index;
/**
* @message_id: Identifier of the message exchanged in this slot.
*/
enum fira_message_id message_id;
/**
* @tx_ant_set: Tx antenna set.
*/
int tx_ant_set;
/**
* @rx_ant_set: Rx antenna set.
*/
int rx_ant_set;
/**
* @controlee: Controlee.
*/
struct fira_controlee *controlee;
};
/**
* struct fira_local_aoa_info - Ranging AoA information.
*/
struct fira_local_aoa_info {
/**
* @pdoa_2pi: Phase Difference of Arrival.
*/
s16 pdoa_2pi;
/**
* @aoa_2pi: Angle of Arrival.
*/
s16 aoa_2pi;
/**
* @aoa_fom: Figure of merit of the AoA.
*/
u8 aoa_fom;
/**
* @rx_ant_set: Antenna set index.
*/
u8 rx_ant_set;
/**
* @present: true if AoA information is present.
*/
bool present;
};
/**
* enum fira_range_data_ntf_status - Device (controller or controlee)
* status, used for range_data_ntf.
* @FIRA_RANGE_DATA_NTF_NONE: Undetermined, no ranging data for this
* device yet, or N/A (not applicable).
* @FIRA_RANGE_DATA_NTF_IN: Last ranging data for this device
* were inside given boudaries.
* @FIRA_RANGE_DATA_NTF_OUT: Last ranging data for this device
* were outside given boudaries.
* @FIRA_RANGE_DATA_NTF_ERROR: Last ranging round(s) for this device
* failed (timeout, error, ...). No info about a previous state or N/A.
* @FIRA_RANGE_DATA_NTF_IN_ERROR: Last ranging round(s) for this device
* failed (timeout, error, ...). Previous data were inside given boudaries.
* @FIRA_RANGE_DATA_NTF_OUT_ERROR: Last ranging round(s) for this device
* failed (timeout, error, ...). Previous data were inside given boudaries.
*/
enum fira_range_data_ntf_status {
FIRA_RANGE_DATA_NTF_NONE,
FIRA_RANGE_DATA_NTF_IN,
FIRA_RANGE_DATA_NTF_OUT,
FIRA_RANGE_DATA_NTF_ERROR,
FIRA_RANGE_DATA_NTF_IN_ERROR,
FIRA_RANGE_DATA_NTF_OUT_ERROR,
};
/**
* struct fira_ranging_info - Ranging information.
*/
struct fira_ranging_info {
/**
* @timestamps_rctu: Timestamps of the ranging messages.
*/
u64 timestamps_rctu[FIRA_MESSAGE_ID_RFRAME_MAX + 1];
/**
* @tof_rctu: Computed Time of Flight.
*/
int tof_rctu;
/**
* @local_aoa: Local ranging AoA information.
*/
struct fira_local_aoa_info local_aoa;
/**
* @local_aoa_azimuth: Azimuth ranging AoA information.
*/
struct fira_local_aoa_info local_aoa_azimuth;
/**
* @local_aoa_elevation: Elevation ranging AoA information.
*/
struct fira_local_aoa_info local_aoa_elevation;
/**
* @remote_aoa_azimuth_2pi: Remote azimuth AoA.
*/
s16 remote_aoa_azimuth_2pi;
/**
* @remote_aoa_elevation_pi: Remote elevation AoA.
*/
s16 remote_aoa_elevation_pi;
/**
* @remote_aoa_azimuth_fom: Remote azimuth FoM.
*/
u8 remote_aoa_azimuth_fom;
/**
* @remote_aoa_elevation_fom: Remote elevation FoM.
*/
u8 remote_aoa_elevation_fom;
/**
* @rx_rssis: RSSI value measured for individual Rx frames.
*/
u8 rx_rssis[FIRA_MESSAGE_ID_MAX + 1];
/**
* @n_rx_rssis: Number of Rx RSSI saved.
*/
int n_rx_rssis;
/**
* @short_addr: Peer short address.
*/
__le16 short_addr;
/**
* @status: Success or failure reason.
*/
enum fira_ranging_status status;
/**
* @slot_index: In case of failure, the slot index where it has occured.
*/
u8 slot_index;
/**
* @tof_present: true if time of flight information is present.
*/
bool tof_present;
/**
* @remote_aoa_azimuth_present: true if azimuth AoA information is present.
*/
bool remote_aoa_azimuth_present;
/**
* @remote_aoa_elevation_present: true if elevation AoA information is present.
*/
bool remote_aoa_elevation_present;
/**
* @remote_aoa_fom_present: true if FoM AoA is present.
*/
bool remote_aoa_fom_present;
/**
* @clock_offset_present: true if the driver provided clock_offset info.
*/
bool clock_offset_present;
/**
* @clock_offset_q26: clock offset value, as signed Q26, if present.
*/
s16 clock_offset_q26;
/**
* @data_payload: Custom data payload.
*/
u8 data_payload[FIRA_DATA_PAYLOAD_SIZE_MAX];
/**
* @data_payload_len: Custom data payload length.
*/
int data_payload_len;
/**
* @rx_ctx: Pointer to the current rx_ctx context controlee.
*/
void *rx_ctx;
/**
* @range_data_ntf_status: range_data_ntf status of the remote device.
*/
enum fira_range_data_ntf_status range_data_ntf_status;
/**
* @notify: if true, add this ranging to the notification report.
*/
bool notify;
};
/**
* struct fira_local - Local context.
*/
struct fira_local {
/**
* @region: Region instance returned to MCPS.
*/
struct mcps802154_region region;
/**
* @llhw: Low-level device pointer.
*/
struct mcps802154_llhw *llhw;
/**
* @access: Access returned to MCPS.
*/
struct mcps802154_access access;
/**
* @report_queue: Queue of report frame to be processed.
*/
struct sk_buff_head report_queue;
/**
* @report_work: Process work of report event.
*/
struct work_struct report_work;
/**
* @frames: Access frames referenced from access.
*/
struct mcps802154_access_frame frames[FIRA_FRAMES_MAX];
/**
* @sts_params: STS parameters for access frames.
*/
struct mcps802154_sts_params sts_params[FIRA_FRAMES_MAX];
/**
* @channel: Channel parameters for access.
*/
struct mcps802154_channel channel;
/**
* @inactive_sessions: List of inactive sessions.
*/
struct list_head inactive_sessions;
/**
* @active_sessions: List of active sessions.
*/
struct list_head active_sessions;
/**
* @current_session: Pointer to the current session.
*/
struct fira_session *current_session;
/**
* @src_short_addr: Source address for the current session (actually
* never put as a source address in a frame, but used for control
* message).
*/
__le16 src_short_addr;
/**
* @dst_short_addr: Destination address for the current session. When
* controller, this is broadcast or the address of the only controlee.
* When controlee, this is the address of the controller.
*/
__le16 dst_short_addr;
/**
* @block_duration_rx_margin_ppm: Block duration rx margin for
* controlees.
*/
int block_duration_rx_margin_ppm;
/**
* @slots: Descriptions of each active slots for the current session.
* When controller, this is filled when the access is requested. When
* controlee, the first slot is filled when the access is requested and
* the other slots are filled when the control message is received.
*/
struct fira_slot slots[FIRA_FRAMES_MAX];
/**
* @ranging_info: Information on ranging for the current session. Index
* in the table is determined by the order of the ranging messages.
* First ranging exchange is put at index 0. When a message is shared
* between several exchanges, its information is stored at index 0.
* Reset when access is requested.
*/
struct fira_ranging_info ranging_info[FIRA_CONTROLEES_MAX];
/**
* @n_ranging_info: Number of element in the ranging information table.
*/
int n_ranging_info;
/**
* @n_ranging_valid: Number of valid ranging in the current ranging
* information table.
*/
int n_ranging_valid;
/**
* @diagnostics: Diagnostic collected for each slot.
*/
struct fira_diagnostic diagnostics[FIRA_FRAMES_MAX];
/**
* @stopped_controlees: Short addresses of the stopped controlees for
* which an element must be added to the Device Management List of
* the control message.
*/
__le16 stopped_controlees[FIRA_CONTROLEES_MAX];
/**
* @n_stopped_controlees: Number of elements in the stopped controlees .
*/
int n_stopped_controlees;
};
static const s64 speed_of_light_mm_per_s = 299702547000ull;
static inline s64 fira_rctu_to_mm(s64 rctu_freq_hz, s32 rctu)
{
s64 temp = speed_of_light_mm_per_s * rctu + rctu_freq_hz / 2;
return div64_s64(temp, rctu_freq_hz);
}
static inline s64 fira_mm_to_rctu(struct fira_local *local, s32 mm)
{
s64 temp = (s64)mm * local->llhw->dtu_freq_hz * local->llhw->dtu_rctu +
speed_of_light_mm_per_s / 2;
return div64_s64(temp, speed_of_light_mm_per_s);
}
static inline struct fira_local *
region_to_local(struct mcps802154_region *region)
{
return container_of(region, struct fira_local, region);
}
static inline struct fira_local *
access_to_local(struct mcps802154_access *access)
{
return container_of(access, struct fira_local, access);
}
/**
* fira_get_session_by_session_id() - Get a session by its identifier.
* @local: FiRa context.
* @session_id: Session identifier.
*
* Return: The session or NULL if not found.
*/
struct fira_session *fira_get_session_by_session_id(struct fira_local *local,
u32 session_id);
/**
* fira_check_all_missed_ranging() - Check missed ranging round for all active
* session except the recent.
* @local: FiRa context.
* @recent_session: FiRa session to not check in active list.
* @timestamp_dtu: Timestamp used to trig (or not) a report of ranging failure.
*/
void fira_check_all_missed_ranging(struct fira_local *local,
const struct fira_session *recent_session,
u32 timestamp_dtu);
#endif /* NET_FIRA_REGION_H */