2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright (C) 2008, 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.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"
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
)
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>.
137 et_phyfind(et_info_t
*et
, uint coreunit
)
141 /* walk the list et's */
142 for (tmp
= et_list
; tmp
; tmp
= tmp
->next
) {
145 if (tmp
->etc
->coreunit
!= coreunit
)
152 /* shared phy read entry point */
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 */
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.
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
);
224 /* Make it chatty in simulation */
228 cfe_attach(drv
, et
, NULL
, name
);
231 /* *********************************************************************
234 * Open the Ethernet device. The MAC is reset, initialized, and
235 * prepared to receive and send packets.
238 * ctx - device context (includes ptr to our softc)
242 ********************************************************************* */
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
));
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.
261 * ctx - device context (includes ptr to our softc)
262 * buffer - pointer to buffer descriptor.
266 ********************************************************************* */
269 et_read(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
271 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
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)
291 if (!(p
= et
->etc
->chops
->rx(et
->etc
->ch
)))
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
);
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
));
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
);
330 PKTFREE(et
->osh
, p
, FALSE
);
333 /* post more rx bufs */
334 et
->etc
->chops
->rxfill(et
->etc
->ch
);
339 /* *********************************************************************
340 * ETHER_INPSTAT(ctx,inpstat)
342 * Check for received packets on the Ethernet device
345 * ctx - device context (includes ptr to our softc)
346 * inpstat - pointer to input status structure
350 ********************************************************************* */
353 et_inpstat(cfe_devctx_t
*ctx
, iocb_inpstat_t
*inpstat
)
355 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
358 events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
);
359 inpstat
->inp_status
= ((events
& INTR_RX
) ? 1 : 0);
364 /* *********************************************************************
365 * ETHER_WRITE(ctx,buffer)
367 * Write a packet to the Ethernet device.
370 * ctx - device context (includes ptr to our softc)
371 * buffer - pointer to buffer descriptor.
375 ********************************************************************* */
378 et_write(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
380 et_info_t
*et
= ctx
->dev_softc
;
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
413 * ctx - device context (includes ptr to our softc)
414 * buffer - pointer to buffer descriptor.
418 ********************************************************************* */
420 et_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
422 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
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
);
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
);
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
;
451 case IOCTL_ETHER_SETSPEED
:
452 val
= *((int *) buffer
->buf_ptr
);
453 if (val
== ETHER_SPEED_AUTO
)
455 else if (val
== ETHER_SPEED_10HDX
)
457 else if (val
== ETHER_SPEED_10FDX
)
459 else if (val
== ETHER_SPEED_100HDX
)
461 else if (val
== ETHER_SPEED_100FDX
)
463 else if (val
== ETHER_SPEED_1000FDX
)
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
;
473 case IOCTL_ETHER_GETLOOPBACK
:
474 *((int *) buffer
->buf_ptr
) = et
->etc
->loopbk
;
477 case IOCTL_ETHER_SETLOOPBACK
:
478 val
= *((int *) buffer
->buf_ptr
);
479 if (val
== ETHER_LOOPBACK_OFF
)
483 return etc_ioctl(et
->etc
, ETCLOOP
, &val
);
486 return CFE_ERR_UNSUPPORTED
;
493 /* *********************************************************************
496 * Close the Ethernet device.
499 * ctx - device context (includes ptr to our softc)
503 ********************************************************************* */
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);
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.
528 * ctx - device context (includes ptr to our softc)
529 * ticks- current time in ticks
533 ********************************************************************* */
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
= {
558 const cfe_driver_t bcmet
= {
567 ui_cmd_et(ui_cmdline_t
*cmdline
, int argc
, char *argv
[])
569 char *command
, *name
;
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
)
580 if (!(dev
= cfe_finddev(name
)) ||
582 return CFE_ERR_DEVNOTFOUND
;
583 for (et
= et_list
; et
; et
= et
->next
)
584 if (et
== dev
->dev_softc
)
586 if (!et
&& !(et
= et_list
))
587 return CFE_ERR_DEVNOTFOUND
;
589 if (!strcmp(command
, "up"))
591 else if (!strcmp(command
, "down"))
593 else if (!strcmp(command
, "loop")) {
595 arg
= cmd_getarg(cmdline
, 1);
597 else if (!strcmp(command
, "dump")) {
599 if (!(arg
= KMALLOC(4096, 0)))
600 return CFE_ERR_NOMEM
;
602 if ((ret
= etc_ioctl(et
->etc
, ETCDUMP
, arg
))) {
606 /* No puts in cfe, and printf only has a 512 byte buffer */
613 else if (!strcmp(command
, "msglevel")) {
614 cmd
= ETCSETMSGLEVEL
;
615 arg
= cmd_getarg(cmdline
, 1);
617 else if (!strcmp(command
, "promisc")) {
619 arg
= cmd_getarg(cmdline
, 1);
622 return CFE_ERR_INV_PARAM
;
625 return CFE_ERR_INV_PARAM
;
626 else if (arg
!= (char *) &val
) {
627 val
= bcm_strtoul(arg
, NULL
, 0);
631 return etc_ioctl(et
->etc
, cmd
, arg
);
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|");