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 #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/conf.h>
38 #include <sys/endian.h>
39 #include <sys/kernel.h>
40 #include <sys/rman.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/module.h>
44 #include <sys/smp.h>
45 #include <sys/taskqueue.h>
46
47 #include <net/ethernet.h>
48 #include <net/if.h>
49 #include <net/if_var.h>
50 #include <net/if_types.h>
51
52 #include "wrapper-cvmx-includes.h"
53 #include "ethernet-headers.h"
54
55 #include "octebusvar.h"
56
57 /*
58 * XXX/juli
59 * Convert 0444 to tunables, 0644 to sysctls.
60 */
61 #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
62 int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
63 #else
64 int num_packet_buffers = 2048;
65 #endif
66 TUNABLE_INT("hw.octe.num_packet_buffers", &num_packet_buffers);
67 /*
68 "\t\tNumber of packet buffers to allocate and store in the\n"
69 "\t\tFPA. By default, 1024 packet buffers are used unless\n"
70 "\t\tCONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS is defined." */
71
72 int pow_receive_group = 15;
73 TUNABLE_INT("hw.octe.pow_receive_group", &pow_receive_group);
74 /*
75 "\t\tPOW group to receive packets from. All ethernet hardware\n"
76 "\t\twill be configured to send incomming packets to this POW\n"
77 "\t\tgroup. Also any other software can submit packets to this\n"
78 "\t\tgroup for the kernel to process." */
79
80 /**
81 * Periodic timer to check auto negotiation
82 */
83 static struct callout cvm_oct_poll_timer;
84
85 /**
86 * Array of every ethernet device owned by this driver indexed by
87 * the ipd input port number.
88 */
89 struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
90
91 /**
92 * Task to handle link status changes.
93 */
94 static struct taskqueue *cvm_oct_link_taskq;
95
96 /*
97 * Number of buffers in output buffer pool.
98 */
99 static int cvm_oct_num_output_buffers;
100
101 /**
102 * Function to update link status.
103 */
104 static 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 */
130 static 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
140 cvm_oct_common_poll(priv->ifp);
141 if (priv->need_link_update) {
142 updated++;
143 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task);
144 }
145
146 queues_per_port = cvmx_pko_get_num_queues(port);
147 /* Drain any pending packets in the free list */
148 for (qos = 0; qos < queues_per_port; qos++) {
149 if (_IF_QLEN(&priv->tx_free_queue[qos]) > 0) {
150 IF_LOCK(&priv->tx_free_queue[qos]);
151 while (_IF_QLEN(&priv->tx_free_queue[qos]) > cvmx_fau_fetch_and_add32(priv->fau+qos*4, 0)) {
152 struct mbuf *m;
153
154 _IF_DEQUEUE(&priv->tx_free_queue[qos], m);
155 m_freem(m);
156 }
157 IF_UNLOCK(&priv->tx_free_queue[qos]);
158
159 /*
160 * XXX locking!
161 */
162 priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
163 }
164 }
165 }
166 port++;
167 /* Poll the next port in a 50th of a second.
168 This spreads the polling of ports out a little bit */
169 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
170 } else {
171 port = 0;
172 /* If any updates were made in this run, continue iterating at
173 * 1/50th of a second, so that if a link has merely gone down
174 * temporarily (e.g. because of interface reinitialization) it
175 * will not be forced to stay down for an entire second.
176 */
177 if (updated > 0) {
178 updated = 0;
179 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
180 } else {
181 /* All ports have been polled. Start the next iteration through
182 the ports in one second */
183 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
184 }
185 }
186 }
187
188 /**
189 * Configure common hardware for all interfaces
190 */
191 static void cvm_oct_configure_common_hw(device_t bus)
192 {
193 struct octebus_softc *sc;
194 int pko_queues;
195 int error;
196 int rid;
197
198 sc = device_get_softc(bus);
199
200 /* Setup the FPA */
201 cvmx_fpa_enable();
202 cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
203 num_packet_buffers);
204 cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
205 num_packet_buffers);
206 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) {
207 /*
208 * If the FPA uses different pools for output buffers and
209 * packets, size the output buffer pool based on the number
210 * of PKO queues.
211 */
212 if (OCTEON_IS_MODEL(OCTEON_CN38XX))
213 pko_queues = 128;
214 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
215 pko_queues = 32;
216 else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
217 pko_queues = 32;
218 else
219 pko_queues = 256;
220
221 cvm_oct_num_output_buffers = 4 * pko_queues;
222 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
223 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE,
224 cvm_oct_num_output_buffers);
225 }
226
227 if (USE_RED)
228 cvmx_helper_setup_red(num_packet_buffers/4,
229 num_packet_buffers/8);
230
231 /* Enable the MII interface */
232 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM)
233 cvmx_write_csr(CVMX_SMI_EN, 1);
234
235 /* Register an IRQ hander for to receive POW interrupts */
236 rid = 0;
237 sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid,
238 OCTEON_IRQ_WORKQ0 + pow_receive_group,
239 OCTEON_IRQ_WORKQ0 + pow_receive_group,
240 1, RF_ACTIVE);
241 if (sc->sc_rx_irq == NULL) {
242 device_printf(bus, "could not allocate workq irq");
243 return;
244 }
245
246 error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
247 cvm_oct_do_interrupt, NULL, cvm_oct_device,
248 &sc->sc_rx_intr_cookie);
249 if (error != 0) {
250 device_printf(bus, "could not setup workq irq");
251 return;
252 }
253
254
255 #ifdef SMP
256 {
257 cvmx_ciu_intx0_t en;
258 int core;
259
260 CPU_FOREACH(core) {
261 if (core == PCPU_GET(cpuid))
262 continue;
263
264 en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(core*2));
265 en.s.workq |= (1<<pow_receive_group);
266 cvmx_write_csr(CVMX_CIU_INTX_EN0(core*2), en.u64);
267 }
268 }
269 #endif
270 }
271
272
273 /**
274 * Free a work queue entry received in a intercept callback.
275 *
276 * @param work_queue_entry
277 * Work queue entry to free
278 * @return Zero on success, Negative on failure.
279 */
280 int cvm_oct_free_work(void *work_queue_entry)
281 {
282 cvmx_wqe_t *work = work_queue_entry;
283
284 int segments = work->word2.s.bufs;
285 cvmx_buf_ptr_t segment_ptr = work->packet_ptr;
286
287 while (segments--) {
288 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8);
289 if (__predict_false(!segment_ptr.s.i))
290 cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128));
291 segment_ptr = next_ptr;
292 }
293 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
294
295 return 0;
296 }
297
298
299 /**
300 * Module/ driver initialization. Creates the linux network
301 * devices.
302 *
303 * @return Zero on success
304 */
305 int cvm_oct_init_module(device_t bus)
306 {
307 device_t dev;
308 int ifnum;
309 int num_interfaces;
310 int interface;
311 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
312 int qos;
313
314 cvm_oct_rx_initialize();
315 cvm_oct_configure_common_hw(bus);
316
317 cvmx_helper_initialize_packet_io_global();
318
319 /* Change the input group for all ports before input is enabled */
320 num_interfaces = cvmx_helper_get_number_of_interfaces();
321 for (interface = 0; interface < num_interfaces; interface++) {
322 int num_ports = cvmx_helper_ports_on_interface(interface);
323 int port;
324
325 for (port = 0; port < num_ports; port++) {
326 cvmx_pip_prt_tagx_t pip_prt_tagx;
327 int pkind = cvmx_helper_get_ipd_port(interface, port);
328
329 pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(pkind));
330 pip_prt_tagx.s.grp = pow_receive_group;
331 cvmx_write_csr(CVMX_PIP_PRT_TAGX(pkind), pip_prt_tagx.u64);
332 }
333 }
334
335 cvmx_helper_ipd_and_packet_input_enable();
336
337 memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
338
339 cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT,
340 taskqueue_thread_enqueue, &cvm_oct_link_taskq);
341 taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET,
342 "octe link taskq");
343
344 /* Initialize the FAU used for counting packet buffers that need to be freed */
345 cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
346
347 ifnum = 0;
348 num_interfaces = cvmx_helper_get_number_of_interfaces();
349 for (interface = 0; interface < num_interfaces; interface++) {
350 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface);
351 int num_ports = cvmx_helper_ports_on_interface(interface);
352 int port;
353
354 for (port = cvmx_helper_get_ipd_port(interface, 0);
355 port < cvmx_helper_get_ipd_port(interface, num_ports);
356 ifnum++, 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("Failed to allocate ethernet device for interface %d port %d\n", interface, port);
365 continue;
366 }
367
368 /* Initialize the device private structure. */
369 device_probe(dev);
370 priv = device_get_softc(dev);
371 priv->dev = dev;
372 priv->ifp = ifp;
373 priv->imode = imode;
374 priv->port = port;
375 priv->queue = cvmx_pko_get_base_queue(priv->port);
376 priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
377 for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++)
378 cvmx_fau_atomic_write32(priv->fau+qos*4, 0);
379 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv);
380
381 switch (priv->imode) {
382
383 /* These types don't support ports to IPD/PKO */
384 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
385 case CVMX_HELPER_INTERFACE_MODE_PCIE:
386 case CVMX_HELPER_INTERFACE_MODE_PICMG:
387 break;
388
389 case CVMX_HELPER_INTERFACE_MODE_NPI:
390 priv->init = cvm_oct_common_init;
391 priv->uninit = cvm_oct_common_uninit;
392 device_set_desc(dev, "Cavium Octeon NPI Ethernet");
393 break;
394
395 case CVMX_HELPER_INTERFACE_MODE_XAUI:
396 priv->init = cvm_oct_xaui_init;
397 priv->uninit = cvm_oct_common_uninit;
398 device_set_desc(dev, "Cavium Octeon XAUI Ethernet");
399 break;
400
401 case CVMX_HELPER_INTERFACE_MODE_LOOP:
402 priv->init = cvm_oct_common_init;
403 priv->uninit = cvm_oct_common_uninit;
404 device_set_desc(dev, "Cavium Octeon LOOP Ethernet");
405 break;
406
407 case CVMX_HELPER_INTERFACE_MODE_SGMII:
408 priv->init = cvm_oct_sgmii_init;
409 priv->uninit = cvm_oct_common_uninit;
410 device_set_desc(dev, "Cavium Octeon SGMII Ethernet");
411 break;
412
413 case CVMX_HELPER_INTERFACE_MODE_SPI:
414 priv->init = cvm_oct_spi_init;
415 priv->uninit = cvm_oct_spi_uninit;
416 device_set_desc(dev, "Cavium Octeon SPI Ethernet");
417 break;
418
419 case CVMX_HELPER_INTERFACE_MODE_RGMII:
420 priv->init = cvm_oct_rgmii_init;
421 priv->uninit = cvm_oct_rgmii_uninit;
422 device_set_desc(dev, "Cavium Octeon RGMII Ethernet");
423 break;
424
425 case CVMX_HELPER_INTERFACE_MODE_GMII:
426 priv->init = cvm_oct_rgmii_init;
427 priv->uninit = cvm_oct_rgmii_uninit;
428 device_set_desc(dev, "Cavium Octeon GMII Ethernet");
429 break;
430 }
431
432 ifp->if_softc = priv;
433
434 if (!priv->init) {
435 printf("octe%d: unsupported device type interface %d, port %d\n",
436 ifnum, interface, priv->port);
437 if_free(ifp);
438 } else if (priv->init(ifp) != 0) {
439 printf("octe%d: failed to register device for interface %d, port %d\n",
440 ifnum, interface, priv->port);
441 if_free(ifp);
442 } else {
443 cvm_oct_device[priv->port] = ifp;
444 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t);
445 }
446 }
447 }
448
449 if (INTERRUPT_LIMIT) {
450 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */
451 cvmx_write_csr(CVMX_POW_WQ_INT_PC, cvmx_clock_get_rate(CVMX_CLOCK_CORE)/((INTERRUPT_LIMIT+1)*16*256)<<8);
452
453 /* Enable POW timer interrupt. It will count when there are packets available */
454 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24);
455 } else {
456 /* Enable POW interrupt when our port has at least one packet */
457 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
458 }
459
460 callout_init(&cvm_oct_poll_timer, 1);
461 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
462
463 return 0;
464 }
465
466
467 /**
468 * Module / driver shutdown
469 *
470 * @return Zero on success
471 */
472 void cvm_oct_cleanup_module(device_t bus)
473 {
474 int port;
475 struct octebus_softc *sc = device_get_softc(bus);
476
477 /* Disable POW interrupt */
478 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
479
480 /* Free the interrupt handler */
481 bus_teardown_intr(bus, sc->sc_rx_irq, sc->sc_rx_intr_cookie);
482
483 callout_stop(&cvm_oct_poll_timer);
484 cvm_oct_rx_shutdown();
485
486 cvmx_helper_shutdown_packet_io_global();
487
488 /* Free the ethernet devices */
489 for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
490 if (cvm_oct_device[port]) {
491 cvm_oct_tx_shutdown(cvm_oct_device[port]);
492 #if 0
493 unregister_netdev(cvm_oct_device[port]);
494 kfree(cvm_oct_device[port]);
495 #else
496 panic("%s: need to detach and free interface.", __func__);
497 #endif
498 cvm_oct_device[port] = NULL;
499 }
500 }
501 /* Free the HW pools */
502 cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
503 cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
504
505 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
506 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, cvm_oct_num_output_buffers);
507
508 /* Disable FPA, all buffers are free, not done by helper shutdown. */
509 cvmx_fpa_disable();
510 }
Cache object: 3b8229ee96827547b82d4a10123e5152
|