Broadcom et driver updates from SDK 5.10.140.0
[tomato.git] / release / src-rt / et / sys / et_cfe.c
blob94a2b6bebe26d14cc6ab06c5c7c4aff795d8b160
1 /*
2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright (C) 2008, Broadcom Corporation
6 * All Rights Reserved.
7 *
8 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom Corporation;
9 * the contents of this file may not be disclosed to third parties, copied
10 * or duplicated in any form, in whole or in part, without the prior
11 * written permission of Broadcom Corporation.
13 * $Id: et_cfe.c,v 1.19.96.2 2008/09/12 04:31:31 Exp $
16 #include "lib_types.h"
17 #include "lib_malloc.h"
18 #include "lib_string.h"
19 #include "lib_printf.h"
21 #include "cfe_iocb.h"
22 #include "cfe_device.h"
23 #include "cfe_ioctl.h"
24 #include "cfe_console.h"
25 #include "cfe_timer.h"
26 #include "cfe_error.h"
27 #include "ui_command.h"
29 #include <typedefs.h>
30 #include <osl.h>
31 #include <epivers.h>
32 #include <bcmendian.h>
33 #include <proto/ethernet.h>
34 #include <bcmdevs.h>
35 #include <bcmenetmib.h>
36 #include <bcmenetrxh.h>
37 #include <bcmutils.h>
38 #include <et_dbg.h>
39 #include <hndsoc.h>
40 #include <bcmgmacrxh.h>
41 #include <etc.h>
43 typedef struct et_info {
44 etc_info_t *etc; /* pointer to common os-independent data */
45 cfe_devctx_t *ctx; /* backpoint to device */
46 int64_t timer; /* one second watchdog timer */
47 osl_t *osh;
48 struct et_info *next; /* pointer to next et_info_t in chain */
49 } et_info_t;
51 static et_info_t *et_list = NULL;
53 void et_init(et_info_t *et, uint options);
54 void et_reset(et_info_t *et);
55 void et_link_up(et_info_t *et);
56 void et_link_down(et_info_t *et);
57 int et_up(et_info_t *et);
58 int et_down(et_info_t *et, int reset);
59 void et_dump(et_info_t *et, struct bcmstrbuf *b);
60 void et_addcmd(void);
61 void et_intrson(et_info_t *et);
63 void
64 et_init(et_info_t *et, uint options)
66 ET_TRACE(("et%d: et_init\n", et->etc->unit));
68 etc_reset(et->etc);
69 etc_init(et->etc, options);
72 void
73 et_reset(et_info_t *et)
75 ET_TRACE(("et%d: et_reset\n", et->etc->unit));
77 etc_reset(et->etc);
80 void
81 et_link_up(et_info_t *et)
83 ET_ERROR(("et%d: link up (%d%s)\n",
84 et->etc->unit, et->etc->speed, (et->etc->duplex? "FD" : "HD")));
87 void
88 et_link_down(et_info_t *et)
90 ET_ERROR(("et%d: link down\n", et->etc->unit));
93 int
94 et_up(et_info_t *et)
96 if (et->etc->up)
97 return 0;
99 ET_TRACE(("et%d: et_up\n", et->etc->unit));
101 etc_up(et->etc);
103 /* schedule one second watchdog timer */
104 TIMER_SET(et->timer, CFE_HZ / 2);
106 return 0;
110 et_down(et_info_t *et, int reset)
112 ET_TRACE(("et%d: et_down\n", et->etc->unit));
114 /* stop watchdog timer */
115 TIMER_CLEAR(et->timer);
117 etc_down(et->etc, reset);
119 return 0;
122 void
123 et_dump(et_info_t *et, struct bcmstrbuf *b)
127 et_info_t *et_phyfind(et_info_t *et, uint coreunit);
128 uint16 et_phyrd(et_info_t *et, uint phyaddr, uint reg);
129 void et_phywr(et_info_t *et, uint reg, uint phyaddr, uint16 val);
132 * 47XX-specific shared mdc/mdio contortion:
133 * Find the et associated with the same chip as <et>
134 * and coreunit matching <coreunit>.
136 et_info_t *
137 et_phyfind(et_info_t *et, uint coreunit)
139 et_info_t *tmp;
141 /* walk the list et's */
142 for (tmp = et_list; tmp; tmp = tmp->next) {
143 if (et->etc == NULL)
144 continue;
145 if (tmp->etc->coreunit != coreunit)
146 continue;
147 break;
149 return (tmp);
152 /* shared phy read entry point */
153 uint16
154 et_phyrd(et_info_t *et, uint phyaddr, uint reg)
156 return et->etc->chops->phyrd(et->etc->ch, phyaddr, reg);
159 /* shared phy write entry point */
160 void
161 et_phywr(et_info_t *et, uint phyaddr, uint reg, uint16 val)
163 et->etc->chops->phywr(et->etc->ch, phyaddr, reg, val);
166 /* *********************************************************************
167 * ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
169 * Probe and install driver.
170 * Create a context structure and attach to the
171 * specified network device.
173 * Input parameters:
174 * drv - driver descriptor
175 * probe_a - device ID
176 * probe_b - unit number
177 * probe_ptr - mapped registers
179 * Return value:
180 * nothing
181 ********************************************************************* */
183 static void
184 et_probe(cfe_driver_t *drv,
185 unsigned long probe_a, unsigned long probe_b,
186 void *probe_ptr)
188 et_info_t *et;
189 uint16 device;
190 uint unit;
191 char name[128];
193 device = (uint16) probe_a;
194 unit = (uint) probe_b;
196 if (!(et = (et_info_t *) KMALLOC(sizeof(et_info_t), 0))) {
197 ET_ERROR(("et%d: KMALLOC failed\n", unit));
198 return;
200 bzero(et, sizeof(et_info_t));
202 et->osh = osl_attach(et);
203 ASSERT(et->osh);
205 /* common load-time initialization */
206 if ((et->etc = etc_attach(et, VENDOR_BROADCOM, device, unit, et->osh, probe_ptr)) == NULL) {
207 ET_ERROR(("et%d: etc_attach failed\n", unit));
208 KFREE(et);
209 return;
212 /* this is a polling driver - the chip intmask stays zero */
213 et->etc->chops->intrsoff(et->etc->ch);
215 /* add us to the global linked list */
216 et->next = et_list;
217 et_list = et;
219 /* print hello string */
220 et->etc->chops->longname(et->etc->ch, name, sizeof (name));
221 printf("et%d: %s %s\n", unit, name, EPI_VERSION_STR);
223 #ifdef CFG_SIM
224 /* Make it chatty in simulation */
225 et_msg_level = 0xf;
226 #endif
228 cfe_attach(drv, et, NULL, name);
231 /* *********************************************************************
232 * ETHER_OPEN(ctx)
234 * Open the Ethernet device. The MAC is reset, initialized, and
235 * prepared to receive and send packets.
237 * Input parameters:
238 * ctx - device context (includes ptr to our softc)
240 * Return value:
241 * status, 0 = ok
242 ********************************************************************* */
244 static int
245 et_open(cfe_devctx_t *ctx)
247 et_info_t *et = (et_info_t *) ctx->dev_softc;
249 ET_TRACE(("et%d: et_open\n", et->etc->unit));
251 return et_up(et);
254 /* *********************************************************************
255 * ETHER_READ(ctx,buffer)
257 * Read a packet from the Ethernet device. If no packets are
258 * available, the read will succeed but return 0 bytes.
260 * Input parameters:
261 * ctx - device context (includes ptr to our softc)
262 * buffer - pointer to buffer descriptor.
264 * Return value:
265 * status, 0 = ok
266 ********************************************************************* */
268 static int
269 et_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
271 et_info_t *et = (et_info_t *) ctx->dev_softc;
272 int events;
273 void *p;
274 bcmenetrxh_t *rxh;
275 uint16 flags;
276 char eabuf[32];
278 ET_TRACE(("et%d: et_read\n", et->etc->unit));
280 /* assume no packets */
281 buffer->buf_retlen = 0;
283 /* poll for packet */
284 events = et->etc->chops->getintrevents(et->etc->ch, FALSE);
285 if (events & INTR_ERROR)
286 return CFE_ERR_IOERR;
287 if ((events & INTR_RX) == 0)
288 return 0;
290 /* get packet */
291 if (!(p = et->etc->chops->rx(et->etc->ch)))
292 goto done;
294 /* packet buffer starts with rxhdr */
295 rxh = (bcmenetrxh_t *) PKTDATA(NULL, p);
297 /* strip off rxhdr */
298 PKTPULL(NULL, p, HWRXOFF);
300 /* check for reported frame errors */
301 flags = RXH_FLAGS(et->etc, rxh);
302 if (flags) {
303 bcm_ether_ntoa((struct ether_addr *)
304 (((struct ether_header *) PKTDATA(NULL, p))->ether_shost), eabuf);
305 if (RXH_OVERSIZE(et->etc, rxh)) {
306 ET_ERROR(("et%d: rx: over size packet from %s\n", et->etc->unit, eabuf));
308 if (RXH_CRC(et->etc, rxh)) {
309 ET_ERROR(("et%d: rx: crc error from %s\n", et->etc->unit, eabuf));
311 if (RXH_OVF(et->etc, rxh)) {
312 ET_ERROR(("et%d: rx: fifo overflow\n", et->etc->unit));
314 if (RXH_NO(et->etc, rxh)) {
315 ET_ERROR(("et%d: rx: crc error (odd nibbles) from %s\n",
316 et->etc->unit, eabuf));
318 if (RXH_RXER(et->etc, rxh)) {
319 ET_ERROR(("et%d: rx: symbol error from %s\n", et->etc->unit, eabuf));
321 } else {
322 bcopy(PKTDATA(NULL, p), buffer->buf_ptr, PKTLEN(NULL, p));
323 buffer->buf_retlen = PKTLEN(NULL, p);
324 ET_PRHDR("rx", (struct ether_header *) buffer->buf_ptr,
325 buffer->buf_retlen, et->etc->unit);
326 ET_PRPKT("rxpkt", buffer->buf_ptr, buffer->buf_retlen, et->etc->unit);
329 /* free packet */
330 PKTFREE(et->osh, p, FALSE);
332 done:
333 /* post more rx bufs */
334 et->etc->chops->rxfill(et->etc->ch);
336 return 0;
339 /* *********************************************************************
340 * ETHER_INPSTAT(ctx,inpstat)
342 * Check for received packets on the Ethernet device
344 * Input parameters:
345 * ctx - device context (includes ptr to our softc)
346 * inpstat - pointer to input status structure
348 * Return value:
349 * status, 0 = ok
350 ********************************************************************* */
352 static int
353 et_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
355 et_info_t *et = (et_info_t *) ctx->dev_softc;
356 int events;
358 events = et->etc->chops->getintrevents(et->etc->ch, FALSE);
359 inpstat->inp_status = ((events & INTR_RX) ? 1 : 0);
361 return 0;
364 /* *********************************************************************
365 * ETHER_WRITE(ctx,buffer)
367 * Write a packet to the Ethernet device.
369 * Input parameters:
370 * ctx - device context (includes ptr to our softc)
371 * buffer - pointer to buffer descriptor.
373 * Return value:
374 * status, 0 = ok
375 ********************************************************************* */
377 static int
378 et_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
380 et_info_t *et = ctx->dev_softc;
381 int events;
382 void *p;
384 if (!(p = PKTGET(NULL, buffer->buf_length, TRUE))) {
385 ET_ERROR(("et%d: PKTGET failed\n", et->etc->unit));
386 return CFE_ERR_NOMEM;
389 bcopy(buffer->buf_ptr, PKTDATA(NULL, p), buffer->buf_length);
391 ET_PRHDR("tx", (struct ether_header *)PKTDATA(NULL, p), PKTLEN(NULL, p), et->etc->unit);
392 ET_PRPKT("txpkt", PKTDATA(NULL, p), PKTLEN(NULL, p), et->etc->unit);
394 ASSERT(*et->etc->txavail[TX_Q0] > 0);
396 /* transmit the frame */
397 et->etc->chops->tx(et->etc->ch, p);
399 while (((events = et->etc->chops->getintrevents(et->etc->ch, FALSE)) & (INTR_ERROR | INTR_TX)) == 0);
401 /* reclaim any completed tx frames */
402 et->etc->chops->txreclaim(et->etc->ch, FALSE);
404 return (events & INTR_ERROR) ? CFE_ERR_IOERR : CFE_OK;
407 /* *********************************************************************
408 * ETHER_IOCTL(ctx,buffer)
410 * Do device-specific I/O control operations for the device
412 * Input parameters:
413 * ctx - device context (includes ptr to our softc)
414 * buffer - pointer to buffer descriptor.
416 * Return value:
417 * status, 0 = ok
418 ********************************************************************* */
419 static int
420 et_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
422 et_info_t *et = (et_info_t *) ctx->dev_softc;
423 int val;
425 ET_TRACE(("et%d: et_ioctl: cmd 0x%x\n", et->etc->unit, buffer->buf_ioctlcmd));
427 switch (buffer->buf_ioctlcmd) {
429 case IOCTL_ETHER_GETHWADDR:
430 bcopy(&et->etc->cur_etheraddr, buffer->buf_ptr, ETHER_ADDR_LEN);
431 break;
433 case IOCTL_ETHER_SETHWADDR:
434 bcopy(buffer->buf_ptr, &et->etc->cur_etheraddr, ETHER_ADDR_LEN);
435 et_init(et, ET_INIT_DEF_OPTIONS);
436 break;
438 case IOCTL_ETHER_GETSPEED:
439 val = ETHER_SPEED_UNKNOWN;
440 if (et->etc->linkstate) {
441 if (et->etc->speed == 10)
442 val = et->etc->duplex ? ETHER_SPEED_10FDX : ETHER_SPEED_10HDX;
443 else if (et->etc->speed == 100)
444 val = et->etc->duplex ? ETHER_SPEED_100FDX : ETHER_SPEED_100HDX;
445 else if (et->etc->speed == 1000)
446 val = ETHER_SPEED_1000FDX;
448 *((int *) buffer->buf_ptr) = val;
449 break;
451 case IOCTL_ETHER_SETSPEED:
452 val = *((int *) buffer->buf_ptr);
453 if (val == ETHER_SPEED_AUTO)
454 val = ET_AUTO;
455 else if (val == ETHER_SPEED_10HDX)
456 val = ET_10HALF;
457 else if (val == ETHER_SPEED_10FDX)
458 val = ET_10FULL;
459 else if (val == ETHER_SPEED_100HDX)
460 val = ET_100HALF;
461 else if (val == ETHER_SPEED_100FDX)
462 val = ET_100FULL;
463 else if (val == ETHER_SPEED_1000FDX)
464 val = ET_1000FULL;
465 else
466 return CFE_ERR_UNSUPPORTED;
467 return etc_ioctl(et->etc, ETCSPEED, &val);
469 case IOCTL_ETHER_GETLINK:
470 *((int *) buffer->buf_ptr) = (int) et->etc->linkstate;
471 break;
473 case IOCTL_ETHER_GETLOOPBACK:
474 *((int *) buffer->buf_ptr) = et->etc->loopbk;
475 break;
477 case IOCTL_ETHER_SETLOOPBACK:
478 val = *((int *) buffer->buf_ptr);
479 if (val == ETHER_LOOPBACK_OFF)
480 val = (int) FALSE;
481 else
482 val = (int) TRUE;
483 return etc_ioctl(et->etc, ETCLOOP, &val);
485 default:
486 return CFE_ERR_UNSUPPORTED;
490 return 0;
493 /* *********************************************************************
494 * ETHER_CLOSE(ctx)
496 * Close the Ethernet device.
498 * Input parameters:
499 * ctx - device context (includes ptr to our softc)
501 * Return value:
502 * status, 0 = ok
503 ********************************************************************* */
505 static int
506 et_close(cfe_devctx_t *ctx)
508 et_info_t *et = (et_info_t *) ctx->dev_softc;
510 ET_TRACE(("et%d: et_close\n", et->etc->unit));
512 return et_down(et, 1);
515 void
516 et_intrson(et_info_t *et)
518 /* this is a polling driver - the chip intmask stays zero */
519 ET_TRACE(("et%d: et_intrson\n", et->etc->unit));
522 /* *********************************************************************
523 * ETHER_POLL(ctx,ticks)
525 * Check for changes in the PHY, so we can track speed changes.
527 * Input parameters:
528 * ctx - device context (includes ptr to our softc)
529 * ticks- current time in ticks
531 * Return value:
532 * nothing
533 ********************************************************************* */
535 static void
536 et_poll(cfe_devctx_t *ctx, int64_t ticks)
538 et_info_t *et = (et_info_t *) ctx->dev_softc;
540 if (TIMER_RUNNING(et->timer) &&
541 TIMER_EXPIRED(et->timer)) {
542 etc_watchdog(et->etc);
543 TIMER_SET(et->timer, CFE_HZ / 2);
547 const static cfe_devdisp_t et_dispatch = {
548 et_open,
549 et_read,
550 et_inpstat,
551 et_write,
552 et_ioctl,
553 et_close,
554 et_poll,
555 NULL
558 const cfe_driver_t bcmet = {
559 "Broadcom Ethernet",
560 "eth",
561 CFE_DEV_NETWORK,
562 &et_dispatch,
563 et_probe
566 static int
567 ui_cmd_et(ui_cmdline_t *cmdline, int argc, char *argv[])
569 char *command, *name;
570 et_info_t *et;
571 cfe_device_t *dev;
572 int cmd, val, ret;
573 char *arg = (char *) &val;
575 if (!(command = cmd_getarg(cmdline, 0)))
576 return CFE_ERR_INV_PARAM;
578 if (!cmd_sw_value(cmdline, "-i", &name) || !name)
579 name = "eth0";
580 if (!(dev = cfe_finddev(name)) ||
581 !dev->dev_softc)
582 return CFE_ERR_DEVNOTFOUND;
583 for (et = et_list; et; et = et->next)
584 if (et == dev->dev_softc)
585 break;
586 if (!et && !(et = et_list))
587 return CFE_ERR_DEVNOTFOUND;
589 if (!strcmp(command, "up"))
590 cmd = ETCUP;
591 else if (!strcmp(command, "down"))
592 cmd = ETCDOWN;
593 else if (!strcmp(command, "loop")) {
594 cmd = ETCLOOP;
595 arg = cmd_getarg(cmdline, 1);
597 else if (!strcmp(command, "dump")) {
598 char *p;
599 if (!(arg = KMALLOC(4096, 0)))
600 return CFE_ERR_NOMEM;
601 bzero(arg, 4096);
602 if ((ret = etc_ioctl(et->etc, ETCDUMP, arg))) {
603 KFREE(arg);
604 return ret;
606 /* No puts in cfe, and printf only has a 512 byte buffer */
607 p = arg;
608 while (*p)
609 printf("%c", *p);
610 KFREE(arg);
611 return 0;
613 else if (!strcmp(command, "msglevel")) {
614 cmd = ETCSETMSGLEVEL;
615 arg = cmd_getarg(cmdline, 1);
617 else if (!strcmp(command, "promisc")) {
618 cmd = ETCPROMISC;
619 arg = cmd_getarg(cmdline, 1);
621 else
622 return CFE_ERR_INV_PARAM;
624 if (!arg)
625 return CFE_ERR_INV_PARAM;
626 else if (arg != (char *) &val) {
627 val = bcm_strtoul(arg, NULL, 0);
628 arg = (char *) &val;
631 return etc_ioctl(et->etc, cmd, arg);
634 void
635 et_addcmd(void)
637 cmd_addcmd("et",
638 ui_cmd_et,
639 NULL,
640 "Broadcom Ethernet utility.",
641 "et command [args..]\n\n"
642 "Configures the specified Broadcom Ethernet interface.",
643 "-i=*;Specifies the interface|"
644 "up;Activate the specified interface|"
645 "down;Deactivate the specified interface|"
646 "loop;Sets the loopback mode (0,1)|"
647 "dump;Dump driver information|"
648 "msglevel;Sets the driver message level|"
649 "promisc;Sets promiscuous mode|");