blob: 2726b8ba55a5f686878086a3a777255bbd79ff63 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2014, 2016-2020 The Linux Foundation. All rights reserved.
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
* above copyright notice and this permission notice appear in all copies.
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
**************************************************************************
*/
#include "nss_tx_rx_common.h"
/*
* nss_shaper_register_shaping()
* Register to obtain an NSS context for basic shaping operations
*/
void *nss_shaper_register_shaping(void)
{
if (nss_top_main.shaping_handler_id == (uint8_t)-1) {
nss_warning("%px: SHAPING IS NOT ENABLED", __func__);
return NULL;
}
return (void *)&nss_top_main.nss[nss_top_main.shaping_handler_id];
}
/*
* nss_shaper_unregister_shaping()
* Unregister an NSS shaping context
*/
void nss_shaper_unregister_shaping(void *nss_ctx)
{
}
/*
* nss_shaper_register_shaper_bounce_interface()
* Register for performing shaper bounce operations for interface shaper
*/
void *nss_shaper_register_shaper_bounce_interface(uint32_t if_num, nss_shaper_bounced_callback_t cb, void *app_data, struct module *owner)
{
struct nss_top_instance *nss_top = &nss_top_main;
struct nss_shaper_bounce_registrant *reg;
nss_info("Shaper bounce interface register: %u, cb: %px, app_data: %px, owner: %px",
if_num, cb, app_data, owner);
/*
* Must be valid interface number
*/
if (if_num >= NSS_MAX_NET_INTERFACES) {
nss_warning("Invalid if_num: %u", if_num);
BUG_ON(false);
}
/*
* Shaping enabled?
*/
if (nss_top_main.shaping_handler_id == (uint8_t)-1) {
nss_warning("%px: SHAPING IS NOT ENABLED", __func__);
return NULL;
}
/*
* Can we hold the module?
*/
if (!try_module_get(owner)) {
nss_warning("%px: Unable to hold owner", __func__);
return NULL;
}
spin_lock_bh(&nss_top->lock);
/*
* Must not have existing registrant
*/
reg = &nss_top->bounce_interface_registrants[if_num];
if (reg->registered) {
spin_unlock_bh(&nss_top->stats_lock);
module_put(owner);
nss_warning("Already registered: %u", if_num);
BUG_ON(false);
}
/*
* Register
*/
reg->bounced_callback = cb;
reg->app_data = app_data;
reg->owner = owner;
reg->registered = true;
spin_unlock_bh(&nss_top->lock);
return (void *)&nss_top->nss[nss_top->shaping_handler_id];
}
/*
* nss_shaper_unregister_shaper_bounce_interface()
* Unregister for shaper bounce operations for interface shaper
*/
void nss_shaper_unregister_shaper_bounce_interface(uint32_t if_num)
{
struct nss_top_instance *nss_top = &nss_top_main;
struct nss_shaper_bounce_registrant *reg;
struct module *owner;
nss_info("Shaper bounce interface unregister: %u", if_num);
/*
* Must be valid interface number
*/
if (if_num >= NSS_MAX_NET_INTERFACES) {
nss_warning("Invalid if_num: %u", if_num);
BUG_ON(false);
}
spin_lock_bh(&nss_top->lock);
/*
* Must have existing registrant
*/
reg = &nss_top->bounce_interface_registrants[if_num];
if (!reg->registered) {
spin_unlock_bh(&nss_top->stats_lock);
nss_warning("Already unregistered: %u", if_num);
BUG_ON(false);
}
/*
* Unegister
*/
owner = reg->owner;
reg->owner = NULL;
reg->registered = false;
spin_unlock_bh(&nss_top->lock);
module_put(owner);
}
/*
* nss_shaper_register_shaper_bounce_bridge()
* Register for performing shaper bounce operations for bridge shaper
*/
void *nss_shaper_register_shaper_bounce_bridge(uint32_t if_num, nss_shaper_bounced_callback_t cb, void *app_data, struct module *owner)
{
struct nss_top_instance *nss_top = &nss_top_main;
struct nss_ctx_instance *nss_ctx;
struct nss_shaper_bounce_registrant *reg;
nss_info("Shaper bounce bridge register: %u, cb: %px, app_data: %px, owner: %px",
if_num, cb, app_data, owner);
/*
* Must be valid interface number
*/
if (if_num >= NSS_MAX_NET_INTERFACES) {
nss_warning("Invalid if_num: %u", if_num);
BUG_ON(false);
}
/*
* Shaping enabled?
*/
if (nss_top_main.shaping_handler_id == (uint8_t)-1) {
nss_warning("%px: SHAPING IS NOT ENABLED", __func__);
return NULL;
}
/*
* Can we hold the module?
*/
if (!try_module_get(owner)) {
nss_warning("%px: Unable to hold owner", __func__);
return NULL;
}
spin_lock_bh(&nss_top->lock);
/*
* Must not have existing registrant
*/
reg = &nss_top->bounce_bridge_registrants[if_num];
if (reg->registered) {
spin_unlock_bh(&nss_top->stats_lock);
module_put(owner);
nss_warning("Already registered: %u", if_num);
BUG_ON(false);
}
/*
* Register
*/
reg->bounced_callback = cb;
reg->app_data = app_data;
reg->owner = owner;
reg->registered = true;
spin_unlock_bh(&nss_top->lock);
nss_ctx = &nss_top->nss[nss_top->shaping_handler_id];
return (void *)nss_ctx;
}
/*
* nss_shaper_unregister_shaper_bounce_bridge()
* Unregister for shaper bounce operations for bridge shaper
*/
void nss_shaper_unregister_shaper_bounce_bridge(uint32_t if_num)
{
struct nss_top_instance *nss_top = &nss_top_main;
struct nss_shaper_bounce_registrant *reg;
struct module *owner;
nss_info("Shaper bounce bridge unregister: %u", if_num);
/*
* Must be valid interface number
*/
if (if_num >= NSS_MAX_NET_INTERFACES) {
nss_warning("Invalid if_num: %u", if_num);
BUG_ON(false);
}
spin_lock_bh(&nss_top->lock);
/*
* Must have existing registrant
*/
reg = &nss_top->bounce_bridge_registrants[if_num];
if (!reg->registered) {
spin_unlock_bh(&nss_top->stats_lock);
nss_warning("Already unregistered: %u", if_num);
BUG_ON(false);
}
/*
* Wait until any bounce callback that is active is finished
*/
while (reg->callback_active) {
spin_unlock_bh(&nss_top->stats_lock);
yield();
spin_lock_bh(&nss_top->stats_lock);
}
/*
* Unegister
*/
owner = reg->owner;
reg->owner = NULL;
reg->registered = false;
spin_unlock_bh(&nss_top->lock);
module_put(owner);
}
/*
* nss_shaper_bounce_interface_packet()
* Bounce a packet to the NSS for interface shaping.
*
* You must have registered for interface bounce shaping to call this.
*/
nss_tx_status_t nss_shaper_bounce_interface_packet(void *ctx, uint32_t if_num, struct sk_buff *skb)
{
struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)ctx;
struct nss_top_instance *nss_top = nss_ctx->nss_top;
struct nss_shaper_bounce_registrant *reg;
int32_t status;
/*
* Must be valid interface number
*/
if (if_num >= NSS_MAX_NET_INTERFACES) {
nss_warning("Invalid if_num: %u", if_num);
BUG_ON(false);
}
/*
* Must have existing registrant
*/
spin_lock_bh(&nss_top->lock);
reg = &nss_top->bounce_interface_registrants[if_num];
if (!reg->registered) {
spin_unlock_bh(&nss_top->stats_lock);
nss_warning("unregistered: %u", if_num);
return NSS_TX_FAILURE;
}
spin_unlock_bh(&nss_top->lock);
status = nss_core_send_buffer(nss_ctx, if_num, skb, NSS_IF_H2N_DATA_QUEUE,
H2N_BUFFER_SHAPER_BOUNCE_INTERFACE, 0);
if (status != NSS_CORE_STATUS_SUCCESS) {
return NSS_TX_FAILURE;
}
nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_PACKET]);
return NSS_TX_SUCCESS;
}
/*
* nss_shaper_bounce_bridge_packet()
* Bounce a packet to the NSS for bridge shaping.
*
* You must have registered for bridge bounce shaping to call this.
*/
nss_tx_status_t nss_shaper_bounce_bridge_packet(void *ctx, uint32_t if_num, struct sk_buff *skb)
{
struct nss_ctx_instance *nss_ctx = (struct nss_ctx_instance *)ctx;
struct nss_top_instance *nss_top = nss_ctx->nss_top;
struct nss_shaper_bounce_registrant *reg;
int32_t status;
/*
* Must be valid interface number
*/
if (if_num >= NSS_MAX_NET_INTERFACES) {
nss_warning("Invalid if_num: %u", if_num);
BUG_ON(false);
}
/*
* Must have existing registrant
*/
spin_lock_bh(&nss_top->lock);
reg = &nss_top->bounce_bridge_registrants[if_num];
if (!reg->registered) {
spin_unlock_bh(&nss_top->stats_lock);
nss_warning("unregistered: %u", if_num);
return NSS_TX_FAILURE;
}
spin_unlock_bh(&nss_top->lock);
nss_info("%s: Bridge bounce skb: %px, if_num: %u, ctx: %px", __func__, skb, if_num, nss_ctx);
status = nss_core_send_buffer(nss_ctx, if_num, skb, NSS_IF_H2N_DATA_QUEUE,
H2N_BUFFER_SHAPER_BOUNCE_BRIDGE, 0);
if (status != NSS_CORE_STATUS_SUCCESS) {
nss_info("%s: Bridge bounce core send rejected", __func__);
return NSS_TX_FAILURE;
}
nss_hal_send_interrupt(nss_ctx, NSS_H2N_INTR_DATA_COMMAND_QUEUE);
NSS_PKT_STATS_INC(&nss_ctx->nss_top->stats_drv[NSS_DRV_STATS_TX_PACKET]);
return NSS_TX_SUCCESS;
}
/*
* nss_shaper_get_device()
* Gets the original device from probe.
*/
struct device *nss_shaper_get_dev(void)
{
struct nss_ctx_instance *nss_ctx = &nss_top_main.nss[nss_top_main.shaping_handler_id];
return nss_ctx->dev;
}
EXPORT_SYMBOL(nss_shaper_bounce_bridge_packet);
EXPORT_SYMBOL(nss_shaper_bounce_interface_packet);
EXPORT_SYMBOL(nss_shaper_unregister_shaper_bounce_interface);
EXPORT_SYMBOL(nss_shaper_register_shaper_bounce_interface);
EXPORT_SYMBOL(nss_shaper_unregister_shaper_bounce_bridge);
EXPORT_SYMBOL(nss_shaper_register_shaper_bounce_bridge);
EXPORT_SYMBOL(nss_shaper_register_shaping);
EXPORT_SYMBOL(nss_shaper_unregister_shaping);
EXPORT_SYMBOL(nss_shaper_get_dev);