]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/mips/cavium/octe/ethernet-common.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.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
44 #include "wrapper-cvmx-includes.h"
45 #include "ethernet-headers.h"
46
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[];
52
53
54 /**
55  * Get the low level ethernet statistics
56  *
57  * @param dev    Device to get the statistics from
58  * @return Pointer to the statistics
59  */
60 #if 0
61 static struct ifnet_stats *cvm_oct_common_get_stats(struct ifnet *ifp)
62 {
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;
66
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));
72                 } else {
73                 cvmx_pip_get_port_status(priv->port, 1, &rx_status);
74                 cvmx_pko_get_port_status(priv->port, 1, &tx_status);
75                 }
76
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;
84
85                 /* The drop counter must be incremented atomically since the RX
86                    tasklet also increments it */
87 #ifdef CONFIG_64BIT
88                 cvmx_atomic_add64_nosync(&priv->stats.rx_dropped, rx_status.dropped_packets);
89 #else
90                 cvmx_atomic_add32_nosync((int32_t *)&priv->stats.rx_dropped, rx_status.dropped_packets);
91 #endif
92         }
93
94         return &priv->stats;
95 }
96 #endif
97
98
99 /**
100  * Set the multicast list. Currently unimplemented.
101  *
102  * @param dev    Device to work on
103  */
104 void cvm_oct_common_set_multicast_list(struct ifnet *ifp)
105 {
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);
110
111         if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
112                 cvmx_gmxx_rxx_adr_ctl_t control;
113                 control.u64 = 0;
114                 control.s.bcst = 1;     /* Allow broadcast MAC addresses */
115
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 */
119                 else
120                         control.s.mcst = 1; /* Force reject multicat packets */
121
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 */
124                 else
125                         control.s.cam_mode = 1; /* Filter packets based on the CAM */
126
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);
129
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);
133                 else
134                         cvmx_write_csr(CVMX_GMXX_RXX_ADR_CAM_EN(index, interface), 1);
135
136                 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
137         }
138 }
139
140
141 /**
142  * Set the hardware MAC address for a device
143  *
144  * @param dev    Device to change the MAC address for
145  * @param addr   Address structure to change it too.
146  */
147 void cvm_oct_common_set_mac_address(struct ifnet *ifp, const void *addr)
148 {
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);
153
154         memcpy(priv->mac, addr, 6);
155
156         if ((interface < 2) && (cvmx_helper_interface_get_mode(interface) != CVMX_HELPER_INTERFACE_MODE_SPI)) {
157                 int i;
158                 const uint8_t *ptr = addr;
159                 uint64_t mac = 0;
160                 for (i = 0; i < 6; i++)
161                         mac = (mac<<8) | (uint64_t)(ptr[i]);
162
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);
165
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);
175         }
176 }
177
178
179 /**
180  * Change the link MTU. Unimplemented
181  *
182  * @param dev     Device to change
183  * @param new_mtu The new MTU
184  * @return Zero on success
185  */
186 int cvm_oct_common_change_mtu(struct ifnet *ifp, int new_mtu)
187 {
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);
191         int vlan_bytes = 4;
192
193         /* Limit the MTU to make sure the ethernet packets are between 64 bytes
194            and 65535 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);
197                 return -EINVAL;
198         }
199         ifp->if_mtu = new_mtu;
200
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. */
203
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);
207                 } else {
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;
211                         frm_len_chk.u64 = 0;
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);
215                 }
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);
219         }
220         return 0;
221 }
222
223
224 /**
225  * Per network device initialization
226  *
227  * @param dev    Device to initialize
228  * @return Zero on success
229  */
230 int cvm_oct_common_init(struct ifnet *ifp)
231 {
232         static int count;
233         char mac[6] = {
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;
241
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))))
245                 priv->queue = -1;
246
247         ifp->if_mtu = ETHERMTU;
248
249         count++;
250
251 #if 0
252         ifp->get_stats          = cvm_oct_common_get_stats;
253 #ifdef CONFIG_NET_POLL_CONTROLLER
254         ifp->poll_controller    = cvm_oct_poll_controller;
255 #endif
256 #endif
257
258         cvm_oct_mdio_setup_device(ifp);
259
260         cvm_oct_common_set_mac_address(ifp, mac);
261         cvm_oct_common_change_mtu(ifp, ifp->if_mtu);
262
263 #if 0
264         /* Zero out stats for port so we won't mistakenly show counters from the
265            bootloader */
266         memset(ifp->get_stats(ifp), 0, sizeof(struct ifnet_stats));
267 #endif
268
269         /*
270          * Do any last-minute board-specific initialization.
271          */
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);
277                 break;
278 #endif
279         default:
280                 break;
281         }
282
283         device_attach(priv->dev);
284
285         return 0;
286 }
287
288 void cvm_oct_common_uninit(struct ifnet *ifp)
289 {
290     /* Currently nothing to do */
291 }
292