ethernet-common.c revision 226024
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: head/sys/mips/cavium/octe/ethernet-common.c 226024 2011-10-04 20:17:43Z marcel $");
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
47extern int octeon_is_simulation(void);
48
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 * Set the hardware MAC address for a device
94 *
95 * @param dev    Device to change the MAC address for
96 * @param addr   Address structure to change it too.
97 */
98void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
99{
100	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
101	cvmx_gmxx_prtx_cfg_t gmx_cfg;
102	int interface = INTERFACE(priv->port);
103	int index = INDEX(priv->port);
104
105	memcpy(priv->mac, addr, 6);
106
107	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
108		int i;
109		const uint8_t *ptr = addr;
110		uint64_t mac = 0;
111		for (i = 0; i < 6; i++)
112			mac = (mac<<8) | (uint64_t)(ptr[i]);
113
114		gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
115		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
116
117		cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
118		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]);
119		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]);
120		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]);
121		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]);
122		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]);
123		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]);
124		cvm_oct_common_set_multicast_list(ifp);
125		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
126	}
127}
128
129
130/**
131 * Change the link MTU. Unimplemented
132 *
133 * @param dev     Device to change
134 * @param new_mtu The new MTU
135 * @return Zero on success
136 */
137int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
138{
139	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
140	int interface = INTERFACE(priv->port);
141	int index = INDEX(priv->port);
142	int vlan_bytes = 4;
143
144	/* Limit the MTU to make sure the ethernet packets are between 64 bytes
145	   and 65535 bytes */
146	if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
147		printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes);
148		return -EINVAL;
149	}
150	ifp->if_mtu = new_mtu;
151
152	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
153		int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */
154
155		if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
156			/* Signal errors on packets larger than the MTU */
157			cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet);
158		} else {
159			/* Set the hardware to truncate packets larger than the MTU and
160				smaller the 64 bytes */
161			cvmx_pip_frm_len_chkx_t frm_len_chk;
162			frm_len_chk.u64 = 0;
163			frm_len_chk.s.minlen = 64;
164			frm_len_chk.s.maxlen = max_packet;
165			cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64);
166		}
167		/* Set the hardware to truncate packets larger than the MTU. The
168		   jabber register must be set to a multiple of 8 bytes, so round up */
169		cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u);
170	}
171	return 0;
172}
173
174
175/**
176 * Enable port.
177 */
178int cvm_oct_common_open(struct ifnet *ifp)
179{
180	cvmx_gmxx_prtx_cfg_t gmx_cfg;
181	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
182	int interface = INTERFACE(priv->port);
183	int index = INDEX(priv->port);
184	cvmx_helper_link_info_t link_info;
185
186	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
187	gmx_cfg.s.en = 1;
188	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
189
190	/*
191	 * Set the link state unless we are using MII.
192	 */
193        if (!octeon_is_simulation() && priv->miibus == NULL) {
194             link_info = cvmx_helper_link_get(priv->port);
195             if (!link_info.s.link_up)
196		if_link_state_change(ifp, LINK_STATE_DOWN);
197	     else
198		if_link_state_change(ifp, LINK_STATE_UP);
199        }
200
201	return 0;
202}
203
204
205/**
206 * Disable port.
207 */
208int cvm_oct_common_stop(struct ifnet *ifp)
209{
210	cvmx_gmxx_prtx_cfg_t gmx_cfg;
211	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
212	int interface = INTERFACE(priv->port);
213	int index = INDEX(priv->port);
214
215	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
216	gmx_cfg.s.en = 0;
217	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
218	return 0;
219}
220
221/**
222 * Poll for link status change.
223 */
224void cvm_oct_common_poll(struct ifnet *ifp)
225{
226	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
227	cvmx_helper_link_info_t link_info;
228
229	/*
230	 * If this is a simulation, do nothing.
231	 */
232	if (octeon_is_simulation())
233		return;
234
235	/*
236	 * If there is a device-specific poll method, use it.
237	 */
238	if (priv->poll != NULL) {
239		priv->poll(ifp);
240		return;
241	}
242
243	/*
244	 * If an MII bus is attached, don't use the Simple Executive's link
245	 * state routines.
246	 */
247	if (priv->miibus != NULL)
248		return;
249
250	/*
251	 * Use the Simple Executive's link state routines.
252	 */
253	link_info = cvmx_helper_link_get(priv->port);
254	if (link_info.u64 == priv->link_info)
255		return;
256
257	link_info = cvmx_helper_link_autoconf(priv->port);
258	priv->link_info = link_info.u64;
259	priv->need_link_update = 1;
260}
261
262
263/**
264 * Per network device initialization
265 *
266 * @param dev    Device to initialize
267 * @return Zero on success
268 */
269int cvm_oct_common_init(struct ifnet *ifp)
270{
271	char mac[6] = {
272		cvmx_sysinfo_get()->mac_addr_base[0],
273		cvmx_sysinfo_get()->mac_addr_base[1],
274		cvmx_sysinfo_get()->mac_addr_base[2],
275		cvmx_sysinfo_get()->mac_addr_base[3],
276		cvmx_sysinfo_get()->mac_addr_base[4],
277		cvmx_sysinfo_get()->mac_addr_base[5] };
278	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
279
280	mac[5] += cvm_oct_mac_addr_offset++;
281
282	ifp->if_mtu = ETHERMTU;
283
284	cvm_oct_mdio_setup_device(ifp);
285
286	cvm_oct_common_set_mac_address(ifp, mac);
287	cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
288
289	/*
290	 * Do any last-minute board-specific initialization.
291	 */
292	switch (cvmx_sysinfo_get()->board_type) {
293#if defined(OCTEON_VENDOR_LANNER)
294	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
295	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
296		if (priv->phy_id == 16)
297			cvm_oct_mv88e61xx_setup_device(ifp);
298		break;
299#endif
300	default:
301		break;
302	}
303
304	device_attach(priv->dev);
305
306	return 0;
307}
308
309void cvm_oct_common_uninit(struct ifnet *ifp)
310{
311    /* Currently nothing to do */
312}
313
314