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