/* lpal_directpath.c * Description: LitePath Directpath device driver implementation * * * GPL LICENSE SUMMARY * * Copyright(c) 2016 Intel Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed 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 GNU * General Public License for more details. * * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. * The full GNU General Public License is included in this distribution * in the file called LICENSE.GPL. * * Contact Information: * Intel Corporation * 2200 Mission College Blvd. * Santa Clara, CA 97052 */ /* Common Head File */ #include #include #include #include #include #include #include #include #include #include #include #include #ifdef LPAL_DEBUG #define LPAL_PRINT_RX(msg, arg...) \ pr_info("[LP-DP-DEBUG][%s:%d] "msg, __func__, __LINE__, ##arg) #else #define LPAL_PRINT_RX(msg, arg...) #endif #define LPAL_PRINT(msg, arg...) \ pr_info("[LP-DP-DEBUG][%s:%d] "msg, __func__, __LINE__, ##arg); /* This API are according to new lpal structure */ #define MAX_SUBIF (MAX_VPID+1) #define DRV_REGISTER ppa_drv_lpal_directpath_register #define DRV_SEND ppa_drv_lpal_directpath_send #define DRV_ALLOC_SKB ppa_drv_lpal_directpath_alloc_skb #define DRV_WIFI_PDSP ppa_drv_lpal_directpath_enable_wifi_pdsp /*! * \brief PPA synchronization primitive for exclusion and/or synchronization */ static spinlock_t g_lpal_dp_lock; static uint32_t g_start_ifid = 0, g_end_ifid = MAX_PID * (MAX_VPID+1); struct ppe_directpath_data *ppa_drv_g_ppe_directpath_data; EXPORT_SYMBOL(ppa_drv_g_ppe_directpath_data); int32_t(*ppa_hook_directpath_ex_register_dev_fn) (PPA_SUBIF *subif, PPA_NETIF *dev, PPA_DIRECTPATH_CB * pDirectpathCb, uint32_t flags) = NULL; int32_t(*ppa_hook_directpath_ex_send_fn) (PPA_SUBIF *subif, PPA_BUF *buf, int32_t len, uint32_t flags) = NULL; PPA_BUF *(*ppa_hook_directpath_alloc_skb_fn) (PPA_SUBIF *psubif, int32_t len, uint32_t flags) = NULL; int32_t (*ppa_hook_directpath_enable_wifi_pdsp) (PPA_SUBIF *subif, uint32_t enable_pdsp) = NULL; /** * Cleanup the device attributes * * @param Interface ID of the device * * @return NULL */ static void __remove_directpath_dev_from_datapath(int if_id) { if ((ppa_drv_g_ppe_directpath_data[if_id].flags & PPE_DIRECTPATH_DATA_ENTRY_VALID)) { memset(&ppa_drv_g_ppe_directpath_data[if_id], 0, sizeof(ppa_drv_g_ppe_directpath_data[if_id])); } } /** * Wrapper to Register/Deregister Network Device using Litepath * * @param Network Device ID of Sub-Interface * * @param Network Device ID of Physical Interface * * @param Callback Interface to Sub-Interface * * @param flags * * @return zero in Success, non-zero on failure */ int32_t ppa_directpath_register_dev_ex(PPA_SUBIF *subif, PPA_NETIF *netif, PPA_DIRECTPATH_CB *pDirectpathCb, uint32_t flags) { int32_t ret; int32_t if_id; uint32_t tmp_flags; if ((subif == NULL) || !ppa_drv_g_ppe_directpath_data) return PPA_INVALID; LPAL_PRINT("Entry Port Id :%d\n", subif->port_id); if ((flags & PPA_F_DIRECTPATH_REGISTER)) { if (!netif || !pDirectpathCb || !pDirectpathCb->rx_fn) return PPA_INVALID; if (netif->name == NULL) return PPA_INVALID; spin_lock_bh(&g_lpal_dp_lock); /* first check whether the interface already added * into PPA directpath or not */ for (if_id = 0; if_id < g_end_ifid; if_id++) { if (ppa_drv_g_ppe_directpath_data[if_id].netif && (ppa_drv_g_ppe_directpath_data[if_id].netif == netif)) { if (subif) { #ifdef CONFIG_PUMA_LITEPATH subif->port_id = DP_PORT_ID(if_id); subif->subif = DP_SUBIF(if_id); #endif } spin_unlock_bh(&g_lpal_dp_lock); return PPA_SUCCESS; } } spin_unlock_bh(&g_lpal_dp_lock); ret = DRV_REGISTER(subif, netif, pDirectpathCb, &if_id, flags); if (ret == PPA_SUCCESS) { LPAL_PRINT("Reg. PortId:[%d] subif:[%d] if_id:[%d]\n", subif->port_id, subif->subif, if_id); spin_lock_bh(&g_lpal_dp_lock); if (subif->subif != -1) LPAL_PRINT("Registered subif :[%d]\n", subif->subif); tmp_flags = ppa_drv_g_ppe_directpath_data[if_id].flags | PPE_DIRECTPATH_DATA_ENTRY_VALID | PPE_DIRECTPATH_DATA_RX_ENABLE; ppa_drv_g_ppe_directpath_data[if_id].flags = tmp_flags; spin_unlock_bh(&g_lpal_dp_lock); } LPAL_PRINT("Exit - DP Register\n"); return ret; } else { if (subif->port_id < 0 || subif->port_id >= g_end_ifid) { LPAL_PRINT("directp unregister wrong id: %d\n", subif->port_id); return PPA_INVALID; } LPAL_PRINT("Entry - DP UnRegister\n"); ret = DRV_REGISTER(subif, netif, pDirectpathCb, &if_id, flags); if (ret == PPA_SUCCESS) { spin_lock_bh(&g_lpal_dp_lock); LPAL_PRINT("Remove directpath device index :%d\n", if_id); __remove_directpath_dev_from_datapath(if_id); spin_unlock_bh(&g_lpal_dp_lock); LPAL_PRINT("Unregiter Directpath ok\n"); return PPA_SUCCESS; } else { LPAL_PRINT("DRV_REGISTER exit with error = %d!\n", ret); return PPA_INVALID; } } } /** * Wrapper to send skb from Network Device to Puma LitePath * * @param Network Device ID for Sub-Interface * * @param skb pointer * * @param Length of skb * * @param flags associated with the network sub-interface * * @return zero in Success, non-zero on failure */ int32_t ppa_directpath_send_ex(PPA_SUBIF *subif, PPA_BUF *skb, int32_t len, uint32_t flags) { int32_t ret = PPA_SUCCESS; if (skb == NULL) { LPAL_PRINT_RX("Null skb\n"); return PPA_INVALID; } if (!subif) { LPAL_PRINT_RX("Null subif\n"); return PPA_INVALID; } if (!ppa_drv_g_ppe_directpath_data) { LPAL_PRINT_RX("Invalid WiFi Device table.\n"); dev_kfree_skb_any(skb); return PPA_INVALID; } spin_lock_bh(&g_lpal_dp_lock); if (subif->port_id < g_start_ifid || subif->port_id >= g_end_ifid) { ret = PPA_INVALID; goto __DIRETPATH_TX_EXIT; } if (!(ppa_drv_g_ppe_directpath_data[subif->port_id * MAX_SUBIF].flags & PPE_DIRECTPATH_DATA_ENTRY_VALID)) { LPAL_PRINT_RX("Invalid index for pid %d.\n", subif->port_id); ret = PPA_EPERM; goto __DIRETPATH_TX_EXIT; } LPAL_PRINT_RX("Send skb to puma_lpal...\n"); ret = DRV_SEND(subif, skb, len, flags); spin_unlock_bh(&g_lpal_dp_lock); return ret; __DIRETPATH_TX_EXIT: if (ret != PPA_SUCCESS && skb) dev_kfree_skb_any(skb); spin_unlock_bh(&g_lpal_dp_lock); return ret; } /** * Wrapper to send skb from Network Device to Puma LitePath * * @param Network Interface ID * * @param skb pointer * * @param Length of skb * * @param flags associated with the network sub-interface * * @return zero in Success, non-zero on failure */ int32_t ppa_directpath_send(uint32_t rx_if_id, PPA_BUF *skb, int32_t len, uint32_t flags) { int32_t ret; PPA_SUBIF sub_if; sub_if.port_id = rx_if_id; sub_if.subif = -1; ret = ppa_directpath_send_ex(&sub_if, skb, len, flags); return ret; } /** * Wrapper for Network Device to allocate a skb * * @param Network Device Sub-Interface * * @param Length of skb * * @param Flags associated with the interface * * @return Pointer to Netowkr Device sub-interface */ PPA_BUF *ppa_directpath_alloc_skb(PPA_SUBIF *subif, int32_t len, uint32_t flags) { PPA_BUF *ret = (void *)PPA_INVALID; #ifdef CONFIG_PUMA_LITEPATH spin_lock_bh(&g_lpal_dp_lock); if (!subif) { LPAL_PRINT_RX("Null subif\n"); return ret; } if (ppa_drv_g_ppe_directpath_data[DP_DATA_INDEX(subif)]. flags & PPE_DIRECTPATH_DATA_ENTRY_VALID) { ret = DRV_ALLOC_SKB(subif, len, flags); } spin_unlock_bh(&g_lpal_dp_lock); #else LPAL_PRINT("ppa_directpath_alloc_skb not defined!!\n"); #endif return ret; } /** * Wrapper to Enable/Disable wifi PDSP using Litepath * * @param Network Device ID of Sub-Interface * * @param enable_pdsp * * @returnzero in Success, non-zero on failure */ uint32_t ppa_directpath_enable_wifi_pdsp(PPA_SUBIF *subif, uint32_t enable_pdsp) { int32_t ret = PPA_SUCCESS; if ((subif == NULL) || !ppa_drv_g_ppe_directpath_data){ return PPA_INVALID; } ret = DRV_WIFI_PDSP(subif, enable_pdsp); return ret; } /** * API for WiFi Driver to register/deregister with Puma Litepath * * @param Network Device sub-interface * * @param Network Device * * @param Pointer to Callback functions of the Network interface registered * * @param Flags associated with the network interface * * @return zero for success, non-zero for failure */ int32_t __ppa_hook_directpath_ex_register_dev_fn(PPA_SUBIF *subif, PPA_NETIF *dev, PPA_DIRECTPATH_CB * pDirectpathCb, uint32_t flags) { return ppa_directpath_register_dev_ex(subif, dev, pDirectpathCb, flags); } EXPORT_SYMBOL_GPL(ppa_hook_directpath_ex_register_dev_fn); /** * API for WiFI Driver to send skb * * @param Network Device sub-interface * * @param Pointer to skb * * @param Length of skb * * @param Flags associated with the interface * * @return zero for success, non-zero for failure */ int32_t __ppa_hook_directpath_ex_send_fn(PPA_SUBIF *subif, PPA_BUF *buf, int32_t len, uint32_t flags) { return ppa_directpath_send_ex(subif, buf, len, flags); } EXPORT_SYMBOL_GPL(ppa_hook_directpath_ex_send_fn); /** * API for WiFI Driver to send skb * * @param Network Device sub-interface * * @param Length of skb * * @param Flags associated with the interface * * @return zero for success, non-zero for failure */ PPA_BUF *__ppa_hook_directpath_alloc_skb_fn(PPA_SUBIF *psubif, int32_t len, uint32_t flags) { return ppa_directpath_alloc_skb(psubif, len, flags); } EXPORT_SYMBOL_GPL(ppa_hook_directpath_alloc_skb_fn); /** * API for WiFI Driver to Enable/Disable PDSP with Puma Litepath * * @param Network Device sub-interface * * @param enable_pdsp 0- Disable 1- Enable * * @return zero for success, non-zero for failure */ int32_t __ppa_hook_directpath_enable_wifi_pdsp(PPA_SUBIF *psubif, uint32_t enable_pdsp) { return ppa_directpath_enable_wifi_pdsp(psubif, enable_pdsp); } EXPORT_SYMBOL_GPL(ppa_hook_directpath_enable_wifi_pdsp); /** * Driver Init * * @return zero for success, non-zero for failure */ static int __init lpal_dp_init(void) { spin_lock_init(&g_lpal_dp_lock); ppa_hook_directpath_ex_register_dev_fn = __ppa_hook_directpath_ex_register_dev_fn; ppa_hook_directpath_ex_send_fn = __ppa_hook_directpath_ex_send_fn; ppa_hook_directpath_alloc_skb_fn = __ppa_hook_directpath_alloc_skb_fn; ppa_hook_directpath_enable_wifi_pdsp = __ppa_hook_directpath_enable_wifi_pdsp; LPAL_PRINT("litepath AL Wrapper module loaded\n"); return 0; } /** * Driver Exit */ static void __exit lpal_dp_exit(void) { LPAL_PRINT("litepath AL Wrapper module unloaded.\n"); } module_init(lpal_dp_init); module_exit(lpal_dp_exit); MODULE_DESCRIPTION("LITEPATH ADAPTATION WRAPPER MODULE"); MODULE_LICENSE("GPL"); MODULE_VERSION("1.0.0");