blob: 5b0f38f6d409c22204f3dcfd24e18a74cad3e90d [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 <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <net/mcps802154_schedule.h>
#include "endless_scheduler.h"
#include "warn_return.h"
struct mcps802154_private_local {
struct mcps802154_scheduler scheduler;
struct mcps802154_llhw *llhw;
struct mcps802154_region *region;
};
static inline struct mcps802154_private_local *
scheduler_to_plocal(const struct mcps802154_scheduler *scheduler)
{
return container_of(scheduler, struct mcps802154_private_local,
scheduler);
}
static struct mcps802154_scheduler *
mcps802154_endless_scheduler_open(struct mcps802154_llhw *llhw)
{
struct mcps802154_private_local *plocal;
plocal = kmalloc(sizeof(*plocal), GFP_KERNEL);
if (!plocal)
return NULL;
plocal->llhw = llhw;
plocal->region = NULL;
return &plocal->scheduler;
}
static void
mcps802154_endless_scheduler_close(struct mcps802154_scheduler *scheduler)
{
struct mcps802154_private_local *plocal =
scheduler_to_plocal(scheduler);
if (plocal->region)
mcps802154_region_close(plocal->llhw, plocal->region);
kfree(plocal);
}
static void
mcps802154_endless_scheduler_notify_stop(struct mcps802154_scheduler *scheduler)
{
struct mcps802154_private_local *plocal =
scheduler_to_plocal(scheduler);
if (plocal->region)
mcps802154_region_notify_stop(plocal->llhw, plocal->region);
}
static int mcps802154_endless_scheduler_set_region_parameters(
struct mcps802154_scheduler *scheduler, u32 region_id,
const char *region_name, const struct nlattr *attrs,
struct netlink_ext_ack *extack)
{
struct mcps802154_private_local *plocal =
scheduler_to_plocal(scheduler);
if (region_id != 0)
return -ENOENT;
/* Close current region. */
if (plocal->region)
mcps802154_region_close(plocal->llhw, plocal->region);
/* Open region, and set its parameters. */
plocal->region = mcps802154_region_open(plocal->llhw, region_name,
attrs, extack);
if (!plocal->region)
return -EINVAL;
return 0;
}
static int mcps802154_endless_scheduler_call_region(
struct mcps802154_scheduler *scheduler, u32 region_id,
const char *region_name, u32 call_id, const struct nlattr *attrs,
const struct genl_info *info)
{
struct mcps802154_private_local *plocal =
scheduler_to_plocal(scheduler);
if (!plocal->region)
return -ENOENT;
if (region_id != 0 || strcmp(region_name, plocal->region->ops->name))
return -EINVAL;
return mcps802154_region_call(plocal->llhw, plocal->region, call_id,
attrs, info);
}
static int mcps802154_endless_scheduler_update_schedule(
struct mcps802154_scheduler *scheduler,
const struct mcps802154_schedule_update *schedule_update,
u32 next_timestamp_dtu)
{
struct mcps802154_private_local *plocal =
scheduler_to_plocal(scheduler);
int r;
if (!plocal->region)
return -ENOENT;
r = mcps802154_schedule_set_start(
schedule_update, schedule_update->expected_start_timestamp_dtu);
/* Can not fail, only possible error is invalid parameters. */
WARN_RETURN(r);
r = mcps802154_schedule_recycle(schedule_update, 0,
MCPS802154_DURATION_NO_CHANGE);
/* Can not fail, only possible error is invalid parameters. */
WARN_RETURN(r);
r = mcps802154_schedule_add_region(schedule_update, plocal->region, 0,
0);
return r;
}
static struct mcps802154_scheduler_ops mcps802154_endless_scheduler_scheduler = {
.owner = THIS_MODULE,
.name = "endless",
.open = mcps802154_endless_scheduler_open,
.close = mcps802154_endless_scheduler_close,
.notify_stop = mcps802154_endless_scheduler_notify_stop,
.set_region_parameters =
mcps802154_endless_scheduler_set_region_parameters,
.call_region = mcps802154_endless_scheduler_call_region,
.update_schedule = mcps802154_endless_scheduler_update_schedule,
};
int __init mcps802154_endless_scheduler_init(void)
{
return mcps802154_scheduler_register(
&mcps802154_endless_scheduler_scheduler);
}
void __exit mcps802154_endless_scheduler_exit(void)
{
mcps802154_scheduler_unregister(
&mcps802154_endless_scheduler_scheduler);
}