blob: 6c81bcae87352a570d5b1afbdabbaef0d223d742 [file] [log] [blame]
Thomas Wu68250352014-04-02 18:59:40 -07001/*
2 **************************************************************************
3 * Copyright (c) 2013, 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_ipv4.c
19 * NSS IPv4 APIs
20 */
21#include <linux/ppp_channel.h>
22#include "nss_tx_rx_common.h"
23#include "nss_ipv4.h"
24
25extern void nss_rx_metadata_ipv4_rule_establish(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_rule_establish *nire);
26extern void nss_rx_ipv4_sync(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync *nirs);
27
28/*
Sol Kavy57d24b42014-04-05 13:45:36 -070029 * nss_ipv4_driver_conn_sync_update()
Thomas Wu68250352014-04-02 18:59:40 -070030 * Update driver specific information from the messsage.
Sol Kavy57d24b42014-04-05 13:45:36 -070031 *
32 * TODO: export for now but once we remove old APIs, this can be made statis.
Thomas Wu68250352014-04-02 18:59:40 -070033 */
Sol Kavy57d24b42014-04-05 13:45:36 -070034void nss_ipv4_driver_conn_sync_update(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_conn_sync *nirs)
Thomas Wu68250352014-04-02 18:59:40 -070035{
Sol Kavy57d24b42014-04-05 13:45:36 -070036 struct nss_top_instance *nss_top = nss_ctx->nss_top;
37 struct net_device *pppoe_dev = NULL;
38
Thomas Wu68250352014-04-02 18:59:40 -070039 /*
40 * Update statistics maintained by NSS driver
41 */
42 spin_lock_bh(&nss_top->stats_lock);
Thomas Wu68250352014-04-02 18:59:40 -070043 nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_RX_PKTS] += nirs->flow_rx_packet_count + nirs->return_rx_packet_count;
44 nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_RX_BYTES] += nirs->flow_rx_byte_count + nirs->return_rx_byte_count;
45 nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_TX_PKTS] += nirs->flow_tx_packet_count + nirs->return_tx_packet_count;
46 nss_top->stats_ipv4[NSS_STATS_IPV4_ACCELERATED_TX_BYTES] += nirs->flow_tx_byte_count + nirs->return_tx_byte_count;
Thomas Wu68250352014-04-02 18:59:40 -070047 spin_unlock_bh(&nss_top->stats_lock);
Sol Kavy57d24b42014-04-05 13:45:36 -070048
49 /*
50 * Update the PPPoE interface stats, if there is any PPPoE session on the interfaces.
51 */
52 if (nirs->flow_pppoe_session_id) {
53 pppoe_dev = ppp_session_to_netdev(nirs->flow_pppoe_session_id, (uint8_t *)nirs->flow_pppoe_remote_mac);
54 if (pppoe_dev) {
55 ppp_update_stats(pppoe_dev, nirs->flow_rx_packet_count, nirs->flow_rx_byte_count,
56 nirs->flow_tx_packet_count, nirs->flow_tx_byte_count);
57 dev_put(pppoe_dev);
58 }
59 }
60
61 if (nirs->return_pppoe_session_id) {
62 pppoe_dev = ppp_session_to_netdev(nirs->return_pppoe_session_id, (uint8_t *)nirs->return_pppoe_remote_mac);
63 if (pppoe_dev) {
64 ppp_update_stats(pppoe_dev, nirs->return_rx_packet_count, nirs->return_rx_byte_count,
65 nirs->return_tx_packet_count, nirs->return_tx_byte_count);
66 dev_put(pppoe_dev);
67 }
68 }
Thomas Wu68250352014-04-02 18:59:40 -070069}
Thomas Wu68250352014-04-02 18:59:40 -070070
71/*
Sol Kavy2783c072014-04-05 12:53:13 -070072 * nss_ipv4_rx_msg_handler()
Thomas Wu68250352014-04-02 18:59:40 -070073 * Handle NSS -> HLOS messages for IPv4 bridge/route
74 */
Sol Kavy2783c072014-04-05 12:53:13 -070075static void nss_ipv4_rx_msg_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
Thomas Wu68250352014-04-02 18:59:40 -070076{
77 struct nss_ipv4_msg *nim = (struct nss_ipv4_msg *)ncm;
Sol Kavy57d24b42014-04-05 13:45:36 -070078 nss_ipv4_msg_callback_t cb;
Thomas Wu68250352014-04-02 18:59:40 -070079
80 BUG_ON(ncm->interface != NSS_IPV4_RX_INTERFACE);
81
82 /*
83 * Sanity check the message type
84 */
85 if (ncm->type > NSS_IPV4_MAX_MSG_TYPES) {
86 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
87 return;
88 }
89
90 if (ncm->len > sizeof(struct nss_ipv4_msg)) {
91 nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
92 return;
93 }
94
Thomas Wu68250352014-04-02 18:59:40 -070095 /*
Thomas Wu68250352014-04-02 18:59:40 -070096 * Log failures
97 */
98 nss_core_log_msg_failures(nss_ctx, ncm);
99
100 /*
101 * Handle deprecated messages. Eventually these messages should be removed.
102 */
103 switch (nim->cm.type) {
104 case NSS_IPV4_RX_ESTABLISH_RULE_MSG:
105 return nss_rx_metadata_ipv4_rule_establish(nss_ctx, &nim->msg.rule_establish);
106 break;
107
108 case NSS_IPV4_RX_CONN_STATS_SYNC_MSG:
Sol Kavy57d24b42014-04-05 13:45:36 -0700109 /*
110 * Update driver statistics on connection sync.
111 */
112 nss_ipv4_driver_conn_sync_update(nss_ctx, &nim->msg.conn_stats);
Thomas Wu68250352014-04-02 18:59:40 -0700113 return nss_rx_ipv4_sync(nss_ctx, &nim->msg.conn_stats);
114 break;
115 }
116
117 /*
Sol Kavy57d24b42014-04-05 13:45:36 -0700118 * Update the callback and app_data for NOTIFY messages, IPv4 sends all notify messages
119 * to the same callback/app_data.
Thomas Wu68250352014-04-02 18:59:40 -0700120 */
Sol Kavy57d24b42014-04-05 13:45:36 -0700121 if (nim->cm.response == NSS_CMM_RESPONSE_NOTIFY) {
122 ncm->cb = (uint32_t)nss_ctx->nss_top->ipv4_callback;
123 ncm->app_data = (uint32_t)nss_ctx->nss_top->ipv4_ctx;
124 }
Sol Kavy2783c072014-04-05 12:53:13 -0700125
Thomas Wu68250352014-04-02 18:59:40 -0700126 /*
127 * Do we have a callback?
128 */
129 if (!ncm->cb) {
130 return;
131 }
132
133 /*
134 * Callback
135 */
Sol Kavy57d24b42014-04-05 13:45:36 -0700136 cb = (nss_ipv4_msg_callback_t)ncm->cb;
Thomas Wu68250352014-04-02 18:59:40 -0700137 cb((void *)ncm->app_data, nim);
Thomas Wu68250352014-04-02 18:59:40 -0700138}
139
140/*
141 * nss_ipv4_tx()
142 * Transmit an ipv4 message to the FW.
143 */
144nss_tx_status_t nss_ipv4_tx(struct nss_ctx_instance *nss_ctx, struct nss_ipv4_msg *nim)
145{
146 struct nss_ipv4_msg *nim2;
147 struct nss_cmn_msg *ncm = &nim->cm;
148 struct sk_buff *nbuf;
149 int32_t status;
150
151 NSS_VERIFY_CTX_MAGIC(nss_ctx);
152 if (unlikely(nss_ctx->state != NSS_CORE_STATE_INITIALIZED)) {
153 nss_warning("%p: ipv4 msg dropped as core not ready", nss_ctx);
154 return NSS_TX_FAILURE_NOT_READY;
155 }
156
157 /*
158 * Sanity check the message
159 */
160 if (ncm->interface != NSS_IPV4_RX_INTERFACE) {
161 nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
162 return NSS_TX_FAILURE;
163 }
164
165 if (ncm->type > NSS_IPV4_MAX_MSG_TYPES) {
166 nss_warning("%p: message type out of range: %d", nss_ctx, ncm->type);
167 return NSS_TX_FAILURE;
168 }
169
170 if (ncm->len > sizeof(struct nss_ipv4_msg)) {
171 nss_warning("%p: tx request for another interface: %d", nss_ctx, ncm->interface);
172 return NSS_TX_FAILURE;
173 }
174
175 nbuf = dev_alloc_skb(NSS_NBUF_PAYLOAD_SIZE);
176 if (unlikely(!nbuf)) {
177 spin_lock_bh(&nss_ctx->nss_top->stats_lock);
178 nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_NBUF_ALLOC_FAILS]++;
179 spin_unlock_bh(&nss_ctx->nss_top->stats_lock);
180 nss_warning("%p: msg dropped as command allocation failed", nss_ctx);
181 return NSS_TX_FAILURE;
182 }
183
184 /*
185 * Copy the message to our skb.
186 */
187 nim2 = (struct nss_ipv4_msg *)skb_put(nbuf, sizeof(struct nss_ipv4_msg));
188 memcpy(nim2, nim, sizeof(struct nss_ipv4_msg));
189
190 status = nss_core_send_buffer(nss_ctx, 0, nbuf, NSS_IF_CMD_QUEUE, H2N_BUFFER_CTRL, 0);
191 if (status != NSS_CORE_STATUS_SUCCESS) {
192 dev_kfree_skb_any(nbuf);
Sol Kavycd1bd5c2014-04-04 11:09:44 -0700193 nss_warning("%p: unable to enqueue IPv4 msg\n", nss_ctx);
Thomas Wu68250352014-04-02 18:59:40 -0700194 return NSS_TX_FAILURE;
195 }
196
197 nss_hal_send_interrupt(nss_ctx->nmap, nss_ctx->h2n_desc_rings[NSS_IF_CMD_QUEUE].desc_ring.int_bit,
198 NSS_REGS_H2N_INTR_STATUS_DATA_COMMAND_QUEUE);
199
200 NSS_PKT_STATS_INCREMENT(nss_ctx, &nss_ctx->nss_top->stats_drv[NSS_STATS_DRV_TX_CMD_REQ]);
201 return NSS_TX_SUCCESS;
202}
203
204/*
205 **********************************
206 Register/Unregister/Miscellaneous APIs
207 **********************************
208 */
209
210/*
211 * nss_ipv4_notify_register()
212 * Register to received IPv4 events.
213 *
214 * NOTE: Do we want to pass an nss_ctx here so that we can register for ipv4 on any core?
215 */
216struct nss_ctx_instance *nss_ipv4_notify_register(nss_ipv4_msg_callback_t cb, void *app_data)
217{
218 /*
219 * TODO: We need to have a new array in support of the new API
220 * TODO: If we use a per-context array, we would move the array into nss_ctx based.
221 */
222 nss_top_main.ipv4_callback = cb;
Abhishek Rastogie11f47b2014-04-04 18:43:32 +0530223 nss_top_main.ipv4_ctx = app_data;
Thomas Wu68250352014-04-02 18:59:40 -0700224 return &nss_top_main.nss[nss_top_main.ipv4_handler_id];
225}
226
227/*
228 * nss_ipv4_notify_unregister()
229 * Unregister to received IPv4 events.
230 *
231 * NOTE: Do we want to pass an nss_ctx here so that we can register for ipv4 on any core?
232 */
233void nss_ipv4_notify_unregister(void)
234{
235 nss_top_main.ipv4_callback = NULL;
236}
237
238/*
239 * nss_ipv4_get_mgr()
240 *
241 * TODO: This only suppports a single ipv4, do we ever want to support more?
242 */
243struct nss_ctx_instance *nss_ipv4_get_mgr(void)
244{
245 return (void *)&nss_top_main.nss[nss_top_main.ipv4_handler_id];
246}
247
248/*
249 * nss_ipv4_register_handler()
250 * Register our handler to receive messages for this interface
251 */
Sol Kavy2783c072014-04-05 12:53:13 -0700252void nss_ipv4_register_handler(void)
Thomas Wu68250352014-04-02 18:59:40 -0700253{
Sol Kavy2783c072014-04-05 12:53:13 -0700254 if (nss_core_register_handler(NSS_IPV4_RX_INTERFACE, nss_ipv4_rx_msg_handler, NULL) != NSS_CORE_STATUS_SUCCESS) {
Thomas Wu68250352014-04-02 18:59:40 -0700255 nss_warning("IPv4 handler failed to register");
256 }
257}
258
259EXPORT_SYMBOL(nss_ipv4_tx);
260EXPORT_SYMBOL(nss_ipv4_notify_register);
261EXPORT_SYMBOL(nss_ipv4_notify_unregister);
262EXPORT_SYMBOL(nss_ipv4_get_mgr);
263EXPORT_SYMBOL(nss_ipv4_register_handler);