source: rtems-libbsd/rtemsbsd/sys/powerpc/drivers/net/ethernet/freescale/dpaa/if_fmanmac.c @ e818128

55-freebsd-126-freebsd-12
Last change on this file since e818128 was e3dc39e, checked in by Sebastian Huber <sebastian.huber@…>, on 06/27/17 at 10:51:07

dpaa: Add <soc/fsl/dpaa.h>

  • Property mode set to 100644
File size: 13.1 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2#include <rtems/bsd/local/opt_dpaa.h>
3
4/*
5 * Copyright 2012 - 2015 Freescale Semiconductor Inc.
6 * Copyright (c) 2016 embedded brains GmbH
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
10 *     * Redistributions of source code must retain the above copyright
11 *      notice, this list of conditions and the following disclaimer.
12 *     * Redistributions in binary form must reproduce the above copyright
13 *      notice, this list of conditions and the following disclaimer in the
14 *      documentation and/or other materials provided with the distribution.
15 *     * Neither the name of Freescale Semiconductor nor the
16 *      names of its contributors may be used to endorse or promote products
17 *      derived from this software without specific prior written permission.
18 *
19 * ALTERNATIVELY, this software may be distributed under the terms of the
20 * GNU General Public License ("GPL") as published by the Free Software
21 * Foundation, either version 2 of that License or (at your option) any
22 * later version.
23 *
24 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
25 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
28 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36#include <machine/rtems-bsd-kernel-space.h>
37
38#include "if_fmanmac.h"
39
40#include <sys/sockio.h>
41
42#include <net/if_vlan_var.h>
43#include <netinet/ip.h>
44
45#include <linux/phy.h>
46
47#include <soc/fsl/dpaa.h>
48
49#include "../../../../../../../../linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h"
50
51#define FMAN_MAC_LOCK(sc)               mtx_lock(&(sc)->mtx)
52#define FMAN_MAC_UNLOCK(sc)             mtx_unlock(&(sc)->mtx)
53#define FMAN_MAC_ASSERT_LOCKED(sc)      mtx_assert(&(sc)->mtx, MA_OWNED)
54
55#define FMAN_MAC_CSUM (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TCP_IPV6 | \
56    CSUM_UDP_IPV6)
57
58struct fman_mac_sgt {
59        char priv[DPAA_TX_PRIV_DATA_SIZE];
60        struct fman_prs_result prs;
61        struct qm_sg_entry sg[DPAA_SGT_MAX_ENTRIES];
62        struct mbuf *m;
63};
64
65static void
66fman_mac_enable_tx_csum(struct mbuf *m, struct qm_fd *fd,
67    struct fman_prs_result *prs)
68{
69        int csum_flags = m->m_pkthdr.csum_flags;
70
71        if ((csum_flags & FMAN_MAC_CSUM) == 0) {
72                return;
73        }
74
75        memset(prs, 0, sizeof(*prs));
76
77        if ((csum_flags & FMAN_MAC_CSUM) == CSUM_IP) {
78                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
79        } else if ((csum_flags & CSUM_TCP) != 0) {
80                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
81                prs->l4r = FM_L4_PARSE_RESULT_TCP;
82        } else if ((csum_flags & CSUM_UDP) != 0) {
83                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
84                prs->l4r = FM_L4_PARSE_RESULT_UDP;
85        } else if ((csum_flags & CSUM_TCP_IPV6) != 0) {
86                prs->l3r = FM_L3_PARSE_RESULT_IPV6;
87                prs->l4r = FM_L4_PARSE_RESULT_TCP;
88        } else if ((csum_flags & CSUM_UDP_IPV6) != 0) {
89                prs->l3r = FM_L3_PARSE_RESULT_IPV6;
90                prs->l4r = FM_L4_PARSE_RESULT_UDP;
91        } else {
92                BSD_ASSERT(0);
93        }
94
95        /* FIXME: VLAN */
96        prs->ip_off[0] = (u8)sizeof(struct ether_header);
97        prs->l4_off = (u8)(sizeof(struct ether_header) + sizeof(struct ip));
98
99        fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
100}
101
102static void
103fman_mac_txstart_locked(struct ifnet *ifp, struct fman_mac_softc *sc)
104{
105
106        FMAN_MAC_ASSERT_LOCKED(sc);
107
108        for (;;) {
109                struct fman_mac_sgt *sgt;
110                struct mbuf *m;
111                struct mbuf *n;
112                struct qm_fd fd;
113                struct dpaa_priv *priv;
114                struct qman_fq *egress_fq;
115                int queue = 0;
116                size_t i;
117                int err;
118
119                IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
120                if (m == NULL) {
121                        break;
122                }
123
124                sgt = uma_zalloc(sc->sgt_zone, M_NOWAIT);
125                if (sgt == NULL) {
126                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
127                        m_freem(m);
128                        continue;
129                }
130
131                qm_fd_clear_fd(&fd);
132                qm_fd_set_sg(&fd, offsetof(struct fman_mac_sgt, sg), m->m_pkthdr.len);
133                fd.bpid = FSL_DPAA_BPID_INV;
134                fd.cmd |= cpu_to_be32(FM_FD_CMD_FCO);
135                qm_fd_addr_set64(&fd, (uintptr_t)sgt);
136                fman_mac_enable_tx_csum(m, &fd, &sgt->prs);
137
138repeat_with_collapsed_mbuf_chain:
139
140                i = 0;
141                n = m;
142
143                while (n != NULL && i < DPAA_SGT_MAX_ENTRIES) {
144                        int len = n->m_len;
145
146                        if (len > 0) {
147                                qm_sg_entry_set_len(&sgt->sg[i], len);
148                                sgt->sg[i].bpid = FSL_DPAA_BPID_INV;
149                                sgt->sg[i].offset = 0;
150                                qm_sg_entry_set64(&sgt->sg[i],
151                                    mtod(n, uintptr_t));
152                                ++i;
153                        }
154
155                        n = n->m_next;
156                }
157
158                if (n != NULL && i == DPAA_SGT_MAX_ENTRIES) {
159                        struct mbuf *c;
160
161                        c = m_collapse(m, M_NOWAIT, DPAA_SGT_MAX_ENTRIES);
162                        if (c == NULL) {
163                                if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
164                                m_freem(m);
165                                uma_zfree(sc->sgt_zone, sgt);
166                                continue;
167                        }
168
169                        m = c;
170                        goto repeat_with_collapsed_mbuf_chain;
171                }
172
173                sgt->sg[i - 1].cfg |= cpu_to_be32(QM_SG_FIN);
174                sgt->m = m;
175                priv = netdev_priv(&sc->mac_dev.net_dev);
176                egress_fq = priv->egress_fqs[queue];
177                fd.cmd |= cpu_to_be32(qman_fq_fqid(priv->conf_fqs[queue]));
178
179                for (i = 0; i < DPAA_ENQUEUE_RETRIES; ++i) {
180                        err = qman_enqueue(egress_fq, &fd);
181                        if (err != -EBUSY) {
182                                break;
183                        }
184                }
185
186                if (unlikely(err < 0)) {
187                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
188                        m_freem(m);
189                        continue;
190                }
191        }
192}
193
194static void
195fman_mac_txstart(struct ifnet *ifp)
196{
197        struct fman_mac_softc *sc;
198
199        sc = ifp->if_softc;
200
201        FMAN_MAC_LOCK(sc);
202        fman_mac_txstart_locked(ifp, sc);
203        FMAN_MAC_UNLOCK(sc);
204}
205
206static void
207fman_mac_tick(void *arg)
208{
209        struct fman_mac_softc *sc;
210        struct ifnet *ifp;
211
212        sc = arg;
213        ifp = sc->ifp;
214
215        FMAN_MAC_ASSERT_LOCKED(sc);
216
217        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
218                return;
219        }
220
221        mii_tick(sc->mii_softc);
222        callout_reset(&sc->fman_mac_callout, hz, fman_mac_tick, sc);
223}
224
225static void
226fman_mac_set_multi(struct fman_mac_softc *sc)
227{
228        struct mac_device *mac_dev;
229
230        FMAN_MAC_ASSERT_LOCKED(sc);
231        mac_dev = &sc->mac_dev;
232        (*mac_dev->set_multi)(&mac_dev->net_dev, mac_dev);
233}
234
235static void
236fman_mac_set_promisc(struct fman_mac_softc *sc, int if_flags)
237{
238        struct mac_device *mac_dev;
239
240        FMAN_MAC_ASSERT_LOCKED(sc);
241        mac_dev = &sc->mac_dev;
242        (*mac_dev->set_promisc)(mac_dev->fman_mac,
243            (if_flags & IFF_PROMISC) != 0);
244}
245
246static int
247fman_mac_set_mtu(struct fman_mac_softc *sc, int mtu)
248{
249        struct ifnet *ifp;
250        int real_mtu;
251
252        ifp = sc->ifp;
253        real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
254        if (real_mtu > fman_get_max_frm() ||
255            real_mtu < ETHER_MIN_LEN) {
256                return (EINVAL);
257        }
258
259        ifp->if_mtu = mtu;
260        return (0);
261}
262
263static void
264fman_mac_init_locked(struct fman_mac_softc *sc)
265{
266        struct ifnet *ifp;
267        int error;
268
269        FMAN_MAC_ASSERT_LOCKED(sc);
270
271        ifp = sc->ifp;
272        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
273                return;
274        }
275
276        ifp->if_drv_flags |= IFF_DRV_RUNNING;
277
278        error = dpa_eth_priv_start(&sc->mac_dev.net_dev);
279        BSD_ASSERT(error == 0);
280
281        if (sc->mii_softc != NULL) {
282                mii_mediachg(sc->mii_softc);
283                callout_reset(&sc->fman_mac_callout, hz, fman_mac_tick, sc);
284        }
285
286        fman_mac_set_multi(sc);
287}
288
289static void
290fman_mac_stop_locked(struct fman_mac_softc *sc)
291{
292        struct ifnet *ifp;
293        int error;
294
295        FMAN_MAC_ASSERT_LOCKED(sc);
296
297        ifp = sc->ifp;
298        ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
299
300        error = dpa_eth_priv_stop(&sc->mac_dev.net_dev);
301        BSD_ASSERT(error == 0);
302}
303
304static void
305fman_mac_init(void *if_softc)
306{
307        struct fman_mac_softc *sc;
308
309        sc = if_softc;
310        FMAN_MAC_LOCK(sc);
311        fman_mac_init_locked(sc);
312        FMAN_MAC_UNLOCK(sc);
313}
314
315static int
316fman_mac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
317{
318        struct fman_mac_softc *sc;
319        struct mii_data *mii;
320        struct ifreq *ifr;
321        int error;
322
323        sc = ifp->if_softc;
324        ifr = (struct ifreq *)data;
325
326        error = 0;
327        switch (cmd) {
328        case SIOCSIFFLAGS:
329                FMAN_MAC_LOCK(sc);
330                if (ifp->if_flags & IFF_UP) {
331                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
332                                if ((ifp->if_flags ^ sc->if_flags) &
333                                    IFF_PROMISC)
334                                        fman_mac_set_promisc(sc,
335                                            ifp->if_flags);
336                        } else {
337                                fman_mac_init_locked(sc);
338                        }
339                } else {
340                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
341                                fman_mac_stop_locked(sc);
342                        }
343                }
344                sc->if_flags = ifp->if_flags;
345                FMAN_MAC_UNLOCK(sc);
346                break;
347        case SIOCSIFMTU:
348                error = fman_mac_set_mtu(sc, ifr->ifr_mtu);
349                break;
350        case SIOCADDMULTI:
351        case SIOCDELMULTI:
352                if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
353                        FMAN_MAC_LOCK(sc);
354                        fman_mac_set_multi(sc);
355                        FMAN_MAC_UNLOCK(sc);
356                }
357                break;
358        case SIOCSIFMEDIA:
359        case SIOCGIFMEDIA:
360                mii = sc->mii_softc;
361
362                if (mii != NULL) {
363                        error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
364                } else {
365                        error = EINVAL;
366                }
367
368                break;
369        default:
370                error = ether_ioctl(ifp, cmd, data);
371                break;
372        }
373
374        return (error);
375}
376
377static int
378fman_mac_media_change(struct ifnet *ifp)
379{
380        struct fman_mac_softc *sc;
381        int error;
382
383        sc = ifp->if_softc;
384        FMAN_MAC_LOCK(sc);
385        error = mii_mediachg(sc->mii_softc);
386        FMAN_MAC_UNLOCK(sc);
387        return (error);
388}
389
390static void
391fman_mac_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
392{
393        struct fman_mac_softc *sc;
394        struct mii_data *mii;
395
396        sc = ifp->if_softc;
397        mii = sc->mii_softc;
398        FMAN_MAC_LOCK(sc);
399        mii_pollstat(mii);
400        ifmr->ifm_active = mii->mii_media_active;
401        ifmr->ifm_status = mii->mii_media_status;
402        FMAN_MAC_UNLOCK(sc);
403}
404
405int
406fman_mac_dev_attach(device_t dev)
407{
408        struct fman_mac_softc *sc;
409        struct ifnet *ifp;
410        struct phy_device *phy_dev;
411        int error;
412
413        sc = device_get_softc(dev);
414
415        mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
416            MTX_DEF);
417
418        callout_init_mtx(&sc->fman_mac_callout, &sc->mtx, 0);
419
420        sc->sgt_zone = uma_zcreate("FMan MAC SGT", sizeof(struct fman_mac_sgt),
421            NULL, NULL, NULL, NULL, 16, 0);
422        if (sc->sgt_zone == NULL) {
423                goto error_0;
424        }
425
426        /* Set up the Ethernet interface */
427        sc->ifp = ifp = if_alloc(IFT_ETHER);
428        if (sc->ifp == NULL) {
429                goto error_1;
430        }
431
432        snprintf(&sc->name[0], sizeof(sc->name), "fm%im",
433            device_get_unit(device_get_parent(dev)));
434
435        ifp->if_softc = sc;
436        if_initname(ifp, &sc->name[0], sc->mac_dev.data.mac_hw_id);
437        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
438        ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
439            IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
440        ifp->if_capenable = ifp->if_capabilities;
441        ifp->if_hwassist = FMAN_MAC_CSUM;
442        ifp->if_start = fman_mac_txstart;
443        ifp->if_ioctl = fman_mac_ioctl;
444        ifp->if_init = fman_mac_init;
445        IFQ_SET_MAXLEN(&ifp->if_snd, 128);
446        ifp->if_snd.ifq_drv_maxlen = 128;
447        IFQ_SET_READY(&ifp->if_snd);
448        ifp->if_hdrlen = sizeof(struct ether_vlan_header);
449
450        /* Attach the MII driver if necessary */
451        phy_dev = sc->mac_dev.phy_dev;
452        if (phy_dev != NULL) {
453                error = mii_attach(dev, &sc->miibus, ifp,
454                    fman_mac_media_change, fman_mac_media_status,
455                    BMSR_DEFCAPMASK, phy_dev->mdio.addr, MII_OFFSET_ANY, 0);
456                if (error == 0) {
457                        sc->mii_softc = device_get_softc(sc->miibus);
458                }
459        }
460
461        sc->mac_dev.net_dev.ifp = ifp;
462
463        ether_ifattach(ifp, &sc->mac_dev.addr[0]);
464#if 0
465        fman_mac_set_mtu(sc, ETHERMTU_JUMBO);
466#endif
467
468        return (0);
469
470        if_free(ifp);
471error_1:
472        uma_zdestroy(sc->sgt_zone);
473error_0:
474        mtx_destroy(&sc->mtx);
475        return (ENXIO);
476}
477
478int
479fman_mac_dev_detach(device_t _dev)
480{
481        struct fman_mac_softc *sc = device_get_softc(_dev);
482
483        ether_ifdetach(sc->ifp);
484
485        FMAN_MAC_LOCK(sc);
486        fman_mac_stop_locked(sc);
487        FMAN_MAC_UNLOCK(sc);
488
489        if_free(sc->ifp);
490        uma_zdestroy(sc->sgt_zone);
491        mtx_destroy(&sc->mtx);
492
493        return (bus_generic_detach(_dev));
494}
495
496int
497fman_mac_miibus_read_reg(device_t dev, int phy, int reg)
498{
499        struct fman_mac_softc *sc;
500        struct phy_device *phy_dev;
501
502        sc = device_get_softc(dev);
503        phy_dev = sc->mac_dev.phy_dev;
504        BSD_ASSERT(phy == phy_dev->mdio.addr);
505        return (phy_read(phy_dev, reg));
506}
507
508int
509fman_mac_miibus_write_reg(device_t dev, int phy, int reg, int val)
510{
511        struct fman_mac_softc *sc;
512        struct phy_device *phy_dev;
513
514        sc = device_get_softc(dev);
515        phy_dev = sc->mac_dev.phy_dev;
516        BSD_ASSERT(phy == phy_dev->mdio.addr);
517        return (phy_write(phy_dev, reg, val));
518}
519
520void
521fman_mac_miibus_statchg(device_t dev)
522{
523        struct fman_mac_softc *sc;
524        struct mac_device *mac_dev;
525        struct mii_data *mii;
526        u16 speed;
527
528        sc = device_get_softc(dev);
529        mac_dev = &sc->mac_dev;
530        mii = sc->mii_softc;
531
532        FMAN_MAC_ASSERT_LOCKED(sc);
533
534        switch (IFM_SUBTYPE(mii->mii_media_active)) {
535        case IFM_10_T:
536        case IFM_10_2:
537        case IFM_10_5:
538        case IFM_10_STP:
539        case IFM_10_FL:
540                speed = SPEED_10;
541                break;
542        case IFM_100_TX:
543        case IFM_100_FX:
544        case IFM_100_T4:
545        case IFM_100_VG:
546        case IFM_100_T2:
547                speed = SPEED_100;
548                break;
549        case IFM_1000_SX:
550        case IFM_1000_LX:
551        case IFM_1000_CX:
552        case IFM_1000_T:
553                speed = SPEED_1000;
554                break;
555        case IFM_10G_LR:
556        case IFM_10G_SR:
557        case IFM_10G_CX4:
558        case IFM_10G_TWINAX:
559        case IFM_10G_TWINAX_LONG:
560        case IFM_10G_LRM:
561                speed = SPEED_10000;
562                break;
563        default:
564                speed = 0;
565                break;
566        }
567
568        (*mac_dev->adjust_link)(mac_dev, speed);
569}
570
571void dpaa_cleanup_tx_fd(struct ifnet *ifp, const struct qm_fd *fd)
572{
573        struct fman_mac_softc *sc;
574        struct fman_mac_sgt *sgt;
575
576        BSD_ASSERT(qm_fd_get_format(fd) == qm_fd_sg);
577
578        sc = ifp->if_softc;
579        sgt = (struct fman_mac_sgt *)qm_fd_addr(fd);
580
581        m_freem(sgt->m);
582        uma_zfree(sc->sgt_zone, sgt);
583}
584
585struct dpaa_priv *
586dpaa_get_priv_of_ifp(struct ifnet *ifp)
587{
588        struct fman_mac_softc *sc;
589
590        sc = ifp->if_softc;
591        return (netdev_priv(&sc->mac_dev.net_dev));
592}
Note: See TracBrowser for help on using the repository browser.