Deleted Added
full compact
ethernet.c (215959) ethernet.c (215974)
1/*************************************************************************
2Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
3reserved.
4
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
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
23This 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
25TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26AND 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#include <sys/cdefs.h>
1/*************************************************************************
2Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
3reserved.
4
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
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
23This 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
25TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
26AND 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#include <sys/cdefs.h>
30__FBSDID("$FreeBSD: head/sys/mips/cavium/octe/ethernet.c 215959 2010-11-28 00:26:08Z jmallett $");
30__FBSDID("$FreeBSD: head/sys/mips/cavium/octe/ethernet.c 215974 2010-11-28 05:57:24Z jmallett $");
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/endian.h>
37#include <sys/kernel.h>
38#include <sys/rman.h>
39#include <sys/mbuf.h>
40#include <sys/socket.h>
41#include <sys/module.h>
42#include <sys/smp.h>
43#include <sys/taskqueue.h>
44
45#include <net/ethernet.h>
46#include <net/if.h>
47#include <net/if_types.h>
48
49#include "wrapper-cvmx-includes.h"
50#include "ethernet-headers.h"
51
52#include "octebusvar.h"
53
54/*
55 * XXX/juli
56 * Convert 0444 to tunables, 0644 to sysctls.
57 */
58#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
59int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
60#else
61int num_packet_buffers = 1024;
62#endif
63TUNABLE_INT("hw.octe.num_packet_buffers", &num_packet_buffers);
64/*
65 "\t\tNumber of packet buffers to allocate and store in the\n"
66 "\t\tFPA. By default, 1024 packet buffers are used unless\n"
67 "\t\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined." */
68
69int pow_receive_group = 15;
70TUNABLE_INT("hw.octe.pow_receive_group", &pow_receive_group);
71/*
72 "\t\tPOW group to receive packets from. All ethernet hardware\n"
73 "\t\twill be configured to send incomming packets to this POW\n"
74 "\t\tgroup. Also any other software can submit packets to this\n"
75 "\t\tgroup for the kernel to process." */
76
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/bus.h>
35#include <sys/conf.h>
36#include <sys/endian.h>
37#include <sys/kernel.h>
38#include <sys/rman.h>
39#include <sys/mbuf.h>
40#include <sys/socket.h>
41#include <sys/module.h>
42#include <sys/smp.h>
43#include <sys/taskqueue.h>
44
45#include <net/ethernet.h>
46#include <net/if.h>
47#include <net/if_types.h>
48
49#include "wrapper-cvmx-includes.h"
50#include "ethernet-headers.h"
51
52#include "octebusvar.h"
53
54/*
55 * XXX/juli
56 * Convert 0444 to tunables, 0644 to sysctls.
57 */
58#if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
59int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
60#else
61int num_packet_buffers = 1024;
62#endif
63TUNABLE_INT("hw.octe.num_packet_buffers", &num_packet_buffers);
64/*
65 "\t\tNumber of packet buffers to allocate and store in the\n"
66 "\t\tFPA. By default, 1024 packet buffers are used unless\n"
67 "\t\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined." */
68
69int pow_receive_group = 15;
70TUNABLE_INT("hw.octe.pow_receive_group", &pow_receive_group);
71/*
72 "\t\tPOW group to receive packets from. All ethernet hardware\n"
73 "\t\twill be configured to send incomming packets to this POW\n"
74 "\t\tgroup. Also any other software can submit packets to this\n"
75 "\t\tgroup for the kernel to process." */
76
77static int disable_core_queueing = 1;
78TUNABLE_INT("hw.octe.disable_core_queueing", &disable_core_queueing);
79/*
80 "\t\tWhen set the networking core's tx_queue_len is set to zero. This\n"
81 "\t\tallows packets to be sent without lock contention in the packet scheduler\n"
82 "\t\tresulting in some cases in improved throughput.\n" */
83
84extern int octeon_is_simulation(void);
85
86/**
87 * Exported from the kernel so we can determine board information. It is
88 * passed by the bootloader to the kernel.
89 */
90extern cvmx_bootinfo_t *octeon_bootinfo;
91
92/**
93 * Periodic timer to check auto negotiation
94 */
95static struct callout cvm_oct_poll_timer;
96
97/**
98 * Array of every ethernet device owned by this driver indexed by
99 * the ipd input port number.
100 */
101struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
102
103/**
104 * Task to handle link status changes.
105 */
106static struct taskqueue *cvm_oct_link_taskq;
107
108/**
109 * Function to update link status.
110 */
111static void cvm_oct_update_link(void *context, int pending)
112{
113 cvm_oct_private_t *priv = (cvm_oct_private_t *)context;
114 struct ifnet *ifp = priv->ifp;
115 cvmx_helper_link_info_t link_info;
116
117 link_info.u64 = priv->link_info;
118
119 if (link_info.s.link_up) {
120 if_link_state_change(ifp, LINK_STATE_UP);
121 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
122 if_name(ifp), link_info.s.speed,
123 (link_info.s.full_duplex) ? "Full" : "Half",
124 priv->port, priv->queue);
125 } else {
126 if_link_state_change(ifp, LINK_STATE_DOWN);
127 DEBUGPRINT("%s: Link down\n", if_name(ifp));
128 }
129 priv->need_link_update = 0;
130}
131
132/**
133 * Periodic timer tick for slow management operations
134 *
135 * @param arg Device to check
136 */
137static void cvm_do_timer(void *arg)
138{
139 static int port;
140 static int updated;
141 if (port < CVMX_PIP_NUM_INPUT_PORTS) {
142 if (cvm_oct_device[port]) {
143 int queues_per_port;
144 int qos;
145 cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc;
146 if (priv->poll)
147 {
148 /* skip polling if we don't get the lock */
149 if (MDIO_TRYLOCK()) {
150 priv->poll(cvm_oct_device[port]);
151 MDIO_UNLOCK();
152
153 if (priv->need_link_update) {
154 updated++;
155 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task);
156 }
157 }
158 }
159
160 queues_per_port = cvmx_pko_get_num_queues(port);
161 /* Drain any pending packets in the free list */
162 for (qos = 0; qos < queues_per_port; qos++) {
163 if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) {
164 IF_LOCK(&priv->tx_free_queue[qos]);
165 while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) {
166 struct mbuf *m;
167
168 _IF_DEQUEUE(&priv->tx_free_queue[qos], m);
169 m_freem(m);
170 }
171 IF_UNLOCK(&priv->tx_free_queue[qos]);
172
173 /*
174 * XXX locking!
175 */
176 priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
177 }
178 }
77extern int octeon_is_simulation(void);
78
79/**
80 * Exported from the kernel so we can determine board information. It is
81 * passed by the bootloader to the kernel.
82 */
83extern cvmx_bootinfo_t *octeon_bootinfo;
84
85/**
86 * Periodic timer to check auto negotiation
87 */
88static struct callout cvm_oct_poll_timer;
89
90/**
91 * Array of every ethernet device owned by this driver indexed by
92 * the ipd input port number.
93 */
94struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
95
96/**
97 * Task to handle link status changes.
98 */
99static struct taskqueue *cvm_oct_link_taskq;
100
101/**
102 * Function to update link status.
103 */
104static void cvm_oct_update_link(void *context, int pending)
105{
106 cvm_oct_private_t *priv = (cvm_oct_private_t *)context;
107 struct ifnet *ifp = priv->ifp;
108 cvmx_helper_link_info_t link_info;
109
110 link_info.u64 = priv->link_info;
111
112 if (link_info.s.link_up) {
113 if_link_state_change(ifp, LINK_STATE_UP);
114 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
115 if_name(ifp), link_info.s.speed,
116 (link_info.s.full_duplex) ? "Full" : "Half",
117 priv->port, priv->queue);
118 } else {
119 if_link_state_change(ifp, LINK_STATE_DOWN);
120 DEBUGPRINT("%s: Link down\n", if_name(ifp));
121 }
122 priv->need_link_update = 0;
123}
124
125/**
126 * Periodic timer tick for slow management operations
127 *
128 * @param arg Device to check
129 */
130static void cvm_do_timer(void *arg)
131{
132 static int port;
133 static int updated;
134 if (port < CVMX_PIP_NUM_INPUT_PORTS) {
135 if (cvm_oct_device[port]) {
136 int queues_per_port;
137 int qos;
138 cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc;
139 if (priv->poll)
140 {
141 /* skip polling if we don't get the lock */
142 if (MDIO_TRYLOCK()) {
143 priv->poll(cvm_oct_device[port]);
144 MDIO_UNLOCK();
145
146 if (priv->need_link_update) {
147 updated++;
148 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task);
149 }
150 }
151 }
152
153 queues_per_port = cvmx_pko_get_num_queues(port);
154 /* Drain any pending packets in the free list */
155 for (qos = 0; qos < queues_per_port; qos++) {
156 if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) {
157 IF_LOCK(&priv->tx_free_queue[qos]);
158 while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) {
159 struct mbuf *m;
160
161 _IF_DEQUEUE(&priv->tx_free_queue[qos], m);
162 m_freem(m);
163 }
164 IF_UNLOCK(&priv->tx_free_queue[qos]);
165
166 /*
167 * XXX locking!
168 */
169 priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
170 }
171 }
179#if 0
180 cvm_oct_device[port]->get_stats(cvm_oct_device[port]);
181#endif
182 }
183 port++;
184 /* Poll the next port in a 50th of a second.
185 This spreads the polling of ports out a little bit */
186 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
187 } else {
188 port = 0;
189 /* If any updates were made in this run, continue iterating at
190 * 1/50th of a second, so that if a link has merely gone down
191 * temporarily (e.g. because of interface reinitialization) it
192 * will not be forced to stay down for an entire second.
193 */
194 if (updated > 0) {
195 updated = 0;
196 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
197 } else {
198 /* All ports have been polled. Start the next iteration through
199 the ports in one second */
200 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
201 }
202 }
203}
204
205
206/**
207 * Configure common hardware for all interfaces
208 */
209static void cvm_oct_configure_common_hw(device_t bus)
210{
211 struct octebus_softc *sc;
212 int error;
213 int rid;
214
215 sc = device_get_softc(bus);
216
217 /* Setup the FPA */
218 cvmx_fpa_enable();
219 cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
220 cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
221 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
222 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
223
224 if (USE_RED)
225 cvmx_helper_setup_red(num_packet_buffers/4, num_packet_buffers/8);
226
227 /* Enable the MII interface */
228 if (!octeon_is_simulation())
229 cvmx_write_csr(CVMX_SMI_EN, 1);
230
231 /* Register an IRQ hander for to receive POW interrupts */
232 rid = 0;
233 sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid,
234 CVMX_IRQ_WORKQ0 + pow_receive_group,
235 CVMX_IRQ_WORKQ0 + pow_receive_group,
236 1, RF_ACTIVE);
237 if (sc->sc_rx_irq == NULL) {
238 device_printf(bus, "could not allocate workq irq");
239 return;
240 }
241
242 error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
243 cvm_oct_do_interrupt, NULL, cvm_oct_device,
244 NULL);
245 if (error != 0) {
246 device_printf(bus, "could not setup workq irq");
247 return;
248 }
249
250
251#ifdef SMP
252 if (USE_MULTICORE_RECEIVE) {
253 critical_enter();
254 {
255 int cpu;
256 for (cpu = 0; cpu < mp_maxid; cpu++) {
257 if (!CPU_ABSENT(cpu) &&
258 (cpu != PCPU_GET(cpuid))) {
259 cvmx_ciu_intx0_t en;
260 en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(cpu*2));
261 en.s.workq |= (1<<pow_receive_group);
262 cvmx_write_csr(CVMX_CIU_INTX_EN0(cpu*2), en.u64);
263 }
264 }
265 }
266 critical_exit();
267 }
268#endif
269}
270
271
272/**
273 * Free a work queue entry received in a intercept callback.
274 *
275 * @param work_queue_entry
276 * Work queue entry to free
277 * @return Zero on success, Negative on failure.
278 */
279int cvm_oct_free_work(void *work_queue_entry)
280{
281 cvmx_wqe_t *work = work_queue_entry;
282
283 int segments = work->word2.s.bufs;
284 cvmx_buf_ptr_t segment_ptr = work->packet_ptr;
285
286 while (segments--) {
287 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8);
288 if (__predict_false(!segment_ptr.s.i))
289 cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128));
290 segment_ptr = next_ptr;
291 }
292 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
293
294 return 0;
295}
296
297
298/**
299 * Module/ driver initialization. Creates the linux network
300 * devices.
301 *
302 * @return Zero on success
303 */
304int cvm_oct_init_module(device_t bus)
305{
306 device_t dev;
307 int ifnum;
308 int num_interfaces;
309 int interface;
310 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
311 int qos;
312
313 printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING);
314
172 }
173 port++;
174 /* Poll the next port in a 50th of a second.
175 This spreads the polling of ports out a little bit */
176 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
177 } else {
178 port = 0;
179 /* If any updates were made in this run, continue iterating at
180 * 1/50th of a second, so that if a link has merely gone down
181 * temporarily (e.g. because of interface reinitialization) it
182 * will not be forced to stay down for an entire second.
183 */
184 if (updated > 0) {
185 updated = 0;
186 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
187 } else {
188 /* All ports have been polled. Start the next iteration through
189 the ports in one second */
190 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
191 }
192 }
193}
194
195
196/**
197 * Configure common hardware for all interfaces
198 */
199static void cvm_oct_configure_common_hw(device_t bus)
200{
201 struct octebus_softc *sc;
202 int error;
203 int rid;
204
205 sc = device_get_softc(bus);
206
207 /* Setup the FPA */
208 cvmx_fpa_enable();
209 cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
210 cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
211 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
212 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
213
214 if (USE_RED)
215 cvmx_helper_setup_red(num_packet_buffers/4, num_packet_buffers/8);
216
217 /* Enable the MII interface */
218 if (!octeon_is_simulation())
219 cvmx_write_csr(CVMX_SMI_EN, 1);
220
221 /* Register an IRQ hander for to receive POW interrupts */
222 rid = 0;
223 sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid,
224 CVMX_IRQ_WORKQ0 + pow_receive_group,
225 CVMX_IRQ_WORKQ0 + pow_receive_group,
226 1, RF_ACTIVE);
227 if (sc->sc_rx_irq == NULL) {
228 device_printf(bus, "could not allocate workq irq");
229 return;
230 }
231
232 error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
233 cvm_oct_do_interrupt, NULL, cvm_oct_device,
234 NULL);
235 if (error != 0) {
236 device_printf(bus, "could not setup workq irq");
237 return;
238 }
239
240
241#ifdef SMP
242 if (USE_MULTICORE_RECEIVE) {
243 critical_enter();
244 {
245 int cpu;
246 for (cpu = 0; cpu < mp_maxid; cpu++) {
247 if (!CPU_ABSENT(cpu) &&
248 (cpu != PCPU_GET(cpuid))) {
249 cvmx_ciu_intx0_t en;
250 en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(cpu*2));
251 en.s.workq |= (1<<pow_receive_group);
252 cvmx_write_csr(CVMX_CIU_INTX_EN0(cpu*2), en.u64);
253 }
254 }
255 }
256 critical_exit();
257 }
258#endif
259}
260
261
262/**
263 * Free a work queue entry received in a intercept callback.
264 *
265 * @param work_queue_entry
266 * Work queue entry to free
267 * @return Zero on success, Negative on failure.
268 */
269int cvm_oct_free_work(void *work_queue_entry)
270{
271 cvmx_wqe_t *work = work_queue_entry;
272
273 int segments = work->word2.s.bufs;
274 cvmx_buf_ptr_t segment_ptr = work->packet_ptr;
275
276 while (segments--) {
277 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8);
278 if (__predict_false(!segment_ptr.s.i))
279 cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128));
280 segment_ptr = next_ptr;
281 }
282 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
283
284 return 0;
285}
286
287
288/**
289 * Module/ driver initialization. Creates the linux network
290 * devices.
291 *
292 * @return Zero on success
293 */
294int cvm_oct_init_module(device_t bus)
295{
296 device_t dev;
297 int ifnum;
298 int num_interfaces;
299 int interface;
300 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
301 int qos;
302
303 printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING);
304
315#if 0
316 cvm_oct_proc_initialize();
317#endif
318 cvm_oct_rx_initialize();
319 cvm_oct_configure_common_hw(bus);
320
321 cvmx_helper_initialize_packet_io_global();
322
323 /* Change the input group for all ports before input is enabled */
324 num_interfaces = cvmx_helper_get_number_of_interfaces();
325 for (interface = 0; interface < num_interfaces; interface++) {
326 int num_ports = cvmx_helper_ports_on_interface(interface);
327 int port;
328
329 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
330 cvmx_pip_prt_tagx_t pip_prt_tagx;
331 pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(port));
332 pip_prt_tagx.s.grp = pow_receive_group;
333 cvmx_write_csr(CVMX_PIP_PRT_TAGX(port), pip_prt_tagx.u64);
334 }
335 }
336
337 cvmx_helper_ipd_and_packet_input_enable();
338
339 memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
340
341 cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT,
342 taskqueue_thread_enqueue, &cvm_oct_link_taskq);
343 taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET,
344 "octe link taskq");
345
346 /* Initialize the FAU used for counting packet buffers that need to be freed */
347 cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
348
349 ifnum = 0;
350 num_interfaces = cvmx_helper_get_number_of_interfaces();
351 for (interface = 0; interface < num_interfaces; interface++) {
352 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface);
353 int num_ports = cvmx_helper_ports_on_interface(interface);
354 int port;
355
356 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
357 cvm_oct_private_t *priv;
358 struct ifnet *ifp;
359
360 dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum++);
361 if (dev != NULL)
362 ifp = if_alloc(IFT_ETHER);
363 if (dev == NULL || ifp == NULL) {
364 printf("\t\tFailed to allocate ethernet device for port %d\n", port);
365 continue;
366 }
305 cvm_oct_rx_initialize();
306 cvm_oct_configure_common_hw(bus);
307
308 cvmx_helper_initialize_packet_io_global();
309
310 /* Change the input group for all ports before input is enabled */
311 num_interfaces = cvmx_helper_get_number_of_interfaces();
312 for (interface = 0; interface < num_interfaces; interface++) {
313 int num_ports = cvmx_helper_ports_on_interface(interface);
314 int port;
315
316 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
317 cvmx_pip_prt_tagx_t pip_prt_tagx;
318 pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(port));
319 pip_prt_tagx.s.grp = pow_receive_group;
320 cvmx_write_csr(CVMX_PIP_PRT_TAGX(port), pip_prt_tagx.u64);
321 }
322 }
323
324 cvmx_helper_ipd_and_packet_input_enable();
325
326 memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
327
328 cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT,
329 taskqueue_thread_enqueue, &cvm_oct_link_taskq);
330 taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET,
331 "octe link taskq");
332
333 /* Initialize the FAU used for counting packet buffers that need to be freed */
334 cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
335
336 ifnum = 0;
337 num_interfaces = cvmx_helper_get_number_of_interfaces();
338 for (interface = 0; interface < num_interfaces; interface++) {
339 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface);
340 int num_ports = cvmx_helper_ports_on_interface(interface);
341 int port;
342
343 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
344 cvm_oct_private_t *priv;
345 struct ifnet *ifp;
346
347 dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum++);
348 if (dev != NULL)
349 ifp = if_alloc(IFT_ETHER);
350 if (dev == NULL || ifp == NULL) {
351 printf("\t\tFailed to allocate ethernet device for port %d\n", port);
352 continue;
353 }
367 /* XXX/juli set max send q len. */
368#if 0
369 if (disable_core_queueing)
370 ifp->tx_queue_len = 0;
371#endif
372
373 /* Initialize the device private structure. */
374 device_probe(dev);
375 priv = device_get_softc(dev);
376 priv->dev = dev;
377 priv->ifp = ifp;
378 priv->imode = imode;
379 priv->port = port;
380 priv->queue = cvmx_pko_get_base_queue(priv->port);
381 priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
382 for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++)
383 cvmx_fau_atomic_write32(priv->fau+qos*4, 0);
384 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv);
385
386 switch (priv->imode) {
387
388 /* These types don't support ports to IPD/PKO */
389 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
390 case CVMX_HELPER_INTERFACE_MODE_PCIE:
391 case CVMX_HELPER_INTERFACE_MODE_PICMG:
392 break;
393
394 case CVMX_HELPER_INTERFACE_MODE_NPI:
395 priv->init = cvm_oct_common_init;
396 priv->uninit = cvm_oct_common_uninit;
397 device_set_desc(dev, "Cavium Octeon NPI Ethernet");
398 break;
399
400 case CVMX_HELPER_INTERFACE_MODE_XAUI:
401 priv->init = cvm_oct_xaui_init;
354
355 /* Initialize the device private structure. */
356 device_probe(dev);
357 priv = device_get_softc(dev);
358 priv->dev = dev;
359 priv->ifp = ifp;
360 priv->imode = imode;
361 priv->port = port;
362 priv->queue = cvmx_pko_get_base_queue(priv->port);
363 priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
364 for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++)
365 cvmx_fau_atomic_write32(priv->fau+qos*4, 0);
366 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv);
367
368 switch (priv->imode) {
369
370 /* These types don't support ports to IPD/PKO */
371 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
372 case CVMX_HELPER_INTERFACE_MODE_PCIE:
373 case CVMX_HELPER_INTERFACE_MODE_PICMG:
374 break;
375
376 case CVMX_HELPER_INTERFACE_MODE_NPI:
377 priv->init = cvm_oct_common_init;
378 priv->uninit = cvm_oct_common_uninit;
379 device_set_desc(dev, "Cavium Octeon NPI Ethernet");
380 break;
381
382 case CVMX_HELPER_INTERFACE_MODE_XAUI:
383 priv->init = cvm_oct_xaui_init;
402 priv->uninit = cvm_oct_xaui_uninit;
384 priv->uninit = cvm_oct_common_uninit;
403 device_set_desc(dev, "Cavium Octeon XAUI Ethernet");
404 break;
405
406 case CVMX_HELPER_INTERFACE_MODE_LOOP:
407 priv->init = cvm_oct_common_init;
408 priv->uninit = cvm_oct_common_uninit;
409 device_set_desc(dev, "Cavium Octeon LOOP Ethernet");
410 break;
411
412 case CVMX_HELPER_INTERFACE_MODE_SGMII:
413 priv->init = cvm_oct_sgmii_init;
385 device_set_desc(dev, "Cavium Octeon XAUI Ethernet");
386 break;
387
388 case CVMX_HELPER_INTERFACE_MODE_LOOP:
389 priv->init = cvm_oct_common_init;
390 priv->uninit = cvm_oct_common_uninit;
391 device_set_desc(dev, "Cavium Octeon LOOP Ethernet");
392 break;
393
394 case CVMX_HELPER_INTERFACE_MODE_SGMII:
395 priv->init = cvm_oct_sgmii_init;
414 priv->uninit = cvm_oct_sgmii_uninit;
396 priv->uninit = cvm_oct_common_uninit;
415 device_set_desc(dev, "Cavium Octeon SGMII Ethernet");
416 break;
417
418 case CVMX_HELPER_INTERFACE_MODE_SPI:
419 priv->init = cvm_oct_spi_init;
420 priv->uninit = cvm_oct_spi_uninit;
421 device_set_desc(dev, "Cavium Octeon SPI Ethernet");
422 break;
423
424 case CVMX_HELPER_INTERFACE_MODE_RGMII:
425 priv->init = cvm_oct_rgmii_init;
426 priv->uninit = cvm_oct_rgmii_uninit;
427 device_set_desc(dev, "Cavium Octeon RGMII Ethernet");
428 break;
429
430 case CVMX_HELPER_INTERFACE_MODE_GMII:
431 priv->init = cvm_oct_rgmii_init;
432 priv->uninit = cvm_oct_rgmii_uninit;
433 device_set_desc(dev, "Cavium Octeon GMII Ethernet");
434 break;
435 }
436
437 ifp->if_softc = priv;
438
439 if (!priv->init) {
440 panic("%s: unsupported device type, need to free ifp.", __func__);
441 } else
442 if (priv->init(ifp) < 0) {
443 printf("\t\tFailed to register ethernet device for interface %d, port %d\n",
444 interface, priv->port);
445 panic("%s: init failed, need to free ifp.", __func__);
446 } else {
447 cvm_oct_device[priv->port] = ifp;
448 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t);
449 }
450 }
451 }
452
453 if (INTERRUPT_LIMIT) {
454 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */
455 cvmx_write_csr(CVMX_POW_WQ_INT_PC, octeon_bootinfo->eclock_hz/(INTERRUPT_LIMIT*16*256)<<8);
456
457 /* Enable POW timer interrupt. It will count when there are packets available */
458 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24);
459 } else {
460 /* Enable POW interrupt when our port has at least one packet */
461 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
462 }
463
464 callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE);
465 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
466
467 return 0;
468}
469
470
471/**
472 * Module / driver shutdown
473 *
474 * @return Zero on success
475 */
476void cvm_oct_cleanup_module(void)
477{
478 int port;
479
480 /* Disable POW interrupt */
481 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
482
483 cvmx_ipd_disable();
484
485#if 0
486 /* Free the interrupt handler */
487 free_irq(8 + pow_receive_group, cvm_oct_device);
488#endif
489
490 callout_stop(&cvm_oct_poll_timer);
491 cvm_oct_rx_shutdown();
492 cvmx_pko_disable();
493
494 /* Free the ethernet devices */
495 for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
496 if (cvm_oct_device[port]) {
497 cvm_oct_tx_shutdown(cvm_oct_device[port]);
498#if 0
499 unregister_netdev(cvm_oct_device[port]);
500 kfree(cvm_oct_device[port]);
501#else
502 panic("%s: need to detach and free interface.", __func__);
503#endif
504 cvm_oct_device[port] = NULL;
505 }
506 }
507
508 cvmx_pko_shutdown();
397 device_set_desc(dev, "Cavium Octeon SGMII Ethernet");
398 break;
399
400 case CVMX_HELPER_INTERFACE_MODE_SPI:
401 priv->init = cvm_oct_spi_init;
402 priv->uninit = cvm_oct_spi_uninit;
403 device_set_desc(dev, "Cavium Octeon SPI Ethernet");
404 break;
405
406 case CVMX_HELPER_INTERFACE_MODE_RGMII:
407 priv->init = cvm_oct_rgmii_init;
408 priv->uninit = cvm_oct_rgmii_uninit;
409 device_set_desc(dev, "Cavium Octeon RGMII Ethernet");
410 break;
411
412 case CVMX_HELPER_INTERFACE_MODE_GMII:
413 priv->init = cvm_oct_rgmii_init;
414 priv->uninit = cvm_oct_rgmii_uninit;
415 device_set_desc(dev, "Cavium Octeon GMII Ethernet");
416 break;
417 }
418
419 ifp->if_softc = priv;
420
421 if (!priv->init) {
422 panic("%s: unsupported device type, need to free ifp.", __func__);
423 } else
424 if (priv->init(ifp) < 0) {
425 printf("\t\tFailed to register ethernet device for interface %d, port %d\n",
426 interface, priv->port);
427 panic("%s: init failed, need to free ifp.", __func__);
428 } else {
429 cvm_oct_device[priv->port] = ifp;
430 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t);
431 }
432 }
433 }
434
435 if (INTERRUPT_LIMIT) {
436 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */
437 cvmx_write_csr(CVMX_POW_WQ_INT_PC, octeon_bootinfo->eclock_hz/(INTERRUPT_LIMIT*16*256)<<8);
438
439 /* Enable POW timer interrupt. It will count when there are packets available */
440 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24);
441 } else {
442 /* Enable POW interrupt when our port has at least one packet */
443 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
444 }
445
446 callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE);
447 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
448
449 return 0;
450}
451
452
453/**
454 * Module / driver shutdown
455 *
456 * @return Zero on success
457 */
458void cvm_oct_cleanup_module(void)
459{
460 int port;
461
462 /* Disable POW interrupt */
463 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
464
465 cvmx_ipd_disable();
466
467#if 0
468 /* Free the interrupt handler */
469 free_irq(8 + pow_receive_group, cvm_oct_device);
470#endif
471
472 callout_stop(&cvm_oct_poll_timer);
473 cvm_oct_rx_shutdown();
474 cvmx_pko_disable();
475
476 /* Free the ethernet devices */
477 for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
478 if (cvm_oct_device[port]) {
479 cvm_oct_tx_shutdown(cvm_oct_device[port]);
480#if 0
481 unregister_netdev(cvm_oct_device[port]);
482 kfree(cvm_oct_device[port]);
483#else
484 panic("%s: need to detach and free interface.", __func__);
485#endif
486 cvm_oct_device[port] = NULL;
487 }
488 }
489
490 cvmx_pko_shutdown();
509#if 0
510 cvm_oct_proc_shutdown();
511#endif
512
513 cvmx_ipd_free_ptr();
514
515 /* Free the HW pools */
516 cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
517 cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
518 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
519 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
520}
491
492 cvmx_ipd_free_ptr();
493
494 /* Free the HW pools */
495 cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
496 cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
497 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
498 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128);
499}