initial commit, pull in sys/arch/armv7/omap
[bbb-pru.git] / if_cpsw.c
CommitLineData
cf3c20ae 1/* $OpenBSD: if_cpsw.c,v 1.34 2016/04/13 11:33:59 mpi Exp $ */
2/* $NetBSD: if_cpsw.c,v 1.3 2013/04/17 14:36:34 bouyer Exp $ */
3
4/*
5 * Copyright (c) 2013 Jonathan A. Kollasch
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/*-
31 * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 *
43 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
44 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
45 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
46 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
47 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
48 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
49 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
50 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
51 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
52 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 * SUCH DAMAGE.
54 */
55
56#include "bpfilter.h"
57
58#include <sys/param.h>
59#include <sys/systm.h>
60#include <sys/sockio.h>
61#include <sys/mbuf.h>
62#include <sys/pool.h>
63#include <sys/queue.h>
64#include <sys/kernel.h>
65#include <sys/device.h>
66#include <sys/timeout.h>
67#include <sys/socket.h>
68
69#include <machine/bus.h>
70
71#include <net/if.h>
72#include <net/if_media.h>
73
74#include <netinet/in.h>
75#include <netinet/if_ether.h>
76
77#if NBPFILTER > 0
78#include <net/bpf.h>
79#endif
80
81#include <dev/mii/mii.h>
82#include <dev/mii/miivar.h>
83
84#include <arch/armv7/armv7/armv7var.h>
85#include <arch/armv7/omap/sitara_cm.h>
86#include <arch/armv7/omap/if_cpswreg.h>
87
88#define CPSW_TXFRAGS 16
89
90#define OMAP2SCM_MAC_ID0_LO 0x630
91#define OMAP2SCM_MAC_ID0_HI 0x634
92
93#define CPSW_CPPI_RAM_SIZE (0x2000)
94#define CPSW_CPPI_RAM_TXDESCS_SIZE (CPSW_CPPI_RAM_SIZE/2)
95#define CPSW_CPPI_RAM_RXDESCS_SIZE \
96 (CPSW_CPPI_RAM_SIZE - CPSW_CPPI_RAM_TXDESCS_SIZE)
97#define CPSW_CPPI_RAM_TXDESCS_BASE (CPSW_CPPI_RAM_OFFSET + 0x0000)
98#define CPSW_CPPI_RAM_RXDESCS_BASE \
99 (CPSW_CPPI_RAM_OFFSET + CPSW_CPPI_RAM_TXDESCS_SIZE)
100
101#define CPSW_NTXDESCS (CPSW_CPPI_RAM_TXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd))
102#define CPSW_NRXDESCS (CPSW_CPPI_RAM_RXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd))
103
104#define CPSW_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN)
105
106#define TXDESC_NEXT(x) cpsw_txdesc_adjust((x), 1)
107#define TXDESC_PREV(x) cpsw_txdesc_adjust((x), -1)
108
109#define RXDESC_NEXT(x) cpsw_rxdesc_adjust((x), 1)
110#define RXDESC_PREV(x) cpsw_rxdesc_adjust((x), -1)
111
112struct cpsw_ring_data {
113 bus_dmamap_t tx_dm[CPSW_NTXDESCS];
114 struct mbuf *tx_mb[CPSW_NTXDESCS];
115 bus_dmamap_t rx_dm[CPSW_NRXDESCS];
116 struct mbuf *rx_mb[CPSW_NRXDESCS];
117};
118
119struct cpsw_softc {
120 struct device sc_dev;
121 bus_space_tag_t sc_bst;
122 bus_space_handle_t sc_bsh;
123 bus_dma_tag_t sc_bdt;
124 bus_space_handle_t sc_bsh_txdescs;
125 bus_space_handle_t sc_bsh_rxdescs;
126 bus_addr_t sc_txdescs_pa;
127 bus_addr_t sc_rxdescs_pa;
128
129 struct arpcom sc_ac;
130 struct mii_data sc_mii;
131
132 struct cpsw_ring_data *sc_rdp;
133 volatile u_int sc_txnext;
134 volatile u_int sc_txhead;
135 volatile u_int sc_rxhead;
136
137 void *sc_rxthih;
138 void *sc_rxih;
139 void *sc_txih;
140 void *sc_miscih;
141
142 void *sc_txpad;
143 bus_dmamap_t sc_txpad_dm;
144#define sc_txpad_pa sc_txpad_dm->dm_segs[0].ds_addr
145
146 volatile bool sc_txrun;
147 volatile bool sc_rxrun;
148 volatile bool sc_txeoq;
149 volatile bool sc_rxeoq;
150 struct timeout sc_tick;
151 int sc_active_port;
152};
153
154#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
155
156void cpsw_attach(struct device *, struct device *, void *);
157
158void cpsw_start(struct ifnet *);
159int cpsw_ioctl(struct ifnet *, u_long, caddr_t);
160void cpsw_watchdog(struct ifnet *);
161int cpsw_init(struct ifnet *);
162void cpsw_stop(struct ifnet *);
163
164int cpsw_mii_readreg(struct device *, int, int);
165void cpsw_mii_writereg(struct device *, int, int, int);
166void cpsw_mii_statchg(struct device *);
167
168void cpsw_tick(void *);
169
170int cpsw_new_rxbuf(struct cpsw_softc * const, const u_int);
171int cpsw_mediachange(struct ifnet *);
172void cpsw_mediastatus(struct ifnet *, struct ifmediareq *);
173
174int cpsw_rxthintr(void *);
175int cpsw_rxintr(void *);
176int cpsw_txintr(void *);
177int cpsw_miscintr(void *);
178
179void cpsw_get_mac_addr(struct cpsw_softc *);
180
181struct cfattach cpsw_ca = {
182 sizeof(struct cpsw_softc),
183 NULL,
184 cpsw_attach
185};
186
187struct cfdriver cpsw_cd = {
188 NULL,
189 "cpsw",
190 DV_IFNET
191};
192
193static inline u_int
194cpsw_txdesc_adjust(u_int x, int y)
195{
196 return (((x) + y) & (CPSW_NTXDESCS - 1));
197}
198
199static inline u_int
200cpsw_rxdesc_adjust(u_int x, int y)
201{
202 return (((x) + y) & (CPSW_NRXDESCS - 1));
203}
204
205static inline void
206cpsw_set_txdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n)
207{
208 const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0;
209 bus_space_write_4(sc->sc_bst, sc->sc_bsh_txdescs, o, n);
210}
211
212static inline void
213cpsw_set_rxdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n)
214{
215 const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0;
216 bus_space_write_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, n);
217}
218
219static inline void
220cpsw_get_txdesc(struct cpsw_softc * const sc, const u_int i,
221 struct cpsw_cpdma_bd * const bdp)
222{
223 const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
224 bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o,
225 (uint32_t *)bdp, 4);
226}
227
228static inline void
229cpsw_set_txdesc(struct cpsw_softc * const sc, const u_int i,
230 struct cpsw_cpdma_bd * const bdp)
231{
232 const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
233 bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o,
234 (uint32_t *)bdp, 4);
235}
236
237static inline void
238cpsw_get_rxdesc(struct cpsw_softc * const sc, const u_int i,
239 struct cpsw_cpdma_bd * const bdp)
240{
241 const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
242 bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o,
243 (uint32_t *)bdp, 4);
244}
245
246static inline void
247cpsw_set_rxdesc(struct cpsw_softc * const sc, const u_int i,
248 struct cpsw_cpdma_bd * const bdp)
249{
250 const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i;
251 bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o,
252 (uint32_t *)bdp, 4);
253}
254
255static inline bus_addr_t
256cpsw_txdesc_paddr(struct cpsw_softc * const sc, u_int x)
257{
258 KASSERT(x < CPSW_NTXDESCS);
259 return sc->sc_txdescs_pa + sizeof(struct cpsw_cpdma_bd) * x;
260}
261
262static inline bus_addr_t
263cpsw_rxdesc_paddr(struct cpsw_softc * const sc, u_int x)
264{
265 KASSERT(x < CPSW_NRXDESCS);
266 return sc->sc_rxdescs_pa + sizeof(struct cpsw_cpdma_bd) * x;
267}
268
269void
270cpsw_get_mac_addr(struct cpsw_softc *sc)
271{
272 struct arpcom *ac = &sc->sc_ac;
273 u_int32_t mac_lo = 0, mac_hi = 0;
274
275 sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_LO, &mac_lo);
276 sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_HI, &mac_hi);
277
278 if ((mac_lo == 0) && (mac_hi == 0))
279 printf("%s: invalid ethernet address\n", DEVNAME(sc));
280 else {
281 ac->ac_enaddr[0] = (mac_hi >> 0) & 0xff;
282 ac->ac_enaddr[1] = (mac_hi >> 8) & 0xff;
283 ac->ac_enaddr[2] = (mac_hi >> 16) & 0xff;
284 ac->ac_enaddr[3] = (mac_hi >> 24) & 0xff;
285 ac->ac_enaddr[4] = (mac_lo >> 0) & 0xff;
286 ac->ac_enaddr[5] = (mac_lo >> 8) & 0xff;
287 }
288}
289
290static void
291cpsw_mdio_init(struct cpsw_softc *sc)
292{
293 uint32_t alive, link;
294 u_int tries;
295
296 sc->sc_active_port = 0;
297
298 /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */
299 /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */
300 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOCONTROL,
301 (1<<30) | (1<<18) | 0xFF);
302
303 for(tries = 0; tries < 1000; tries++) {
304 alive = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOALIVE) & 3;
305 if (alive)
306 break;
307 delay(1);
308 }
309
310 if (alive == 0) {
311 printf("%s: no PHY is alive\n", DEVNAME(sc));
312 return;
313 }
314
315 link = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOLINK) & 3;
316
317 if (alive == 3) {
318 /* both ports are alive, prefer one with link */
319 if (link == 2)
320 sc->sc_active_port = 1;
321 } else if (alive == 2)
322 sc->sc_active_port = 1;
323
324 /* Select the port to monitor */
325 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOUSERPHYSEL0,
326 sc->sc_active_port);
327}
328
329void
330cpsw_attach(struct device *parent, struct device *self, void *aux)
331{
332 struct cpsw_softc *sc = (struct cpsw_softc *)self;
333 struct armv7_attach_args *aa = aux;
334 struct arpcom * const ac = &sc->sc_ac;
335 struct ifnet * const ifp = &ac->ac_if;
336 u_int32_t idver;
337 int error;
338 u_int i;
339
340 timeout_set(&sc->sc_tick, cpsw_tick, sc);
341
342 cpsw_get_mac_addr(sc);
343
344 sc->sc_rxthih = arm_intr_establish(aa->aa_dev->irq[0] +
345 CPSW_INTROFF_RXTH, IPL_NET, cpsw_rxthintr, sc, DEVNAME(sc));
346 sc->sc_rxih = arm_intr_establish(aa->aa_dev->irq[0] +
347 CPSW_INTROFF_RX, IPL_NET, cpsw_rxintr, sc, DEVNAME(sc));
348 sc->sc_txih = arm_intr_establish(aa->aa_dev->irq[0] +
349 CPSW_INTROFF_TX, IPL_NET, cpsw_txintr, sc, DEVNAME(sc));
350 sc->sc_miscih = arm_intr_establish(aa->aa_dev->irq[0] +
351 CPSW_INTROFF_MISC, IPL_NET, cpsw_miscintr, sc, DEVNAME(sc));
352
353 sc->sc_bst = aa->aa_iot;
354 sc->sc_bdt = aa->aa_dmat;
355
356 error = bus_space_map(sc->sc_bst, aa->aa_dev->mem[0].addr,
357 aa->aa_dev->mem[0].size, 0, &sc->sc_bsh);
358 if (error) {
359 printf("can't map registers: %d\n", error);
360 return;
361 }
362
363 sc->sc_txdescs_pa = aa->aa_dev->mem[0].addr +
364 CPSW_CPPI_RAM_TXDESCS_BASE;
365 error = bus_space_subregion(sc->sc_bst, sc->sc_bsh,
366 CPSW_CPPI_RAM_TXDESCS_BASE, CPSW_CPPI_RAM_TXDESCS_SIZE,
367 &sc->sc_bsh_txdescs);
368 if (error) {
369 printf("can't subregion tx ring SRAM: %d\n", error);
370 return;
371 }
372
373 sc->sc_rxdescs_pa = aa->aa_dev->mem[0].addr +
374 CPSW_CPPI_RAM_RXDESCS_BASE;
375 error = bus_space_subregion(sc->sc_bst, sc->sc_bsh,
376 CPSW_CPPI_RAM_RXDESCS_BASE, CPSW_CPPI_RAM_RXDESCS_SIZE,
377 &sc->sc_bsh_rxdescs);
378 if (error) {
379 printf("can't subregion rx ring SRAM: %d\n", error);
380 return;
381 }
382
383 sc->sc_rdp = malloc(sizeof(*sc->sc_rdp), M_TEMP, M_WAITOK);
384 KASSERT(sc->sc_rdp != NULL);
385
386 for (i = 0; i < CPSW_NTXDESCS; i++) {
387 if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES,
388 CPSW_TXFRAGS, MCLBYTES, 0, 0,
389 &sc->sc_rdp->tx_dm[i])) != 0) {
390 printf("unable to create tx DMA map: %d\n", error);
391 }
392 sc->sc_rdp->tx_mb[i] = NULL;
393 }
394
395 for (i = 0; i < CPSW_NRXDESCS; i++) {
396 if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES, 1,
397 MCLBYTES, 0, 0, &sc->sc_rdp->rx_dm[i])) != 0) {
398 printf("unable to create rx DMA map: %d\n", error);
399 }
400 sc->sc_rdp->rx_mb[i] = NULL;
401 }
402
403 sc->sc_txpad = dma_alloc(ETHER_MIN_LEN, PR_WAITOK | PR_ZERO);
404 KASSERT(sc->sc_txpad != NULL);
405 bus_dmamap_create(sc->sc_bdt, ETHER_MIN_LEN, 1, ETHER_MIN_LEN, 0,
406 BUS_DMA_WAITOK, &sc->sc_txpad_dm);
407 bus_dmamap_load(sc->sc_bdt, sc->sc_txpad_dm, sc->sc_txpad,
408 ETHER_MIN_LEN, NULL, BUS_DMA_WAITOK|BUS_DMA_WRITE);
409 bus_dmamap_sync(sc->sc_bdt, sc->sc_txpad_dm, 0, ETHER_MIN_LEN,
410 BUS_DMASYNC_PREWRITE);
411
412 idver = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_IDVER);
413 printf(": version %d.%d (%d), address %s\n",
414 CPSW_SS_IDVER_MAJ(idver), CPSW_SS_IDVER_MIN(idver),
415 CPSW_SS_IDVER_RTL(idver), ether_sprintf(ac->ac_enaddr));
416
417 ifp->if_softc = sc;
418 ifp->if_capabilities = 0;
419 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
420 ifp->if_start = cpsw_start;
421 ifp->if_ioctl = cpsw_ioctl;
422 ifp->if_watchdog = cpsw_watchdog;
423 IFQ_SET_MAXLEN(&ifp->if_snd, CPSW_NTXDESCS - 1);
424 memcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
425
426 cpsw_stop(ifp);
427
428 sc->sc_mii.mii_ifp = ifp;
429 sc->sc_mii.mii_readreg = cpsw_mii_readreg;
430 sc->sc_mii.mii_writereg = cpsw_mii_writereg;
431 sc->sc_mii.mii_statchg = cpsw_mii_statchg;
432
433 cpsw_mdio_init(sc);
434
435 ifmedia_init(&sc->sc_mii.mii_media, 0, cpsw_mediachange,
436 cpsw_mediastatus);
437 mii_attach(self, &sc->sc_mii, 0xffffffff,
438 MII_PHY_ANY, MII_OFFSET_ANY, 0);
439 if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
440 printf("no PHY found!\n");
441 ifmedia_add(&sc->sc_mii.mii_media,
442 IFM_ETHER|IFM_MANUAL, 0, NULL);
443 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL);
444 } else {
445 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
446 }
447
448 if_attach(ifp);
449 ether_ifattach(ifp);
450
451 return;
452}
453
454int
455cpsw_mediachange(struct ifnet *ifp)
456{
457 struct cpsw_softc *sc = ifp->if_softc;
458
459 if (LIST_FIRST(&sc->sc_mii.mii_phys))
460 mii_mediachg(&sc->sc_mii);
461
462 return (0);
463}
464
465void
466cpsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
467{
468 struct cpsw_softc *sc = ifp->if_softc;
469
470 if (LIST_FIRST(&sc->sc_mii.mii_phys)) {
471 mii_pollstat(&sc->sc_mii);
472 ifmr->ifm_active = sc->sc_mii.mii_media_active;
473 ifmr->ifm_status = sc->sc_mii.mii_media_status;
474 }
475}
476
477void
478cpsw_start(struct ifnet *ifp)
479{
480 struct cpsw_softc * const sc = ifp->if_softc;
481 struct cpsw_ring_data * const rdp = sc->sc_rdp;
482 struct cpsw_cpdma_bd bd;
483 struct mbuf *m;
484 bus_dmamap_t dm;
485 u_int eopi = ~0;
486 u_int seg;
487 u_int txfree;
488 int txstart = -1;
489 int error;
490 bool pad;
491 u_int mlen;
492
493 if (!ISSET(ifp->if_flags, IFF_RUNNING) ||
494 ifq_is_oactive(&ifp->if_snd) ||
495 IFQ_IS_EMPTY(&ifp->if_snd))
496 return;
497
498 if (sc->sc_txnext >= sc->sc_txhead)
499 txfree = CPSW_NTXDESCS - 1 + sc->sc_txhead - sc->sc_txnext;
500 else
501 txfree = sc->sc_txhead - sc->sc_txnext - 1;
502
503 for (;;) {
504 if (txfree <= CPSW_TXFRAGS) {
505 ifq_set_oactive(&ifp->if_snd);
506 break;
507 }
508
509 IFQ_DEQUEUE(&ifp->if_snd, m);
510 if (m == NULL)
511 break;
512
513 dm = rdp->tx_dm[sc->sc_txnext];
514 error = bus_dmamap_load_mbuf(sc->sc_bdt, dm, m, BUS_DMA_NOWAIT);
515 switch (error) {
516 case 0:
517 break;
518
519 case EFBIG: /* mbuf chain is too fragmented */
520 if (m_defrag(m, M_DONTWAIT) == 0 &&
521 bus_dmamap_load_mbuf(sc->sc_bdt, dm, m,
522 BUS_DMA_NOWAIT) == 0)
523 break;
524
525 /* FALLTHROUGH */
526 default:
527 m_freem(m);
528 ifp->if_oerrors++;
529 continue;
530 }
531
532 mlen = dm->dm_mapsize;
533 pad = mlen < CPSW_PAD_LEN;
534
535 KASSERT(rdp->tx_mb[sc->sc_txnext] == NULL);
536 rdp->tx_mb[sc->sc_txnext] = m;
537
538#if NBPFILTER > 0
539 if (ifp->if_bpf)
540 bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
541#endif
542
543 bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize,
544 BUS_DMASYNC_PREWRITE);
545
546 if (txstart == -1)
547 txstart = sc->sc_txnext;
548 eopi = sc->sc_txnext;
549 for (seg = 0; seg < dm->dm_nsegs; seg++) {
550 bd.next = cpsw_txdesc_paddr(sc,
551 TXDESC_NEXT(sc->sc_txnext));
552 bd.bufptr = dm->dm_segs[seg].ds_addr;
553 bd.bufoff = 0;
554 bd.buflen = dm->dm_segs[seg].ds_len;
555 bd.pktlen = 0;
556 bd.flags = 0;
557
558 if (seg == 0) {
559 bd.flags = CPDMA_BD_OWNER | CPDMA_BD_SOP;
560 bd.pktlen = MAX(mlen, CPSW_PAD_LEN);
561 }
562
563 if (seg == dm->dm_nsegs - 1 && !pad)
564 bd.flags |= CPDMA_BD_EOP;
565
566 cpsw_set_txdesc(sc, sc->sc_txnext, &bd);
567 txfree--;
568 eopi = sc->sc_txnext;
569 sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext);
570 }
571 if (pad) {
572 bd.next = cpsw_txdesc_paddr(sc,
573 TXDESC_NEXT(sc->sc_txnext));
574 bd.bufptr = sc->sc_txpad_pa;
575 bd.bufoff = 0;
576 bd.buflen = CPSW_PAD_LEN - mlen;
577 bd.pktlen = 0;
578 bd.flags = CPDMA_BD_EOP;
579
580 cpsw_set_txdesc(sc, sc->sc_txnext, &bd);
581 txfree--;
582 eopi = sc->sc_txnext;
583 sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext);
584 }
585 }
586
587 if (txstart >= 0) {
588 ifp->if_timer = 5;
589 /* terminate the new chain */
590 KASSERT(eopi == TXDESC_PREV(sc->sc_txnext));
591 cpsw_set_txdesc_next(sc, TXDESC_PREV(sc->sc_txnext), 0);
592
593 /* link the new chain on */
594 cpsw_set_txdesc_next(sc, TXDESC_PREV(txstart),
595 cpsw_txdesc_paddr(sc, txstart));
596 if (sc->sc_txeoq) {
597 /* kick the dma engine */
598 sc->sc_txeoq = false;
599 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0),
600 cpsw_txdesc_paddr(sc, txstart));
601 }
602 }
603}
604
605int
606cpsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
607{
608 struct cpsw_softc *sc = ifp->if_softc;
609 struct ifreq *ifr = (struct ifreq *)data;
610 int s = splnet();
611 int error = 0;
612
613 switch (cmd) {
614 case SIOCSIFADDR:
615 ifp->if_flags |= IFF_UP;
616 /* FALLTHROUGH */
617 case SIOCSIFFLAGS:
618 if (ifp->if_flags & IFF_UP) {
619 if (ifp->if_flags & IFF_RUNNING)
620 error = ENETRESET;
621 else
622 cpsw_init(ifp);
623 } else {
624 if (ifp->if_flags & IFF_RUNNING)
625 cpsw_stop(ifp);
626 }
627 break;
628 case SIOCSIFMEDIA:
629 ifr->ifr_media &= ~IFM_ETH_FMASK;
630 /* FALLTHROUGH */
631 case SIOCGIFMEDIA:
632 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
633 break;
634 default:
635 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
636 break;
637 }
638 if (error == ENETRESET) {
639 if (ifp->if_flags & IFF_RUNNING)
640 cpsw_init(ifp);
641 error = 0;
642 }
643
644 splx(s);
645
646 return error;
647}
648
649void
650cpsw_watchdog(struct ifnet *ifp)
651{
652 printf("%s: device timeout\n", ifp->if_xname);
653
654 ifp->if_oerrors++;
655 cpsw_init(ifp);
656 cpsw_start(ifp);
657}
658
659static int
660cpsw_mii_wait(struct cpsw_softc * const sc, int reg)
661{
662 u_int tries;
663
664 for(tries = 0; tries < 1000; tries++) {
665 if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg) & (1U << 31)) == 0)
666 return 0;
667 delay(1);
668 }
669 return ETIMEDOUT;
670}
671
672int
673cpsw_mii_readreg(struct device *dev, int phy, int reg)
674{
675 struct cpsw_softc * const sc = (struct cpsw_softc *)dev;
676 uint32_t v;
677
678 if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
679 return 0;
680
681 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0, (1U << 31) |
682 ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16));
683
684 if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
685 return 0;
686
687 v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0);
688 if (v & (1 << 29))
689 return v & 0xffff;
690 else
691 return 0;
692}
693
694void
695cpsw_mii_writereg(struct device *dev, int phy, int reg, int val)
696{
697 struct cpsw_softc * const sc = (struct cpsw_softc *)dev;
698 uint32_t v;
699
700 KASSERT((val & 0xffff0000UL) == 0);
701
702 if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
703 goto out;
704
705 bus_space_write_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0, (1U << 31) | (1 << 30) |
706 ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16) | val);
707
708 if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0)
709 goto out;
710
711 v = bus_space_read_4(sc->sc_bst, sc->sc_bsh, MDIOUSERACCESS0);
712 if ((v & (1 << 29)) == 0)
713out:
714 printf("%s error\n", __func__);
715
716}
717
718void
719cpsw_mii_statchg(struct device *self)
720{
721 return;
722}
723
724int
725cpsw_new_rxbuf(struct cpsw_softc * const sc, const u_int i)
726{
727 struct cpsw_ring_data * const rdp = sc->sc_rdp;
728 const u_int h = RXDESC_PREV(i);
729 struct cpsw_cpdma_bd bd;
730 struct mbuf *m;
731 int error = ENOBUFS;
732
733 MGETHDR(m, M_DONTWAIT, MT_DATA);
734 if (m == NULL) {
735 goto reuse;
736 }
737
738 MCLGET(m, M_DONTWAIT);
739 if ((m->m_flags & M_EXT) == 0) {
740 m_freem(m);
741 goto reuse;
742 }
743
744 /* We have a new buffer, prepare it for the ring. */
745
746 if (rdp->rx_mb[i] != NULL)
747 bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]);
748
749 m->m_len = m->m_pkthdr.len = MCLBYTES;
750
751 rdp->rx_mb[i] = m;
752
753 error = bus_dmamap_load_mbuf(sc->sc_bdt, rdp->rx_dm[i], rdp->rx_mb[i],
754 BUS_DMA_READ|BUS_DMA_NOWAIT);
755 if (error) {
756 printf("can't load rx DMA map %d: %d\n", i, error);
757 }
758
759 bus_dmamap_sync(sc->sc_bdt, rdp->rx_dm[i],
760 0, rdp->rx_dm[i]->dm_mapsize, BUS_DMASYNC_PREREAD);
761
762 error = 0;
763
764reuse:
765 /* (re-)setup the descriptor */
766 bd.next = 0;
767 bd.bufptr = rdp->rx_dm[i]->dm_segs[0].ds_addr;
768 bd.bufoff = 0;
769 bd.buflen = MIN(0x7ff, rdp->rx_dm[i]->dm_segs[0].ds_len);
770 bd.pktlen = 0;
771 bd.flags = CPDMA_BD_OWNER;
772
773 cpsw_set_rxdesc(sc, i, &bd);
774 /* and link onto ring */
775 cpsw_set_rxdesc_next(sc, h, cpsw_rxdesc_paddr(sc, i));
776
777 return error;
778}
779
780int
781cpsw_init(struct ifnet *ifp)
782{
783 struct cpsw_softc * const sc = ifp->if_softc;
784 struct arpcom *ac = &sc->sc_ac;
785 struct mii_data * const mii = &sc->sc_mii;
786 int i;
787
788 cpsw_stop(ifp);
789
790 sc->sc_txnext = 0;
791 sc->sc_txhead = 0;
792
793 /* Reset wrapper */
794 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET, 1);
795 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET) & 1);
796
797 /* Reset SS */
798 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET, 1);
799 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET) & 1);
800
801 /* Clear table (30) and enable ALE(31) and set passthrough (4) */
802 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_ALE_CONTROL, (3 << 30) | 0x10);
803
804 /* Reset and init Sliver port 1 and 2 */
805 for (i = 0; i < 2; i++) {
806 /* Reset */
807 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i), 1);
808 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i)) & 1);
809 /* Set Slave Mapping */
810 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_RX_PRI_MAP(i), 0x76543210);
811 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P_TX_PRI_MAP(i+1), 0x33221100);
812 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_RX_MAXLEN(i), 0x5f2);
813 /* Set MAC Address */
814 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P_SA_HI(i+1),
815 ac->ac_enaddr[0] | (ac->ac_enaddr[1] << 8) |
816 (ac->ac_enaddr[2] << 16) | (ac->ac_enaddr[3] << 24));
817 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P_SA_LO(i+1),
818 ac->ac_enaddr[4] | (ac->ac_enaddr[5] << 8));
819
820 /* Set MACCONTROL for ports 0,1: FULLDUPLEX(0), GMII_EN(5),
821 IFCTL_A(15), IFCTL_B(16) FIXME */
822 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_MACCONTROL(i),
823 1 | (1<<5) | (1<<15) | (1<<16));
824
825 /* Set ALE port to forwarding(3) on the active port */
826 if (i == sc->sc_active_port)
827 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_ALE_PORTCTL(i+1), 3);
828 }
829
830 /* Set Host Port Mapping */
831 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210);
832 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0);
833
834 /* Set ALE port to forwarding(3) */
835 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_ALE_PORTCTL(0), 3);
836
837 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_PTYPE, 0);
838 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_STAT_PORT_EN, 7);
839
840 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET, 1);
841 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET) & 1);
842
843 for (i = 0; i < 8; i++) {
844 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(i), 0);
845 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(i), 0);
846 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(i), 0);
847 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CP(i), 0);
848 }
849
850 bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_txdescs, 0, 0,
851 CPSW_CPPI_RAM_TXDESCS_SIZE/4);
852
853 sc->sc_txhead = 0;
854 sc->sc_txnext = 0;
855
856 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_FREEBUFFER(0), 0);
857
858 bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, 0, 0,
859 CPSW_CPPI_RAM_RXDESCS_SIZE/4);
860
861 /* Initialize RX Buffer Descriptors */
862 cpsw_set_rxdesc_next(sc, RXDESC_PREV(0), 0);
863 for (i = 0; i < CPSW_NRXDESCS; i++) {
864 cpsw_new_rxbuf(sc, i);
865 }
866 sc->sc_rxhead = 0;
867
868 /* align layer 3 header to 32-bit */
869 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_BUFFER_OFFSET, ETHER_ALIGN);
870
871 /* Clear all interrupt Masks */
872 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF);
873 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF);
874
875 /* Enable TX & RX DMA */
876 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CONTROL, 1);
877 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CONTROL, 1);
878
879 /* Enable interrupt pacing for C0 RX/TX (IMAX set to max intr/ms allowed) */
880#define CPSW_VBUSP_CLK_MHZ 2400 /* hardcoded for BBB */
881 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_RX_IMAX(0), 2);
882 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_TX_IMAX(0), 2);
883 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_INT_CONTROL, 3 << 16 | CPSW_VBUSP_CLK_MHZ/4);
884
885 /* Enable TX and RX interrupt receive for core 0 */
886 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_TX_EN(0), 1);
887 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_RX_EN(0), 1);
888 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_MISC_EN(0), 0x1F);
889
890 /* Enable host Error Interrupt */
891 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTMASK_SET, 2);
892
893 /* Enable interrupts for TX and RX Channel 0 */
894 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_INTMASK_SET, 1);
895 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_INTMASK_SET, 1);
896
897 /* Ack stalled irqs */
898 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH);
899 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX);
900 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX);
901 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC);
902
903 cpsw_mdio_init(sc);
904
905 mii_mediachg(mii);
906
907 /* Write channel 0 RX HDP */
908 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(0), cpsw_rxdesc_paddr(sc, 0));
909 sc->sc_rxrun = true;
910 sc->sc_rxeoq = false;
911
912 sc->sc_txrun = true;
913 sc->sc_txeoq = true;
914
915 ifp->if_flags |= IFF_RUNNING;
916 ifq_clr_oactive(&ifp->if_snd);
917
918 timeout_add_sec(&sc->sc_tick, 1);
919
920 return 0;
921}
922
923void
924cpsw_stop(struct ifnet *ifp)
925{
926 struct cpsw_softc * const sc = ifp->if_softc;
927 struct cpsw_ring_data * const rdp = sc->sc_rdp;
928 u_int i;
929
930#if 0
931 /* XXX find where disable comes from */
932 printf("%s: ifp %p disable %d\n", __func__, ifp, disable);
933#endif
934 if ((ifp->if_flags & IFF_RUNNING) == 0)
935 return;
936
937 timeout_del(&sc->sc_tick);
938
939 mii_down(&sc->sc_mii);
940
941 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_INTMASK_CLEAR, 1);
942 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_INTMASK_CLEAR, 1);
943 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_TX_EN(0), 0x0);
944 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_RX_EN(0), 0x0);
945 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_MISC_EN(0), 0x1F);
946
947 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_TEARDOWN, 0);
948 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_TEARDOWN, 0);
949 i = 0;
950 while ((sc->sc_txrun || sc->sc_rxrun) && i < 10000) {
951 delay(10);
952 if ((sc->sc_txrun == true) && cpsw_txintr(sc) == 0)
953 sc->sc_txrun = false;
954 if ((sc->sc_rxrun == true) && cpsw_rxintr(sc) == 0)
955 sc->sc_rxrun = false;
956 i++;
957 }
958 /* printf("%s toredown complete in %u\n", __func__, i); */
959
960 /* Reset wrapper */
961 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET, 1);
962 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_SOFT_RESET) & 1);
963
964 /* Reset SS */
965 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET, 1);
966 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SS_SOFT_RESET) & 1);
967
968 for (i = 0; i < 2; i++) {
969 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i), 1);
970 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_SL_SOFT_RESET(i)) & 1);
971 }
972
973 /* Reset CPDMA */
974 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET, 1);
975 while(bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_SOFT_RESET) & 1);
976
977 /* Release any queued transmit buffers. */
978 for (i = 0; i < CPSW_NTXDESCS; i++) {
979 bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[i]);
980 m_freem(rdp->tx_mb[i]);
981 rdp->tx_mb[i] = NULL;
982 }
983
984 ifp->if_flags &= ~IFF_RUNNING;
985 ifp->if_timer = 0;
986 ifq_clr_oactive(&ifp->if_snd);
987
988 /* XXX Not sure what this is doing calling disable here
989 where is disable set?
990 */
991#if 0
992 if (!disable)
993 return;
994#endif
995
996 for (i = 0; i < CPSW_NRXDESCS; i++) {
997 bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]);
998 m_freem(rdp->rx_mb[i]);
999 rdp->rx_mb[i] = NULL;
1000 }
1001}
1002
1003int
1004cpsw_rxthintr(void *arg)
1005{
1006 struct cpsw_softc * const sc = arg;
1007
1008 /* this won't deassert the interrupt though */
1009 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH);
1010
1011 return 1;
1012}
1013
1014int
1015cpsw_rxintr(void *arg)
1016{
1017 struct cpsw_softc * const sc = arg;
1018 struct ifnet * const ifp = &sc->sc_ac.ac_if;
1019 struct cpsw_ring_data * const rdp = sc->sc_rdp;
1020 struct cpsw_cpdma_bd bd;
1021 bus_dmamap_t dm;
1022 struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1023 struct mbuf *m;
1024 u_int i;
1025 u_int len, off;
1026
1027 sc->sc_rxeoq = false;
1028
1029 for (;;) {
1030 KASSERT(sc->sc_rxhead < CPSW_NRXDESCS);
1031
1032 i = sc->sc_rxhead;
1033 dm = rdp->rx_dm[i];
1034 m = rdp->rx_mb[i];
1035
1036 KASSERT(dm != NULL);
1037 KASSERT(m != NULL);
1038
1039 cpsw_get_rxdesc(sc, i, &bd);
1040
1041 if (bd.flags & CPDMA_BD_OWNER)
1042 break;
1043
1044 if (bd.flags & CPDMA_BD_TDOWNCMPLT) {
1045 sc->sc_rxrun = false;
1046 goto done;
1047 }
1048
1049 bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize,
1050 BUS_DMASYNC_POSTREAD);
1051
1052 if (cpsw_new_rxbuf(sc, i) != 0) {
1053 /* drop current packet, reuse buffer for new */
1054 ifp->if_ierrors++;
1055 goto next;
1056 }
1057
1058 if ((bd.flags & (CPDMA_BD_SOP|CPDMA_BD_EOP)) !=
1059 (CPDMA_BD_SOP|CPDMA_BD_EOP)) {
1060 if (bd.flags & CPDMA_BD_SOP) {
1061 printf("cpsw: rx packet too large\n");
1062 ifp->if_ierrors++;
1063 }
1064 m_freem(m);
1065 goto next;
1066 }
1067
1068 off = bd.bufoff;
1069 len = bd.pktlen;
1070
1071 if (bd.flags & CPDMA_BD_PASSCRC)
1072 len -= ETHER_CRC_LEN;
1073
1074 m->m_pkthdr.len = m->m_len = len;
1075 m->m_data += off;
1076
1077 ml_enqueue(&ml, m);
1078
1079next:
1080 sc->sc_rxhead = RXDESC_NEXT(sc->sc_rxhead);
1081 if (bd.flags & CPDMA_BD_EOQ) {
1082 sc->sc_rxeoq = true;
1083 sc->sc_rxrun = false;
1084 }
1085 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CP(0),
1086 cpsw_rxdesc_paddr(sc, i));
1087 }
1088
1089 if (sc->sc_rxeoq) {
1090 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(0),
1091 cpsw_rxdesc_paddr(sc, sc->sc_rxhead));
1092 sc->sc_rxrun = true;
1093 sc->sc_rxeoq = false;
1094 }
1095
1096 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR,
1097 CPSW_INTROFF_RX);
1098
1099done:
1100 if_input(ifp, &ml);
1101
1102 return 1;
1103}
1104
1105void
1106cpsw_tick(void *arg)
1107{
1108 struct cpsw_softc *sc = arg;
1109 int s;
1110
1111 s = splnet();
1112 mii_tick(&sc->sc_mii);
1113 splx(s);
1114
1115 timeout_add_sec(&sc->sc_tick, 1);
1116}
1117
1118int
1119cpsw_txintr(void *arg)
1120{
1121 struct cpsw_softc * const sc = arg;
1122 struct ifnet * const ifp = &sc->sc_ac.ac_if;
1123 struct cpsw_ring_data * const rdp = sc->sc_rdp;
1124 struct cpsw_cpdma_bd bd;
1125 bool handled = false;
1126 uint32_t tx0_cp;
1127 u_int cpi;
1128
1129 KASSERT(sc->sc_txrun);
1130
1131 tx0_cp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0));
1132
1133 if (tx0_cp == 0xfffffffc) {
1134 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0), 0xfffffffc);
1135 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0), 0);
1136 sc->sc_txrun = false;
1137 return 0;
1138 }
1139
1140 for (;;) {
1141 tx0_cp = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0));
1142 cpi = (tx0_cp - sc->sc_txdescs_pa) /
1143 sizeof(struct cpsw_cpdma_bd);
1144 KASSERT(sc->sc_txhead < CPSW_NTXDESCS);
1145
1146 cpsw_get_txdesc(sc, sc->sc_txhead, &bd);
1147
1148 if (bd.buflen == 0) {
1149 /* Debugger(); */
1150 }
1151
1152 if ((bd.flags & CPDMA_BD_SOP) == 0)
1153 goto next;
1154
1155 if (bd.flags & CPDMA_BD_OWNER) {
1156 printf("pwned %x %x %x\n", cpi, sc->sc_txhead,
1157 sc->sc_txnext);
1158 break;
1159 }
1160
1161 if (bd.flags & CPDMA_BD_TDOWNCMPLT) {
1162 sc->sc_txrun = false;
1163 return 1;
1164 }
1165
1166 bus_dmamap_sync(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead],
1167 0, rdp->tx_dm[sc->sc_txhead]->dm_mapsize,
1168 BUS_DMASYNC_POSTWRITE);
1169 bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead]);
1170
1171 m_freem(rdp->tx_mb[sc->sc_txhead]);
1172 rdp->tx_mb[sc->sc_txhead] = NULL;
1173
1174 ifp->if_opackets++;
1175
1176 handled = true;
1177
1178 ifq_clr_oactive(&ifp->if_snd);
1179
1180next:
1181 if ((bd.flags & (CPDMA_BD_EOP|CPDMA_BD_EOQ)) ==
1182 (CPDMA_BD_EOP|CPDMA_BD_EOQ))
1183 sc->sc_txeoq = true;
1184
1185 if (sc->sc_txhead == cpi) {
1186 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0),
1187 cpsw_txdesc_paddr(sc, cpi));
1188 sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead);
1189 break;
1190 }
1191 sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead);
1192 if (sc->sc_txeoq == true)
1193 break;
1194 }
1195
1196 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX);
1197
1198 if ((sc->sc_txnext != sc->sc_txhead) && sc->sc_txeoq) {
1199 if (bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0)) == 0) {
1200 sc->sc_txeoq = false;
1201 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0),
1202 cpsw_txdesc_paddr(sc, sc->sc_txhead));
1203 }
1204 }
1205
1206 if (handled && sc->sc_txnext == sc->sc_txhead)
1207 ifp->if_timer = 0;
1208
1209 if (handled)
1210 cpsw_start(ifp);
1211
1212 return handled;
1213}
1214
1215int
1216cpsw_miscintr(void *arg)
1217{
1218 struct cpsw_softc * const sc = arg;
1219 uint32_t miscstat;
1220 uint32_t dmastat;
1221 uint32_t stat;
1222
1223 miscstat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_WR_C_MISC_STAT(0));
1224 printf("%s %x FIRE\n", __func__, miscstat);
1225
1226 if (miscstat & CPSW_MISC_HOST_PEND) {
1227 /* Host Error */
1228 dmastat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTSTAT_MASKED);
1229 printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat);
1230
1231 printf("rxhead %02x\n", sc->sc_rxhead);
1232
1233 stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMASTATUS);
1234 printf("CPSW_CPDMA_DMASTATUS %x\n", stat);
1235 stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_HDP(0));
1236 printf("CPSW_CPDMA_TX0_HDP %x\n", stat);
1237 stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_TX_CP(0));
1238 printf("CPSW_CPDMA_TX0_CP %x\n", stat);
1239 stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_HDP(0));
1240 printf("CPSW_CPDMA_RX0_HDP %x\n", stat);
1241 stat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_RX_CP(0));
1242 printf("CPSW_CPDMA_RX0_CP %x\n", stat);
1243
1244 /* Debugger(); */
1245
1246 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTMASK_CLEAR, dmastat);
1247 dmastat = bus_space_read_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_DMA_INTSTAT_MASKED);
1248 printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat);
1249 }
1250
1251 bus_space_write_4(sc->sc_bst, sc->sc_bsh, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC);
1252
1253 return 1;
1254}