]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/mips/cavium/octe/ethernet-common.c
MFV r302218: file 5.28.
[FreeBSD/FreeBSD.git] / sys / mips / cavium / octe / ethernet-common.c
1 /*************************************************************************
2 Copyright (c) 2003-2007  Cavium Networks (support@cavium.com). All rights
3 reserved.
4
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
8 met:
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
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.
24
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.
27
28 *************************************************************************/
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
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 #include <net/if_var.h>
44
45 #include "wrapper-cvmx-includes.h"
46 #include "ethernet-headers.h"
47
48 static uint64_t cvm_oct_mac_addr = 0;
49 static uint32_t cvm_oct_mac_addr_offset = 0;
50
51 /**
52  * Set the multicast list. Currently unimplemented.
53  *
54  * @param dev    Device to work on
55  */
56 void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
57 {
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);
62
63         if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
64                 cvmx_gmxx_rxx_adr_ctl_t control;
65                 control.u64 = 0;
66                 control.s.bcst = 1;     /* Allow broadcast MAC addresses */
67
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 */
71                 else
72                         control.s.mcst = 1; /* Force reject multicat packets */
73
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 */
76                 else
77                         control.s.cam_mode = 1; /* Filter packets based on the CAM */
78
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);
81
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);
85                 else
86                         cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
87
88                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
89         }
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 /**
168  * Change the link MTU. Unimplemented
169  *
170  * @param dev     Device to change
171  * @param new_mtu The new MTU
172  * @return Zero on success
173  */
174 int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
175 {
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);
179         int vlan_bytes = 4;
180
181         /* Limit the MTU to make sure the ethernet packets are between 64 bytes
182            and 65535 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);
185                 return -EINVAL;
186         }
187         ifp->if_mtu = new_mtu;
188
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. */
191
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);
195                 } else {
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;
199                         frm_len_chk.u64 = 0;
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);
203                 }
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);
207         }
208         return 0;
209 }
210
211
212 /**
213  * Enable port.
214  */
215 int cvm_oct_common_open(struct ifnet *ifp)
216 {
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;
222
223         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
224         gmx_cfg.s.en = 1;
225         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
226
227         /*
228          * Set the link state unless we are using MII.
229          */
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);
234              else
235                 if_link_state_change(ifp, LINK_STATE_UP);
236         }
237
238         return 0;
239 }
240
241
242 /**
243  * Disable port.
244  */
245 int cvm_oct_common_stop(struct ifnet *ifp)
246 {
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);
251
252         gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
253         gmx_cfg.s.en = 0;
254         cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
255         return 0;
256 }
257
258 /**
259  * Poll for link status change.
260  */
261 void cvm_oct_common_poll(struct ifnet *ifp)
262 {
263         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
264         cvmx_helper_link_info_t link_info;
265
266         /*
267          * If this is a simulation, do nothing.
268          */
269         if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
270                 return;
271
272         /*
273          * If there is a device-specific poll method, use it.
274          */
275         if (priv->poll != NULL) {
276                 priv->poll(ifp);
277                 return;
278         }
279
280         /*
281          * If an MII bus is attached, don't use the Simple Executive's link
282          * state routines.
283          */
284         if (priv->miibus != NULL)
285                 return;
286
287         /*
288          * Use the Simple Executive's link state routines.
289          */
290         link_info = cvmx_helper_link_get(priv->port);
291         if (link_info.u64 == priv->link_info)
292                 return;
293
294         link_info = cvmx_helper_link_autoconf(priv->port);
295         priv->link_info = link_info.u64;
296         priv->need_link_update = 1;
297 }
298
299
300 /**
301  * Per network device initialization
302  *
303  * @param dev    Device to initialize
304  * @return Zero on success
305  */
306 int cvm_oct_common_init(struct ifnet *ifp)
307 {
308         uint8_t mac[6];
309         cvm_oct_private_t *priv = (cvm_oct_private_t *)ifp->if_softc;
310
311         if (cvm_assign_mac_address(NULL, mac) != 0)
312                 return ENXIO;
313
314         ifp->if_mtu = ETHERMTU;
315
316         cvm_oct_mdio_setup_device(ifp);
317
318         cvm_oct_common_set_mac_address(ifp, mac);
319         cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
320
321         /*
322          * Do any last-minute board-specific initialization.
323          */
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);
330                 break;
331 #endif
332         default:
333                 break;
334         }
335
336         device_attach(priv->dev);
337
338         return 0;
339 }
340
341 void cvm_oct_common_uninit(struct ifnet *ifp)
342 {
343     /* Currently nothing to do */
344 }
345