2 * Copyright (c) 2012 Semihalf.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/module.h>
36 #include <sys/malloc.h>
38 #include <sys/socket.h>
39 #include <sys/sysctl.h>
40 #include <sys/sockio.h>
42 #include <net/ethernet.h>
44 #include <net/if_dl.h>
45 #include <net/if_media.h>
46 #include <net/if_types.h>
47 #include <net/if_arp.h>
49 #include <dev/mii/mii.h>
50 #include <dev/mii/miivar.h>
52 #include "miibus_if.h"
54 #include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h>
55 #include <contrib/ncsw/inc/Peripherals/fm_port_ext.h>
56 #include <contrib/ncsw/inc/xx_ext.h>
62 #include "if_dtsec_rm.h"
66 * @group dTSEC RM private defines.
69 #define DTSEC_BPOOLS_USED (1)
70 #define DTSEC_MAX_TX_QUEUE_LEN 256
72 struct dtsec_rm_frame_info {
74 t_DpaaSGTE fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY];
77 enum dtsec_rm_pool_params {
78 DTSEC_RM_POOL_RX_LOW_MARK = 16,
79 DTSEC_RM_POOL_RX_HIGH_MARK = 64,
80 DTSEC_RM_POOL_RX_MAX_SIZE = 256,
82 DTSEC_RM_POOL_FI_LOW_MARK = 16,
83 DTSEC_RM_POOL_FI_HIGH_MARK = 64,
84 DTSEC_RM_POOL_FI_MAX_SIZE = 256,
87 enum dtsec_rm_fqr_params {
88 DTSEC_RM_FQR_RX_CHANNEL = e_QM_FQ_CHANNEL_POOL1,
89 DTSEC_RM_FQR_RX_WQ = 1,
90 DTSEC_RM_FQR_TX_CONF_CHANNEL = e_QM_FQ_CHANNEL_SWPORTAL0,
91 DTSEC_RM_FQR_TX_WQ = 1,
92 DTSEC_RM_FQR_TX_CONF_WQ = 1
98 * @group dTSEC Frame Info routines.
102 dtsec_rm_fi_pool_free(struct dtsec_softc *sc)
105 if (sc->sc_fi_zone != NULL)
106 uma_zdestroy(sc->sc_fi_zone);
110 dtsec_rm_fi_pool_init(struct dtsec_softc *sc)
113 snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info",
114 device_get_nameunit(sc->sc_dev));
116 sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname,
117 sizeof(struct dtsec_rm_frame_info), NULL, NULL, NULL, NULL,
119 if (sc->sc_fi_zone == NULL)
125 static struct dtsec_rm_frame_info *
126 dtsec_rm_fi_alloc(struct dtsec_softc *sc)
128 struct dtsec_rm_frame_info *fi;
130 fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT);
136 dtsec_rm_fi_free(struct dtsec_softc *sc, struct dtsec_rm_frame_info *fi)
139 uma_zfree(sc->sc_fi_zone, fi);
145 * @group dTSEC FMan PORT routines.
149 dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit)
151 t_FmPortParams params;
152 t_FmPortRxParams *rx_params;
153 t_FmPortExtPools *pool_params;
156 memset(¶ms, 0, sizeof(params));
158 params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id;
159 params.h_Fm = sc->sc_fmh;
160 params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type);
161 params.portId = sc->sc_eth_id;
162 params.independentModeEnable = FALSE;
163 params.liodnBase = FM_PORT_LIODN_BASE;
164 params.f_Exception = dtsec_fm_port_rx_exception_callback;
167 rx_params = ¶ms.specificParams.rxParams;
168 rx_params->errFqid = sc->sc_rx_fqid;
169 rx_params->dfltFqid = sc->sc_rx_fqid;
170 rx_params->liodnOffset = 0;
172 pool_params = &rx_params->extBufPools;
173 pool_params->numOfPoolsUsed = DTSEC_BPOOLS_USED;
174 pool_params->extBufPool->id = sc->sc_rx_bpid;
175 pool_params->extBufPool->size = FM_PORT_BUFFER_SIZE;
177 sc->sc_rxph = FM_PORT_Config(¶ms);
178 if (sc->sc_rxph == NULL) {
179 device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n");
183 error = FM_PORT_Init(sc->sc_rxph);
185 device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n");
186 FM_PORT_Free(sc->sc_rxph);
191 device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n",
192 sc->sc_port_rx_hw_id);
198 dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit)
200 t_FmPortParams params;
201 t_FmPortNonRxParams *tx_params;
204 memset(¶ms, 0, sizeof(params));
206 params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id;
207 params.h_Fm = sc->sc_fmh;
208 params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type);
209 params.portId = sc->sc_eth_id;
210 params.independentModeEnable = FALSE;
211 params.liodnBase = FM_PORT_LIODN_BASE;
212 params.f_Exception = dtsec_fm_port_tx_exception_callback;
215 tx_params = ¶ms.specificParams.nonRxParams;
216 tx_params->errFqid = sc->sc_tx_conf_fqid;
217 tx_params->dfltFqid = sc->sc_tx_conf_fqid;
218 tx_params->qmChannel = sc->sc_port_tx_qman_chan;
219 #ifdef FM_OP_PARTITION_ERRATA_FMANx8
220 tx_params->opLiodnOffset = 0;
223 sc->sc_txph = FM_PORT_Config(¶ms);
224 if (sc->sc_txph == NULL) {
225 device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n");
229 error = FM_PORT_Init(sc->sc_txph);
231 device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n");
232 FM_PORT_Free(sc->sc_txph);
237 device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n",
238 sc->sc_port_tx_hw_id);
246 * @group dTSEC buffer pools routines.
250 dtsec_rm_pool_rx_put_buffer(t_Handle h_BufferPool, uint8_t *buffer,
253 struct dtsec_softc *sc;
256 uma_zfree(sc->sc_rx_zone, buffer);
262 dtsec_rm_pool_rx_get_buffer(t_Handle h_BufferPool, t_Handle *context)
264 struct dtsec_softc *sc;
268 buffer = uma_zalloc(sc->sc_rx_zone, M_NOWAIT);
274 dtsec_rm_pool_rx_depleted(t_Handle h_App, bool in)
276 struct dtsec_softc *sc;
285 count = bman_count(sc->sc_rx_pool);
286 if (count > DTSEC_RM_POOL_RX_HIGH_MARK)
289 bman_pool_fill(sc->sc_rx_pool, DTSEC_RM_POOL_RX_HIGH_MARK);
294 dtsec_rm_pool_rx_free(struct dtsec_softc *sc)
297 if (sc->sc_rx_pool != NULL)
298 bman_pool_destroy(sc->sc_rx_pool);
300 if (sc->sc_rx_zone != NULL)
301 uma_zdestroy(sc->sc_rx_zone);
305 dtsec_rm_pool_rx_init(struct dtsec_softc *sc)
308 /* FM_PORT_BUFFER_SIZE must be less than PAGE_SIZE */
309 CTASSERT(FM_PORT_BUFFER_SIZE < PAGE_SIZE);
311 snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers",
312 device_get_nameunit(sc->sc_dev));
314 sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, FM_PORT_BUFFER_SIZE, NULL,
315 NULL, NULL, NULL, FM_PORT_BUFFER_SIZE - 1, 0);
316 if (sc->sc_rx_zone == NULL)
319 sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, FM_PORT_BUFFER_SIZE,
320 0, 0, DTSEC_RM_POOL_RX_MAX_SIZE, dtsec_rm_pool_rx_get_buffer,
321 dtsec_rm_pool_rx_put_buffer, DTSEC_RM_POOL_RX_LOW_MARK,
322 DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dtsec_rm_pool_rx_depleted, sc, NULL,
324 if (sc->sc_rx_pool == NULL) {
325 device_printf(sc->sc_dev, "NULL rx pool somehow\n");
326 dtsec_rm_pool_rx_free(sc);
336 * @group dTSEC Frame Queue Range routines.
340 dtsec_rm_fqr_mext_free(struct mbuf *m, void *buffer, void *arg)
342 struct dtsec_softc *sc;
345 if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE)
346 bman_put_buffer(sc->sc_rx_pool, buffer);
348 dtsec_rm_pool_rx_put_buffer(arg, buffer, NULL);
351 static e_RxStoreResponse
352 dtsec_rm_fqr_rx_callback(t_Handle app, t_Handle fqr, t_Handle portal,
353 uint32_t fqid_off, t_DpaaFD *frame)
355 struct dtsec_softc *sc;
361 KASSERT(DPAA_FD_GET_FORMAT(frame) == e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF,
362 ("%s(): Got unsupported frame format 0x%02X!", __func__,
363 DPAA_FD_GET_FORMAT(frame)));
365 KASSERT(DPAA_FD_GET_OFFSET(frame) == 0,
366 ("%s(): Only offset 0 is supported!", __func__));
368 if (DPAA_FD_GET_STATUS(frame) != 0) {
369 device_printf(sc->sc_dev, "RX error: 0x%08X\n",
370 DPAA_FD_GET_STATUS(frame));
374 m = m_gethdr(M_NOWAIT, MT_HEADER);
378 m_extadd(m, DPAA_FD_GET_ADDR(frame), FM_PORT_BUFFER_SIZE,
379 dtsec_rm_fqr_mext_free, DPAA_FD_GET_ADDR(frame), sc, 0,
382 m->m_pkthdr.rcvif = sc->sc_ifnet;
383 m->m_len = DPAA_FD_GET_LENGTH(frame);
386 (*sc->sc_ifnet->if_input)(sc->sc_ifnet, m);
388 return (e_RX_STORE_RESPONSE_CONTINUE);
391 bman_put_buffer(sc->sc_rx_pool, DPAA_FD_GET_ADDR(frame));
395 return (e_RX_STORE_RESPONSE_CONTINUE);
398 static e_RxStoreResponse
399 dtsec_rm_fqr_tx_confirm_callback(t_Handle app, t_Handle fqr, t_Handle portal,
400 uint32_t fqid_off, t_DpaaFD *frame)
402 struct dtsec_rm_frame_info *fi;
403 struct dtsec_softc *sc;
409 if (DPAA_FD_GET_STATUS(frame) != 0)
410 device_printf(sc->sc_dev, "TX error: 0x%08X\n",
411 DPAA_FD_GET_STATUS(frame));
414 * We are storing struct dtsec_rm_frame_info in first entry
415 * of scatter-gather table.
417 sgt0 = DPAA_FD_GET_ADDR(frame);
418 fi = DPAA_SGTE_GET_ADDR(sgt0);
420 /* Free transmitted frame */
421 m_freem(fi->fi_mbuf);
422 dtsec_rm_fi_free(sc, fi);
424 qlen = qman_fqr_get_counter(sc->sc_tx_conf_fqr, 0,
425 e_QM_FQR_COUNTERS_FRAME);
430 if (sc->sc_tx_fqr_full) {
431 sc->sc_tx_fqr_full = 0;
432 dtsec_rm_if_start_locked(sc);
438 return (e_RX_STORE_RESPONSE_CONTINUE);
442 dtsec_rm_fqr_rx_free(struct dtsec_softc *sc)
446 qman_fqr_free(sc->sc_rx_fqr);
450 dtsec_rm_fqr_rx_init(struct dtsec_softc *sc)
455 /* Default Frame Queue */
456 fqr = qman_fqr_create(1, DTSEC_RM_FQR_RX_CHANNEL, DTSEC_RM_FQR_RX_WQ,
457 FALSE, 0, FALSE, FALSE, TRUE, FALSE, 0, 0, 0);
459 device_printf(sc->sc_dev, "could not create default RX queue"
465 sc->sc_rx_fqid = qman_fqr_get_base_fqid(fqr);
467 error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_rx_callback, sc);
469 device_printf(sc->sc_dev, "could not register RX callback\n");
470 dtsec_rm_fqr_rx_free(sc);
478 dtsec_rm_fqr_tx_free(struct dtsec_softc *sc)
482 qman_fqr_free(sc->sc_tx_fqr);
484 if (sc->sc_tx_conf_fqr)
485 qman_fqr_free(sc->sc_tx_conf_fqr);
489 dtsec_rm_fqr_tx_init(struct dtsec_softc *sc)
495 fqr = qman_fqr_create(1, sc->sc_port_tx_qman_chan,
496 DTSEC_RM_FQR_TX_WQ, FALSE, 0, FALSE, FALSE, TRUE, FALSE, 0, 0, 0);
498 device_printf(sc->sc_dev, "could not create default TX queue"
505 /* TX Confirmation Frame Queue */
506 fqr = qman_fqr_create(1, DTSEC_RM_FQR_TX_CONF_CHANNEL,
507 DTSEC_RM_FQR_TX_CONF_WQ, FALSE, 0, FALSE, FALSE, TRUE, FALSE, 0, 0,
510 device_printf(sc->sc_dev, "could not create TX confirmation "
512 dtsec_rm_fqr_tx_free(sc);
516 sc->sc_tx_conf_fqr = fqr;
517 sc->sc_tx_conf_fqid = qman_fqr_get_base_fqid(fqr);
519 error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_tx_confirm_callback, sc);
521 device_printf(sc->sc_dev, "could not register TX confirmation "
523 dtsec_rm_fqr_tx_free(sc);
533 * @group dTSEC IFnet routines.
537 dtsec_rm_if_start_locked(struct dtsec_softc *sc)
539 vm_size_t dsize, psize, ssize;
540 struct dtsec_rm_frame_info *fi;
541 unsigned int qlen, i;
547 DTSEC_LOCK_ASSERT(sc);
548 /* TODO: IFF_DRV_OACTIVE */
550 if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0)
553 if ((sc->sc_ifnet->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING)
556 while (!IFQ_DRV_IS_EMPTY(&sc->sc_ifnet->if_snd)) {
557 /* Check length of the TX queue */
558 qlen = qman_fqr_get_counter(sc->sc_tx_fqr, 0,
559 e_QM_FQR_COUNTERS_FRAME);
561 if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) {
562 sc->sc_tx_fqr_full = 1;
566 fi = dtsec_rm_fi_alloc(sc);
570 IFQ_DRV_DEQUEUE(&sc->sc_ifnet->if_snd, m0);
572 dtsec_rm_fi_free(sc, fi);
581 while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
586 * First entry in scatter-gather table is used to keep
587 * pointer to frame info structure.
589 DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i], (void *)fi);
590 DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], 0);
592 DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
593 DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
594 DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
595 DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
599 vaddr = (vm_offset_t)m->m_data;
600 while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) {
601 paddr = XX_VirtToPhys((void *)vaddr);
602 ssize = PAGE_SIZE - (paddr & PAGE_MASK);
603 if (m->m_len < ssize)
606 DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i],
608 DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], ssize);
610 DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0);
611 DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0);
612 DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0);
613 DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0);
627 /* Check if SG table was constructed properly */
628 if (m != NULL || dsize != 0) {
629 dtsec_rm_fi_free(sc, fi);
634 DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i-1], 1);
636 DPAA_FD_SET_ADDR(&fd, fi->fi_sgt);
637 DPAA_FD_SET_LENGTH(&fd, psize);
638 DPAA_FD_SET_FORMAT(&fd, e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF);
640 DPAA_FD_SET_DD(&fd, 0);
641 DPAA_FD_SET_PID(&fd, 0);
642 DPAA_FD_SET_BPID(&fd, 0);
643 DPAA_FD_SET_OFFSET(&fd, 0);
644 DPAA_FD_SET_STATUS(&fd, 0);
647 if (qman_fqr_enqueue(sc->sc_tx_fqr, 0, &fd) != E_OK) {
648 dtsec_rm_fi_free(sc, fi);