blob: 90588a8247bb84695b97cf642972fb511e6c5d5b [file] [log] [blame]
/*
* This file is part of the UWB stack for linux.
*
* Copyright (c) 2020-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.
*/
#include <linux/errno.h>
#include "mcps802154_i.h"
#include "llhw-ops.h"
static void
mcps802154_fproc_rx_wait_tx_done_tx_done(struct mcps802154_local *local)
{
/* End current access and ask for next one. */
mcps802154_fproc_access_done(local, 0);
mcps802154_fproc_access_now(local);
}
static void
mcps802154_fproc_rx_wait_tx_done_schedule_change(struct mcps802154_local *local)
{
/* Nothing, wait for tx_done. */
}
static const struct mcps802154_fproc_state mcps802154_fproc_rx_wait_tx_done = {
.name = "rx_wait_tx_done",
.tx_done = mcps802154_fproc_rx_wait_tx_done_tx_done,
.schedule_change = mcps802154_fproc_rx_wait_tx_done_schedule_change,
};
static void mcps802154_fproc_rx_rx_frame(struct mcps802154_local *local)
{
struct mcps802154_access *access = local->fproc.access;
int r;
/* Read frame. */
struct sk_buff *skb = NULL;
struct mcps802154_rx_frame_info info = {
.flags = MCPS802154_RX_FRAME_INFO_LQI,
};
r = llhw_rx_get_frame(local, &skb, &info);
if (!r) {
access->ops->rx_frame(access, 0, skb, &info,
MCPS802154_RX_ERROR_NONE);
/* If auto-ack was sent, wait for tx_done. */
if (info.flags & MCPS802154_RX_FRAME_INFO_AACK) {
mcps802154_fproc_change_state(
local, &mcps802154_fproc_rx_wait_tx_done);
return;
}
}
mcps802154_fproc_access_done(local, r);
if (r && r != -EBUSY)
mcps802154_fproc_broken_handle(local);
else
/* Next access. */
mcps802154_fproc_access_now(local);
}
static void mcps802154_fproc_rx_rx_error(struct mcps802154_local *local,
enum mcps802154_rx_error_type error)
{
mcps802154_fproc_access_done(local, -EINVAL);
/* Next access. */
mcps802154_fproc_access_now(local);
}
static void mcps802154_fproc_rx_schedule_change(struct mcps802154_local *local)
{
int r;
/* Disable RX. */
r = llhw_rx_disable(local);
if (r == -EBUSY)
/* Wait for RX result. */
return;
mcps802154_fproc_access_done(local, r);
if (r)
mcps802154_fproc_broken_handle(local);
else
/* Next access. */
mcps802154_fproc_access_now(local);
}
static const struct mcps802154_fproc_state mcps802154_fproc_rx = {
.name = "rx",
.rx_frame = mcps802154_fproc_rx_rx_frame,
.rx_error = mcps802154_fproc_rx_rx_error,
.schedule_change = mcps802154_fproc_rx_schedule_change,
};
int mcps802154_fproc_rx_handle(struct mcps802154_local *local,
struct mcps802154_access *access)
{
int r;
struct mcps802154_rx_info rx_info = {
.flags = MCPS802154_RX_INFO_AACK,
.timeout_dtu = -1,
};
r = llhw_rx_enable(local, &rx_info, 0, 0);
if (r)
return r;
mcps802154_fproc_change_state(local, &mcps802154_fproc_rx);
return 0;
}