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

55-freebsd-126-freebsd-12
Last change on this file since 03d1426 was 03d1426, checked in by Sebastian Huber <sebastian.huber@…>, on 05/24/17 at 11:15:14

dpaa: No error if MII attach failed

  • Property mode set to 100644
File size: 12.9 KB
RevLine 
[28ee86a]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 {
[cd089b9]57        char priv[DPAA_TX_PRIV_DATA_SIZE];
[28ee86a]58        struct fman_prs_result prs;
[cd089b9]59        struct qm_sg_entry sg[DPAA_SGT_MAX_ENTRIES];
[28ee86a]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;
[cd089b9]111                struct dpaa_priv *priv;
[28ee86a]112                struct qman_fq *egress_fq;
113                int queue = 0;
114                size_t i;
[cd089b9]115                int err;
[28ee86a]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) {
[cd089b9]124                        if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
[28ee86a]125                        m_freem(m);
126                        continue;
127                }
128
[cd089b9]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);
[28ee86a]134                fman_mac_enable_tx_csum(m, &fd, &sgt->prs);
135
136repeat_with_collapsed_mbuf_chain:
137
138                i = 0;
139                n = m;
140
[cd089b9]141                while (n != NULL && i < DPAA_SGT_MAX_ENTRIES) {
[28ee86a]142                        int len = n->m_len;
143
144                        if (len > 0) {
[cd089b9]145                                qm_sg_entry_set_len(&sgt->sg[i], len);
146                                sgt->sg[i].bpid = FSL_DPAA_BPID_INV;
[28ee86a]147                                sgt->sg[i].offset = 0;
[cd089b9]148                                qm_sg_entry_set64(&sgt->sg[i],
149                                    mtod(n, uintptr_t));
[28ee86a]150                                ++i;
151                        }
152
153                        n = n->m_next;
154                }
155
[cd089b9]156                if (n != NULL && i == DPAA_SGT_MAX_ENTRIES) {
[28ee86a]157                        struct mbuf *c;
158
[cd089b9]159                        c = m_collapse(m, M_NOWAIT, DPAA_SGT_MAX_ENTRIES);
[28ee86a]160                        if (c == NULL) {
[cd089b9]161                                if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
[28ee86a]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
[cd089b9]171                sgt->sg[i - 1].cfg |= cpu_to_be32(QM_SG_FIN);
[28ee86a]172                sgt->m = m;
173                priv = netdev_priv(&sc->mac_dev.net_dev);
174                egress_fq = priv->egress_fqs[queue];
[cd089b9]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                }
[28ee86a]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
[cd089b9]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        }
[28ee86a]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;
[cd089b9]359
360                if (mii != NULL) {
361                        error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
362                } else {
363                        error = EINVAL;
364                }
365
[28ee86a]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;
[cd089b9]408        struct phy_device *phy_dev;
[28ee86a]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;
[ed254d58]436        ifp->if_capabilities = IFCAP_HWCSUM | IFCAP_HWCSUM_IPV6 |
[28ee86a]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 */
[cd089b9]449        phy_dev = sc->mac_dev.phy_dev;
450        if (phy_dev != NULL) {
[28ee86a]451                error = mii_attach(dev, &sc->miibus, ifp,
452                    fman_mac_media_change, fman_mac_media_status,
[cd089b9]453                    BMSR_DEFCAPMASK, phy_dev->mdio.addr, MII_OFFSET_ANY, 0);
[03d1426]454                if (error == 0) {
455                        sc->mii_softc = device_get_softc(sc->miibus);
[28ee86a]456                }
457        }
458
459        sc->mac_dev.net_dev.ifp = ifp;
460
461        ether_ifattach(ifp, &sc->mac_dev.addr[0]);
462#if 0
463        fman_mac_set_mtu(sc, ETHERMTU_JUMBO);
464#endif
465
466        return (0);
467
468        if_free(ifp);
469error_1:
470        uma_zdestroy(sc->sgt_zone);
471error_0:
472        mtx_destroy(&sc->mtx);
473        return (ENXIO);
474}
475
476int
477fman_mac_dev_detach(device_t _dev)
478{
479        struct fman_mac_softc *sc = device_get_softc(_dev);
480
481        ether_ifdetach(sc->ifp);
482
483        FMAN_MAC_LOCK(sc);
484        fman_mac_stop_locked(sc);
485        FMAN_MAC_UNLOCK(sc);
486
487        if_free(sc->ifp);
488        uma_zdestroy(sc->sgt_zone);
489        mtx_destroy(&sc->mtx);
490
491        return (bus_generic_detach(_dev));
492}
493
494int
495fman_mac_miibus_read_reg(device_t dev, int phy, int reg)
496{
497        struct fman_mac_softc *sc;
[cd089b9]498        struct phy_device *phy_dev;
[28ee86a]499
500        sc = device_get_softc(dev);
[cd089b9]501        phy_dev = sc->mac_dev.phy_dev;
502        BSD_ASSERT(phy == phy_dev->mdio.addr);
503        return (phy_read(phy_dev, reg));
[28ee86a]504}
505
506int
507fman_mac_miibus_write_reg(device_t dev, int phy, int reg, int val)
508{
509        struct fman_mac_softc *sc;
[cd089b9]510        struct phy_device *phy_dev;
[28ee86a]511
512        sc = device_get_softc(dev);
[cd089b9]513        phy_dev = sc->mac_dev.phy_dev;
514        BSD_ASSERT(phy == phy_dev->mdio.addr);
515        return (phy_write(phy_dev, reg, val));
[28ee86a]516}
517
518void
519fman_mac_miibus_statchg(device_t dev)
520{
521        struct fman_mac_softc *sc;
522        struct mac_device *mac_dev;
523        struct mii_data *mii;
524        u16 speed;
525
526        sc = device_get_softc(dev);
527        mac_dev = &sc->mac_dev;
528        mii = sc->mii_softc;
529
530        FMAN_MAC_ASSERT_LOCKED(sc);
531
532        switch (IFM_SUBTYPE(mii->mii_media_active)) {
533        case IFM_10_T:
534        case IFM_10_2:
535        case IFM_10_5:
536        case IFM_10_STP:
537        case IFM_10_FL:
538                speed = SPEED_10;
539                break;
540        case IFM_100_TX:
541        case IFM_100_FX:
542        case IFM_100_T4:
543        case IFM_100_VG:
544        case IFM_100_T2:
545                speed = SPEED_100;
546                break;
547        case IFM_1000_SX:
548        case IFM_1000_LX:
549        case IFM_1000_CX:
550        case IFM_1000_T:
551                speed = SPEED_1000;
552                break;
553        case IFM_10G_LR:
554        case IFM_10G_SR:
555        case IFM_10G_CX4:
556        case IFM_10G_TWINAX:
557        case IFM_10G_TWINAX_LONG:
558        case IFM_10G_LRM:
559                speed = SPEED_10000;
560                break;
561        default:
562                speed = 0;
563                break;
564        }
565
566        (*mac_dev->adjust_link)(mac_dev, speed);
567}
568
[cd089b9]569void dpaa_cleanup_tx_fd(struct ifnet *ifp, const struct qm_fd *fd)
[28ee86a]570{
571        struct fman_mac_softc *sc;
572        struct fman_mac_sgt *sgt;
573
[cd089b9]574        BSD_ASSERT(qm_fd_get_format(fd) == qm_fd_sg);
[28ee86a]575
576        sc = ifp->if_softc;
577        sgt = (struct fman_mac_sgt *)qm_fd_addr(fd);
578
579        m_freem(sgt->m);
580        uma_zfree(sc->sgt_zone, sgt);
581}
Note: See TracBrowser for help on using the repository browser.