2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright (C) 2010, Broadcom Corporation
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.25 2009-10-18 18:35:22 Exp $
16 #include "lib_types.h"
17 #include "lib_malloc.h"
18 #include "lib_string.h"
19 #include "lib_printf.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"
32 #include <bcmendian.h>
33 #include <proto/ethernet.h>
35 #include <bcmenetmib.h>
36 #include <bcmenetrxh.h>
40 #include <bcmgmacrxh.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 */
48 struct et_info
*next
; /* pointer to next et_info_t in chain */
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
);
61 void et_intrson(et_info_t
*et
);
64 et_init(et_info_t
*et
, uint options
)
66 ET_TRACE(("et%d: et_init\n", et
->etc
->unit
));
69 etc_init(et
->etc
, options
);
73 et_reset(et_info_t
*et
)
75 ET_TRACE(("et%d: et_reset\n", et
->etc
->unit
));
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")));
88 et_link_down(et_info_t
*et
)
90 ET_ERROR(("et%d: link down\n", et
->etc
->unit
));
99 ET_TRACE(("et%d: et_up\n", et
->etc
->unit
));
103 /* schedule one second watchdog timer */
104 TIMER_SET(et
->timer
, CFE_HZ
/ 2);
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
);
123 et_dump(et_info_t
*et
, struct bcmstrbuf
*b
)
126 etc_dump(et
->etc
, b
);
130 et_info_t
*et_phyfind(et_info_t
*et
, uint coreunit
);
131 uint16
et_phyrd(et_info_t
*et
, uint phyaddr
, uint reg
);
132 void et_phywr(et_info_t
*et
, uint reg
, uint phyaddr
, uint16 val
);
135 * 47XX-specific shared mdc/mdio contortion:
136 * Find the et associated with the same chip as <et>
137 * and coreunit matching <coreunit>.
140 et_phyfind(et_info_t
*et
, uint coreunit
)
144 /* walk the list et's */
145 for (tmp
= et_list
; tmp
; tmp
= tmp
->next
) {
148 if (tmp
->etc
->coreunit
!= coreunit
)
155 /* shared phy read entry point */
157 et_phyrd(et_info_t
*et
, uint phyaddr
, uint reg
)
159 return et
->etc
->chops
->phyrd(et
->etc
->ch
, phyaddr
, reg
);
162 /* shared phy write entry point */
164 et_phywr(et_info_t
*et
, uint phyaddr
, uint reg
, uint16 val
)
166 et
->etc
->chops
->phywr(et
->etc
->ch
, phyaddr
, reg
, val
);
169 /* *********************************************************************
170 * ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
172 * Probe and install driver.
173 * Create a context structure and attach to the
174 * specified network device.
177 * drv - driver descriptor
178 * probe_a - device ID
179 * probe_b - unit number
180 * probe_ptr - mapped registers
184 ********************************************************************* */
187 et_probe(cfe_driver_t
*drv
,
188 unsigned long probe_a
, unsigned long probe_b
,
196 device
= (uint16
) probe_a
;
197 unit
= (uint
) probe_b
;
199 if (!(et
= (et_info_t
*) KMALLOC(sizeof(et_info_t
), 0))) {
200 ET_ERROR(("et%d: KMALLOC failed\n", unit
));
203 bzero(et
, sizeof(et_info_t
));
205 et
->osh
= osl_attach(et
);
209 /* Make it chatty in simulation */
213 /* common load-time initialization */
214 if ((et
->etc
= etc_attach(et
, VENDOR_BROADCOM
, device
, unit
, et
->osh
, probe_ptr
)) == NULL
) {
215 ET_ERROR(("et%d: etc_attach failed\n", unit
));
220 /* this is a polling driver - the chip intmask stays zero */
221 et
->etc
->chops
->intrsoff(et
->etc
->ch
);
223 /* add us to the global linked list */
227 /* print hello string */
228 et
->etc
->chops
->longname(et
->etc
->ch
, name
, sizeof (name
));
229 printf("et%d: %s %s\n", unit
, name
, EPI_VERSION_STR
);
231 cfe_attach(drv
, et
, NULL
, name
);
234 /* *********************************************************************
237 * Open the Ethernet device. The MAC is reset, initialized, and
238 * prepared to receive and send packets.
241 * ctx - device context (includes ptr to our softc)
245 ********************************************************************* */
248 et_open(cfe_devctx_t
*ctx
)
250 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
252 ET_TRACE(("et%d: et_open\n", et
->etc
->unit
));
257 /* *********************************************************************
258 * ETHER_READ(ctx,buffer)
260 * Read a packet from the Ethernet device. If no packets are
261 * available, the read will succeed but return 0 bytes.
264 * ctx - device context (includes ptr to our softc)
265 * buffer - pointer to buffer descriptor.
269 ********************************************************************* */
272 et_read(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
274 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
281 ET_TRACE(("et%d: et_read\n", et
->etc
->unit
));
283 /* assume no packets */
284 buffer
->buf_retlen
= 0;
286 /* poll for packet */
287 events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
);
288 if (events
& INTR_ERROR
)
289 return CFE_ERR_IOERR
;
290 if ((events
& INTR_RX
) == 0)
294 if (!(p
= et
->etc
->chops
->rx(et
->etc
->ch
)))
297 /* packet buffer starts with rxhdr */
298 rxh
= (bcmenetrxh_t
*) PKTDATA(NULL
, p
);
300 /* strip off rxhdr */
301 PKTPULL(NULL
, p
, HWRXOFF
);
303 /* check for reported frame errors */
304 flags
= RXH_FLAGS(et
->etc
, rxh
);
306 bcm_ether_ntoa((struct ether_addr
*)
307 (((struct ether_header
*) PKTDATA(NULL
, p
))->ether_shost
), eabuf
);
308 if (RXH_OVERSIZE(et
->etc
, rxh
)) {
309 ET_ERROR(("et%d: rx: over size packet from %s\n", et
->etc
->unit
, eabuf
));
311 if (RXH_CRC(et
->etc
, rxh
)) {
312 ET_ERROR(("et%d: rx: crc error from %s\n", et
->etc
->unit
, eabuf
));
314 if (RXH_OVF(et
->etc
, rxh
)) {
315 ET_ERROR(("et%d: rx: fifo overflow\n", et
->etc
->unit
));
317 if (RXH_NO(et
->etc
, rxh
)) {
318 ET_ERROR(("et%d: rx: crc error (odd nibbles) from %s\n",
319 et
->etc
->unit
, eabuf
));
321 if (RXH_RXER(et
->etc
, rxh
)) {
322 ET_ERROR(("et%d: rx: symbol error from %s\n", et
->etc
->unit
, eabuf
));
325 bcopy(PKTDATA(NULL
, p
), buffer
->buf_ptr
, PKTLEN(NULL
, p
));
326 buffer
->buf_retlen
= PKTLEN(NULL
, p
);
327 ET_PRHDR("rx", (struct ether_header
*) buffer
->buf_ptr
,
328 buffer
->buf_retlen
, et
->etc
->unit
);
329 ET_PRPKT("rxpkt", buffer
->buf_ptr
, buffer
->buf_retlen
, et
->etc
->unit
);
333 PKTFREE(et
->osh
, p
, FALSE
);
336 /* post more rx bufs */
337 et
->etc
->chops
->rxfill(et
->etc
->ch
);
342 /* *********************************************************************
343 * ETHER_INPSTAT(ctx,inpstat)
345 * Check for received packets on the Ethernet device
348 * ctx - device context (includes ptr to our softc)
349 * inpstat - pointer to input status structure
353 ********************************************************************* */
356 et_inpstat(cfe_devctx_t
*ctx
, iocb_inpstat_t
*inpstat
)
358 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
361 events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
);
362 inpstat
->inp_status
= ((events
& INTR_RX
) ? 1 : 0);
367 /* *********************************************************************
368 * ETHER_WRITE(ctx,buffer)
370 * Write a packet to the Ethernet device.
373 * ctx - device context (includes ptr to our softc)
374 * buffer - pointer to buffer descriptor.
378 ********************************************************************* */
381 et_write(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
383 et_info_t
*et
= ctx
->dev_softc
;
387 if (!(p
= PKTGET(NULL
, buffer
->buf_length
, TRUE
))) {
388 ET_ERROR(("et%d: PKTGET failed\n", et
->etc
->unit
));
389 return CFE_ERR_NOMEM
;
392 bcopy(buffer
->buf_ptr
, PKTDATA(NULL
, p
), buffer
->buf_length
);
394 ET_PRHDR("tx", (struct ether_header
*)PKTDATA(NULL
, p
), PKTLEN(NULL
, p
), et
->etc
->unit
);
395 ET_PRPKT("txpkt", PKTDATA(NULL
, p
), PKTLEN(NULL
, p
), et
->etc
->unit
);
397 ASSERT(*et
->etc
->txavail
[TX_Q0
] > 0);
399 /* transmit the frame */
400 et
->etc
->chops
->tx(et
->etc
->ch
, p
);
402 while (((events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
)) & (INTR_ERROR
| INTR_TX
)) == 0);
404 /* reclaim any completed tx frames */
405 et
->etc
->chops
->txreclaim(et
->etc
->ch
, FALSE
);
407 return (events
& INTR_ERROR
) ? CFE_ERR_IOERR
: CFE_OK
;
410 /* *********************************************************************
411 * ETHER_IOCTL(ctx,buffer)
413 * Do device-specific I/O control operations for the device
416 * ctx - device context (includes ptr to our softc)
417 * buffer - pointer to buffer descriptor.
421 ********************************************************************* */
423 et_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
425 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
428 ET_TRACE(("et%d: et_ioctl: cmd 0x%x\n", et
->etc
->unit
, buffer
->buf_ioctlcmd
));
430 switch (buffer
->buf_ioctlcmd
) {
432 case IOCTL_ETHER_GETHWADDR
:
433 bcopy(&et
->etc
->cur_etheraddr
, buffer
->buf_ptr
, ETHER_ADDR_LEN
);
436 case IOCTL_ETHER_SETHWADDR
:
437 bcopy(buffer
->buf_ptr
, &et
->etc
->cur_etheraddr
, ETHER_ADDR_LEN
);
438 et_init(et
, ET_INIT_DEF_OPTIONS
);
441 case IOCTL_ETHER_GETSPEED
:
442 val
= ETHER_SPEED_UNKNOWN
;
443 if (et
->etc
->linkstate
) {
444 if (et
->etc
->speed
== 10)
445 val
= et
->etc
->duplex
? ETHER_SPEED_10FDX
: ETHER_SPEED_10HDX
;
446 else if (et
->etc
->speed
== 100)
447 val
= et
->etc
->duplex
? ETHER_SPEED_100FDX
: ETHER_SPEED_100HDX
;
448 else if (et
->etc
->speed
== 1000)
449 val
= ETHER_SPEED_1000FDX
;
451 *((int *) buffer
->buf_ptr
) = val
;
454 case IOCTL_ETHER_SETSPEED
:
455 val
= *((int *) buffer
->buf_ptr
);
456 if (val
== ETHER_SPEED_AUTO
)
458 else if (val
== ETHER_SPEED_10HDX
)
460 else if (val
== ETHER_SPEED_10FDX
)
462 else if (val
== ETHER_SPEED_100HDX
)
464 else if (val
== ETHER_SPEED_100FDX
)
466 else if (val
== ETHER_SPEED_1000FDX
)
469 return CFE_ERR_UNSUPPORTED
;
470 return etc_ioctl(et
->etc
, ETCSPEED
, &val
);
472 case IOCTL_ETHER_GETLINK
:
473 *((int *) buffer
->buf_ptr
) = (int) et
->etc
->linkstate
;
476 case IOCTL_ETHER_GETLOOPBACK
:
477 *((int *) buffer
->buf_ptr
) = et
->etc
->loopbk
;
480 case IOCTL_ETHER_SETLOOPBACK
:
481 val
= *((int *) buffer
->buf_ptr
);
482 if (val
== ETHER_LOOPBACK_OFF
)
486 return etc_ioctl(et
->etc
, ETCLOOP
, &val
);
489 return CFE_ERR_UNSUPPORTED
;
496 /* *********************************************************************
499 * Close the Ethernet device.
502 * ctx - device context (includes ptr to our softc)
506 ********************************************************************* */
509 et_close(cfe_devctx_t
*ctx
)
511 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
513 ET_TRACE(("et%d: et_close\n", et
->etc
->unit
));
515 return et_down(et
, 1);
519 et_intrson(et_info_t
*et
)
521 /* this is a polling driver - the chip intmask stays zero */
522 ET_TRACE(("et%d: et_intrson\n", et
->etc
->unit
));
525 /* *********************************************************************
526 * ETHER_POLL(ctx,ticks)
528 * Check for changes in the PHY, so we can track speed changes.
531 * ctx - device context (includes ptr to our softc)
532 * ticks- current time in ticks
536 ********************************************************************* */
539 et_poll(cfe_devctx_t
*ctx
, int64_t ticks
)
541 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
543 if (TIMER_RUNNING(et
->timer
) &&
544 TIMER_EXPIRED(et
->timer
)) {
545 etc_watchdog(et
->etc
);
546 TIMER_SET(et
->timer
, CFE_HZ
/ 2);
550 const static cfe_devdisp_t et_dispatch
= {
561 const cfe_driver_t bcmet
= {
570 ui_cmd_et(ui_cmdline_t
*cmdline
, int argc
, char *argv
[])
572 char *command
, *name
;
576 char *arg
= (char *) &val
;
578 if (!(command
= cmd_getarg(cmdline
, 0)))
579 return CFE_ERR_INV_PARAM
;
581 if (!cmd_sw_value(cmdline
, "-i", &name
) || !name
)
583 if (!(dev
= cfe_finddev(name
)) ||
585 return CFE_ERR_DEVNOTFOUND
;
586 for (et
= et_list
; et
; et
= et
->next
)
587 if (et
== dev
->dev_softc
)
589 if (!et
&& !(et
= et_list
))
590 return CFE_ERR_DEVNOTFOUND
;
592 if (!strcmp(command
, "up"))
594 else if (!strcmp(command
, "down"))
596 else if (!strcmp(command
, "loop")) {
598 arg
= cmd_getarg(cmdline
, 1);
600 else if (!strcmp(command
, "dump")) {
602 if (!(arg
= KMALLOC(4096, 0)))
603 return CFE_ERR_NOMEM
;
605 if ((ret
= etc_ioctl(et
->etc
, ETCDUMP
, arg
))) {
609 /* No puts in cfe, and printf only has a 512 byte buffer */
616 else if (!strcmp(command
, "msglevel")) {
617 cmd
= ETCSETMSGLEVEL
;
618 arg
= cmd_getarg(cmdline
, 1);
620 else if (!strcmp(command
, "promisc")) {
622 arg
= cmd_getarg(cmdline
, 1);
625 return CFE_ERR_INV_PARAM
;
628 return CFE_ERR_INV_PARAM
;
629 else if (arg
!= (char *) &val
) {
630 val
= bcm_strtoul(arg
, NULL
, 0);
634 return etc_ioctl(et
->etc
, cmd
, arg
);
643 "Broadcom Ethernet utility.",
644 "et command [args..]\n\n"
645 "Configures the specified Broadcom Ethernet interface.",
646 "-i=*;Specifies the interface|"
647 "up;Activate the specified interface|"
648 "down;Deactivate the specified interface|"
649 "loop;Sets the loopback mode (0,1)|"
650 "dump;Dump driver information|"
651 "msglevel;Sets the driver message level|"
652 "promisc;Sets promiscuous mode|");