1 /*************************************************************************
2 Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
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.
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
23 This 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.
25 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26 AND 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.
28 *************************************************************************/
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
39 #include <sys/socket.h>
41 #include <net/ethernet.h>
43 #include <net/if_var.h>
45 #include "wrapper-cvmx-includes.h"
46 #include "ethernet-headers.h"
48 static uint64_t cvm_oct_mac_addr = 0;
49 static uint32_t cvm_oct_mac_addr_offset = 0;
52 * Set the multicast list. Currently unimplemented.
54 * @param dev Device to work on
56 void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
58 cvmx_gmxx_prtx_cfg_t gmx_cfg;
59 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
60 int interface = INTERFACE(priv->port);
61 int index = INDEX(priv->port);
63 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
64 cvmx_gmxx_rxx_adr_ctl_t control;
66 control.s.bcst = 1; /* Allow broadcast MAC addresses */
68 if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) ||
69 (ifp->if_flags & IFF_PROMISC))
70 control.s.mcst = 2; /* Force accept multicast packets */
72 control.s.mcst = 1; /* Force reject multicat packets */
74 if (ifp->if_flags & IFF_PROMISC)
75 control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */
77 control.s.cam_mode = 1; /* Filter packets based on the CAM */
79 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
80 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
82 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64);
83 if (ifp->if_flags&IFF_PROMISC)
84 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
86 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
88 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
94 * Assign a MAC addres from the pool of available MAC addresses
95 * Can return as either a 64-bit value and/or 6 octets.
97 * @param macp Filled in with the assigned address if non-NULL
98 * @param octets Filled in with the assigned address if non-NULL
99 * @return Zero on success
101 int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets)
103 /* Initialize from global MAC address base; fail if not set */
104 if (cvm_oct_mac_addr == 0) {
105 memcpy((uint8_t *)&cvm_oct_mac_addr + 2,
106 cvmx_sysinfo_get()->mac_addr_base, 6);
108 if (cvm_oct_mac_addr == 0)
111 cvm_oct_mac_addr_offset = cvmx_mgmt_port_num_ports();
112 cvm_oct_mac_addr += cvm_oct_mac_addr_offset;
115 if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count)
116 return ENXIO; /* Out of addresses to assign */
119 *macp = cvm_oct_mac_addr;
121 memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6);
124 cvm_oct_mac_addr_offset++;
130 * Set the hardware MAC address for a device
132 * @param dev Device to change the MAC address for
133 * @param addr Address structure to change it too.
135 void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
137 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
138 cvmx_gmxx_prtx_cfg_t gmx_cfg;
139 int interface = INTERFACE(priv->port);
140 int index = INDEX(priv->port);
142 memcpy(priv->mac, addr, 6);
144 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
146 const uint8_t *ptr = addr;
148 for (i = 0; i < 6; i++)
149 mac = (mac<<8) | (uint64_t)(ptr[i]);
151 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
152 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
154 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
155 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]);
156 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]);
157 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]);
158 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]);
159 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]);
160 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]);
161 cvm_oct_common_set_multicast_list(ifp);
162 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
168 * Change the link MTU. Unimplemented
170 * @param dev Device to change
171 * @param new_mtu The new MTU
172 * @return Zero on success
174 int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
176 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
177 int interface = INTERFACE(priv->port);
178 int index = INDEX(priv->port);
181 /* Limit the MTU to make sure the ethernet packets are between 64 bytes
183 if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
184 printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes);
187 ifp->if_mtu = new_mtu;
189 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
190 int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */
192 if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
193 /* Signal errors on packets larger than the MTU */
194 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet);
196 /* Set the hardware to truncate packets larger than the MTU and
197 smaller the 64 bytes */
198 cvmx_pip_frm_len_chkx_t frm_len_chk;
200 frm_len_chk.s.minlen = 64;
201 frm_len_chk.s.maxlen = max_packet;
202 cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64);
204 /* Set the hardware to truncate packets larger than the MTU. The
205 jabber register must be set to a multiple of 8 bytes, so round up */
206 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u);
215 int cvm_oct_common_open(struct ifnet *ifp)
217 cvmx_gmxx_prtx_cfg_t gmx_cfg;
218 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
219 int interface = INTERFACE(priv->port);
220 int index = INDEX(priv->port);
221 cvmx_helper_link_info_t link_info;
223 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
225 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
228 * Set the link state unless we are using MII.
230 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM && priv->miibus == NULL) {
231 link_info = cvmx_helper_link_get(priv->port);
232 if (!link_info.s.link_up)
233 if_link_state_change(ifp, LINK_STATE_DOWN);
235 if_link_state_change(ifp, LINK_STATE_UP);
245 int cvm_oct_common_stop(struct ifnet *ifp)
247 cvmx_gmxx_prtx_cfg_t gmx_cfg;
248 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
249 int interface = INTERFACE(priv->port);
250 int index = INDEX(priv->port);
252 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
254 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
259 * Poll for link status change.
261 void cvm_oct_common_poll(struct ifnet *ifp)
263 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
264 cvmx_helper_link_info_t link_info;
267 * If this is a simulation, do nothing.
269 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
273 * If there is a device-specific poll method, use it.
275 if (priv->poll != NULL) {
281 * If an MII bus is attached, don't use the Simple Executive's link
284 if (priv->miibus != NULL)
288 * Use the Simple Executive's link state routines.
290 link_info = cvmx_helper_link_get(priv->port);
291 if (link_info.u64 == priv->link_info)
294 link_info = cvmx_helper_link_autoconf(priv->port);
295 priv->link_info = link_info.u64;
296 priv->need_link_update = 1;
301 * Per network device initialization
303 * @param dev Device to initialize
304 * @return Zero on success
306 int cvm_oct_common_init(struct ifnet *ifp)
309 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
311 if (cvm_assign_mac_address(NULL, mac) != 0)
314 ifp->if_mtu = ETHERMTU;
316 cvm_oct_mdio_setup_device(ifp);
318 cvm_oct_common_set_mac_address(ifp, mac);
319 cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
322 * Do any last-minute board-specific initialization.
324 switch (cvmx_sysinfo_get()->board_type) {
325 #if defined(OCTEON_VENDOR_LANNER)
326 case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
327 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
328 if (priv->phy_id == 16)
329 cvm_oct_mv88e61xx_setup_device(ifp);
336 device_attach(priv->dev);
341 void cvm_oct_common_uninit(struct ifnet *ifp)
343 /* Currently nothing to do */