1/*************************************************************************
2Copyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
3reserved.
4
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
9
10    * Redistributions of source code must retain the above copyright
11      notice, this list of conditions and the following disclaimer.
12
13    * Redistributions in binary form must reproduce the above
14      copyright notice, this list of conditions and the following
15      disclaimer in the documentation and/or other materials provided
16      with the distribution.
17
18    * Neither the name of Cavium Networks nor the names of
19      its contributors may be used to endorse or promote products
20      derived from this software without specific prior written
21      permission.
22
23This Software, including technical data, may be subject to U.S. export  control laws, including the U.S. Export Administration Act and its  associated regulations, and may be subject to export or import  regulations in other countries.
24
25TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26AND WITH ALL FAULTS AND CAVIUM  NETWORKS MAKES NO PROMISES, REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
27
28*************************************************************************/
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: releng/10.3/sys/mips/cavium/octe/ethernet-common.c 250192 2013-05-02 19:47:36Z imp $");
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/bus.h>
36#include <sys/endian.h>
37#include <sys/kernel.h>
38#include <sys/mbuf.h>
39#include <sys/socket.h>
40
41#include <net/ethernet.h>
42#include <net/if.h>
43
44#include "wrapper-cvmx-includes.h"
45#include "ethernet-headers.h"
46
47static uint64_t cvm_oct_mac_addr = 0;
48static uint32_t cvm_oct_mac_addr_offset = 0;
49
50/**
51 * Set the multicast list. Currently unimplemented.
52 *
53 * @param dev    Device to work on
54 */
55void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
56{
57	cvmx_gmxx_prtx_cfg_t gmx_cfg;
58	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
59	int interface = INTERFACE(priv->port);
60	int index = INDEX(priv->port);
61
62	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
63		cvmx_gmxx_rxx_adr_ctl_t control;
64		control.u64 = 0;
65		control.s.bcst = 1;     /* Allow broadcast MAC addresses */
66
67		if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) ||
68		    (ifp->if_flags & IFF_PROMISC))
69			control.s.mcst = 2; /* Force accept multicast packets */
70		else
71			control.s.mcst = 1; /* Force reject multicat packets */
72
73		if (ifp->if_flags & IFF_PROMISC)
74			control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */
75		else
76			control.s.cam_mode = 1; /* Filter packets based on the CAM */
77
78		gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
79		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
80
81		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64);
82		if (ifp->if_flags&IFF_PROMISC)
83			cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
84		else
85			cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
86
87		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
88	}
89}
90
91
92/**
93 * Assign a MAC addres from the pool of available MAC addresses
94 * Can return as either a 64-bit value and/or 6 octets.
95 *
96 * @param macp    Filled in with the assigned address if non-NULL
97 * @param octets  Filled in with the assigned address if non-NULL
98 * @return Zero on success
99 */
100int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets)
101{
102	/* Initialize from global MAC address base; fail if not set */
103	if (cvm_oct_mac_addr == 0) {
104		memcpy((uint8_t *)&cvm_oct_mac_addr + 2,
105		    cvmx_sysinfo_get()->mac_addr_base, 6);
106
107		if (cvm_oct_mac_addr == 0)
108			return ENXIO;
109
110		cvm_oct_mac_addr_offset = cvmx_mgmt_port_num_ports();
111		cvm_oct_mac_addr += cvm_oct_mac_addr_offset;
112	}
113
114	if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count)
115		return ENXIO;	    /* Out of addresses to assign */
116
117	if (macp)
118		*macp = cvm_oct_mac_addr;
119	if (octets)
120		memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6);
121
122	cvm_oct_mac_addr++;
123	cvm_oct_mac_addr_offset++;
124
125	return 0;
126}
127
128/**
129 * Set the hardware MAC address for a device
130 *
131 * @param dev    Device to change the MAC address for
132 * @param addr   Address structure to change it too.
133 */
134void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
135{
136	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
137	cvmx_gmxx_prtx_cfg_t gmx_cfg;
138	int interface = INTERFACE(priv->port);
139	int index = INDEX(priv->port);
140
141	memcpy(priv->mac, addr, 6);
142
143	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
144		int i;
145		const uint8_t *ptr = addr;
146		uint64_t mac = 0;
147		for (i = 0; i < 6; i++)
148			mac = (mac<<8) | (uint64_t)(ptr[i]);
149
150		gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
151		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
152
153		cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
154		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]);
155		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]);
156		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]);
157		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]);
158		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]);
159		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]);
160		cvm_oct_common_set_multicast_list(ifp);
161		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
162	}
163}
164
165
166/**
167 * Change the link MTU. Unimplemented
168 *
169 * @param dev     Device to change
170 * @param new_mtu The new MTU
171 * @return Zero on success
172 */
173int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
174{
175	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
176	int interface = INTERFACE(priv->port);
177	int index = INDEX(priv->port);
178	int vlan_bytes = 4;
179
180	/* Limit the MTU to make sure the ethernet packets are between 64 bytes
181	   and 65535 bytes */
182	if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
183		printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes);
184		return -EINVAL;
185	}
186	ifp->if_mtu = new_mtu;
187
188	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
189		int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */
190
191		if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
192			/* Signal errors on packets larger than the MTU */
193			cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet);
194		} else {
195			/* Set the hardware to truncate packets larger than the MTU and
196				smaller the 64 bytes */
197			cvmx_pip_frm_len_chkx_t frm_len_chk;
198			frm_len_chk.u64 = 0;
199			frm_len_chk.s.minlen = 64;
200			frm_len_chk.s.maxlen = max_packet;
201			cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64);
202		}
203		/* Set the hardware to truncate packets larger than the MTU. The
204		   jabber register must be set to a multiple of 8 bytes, so round up */
205		cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u);
206	}
207	return 0;
208}
209
210
211/**
212 * Enable port.
213 */
214int cvm_oct_common_open(struct ifnet *ifp)
215{
216	cvmx_gmxx_prtx_cfg_t gmx_cfg;
217	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
218	int interface = INTERFACE(priv->port);
219	int index = INDEX(priv->port);
220	cvmx_helper_link_info_t link_info;
221
222	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
223	gmx_cfg.s.en = 1;
224	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
225
226	/*
227	 * Set the link state unless we are using MII.
228	 */
229        if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM && priv->miibus == NULL) {
230             link_info = cvmx_helper_link_get(priv->port);
231             if (!link_info.s.link_up)
232		if_link_state_change(ifp, LINK_STATE_DOWN);
233	     else
234		if_link_state_change(ifp, LINK_STATE_UP);
235        }
236
237	return 0;
238}
239
240
241/**
242 * Disable port.
243 */
244int cvm_oct_common_stop(struct ifnet *ifp)
245{
246	cvmx_gmxx_prtx_cfg_t gmx_cfg;
247	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
248	int interface = INTERFACE(priv->port);
249	int index = INDEX(priv->port);
250
251	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
252	gmx_cfg.s.en = 0;
253	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
254	return 0;
255}
256
257/**
258 * Poll for link status change.
259 */
260void cvm_oct_common_poll(struct ifnet *ifp)
261{
262	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
263	cvmx_helper_link_info_t link_info;
264
265	/*
266	 * If this is a simulation, do nothing.
267	 */
268	if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
269		return;
270
271	/*
272	 * If there is a device-specific poll method, use it.
273	 */
274	if (priv->poll != NULL) {
275		priv->poll(ifp);
276		return;
277	}
278
279	/*
280	 * If an MII bus is attached, don't use the Simple Executive's link
281	 * state routines.
282	 */
283	if (priv->miibus != NULL)
284		return;
285
286	/*
287	 * Use the Simple Executive's link state routines.
288	 */
289	link_info = cvmx_helper_link_get(priv->port);
290	if (link_info.u64 == priv->link_info)
291		return;
292
293	link_info = cvmx_helper_link_autoconf(priv->port);
294	priv->link_info = link_info.u64;
295	priv->need_link_update = 1;
296}
297
298
299/**
300 * Per network device initialization
301 *
302 * @param dev    Device to initialize
303 * @return Zero on success
304 */
305int cvm_oct_common_init(struct ifnet *ifp)
306{
307	uint8_t mac[6];
308	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
309
310	if (cvm_assign_mac_address(NULL, mac) != 0)
311		return ENXIO;
312
313	ifp->if_mtu = ETHERMTU;
314
315	cvm_oct_mdio_setup_device(ifp);
316
317	cvm_oct_common_set_mac_address(ifp, mac);
318	cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
319
320	/*
321	 * Do any last-minute board-specific initialization.
322	 */
323	switch (cvmx_sysinfo_get()->board_type) {
324#if defined(OCTEON_VENDOR_LANNER)
325	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
326	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
327		if (priv->phy_id == 16)
328			cvm_oct_mv88e61xx_setup_device(ifp);
329		break;
330#endif
331	default:
332		break;
333	}
334
335	device_attach(priv->dev);
336
337	return 0;
338}
339
340void cvm_oct_common_uninit(struct ifnet *ifp)
341{
342    /* Currently nothing to do */
343}
344
345