1/* 2 ************************************************************************** 3 * Copyright (c) 2014,2015, The Linux Foundation. All rights reserved. 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all copies. 7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 ************************************************************************** 15 */ 16 17/* 18 * nss_tx_rx_lag.c 19 * NSS LAG Tx APIs 20 */ 21 22#include <linux/if_bonding.h> 23 24#include "nss_tx_rx_common.h" 25 26/* 27 * nss_lag_tx() 28 * Transmit a LAG msg to the firmware. 29 */ 30nss_tx_status_t nss_lag_tx(struct nss_ctx_instance *nss_ctx, struct nss_lag_msg *msg) 31{ 32 struct sk_buff *nbuf; 33 int32_t status; 34 struct nss_lag_msg *nm; 35 36 nss_info("%p: NSS LAG Tx\n", nss_ctx); 37 38 NSS_VERIFY_CTX_MAGIC(nss_ctx); 39 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) { 40 nss_warning("%p: LAG msg dropped as core not ready", nss_ctx); 41 return NSS_TX_FAILURE_NOT_READY; 42 } 43 44 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE); 45 if (unlikely(!nbuf)) { 46 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]); 47 nss_warning("%p: LAG msg dropped as command allocation failed", nss_ctx); 48 return NSS_TX_FAILURE; 49 } 50 51 nm = (struct nss_lag_msg *)skb_put(nbuf, sizeof(struct nss_lag_msg)); 52 memcpy(nm, msg, sizeof(struct nss_lag_msg)); 53 54 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0); 55 if (status != NSS_CORE_STATUS_SUCCESS) { 56 dev_kfree_skb_any(nbuf); 57 nss_warning("%p: Unable to enqueue LAG msg\n", nss_ctx); 58 return NSS_TX_FAILURE; 59 } 60 nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit, 61 NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE); 62 63 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]); 64 return NSS_TX_SUCCESS; 65} 66EXPORT_SYMBOL(nss_lag_tx); 67 68/** 69 * nss_register_lag_if() 70 */ 71void *nss_register_lag_if(uint32_t if_num, 72 nss_lag_callback_t lag_cb, 73 nss_lag_event_callback_t lag_ev_cb, 74 struct net_device *netdev) 75{ 76 uint32_t features = 0; 77 78 nss_assert((if_num == NSS_LAG0_INTERFACE_NUM) || (if_num == NSS_LAG1_INTERFACE_NUM) || 79 (if_num == NSS_LAG2_INTERFACE_NUM) || (if_num == NSS_LAG3_INTERFACE_NUM)); 80 81 nss_top_main.subsys_dp_register[if_num].ndev = netdev; 82 nss_top_main.subsys_dp_register[if_num].cb = lag_cb; 83 nss_top_main.subsys_dp_register[if_num].app_data = NULL; 84 nss_top_main.subsys_dp_register[if_num].features = features; 85 86 nss_top_main.lag_event_callback = lag_ev_cb; 87 88 /* 89 * Return the NSS driver context for LAG (same as for ipv4 functions) 90 */ 91 return (void *)&nss_top_main.nss[nss_top_main.ipv4_handler_id]; 92} 93EXPORT_SYMBOL(nss_register_lag_if); 94 95 96/** 97 * nss_unregister_lag_if() 98 */ 99void nss_unregister_lag_if(uint32_t if_num) 100{ 101 nss_assert((if_num == NSS_LAG0_INTERFACE_NUM) || (if_num == NSS_LAG1_INTERFACE_NUM) || 102 (if_num == NSS_LAG2_INTERFACE_NUM) || (if_num == NSS_LAG3_INTERFACE_NUM)); 103 104 nss_top_main.subsys_dp_register[if_num].cb = NULL; 105 nss_top_main.subsys_dp_register[if_num].ndev = NULL; 106 nss_top_main.subsys_dp_register[if_num].app_data = NULL; 107 nss_top_main.subsys_dp_register[if_num].features = 0; 108 109 nss_top_main.lag_event_callback = NULL; 110} 111EXPORT_SYMBOL(nss_unregister_lag_if); 112 113 114/** 115 * nss_lag_handler() 116 */ 117void nss_lag_handler(struct nss_ctx_instance *nss_ctx, 118 struct nss_cmn_msg *ncm, 119 void *app_data) 120{ 121 struct nss_lag_msg *lm = (struct nss_lag_msg *)ncm; 122 void *ctx = NULL; 123 nss_lag_event_callback_t cb; 124 125 BUG_ON(ncm->interface != NSS_LAG0_INTERFACE_NUM 126 && ncm->interface != NSS_LAG1_INTERFACE_NUM 127 && ncm->interface != NSS_LAG2_INTERFACE_NUM 128 && ncm->interface != NSS_LAG3_INTERFACE_NUM); 129 130 if (ncm->type >= NSS_TX_METADATA_LAG_MAX) { 131 nss_warning("%p: received invalid message %d for LAG interface", nss_ctx, ncm->type); 132 return; 133 } 134 135 if (ncm->len > sizeof(struct nss_lag_msg)) { 136 nss_warning("%p: invalid length for LAG message: %d", nss_ctx, ncm->len); 137 return; 138 } 139 140 /** 141 * Update the callback and app_data for NOTIFY messages. 142 * LAG sends all notify messages to the same callback. 143 */ 144 if (ncm->response == NSS_CMM_RESPONSE_NOTIFY) { 145 ncm->cb = (uint32_t)nss_ctx->nss_top->lag_event_callback; 146 } 147 148 /** 149 * Log failures 150 */ 151 nss_core_log_msg_failures(nss_ctx, ncm); 152 153 /** 154 * Do we have a call back 155 */ 156 if (!ncm->cb) { 157 return; 158 } 159 160 /** 161 * callback 162 */ 163 cb = (nss_lag_event_callback_t)ncm->cb; 164 ctx = nss_ctx->nss_top->subsys_dp_register[ncm->interface].ndev; 165 166 cb(ctx, lm); 167} 168 169 170/** 171 * nss_lag_register_handler() 172 */ 173void nss_lag_register_handler(void) 174{ 175 nss_core_register_handler(NSS_LAG0_INTERFACE_NUM, nss_lag_handler, NULL); 176 nss_core_register_handler(NSS_LAG1_INTERFACE_NUM, nss_lag_handler, NULL); 177 nss_core_register_handler(NSS_LAG2_INTERFACE_NUM, nss_lag_handler, NULL); 178 nss_core_register_handler(NSS_LAG3_INTERFACE_NUM, nss_lag_handler, NULL); 179} 180 181/** 182 * nss_lag_msg_init() 183 * Initialize lag message 184 */ 185void nss_lag_msg_init(struct nss_lag_msg *nlm, uint16_t lag_num, uint32_t type, uint32_t len, 186 nss_lag_callback_t cb, void *app_data) 187{ 188 nss_cmn_msg_init(&nlm->cm, lag_num, type, len, (void *)cb, app_data); 189} 190EXPORT_SYMBOL(nss_lag_msg_init); 191