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>
44 #include "wrapper-cvmx-includes.h"
45 #include "ethernet-headers.h"
47 extern int octeon_is_simulation(void);
48 extern cvmx_bootinfo_t *octeon_bootinfo;
49 extern int pow_send_group;
50 extern int always_use_pow;
51 extern char pow_send_list[];
55 * Get the low level ethernet statistics
57 * @param dev Device to get the statistics from
58 * @return Pointer to the statistics
61 static struct ifnet_stats *cvm_oct_common_get_stats(struct ifnet *ifp)
63 cvmx_pip_port_status_t rx_status;
64 cvmx_pko_port_status_t tx_status;
65 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
67 if (priv->port < CVMX_PIP_NUM_INPUT_PORTS) {
68 if (octeon_is_simulation()) {
69 /* The simulator doesn't support statistics */
70 memset(&rx_status, 0, sizeof(rx_status));
71 memset(&tx_status, 0, sizeof(tx_status));
73 cvmx_pip_get_port_status(priv->port, 1, &rx_status);
74 cvmx_pko_get_port_status(priv->port, 1, &tx_status);
77 priv->stats.rx_packets += rx_status.inb_packets;
78 priv->stats.tx_packets += tx_status.packets;
79 priv->stats.rx_bytes += rx_status.inb_octets;
80 priv->stats.tx_bytes += tx_status.octets;
81 priv->stats.multicast += rx_status.multicast_packets;
82 priv->stats.rx_crc_errors += rx_status.inb_errors;
83 priv->stats.rx_frame_errors += rx_status.fcs_align_err_packets;
85 /* The drop counter must be incremented atomically since the RX
86 tasklet also increments it */
88 cvmx_atomic_add64_nosync(&priv->stats.rx_dropped, rx_status.dropped_packets);
90 cvmx_atomic_add32_nosync((int32_t *)&priv->stats.rx_dropped, rx_status.dropped_packets);
100 * Set the multicast list. Currently unimplemented.
102 * @param dev Device to work on
104 void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
106 cvmx_gmxx_prtx_cfg_t gmx_cfg;
107 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
108 int interface = INTERFACE(priv->port);
109 int index = INDEX(priv->port);
111 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
112 cvmx_gmxx_rxx_adr_ctl_t control;
114 control.s.bcst = 1; /* Allow broadcast MAC addresses */
116 if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) ||
117 (ifp->if_flags & IFF_PROMISC))
118 control.s.mcst = 2; /* Force accept multicast packets */
120 control.s.mcst = 1; /* Force reject multicat packets */
122 if (ifp->if_flags & IFF_PROMISC)
123 control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */
125 control.s.cam_mode = 1; /* Filter packets based on the CAM */
127 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
128 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
130 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64);
131 if (ifp->if_flags&IFF_PROMISC)
132 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
134 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
136 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
142 * Set the hardware MAC address for a device
144 * @param dev Device to change the MAC address for
145 * @param addr Address structure to change it too.
147 void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
149 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
150 cvmx_gmxx_prtx_cfg_t gmx_cfg;
151 int interface = INTERFACE(priv->port);
152 int index = INDEX(priv->port);
154 memcpy(priv->mac, addr, 6);
156 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
158 const uint8_t *ptr = addr;
160 for (i = 0; i < 6; i++)
161 mac = (mac<<8) | (uint64_t)(ptr[i]);
163 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
164 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
166 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
167 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]);
168 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]);
169 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]);
170 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]);
171 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]);
172 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]);
173 cvm_oct_common_set_multicast_list(ifp);
174 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
180 * Change the link MTU. Unimplemented
182 * @param dev Device to change
183 * @param new_mtu The new MTU
184 * @return Zero on success
186 int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
188 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
189 int interface = INTERFACE(priv->port);
190 int index = INDEX(priv->port);
193 /* Limit the MTU to make sure the ethernet packets are between 64 bytes
195 if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
196 printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes);
199 ifp->if_mtu = new_mtu;
201 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
202 int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */
204 if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
205 /* Signal errors on packets larger than the MTU */
206 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet);
208 /* Set the hardware to truncate packets larger than the MTU and
209 smaller the 64 bytes */
210 cvmx_pip_frm_len_chkx_t frm_len_chk;
212 frm_len_chk.s.minlen = 64;
213 frm_len_chk.s.maxlen = max_packet;
214 cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64);
216 /* Set the hardware to truncate packets larger than the MTU. The
217 jabber register must be set to a multiple of 8 bytes, so round up */
218 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u);
225 * Per network device initialization
227 * @param dev Device to initialize
228 * @return Zero on success
230 int cvm_oct_common_init(struct ifnet *ifp)
234 octeon_bootinfo->mac_addr_base[0],
235 octeon_bootinfo->mac_addr_base[1],
236 octeon_bootinfo->mac_addr_base[2],
237 octeon_bootinfo->mac_addr_base[3],
238 octeon_bootinfo->mac_addr_base[4],
239 octeon_bootinfo->mac_addr_base[5] + count};
240 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
242 /* Force the interface to use the POW send if always_use_pow was
243 specified or it is in the pow send list */
244 if ((pow_send_group != -1) && (always_use_pow || strstr(pow_send_list, if_name(ifp))))
247 ifp->if_mtu = ETHERMTU;
252 ifp->get_stats = cvm_oct_common_get_stats;
253 #ifdef CONFIG_NET_POLL_CONTROLLER
254 ifp->poll_controller = cvm_oct_poll_controller;
258 cvm_oct_mdio_setup_device(ifp);
260 cvm_oct_common_set_mac_address(ifp, mac);
261 cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
264 /* Zero out stats for port so we won't mistakenly show counters from the
266 memset(ifp->get_stats(ifp), 0, sizeof(struct ifnet_stats));
270 * Do any last-minute board-specific initialization.
272 switch (cvmx_sysinfo_get()->board_type) {
273 #if defined(OCTEON_VENDOR_LANNER)
274 case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
275 if (priv->phy_id == 16)
276 cvm_oct_mv88e61xx_setup_device(ifp);
283 device_attach(priv->dev);
288 void cvm_oct_common_uninit(struct ifnet *ifp)
290 /* Currently nothing to do */