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

55-freebsd-126-freebsd-12
Last change on this file since ed254d58 was ed254d58, checked in by Sebastian Huber <sebastian.huber@…>, on 05/18/17 at 06:13:07

dpaa: Use receive checksum offload

  • Property mode set to 100644
File size: 13.0 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 "../../../../../../../../linux/drivers/net/ethernet/freescale/dpaa/dpaa_eth.h"
48
49#define FMAN_MAC_LOCK(sc)               mtx_lock(&(sc)->mtx)
50#define FMAN_MAC_UNLOCK(sc)             mtx_unlock(&(sc)->mtx)
51#define FMAN_MAC_ASSERT_LOCKED(sc)      mtx_assert(&(sc)->mtx, MA_OWNED)
52
53#define FMAN_MAC_CSUM (CSUM_IP | CSUM_TCP | CSUM_UDP | CSUM_TCP_IPV6 | \
54    CSUM_UDP_IPV6)
55
56struct fman_mac_sgt {
57        char priv[DPAA_TX_PRIV_DATA_SIZE];
58        struct fman_prs_result prs;
59        struct qm_sg_entry sg[DPAA_SGT_MAX_ENTRIES];
60        struct mbuf *m;
61};
62
63static void
64fman_mac_enable_tx_csum(struct mbuf *m, struct qm_fd *fd,
65    struct fman_prs_result *prs)
66{
67        int csum_flags = m->m_pkthdr.csum_flags;
68
69        if ((csum_flags & FMAN_MAC_CSUM) == 0) {
70                return;
71        }
72
73        memset(prs, 0, sizeof(*prs));
74
75        if ((csum_flags & FMAN_MAC_CSUM) == CSUM_IP) {
76                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
77        } else if ((csum_flags & CSUM_TCP) != 0) {
78                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
79                prs->l4r = FM_L4_PARSE_RESULT_TCP;
80        } else if ((csum_flags & CSUM_UDP) != 0) {
81                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
82                prs->l4r = FM_L4_PARSE_RESULT_UDP;
83        } else if ((csum_flags & CSUM_TCP_IPV6) != 0) {
84                prs->l3r = FM_L3_PARSE_RESULT_IPV6;
85                prs->l4r = FM_L4_PARSE_RESULT_TCP;
86        } else if ((csum_flags & CSUM_UDP_IPV6) != 0) {
87                prs->l3r = FM_L3_PARSE_RESULT_IPV6;
88                prs->l4r = FM_L4_PARSE_RESULT_UDP;
89        } else {
90                BSD_ASSERT(0);
91        }
92
93        /* FIXME: VLAN */
94        prs->ip_off[0] = (u8)sizeof(struct ether_header);
95        prs->l4_off = (u8)(sizeof(struct ether_header) + sizeof(struct ip));
96
97        fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
98}
99
100static void
101fman_mac_txstart_locked(struct ifnet *ifp, struct fman_mac_softc *sc)
102{
103
104        FMAN_MAC_ASSERT_LOCKED(sc);
105
106        for (;;) {
107                struct fman_mac_sgt *sgt;
108                struct mbuf *m;
109                struct mbuf *n;
110                struct qm_fd fd;
111                struct dpaa_priv *priv;
112                struct qman_fq *egress_fq;
113                int queue = 0;
114                size_t i;
115                int err;
116
117                IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
118                if (m == NULL) {
119                        break;
120                }
121
122                sgt = uma_zalloc(sc->sgt_zone, M_NOWAIT);
123                if (sgt == NULL) {
124                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
125                        m_freem(m);
126                        continue;
127                }
128
129                qm_fd_clear_fd(&fd);
130                qm_fd_set_sg(&fd, offsetof(struct fman_mac_sgt, sg), m->m_pkthdr.len);
131                fd.bpid = FSL_DPAA_BPID_INV;
132                fd.cmd |= cpu_to_be32(FM_FD_CMD_FCO);
133                qm_fd_addr_set64(&fd, (uintptr_t)sgt);
134                fman_mac_enable_tx_csum(m, &fd, &sgt->prs);
135
136repeat_with_collapsed_mbuf_chain:
137
138                i = 0;
139                n = m;
140
141                while (n != NULL && i < DPAA_SGT_MAX_ENTRIES) {
142                        int len = n->m_len;
143
144                        if (len > 0) {
145                                qm_sg_entry_set_len(&sgt->sg[i], len);
146                                sgt->sg[i].bpid = FSL_DPAA_BPID_INV;
147                                sgt->sg[i].offset = 0;
148                                qm_sg_entry_set64(&sgt->sg[i],
149                                    mtod(n, uintptr_t));
150                                ++i;
151                        }
152
153                        n = n->m_next;
154                }
155
156                if (n != NULL && i == DPAA_SGT_MAX_ENTRIES) {
157                        struct mbuf *c;
158
159                        c = m_collapse(m, M_NOWAIT, DPAA_SGT_MAX_ENTRIES);
160                        if (c == NULL) {
161                                if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
162                                m_freem(m);
163                                uma_zfree(sc->sgt_zone, sgt);
164                                continue;
165                        }
166
167                        m = c;
168                        goto repeat_with_collapsed_mbuf_chain;
169                }
170
171                sgt->sg[i - 1].cfg |= cpu_to_be32(QM_SG_FIN);
172                sgt->m = m;
173                priv = netdev_priv(&sc->mac_dev.net_dev);
174                egress_fq = priv->egress_fqs[queue];
175                fd.cmd |= cpu_to_be32(qman_fq_fqid(priv->conf_fqs[queue]));
176
177                for (i = 0; i < DPAA_ENQUEUE_RETRIES; ++i) {
178                        err = qman_enqueue(egress_fq, &fd);
179                        if (err != -EBUSY) {
180                                break;
181                        }
182                }
183
184                if (unlikely(err < 0)) {
185                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
186                        m_freem(m);
187                        continue;
188                }
189        }
190}
191
192static void
193fman_mac_txstart(struct ifnet *ifp)
194{
195        struct fman_mac_softc *sc;
196
197        sc = ifp->if_softc;
198
199        FMAN_MAC_LOCK(sc);
200        fman_mac_txstart_locked(ifp, sc);
201        FMAN_MAC_UNLOCK(sc);
202}
203
204static void
205fman_mac_tick(void *arg)
206{
207        struct fman_mac_softc *sc;
208        struct ifnet *ifp;
209
210        sc = arg;
211        ifp = sc->ifp;
212
213        FMAN_MAC_ASSERT_LOCKED(sc);
214
215        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
216                return;
217        }
218
219        mii_tick(sc->mii_softc);
220        callout_reset(&sc->fman_mac_callout, hz, fman_mac_tick, sc);
221}
222
223static void
224fman_mac_set_multi(struct fman_mac_softc *sc)
225{
226        struct mac_device *mac_dev;
227
228        FMAN_MAC_ASSERT_LOCKED(sc);
229        mac_dev = &sc->mac_dev;
230        (*mac_dev->set_multi)(&mac_dev->net_dev, mac_dev);
231}
232
233static void
234fman_mac_set_promisc(struct fman_mac_softc *sc, int if_flags)
235{
236        struct mac_device *mac_dev;
237
238        FMAN_MAC_ASSERT_LOCKED(sc);
239        mac_dev = &sc->mac_dev;
240        (*mac_dev->set_promisc)(mac_dev->fman_mac,
241            (if_flags & IFF_PROMISC) != 0);
242}
243
244static int
245fman_mac_set_mtu(struct fman_mac_softc *sc, int mtu)
246{
247        struct ifnet *ifp;
248        int real_mtu;
249
250        ifp = sc->ifp;
251        real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
252        if (real_mtu > fman_get_max_frm() ||
253            real_mtu < ETHER_MIN_LEN) {
254                return (EINVAL);
255        }
256
257        ifp->if_mtu = mtu;
258        return (0);
259}
260
261static void
262fman_mac_init_locked(struct fman_mac_softc *sc)
263{
264        struct ifnet *ifp;
265        int error;
266
267        FMAN_MAC_ASSERT_LOCKED(sc);
268
269        ifp = sc->ifp;
270        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
271                return;
272        }
273
274        ifp->if_drv_flags |= IFF_DRV_RUNNING;
275
276        error = dpa_eth_priv_start(&sc->mac_dev.net_dev);
277        BSD_ASSERT(error == 0);
278
279        if (sc->mii_softc != NULL) {
280                mii_mediachg(sc->mii_softc);
281                callout_reset(&sc->fman_mac_callout, hz, fman_mac_tick, sc);
282        }
283
284        fman_mac_set_multi(sc);
285}
286
287static void
288fman_mac_stop_locked(struct fman_mac_softc *sc)
289{
290        struct ifnet *ifp;
291        int error;
292
293        FMAN_MAC_ASSERT_LOCKED(sc);
294
295        ifp = sc->ifp;
296        ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
297
298        error = dpa_eth_priv_stop(&sc->mac_dev.net_dev);
299        BSD_ASSERT(error == 0);
300}
301
302static void
303fman_mac_init(void *if_softc)
304{
305        struct fman_mac_softc *sc;
306
307        sc = if_softc;
308        FMAN_MAC_LOCK(sc);
309        fman_mac_init_locked(sc);
310        FMAN_MAC_UNLOCK(sc);
311}
312
313static int
314fman_mac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
315{
316        struct fman_mac_softc *sc;
317        struct mii_data *mii;
318        struct ifreq *ifr;
319        int error;
320
321        sc = ifp->if_softc;
322        ifr = (struct ifreq *)data;
323
324        error = 0;
325        switch (cmd) {
326        case SIOCSIFFLAGS:
327                FMAN_MAC_LOCK(sc);
328                if (ifp->if_flags & IFF_UP) {
329                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
330                                if ((ifp->if_flags ^ sc->if_flags) &
331                                    IFF_PROMISC)
332                                        fman_mac_set_promisc(sc,
333                                            ifp->if_flags);
334                        } else {
335                                fman_mac_init_locked(sc);
336                        }
337                } else {
338                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
339                                fman_mac_stop_locked(sc);
340                        }
341                }
342                sc->if_flags = ifp->if_flags;
343                FMAN_MAC_UNLOCK(sc);
344                break;
345        case SIOCSIFMTU:
346                error = fman_mac_set_mtu(sc, ifr->ifr_mtu);
347                break;
348        case SIOCADDMULTI:
349        case SIOCDELMULTI:
350                if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
351                        FMAN_MAC_LOCK(sc);
352                        fman_mac_set_multi(sc);
353                        FMAN_MAC_UNLOCK(sc);
354                }
355                break;
356        case SIOCSIFMEDIA:
357        case SIOCGIFMEDIA:
358                mii = sc->mii_softc;
359
360                if (mii != NULL) {
361                        error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
362                } else {
363                        error = EINVAL;
364                }
365
366                break;
367        default:
368                error = ether_ioctl(ifp, cmd, data);
369                break;
370        }
371
372        return (error);
373}
374
375static int
376fman_mac_media_change(struct ifnet *ifp)
377{
378        struct fman_mac_softc *sc;
379        int error;
380
381        sc = ifp->if_softc;
382        FMAN_MAC_LOCK(sc);
383        error = mii_mediachg(sc->mii_softc);
384        FMAN_MAC_UNLOCK(sc);
385        return (error);
386}
387
388static void
389fman_mac_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
390{
391        struct fman_mac_softc *sc;
392        struct mii_data *mii;
393
394        sc = ifp->if_softc;
395        mii = sc->mii_softc;
396        FMAN_MAC_LOCK(sc);
397        mii_pollstat(mii);
398        ifmr->ifm_active = mii->mii_media_active;
399        ifmr->ifm_status = mii->mii_media_status;
400        FMAN_MAC_UNLOCK(sc);
401}
402
403int
404fman_mac_dev_attach(device_t dev)
405{
406        struct fman_mac_softc *sc;
407        struct ifnet *ifp;
408        struct phy_device *phy_dev;
409        int error;
410
411        sc = device_get_softc(dev);
412
413        mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
414            MTX_DEF);
415
416        callout_init_mtx(&sc->fman_mac_callout, &sc->mtx, 0);
417
418        sc->sgt_zone = uma_zcreate("FMan MAC SGT", sizeof(struct fman_mac_sgt),
419            NULL, NULL, NULL, NULL, 16, 0);
420        if (sc->sgt_zone == NULL) {
421                goto error_0;
422        }
423
424        /* Set up the Ethernet interface */
425        sc->ifp = ifp = if_alloc(IFT_ETHER);
426        if (sc->ifp == NULL) {
427                goto error_1;
428        }
429
430        snprintf(&sc->name[0], sizeof(sc->name), "fm%im",
431            device_get_unit(device_get_parent(dev)));
432
433        ifp->if_softc = sc;
434        if_initname(ifp, &sc->name[0], sc->mac_dev.data.mac_hw_id);
435        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
436        ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
437            IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
438        ifp->if_capenable = ifp->if_capabilities;
439        ifp->if_hwassist = FMAN_MAC_CSUM;
440        ifp->if_start = fman_mac_txstart;
441        ifp->if_ioctl = fman_mac_ioctl;
442        ifp->if_init = fman_mac_init;
443        IFQ_SET_MAXLEN(&ifp->if_snd, 128);
444        ifp->if_snd.ifq_drv_maxlen = 128;
445        IFQ_SET_READY(&ifp->if_snd);
446        ifp->if_hdrlen = sizeof(struct ether_vlan_header);
447
448        /* Attach the MII driver if necessary */
449        phy_dev = sc->mac_dev.phy_dev;
450        if (phy_dev != NULL) {
451                error = mii_attach(dev, &sc->miibus, ifp,
452                    fman_mac_media_change, fman_mac_media_status,
453                    BMSR_DEFCAPMASK, phy_dev->mdio.addr, MII_OFFSET_ANY, 0);
454                if (error != 0) {
455                        goto error_2;
456                }
457                sc->mii_softc = device_get_softc(sc->miibus);
458        }
459
460        sc->mac_dev.net_dev.ifp = ifp;
461
462        ether_ifattach(ifp, &sc->mac_dev.addr[0]);
463#if 0
464        fman_mac_set_mtu(sc, ETHERMTU_JUMBO);
465#endif
466
467        return (0);
468
469error_2:
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}
Note: See TracBrowser for help on using the repository browser.