ethernet-common.c revision 232289
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 232289 2012-02-29 05:48:29Z gonzo $");
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
49static uint64_t cvm_oct_mac_addr = 0;
50static uint32_t cvm_oct_mac_addr_offset = 0;
51
52/**
53 * Set the multicast list. Currently unimplemented.
54 *
55 * @param dev    Device to work on
56 */
57void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
58{
59	cvmx_gmxx_prtx_cfg_t gmx_cfg;
60	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
61	int interface = INTERFACE(priv->port);
62	int index = INDEX(priv->port);
63
64	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
65		cvmx_gmxx_rxx_adr_ctl_t control;
66		control.u64 = 0;
67		control.s.bcst = 1;     /* Allow broadcast MAC addresses */
68
69		if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) ||
70		    (ifp->if_flags & IFF_PROMISC))
71			control.s.mcst = 2; /* Force accept multicast packets */
72		else
73			control.s.mcst = 1; /* Force reject multicat packets */
74
75		if (ifp->if_flags & IFF_PROMISC)
76			control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */
77		else
78			control.s.cam_mode = 1; /* Filter packets based on the CAM */
79
80		gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
81		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
82
83		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64);
84		if (ifp->if_flags&IFF_PROMISC)
85			cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
86		else
87			cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
88
89		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
90	}
91}
92
93
94/**
95 * Assign a MAC addres from the pool of available MAC addresses
96 * Can return as either a 64-bit value and/or 6 octets.
97 *
98 * @param macp    Filled in with the assigned address if non-NULL
99 * @param octets  Filled in with the assigned address if non-NULL
100 * @return Zero on success
101 */
102int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets)
103{
104	/* Initialize from global MAC address base; fail if not set */
105	if (cvm_oct_mac_addr == 0) {
106		memcpy((uint8_t *)&cvm_oct_mac_addr + 2,
107		    cvmx_sysinfo_get()->mac_addr_base, 6);
108
109		if (cvm_oct_mac_addr == 0)
110			return ENXIO;
111
112		/*
113		 * The offset from mac_addr_base that should be used for the next port
114		 * that is configured.  By convention, if any mgmt ports exist on the
115		 * chip, they get the first mac addresses.  The ports controlled by
116		 * driver that use this function are numbered sequencially following
117		 * any mgmt addresses that may exist.
118		 *
119		 * XXX Would be nice if __cvmx_mgmt_port_num_ports() were
120		 *     not static to cvmx-mgmt-port.c.
121		 */
122		if (OCTEON_IS_MODEL(OCTEON_CN56XX))
123			cvm_oct_mac_addr_offset = 1;
124		else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
125			cvm_oct_mac_addr_offset = 2;
126		else
127			cvm_oct_mac_addr_offset = 0;
128		cvm_oct_mac_addr += cvm_oct_mac_addr_offset;
129	}
130
131	if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count)
132		return ENXIO;	    /* Out of addresses to assign */
133
134	if (macp)
135		*macp = cvm_oct_mac_addr;
136	if (octets)
137		memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6);
138
139	cvm_oct_mac_addr++;
140	cvm_oct_mac_addr_offset++;
141
142	return 0;
143}
144
145/**
146 * Set the hardware MAC address for a device
147 *
148 * @param dev    Device to change the MAC address for
149 * @param addr   Address structure to change it too.
150 */
151void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
152{
153	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
154	cvmx_gmxx_prtx_cfg_t gmx_cfg;
155	int interface = INTERFACE(priv->port);
156	int index = INDEX(priv->port);
157
158	memcpy(priv->mac, addr, 6);
159
160	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
161		int i;
162		const uint8_t *ptr = addr;
163		uint64_t mac = 0;
164		for (i = 0; i < 6; i++)
165			mac = (mac<<8) | (uint64_t)(ptr[i]);
166
167		gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
168		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
169
170		cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
171		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]);
172		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]);
173		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]);
174		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]);
175		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]);
176		cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]);
177		cvm_oct_common_set_multicast_list(ifp);
178		cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
179	}
180}
181
182
183/**
184 * Change the link MTU. Unimplemented
185 *
186 * @param dev     Device to change
187 * @param new_mtu The new MTU
188 * @return Zero on success
189 */
190int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
191{
192	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
193	int interface = INTERFACE(priv->port);
194	int index = INDEX(priv->port);
195	int vlan_bytes = 4;
196
197	/* Limit the MTU to make sure the ethernet packets are between 64 bytes
198	   and 65535 bytes */
199	if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
200		printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes);
201		return -EINVAL;
202	}
203	ifp->if_mtu = new_mtu;
204
205	if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
206		int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */
207
208		if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
209			/* Signal errors on packets larger than the MTU */
210			cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet);
211		} else {
212			/* Set the hardware to truncate packets larger than the MTU and
213				smaller the 64 bytes */
214			cvmx_pip_frm_len_chkx_t frm_len_chk;
215			frm_len_chk.u64 = 0;
216			frm_len_chk.s.minlen = 64;
217			frm_len_chk.s.maxlen = max_packet;
218			cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64);
219		}
220		/* Set the hardware to truncate packets larger than the MTU. The
221		   jabber register must be set to a multiple of 8 bytes, so round up */
222		cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u);
223	}
224	return 0;
225}
226
227
228/**
229 * Enable port.
230 */
231int cvm_oct_common_open(struct ifnet *ifp)
232{
233	cvmx_gmxx_prtx_cfg_t gmx_cfg;
234	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
235	int interface = INTERFACE(priv->port);
236	int index = INDEX(priv->port);
237	cvmx_helper_link_info_t link_info;
238
239	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
240	gmx_cfg.s.en = 1;
241	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
242
243	/*
244	 * Set the link state unless we are using MII.
245	 */
246        if (!octeon_is_simulation() && priv->miibus == NULL) {
247             link_info = cvmx_helper_link_get(priv->port);
248             if (!link_info.s.link_up)
249		if_link_state_change(ifp, LINK_STATE_DOWN);
250	     else
251		if_link_state_change(ifp, LINK_STATE_UP);
252        }
253
254	return 0;
255}
256
257
258/**
259 * Disable port.
260 */
261int cvm_oct_common_stop(struct ifnet *ifp)
262{
263	cvmx_gmxx_prtx_cfg_t gmx_cfg;
264	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
265	int interface = INTERFACE(priv->port);
266	int index = INDEX(priv->port);
267
268	gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
269	gmx_cfg.s.en = 0;
270	cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
271	return 0;
272}
273
274/**
275 * Poll for link status change.
276 */
277void cvm_oct_common_poll(struct ifnet *ifp)
278{
279	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
280	cvmx_helper_link_info_t link_info;
281
282	/*
283	 * If this is a simulation, do nothing.
284	 */
285	if (octeon_is_simulation())
286		return;
287
288	/*
289	 * If there is a device-specific poll method, use it.
290	 */
291	if (priv->poll != NULL) {
292		priv->poll(ifp);
293		return;
294	}
295
296	/*
297	 * If an MII bus is attached, don't use the Simple Executive's link
298	 * state routines.
299	 */
300	if (priv->miibus != NULL)
301		return;
302
303	/*
304	 * Use the Simple Executive's link state routines.
305	 */
306	link_info = cvmx_helper_link_get(priv->port);
307	if (link_info.u64 == priv->link_info)
308		return;
309
310	link_info = cvmx_helper_link_autoconf(priv->port);
311	priv->link_info = link_info.u64;
312	priv->need_link_update = 1;
313}
314
315
316/**
317 * Per network device initialization
318 *
319 * @param dev    Device to initialize
320 * @return Zero on success
321 */
322int cvm_oct_common_init(struct ifnet *ifp)
323{
324	uint8_t mac[6];
325	cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
326
327	if (cvm_assign_mac_address(NULL, mac) != 0)
328		return ENXIO;
329
330	ifp->if_mtu = ETHERMTU;
331
332	cvm_oct_mdio_setup_device(ifp);
333
334	cvm_oct_common_set_mac_address(ifp, mac);
335	cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
336
337	/*
338	 * Do any last-minute board-specific initialization.
339	 */
340	switch (cvmx_sysinfo_get()->board_type) {
341#if defined(OCTEON_VENDOR_LANNER)
342	case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
343	case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
344		if (priv->phy_id == 16)
345			cvm_oct_mv88e61xx_setup_device(ifp);
346		break;
347#endif
348	default:
349		break;
350	}
351
352	device_attach(priv->dev);
353
354	return 0;
355}
356
357void cvm_oct_common_uninit(struct ifnet *ifp)
358{
359    /* Currently nothing to do */
360}
361
362