blob: c667b26f2ff045ef37f6f9919e0afdecc37130f6 [file] [log] [blame]
/*
**************************************************************************
* Copyright (c) 2016-2017, 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2022, Qualcomm Innovation Center, Inc. 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 <linux/version.h>
#include "nss_dp_hal.h"
/*
* nss_dp_reset_netdev_features()
* Resets the netdev features
*/
static inline void nss_dp_reset_netdev_features(struct net_device *netdev)
{
netdev->features = 0;
netdev->hw_features = 0;
netdev->vlan_features = 0;
netdev->wanted_features = 0;
}
/*
* nss_dp_receive()
* Called by overlay drivers to deliver packets to nss-dp
*/
void nss_dp_receive(struct net_device *netdev, struct sk_buff *skb,
struct napi_struct *napi)
{
struct nss_dp_dev *dp_dev = netdev_priv(netdev);
skb->dev = netdev;
skb->protocol = eth_type_trans(skb, netdev);
netdev_dbg(netdev, "Rx on port%d, packet len %d, CSUM %d\n",
dp_dev->macid, skb->len, skb->ip_summed);
#ifdef NSS_DP_PPE_SWITCHDEV
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 5, 0))
skb->offload_fwd_mark = netdev->offload_fwd_mark;
#else
/*
* TODO: Implement ndo_get_devlink_port()
*/
skb->offload_fwd_mark = 0;
#endif
#endif
napi_gro_receive(napi, skb);
}
EXPORT_SYMBOL(nss_dp_receive);
/*
* nss_dp_is_in_open_state()
* Return if a data plane is opened or not
*/
bool nss_dp_is_in_open_state(struct net_device *netdev)
{
struct nss_dp_dev *dp_dev = (struct nss_dp_dev *)netdev_priv(netdev);
if (test_bit(__NSS_DP_UP, &dp_dev->flags))
return true;
return false;
}
EXPORT_SYMBOL(nss_dp_is_in_open_state);
/*
* nss_dp_override_data_plane()
* API to allow overlay drivers to override the data plane
*/
int nss_dp_override_data_plane(struct net_device *netdev,
struct nss_dp_data_plane_ops *dp_ops,
struct nss_dp_data_plane_ctx *dpc)
{
struct nss_dp_dev *dp_dev = (struct nss_dp_dev *)netdev_priv(netdev);
if (!dp_ops->open || !dp_ops->close || !dp_ops->link_state
|| !dp_ops->mac_addr || !dp_ops->change_mtu || !dp_ops->xmit
|| !dp_ops->set_features || !dp_ops->pause_on_off || !dp_ops->deinit) {
netdev_dbg(netdev, "All the op functions must be present, reject this registeration\n");
return NSS_DP_FAILURE;
}
/*
* If this data plane is up, close the netdev to force TX/RX stop, and
* also reset the features
*/
if (test_bit(__NSS_DP_UP, &dp_dev->flags)) {
netdev->netdev_ops->ndo_stop(netdev);
nss_dp_reset_netdev_features(netdev);
}
/*
* Free up the resources used by the data plane
*/
if (dp_dev->drv_flags & NSS_DP_PRIV_FLAG(INIT_DONE)) {
if (dp_dev->data_plane_ops->deinit(dpc)) {
netdev_dbg(netdev, "Data plane de-init failed\n");
return -ENOMEM;
}
dp_dev->drv_flags &= ~NSS_DP_PRIV_FLAG(INIT_DONE);
}
/*
* Override the data_plane_ctx, data_plane_ops
*/
dp_dev->drv_flags |= NSS_DP_PRIV_FLAG(INIT_OVERRIDE);
dp_dev->dpc = dpc;
dp_dev->data_plane_ops = dp_ops;
/*
* Initialize the updated data plane
*/
if (dp_dev->data_plane_ops->init(dpc)) {
netdev_dbg(netdev, "Data Plane init failed\n");
return -EFAULT;
}
dp_dev->drv_flags |= NSS_DP_PRIV_FLAG(INIT_DONE);
return NSS_DP_SUCCESS;
}
EXPORT_SYMBOL(nss_dp_override_data_plane);
/*
* nss_dp_start_data_plane()
* Data plane to inform netdev it is ready to start
*/
void nss_dp_start_data_plane(struct net_device *netdev,
struct nss_dp_data_plane_ctx *dpc)
{
struct nss_dp_dev *dp_dev = (struct nss_dp_dev *)netdev_priv(netdev);
if (test_bit(__NSS_DP_UP, &dp_dev->flags)) {
netdev_dbg(netdev, "This netdev already up, something is wrong\n");
return;
}
if (dp_dev->dpc != dpc) {
netdev_dbg(netdev, "Cookie %px does not match, reject\n", dpc);
return;
}
netdev->netdev_ops->ndo_open(dp_dev->netdev);
}
EXPORT_SYMBOL(nss_dp_start_data_plane);
/*
* nss_dp_restore_data_plane()
* Called by overlay drivers to detach itself from nss-dp
*/
void nss_dp_restore_data_plane(struct net_device *netdev)
{
struct nss_dp_dev *dp_dev = (struct nss_dp_dev *)netdev_priv(netdev);
/*
* If this data plane is up, close the netdev to force TX/RX stop, and
* also reset the features
*/
if (test_bit(__NSS_DP_UP, &dp_dev->flags)) {
netdev->netdev_ops->ndo_stop(netdev);
nss_dp_reset_netdev_features(netdev);
}
dp_dev->data_plane_ops = nss_dp_hal_get_data_plane_ops();
dp_dev->dpc = &dp_global_data_plane_ctx[dp_dev->macid - NSS_DP_START_IFNUM];
/*
* TODO: Re-initialize EDMA dataplane
*/
}
EXPORT_SYMBOL(nss_dp_restore_data_plane);
/*
* nss_dp_get_netdev_by_nss_if_num()
* return the net device of the corrsponding id if exist
*/
struct net_device *nss_dp_get_netdev_by_nss_if_num(int if_num)
{
struct nss_dp_dev *dp_dev;
if ((if_num > NSS_DP_HAL_MAX_PORTS) || (if_num < NSS_DP_START_IFNUM)) {
pr_err("Invalid if_num %d\n", if_num);
return NULL;
}
dp_dev = dp_global_ctx.nss_dp[if_num - NSS_DP_START_IFNUM];
if (!dp_dev)
return NULL;
return dp_dev->netdev;
}
EXPORT_SYMBOL(nss_dp_get_netdev_by_nss_if_num);