]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/octe/ethernet-common.c
Merge ^/vendor/clang/dist up to its last change, and resolve conflicts.
[FreeBSD/FreeBSD.git] / sys / mips / cavium / octe / ethernet-common.c
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
8 Redistribution and use in source and binary forms, with or without
9 modification, are permitted provided that the following conditions are
10 met:
11
12     * Redistributions of source code must retain the above copyright
13       notice, this list of conditions and the following disclaimer.
14
15     * Redistributions in binary form must reproduce the above
16       copyright notice, this list of conditions and the following
17       disclaimer in the documentation and/or other materials provided
18       with the distribution.
19
20     * Neither the name of Cavium Networks nor the names of
21       its contributors may be used to endorse or promote products
22       derived from this software without specific prior written
23       permission.
24
25 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.
26
27 TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
28 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.
29
30 *************************************************************************/
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/bus.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
40 #include <sys/mbuf.h>
41 #include <sys/socket.h>
42
43 #include <net/ethernet.h>
44 #include <net/if.h>
45 #include <net/if_var.h>
46
47 #include "wrapper-cvmx-includes.h"
48 #include "ethernet-headers.h"
49
50 static uint64_t cvm_oct_mac_addr = 0;
51 static uint32_t cvm_oct_mac_addr_offset = 0;
52
53 /**
54  * Set the multicast list. Currently unimplemented.
55  *
56  * @param dev    Device to work on
57  */
58 void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
59 {
60         cvmx_gmxx_prtx_cfg_t gmx_cfg;
61         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
62         int interface = INTERFACE(priv->port);
63         int index = INDEX(priv->port);
64
65         if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
66                 cvmx_gmxx_rxx_adr_ctl_t control;
67                 control.u64 = 0;
68                 control.s.bcst = 1;     /* Allow broadcast MAC addresses */
69
70                 if (/*ifp->mc_list || */(ifp->if_flags&IFF_ALLMULTI) ||
71                     (ifp->if_flags & IFF_PROMISC))
72                         control.s.mcst = 2; /* Force accept multicast packets */
73                 else
74                         control.s.mcst = 1; /* Force reject multicat packets */
75
76                 if (ifp->if_flags & IFF_PROMISC)
77                         control.s.cam_mode = 0; /* Reject matches if promisc. Since CAM is shut off, should accept everything */
78                 else
79                         control.s.cam_mode = 1; /* Filter packets based on the CAM */
80
81                 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
82                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
83
84                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CTL(index, interface), control.u64);
85                 if (ifp->if_flags&IFF_PROMISC)
86                         cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 0);
87                 else
88                         cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
89
90                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
91         }
92 }
93
94
95 /**
96  * Assign a MAC addres from the pool of available MAC addresses
97  * Can return as either a 64-bit value and/or 6 octets.
98  *
99  * @param macp    Filled in with the assigned address if non-NULL
100  * @param octets  Filled in with the assigned address if non-NULL
101  * @return Zero on success
102  */
103 int cvm_assign_mac_address(uint64_t *macp, uint8_t *octets)
104 {
105         /* Initialize from global MAC address base; fail if not set */
106         if (cvm_oct_mac_addr == 0) {
107                 memcpy((uint8_t *)&cvm_oct_mac_addr + 2,
108                     cvmx_sysinfo_get()->mac_addr_base, 6);
109
110                 if (cvm_oct_mac_addr == 0)
111                         return ENXIO;
112
113                 cvm_oct_mac_addr_offset = cvmx_mgmt_port_num_ports();
114                 cvm_oct_mac_addr += cvm_oct_mac_addr_offset;
115         }
116
117         if (cvm_oct_mac_addr_offset >= cvmx_sysinfo_get()->mac_addr_count)
118                 return ENXIO;       /* Out of addresses to assign */
119         
120         if (macp)
121                 *macp = cvm_oct_mac_addr;
122         if (octets)
123                 memcpy(octets, (u_int8_t *)&cvm_oct_mac_addr + 2, 6);
124
125         cvm_oct_mac_addr++;
126         cvm_oct_mac_addr_offset++;
127
128         return 0;
129 }
130
131 /**
132  * Set the hardware MAC address for a device
133  *
134  * @param dev    Device to change the MAC address for
135  * @param addr   Address structure to change it too.
136  */
137 void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
138 {
139         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
140         cvmx_gmxx_prtx_cfg_t gmx_cfg;
141         int interface = INTERFACE(priv->port);
142         int index = INDEX(priv->port);
143
144         memcpy(priv->mac, addr, 6);
145
146         if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
147                 int i;
148                 const uint8_t *ptr = addr;
149                 uint64_t mac = 0;
150                 for (i = 0; i < 6; i++)
151                         mac = (mac<<8) | (uint64_t)(ptr[i]);
152
153                 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
154                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64 & ~1ull);
155
156                 cvmx_write_csr(CVMX_GMXX_SMACX(index, interface), mac);
157                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM0(index, interface), ptr[0]);
158                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM1(index, interface), ptr[1]);
159                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM2(index, interface), ptr[2]);
160                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM3(index, interface), ptr[3]);
161                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM4(index, interface), ptr[4]);
162                 cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM5(index, interface), ptr[5]);
163                 cvm_oct_common_set_multicast_list(ifp);
164                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
165         }
166 }
167
168
169 /**
170  * Change the link MTU. Unimplemented
171  *
172  * @param dev     Device to change
173  * @param new_mtu The new MTU
174  * @return Zero on success
175  */
176 int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
177 {
178         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
179         int interface = INTERFACE(priv->port);
180         int index = INDEX(priv->port);
181         int vlan_bytes = 4;
182
183         /* Limit the MTU to make sure the ethernet packets are between 64 bytes
184            and 65535 bytes */
185         if ((new_mtu + 14 + 4 + vlan_bytes < 64) || (new_mtu + 14 + 4 + vlan_bytes > 65392)) {
186                 printf("MTU must be between %d and %d.\n", 64-14-4-vlan_bytes, 65392-14-4-vlan_bytes);
187                 return -EINVAL;
188         }
189         ifp->if_mtu = new_mtu;
190
191         if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
192                 int max_packet = new_mtu + 14 + 4 + vlan_bytes; /* Add ethernet header and FCS, and VLAN if configured. */
193
194                 if (OCTEON_IS_MODEL(OCTEON_CN3XXX) || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
195                         /* Signal errors on packets larger than the MTU */
196                         cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(index, interface), max_packet);
197                 } else {
198                         /* Set the hardware to truncate packets larger than the MTU and
199                                 smaller the 64 bytes */
200                         cvmx_pip_frm_len_chkx_t frm_len_chk;
201                         frm_len_chk.u64 = 0;
202                         frm_len_chk.s.minlen = 64;
203                         frm_len_chk.s.maxlen = max_packet;
204                         cvmx_write_csr(CVMX_PIP_FRM_LEN_CHKX(interface), frm_len_chk.u64);
205                 }
206                 /* Set the hardware to truncate packets larger than the MTU. The
207                    jabber register must be set to a multiple of 8 bytes, so round up */
208                 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(index, interface), (max_packet + 7) & ~7u);
209         }
210         return 0;
211 }
212
213
214 /**
215  * Enable port.
216  */
217 int cvm_oct_common_open(struct ifnet *ifp)
218 {
219         cvmx_gmxx_prtx_cfg_t gmx_cfg;
220         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
221         int interface = INTERFACE(priv->port);
222         int index = INDEX(priv->port);
223         cvmx_helper_link_info_t link_info;
224
225         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
226         gmx_cfg.s.en = 1;
227         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
228
229         /*
230          * Set the link state unless we are using MII.
231          */
232         if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM && priv->miibus == NULL) {
233              link_info = cvmx_helper_link_get(priv->port);
234              if (!link_info.s.link_up)  
235                 if_link_state_change(ifp, LINK_STATE_DOWN);
236              else
237                 if_link_state_change(ifp, LINK_STATE_UP);
238         }
239
240         return 0;
241 }
242
243
244 /**
245  * Disable port.
246  */
247 int cvm_oct_common_stop(struct ifnet *ifp)
248 {
249         cvmx_gmxx_prtx_cfg_t gmx_cfg;
250         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
251         int interface = INTERFACE(priv->port);
252         int index = INDEX(priv->port);
253
254         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
255         gmx_cfg.s.en = 0;
256         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
257         return 0;
258 }
259
260 /**
261  * Poll for link status change.
262  */
263 void cvm_oct_common_poll(struct ifnet *ifp)
264 {
265         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
266         cvmx_helper_link_info_t link_info;
267
268         /*
269          * If this is a simulation, do nothing.
270          */
271         if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
272                 return;
273
274         /*
275          * If there is a device-specific poll method, use it.
276          */
277         if (priv->poll != NULL) {
278                 priv->poll(ifp);
279                 return;
280         }
281
282         /*
283          * If an MII bus is attached, don't use the Simple Executive's link
284          * state routines.
285          */
286         if (priv->miibus != NULL)
287                 return;
288
289         /*
290          * Use the Simple Executive's link state routines.
291          */
292         link_info = cvmx_helper_link_get(priv->port);
293         if (link_info.u64 == priv->link_info)
294                 return;
295
296         link_info = cvmx_helper_link_autoconf(priv->port);
297         priv->link_info = link_info.u64;
298         priv->need_link_update = 1;
299 }
300
301
302 /**
303  * Per network device initialization
304  *
305  * @param dev    Device to initialize
306  * @return Zero on success
307  */
308 int cvm_oct_common_init(struct ifnet *ifp)
309 {
310         uint8_t mac[6];
311         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
312
313         if (cvm_assign_mac_address(NULL, mac) != 0)
314                 return ENXIO;
315
316         ifp->if_mtu = ETHERMTU;
317
318         cvm_oct_mdio_setup_device(ifp);
319
320         cvm_oct_common_set_mac_address(ifp, mac);
321         cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
322
323         /*
324          * Do any last-minute board-specific initialization.
325          */
326         switch (cvmx_sysinfo_get()->board_type) {
327 #if defined(OCTEON_VENDOR_LANNER)
328         case CVMX_BOARD_TYPE_CUST_LANNER_MR320:
329         case CVMX_BOARD_TYPE_CUST_LANNER_MR321X:
330                 if (priv->phy_id == 16)
331                         cvm_oct_mv88e61xx_setup_device(ifp);
332                 break;
333 #endif
334         default:
335                 break;
336         }
337
338         device_attach(priv->dev);
339
340         return 0;
341 }
342
343 void cvm_oct_common_uninit(struct ifnet *ifp)
344 {
345     /* Currently nothing to do */
346 }
347