1 /*************************************************************************
2 SPDX-License-Identifier: BSD-3-Clause
3
4 Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
5 reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above
15 copyright notice, this list of conditions and the following
16 disclaimer in the documentation and/or other materials provided
17 with the distribution.
18
19 * Neither the name of Cavium Networks nor the names of
20 its contributors may be used to endorse or promote products
21 derived from this software without specific prior written
22 permission.
23
24 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
26 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
27 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
29 *************************************************************************/
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/bus.h>
37 #include <sys/endian.h>
38 #include <sys/kernel.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41
42 #include <net/ethernet.h>
43 #include <net/if.h>
44 #include <net/if_var.h>
45
46 #include "wrapper-cvmx-includes.h"
47 #include "ethernet-headers.h"
48
49 static uint64_t cvm_oct_mac_addr = 0;
50 static 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 */
57 void 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 * Assign a MAC addres from the pool of available MAC addresses
95 * Can return as either a 64-bit value and/or 6 octets.
96 *
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
100 */
101 int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets)
102 {
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);
107
108 if (cvm_oct_mac_addr == 0)
109 return ENXIO;
110
111 cvm_oct_mac_addr_offset = cvmx_mgmt_port_num_ports();
112 cvm_oct_mac_addr += cvm_oct_mac_addr_offset;
113 }
114
115 if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count)
116 return ENXIO; /* Out of addresses to assign */
117
118 if (macp)
119 *macp = cvm_oct_mac_addr;
120 if (octets)
121 memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6);
122
123 cvm_oct_mac_addr++;
124 cvm_oct_mac_addr_offset++;
125
126 return 0;
127 }
128
129 /**
130 * Set the hardware MAC address for a device
131 *
132 * @param dev Device to change the MAC address for
133 * @param addr Address structure to change it too.
134 */
135 void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
136 {
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);
141
142 memcpy(priv->mac, addr, 6);
143
144 if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
145 int i;
146 const uint8_t *ptr = addr;
147 uint64_t mac = 0;
148 for (i = 0; i < 6; i++)
149 mac = (mac<<8) | (uint64_t)(ptr[i]);
150
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);
153
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);
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 */
173 int 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 * Enable port.
212 */
213 int cvm_oct_common_open(struct ifnet *ifp)
214 {
215 cvmx_gmxx_prtx_cfg_t gmx_cfg;
216 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
217 int interface = INTERFACE(priv->port);
218 int index = INDEX(priv->port);
219 cvmx_helper_link_info_t link_info;
220
221 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
222 gmx_cfg.s.en = 1;
223 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
224
225 /*
226 * Set the link state unless we are using MII.
227 */
228 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM && priv->miibus == NULL) {
229 link_info = cvmx_helper_link_get(priv->port);
230 if (!link_info.s.link_up)
231 if_link_state_change(ifp, LINK_STATE_DOWN);
232 else
233 if_link_state_change(ifp, LINK_STATE_UP);
234 }
235
236 return 0;
237 }
238
239 /**
240 * Disable port.
241 */
242 int cvm_oct_common_stop(struct ifnet *ifp)
243 {
244 cvmx_gmxx_prtx_cfg_t gmx_cfg;
245 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
246 int interface = INTERFACE(priv->port);
247 int index = INDEX(priv->port);
248
249 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
250 gmx_cfg.s.en = 0;
251 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
252 return 0;
253 }
254
255 /**
256 * Poll for link status change.
257 */
258 void cvm_oct_common_poll(struct ifnet *ifp)
259 {
260 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
261 cvmx_helper_link_info_t link_info;
262
263 /*
264 * If this is a simulation, do nothing.
265 */
266 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
267 return;
268
269 /*
270 * If there is a device-specific poll method, use it.
271 */
272 if (priv->poll != NULL) {
273 priv->poll(ifp);
274 return;
275 }
276
277 /*
278 * If an MII bus is attached, don't use the Simple Executive's link
279 * state routines.
280 */
281 if (priv->miibus != NULL)
282 return;
283
284 /*
285 * Use the Simple Executive's link state routines.
286 */
287 link_info = cvmx_helper_link_get(priv->port);
288 if (link_info.u64 == priv->link_info)
289 return;
290
291 link_info = cvmx_helper_link_autoconf(priv->port);
292 priv->link_info = link_info.u64;
293 priv->need_link_update = 1;
294 }
295
296 /**
297 * Per network device initialization
298 *
299 * @param dev Device to initialize
300 * @return Zero on success
301 */
302 int cvm_oct_common_init(struct ifnet *ifp)
303 {
304 uint8_t mac[6];
305 cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
306
307 if (cvm_assign_mac_address(NULL, mac) != 0)
308 return ENXIO;
309
310 ifp->if_mtu = ETHERMTU;
311
312 cvm_oct_mdio_setup_device(ifp);
313
314 cvm_oct_common_set_mac_address(ifp, mac);
315 cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
316
317 /*
318 * Do any last-minute board-specific initialization.
319 */
320 switch (cvmx_sysinfo_get()->board_type) {
321 #if defined(OCTEON_VENDOR_LANNER)
322 case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
323 case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
324 if (priv->phy_id == 16)
325 cvm_oct_mv88e61xx_setup_device(ifp);
326 break;
327 #endif
328 default:
329 break;
330 }
331
332 device_attach(priv->dev);
333
334 return 0;
335 }
336
337 void cvm_oct_common_uninit(struct ifnet *ifp)
338 {
339 /* Currently nothing to do */
340 }
Cache object: 500d57f74b1f318adad3779cbe262739
|