RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / et / sys / et_cfe.c
blob44eb631d02de16fb1013f3cbf8aca3cd24a50833
1 /*
2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
6 *
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * $Id: et_cfe.c 341899 2012-06-29 04:06:38Z $
22 #include <et_cfg.h>
23 #include "lib_types.h"
24 #include "lib_malloc.h"
25 #include "lib_string.h"
26 #include "lib_printf.h"
28 #include "cfe_iocb.h"
29 #include "cfe_device.h"
30 #include "cfe_ioctl.h"
31 #include "cfe_console.h"
32 #include "cfe_timer.h"
33 #include "cfe_error.h"
34 #include "ui_command.h"
36 #include <typedefs.h>
37 #include <osl.h>
38 #include <epivers.h>
39 #include <bcmendian.h>
40 #include <proto/ethernet.h>
41 #include <bcmdevs.h>
42 #include <bcmenetmib.h>
43 #include <bcmenetrxh.h>
44 #include <bcmutils.h>
45 #include <et_dbg.h>
46 #include <hndsoc.h>
47 #include <bcmgmacrxh.h>
48 #include <etc.h>
50 typedef struct et_info {
51 etc_info_t *etc; /* pointer to common os-independent data */
52 cfe_devctx_t *ctx; /* backpoint to device */
53 int64_t timer; /* one second watchdog timer */
54 osl_t *osh;
55 struct et_info *next; /* pointer to next et_info_t in chain */
56 } et_info_t;
58 static et_info_t *et_list = NULL;
60 void et_init(et_info_t *et, uint options);
61 void et_reset(et_info_t *et);
62 void et_link_up(et_info_t *et);
63 void et_link_down(et_info_t *et);
64 int et_up(et_info_t *et);
65 int et_down(et_info_t *et, int reset);
66 void et_dump(et_info_t *et, struct bcmstrbuf *b);
67 void et_addcmd(void);
68 void et_intrson(et_info_t *et);
70 void
71 et_init(et_info_t *et, uint options)
73 ET_TRACE(("et%d: et_init\n", et->etc->unit));
75 etc_reset(et->etc);
76 etc_init(et->etc, options);
79 void
80 et_reset(et_info_t *et)
82 ET_TRACE(("et%d: et_reset\n", et->etc->unit));
84 etc_reset(et->etc);
87 void
88 et_link_up(et_info_t *et)
90 ET_ERROR(("et%d: link up (%d%s)\n",
91 et->etc->unit, et->etc->speed, (et->etc->duplex? "FD" : "HD")));
94 void
95 et_link_down(et_info_t *et)
97 ET_ERROR(("et%d: link down\n", et->etc->unit));
101 et_up(et_info_t *et)
103 if (et->etc->up)
104 return 0;
106 ET_TRACE(("et%d: et_up\n", et->etc->unit));
108 etc_up(et->etc);
110 /* schedule one second watchdog timer */
111 TIMER_SET(et->timer, CFE_HZ / 2);
113 return 0;
117 et_down(et_info_t *et, int reset)
119 ET_TRACE(("et%d: et_down\n", et->etc->unit));
121 /* stop watchdog timer */
122 TIMER_CLEAR(et->timer);
124 etc_down(et->etc, reset);
126 return 0;
129 void
130 et_dump(et_info_t *et, struct bcmstrbuf *b)
132 #ifdef BCMDBG
133 etc_dump(et->etc, b);
134 #endif
137 et_info_t *et_phyfind(et_info_t *et, uint coreunit);
138 uint16 et_phyrd(et_info_t *et, uint phyaddr, uint reg);
139 void et_phywr(et_info_t *et, uint reg, uint phyaddr, uint16 val);
142 * 47XX-specific shared mdc/mdio contortion:
143 * Find the et associated with the same chip as <et>
144 * and coreunit matching <coreunit>.
146 et_info_t *
147 et_phyfind(et_info_t *et, uint coreunit)
149 et_info_t *tmp;
151 /* walk the list et's */
152 for (tmp = et_list; tmp; tmp = tmp->next) {
153 if (et->etc == NULL)
154 continue;
155 if (tmp->etc->coreunit != coreunit)
156 continue;
157 break;
159 return (tmp);
162 /* shared phy read entry point */
163 uint16
164 et_phyrd(et_info_t *et, uint phyaddr, uint reg)
166 return et->etc->chops->phyrd(et->etc->ch, phyaddr, reg);
169 /* shared phy write entry point */
170 void
171 et_phywr(et_info_t *et, uint phyaddr, uint reg, uint16 val)
173 et->etc->chops->phywr(et->etc->ch, phyaddr, reg, val);
176 /* *********************************************************************
177 * ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
179 * Probe and install driver.
180 * Create a context structure and attach to the
181 * specified network device.
183 * Input parameters:
184 * drv - driver descriptor
185 * probe_a - device ID
186 * probe_b - unit number
187 * probe_ptr - mapped registers
189 * Return value:
190 * nothing
191 ********************************************************************* */
193 static void
194 et_probe(cfe_driver_t *drv,
195 unsigned long probe_a, unsigned long probe_b,
196 void *probe_ptr)
198 et_info_t *et;
199 uint16 device;
200 uint unit;
201 char name[128];
203 device = (uint16) probe_a;
204 unit = (uint) probe_b;
206 if (!(et = (et_info_t *) KMALLOC(sizeof(et_info_t), 0))) {
207 ET_ERROR(("et%d: KMALLOC failed\n", unit));
208 return;
210 bzero(et, sizeof(et_info_t));
212 et->osh = osl_attach(et);
213 ASSERT(et->osh);
215 #ifdef CFG_SIM
216 /* Make it chatty in simulation */
217 et_msg_level = 0xf;
218 #endif
220 /* common load-time initialization */
221 if ((et->etc = etc_attach(et, VENDOR_BROADCOM, device, unit, et->osh, probe_ptr)) == NULL) {
222 ET_ERROR(("et%d: etc_attach failed\n", unit));
223 KFREE(et);
224 return;
227 /* this is a polling driver - the chip intmask stays zero */
228 et->etc->chops->intrsoff(et->etc->ch);
230 /* add us to the global linked list */
231 et->next = et_list;
232 et_list = et;
234 /* print hello string */
235 et->etc->chops->longname(et->etc->ch, name, sizeof (name));
236 printf("et%d: %s %s\n", unit, name, EPI_VERSION_STR);
238 cfe_attach(drv, et, NULL, name);
241 /* *********************************************************************
242 * ETHER_OPEN(ctx)
244 * Open the Ethernet device. The MAC is reset, initialized, and
245 * prepared to receive and send packets.
247 * Input parameters:
248 * ctx - device context (includes ptr to our softc)
250 * Return value:
251 * status, 0 = ok
252 ********************************************************************* */
254 static int
255 et_open(cfe_devctx_t *ctx)
257 et_info_t *et = (et_info_t *) ctx->dev_softc;
259 ET_TRACE(("et%d: et_open\n", et->etc->unit));
261 return et_up(et);
264 /* *********************************************************************
265 * ETHER_READ(ctx,buffer)
267 * Read a packet from the Ethernet device. If no packets are
268 * available, the read will succeed but return 0 bytes.
270 * Input parameters:
271 * ctx - device context (includes ptr to our softc)
272 * buffer - pointer to buffer descriptor.
274 * Return value:
275 * status, 0 = ok
276 ********************************************************************* */
278 static int
279 et_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
281 et_info_t *et = (et_info_t *) ctx->dev_softc;
282 int events;
283 void *p;
284 bcmenetrxh_t *rxh;
285 uint16 flags;
286 char eabuf[32];
288 ET_TRACE(("et%d: et_read\n", et->etc->unit));
290 /* assume no packets */
291 buffer->buf_retlen = 0;
293 /* poll for packet */
294 events = et->etc->chops->getintrevents(et->etc->ch, FALSE);
295 if (events & INTR_ERROR)
296 return CFE_ERR_IOERR;
297 if ((events & INTR_RX) == 0)
298 return 0;
300 /* get packet */
301 if (!(p = et->etc->chops->rx(et->etc->ch)))
302 goto done;
304 /* packet buffer starts with rxhdr */
305 rxh = (bcmenetrxh_t *) PKTDATA(NULL, p);
307 /* strip off rxhdr */
308 PKTPULL(NULL, p, HWRXOFF);
310 /* check for reported frame errors */
311 flags = RXH_FLAGS(et->etc, rxh);
312 if (flags) {
313 bcm_ether_ntoa((struct ether_addr *)
314 (((struct ether_header *) PKTDATA(NULL, p))->ether_shost), eabuf);
315 if (RXH_OVERSIZE(et->etc, rxh)) {
316 ET_ERROR(("et%d: rx: over size packet from %s\n", et->etc->unit, eabuf));
318 if (RXH_CRC(et->etc, rxh)) {
319 ET_ERROR(("et%d: rx: crc error from %s\n", et->etc->unit, eabuf));
321 if (RXH_OVF(et->etc, rxh)) {
322 ET_ERROR(("et%d: rx: fifo overflow\n", et->etc->unit));
324 if (RXH_NO(et->etc, rxh)) {
325 ET_ERROR(("et%d: rx: crc error (odd nibbles) from %s\n",
326 et->etc->unit, eabuf));
328 if (RXH_RXER(et->etc, rxh)) {
329 ET_ERROR(("et%d: rx: symbol error from %s\n", et->etc->unit, eabuf));
331 } else {
332 bcopy(PKTDATA(NULL, p), buffer->buf_ptr, PKTLEN(NULL, p));
333 buffer->buf_retlen = PKTLEN(NULL, p);
334 ET_PRHDR("rx", (struct ether_header *) buffer->buf_ptr,
335 buffer->buf_retlen, et->etc->unit);
336 ET_PRPKT("rxpkt", buffer->buf_ptr, buffer->buf_retlen, et->etc->unit);
339 /* free packet */
340 PKTFREE(et->osh, p, FALSE);
342 done:
343 /* post more rx bufs */
344 et->etc->chops->rxfill(et->etc->ch);
346 return 0;
349 /* *********************************************************************
350 * ETHER_INPSTAT(ctx,inpstat)
352 * Check for received packets on the Ethernet device
354 * Input parameters:
355 * ctx - device context (includes ptr to our softc)
356 * inpstat - pointer to input status structure
358 * Return value:
359 * status, 0 = ok
360 ********************************************************************* */
362 static int
363 et_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
365 et_info_t *et = (et_info_t *) ctx->dev_softc;
366 int events;
368 events = et->etc->chops->getintrevents(et->etc->ch, FALSE);
369 inpstat->inp_status = ((events & INTR_RX) ? 1 : 0);
371 return 0;
374 /* *********************************************************************
375 * ETHER_WRITE(ctx,buffer)
377 * Write a packet to the Ethernet device.
379 * Input parameters:
380 * ctx - device context (includes ptr to our softc)
381 * buffer - pointer to buffer descriptor.
383 * Return value:
384 * status, 0 = ok
385 ********************************************************************* */
387 static int
388 et_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
390 et_info_t *et = ctx->dev_softc;
391 int events;
392 void *p;
394 if (!(p = PKTGET(NULL, buffer->buf_length, TRUE))) {
395 ET_ERROR(("et%d: PKTGET failed\n", et->etc->unit));
396 return CFE_ERR_NOMEM;
399 bcopy(buffer->buf_ptr, PKTDATA(NULL, p), buffer->buf_length);
401 ET_PRHDR("tx", (struct ether_header *)PKTDATA(NULL, p), PKTLEN(NULL, p), et->etc->unit);
402 ET_PRPKT("txpkt", PKTDATA(NULL, p), PKTLEN(NULL, p), et->etc->unit);
404 ASSERT(*et->etc->txavail[TX_Q0] > 0);
406 /* transmit the frame */
407 et->etc->chops->tx(et->etc->ch, p);
409 while (((events = et->etc->chops->getintrevents(et->etc->ch, FALSE)) & (INTR_ERROR | INTR_TX)) == 0);
411 /* reclaim any completed tx frames */
412 et->etc->chops->txreclaim(et->etc->ch, FALSE);
414 return (events & INTR_ERROR) ? CFE_ERR_IOERR : CFE_OK;
417 /* *********************************************************************
418 * ETHER_IOCTL(ctx,buffer)
420 * Do device-specific I/O control operations for the device
422 * Input parameters:
423 * ctx - device context (includes ptr to our softc)
424 * buffer - pointer to buffer descriptor.
426 * Return value:
427 * status, 0 = ok
428 ********************************************************************* */
429 static int
430 et_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
432 et_info_t *et = (et_info_t *) ctx->dev_softc;
433 int val;
435 ET_TRACE(("et%d: et_ioctl: cmd 0x%x\n", et->etc->unit, buffer->buf_ioctlcmd));
437 switch (buffer->buf_ioctlcmd) {
439 case IOCTL_ETHER_GETHWADDR:
440 bcopy(&et->etc->cur_etheraddr, buffer->buf_ptr, ETHER_ADDR_LEN);
441 break;
443 case IOCTL_ETHER_SETHWADDR:
444 bcopy(buffer->buf_ptr, &et->etc->cur_etheraddr, ETHER_ADDR_LEN);
445 et_init(et, ET_INIT_DEF_OPTIONS);
446 break;
448 case IOCTL_ETHER_GETSPEED:
449 val = ETHER_SPEED_UNKNOWN;
450 if (et->etc->linkstate) {
451 if (et->etc->speed == 10)
452 val = et->etc->duplex ? ETHER_SPEED_10FDX : ETHER_SPEED_10HDX;
453 else if (et->etc->speed == 100)
454 val = et->etc->duplex ? ETHER_SPEED_100FDX : ETHER_SPEED_100HDX;
455 else if (et->etc->speed == 1000)
456 val = ETHER_SPEED_1000FDX;
458 *((int *) buffer->buf_ptr) = val;
459 break;
461 case IOCTL_ETHER_SETSPEED:
462 val = *((int *) buffer->buf_ptr);
463 if (val == ETHER_SPEED_AUTO)
464 val = ET_AUTO;
465 else if (val == ETHER_SPEED_10HDX)
466 val = ET_10HALF;
467 else if (val == ETHER_SPEED_10FDX)
468 val = ET_10FULL;
469 else if (val == ETHER_SPEED_100HDX)
470 val = ET_100HALF;
471 else if (val == ETHER_SPEED_100FDX)
472 val = ET_100FULL;
473 else if (val == ETHER_SPEED_1000FDX)
474 val = ET_1000FULL;
475 else
476 return CFE_ERR_UNSUPPORTED;
477 return etc_ioctl(et->etc, ETCSPEED, &val);
479 case IOCTL_ETHER_GETLINK:
480 *((int *) buffer->buf_ptr) = (int) et->etc->linkstate;
481 break;
483 case IOCTL_ETHER_GETLOOPBACK:
484 *((int *) buffer->buf_ptr) = et->etc->loopbk;
485 break;
487 case IOCTL_ETHER_SETLOOPBACK:
488 val = *((int *) buffer->buf_ptr);
489 if (val == ETHER_LOOPBACK_OFF)
490 val = (int) FALSE;
491 else
492 val = (int) TRUE;
493 return etc_ioctl(et->etc, ETCLOOP, &val);
495 default:
496 return CFE_ERR_UNSUPPORTED;
500 return 0;
503 /* *********************************************************************
504 * ETHER_CLOSE(ctx)
506 * Close the Ethernet device.
508 * Input parameters:
509 * ctx - device context (includes ptr to our softc)
511 * Return value:
512 * status, 0 = ok
513 ********************************************************************* */
515 static int
516 et_close(cfe_devctx_t *ctx)
518 et_info_t *et = (et_info_t *) ctx->dev_softc;
520 ET_TRACE(("et%d: et_close\n", et->etc->unit));
522 return et_down(et, 1);
525 void
526 et_intrson(et_info_t *et)
528 /* this is a polling driver - the chip intmask stays zero */
529 ET_TRACE(("et%d: et_intrson\n", et->etc->unit));
532 /* *********************************************************************
533 * ETHER_POLL(ctx,ticks)
535 * Check for changes in the PHY, so we can track speed changes.
537 * Input parameters:
538 * ctx - device context (includes ptr to our softc)
539 * ticks- current time in ticks
541 * Return value:
542 * nothing
543 ********************************************************************* */
545 static void
546 et_poll(cfe_devctx_t *ctx, int64_t ticks)
548 et_info_t *et = (et_info_t *) ctx->dev_softc;
550 if (TIMER_RUNNING(et->timer) &&
551 TIMER_EXPIRED(et->timer)) {
552 etc_watchdog(et->etc);
553 TIMER_SET(et->timer, CFE_HZ / 2);
557 const static cfe_devdisp_t et_dispatch = {
558 et_open,
559 et_read,
560 et_inpstat,
561 et_write,
562 et_ioctl,
563 et_close,
564 et_poll,
565 NULL
568 const cfe_driver_t bcmet = {
569 "Broadcom Ethernet",
570 "eth",
571 CFE_DEV_NETWORK,
572 &et_dispatch,
573 et_probe
576 static int
577 ui_cmd_et(ui_cmdline_t *cmdline, int argc, char *argv[])
579 char *command, *name;
580 et_info_t *et;
581 cfe_device_t *dev;
582 int cmd, val, ret;
583 char *arg = (char *) &val;
585 if (!(command = cmd_getarg(cmdline, 0)))
586 return CFE_ERR_INV_PARAM;
588 if (!cmd_sw_value(cmdline, "-i", &name) || !name)
589 name = "eth0";
590 if (!(dev = cfe_finddev(name)) ||
591 !dev->dev_softc)
592 return CFE_ERR_DEVNOTFOUND;
593 for (et = et_list; et; et = et->next)
594 if (et == dev->dev_softc)
595 break;
596 if (!et && !(et = et_list))
597 return CFE_ERR_DEVNOTFOUND;
599 if (!strcmp(command, "up"))
600 cmd = ETCUP;
601 else if (!strcmp(command, "down"))
602 cmd = ETCDOWN;
603 else if (!strcmp(command, "loop")) {
604 cmd = ETCLOOP;
605 arg = cmd_getarg(cmdline, 1);
607 else if (!strcmp(command, "dump")) {
608 char *p;
609 if (!(arg = KMALLOC(IOCBUFSZ, 0)))
610 return CFE_ERR_NOMEM;
611 bzero(arg, IOCBUFSZ);
612 if ((ret = etc_ioctl(et->etc, ETCDUMP, arg))) {
613 KFREE(arg);
614 return ret;
616 /* No puts in cfe, and printf only has a 512 byte buffer */
617 p = arg;
618 while (*p)
619 printf("%c", *p++);
620 KFREE(arg);
621 return 0;
623 else if (!strcmp(command, "msglevel")) {
624 cmd = ETCSETMSGLEVEL;
625 arg = cmd_getarg(cmdline, 1);
627 else if (!strcmp(command, "promisc")) {
628 cmd = ETCPROMISC;
629 arg = cmd_getarg(cmdline, 1);
631 else
632 return CFE_ERR_INV_PARAM;
634 if (!arg)
635 return CFE_ERR_INV_PARAM;
636 else if (arg != (char *) &val) {
637 val = bcm_strtoul(arg, NULL, 0);
638 arg = (char *) &val;
641 return etc_ioctl(et->etc, cmd, arg);
644 void
645 et_addcmd(void)
647 cmd_addcmd("et",
648 ui_cmd_et,
649 NULL,
650 "Broadcom Ethernet utility.",
651 "et command [args..]\n\n"
652 "Configures the specified Broadcom Ethernet interface.",
653 "-i=*;Specifies the interface|"
654 "up;Activate the specified interface|"
655 "down;Deactivate the specified interface|"
656 "loop;Sets the loopback mode (0,1)|"
657 "dump;Dump driver information|"
658 "msglevel;Sets the driver message level|"
659 "promisc;Sets promiscuous mode|");