2 * CFE polled-mode device driver for
3 * Broadcom BCM47XX 10/100 Mbps Ethernet Controller
5 * Copyright (C) 2012, Broadcom Corporation. All Rights Reserved.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
14 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
16 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
17 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * $Id: et_cfe.c 341899 2012-06-29 04:06:38Z $
23 #include "lib_types.h"
24 #include "lib_malloc.h"
25 #include "lib_string.h"
26 #include "lib_printf.h"
29 #include "cfe_device.h"
30 #include "cfe_ioctl.h"
31 #include "cfe_console.h"
32 #include "cfe_timer.h"
33 #include "cfe_error.h"
34 #include "ui_command.h"
39 #include <bcmendian.h>
40 #include <proto/ethernet.h>
42 #include <bcmenetmib.h>
43 #include <bcmenetrxh.h>
47 #include <bcmgmacrxh.h>
50 typedef struct et_info
{
51 etc_info_t
*etc
; /* pointer to common os-independent data */
52 cfe_devctx_t
*ctx
; /* backpoint to device */
53 int64_t timer
; /* one second watchdog timer */
55 struct et_info
*next
; /* pointer to next et_info_t in chain */
58 static et_info_t
*et_list
= NULL
;
60 void et_init(et_info_t
*et
, uint options
);
61 void et_reset(et_info_t
*et
);
62 void et_link_up(et_info_t
*et
);
63 void et_link_down(et_info_t
*et
);
64 int et_up(et_info_t
*et
);
65 int et_down(et_info_t
*et
, int reset
);
66 void et_dump(et_info_t
*et
, struct bcmstrbuf
*b
);
68 void et_intrson(et_info_t
*et
);
71 et_init(et_info_t
*et
, uint options
)
73 ET_TRACE(("et%d: et_init\n", et
->etc
->unit
));
76 etc_init(et
->etc
, options
);
80 et_reset(et_info_t
*et
)
82 ET_TRACE(("et%d: et_reset\n", et
->etc
->unit
));
88 et_link_up(et_info_t
*et
)
90 ET_ERROR(("et%d: link up (%d%s)\n",
91 et
->etc
->unit
, et
->etc
->speed
, (et
->etc
->duplex
? "FD" : "HD")));
95 et_link_down(et_info_t
*et
)
97 ET_ERROR(("et%d: link down\n", et
->etc
->unit
));
106 ET_TRACE(("et%d: et_up\n", et
->etc
->unit
));
110 /* schedule one second watchdog timer */
111 TIMER_SET(et
->timer
, CFE_HZ
/ 2);
117 et_down(et_info_t
*et
, int reset
)
119 ET_TRACE(("et%d: et_down\n", et
->etc
->unit
));
121 /* stop watchdog timer */
122 TIMER_CLEAR(et
->timer
);
124 etc_down(et
->etc
, reset
);
130 et_dump(et_info_t
*et
, struct bcmstrbuf
*b
)
133 etc_dump(et
->etc
, b
);
137 et_info_t
*et_phyfind(et_info_t
*et
, uint coreunit
);
138 uint16
et_phyrd(et_info_t
*et
, uint phyaddr
, uint reg
);
139 void et_phywr(et_info_t
*et
, uint reg
, uint phyaddr
, uint16 val
);
142 * 47XX-specific shared mdc/mdio contortion:
143 * Find the et associated with the same chip as <et>
144 * and coreunit matching <coreunit>.
147 et_phyfind(et_info_t
*et
, uint coreunit
)
151 /* walk the list et's */
152 for (tmp
= et_list
; tmp
; tmp
= tmp
->next
) {
155 if (tmp
->etc
->coreunit
!= coreunit
)
162 /* shared phy read entry point */
164 et_phyrd(et_info_t
*et
, uint phyaddr
, uint reg
)
166 return et
->etc
->chops
->phyrd(et
->etc
->ch
, phyaddr
, reg
);
169 /* shared phy write entry point */
171 et_phywr(et_info_t
*et
, uint phyaddr
, uint reg
, uint16 val
)
173 et
->etc
->chops
->phywr(et
->etc
->ch
, phyaddr
, reg
, val
);
176 /* *********************************************************************
177 * ETHER_PROBE(drv,probe_a,probe_b,probe_ptr)
179 * Probe and install driver.
180 * Create a context structure and attach to the
181 * specified network device.
184 * drv - driver descriptor
185 * probe_a - device ID
186 * probe_b - unit number
187 * probe_ptr - mapped registers
191 ********************************************************************* */
194 et_probe(cfe_driver_t
*drv
,
195 unsigned long probe_a
, unsigned long probe_b
,
203 device
= (uint16
) probe_a
;
204 unit
= (uint
) probe_b
;
206 if (!(et
= (et_info_t
*) KMALLOC(sizeof(et_info_t
), 0))) {
207 ET_ERROR(("et%d: KMALLOC failed\n", unit
));
210 bzero(et
, sizeof(et_info_t
));
212 et
->osh
= osl_attach(et
);
216 /* Make it chatty in simulation */
220 /* common load-time initialization */
221 if ((et
->etc
= etc_attach(et
, VENDOR_BROADCOM
, device
, unit
, et
->osh
, probe_ptr
)) == NULL
) {
222 ET_ERROR(("et%d: etc_attach failed\n", unit
));
227 /* this is a polling driver - the chip intmask stays zero */
228 et
->etc
->chops
->intrsoff(et
->etc
->ch
);
230 /* add us to the global linked list */
234 /* print hello string */
235 et
->etc
->chops
->longname(et
->etc
->ch
, name
, sizeof (name
));
236 printf("et%d: %s %s\n", unit
, name
, EPI_VERSION_STR
);
238 cfe_attach(drv
, et
, NULL
, name
);
241 /* *********************************************************************
244 * Open the Ethernet device. The MAC is reset, initialized, and
245 * prepared to receive and send packets.
248 * ctx - device context (includes ptr to our softc)
252 ********************************************************************* */
255 et_open(cfe_devctx_t
*ctx
)
257 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
259 ET_TRACE(("et%d: et_open\n", et
->etc
->unit
));
264 /* *********************************************************************
265 * ETHER_READ(ctx,buffer)
267 * Read a packet from the Ethernet device. If no packets are
268 * available, the read will succeed but return 0 bytes.
271 * ctx - device context (includes ptr to our softc)
272 * buffer - pointer to buffer descriptor.
276 ********************************************************************* */
279 et_read(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
281 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
288 ET_TRACE(("et%d: et_read\n", et
->etc
->unit
));
290 /* assume no packets */
291 buffer
->buf_retlen
= 0;
293 /* poll for packet */
294 events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
);
295 if (events
& INTR_ERROR
)
296 return CFE_ERR_IOERR
;
297 if ((events
& INTR_RX
) == 0)
301 if (!(p
= et
->etc
->chops
->rx(et
->etc
->ch
)))
304 /* packet buffer starts with rxhdr */
305 rxh
= (bcmenetrxh_t
*) PKTDATA(NULL
, p
);
307 /* strip off rxhdr */
308 PKTPULL(NULL
, p
, HWRXOFF
);
310 /* check for reported frame errors */
311 flags
= RXH_FLAGS(et
->etc
, rxh
);
313 bcm_ether_ntoa((struct ether_addr
*)
314 (((struct ether_header
*) PKTDATA(NULL
, p
))->ether_shost
), eabuf
);
315 if (RXH_OVERSIZE(et
->etc
, rxh
)) {
316 ET_ERROR(("et%d: rx: over size packet from %s\n", et
->etc
->unit
, eabuf
));
318 if (RXH_CRC(et
->etc
, rxh
)) {
319 ET_ERROR(("et%d: rx: crc error from %s\n", et
->etc
->unit
, eabuf
));
321 if (RXH_OVF(et
->etc
, rxh
)) {
322 ET_ERROR(("et%d: rx: fifo overflow\n", et
->etc
->unit
));
324 if (RXH_NO(et
->etc
, rxh
)) {
325 ET_ERROR(("et%d: rx: crc error (odd nibbles) from %s\n",
326 et
->etc
->unit
, eabuf
));
328 if (RXH_RXER(et
->etc
, rxh
)) {
329 ET_ERROR(("et%d: rx: symbol error from %s\n", et
->etc
->unit
, eabuf
));
332 bcopy(PKTDATA(NULL
, p
), buffer
->buf_ptr
, PKTLEN(NULL
, p
));
333 buffer
->buf_retlen
= PKTLEN(NULL
, p
);
334 ET_PRHDR("rx", (struct ether_header
*) buffer
->buf_ptr
,
335 buffer
->buf_retlen
, et
->etc
->unit
);
336 ET_PRPKT("rxpkt", buffer
->buf_ptr
, buffer
->buf_retlen
, et
->etc
->unit
);
340 PKTFREE(et
->osh
, p
, FALSE
);
343 /* post more rx bufs */
344 et
->etc
->chops
->rxfill(et
->etc
->ch
);
349 /* *********************************************************************
350 * ETHER_INPSTAT(ctx,inpstat)
352 * Check for received packets on the Ethernet device
355 * ctx - device context (includes ptr to our softc)
356 * inpstat - pointer to input status structure
360 ********************************************************************* */
363 et_inpstat(cfe_devctx_t
*ctx
, iocb_inpstat_t
*inpstat
)
365 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
368 events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
);
369 inpstat
->inp_status
= ((events
& INTR_RX
) ? 1 : 0);
374 /* *********************************************************************
375 * ETHER_WRITE(ctx,buffer)
377 * Write a packet to the Ethernet device.
380 * ctx - device context (includes ptr to our softc)
381 * buffer - pointer to buffer descriptor.
385 ********************************************************************* */
388 et_write(cfe_devctx_t
*ctx
, iocb_buffer_t
*buffer
)
390 et_info_t
*et
= ctx
->dev_softc
;
394 if (!(p
= PKTGET(NULL
, buffer
->buf_length
, TRUE
))) {
395 ET_ERROR(("et%d: PKTGET failed\n", et
->etc
->unit
));
396 return CFE_ERR_NOMEM
;
399 bcopy(buffer
->buf_ptr
, PKTDATA(NULL
, p
), buffer
->buf_length
);
401 ET_PRHDR("tx", (struct ether_header
*)PKTDATA(NULL
, p
), PKTLEN(NULL
, p
), et
->etc
->unit
);
402 ET_PRPKT("txpkt", PKTDATA(NULL
, p
), PKTLEN(NULL
, p
), et
->etc
->unit
);
404 ASSERT(*et
->etc
->txavail
[TX_Q0
] > 0);
406 /* transmit the frame */
407 et
->etc
->chops
->tx(et
->etc
->ch
, p
);
409 while (((events
= et
->etc
->chops
->getintrevents(et
->etc
->ch
, FALSE
)) & (INTR_ERROR
| INTR_TX
)) == 0);
411 /* reclaim any completed tx frames */
412 et
->etc
->chops
->txreclaim(et
->etc
->ch
, FALSE
);
414 return (events
& INTR_ERROR
) ? CFE_ERR_IOERR
: CFE_OK
;
417 /* *********************************************************************
418 * ETHER_IOCTL(ctx,buffer)
420 * Do device-specific I/O control operations for the device
423 * ctx - device context (includes ptr to our softc)
424 * buffer - pointer to buffer descriptor.
428 ********************************************************************* */
430 et_ioctl(cfe_devctx_t
*ctx
,iocb_buffer_t
*buffer
)
432 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
435 ET_TRACE(("et%d: et_ioctl: cmd 0x%x\n", et
->etc
->unit
, buffer
->buf_ioctlcmd
));
437 switch (buffer
->buf_ioctlcmd
) {
439 case IOCTL_ETHER_GETHWADDR
:
440 bcopy(&et
->etc
->cur_etheraddr
, buffer
->buf_ptr
, ETHER_ADDR_LEN
);
443 case IOCTL_ETHER_SETHWADDR
:
444 bcopy(buffer
->buf_ptr
, &et
->etc
->cur_etheraddr
, ETHER_ADDR_LEN
);
445 et_init(et
, ET_INIT_DEF_OPTIONS
);
448 case IOCTL_ETHER_GETSPEED
:
449 val
= ETHER_SPEED_UNKNOWN
;
450 if (et
->etc
->linkstate
) {
451 if (et
->etc
->speed
== 10)
452 val
= et
->etc
->duplex
? ETHER_SPEED_10FDX
: ETHER_SPEED_10HDX
;
453 else if (et
->etc
->speed
== 100)
454 val
= et
->etc
->duplex
? ETHER_SPEED_100FDX
: ETHER_SPEED_100HDX
;
455 else if (et
->etc
->speed
== 1000)
456 val
= ETHER_SPEED_1000FDX
;
458 *((int *) buffer
->buf_ptr
) = val
;
461 case IOCTL_ETHER_SETSPEED
:
462 val
= *((int *) buffer
->buf_ptr
);
463 if (val
== ETHER_SPEED_AUTO
)
465 else if (val
== ETHER_SPEED_10HDX
)
467 else if (val
== ETHER_SPEED_10FDX
)
469 else if (val
== ETHER_SPEED_100HDX
)
471 else if (val
== ETHER_SPEED_100FDX
)
473 else if (val
== ETHER_SPEED_1000FDX
)
476 return CFE_ERR_UNSUPPORTED
;
477 return etc_ioctl(et
->etc
, ETCSPEED
, &val
);
479 case IOCTL_ETHER_GETLINK
:
480 *((int *) buffer
->buf_ptr
) = (int) et
->etc
->linkstate
;
483 case IOCTL_ETHER_GETLOOPBACK
:
484 *((int *) buffer
->buf_ptr
) = et
->etc
->loopbk
;
487 case IOCTL_ETHER_SETLOOPBACK
:
488 val
= *((int *) buffer
->buf_ptr
);
489 if (val
== ETHER_LOOPBACK_OFF
)
493 return etc_ioctl(et
->etc
, ETCLOOP
, &val
);
496 return CFE_ERR_UNSUPPORTED
;
503 /* *********************************************************************
506 * Close the Ethernet device.
509 * ctx - device context (includes ptr to our softc)
513 ********************************************************************* */
516 et_close(cfe_devctx_t
*ctx
)
518 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
520 ET_TRACE(("et%d: et_close\n", et
->etc
->unit
));
522 return et_down(et
, 1);
526 et_intrson(et_info_t
*et
)
528 /* this is a polling driver - the chip intmask stays zero */
529 ET_TRACE(("et%d: et_intrson\n", et
->etc
->unit
));
532 /* *********************************************************************
533 * ETHER_POLL(ctx,ticks)
535 * Check for changes in the PHY, so we can track speed changes.
538 * ctx - device context (includes ptr to our softc)
539 * ticks- current time in ticks
543 ********************************************************************* */
546 et_poll(cfe_devctx_t
*ctx
, int64_t ticks
)
548 et_info_t
*et
= (et_info_t
*) ctx
->dev_softc
;
550 if (TIMER_RUNNING(et
->timer
) &&
551 TIMER_EXPIRED(et
->timer
)) {
552 etc_watchdog(et
->etc
);
553 TIMER_SET(et
->timer
, CFE_HZ
/ 2);
557 const static cfe_devdisp_t et_dispatch
= {
568 const cfe_driver_t bcmet
= {
577 ui_cmd_et(ui_cmdline_t
*cmdline
, int argc
, char *argv
[])
579 char *command
, *name
;
583 char *arg
= (char *) &val
;
585 if (!(command
= cmd_getarg(cmdline
, 0)))
586 return CFE_ERR_INV_PARAM
;
588 if (!cmd_sw_value(cmdline
, "-i", &name
) || !name
)
590 if (!(dev
= cfe_finddev(name
)) ||
592 return CFE_ERR_DEVNOTFOUND
;
593 for (et
= et_list
; et
; et
= et
->next
)
594 if (et
== dev
->dev_softc
)
596 if (!et
&& !(et
= et_list
))
597 return CFE_ERR_DEVNOTFOUND
;
599 if (!strcmp(command
, "up"))
601 else if (!strcmp(command
, "down"))
603 else if (!strcmp(command
, "loop")) {
605 arg
= cmd_getarg(cmdline
, 1);
607 else if (!strcmp(command
, "dump")) {
609 if (!(arg
= KMALLOC(IOCBUFSZ
, 0)))
610 return CFE_ERR_NOMEM
;
611 bzero(arg
, IOCBUFSZ
);
612 if ((ret
= etc_ioctl(et
->etc
, ETCDUMP
, arg
))) {
616 /* No puts in cfe, and printf only has a 512 byte buffer */
623 else if (!strcmp(command
, "msglevel")) {
624 cmd
= ETCSETMSGLEVEL
;
625 arg
= cmd_getarg(cmdline
, 1);
627 else if (!strcmp(command
, "promisc")) {
629 arg
= cmd_getarg(cmdline
, 1);
632 return CFE_ERR_INV_PARAM
;
635 return CFE_ERR_INV_PARAM
;
636 else if (arg
!= (char *) &val
) {
637 val
= bcm_strtoul(arg
, NULL
, 0);
641 return etc_ioctl(et
->etc
, cmd
, arg
);
650 "Broadcom Ethernet utility.",
651 "et command [args..]\n\n"
652 "Configures the specified Broadcom Ethernet interface.",
653 "-i=*;Specifies the interface|"
654 "up;Activate the specified interface|"
655 "down;Deactivate the specified interface|"
656 "loop;Sets the loopback mode (0,1)|"
657 "dump;Dump driver information|"
658 "msglevel;Sets the driver message level|"
659 "promisc;Sets promiscuous mode|");