blob: 5c694cf3780c8bbe2787a77a48af5b3969a36658 [file] [log] [blame]
Amit Gupta316729b2016-08-12 12:21:15 +05301/*
2 **************************************************************************
3 * Copyright (c) 2016, 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#include "nss_ppe.h"
18
19/*
20 * nss_ppe_verify_ifnum()
21 * Verify PPE interface number.
22 */
23static inline bool nss_ppe_verify_ifnum(int if_num)
24{
25 return nss_is_dynamic_interface(if_num) || (if_num == NSS_PPE_INTERFACE);
26}
27
28/*
29 * nss_ppe_stats_sync
30 * PPE connection sync stats from NSS
31 */
32static void nss_ppe_stats_sync(struct nss_ctx_instance *nss_ctx, struct nss_ppe_sync_stats_msg *stats_msg, uint16_t if_num)
33{
34 spin_lock_bh(&nss_ppe_stats_lock);
35 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V4_L3_FLOWS] += stats_msg->nss_ppe_v4_l3_flows;
36 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V4_L2_FLOWS] += stats_msg->nss_ppe_v4_l2_flows;
37 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V4_CREATE_REQ] += stats_msg->nss_ppe_v4_create_req;
38 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V4_CREATE_FAIL] += stats_msg->nss_ppe_v4_create_fail;
39 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V4_DESTROY_REQ] += stats_msg->nss_ppe_v4_destroy_req;
40 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V4_DESTROY_FAIL] += stats_msg->nss_ppe_v4_destroy_fail;
41
42 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V6_L3_FLOWS] += stats_msg->nss_ppe_v6_l3_flows;
43 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V6_L2_FLOWS] += stats_msg->nss_ppe_v6_l2_flows;
44 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V6_CREATE_REQ] += stats_msg->nss_ppe_v6_create_req;
45 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V6_CREATE_FAIL] += stats_msg->nss_ppe_v6_create_fail;
46 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V6_DESTROY_REQ] += stats_msg->nss_ppe_v6_destroy_req;
47 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_V6_DESTROY_FAIL] += stats_msg->nss_ppe_v6_destroy_fail;
48
49 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_NH_FULL] += stats_msg->nss_ppe_fail_nh_full;
50 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_FLOW_FULL] += stats_msg->nss_ppe_fail_flow_full;
51 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_HOST_FULL] += stats_msg->nss_ppe_fail_host_full;
52 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_PUBIP_FULL] += stats_msg->nss_ppe_fail_pubip_full;
53 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_PORT_SETUP] += stats_msg->nss_ppe_fail_port_setup;
54 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_RW_FIFO_FULL] += stats_msg->nss_ppe_fail_rw_fifo_full;
55 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_FLOW_COMMAND] += stats_msg->nss_ppe_fail_flow_command;
56 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_UNKNOWN_PROTO] += stats_msg->nss_ppe_fail_unknown_proto;
57 nss_ppe_debug_stats.conn_stats[NSS_STATS_PPE_FAIL_PPE_UNRESPONSIVE] += stats_msg->nss_ppe_fail_ppe_unresponsive;
58 spin_unlock_bh(&nss_ppe_stats_lock);
59}
60
61/*
62 * nss_ppe_stats_conn_get()
63 * Get ppe connection stats.
64 */
65void nss_ppe_stats_conn_get(uint32_t *stats)
66{
67 if (!stats) {
68 nss_warning("No memory to copy ppe connection stats");
69 return;
70 }
71
72 spin_lock_bh(&nss_ppe_stats_lock);
73
74 if (!nss_ppe_debug_stats.valid) {
75 spin_unlock_bh(&nss_ppe_stats_lock);
76 nss_warning("PPE base address not initialized!\n");
77 return;
78 }
79
80 /*
81 * Get flow stats
82 */
83 memcpy(stats, nss_ppe_debug_stats.conn_stats, (sizeof(uint32_t) * NSS_STATS_PPE_CONN_MAX));
84
85 spin_unlock_bh(&nss_ppe_stats_lock);
86}
87
88/*
89 * nss_ppe_stats_l3_get()
90 * Get ppe L3 debug stats.
91 */
92void nss_ppe_stats_l3_get(uint32_t *stats)
93{
94 if (!stats) {
95 nss_warning("No memory to copy ppe l3 dbg stats\n");
96 return;
97 }
98
99 spin_lock_bh(&nss_ppe_stats_lock);
100
101 if (!nss_ppe_debug_stats.valid) {
102 spin_unlock_bh(&nss_ppe_stats_lock);
103 nss_warning("PPE base address not initialized!\n");
104 return;
105 }
106
107 nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG0_OFFSET);
108 nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_STATS_PPE_L3_DBG_0]);
109
110 nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG1_OFFSET);
111 nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_STATS_PPE_L3_DBG_1]);
112
113 nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG2_OFFSET);
114 nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_STATS_PPE_L3_DBG_2]);
115
116 nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG3_OFFSET);
117 nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_STATS_PPE_L3_DBG_3]);
118
119 nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG4_OFFSET);
120 nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_STATS_PPE_L3_DBG_4]);
121
122 nss_ppe_reg_write(PPE_L3_DBG_WR_OFFSET, PPE_L3_DBG_PORT_OFFSET);
123 nss_ppe_reg_read(PPE_L3_DBG_RD_OFFSET, &stats[NSS_STATS_PPE_L3_DBG_PORT]);
124
125 spin_unlock_bh(&nss_ppe_stats_lock);
126}
127
128/*
129 * nss_ppe_stats_code_get()
130 * Get ppe CPU and DROP code for last packet processed.
131 */
132void nss_ppe_stats_code_get(uint32_t *stats)
133{
134 uint32_t drop_0, drop_1, cpu_code;
135
136 nss_trace("%s(%d) Start\n", __func__, __LINE__);
137 if (!stats) {
138 nss_warning("No memory to copy ppe code\n");
139 return;
140 }
141
142 if (!nss_ppe_debug_stats.valid) {
143 nss_warning("PPE base address not initialized!\n");
144 return;
145 }
146
147 spin_lock_bh(&nss_ppe_stats_lock);
148 nss_ppe_reg_write(PPE_PKT_CODE_WR_OFFSET, PPE_PKT_CODE_DROP0_OFFSET);
149 nss_ppe_reg_read(PPE_PKT_CODE_RD_OFFSET, &drop_0);
150
151 nss_ppe_reg_write(PPE_PKT_CODE_WR_OFFSET, PPE_PKT_CODE_DROP1_OFFSET);
152 nss_ppe_reg_read(PPE_PKT_CODE_RD_OFFSET, &drop_1);
153
154 stats[NSS_STATS_PPE_CODE_DROP] = PPE_PKT_CODE_DROP_GET(drop_0, drop_1);
155
156 nss_ppe_reg_write(PPE_PKT_CODE_WR_OFFSET, PPE_PKT_CODE_CPU_OFFSET);
157 nss_ppe_reg_read(PPE_PKT_CODE_RD_OFFSET, &cpu_code);
158
159 stats[NSS_STATS_PPE_CODE_CPU] = PPE_PKT_CODE_CPU_GET(cpu_code);
160
161 spin_unlock_bh(&nss_ppe_stats_lock);
162}
163
164/*
165 * nss_ppe_handler()
166 * Handle NSS -> HLOS messages for ppe tunnel
167 */
168static void nss_ppe_handler(struct nss_ctx_instance *nss_ctx, struct nss_cmn_msg *ncm, __attribute__((unused))void *app_data)
169{
170 struct nss_ppe_msg *msg = (struct nss_ppe_msg *)ncm;
171
172 nss_trace("nss_ctx: %p ppe msg: %p", nss_ctx, msg);
173 BUG_ON(!nss_ppe_verify_ifnum(ncm->interface));
174
175 /*
176 * Is this a valid request/response packet?
177 */
178 if (ncm->type >= NSS_PPE_MSG_MAX) {
179 nss_warning("%p: received invalid message %d for PPE interface", nss_ctx, ncm->type);
180 return;
181 }
182
183 if (nss_cmn_get_msg_len(ncm) > sizeof(struct nss_ppe_msg)) {
184 nss_warning("%p: Length of message is greater than required: %d", nss_ctx, nss_cmn_get_msg_len(ncm));
185 return;
186 }
187
188 switch (msg->cm.type) {
189 case NSS_PPE_MSG_SYNC_STATS:
190 /*
191 * session debug stats embeded in session stats msg
192 */
193 nss_ppe_stats_sync(nss_ctx, &msg->msg.stats, ncm->interface);
194 break;
195 }
196}
197
198/*
199 * nss_ppe_register_handler()
200 * debugfs stats msg handler received on static ppe interface
201 *
202 * TODO: Export API so that others can also read PPE stats.
203 */
204void nss_ppe_register_handler(void)
205{
206 nss_core_register_handler(NSS_PPE_INTERFACE, nss_ppe_handler, NULL);
207}
208
209/*
210 * nss_ppe_free()
211 * Uninitialize PPE base
212 */
213void nss_ppe_free(void)
214{
215 /*
216 * Check if PPE base is already uninitialized.
217 */
218 if (!ppe_pvt.ppe_base) {
219 return;
220 }
221
222 /*
223 * Unmap PPE base address
224 */
225 iounmap(ppe_pvt.ppe_base);
226 ppe_pvt.ppe_base = NULL;
227
228 spin_lock_bh(&nss_ppe_stats_lock);
229 nss_ppe_debug_stats.valid = false;
230 nss_ppe_debug_stats.if_num = 0;
231 nss_ppe_debug_stats.if_index = 0;
232 spin_unlock_bh(&nss_ppe_stats_lock);
233}
234
235/*
236 * nss_ppe_init()
237 * Initialize PPE base
238 */
239void nss_ppe_init(void)
240{
241 /*
242 * Check if PPE base is already initialized.
243 */
244 if (ppe_pvt.ppe_base) {
245 return;
246 }
247
248 /*
249 * Get the PPE base address
250 */
251 ppe_pvt.ppe_base = ioremap_nocache(PPE_BASE_ADDR, PPE_REG_SIZE);
252 if (!ppe_pvt.ppe_base) {
253 nss_warning("DRV can't get PPE base address\n");
254 return;
255 }
256
257 spin_lock_bh(&nss_ppe_stats_lock);
258 nss_ppe_debug_stats.valid = true;
259 nss_ppe_debug_stats.if_num = 0;
260 nss_ppe_debug_stats.if_index = 0;
261 spin_unlock_bh(&nss_ppe_stats_lock);
262}