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

5
Last change on this file since a1bad53 was a1bad53, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 14, 2019 at 12:08:08 PM

dpaa: Fix FMan MAC SGT zone alignment

  • Property mode set to 100644
File size: 13.4 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 uma_zone_t fman_mac_sgt_zone;
66
67static void
68fman_mac_sgt_init(void)
69{
70
71        fman_mac_sgt_zone = uma_zcreate("FMan MAC SGT", sizeof(struct fman_mac_sgt),
72            NULL, NULL, NULL, NULL, 16 - 1, 0);
73        if (fman_mac_sgt_zone == NULL) {
74                panic("Cannot create FMan MAC SGT zone");
75        }
76}
77SYSINIT(fman_mac_sgt, SI_SUB_MBUF, SI_ORDER_ANY, fman_mac_sgt_init, NULL);
78
79static void
80fman_mac_enable_tx_csum(struct mbuf *m, struct qm_fd *fd,
81    struct fman_prs_result *prs)
82{
83        int csum_flags = m->m_pkthdr.csum_flags;
84
85        if ((csum_flags & FMAN_MAC_CSUM) == 0) {
86                return;
87        }
88
89        memset(prs, 0, sizeof(*prs));
90
91        if ((csum_flags & FMAN_MAC_CSUM) == CSUM_IP) {
92                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
93        } else if ((csum_flags & CSUM_TCP) != 0) {
94                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
95                prs->l4r = FM_L4_PARSE_RESULT_TCP;
96        } else if ((csum_flags & CSUM_UDP) != 0) {
97                prs->l3r = FM_L3_PARSE_RESULT_IPV4;
98                prs->l4r = FM_L4_PARSE_RESULT_UDP;
99        } else if ((csum_flags & CSUM_TCP_IPV6) != 0) {
100                prs->l3r = FM_L3_PARSE_RESULT_IPV6;
101                prs->l4r = FM_L4_PARSE_RESULT_TCP;
102        } else if ((csum_flags & CSUM_UDP_IPV6) != 0) {
103                prs->l3r = FM_L3_PARSE_RESULT_IPV6;
104                prs->l4r = FM_L4_PARSE_RESULT_UDP;
105        } else {
106                BSD_ASSERT(0);
107        }
108
109        /* FIXME: VLAN */
110        prs->ip_off[0] = (u8)sizeof(struct ether_header);
111        prs->l4_off = (u8)(sizeof(struct ether_header) + sizeof(struct ip));
112
113        fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC;
114}
115
116static void
117fman_mac_txstart_locked(struct ifnet *ifp, struct fman_mac_softc *sc)
118{
119
120        FMAN_MAC_ASSERT_LOCKED(sc);
121
122        for (;;) {
123                struct fman_mac_sgt *sgt;
124                struct mbuf *m;
125                struct mbuf *n;
126                struct qm_fd fd;
127                struct dpaa_priv *priv;
128                struct qman_fq *egress_fq;
129                int queue = 0;
130                size_t i;
131                int err;
132
133                IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
134                if (m == NULL) {
135                        break;
136                }
137
138                sgt = uma_zalloc(fman_mac_sgt_zone, M_NOWAIT);
139                if (sgt == NULL) {
140                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
141                        m_freem(m);
142                        continue;
143                }
144
145                qm_fd_clear_fd(&fd);
146                qm_fd_set_sg(&fd, offsetof(struct fman_mac_sgt, sg), m->m_pkthdr.len);
147                fd.bpid = FSL_DPAA_BPID_INV;
148                fd.cmd |= cpu_to_be32(FM_FD_CMD_FCO);
149                qm_fd_addr_set64(&fd, (uintptr_t)sgt);
150                fman_mac_enable_tx_csum(m, &fd, &sgt->prs);
151
152repeat_with_collapsed_mbuf_chain:
153
154                i = 0;
155                n = m;
156
157                while (n != NULL && i < DPAA_SGT_MAX_ENTRIES) {
158                        int len = n->m_len;
159
160                        if (len > 0) {
161                                qm_sg_entry_set_len(&sgt->sg[i], len);
162                                sgt->sg[i].bpid = FSL_DPAA_BPID_INV;
163                                sgt->sg[i].offset = 0;
164                                qm_sg_entry_set64(&sgt->sg[i],
165                                    mtod(n, uintptr_t));
166                                ++i;
167                        }
168
169                        n = n->m_next;
170                }
171
172                if (n != NULL && i == DPAA_SGT_MAX_ENTRIES) {
173                        struct mbuf *c;
174
175                        c = m_collapse(m, M_NOWAIT, DPAA_SGT_MAX_ENTRIES);
176                        if (c == NULL) {
177                                if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
178                                m_freem(m);
179                                uma_zfree(fman_mac_sgt_zone, sgt);
180                                continue;
181                        }
182
183                        m = c;
184                        goto repeat_with_collapsed_mbuf_chain;
185                }
186
187                sgt->sg[i - 1].cfg |= cpu_to_be32(QM_SG_FIN);
188                sgt->m = m;
189                priv = netdev_priv(&sc->mac_dev.net_dev);
190                egress_fq = priv->egress_fqs[queue];
191                fd.cmd |= cpu_to_be32(qman_fq_fqid(priv->conf_fqs[queue]));
192
193                for (i = 0; i < DPAA_ENQUEUE_RETRIES; ++i) {
194                        err = qman_enqueue(egress_fq, &fd);
195                        if (err != -EBUSY) {
196                                break;
197                        }
198                }
199
200                if (unlikely(err < 0)) {
201                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
202                        m_freem(m);
203                        continue;
204                }
205        }
206}
207
208static void
209fman_mac_txstart(struct ifnet *ifp)
210{
211        struct fman_mac_softc *sc;
212
213        sc = ifp->if_softc;
214
215        FMAN_MAC_LOCK(sc);
216        fman_mac_txstart_locked(ifp, sc);
217        FMAN_MAC_UNLOCK(sc);
218}
219
220static void
221fman_mac_tick(void *arg)
222{
223        struct fman_mac_softc *sc;
224        struct ifnet *ifp;
225
226        sc = arg;
227        ifp = sc->ifp;
228
229        FMAN_MAC_ASSERT_LOCKED(sc);
230
231        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
232                return;
233        }
234
235        mii_tick(sc->mii_softc);
236        callout_reset(&sc->fman_mac_callout, hz, fman_mac_tick, sc);
237}
238
239static void
240fman_mac_set_multi(struct fman_mac_softc *sc)
241{
242        struct mac_device *mac_dev;
243
244        FMAN_MAC_ASSERT_LOCKED(sc);
245        mac_dev = &sc->mac_dev;
246        (*mac_dev->set_multi)(&mac_dev->net_dev, mac_dev);
247}
248
249static void
250fman_mac_set_promisc(struct fman_mac_softc *sc, int if_flags)
251{
252        struct mac_device *mac_dev;
253
254        FMAN_MAC_ASSERT_LOCKED(sc);
255        mac_dev = &sc->mac_dev;
256        (*mac_dev->set_promisc)(mac_dev->fman_mac,
257            (if_flags & IFF_PROMISC) != 0);
258}
259
260static int
261fman_mac_set_mtu(struct fman_mac_softc *sc, int mtu)
262{
263        struct ifnet *ifp;
264        int real_mtu;
265
266        ifp = sc->ifp;
267        real_mtu = mtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
268        if (real_mtu > fman_get_max_frm() ||
269            real_mtu < ETHER_MIN_LEN) {
270                return (EINVAL);
271        }
272
273        ifp->if_mtu = mtu;
274        return (0);
275}
276
277static void
278fman_mac_init_locked(struct fman_mac_softc *sc)
279{
280        struct ifnet *ifp;
281        int error;
282
283        FMAN_MAC_ASSERT_LOCKED(sc);
284
285        ifp = sc->ifp;
286        if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
287                return;
288        }
289
290        ifp->if_drv_flags |= IFF_DRV_RUNNING;
291
292        error = dpa_eth_priv_start(&sc->mac_dev.net_dev);
293        BSD_ASSERT(error == 0);
294
295        if (sc->mii_softc != NULL) {
296                mii_mediachg(sc->mii_softc);
297                callout_reset(&sc->fman_mac_callout, hz, fman_mac_tick, sc);
298        }
299
300        fman_mac_set_multi(sc);
301}
302
303static void
304fman_mac_stop_locked(struct fman_mac_softc *sc)
305{
306        struct ifnet *ifp;
307        int error;
308
309        FMAN_MAC_ASSERT_LOCKED(sc);
310
311        ifp = sc->ifp;
312        ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
313
314        error = dpa_eth_priv_stop(&sc->mac_dev.net_dev);
315        BSD_ASSERT(error == 0);
316}
317
318static void
319fman_mac_init(void *if_softc)
320{
321        struct fman_mac_softc *sc;
322
323        sc = if_softc;
324        FMAN_MAC_LOCK(sc);
325        fman_mac_init_locked(sc);
326        FMAN_MAC_UNLOCK(sc);
327}
328
329static int
330fman_mac_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
331{
332        struct fman_mac_softc *sc;
333        struct mii_data *mii;
334        struct ifreq *ifr;
335        int error;
336
337        sc = ifp->if_softc;
338        ifr = (struct ifreq *)data;
339
340        error = 0;
341        switch (cmd) {
342        case SIOCSIFFLAGS:
343                FMAN_MAC_LOCK(sc);
344                if (ifp->if_flags & IFF_UP) {
345                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
346                                if ((ifp->if_flags ^ sc->if_flags) &
347                                    IFF_PROMISC)
348                                        fman_mac_set_promisc(sc,
349                                            ifp->if_flags);
350                        } else {
351                                fman_mac_init_locked(sc);
352                        }
353                } else {
354                        if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
355                                fman_mac_stop_locked(sc);
356                        }
357                }
358                sc->if_flags = ifp->if_flags;
359                FMAN_MAC_UNLOCK(sc);
360                break;
361        case SIOCSIFMTU:
362                error = fman_mac_set_mtu(sc, ifr->ifr_mtu);
363                break;
364        case SIOCADDMULTI:
365        case SIOCDELMULTI:
366                if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
367                        FMAN_MAC_LOCK(sc);
368                        fman_mac_set_multi(sc);
369                        FMAN_MAC_UNLOCK(sc);
370                }
371                break;
372        case SIOCSIFMEDIA:
373        case SIOCGIFMEDIA:
374                mii = sc->mii_softc;
375
376                if (mii != NULL) {
377                        error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
378                } else {
379                        error = EINVAL;
380                }
381
382                break;
383        default:
384                error = ether_ioctl(ifp, cmd, data);
385                break;
386        }
387
388        return (error);
389}
390
391static int
392fman_mac_media_change(struct ifnet *ifp)
393{
394        struct fman_mac_softc *sc;
395        int error;
396
397        sc = ifp->if_softc;
398        FMAN_MAC_LOCK(sc);
399        error = mii_mediachg(sc->mii_softc);
400        FMAN_MAC_UNLOCK(sc);
401        return (error);
402}
403
404static void
405fman_mac_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
406{
407        struct fman_mac_softc *sc;
408        struct mii_data *mii;
409
410        sc = ifp->if_softc;
411        mii = sc->mii_softc;
412        FMAN_MAC_LOCK(sc);
413        mii_pollstat(mii);
414        ifmr->ifm_active = mii->mii_media_active;
415        ifmr->ifm_status = mii->mii_media_status;
416        FMAN_MAC_UNLOCK(sc);
417}
418
419int
420fman_mac_dev_attach(device_t dev)
421{
422        struct fman_mac_softc *sc;
423        struct ifnet *ifp;
424        struct phy_device *phy_dev;
425        int error;
426
427        sc = device_get_softc(dev);
428
429        mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
430            MTX_DEF);
431
432        callout_init_mtx(&sc->fman_mac_callout, &sc->mtx, 0);
433
434        /* Set up the Ethernet interface */
435        sc->ifp = ifp = if_alloc(IFT_ETHER);
436        if (sc->ifp == NULL) {
437                goto error;
438        }
439
440        snprintf(&sc->name[0], sizeof(sc->name), "fm%im",
441            device_get_unit(device_get_parent(dev)));
442
443        ifp->if_softc = sc;
444        if_initname(ifp, &sc->name[0], sc->mac_dev.data.mac_hw_id);
445        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
446        ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
447            IFCAP_VLAN_MTU | IFCAP_JUMBO_MTU;
448        ifp->if_capenable = ifp->if_capabilities;
449        ifp->if_hwassist = FMAN_MAC_CSUM;
450        ifp->if_start = fman_mac_txstart;
451        ifp->if_ioctl = fman_mac_ioctl;
452        ifp->if_init = fman_mac_init;
453        IFQ_SET_MAXLEN(&ifp->if_snd, 128);
454        ifp->if_snd.ifq_drv_maxlen = 128;
455        IFQ_SET_READY(&ifp->if_snd);
456        ifp->if_hdrlen = sizeof(struct ether_vlan_header);
457
458        /* Attach the MII driver if necessary */
459        phy_dev = sc->mac_dev.phy_dev;
460        if (phy_dev != NULL) {
461                error = mii_attach(dev, &sc->miibus, ifp,
462                    fman_mac_media_change, fman_mac_media_status,
463                    BMSR_DEFCAPMASK, phy_dev->mdio.addr, MII_OFFSET_ANY, 0);
464                if (error == 0) {
465                        sc->mii_softc = device_get_softc(sc->miibus);
466                }
467        }
468
469        sc->mac_dev.net_dev.ifp = ifp;
470
471        ether_ifattach(ifp, &sc->mac_dev.addr[0]);
472#if 0
473        fman_mac_set_mtu(sc, ETHERMTU_JUMBO);
474#endif
475
476        return (0);
477
478        if_free(ifp);
479error:
480        mtx_destroy(&sc->mtx);
481        return (ENXIO);
482}
483
484int
485fman_mac_dev_detach(device_t _dev)
486{
487        struct fman_mac_softc *sc = device_get_softc(_dev);
488
489        ether_ifdetach(sc->ifp);
490
491        FMAN_MAC_LOCK(sc);
492        fman_mac_stop_locked(sc);
493        FMAN_MAC_UNLOCK(sc);
494
495        if_free(sc->ifp);
496        mtx_destroy(&sc->mtx);
497
498        return (bus_generic_detach(_dev));
499}
500
501int
502fman_mac_miibus_read_reg(device_t dev, int phy, int reg)
503{
504        struct fman_mac_softc *sc;
505        struct phy_device *phy_dev;
506
507        sc = device_get_softc(dev);
508        phy_dev = sc->mac_dev.phy_dev;
509        BSD_ASSERT(phy == phy_dev->mdio.addr);
510        return (phy_read(phy_dev, reg));
511}
512
513int
514fman_mac_miibus_write_reg(device_t dev, int phy, int reg, int val)
515{
516        struct fman_mac_softc *sc;
517        struct phy_device *phy_dev;
518
519        sc = device_get_softc(dev);
520        phy_dev = sc->mac_dev.phy_dev;
521        BSD_ASSERT(phy == phy_dev->mdio.addr);
522        return (phy_write(phy_dev, reg, val));
523}
524
525void
526fman_mac_miibus_statchg(device_t dev)
527{
528        struct fman_mac_softc *sc;
529        struct mac_device *mac_dev;
530        struct mii_data *mii;
531        u16 speed;
532
533        sc = device_get_softc(dev);
534        mac_dev = &sc->mac_dev;
535        mii = sc->mii_softc;
536
537        FMAN_MAC_ASSERT_LOCKED(sc);
538
539        switch (IFM_SUBTYPE(mii->mii_media_active)) {
540        case IFM_10_T:
541        case IFM_10_2:
542        case IFM_10_5:
543        case IFM_10_STP:
544        case IFM_10_FL:
545                speed = SPEED_10;
546                break;
547        case IFM_100_TX:
548        case IFM_100_FX:
549        case IFM_100_T4:
550        case IFM_100_VG:
551        case IFM_100_T2:
552                speed = SPEED_100;
553                break;
554        case IFM_1000_SX:
555        case IFM_1000_LX:
556        case IFM_1000_CX:
557        case IFM_1000_T:
558                speed = SPEED_1000;
559                break;
560        case IFM_10G_LR:
561        case IFM_10G_SR:
562        case IFM_10G_CX4:
563        case IFM_10G_TWINAX:
564        case IFM_10G_TWINAX_LONG:
565        case IFM_10G_LRM:
566                speed = SPEED_10000;
567                break;
568        default:
569                speed = 0;
570                break;
571        }
572
573        (*mac_dev->adjust_link)(mac_dev, speed);
574}
575
576void dpaa_cleanup_tx_fd(struct ifnet *ifp, const struct qm_fd *fd)
577{
578        struct fman_mac_sgt *sgt;
579
580        BSD_ASSERT(qm_fd_get_format(fd) == qm_fd_sg);
581
582        sgt = (struct fman_mac_sgt *)qm_fd_addr(fd);
583
584        m_freem(sgt->m);
585        uma_zfree(fman_mac_sgt_zone, sgt);
586}
587
588struct dpaa_priv *
589dpaa_get_priv_of_ifp(struct ifnet *ifp)
590{
591        struct fman_mac_softc *sc;
592
593        sc = ifp->if_softc;
594        return (netdev_priv(&sc->mac_dev.net_dev));
595}
596
597int
598dpaa_get_qman_portal_irq_of_ifp(struct ifnet *ifp)
599{
600        struct fman_mac_softc *sc;
601
602        sc = ifp->if_softc;
603        return (qman_portal_get_irq(sc->mac_dev.portal));
604}
Note: See TracBrowser for help on using the repository browser.