1 /*************************************************************************
2 Copyright (c) 2003-2007 Cavium Networks (support@cavium.com). All rights
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
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.
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
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.
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 *************************************************************************/
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
33 #include <sys/systm.h>
36 #include <sys/endian.h>
37 #include <sys/kernel.h>
40 #include <sys/socket.h>
41 #include <sys/module.h>
43 #include <sys/taskqueue.h>
45 #include <net/ethernet.h>
47 #include <net/if_types.h>
49 #include "wrapper-cvmx-includes.h"
50 #include "ethernet-headers.h"
52 #include "octebusvar.h"
56 * Convert 0444 to tunables, 0644 to sysctls.
58 #if defined(CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS) && CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS
59 int num_packet_buffers = CONFIG_CAVIUM_OCTEON_NUM_PACKET_BUFFERS;
61 int num_packet_buffers = 1024;
63 TUNABLE_INT("hw.octe.num_packet_buffers", &num_packet_buffers);
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." */
69 int pow_receive_group = 15;
70 TUNABLE_INT("hw.octe.pow_receive_group", &pow_receive_group);
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." */
77 extern int octeon_is_simulation(void);
80 * Exported from the kernel so we can determine board information. It is
81 * passed by the bootloader to the kernel.
83 extern cvmx_bootinfo_t *octeon_bootinfo;
86 * Periodic timer to check auto negotiation
88 static struct callout cvm_oct_poll_timer;
91 * Array of every ethernet device owned by this driver indexed by
92 * the ipd input port number.
94 struct ifnet *cvm_oct_device[TOTAL_NUMBER_OF_PORTS];
97 * Task to handle link status changes.
99 static struct taskqueue *cvm_oct_link_taskq;
102 * Number of buffers in output buffer pool.
104 static int cvm_oct_num_output_buffers;
107 * The offset from mac_addr_base that should be used for the next port
108 * that is configured. By convention, if any mgmt ports exist on the
109 * chip, they get the first mac addresses. The ports controlled by
110 * this driver are numbered sequencially following any mgmt addresses
113 unsigned int cvm_oct_mac_addr_offset;
116 * Function to update link status.
118 static void cvm_oct_update_link(void *context, int pending)
120 cvm_oct_private_t *priv = (cvm_oct_private_t *)context;
121 struct ifnet *ifp = priv->ifp;
122 cvmx_helper_link_info_t link_info;
124 link_info.u64 = priv->link_info;
126 if (link_info.s.link_up) {
127 if_link_state_change(ifp, LINK_STATE_UP);
128 DEBUGPRINT("%s: %u Mbps %s duplex, port %2d, queue %2d\n",
129 if_name(ifp), link_info.s.speed,
130 (link_info.s.full_duplex) ? "Full" : "Half",
131 priv->port, priv->queue);
133 if_link_state_change(ifp, LINK_STATE_DOWN);
134 DEBUGPRINT("%s: Link down\n", if_name(ifp));
136 priv->need_link_update = 0;
140 * Periodic timer tick for slow management operations
142 * @param arg Device to check
144 static void cvm_do_timer(void *arg)
148 if (port < CVMX_PIP_NUM_INPUT_PORTS) {
149 if (cvm_oct_device[port]) {
152 cvm_oct_private_t *priv = (cvm_oct_private_t *)cvm_oct_device[port]->if_softc;
154 cvm_oct_common_poll(priv->ifp);
155 if (priv->need_link_update) {
157 taskqueue_enqueue(cvm_oct_link_taskq, &priv->link_task);
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)) {
168 _IF_DEQUEUE(&priv->tx_free_queue[qos], m);
171 IF_UNLOCK(&priv->tx_free_queue[qos]);
176 priv->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
181 /* Poll the next port in a 50th of a second.
182 This spreads the polling of ports out a little bit */
183 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
186 /* If any updates were made in this run, continue iterating at
187 * 1/50th of a second, so that if a link has merely gone down
188 * temporarily (e.g. because of interface reinitialization) it
189 * will not be forced to stay down for an entire second.
193 callout_reset(&cvm_oct_poll_timer, hz / 50, cvm_do_timer, NULL);
195 /* All ports have been polled. Start the next iteration through
196 the ports in one second */
197 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
203 * Configure common hardware for all interfaces
205 static void cvm_oct_configure_common_hw(device_t bus)
207 struct octebus_softc *sc;
212 sc = device_get_softc(bus);
216 cvm_oct_mem_fill_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE,
218 cvm_oct_mem_fill_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE,
220 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) {
222 * If the FPA uses different pools for output buffers and
223 * packets, size the output buffer pool based on the number
226 if (OCTEON_IS_MODEL(OCTEON_CN38XX))
228 else if (OCTEON_IS_MODEL(OCTEON_CN3XXX))
230 else if (OCTEON_IS_MODEL(OCTEON_CN50XX))
235 cvm_oct_num_output_buffers = 4 * pko_queues;
236 cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL,
237 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE,
238 cvm_oct_num_output_buffers);
242 cvmx_helper_setup_red(num_packet_buffers/4,
243 num_packet_buffers/8);
245 /* Enable the MII interface */
246 if (!octeon_is_simulation())
247 cvmx_write_csr(CVMX_SMI_EN, 1);
249 /* Register an IRQ hander for to receive POW interrupts */
251 sc->sc_rx_irq = bus_alloc_resource(bus, SYS_RES_IRQ, &rid,
252 CVMX_IRQ_WORKQ0 + pow_receive_group,
253 CVMX_IRQ_WORKQ0 + pow_receive_group,
255 if (sc->sc_rx_irq == NULL) {
256 device_printf(bus, "could not allocate workq irq");
260 error = bus_setup_intr(bus, sc->sc_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
261 cvm_oct_do_interrupt, NULL, cvm_oct_device,
262 &sc->sc_rx_intr_cookie);
264 device_printf(bus, "could not setup workq irq");
275 if (core == PCPU_GET(cpuid))
278 en.u64 = cvmx_read_csr(CVMX_CIU_INTX_EN0(core*2));
279 en.s.workq |= (1<<pow_receive_group);
280 cvmx_write_csr(CVMX_CIU_INTX_EN0(core*2), en.u64);
288 * Free a work queue entry received in a intercept callback.
290 * @param work_queue_entry
291 * Work queue entry to free
292 * @return Zero on success, Negative on failure.
294 int cvm_oct_free_work(void *work_queue_entry)
296 cvmx_wqe_t *work = work_queue_entry;
298 int segments = work->word2.s.bufs;
299 cvmx_buf_ptr_t segment_ptr = work->packet_ptr;
302 cvmx_buf_ptr_t next_ptr = *(cvmx_buf_ptr_t *)cvmx_phys_to_ptr(segment_ptr.s.addr-8);
303 if (__predict_false(!segment_ptr.s.i))
304 cvmx_fpa_free(cvm_oct_get_buffer_ptr(segment_ptr), segment_ptr.s.pool, DONT_WRITEBACK(CVMX_FPA_PACKET_POOL_SIZE/128));
305 segment_ptr = next_ptr;
307 cvmx_fpa_free(work, CVMX_FPA_WQE_POOL, DONT_WRITEBACK(1));
314 * Module/ driver initialization. Creates the linux network
317 * @return Zero on success
319 int cvm_oct_init_module(device_t bus)
325 int fau = FAU_NUM_PACKET_BUFFERS_TO_FREE;
328 printf("cavium-ethernet: %s\n", OCTEON_SDK_VERSION_STRING);
331 * MAC addresses for this driver start after the management
334 * XXX Would be nice if __cvmx_mgmt_port_num_ports() were
335 * not static to cvmx-mgmt-port.c.
337 if (OCTEON_IS_MODEL(OCTEON_CN56XX))
338 cvm_oct_mac_addr_offset = 1;
339 else if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN63XX))
340 cvm_oct_mac_addr_offset = 2;
342 cvm_oct_mac_addr_offset = 0;
344 cvm_oct_rx_initialize();
345 cvm_oct_configure_common_hw(bus);
347 cvmx_helper_initialize_packet_io_global();
349 /* Change the input group for all ports before input is enabled */
350 num_interfaces = cvmx_helper_get_number_of_interfaces();
351 for (interface = 0; interface < num_interfaces; interface++) {
352 int num_ports = cvmx_helper_ports_on_interface(interface);
355 for (port = 0; port < num_ports; port++) {
356 cvmx_pip_prt_tagx_t pip_prt_tagx;
357 int pkind = cvmx_helper_get_ipd_port(interface, port);
359 pip_prt_tagx.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(pkind));
360 pip_prt_tagx.s.grp = pow_receive_group;
361 cvmx_write_csr(CVMX_PIP_PRT_TAGX(pkind), pip_prt_tagx.u64);
365 cvmx_helper_ipd_and_packet_input_enable();
367 memset(cvm_oct_device, 0, sizeof(cvm_oct_device));
369 cvm_oct_link_taskq = taskqueue_create("octe link", M_NOWAIT,
370 taskqueue_thread_enqueue, &cvm_oct_link_taskq);
371 taskqueue_start_threads(&cvm_oct_link_taskq, 1, PI_NET,
374 /* Initialize the FAU used for counting packet buffers that need to be freed */
375 cvmx_fau_atomic_write32(FAU_NUM_PACKET_BUFFERS_TO_FREE, 0);
378 num_interfaces = cvmx_helper_get_number_of_interfaces();
379 for (interface = 0; interface < num_interfaces; interface++) {
380 cvmx_helper_interface_mode_t imode = cvmx_helper_interface_get_mode(interface);
381 int num_ports = cvmx_helper_ports_on_interface(interface);
384 for (port = cvmx_helper_get_ipd_port(interface, 0); port < cvmx_helper_get_ipd_port(interface, num_ports); port++) {
385 cvm_oct_private_t *priv;
388 dev = BUS_ADD_CHILD(bus, 0, "octe", ifnum++);
390 ifp = if_alloc(IFT_ETHER);
391 if (dev == NULL || ifp == NULL) {
392 printf("\t\tFailed to allocate ethernet device for port %d\n", port);
396 /* Initialize the device private structure. */
398 priv = device_get_softc(dev);
403 priv->queue = cvmx_pko_get_base_queue(priv->port);
404 priv->fau = fau - cvmx_pko_get_num_queues(port) * 4;
405 for (qos = 0; qos < cvmx_pko_get_num_queues(port); qos++)
406 cvmx_fau_atomic_write32(priv->fau+qos*4, 0);
407 TASK_INIT(&priv->link_task, 0, cvm_oct_update_link, priv);
409 switch (priv->imode) {
411 /* These types don't support ports to IPD/PKO */
412 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
413 case CVMX_HELPER_INTERFACE_MODE_PCIE:
414 case CVMX_HELPER_INTERFACE_MODE_PICMG:
417 case CVMX_HELPER_INTERFACE_MODE_NPI:
418 priv->init = cvm_oct_common_init;
419 priv->uninit = cvm_oct_common_uninit;
420 device_set_desc(dev, "Cavium Octeon NPI Ethernet");
423 case CVMX_HELPER_INTERFACE_MODE_XAUI:
424 priv->init = cvm_oct_xaui_init;
425 priv->uninit = cvm_oct_common_uninit;
426 device_set_desc(dev, "Cavium Octeon XAUI Ethernet");
429 case CVMX_HELPER_INTERFACE_MODE_LOOP:
430 priv->init = cvm_oct_common_init;
431 priv->uninit = cvm_oct_common_uninit;
432 device_set_desc(dev, "Cavium Octeon LOOP Ethernet");
435 case CVMX_HELPER_INTERFACE_MODE_SGMII:
436 priv->init = cvm_oct_sgmii_init;
437 priv->uninit = cvm_oct_common_uninit;
438 device_set_desc(dev, "Cavium Octeon SGMII Ethernet");
441 case CVMX_HELPER_INTERFACE_MODE_SPI:
442 priv->init = cvm_oct_spi_init;
443 priv->uninit = cvm_oct_spi_uninit;
444 device_set_desc(dev, "Cavium Octeon SPI Ethernet");
447 case CVMX_HELPER_INTERFACE_MODE_RGMII:
448 priv->init = cvm_oct_rgmii_init;
449 priv->uninit = cvm_oct_rgmii_uninit;
450 device_set_desc(dev, "Cavium Octeon RGMII Ethernet");
453 case CVMX_HELPER_INTERFACE_MODE_GMII:
454 priv->init = cvm_oct_rgmii_init;
455 priv->uninit = cvm_oct_rgmii_uninit;
456 device_set_desc(dev, "Cavium Octeon GMII Ethernet");
460 ifp->if_softc = priv;
463 panic("%s: unsupported device type, need to free ifp.", __func__);
465 if (priv->init(ifp) < 0) {
466 printf("\t\tFailed to register ethernet device for interface %d, port %d\n",
467 interface, priv->port);
468 panic("%s: init failed, need to free ifp.", __func__);
470 cvm_oct_device[priv->port] = ifp;
471 fau -= cvmx_pko_get_num_queues(priv->port) * sizeof(uint32_t);
476 if (INTERRUPT_LIMIT) {
477 /* Set the POW timer rate to give an interrupt at most INTERRUPT_LIMIT times per second */
478 cvmx_write_csr(CVMX_POW_WQ_INT_PC, octeon_bootinfo->eclock_hz/(INTERRUPT_LIMIT*16*256)<<8);
480 /* Enable POW timer interrupt. It will count when there are packets available */
481 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1ful<<24);
483 /* Enable POW interrupt when our port has at least one packet */
484 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0x1001);
487 callout_init(&cvm_oct_poll_timer, CALLOUT_MPSAFE);
488 callout_reset(&cvm_oct_poll_timer, hz, cvm_do_timer, NULL);
495 * Module / driver shutdown
497 * @return Zero on success
499 void cvm_oct_cleanup_module(device_t bus)
502 struct octebus_softc *sc = device_get_softc(bus);
504 /* Disable POW interrupt */
505 cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0);
507 /* Free the interrupt handler */
508 bus_teardown_intr(bus, sc->sc_rx_irq, sc->sc_rx_intr_cookie);
510 callout_stop(&cvm_oct_poll_timer);
511 cvm_oct_rx_shutdown();
513 cvmx_helper_shutdown_packet_io_global();
515 /* Free the ethernet devices */
516 for (port = 0; port < TOTAL_NUMBER_OF_PORTS; port++) {
517 if (cvm_oct_device[port]) {
518 cvm_oct_tx_shutdown(cvm_oct_device[port]);
520 unregister_netdev(cvm_oct_device[port]);
521 kfree(cvm_oct_device[port]);
523 panic("%s: need to detach and free interface.", __func__);
525 cvm_oct_device[port] = NULL;
528 /* Free the HW pools */
529 cvm_oct_mem_empty_fpa(CVMX_FPA_PACKET_POOL, CVMX_FPA_PACKET_POOL_SIZE, num_packet_buffers);
530 cvm_oct_mem_empty_fpa(CVMX_FPA_WQE_POOL, CVMX_FPA_WQE_POOL_SIZE, num_packet_buffers);
532 if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL)
533 cvm_oct_mem_empty_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, cvm_oct_num_output_buffers);
535 /* Disable FPA, all buffers are free, not done by helper shutdown. */