1/*
2 **************************************************************************
3 * Copyright (c) 2014, 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_data_plane.h"
18#include "nss_phys_if.h"
19#include "nss_core.h"
20#include "nss_tx_rx_common.h"
21#include <nss_gmac_api_if.h>
22
23#define NSS_DP_SUPPORTED_FEATURES NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_FRAGLIST | (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO)
24
25struct nss_data_plane_param nss_data_plane_params[NSS_MAX_PHYSICAL_INTERFACES];
26
27/*
28 * nss_data_plane_open()
29 *	Called by gmac to notify open to nss-fw
30 */
31static int nss_data_plane_open(void *arg, uint32_t tx_desc_ring, uint32_t rx_desc_ring, uint32_t mode)
32{
33	struct nss_data_plane_param *dp = (struct nss_data_plane_param *)arg;
34
35	if (dp->notify_open) {
36		return NSS_GMAC_SUCCESS;
37	}
38	if (nss_phys_if_open(dp->nss_ctx, tx_desc_ring, rx_desc_ring, mode, dp->if_num) == NSS_TX_SUCCESS) {
39		dp->notify_open = 1;
40		return NSS_GMAC_SUCCESS;
41	}
42	return NSS_GMAC_FAILURE;
43}
44
45/*
46 * nss_data_plane_close()
47 *	Called by gmac to notify close to nss-fw
48 */
49static int nss_data_plane_close(void *arg)
50{
51	/*
52	 * We don't actually do synopsys gmac close in fw, just return success
53	 */
54	return NSS_GMAC_SUCCESS;
55}
56
57/*
58 * nss_data_plane_link_state()
59 *	Called by gmac to notify link state change to nss-fw
60 */
61static int nss_data_plane_link_state(void *arg, uint32_t link_state)
62{
63	struct nss_data_plane_param *dp = (struct nss_data_plane_param *)arg;
64
65	return nss_phys_if_link_state(dp->nss_ctx, link_state, dp->if_num);
66}
67
68/*
69 * nss_data_plane_mac_addr()
70 *	Called by gmac to set mac address
71 */
72static int nss_data_plane_mac_addr(void *arg, uint8_t *addr)
73{
74	struct nss_data_plane_param *dp = (struct nss_data_plane_param *)arg;
75
76	return nss_phys_if_mac_addr(dp->nss_ctx, addr, dp->if_num);
77}
78
79/*
80 * nss_data_plane_change_mtu()
81 *	Called by gmac to change mtu of a gmac
82 */
83static int nss_data_plane_change_mtu(void *arg, uint32_t mtu)
84{
85	struct nss_data_plane_param *dp = (struct nss_data_plane_param *)arg;
86
87	return nss_phys_if_change_mtu(dp->nss_ctx, mtu, dp->if_num);
88}
89
90/*
91 * nss_data_plane_buf()
92 *	Called by gmac to pass a sk_buff for xmit
93 */
94static int nss_data_plane_buf(void *arg, struct sk_buff *os_buf)
95{
96	struct nss_data_plane_param *dp = (struct nss_data_plane_param *)arg;
97
98	return nss_phys_if_buf(dp->nss_ctx, os_buf, dp->if_num);
99}
100
101/*
102 * nss_data_plane_set_features()
103 *	Called by gmac to allow data plane to modify the set of features it supports
104*/
105static void nss_data_plane_set_features(struct net_device *netdev)
106{
107	netdev->features |= NSS_DP_SUPPORTED_FEATURES;
108	netdev->hw_features |= NSS_DP_SUPPORTED_FEATURES;
109	netdev->vlan_features |= NSS_DP_SUPPORTED_FEATURES;
110	netdev->wanted_features |= NSS_DP_SUPPORTED_FEATURES;
111}
112
113/*
114 * nss offload data plane ops
115 */
116static struct nss_gmac_data_plane_ops dp_ops =
117{
118	.open		= nss_data_plane_open,
119	.close		= nss_data_plane_close,
120	.link_state	= nss_data_plane_link_state,
121	.mac_addr	= nss_data_plane_mac_addr,
122	.change_mtu	= nss_data_plane_change_mtu,
123	.xmit		= nss_data_plane_buf,
124	.set_features	= nss_data_plane_set_features,
125};
126
127/*
128 * nss_data_plane_set_enabled()
129 */
130void nss_data_plane_set_enabled(int if_num)
131{
132	nss_data_plane_params[if_num].enabled = 1;
133}
134
135/*
136 * nss_data_plane_register_to_nss_gmac()
137 */
138bool nss_data_plane_register_to_nss_gmac(struct nss_ctx_instance *nss_ctx, int if_num)
139{
140	struct nss_data_plane_param *ndpp = &nss_data_plane_params[if_num];
141	struct nss_top_instance *nss_top = nss_ctx->nss_top;
142	struct net_device *netdev;
143	bool is_open;
144
145	if (!ndpp->enabled) {
146		return false;
147	}
148
149	netdev = nss_gmac_get_netdev_by_macid(if_num);
150	if (!netdev) {
151		nss_info("Platform don't have gmac%d enabled, don't bring up nss_phys_if and don't register to nss-gmac", if_num);
152		return false;
153	}
154
155	is_open = nss_gmac_is_in_open_state(netdev);
156	ndpp->dev = netdev;
157	ndpp->nss_ctx = nss_ctx;
158	ndpp->if_num = if_num;
159	ndpp->notify_open = 0;
160	ndpp->features = 0;
161
162	if (nss_gmac_override_data_plane(netdev, &dp_ops, ndpp) != NSS_GMAC_SUCCESS) {
163		nss_info("Override nss-gmac data plane failed\n");
164		return false;
165	}
166
167	/*
168	 * Setup the receive callback so that data pkts received form NSS-FW will
169	 * be redirected to the gmac driver as we are overriding the data plane
170	 */
171	nss_top->phys_if_handler_id[if_num] = nss_ctx->id;
172	nss_phys_if_register_handler(if_num);
173
174	nss_top->subsys_dp_register[if_num].ndev = netdev;
175	nss_top->subsys_dp_register[if_num].cb = nss_gmac_receive;
176	nss_top->subsys_dp_register[if_num].app_data = NULL;
177	nss_top->subsys_dp_register[if_num].features = ndpp->features;
178
179	/*
180	 * Now we are registered and our side is ready, if the gmac was opened, ask it to start again
181	 */
182	if (is_open) {
183		nss_gmac_start_data_plane(netdev, ndpp);
184	}
185	return true;
186}
187
188/*
189 * nss_data_plane_unregister_from_nss_gmac()
190 */
191void nss_data_plane_unregister_from_nss_gmac(int if_num)
192{
193	nss_gmac_restore_data_plane(nss_data_plane_params[if_num].dev);
194	nss_data_plane_params[if_num].dev = NULL;
195	nss_data_plane_params[if_num].nss_ctx = NULL;
196	nss_data_plane_params[if_num].if_num = 0;
197	nss_data_plane_params[if_num].notify_open = 0;
198	nss_data_plane_params[if_num].enabled = 0;
199}
200