SSID: Respect ASCII character Label.
[tomato.git] / release / src / et / sys / et_cfe.c
blob800af7c83c681596025456524e41ede65a35b953
1 /*
2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright 2006, 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.1.1.1 2007/03/20 12:22:00 roly 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 <etc.h>
41 typedef struct et_info {
42 etc_info_t *etc; /* pointer to common os-independent data */
43 cfe_devctx_t *ctx; /* backpoint to device */
44 int64_t timer; /* one second watchdog timer */
45 osl_t *osh;
46 struct et_info *next; /* pointer to next et_info_t in chain */
47 } et_info_t;
49 static et_info_t *et_list = NULL;
51 void et_init(et_info_t *et);
52 void et_reset(et_info_t *et);
53 void et_link_up(et_info_t *et);
54 void et_link_down(et_info_t *et);
55 int et_up(et_info_t *et);
56 int et_down(et_info_t *et, int reset);
57 void et_dump(et_info_t *et, struct bcmstrbuf *b);
58 void et_addcmd(void);
59 void et_intrson(et_info_t *et);
61 void
62 et_init(et_info_t *et)
64 ET_TRACE(("et%d: et_init\n", et->etc->unit));
66 etc_reset(et->etc);
67 etc_init(et->etc);
70 void
71 et_reset(et_info_t *et)
73 ET_TRACE(("et%d: et_reset\n", et->etc->unit));
75 etc_reset(et->etc);
78 void
79 et_link_up(et_info_t *et)
81 ET_ERROR(("et%d: link up (%d%s)\n",
82 et->etc->unit, et->etc->speed, (et->etc->duplex? "FD" : "HD")));
85 void
86 et_link_down(et_info_t *et)
88 ET_ERROR(("et%d: link down\n", et->etc->unit));
91 int
92 et_up(et_info_t *et)
94 if (et->etc->up)
95 return 0;
97 ET_TRACE(("et%d: et_up\n", et->etc->unit));
99 etc_up(et->etc);
101 /* schedule one second watchdog timer */
102 TIMER_SET(et->timer, CFE_HZ / 2);
104 return 0;
108 et_down(et_info_t *et, int reset)
110 ET_TRACE(("et%d: et_down\n", et->etc->unit));
112 /* stop watchdog timer */
113 TIMER_CLEAR(et->timer);
115 etc_down(et->etc, reset);
117 return 0;
120 void
121 et_dump(et_info_t *et, struct bcmstrbuf *b)
126 et_info_t *et_phyfind(et_info_t *et, uint coreunit);
127 uint16 et_phyrd(et_info_t *et, uint phyaddr, uint reg);
128 void et_phywr(et_info_t *et, uint reg, uint phyaddr, uint16 val);
131 * 47XX-specific shared mdc/mdio contortion:
132 * Find the et associated with the same chip as <et>
133 * and coreunit matching <coreunit>.
135 et_info_t *
136 et_phyfind(et_info_t *et, uint coreunit)
138 et_info_t *tmp;
140 /* walk the list et's */
141 for (tmp = et_list; tmp; tmp = tmp->next) {
142 if (et->etc == NULL)
143 continue;
144 if (tmp->etc->coreunit != coreunit)
145 continue;
146 break;
148 return (tmp);
151 /* shared phy read entry point */
152 uint16
153 et_phyrd(et_info_t *et, uint phyaddr, uint reg)
155 return et->etc->chops->phyrd(et->etc->ch, phyaddr, reg);
158 /* shared phy write entry point */
159 void
160 et_phywr(et_info_t *et, uint phyaddr, uint reg, uint16 val)
162 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 cfe_attach(drv, et, NULL, name);
226 /* *********************************************************************
227 * ETHER_OPEN(ctx)
229 * Open the Ethernet device. The MAC is reset, initialized, and
230 * prepared to receive and send packets.
232 * Input parameters:
233 * ctx - device context (includes ptr to our softc)
235 * Return value:
236 * status, 0 = ok
237 ********************************************************************* */
239 static int
240 et_open(cfe_devctx_t *ctx)
242 et_info_t *et = (et_info_t *) ctx->dev_softc;
244 ET_TRACE(("et%d: et_open\n", et->etc->unit));
246 return et_up(et);
249 /* *********************************************************************
250 * ETHER_READ(ctx,buffer)
252 * Read a packet from the Ethernet device. If no packets are
253 * available, the read will succeed but return 0 bytes.
255 * Input parameters:
256 * ctx - device context (includes ptr to our softc)
257 * buffer - pointer to buffer descriptor.
259 * Return value:
260 * status, 0 = ok
261 ********************************************************************* */
263 static int
264 et_read(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
266 et_info_t *et = (et_info_t *) ctx->dev_softc;
267 int events;
268 void *p;
269 bcmenetrxh_t *rxh;
270 uint16 flags;
271 char eabuf[32];
273 ET_TRACE(("et%d: et_read\n", et->etc->unit));
275 /* assume no packets */
276 buffer->buf_retlen = 0;
278 /* poll for packet */
279 events = et->etc->chops->getintrevents(et->etc->ch, FALSE);
280 if ((events & INTR_RX) == 0)
281 return 0;
283 /* get packet */
284 if (!(p = et->etc->chops->rx(et->etc->ch)))
285 goto done;
287 /* packet buffer starts with rxhdr */
288 rxh = (bcmenetrxh_t *) PKTDATA(NULL, p);
290 /* strip off rxhdr */
291 PKTPULL(NULL, p, HWRXOFF);
293 /* check for reported frame errors */
294 flags = ltoh16(rxh->flags);
295 if ((flags & (RXF_NO | RXF_RXER | RXF_CRC | RXF_OV))) {
296 bcm_ether_ntoa((struct ether_addr *)
297 (((struct ether_header *) PKTDATA(NULL, p))->ether_shost), eabuf);
298 if (flags & RXF_NO) {
299 ET_ERROR(("et%d: rx: crc error (odd nibbles) from %s\n", et->etc->unit, eabuf));
301 if (flags & RXF_RXER) {
302 ET_ERROR(("et%d: rx: symbol error from %s\n", et->etc->unit, eabuf));
304 if (flags & RXF_CRC) {
305 ET_ERROR(("et%d: rx: crc error from %s\n", et->etc->unit, eabuf));
307 if (flags & RXF_OV) {
308 ET_ERROR(("et%d: rx: fifo overflow\n", et->etc->unit));
310 } else {
311 bcopy(PKTDATA(NULL, p), buffer->buf_ptr, PKTLEN(NULL, p));
312 buffer->buf_retlen = PKTLEN(NULL, p);
313 ET_PRHDR("rx", (struct ether_header *) buffer->buf_ptr, buffer->buf_retlen, et->etc->unit);
314 ET_PRPKT("rxpkt", buffer->buf_ptr, buffer->buf_retlen, et->etc->unit);
317 /* free packet */
318 PKTFREE(et->osh, p, FALSE);
320 done:
321 /* post more rx bufs */
322 et->etc->chops->rxfill(et->etc->ch);
324 return 0;
327 /* *********************************************************************
328 * ETHER_INPSTAT(ctx,inpstat)
330 * Check for received packets on the Ethernet device
332 * Input parameters:
333 * ctx - device context (includes ptr to our softc)
334 * inpstat - pointer to input status structure
336 * Return value:
337 * status, 0 = ok
338 ********************************************************************* */
340 static int
341 et_inpstat(cfe_devctx_t *ctx, iocb_inpstat_t *inpstat)
343 et_info_t *et = (et_info_t *) ctx->dev_softc;
344 int events;
346 events = et->etc->chops->getintrevents(et->etc->ch, FALSE);
347 inpstat->inp_status = ((events & INTR_RX) ? 1 : 0);
349 return 0;
352 /* *********************************************************************
353 * ETHER_WRITE(ctx,buffer)
355 * Write a packet to the Ethernet device.
357 * Input parameters:
358 * ctx - device context (includes ptr to our softc)
359 * buffer - pointer to buffer descriptor.
361 * Return value:
362 * status, 0 = ok
363 ********************************************************************* */
365 static int
366 et_write(cfe_devctx_t *ctx, iocb_buffer_t *buffer)
368 et_info_t *et = ctx->dev_softc;
369 void *p;
371 if (!(p = PKTGET(NULL, buffer->buf_length, TRUE))) {
372 ET_ERROR(("et%d: PKTGET failed\n", et->etc->unit));
373 return CFE_ERR_NOMEM;
376 bcopy(buffer->buf_ptr, PKTDATA(NULL, p), buffer->buf_length);
378 ET_PRHDR("tx", (struct ether_header *) PKTDATA(NULL, p), PKTLEN(NULL, p), et->etc->unit);
379 ET_PRPKT("txpkt", PKTDATA(NULL, p), PKTLEN(NULL, p), et->etc->unit);
381 ASSERT(*et->etc->txavail > 0);
383 /* transmit the frame */
384 et->etc->chops->tx(et->etc->ch, p);
386 /* wait for frame to complete */
387 while (!(et->etc->chops->getintrevents(et->etc->ch, FALSE) & INTR_TX));
389 /* reclaim any completed tx frames */
390 et->etc->chops->txreclaim(et->etc->ch, FALSE);
392 return 0;
395 /* *********************************************************************
396 * ETHER_IOCTL(ctx,buffer)
398 * Do device-specific I/O control operations for the device
400 * Input parameters:
401 * ctx - device context (includes ptr to our softc)
402 * buffer - pointer to buffer descriptor.
404 * Return value:
405 * status, 0 = ok
406 ********************************************************************* */
407 static int
408 et_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
410 et_info_t *et = (et_info_t *) ctx->dev_softc;
411 int val;
413 ET_TRACE(("et%d: et_ioctl: cmd 0x%x\n", et->etc->unit, buffer->buf_ioctlcmd));
415 switch (buffer->buf_ioctlcmd) {
417 case IOCTL_ETHER_GETHWADDR:
418 bcopy(&et->etc->cur_etheraddr, buffer->buf_ptr, ETHER_ADDR_LEN);
419 break;
421 case IOCTL_ETHER_SETHWADDR:
422 bcopy(buffer->buf_ptr, &et->etc->cur_etheraddr, ETHER_ADDR_LEN);
423 et_init(et);
424 break;
426 case IOCTL_ETHER_GETSPEED:
427 val = ETHER_SPEED_UNKNOWN;
428 if (et->etc->linkstate) {
429 if (et->etc->speed == 10)
430 val = et->etc->duplex ? ETHER_SPEED_10FDX : ETHER_SPEED_10HDX;
431 else if (et->etc->speed == 100)
432 val = et->etc->duplex ? ETHER_SPEED_100FDX : ETHER_SPEED_100HDX;
434 *((int *) buffer->buf_ptr) = val;
435 break;
437 case IOCTL_ETHER_SETSPEED:
438 val = *((int *) buffer->buf_ptr);
439 if (val == ETHER_SPEED_AUTO)
440 val = ET_AUTO;
441 else if (val == ETHER_SPEED_10HDX)
442 val = ET_10HALF;
443 else if (val == ETHER_SPEED_10FDX)
444 val = ET_10FULL;
445 else if (val == ETHER_SPEED_100HDX)
446 val = ET_100HALF;
447 else if (val == ETHER_SPEED_100FDX)
448 val = ET_100FULL;
449 else
450 return CFE_ERR_UNSUPPORTED;
451 return etc_ioctl(et->etc, ETCSPEED, &val);
453 case IOCTL_ETHER_GETLINK:
454 *((int *) buffer->buf_ptr) = (int) et->etc->linkstate;
455 break;
457 case IOCTL_ETHER_GETLOOPBACK:
458 *((int *) buffer->buf_ptr) = et->etc->loopbk;
459 break;
461 case IOCTL_ETHER_SETLOOPBACK:
462 val = *((int *) buffer->buf_ptr);
463 if (val == ETHER_LOOPBACK_OFF)
464 val = (int) FALSE;
465 else
466 val = (int) TRUE;
467 return etc_ioctl(et->etc, ETCLOOP, &val);
469 default:
470 return CFE_ERR_UNSUPPORTED;
474 return 0;
477 /* *********************************************************************
478 * ETHER_CLOSE(ctx)
480 * Close the Ethernet device.
482 * Input parameters:
483 * ctx - device context (includes ptr to our softc)
485 * Return value:
486 * status, 0 = ok
487 ********************************************************************* */
489 static int
490 et_close(cfe_devctx_t *ctx)
492 et_info_t *et = (et_info_t *) ctx->dev_softc;
494 ET_TRACE(("et%d: et_close\n", et->etc->unit));
496 return et_down(et, 1);
499 void
500 et_intrson(et_info_t *et)
502 /* this is a polling driver - the chip intmask stays zero */
503 ET_TRACE(("et%d: et_intrson\n", et->etc->unit));
506 /* *********************************************************************
507 * ETHER_POLL(ctx,ticks)
509 * Check for changes in the PHY, so we can track speed changes.
511 * Input parameters:
512 * ctx - device context (includes ptr to our softc)
513 * ticks- current time in ticks
515 * Return value:
516 * nothing
517 ********************************************************************* */
519 static void
520 et_poll(cfe_devctx_t *ctx, int64_t ticks)
522 et_info_t *et = (et_info_t *) ctx->dev_softc;
524 if (TIMER_RUNNING(et->timer) &&
525 TIMER_EXPIRED(et->timer)) {
526 etc_watchdog(et->etc);
527 TIMER_SET(et->timer, CFE_HZ / 2);
531 const static cfe_devdisp_t et_dispatch = {
532 et_open,
533 et_read,
534 et_inpstat,
535 et_write,
536 et_ioctl,
537 et_close,
538 et_poll,
539 NULL
542 const cfe_driver_t bcmet = {
543 "Broadcom Ethernet",
544 "eth",
545 CFE_DEV_NETWORK,
546 &et_dispatch,
547 et_probe
550 static int
551 ui_cmd_et(ui_cmdline_t *cmdline, int argc, char *argv[])
553 char *command, *name;
554 et_info_t *et;
555 cfe_device_t *dev;
556 int cmd, val, ret;
557 char *arg = (char *) &val;
559 if (!(command = cmd_getarg(cmdline, 0)))
560 return CFE_ERR_INV_PARAM;
562 if (!cmd_sw_value(cmdline, "-i", &name) || !name)
563 name = "eth0";
564 if (!(dev = cfe_finddev(name)) ||
565 !dev->dev_softc)
566 return CFE_ERR_DEVNOTFOUND;
567 for (et = et_list; et; et = et->next)
568 if (et == dev->dev_softc)
569 break;
570 if (!et && !(et = et_list))
571 return CFE_ERR_DEVNOTFOUND;
573 if (!strcmp(command, "up"))
574 cmd = ETCUP;
575 else if (!strcmp(command, "down"))
576 cmd = ETCDOWN;
577 else if (!strcmp(command, "loop")) {
578 cmd = ETCLOOP;
579 arg = cmd_getarg(cmdline, 1);
581 else if (!strcmp(command, "dump")) {
582 if (!(arg = KMALLOC(4096, 0)))
583 return CFE_ERR_NOMEM;
584 bzero(arg, 4096);
585 if ((ret = etc_ioctl(et->etc, ETCDUMP, arg))) {
586 KFREE(arg);
587 return ret;
589 puts(arg);
590 KFREE(arg);
591 return 0;
593 else if (!strcmp(command, "msglevel")) {
594 cmd = ETCSETMSGLEVEL;
595 arg = cmd_getarg(cmdline, 1);
597 else if (!strcmp(command, "promisc")) {
598 cmd = ETCPROMISC;
599 arg = cmd_getarg(cmdline, 1);
601 else
602 return CFE_ERR_INV_PARAM;
604 if (!arg)
605 return CFE_ERR_INV_PARAM;
606 else if (arg != (char *) &val) {
607 val = bcm_strtoul(arg, NULL, 0);
608 arg = (char *) &val;
611 return etc_ioctl(et->etc, cmd, arg);
614 void
615 et_addcmd(void)
617 cmd_addcmd("et",
618 ui_cmd_et,
619 NULL,
620 "Broadcom Ethernet utility.",
621 "et command [args..]\n\n"
622 "Configures the specified Broadcom Ethernet interface.",
623 "-i=*;Specifies the interface|"
624 "up;Activate the specified interface|"
625 "down;Deactivate the specified interface|"
626 "loop;Sets the loopback mode (0,1)|"
627 "dump;Dump driver information|"
628 "msglevel;Sets the driver message level|"
629 "promisc;Sets promiscuous mode|");