| /* |
| ************************************************************************** |
| * 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); |