2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright 2006, 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.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"
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>
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 */
46 struct et_info
*next
; /* pointer to next et_info_t in chain */
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
);
59 void et_intrson(et_info_t
*et
);
62 et_init(et_info_t
*et
)
64 ET_TRACE(("et%d: et_init\n", et
->etc
->unit
));
71 et_reset(et_info_t
*et
)
73 ET_TRACE(("et%d: et_reset\n", et
->etc
->unit
));
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")));
86 et_link_down(et_info_t
*et
)
88 ET_ERROR(("et%d: link down\n", et
->etc
->unit
));
97 ET_TRACE(("et%d: et_up\n", et
->etc
->unit
));
101 /* schedule one second watchdog timer */
102 TIMER_SET(et
->timer
, CFE_HZ
/ 2);
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
);
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>.
136 et_phyfind(et_info_t
*et
, uint coreunit
)
140 /* walk the list et's */
141 for (tmp
= et_list
; tmp
; tmp
= tmp
->next
) {
144 if (tmp
->etc
->coreunit
!= coreunit
)
151 /* shared phy read entry point */
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 */
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.
174 * drv - driver descriptor
175 * probe_a - device ID
176 * probe_b - unit number
177 * probe_ptr - mapped registers
181 ********************************************************************* */
184 et_probe(cfe_driver_t
*drv
,
185 unsigned long probe_a
, unsigned long probe_b
,
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
));
200 bzero(et
, sizeof(et_info_t
));
202 et
->osh
= osl_attach(et
);
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
));
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 */
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 /* *********************************************************************
229 * Open the Ethernet device. The MAC is reset, initialized, and
230 * prepared to receive and send packets.
233 * ctx - device context (includes ptr to our softc)
237 ********************************************************************* */
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
));
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.
256 * ctx - device context (includes ptr to our softc)
257 * buffer - pointer to buffer descriptor.
261 ********************************************************************* */
264 et_read(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
266 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
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)
284 if (!(p
= et
->etc
->chops
->rx(et
->etc
->ch
)))
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
));
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
);
318 PKTFREE(et
->osh
, p
, FALSE
);
321 /* post more rx bufs */
322 et
->etc
->chops
->rxfill(et
->etc
->ch
);
327 /* *********************************************************************
328 * ETHER_INPSTAT(ctx,inpstat)
330 * Check for received packets on the Ethernet device
333 * ctx - device context (includes ptr to our softc)
334 * inpstat - pointer to input status structure
338 ********************************************************************* */
341 et_inpstat(cfe_devctx_t
*ctx
, iocb_inpstat_t
*inpstat
)
343 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
346 events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
);
347 inpstat
->inp_status
= ((events
& INTR_RX
) ? 1 : 0);
352 /* *********************************************************************
353 * ETHER_WRITE(ctx,buffer)
355 * Write a packet to the Ethernet device.
358 * ctx - device context (includes ptr to our softc)
359 * buffer - pointer to buffer descriptor.
363 ********************************************************************* */
366 et_write(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
368 et_info_t
*et
= ctx
->dev_softc
;
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
);
395 /* *********************************************************************
396 * ETHER_IOCTL(ctx,buffer)
398 * Do device-specific I/O control operations for the device
401 * ctx - device context (includes ptr to our softc)
402 * buffer - pointer to buffer descriptor.
406 ********************************************************************* */
408 et_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
410 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
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
);
421 case IOCTL_ETHER_SETHWADDR
:
422 bcopy(buffer
->buf_ptr
, &et
->etc
->cur_etheraddr
, ETHER_ADDR_LEN
);
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
;
437 case IOCTL_ETHER_SETSPEED
:
438 val
= *((int *) buffer
->buf_ptr
);
439 if (val
== ETHER_SPEED_AUTO
)
441 else if (val
== ETHER_SPEED_10HDX
)
443 else if (val
== ETHER_SPEED_10FDX
)
445 else if (val
== ETHER_SPEED_100HDX
)
447 else if (val
== ETHER_SPEED_100FDX
)
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
;
457 case IOCTL_ETHER_GETLOOPBACK
:
458 *((int *) buffer
->buf_ptr
) = et
->etc
->loopbk
;
461 case IOCTL_ETHER_SETLOOPBACK
:
462 val
= *((int *) buffer
->buf_ptr
);
463 if (val
== ETHER_LOOPBACK_OFF
)
467 return etc_ioctl(et
->etc
, ETCLOOP
, &val
);
470 return CFE_ERR_UNSUPPORTED
;
477 /* *********************************************************************
480 * Close the Ethernet device.
483 * ctx - device context (includes ptr to our softc)
487 ********************************************************************* */
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);
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.
512 * ctx - device context (includes ptr to our softc)
513 * ticks- current time in ticks
517 ********************************************************************* */
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
= {
542 const cfe_driver_t bcmet
= {
551 ui_cmd_et(ui_cmdline_t
*cmdline
, int argc
, char *argv
[])
553 char *command
, *name
;
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
)
564 if (!(dev
= cfe_finddev(name
)) ||
566 return CFE_ERR_DEVNOTFOUND
;
567 for (et
= et_list
; et
; et
= et
->next
)
568 if (et
== dev
->dev_softc
)
570 if (!et
&& !(et
= et_list
))
571 return CFE_ERR_DEVNOTFOUND
;
573 if (!strcmp(command
, "up"))
575 else if (!strcmp(command
, "down"))
577 else if (!strcmp(command
, "loop")) {
579 arg
= cmd_getarg(cmdline
, 1);
581 else if (!strcmp(command
, "dump")) {
582 if (!(arg
= KMALLOC(4096, 0)))
583 return CFE_ERR_NOMEM
;
585 if ((ret
= etc_ioctl(et
->etc
, ETCDUMP
, arg
))) {
593 else if (!strcmp(command
, "msglevel")) {
594 cmd
= ETCSETMSGLEVEL
;
595 arg
= cmd_getarg(cmdline
, 1);
597 else if (!strcmp(command
, "promisc")) {
599 arg
= cmd_getarg(cmdline
, 1);
602 return CFE_ERR_INV_PARAM
;
605 return CFE_ERR_INV_PARAM
;
606 else if (arg
!= (char *) &val
) {
607 val
= bcm_strtoul(arg
, NULL
, 0);
611 return etc_ioctl(et
->etc
, cmd
, arg
);
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|");