BCM WL 6.30.102.9 (r366174)
[tomato.git] / release / src-rt / cfe / cfe / arch / mips / board / bcm9635x / src / dev_bcm635x_enet.c
blob6d6b37ca2f9fbbbebe0f12587055382071a6f857
1 /*
2 <:copyright-broadcom
4 Copyright (c) 2002 Broadcom Corporation
5 All Rights Reserved
6 No portions of this material may be reproduced in any form without the
7 written permission of:
8 Broadcom Corporation
9 16215 Alton Parkway
10 Irvine, California 92619
11 All information contained in this document is Broadcom Corporation
12 company private, proprietary, and trade secret.
16 //**************************************************************************
17 // File Name : bcm6352Enet.c
19 // Description: This is the CFE network driver for the BCM6352 Ethenet Switch
20 //
21 // Updates : 09/26/2001 jefchiao. Created.
22 // 05/21/2002 lat. Port to CFE.
23 //**************************************************************************
25 #define CARDNAME "BCM6352_ENET"
26 #define VERSION "0.1"
27 #define VER_STR "v" VERSION " " __DATE__ " " __TIME__
29 /* Includes. */
30 #include "lib_types.h"
31 #include "lib_malloc.h"
32 #include "lib_string.h"
33 #include "lib_printf.h"
35 #include "cfe_iocb.h"
36 #include "cfe_ioctl.h"
37 #include "cfe_device.h"
38 #include "cfe_devfuncs.h"
39 #include "sbmips.h"
40 #include "board.h"
41 #include "dev_bcm635x_enet.h"
42 #include "ethersw.h"
43 #include "dev_bcm63xx_flash.h"
45 /* Externs. */
46 extern cfe_driver_t flashdrv;
47 extern void udelay(long us);
48 extern NVRAM_DATA nvramData;
50 /* Prototypes. */
51 static void bcm6352_enet_probe( cfe_driver_t *drv, unsigned long probe_a,
52 unsigned long probe_b, void *probe_ptr );
53 static void ext_mii_check(void);
54 static void port_control(int portId, int enable);
55 static void init_arl(void);
56 static void init_mii(bcm6352enet_softc *softc);
57 static void init_dma(bcm6352enet_softc *softc);
58 static int bcm6352_init_dev(bcm6352enet_softc *softc);
59 int internal_open( bcm6352enet_softc *softc );
60 void write_mac_address( bcm6352enet_softc *softc );
61 static int bcm6352_enet_open(cfe_devctx_t *ctx);
62 static int bcm6352_enet_read( cfe_devctx_t *ctx, iocb_buffer_t *buffer );
63 static int bcm6352_enet_inpstat( cfe_devctx_t *ctx, iocb_inpstat_t *inpstat );
64 static int bcm6352_enet_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
65 static int bcm6352_enet_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
66 static int bcm6352_enet_close(cfe_devctx_t *ctx);
68 /* Globals. */
69 volatile uint32_t *swreg32 = (uint32_t *) ESWITCH_BASE;
70 volatile uint16_t *swreg16 = (uint16_t *) ESWITCH_BASE;
71 volatile unsigned char *swreg8 = (unsigned char *) ESWITCH_BASE;
72 volatile BusBridge *bridge = (BusBridge *) BB_BASE;
74 const static cfe_devdisp_t bcm6352_enet_dispatch =
76 bcm6352_enet_open,
77 bcm6352_enet_read,
78 bcm6352_enet_inpstat,
79 bcm6352_enet_write,
80 bcm6352_enet_ioctl,
81 bcm6352_enet_close,
82 NULL,
83 NULL
86 const cfe_driver_t bcm6352_enet =
88 "BCM6352 Ethernet",
89 "eth",
90 CFE_DEV_NETWORK,
91 &bcm6352_enet_dispatch,
92 bcm6352_enet_probe
96 /* --------------------------------------------------------------------------
97 Name: bcm6352_enet_probe
98 Purpose: Initial call to this driver.
99 -------------------------------------------------------------------------- */
100 static void bcm6352_enet_probe( cfe_driver_t *drv, unsigned long probe_a,
101 unsigned long probe_b, void * probe_ptr )
103 bcm6352enet_softc *softc;
104 char descr[100];
106 softc = (bcm6352enet_softc *) KMALLOC( sizeof(bcm6352enet_softc), 0 );
107 if( softc == NULL )
108 xprintf( "BCM6352 : Failed to allocate softc memory.\n" );
109 else
111 memset( softc, 0, sizeof(bcm6352enet_softc) );
113 if (internal_open( softc ) == -1)
114 xprintf("Failed initializing enet hardware\n");
115 else
117 cfe_attach( drv, softc, NULL, descr );
118 cfe_attach(&flashdrv, softc, NULL, NULL);
125 * ext_mii_check - checking external MII status, update MII port state override
126 * register if link up/down, duplex, or speed change.
128 static void ext_mii_check(void)
130 int change;
131 uint16_t miiaddr0a;
132 uint16_t miiaddr32;
133 uint16_t miiaddr30;
134 uint16_t data16bit;
135 uint16_t transtimer;
136 uint16_t status = 0;
138 transtimer = bridge->status;
139 bridge->status = transtimer & ~0x3FF;
140 /* read auto-negotiation link partner ability */
141 miiaddr0a = swreg16[(PORT1_MII_dp+ANLPA_d)/2];
142 udelay(10);
144 /* read auxiliary status summary */
145 miiaddr32 = swreg16[(PORT1_MII_dp+ASTSSUM_d)/2];
146 udelay(10);
148 /* read auxiliary control/status */
149 miiaddr30 = swreg16[(PORT1_MII_dp+ACTLSTS_d)/2];
150 udelay(10);
152 /* enable ISB abort timer */
153 transtimer = bridge->status;
154 bridge->status = transtimer | 0x3FF;
156 /* update link partner has pasue capability */
157 status |= ((miiaddr0a & 0x0400) != 0 ? 0x0008 : 0);
158 /* update current speed indication */
159 status |= ((miiaddr32 & 0x0008) != 0 ? 0 : 0x0004);
160 /* update current link status */
161 status |= ((miiaddr32 & 0x0004) != 0 ? 0x0001 : 0);
162 /* update current duplex indication */
163 status |= ((miiaddr30 & 0x0001) != 0 ? 0x0002 : 0);
166 data16bit = swreg16[(CTLREG_dp+MII_PSTS_d)/2];
167 data16bit &= 0x000F;
168 change = (data16bit ^ status) != 0 ? 1 : 0;
169 if (change) {
170 udelay(10);
171 /* set MII port state override register for port 1 (external PHY) */
172 swreg16[(CTLREG_dp+MII_PSTS_d)/2] = 0xfff0 | status;
178 * port_control: enable/disable rx functions of the port at the MAC level
180 static void port_control(int portId, int enable)
182 unsigned char data8bit;
183 int addr;
185 switch(portId) {
186 case 0:
187 addr = TH_PCTL0_d;
188 break;
189 case 1:
190 addr = TH_PCTL1_d;
191 break;
192 default:
193 return;
197 * disable rx function.
198 * if disable tx function, it has potential race condition if DMA still
199 * has frames need to sending out and it will block the DMA.
201 data8bit = swreg8[(CTLREG_dp + addr)];
202 if (enable)
203 data8bit &= ~RX_DISABLE; // clear RX_DISABLE bit
204 else
205 data8bit |= RX_DISABLE; // set RX_DISABLE bit
206 swreg8[(CTLREG_dp + addr)] = data8bit;
211 * init_arl: initialise ARL table memory
213 * Parameter: None
215 * Note:
217 * There are 1K entries in the arl table. However, they are not
218 * physically located consecutively. Each arl entry is a 64-bit
219 * word. It takes 10 bits to address 1K entries. The addressing
220 * scheme is as follows :
222 * Logical address : addr[9:0]
224 * Physical address : { addr[9:5], 3'b111, addr[4:0] }
226 * Please note that the addresses above are 64-bit word addresses,
227 * not byte addresses.
229 * Pattern for initializing table is:
231 * swreg32[(MEM_dp+MEMDAT_d)/4] = 0x0; (make DAT = 0)
232 * swreg32[(MEM_dp+MEMDAT_d+4)/4] = 0x0;
234 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x800e0;
235 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x800e1;
236 * ....
237 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x800fe;
238 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x800ff; (32 entries )
240 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x801e0;
241 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x801e1;
242 * ....
243 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x801fe;
244 * swreg32[(MEM_dp+MEMADR_d)/4] = 0x801ff; (another 32 entries)
245 * ....
247 static void init_arl(void)
249 int bits_9_5;
250 int bits_4_0;
252 swreg32[(MEM_dp+MEMDAT_d)/4] = 0x0; /*make DAT = 0*/
253 swreg32[(MEM_dp+MEMDAT_d)/4 + 1] = 0x0;
255 for ( bits_9_5 = 0x0; bits_9_5 <= 0x1f; bits_9_5++ ) {
256 for ( bits_4_0 = 0x0; bits_4_0 <= 0x1f; bits_4_0++ ) {
257 swreg32[(MEM_dp+MEMADR_d)/4] = 0x800e0 | bits_9_5 << 8 | bits_4_0;
264 * init_mii: Initializes the Ethernet Switch control registers
266 static void init_mii(bcm6352enet_softc *softc)
268 uint16_t transtimer;
269 uint16_t data16bit;
271 /* initialize the memeory */
272 init_arl(); /* clear ARL table */
274 /* set up SMP as the manamgement port */
275 swreg32[(MNGMODE_dp+GMNGCFG_d)/4] = SMP_PORT;
276 swreg32[(MNGMODE_dp+MNGPID_d)/4] = SMP_PORT_ID;
278 /* enable software forwarding */
279 if (test_bit(0, &softc->dualMacMode)) {
280 swreg32[(CTLREG_dp+TH_PCTL0_d)/4] = FORWARDING_STATE | RX_DISABLE;
281 swreg32[(CTLREG_dp+TH_PCTL1_d)/4] = FORWARDING_STATE | RX_DISABLE;
282 } else {
283 swreg32[(CTLREG_dp+TH_PCTL0_d)/4] = FORWARDING_STATE;
284 swreg32[(CTLREG_dp+TH_PCTL1_d)/4] = FORWARDING_STATE;
286 swreg32[(CTLREG_dp+SWMODE_d)/4] = SW_FWDG_EN|MANAGED_MODE;
288 /* set the MIB autocast header length */
289 swreg32[(MIBACST_dp+ACSTHDLT_d)/4] = 0x5555;
291 /* enable broadcast packets */
292 swreg32[(CTLREG_dp+SMP_CTL_d) /4] = 0x04;
294 /* correct the default congestion registers to allow 10BT mode
295 * (the defaults will be fixed in B0) */
296 swreg16[(CNGMREG_dp + 0x02) /2] = 0x0408;
297 swreg16[(CNGMREG_dp + 0x04) /2] = 0x000D;
298 swreg16[(CNGMREG_dp + 0x06) /2] = 0x070A;
299 swreg16[(CNGMREG_dp + 0x08) /2] = 0x000D;
300 swreg16[(CNGMREG_dp + 0x0e) /2] = 0x0C12;
301 swreg16[(CNGMREG_dp + 0x10) /2] = 0x001D;
303 // disable ISB abort timer for MII port 1 access
304 // from/to external Ethernet PHY, the transaction will
305 // terminate prematurely due to an early timeout.
306 transtimer = bridge->status;
307 bridge->status = transtimer & ~0x3FF;
308 transtimer = bridge->status;
310 // set MII Auxiliary Mode 2 register for port 1 (external PHY)
311 // set Activity/Link LED Mode bit for external PHY LED goes active
312 // upon acquiring link and pulses during receive or transmit activity
313 data16bit = swreg16[(PORT1_MII_dp+AMODE2_d)/2];
314 data16bit |= 0x0004;
315 udelay(10);
316 swreg16[(PORT1_MII_dp+AMODE2_d)/2] = data16bit;
317 udelay(10);
319 /* advertise pause capability on MII port 1 */
320 data16bit = swreg16[(PORT1_MII_dp+ANADV_d)/2];
321 data16bit |= 0x0400;
322 udelay(10);
323 swreg16[(PORT1_MII_dp+ANADV_d)/2] = data16bit;
324 udelay(10);
326 /* enable HP Auto-MDIX on MII port 1 */
327 data16bit = swreg16[(PORT1_MII_dp+AEGSTS_d)/2];
328 data16bit &= ~0x0800;
329 udelay(10);
330 swreg16[(PORT1_MII_dp+AEGSTS_d)/2] = data16bit;
331 udelay(10);
333 // enable ISB abort timer
334 transtimer = bridge->status;
335 bridge->status = transtimer | 0x3FF;
336 transtimer = bridge->status;
338 * set MII port state override register for port 1 (external PHY)
339 * set full duplex and 100Mbs (bit 2: 0 for 100Mbs, 1 for 10Mbs)
341 swreg16[(CTLREG_dp+MII_PSTS_d)/2] = 0xfffb;
346 * init_dma: Initialize DMA control register
348 static void init_dma(bcm6352enet_softc *softc)
350 volatile DmaChannel *txDma = softc->txDma;
351 volatile DmaChannel *rxDma = softc->rxDma;
353 // transmit
354 txDma->cfg = 0; /* initialize first (will enable later) */
355 txDma->maxBurst = DMA_MAX_BURST_LENGTH;
356 txDma->intMask = 0; /* mask all ints */
357 txDma->intStat = DMA_DONE|DMA_NO_DESC|DMA_BUFF_DONE;
358 txDma->startAddr = (uint32_t) K1_TO_PHYS((uint32_t)softc->txBufPtr);
360 // receive
361 rxDma->cfg = 0; // initialize first (will enable later)
362 rxDma->maxBurst = DMA_MAX_BURST_LENGTH;
363 rxDma->startAddr = (uint32_t)K1_TO_PHYS((uint32_t)softc->rxFirstBdPtr);
364 rxDma->length = softc->nrRxBds;
365 rxDma->fcThreshold = 0;
366 rxDma->numAlloc = 0;
367 rxDma->intMask = 0; /* mask all ints */
368 /* clr any pending interrupts on channel */
369 rxDma->intStat = DMA_DONE|DMA_NO_DESC|DMA_BUFF_DONE;
370 /* set to interrupt on packet complete and no descriptor available */
371 rxDma->intMask = 0;
372 /* configure DMA channels and enable Rx */
373 rxDma->cfg = DMA_CHAINING|DMA_WRAP_EN;
378 * bcm6352_init_dev: initialize Ethernet Switch device,
379 * allocate Tx/Rx buffer descriptors pool, Tx control block pool.
381 static int bcm6352_init_dev(bcm6352enet_softc *softc)
383 unsigned long i, j;
384 unsigned char *p = NULL;
386 /* make sure emac clock is on */
387 INTC->blkEnables |= (ESWITCH_CLK_EN | EPHY_CLK_EN);
389 /* setup buffer/pointer relationships here */
390 softc->nrRxBds = NR_RX_BDS;
391 softc->rxBufLen = ENET_MAX_MTU_SIZE;
393 /* init rx/tx dma channels */
394 softc->dmaChannels = (DmaChannel *)(DMA_BASE);
395 softc->rxDma = &softc->dmaChannels[EMAC_RX_CHAN];
396 softc->txDma = &softc->dmaChannels[EMAC_TX_CHAN];
398 p = (unsigned char *) (((uint32_t) softc->txBuf + 0x10) & ~0x0f);
399 softc->txBufPtr = (unsigned char *)K0_TO_K1((uint32_t) p);
401 p = (unsigned char *) (((uint32_t) softc->rxMem + 0x10) & ~0x0f);
402 softc->rxBds = (DmaDesc *)K0_TO_K1((uint32_t) p);
403 p += softc->nrRxBds * sizeof(DmaDesc);
404 softc->rxBuffers = (unsigned char *) K0_TO_PHYS((uint32_t) p);
406 /* initialize rx ring pointer variables. */
407 softc->rxBdAssignPtr = softc->rxBdReadPtr = softc->rxBds;
408 softc->rxFirstBdPtr = softc->rxBds;
409 softc->rxLastBdPtr = softc->rxFirstBdPtr + softc->nrRxBds - 1;
411 /* init the receive buffer descriptor ring */
412 for (i = 0, j = (unsigned long) softc->rxBuffers; i < softc->nrRxBds;
413 i++, j += softc->rxBufLen)
415 (softc->rxFirstBdPtr + i)->length = softc->rxBufLen;
416 (softc->rxFirstBdPtr + i)->address = j;
417 (softc->rxFirstBdPtr + i)->status = DMA_OWN;
419 softc->rxLastBdPtr->status = DMA_OWN | DMA_WRAP;
421 /* init dma registers */
422 init_dma(softc);
424 /* init switch control registers */
425 init_mii(softc);
427 softc->rxDma->cfg |= DMA_ENABLE;
429 /* if we reach this point, we've init'ed successfully */
430 return 0;
435 * internal_open - initialize Ethernet device
437 int internal_open( bcm6352enet_softc *softc )
439 int status;
440 int i;
441 unsigned char macAddr[ETH_ALEN];
442 int dualMacMode = 0;
444 /* figure out which chip we're running on */
445 softc->chipId = (INTC->RevID & 0xFFFF0000) >> 16;
446 softc->chipRev = (INTC->RevID & 0xFF);
448 /* print the ChipID and module version info */
449 printf("Broadcom BCM%X%X Ethernet Network Device ",
450 softc->chipId, softc->chipRev);
451 printf(VER_STR "\n");
453 clear_bit(0, &softc->dualMacMode);
455 /* read NVRam setting on route mode or switch mode */
456 dualMacMode = nvramData.ulEnetModeFlag;
458 if (dualMacMode == 1)
459 set_bit(0, &softc->dualMacMode);
461 printf("bcm6352Enet configure as %s mode\n",
462 softc->dualMacMode ? "MAC Isolation" : "Switching");
464 if( (status = bcm6352_init_dev(softc)) == 0 )
466 /* Read first MAC address. Only use first MAC even if dual MAC is
467 * configured.
469 macAddr[0] = 0xff;
470 memcpy(macAddr, nvramData.ucaBaseMacAddr, sizeof(macAddr));
472 if( macAddr[0] == 0xff )
473 memcpy( macAddr, "\x00\x10\x18\x00\x00\x01", 6 );
475 /* fill in the MAC address */
476 for (i = 0; i < 6; i++)
477 softc->macAddr[i] = macAddr[i];
479 printf( "MAC Address: %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n",
480 macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4],
481 macAddr[5], macAddr[6], macAddr[7] );
483 write_mac_address(softc);
486 return( status );
491 * write_mac_address: store MAC address into ARL table
493 * NOTE: THE MAC ADDRESS MUST BE NIBBLE-SWAPPED AND BIT-FLIPPED FOR THE
494 * ARL TABLE
496 void write_mac_address( bcm6352enet_softc *softc )
498 unsigned char data8bit;
499 int i;
500 int j;
502 if (test_bit(0, &softc->dualMacMode)) {
503 unsigned char *addr;
505 /* set to dual mac mode if in single mac mode*/
506 if (!test_and_set_bit(1, &softc->dualMacMode)) {
507 /* set secure source port mask */
508 /* bit mask identifies port 0 and port 1 initiates a secure VPN session */
509 swreg16[(ARLCTL_dp + SEC_SPMSK_d) /2] = 0x0003;
510 /* set secure destination port mask */
512 *bit mask identifies SMP port which is designated as
513 * the secure destination
515 swreg16[(ARLCTL_dp + SEC_DPMSK_d) /2] = 0x0400;
517 /* disable unicast packets */
519 * if RX-UCST_EN bit enable, it will only receive unknown unicast.
520 * To receive known unicast, it should set MIRROR_ENABLE and
521 * IN_MIRROR_FILTER, or MULTIPORT VECTOR/ADDRESS registers
523 data8bit = swreg8[(CTLREG_dp + SMP_CTL_d)];
524 data8bit &= ~0x10; // disable RX_UCST_EN bit
525 swreg8[(CTLREG_dp + SMP_CTL_d)] = data8bit;
527 /* Enable Multiport Address */
528 swreg8[(ARLCTL_dp + GARLCFG_d)] = 0x10;
530 /* Set Multiport Vector 1 to port 10 */
531 swreg16[(ARLCTL_dp + PORTVEC1_d)/2] = 0x0400;
533 /* Set Multiport Vector 2 to port 10 */
534 swreg16[(ARLCTL_dp + PORTVEC2_d)/2] = 0x0400;
537 /* Only set first MAC address */
538 j = GRPADDR1_d;
539 addr = softc->macAddr;
540 swreg32[(ARLCTL_dp+j)/4] =
541 ((*(uint16_t *)(addr+2))<<16) | *(uint16_t *)(addr+4);
542 swreg16[(ARLCTL_dp+j+4)/2] = *(uint16_t *)addr;
544 else {
545 unsigned char tempAddress[ETH_ALEN];
546 unsigned char flippedAddress[ETH_ALEN];
548 memset(flippedAddress, 0x00, ETH_ALEN);
549 /* set to single mac mode if in dual mac mode */
550 if (test_and_clear_bit(1, &softc->dualMacMode)) {
551 /* secure source port mask */
552 swreg16[(ARLCTL_dp + SEC_SPMSK_d) /2] = 0x0000;
553 /* secure destination port mask */
554 swreg16[(ARLCTL_dp + SEC_DPMSK_d) /2] = 0x0000;
556 /* enable unicast packets */
557 data8bit = swreg8[(CTLREG_dp + SMP_CTL_d)];
558 data8bit |= 0x10; // enable RX_UCST_EN bit
559 swreg8[(CTLREG_dp + SMP_CTL_d)] = data8bit;
561 /* disable multiport address */
562 swreg8[(ARLCTL_dp + GARLCFG_d)] = 0x00;
565 memcpy(tempAddress, softc->macAddr, ETH_ALEN);
566 /* nibble-swap and bit-flip */
567 for(i=0; i<6; i++)
569 for(j=0; j<7; j++)
571 flippedAddress[i] |= tempAddress[i] & 0x01;
572 flippedAddress[i] <<= 1;
573 tempAddress[i] >>= 1;
575 flippedAddress[i] |= tempAddress[i] & 0x01;
578 /* storing to ARL table */
579 swreg32[(ARLACCS_dp+ARLA_ENTRY0_d)/4] =
580 ((*(uint16_t *)&flippedAddress[2])<<16) | *(uint16_t *)&flippedAddress[4];
581 swreg32[(ARLACCS_dp+ARLA_ENTRY0_d+4)/4] =
582 0xc0000000 | *(uint16_t *)&flippedAddress[0] | (MANAGEMENT_PORT << 16);
583 swreg32[(ARLACCS_dp+ARLA_MAC_d)/4] =
584 ((*(uint16_t *)&flippedAddress[2])<<16) | *(uint16_t *)&flippedAddress[4];
585 swreg32[(ARLACCS_dp+ARLA_MAC_d+4)/4] = *(uint16_t *)&flippedAddress[0];
586 swreg32[(ARLACCS_dp+ARLA_RWCTL_d)/4] = 0x80;
591 /* --------------------------------------------------------------------------
592 Name: bcm6352_enet_open
593 Purpose: CFE driver open entry point.
594 -------------------------------------------------------------------------- */
595 static int bcm6352_enet_open(cfe_devctx_t *ctx)
597 bcm6352enet_softc *softc = (bcm6352enet_softc *) ctx->dev_softc;
599 if ((softc->chipId == 0x6352) && (softc->chipRev == 0xa1))
600 ext_mii_check();
602 if (test_bit(0, &softc->dualMacMode))
603 port_control(0, 1);
605 return 0;
609 /* --------------------------------------------------------------------------
610 Name: bcm6352_enet_read
611 Purpose: Returns a recevied data buffer.
612 -------------------------------------------------------------------------- */
613 static int bcm6352_enet_read( cfe_devctx_t *ctx, iocb_buffer_t *buffer )
615 uint32_t rxEvents;
616 unsigned char *dstptr;
617 unsigned char *srcptr;
618 volatile DmaDesc *CurrentBdPtr;
619 bcm6352enet_softc *softc = (bcm6352enet_softc *) ctx->dev_softc;
621 /* ============================= ASSERTIONS ============================= */
623 if( ctx == NULL ) {
624 xprintf( "No context\n" );
625 return -1;
628 if( buffer == NULL ) {
629 xprintf( "No dst buffer\n" );
630 return -1;
633 if( buffer->buf_length != ENET_MAX_BUF_SIZE ) {
634 xprintf( "dst buffer too small.\n" );
635 xprintf( "actual size is %d\n", buffer->buf_length );
636 return -1;
639 if( softc == NULL ) {
640 xprintf( "softc has not been initialized.\n" );
641 return -1;
644 /* ====================================================================== */
646 dstptr = buffer->buf_ptr;
647 CurrentBdPtr = softc->rxBdReadPtr;
649 if( (CurrentBdPtr->status & DMA_OWN) == 1 )
650 return -1;
652 srcptr = (unsigned char *)( PHYS_TO_K1(CurrentBdPtr->address) );
653 memcpy( dstptr, srcptr, ETH_ALEN * 2 );
654 dstptr += ETH_ALEN * 2;
655 memcpy( dstptr, srcptr + HEDR_LEN, CurrentBdPtr->length - HEDR_LEN - 8 );
657 /* length - header difference - 2 CRCs */
658 buffer->buf_retlen = CurrentBdPtr->length - 6 - 8;
660 CurrentBdPtr->length = ENET_MAX_MTU_SIZE;
661 CurrentBdPtr->status &= DMA_WRAP;
662 CurrentBdPtr->status |= DMA_OWN;
664 IncRxBDptr(CurrentBdPtr, softc);
665 softc->rxBdReadPtr = CurrentBdPtr;
667 rxEvents = softc->rxDma->intStat;
668 softc->rxDma->intStat = rxEvents;
670 softc->rxDma->cfg = DMA_ENABLE | DMA_CHAINING | DMA_WRAP_EN;
672 return 0;
676 /* --------------------------------------------------------------------------
677 Name: bcm6352_enet_inpstat
678 Purpose: Indicates if data has been received.
679 -------------------------------------------------------------------------- */
680 static int bcm6352_enet_inpstat( cfe_devctx_t *ctx, iocb_inpstat_t *inpstat )
682 bcm6352enet_softc *softc;
683 volatile DmaDesc *CurrentBdPtr;
685 /* ============================= ASSERTIONS ============================= */
687 if( ctx == NULL ) {
688 xprintf( "No context\n" );
689 return -1;
692 if( inpstat == NULL ) {
693 xprintf( "No inpstat buffer\n" );
694 return -1;
697 softc = (bcm6352enet_softc *)ctx->dev_softc;
698 if( softc == NULL ) {
699 xprintf( "softc has not been initialized.\n" );
700 return -1;
703 /* ====================================================================== */
706 CurrentBdPtr = softc->rxBdReadPtr;
708 /* inp_status == 1 -> data available */
709 inpstat->inp_status = (CurrentBdPtr->status & DMA_OWN) ? 0 : 1;
711 return 0;
715 /* --------------------------------------------------------------------------
716 Name: bcm6352_enet_write
717 Purpose: Sends a data buffer.
718 -------------------------------------------------------------------------- */
719 static int bcm6352_enet_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
721 int copycount;
722 unsigned int srclen;
723 unsigned char *dstptr;
724 unsigned char *srcptr;
725 bcm6352enet_softc *softc = (bcm6352enet_softc *) ctx->dev_softc;
726 volatile DmaChannel *txDma = softc->txDma;
728 /* ============================= ASSERTIONS ============================= */
730 if( ctx == NULL ) {
731 xprintf( "No context\n" );
732 return -1;
735 if( buffer == NULL ) {
736 xprintf( "No dst buffer\n" );
737 return -1;
740 if( buffer->buf_length > ENET_MAX_BUF_SIZE ) {
741 xprintf( "src buffer too large.\n" );
742 xprintf( "size is %d\n", buffer->buf_length );
743 return -1;
746 if( softc == NULL ) {
747 xprintf( "softc has not been initialized.\n" );
748 return -1;
751 /* ====================================================================== */
754 /******** Convert header to Broadcom's special header format. ********/
755 dstptr = softc->txBufPtr;
756 srcptr = buffer->buf_ptr;
757 srclen = buffer->buf_length;
759 memcpy( dstptr, srcptr, ETH_ALEN * 2 );
760 dstptr += ETH_ALEN * 2;
761 srcptr += ETH_ALEN * 2;
763 *((uint16_t *)dstptr) = BRCM_TYPE;
764 dstptr += 2;
766 if( srclen < 60 - 6 - 8 ) {
767 *((uint16_t *)dstptr) = (uint16_t)60;
768 } else {
769 *((uint16_t *)dstptr) = (uint16_t)(srclen + 6 + 8);
771 dstptr += 2;
773 *((uint16_t *)dstptr) = (uint16_t)MANAGEMENT_PORT;
774 dstptr += 2;
776 copycount = srclen - ETH_ALEN * 2;
777 memcpy( dstptr, srcptr, copycount );
779 if( srclen < 60 ) {
780 dstptr += copycount;
781 memset( dstptr, 0, 60 - srclen );
782 txDma->length = 66;
783 } else {
784 txDma->length = srclen + 6;
787 /* Set status of DMA buffer to be transmitted. */
788 txDma->bufStat = DMA_SOP | DMA_EOP | DMA_APPEND_CRC | DMA_OWN;
790 /* Enable DMA for this channel. */
791 softc->txDma->cfg |= DMA_ENABLE;
793 /* poll the dma status until done. */
794 while( (txDma->bufStat & DMA_OWN) == 0 )
796 txDma->bufStat = 0;
798 return 0;
802 /* --------------------------------------------------------------------------
803 Name: bcm6352_enet_ioctl
804 Purpose: I/O Control function.
805 -------------------------------------------------------------------------- */
806 static int bcm6352_enet_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
808 bcm6352enet_softc *softc = (bcm6352enet_softc *) ctx->dev_softc;
809 int retval = 0;
811 switch( (int)buffer->buf_ioctlcmd ) {
812 case IOCTL_ETHER_GETHWADDR:
813 memcpy( buffer->buf_ptr, softc->macAddr, sizeof(softc->macAddr) );
814 break;
815 case IOCTL_ETHER_SETHWADDR:
816 memcpy( softc->macAddr, buffer->buf_ptr, sizeof(softc->macAddr) );
817 write_mac_address( softc );
818 break;
819 case IOCTL_ETHER_GETSPEED:
820 xprintf( "BCM6352 : GETSPEED not implemented.\n" );
821 retval = -1;
822 break;
823 case IOCTL_ETHER_SETSPEED:
824 xprintf( "BCM6352 : SETSPEED not implemented.\n" );
825 retval = -1;
826 break;
827 case IOCTL_ETHER_GETLINK:
828 xprintf( "BCM6352 : GETLINK not implemented.\n" );
829 retval = -1;
830 break;
831 case IOCTL_ETHER_GETLOOPBACK:
832 xprintf( "BCM6352 : GETLOOPBACK not implemented.\n" );
833 retval = -1;
834 break;
835 case IOCTL_ETHER_SETLOOPBACK:
836 xprintf( "BCM6352 : SETLOOPBACK not implemented.\n" );
837 retval = -1;
838 break;
839 default:
840 xprintf( "Invalid IOCTL to bcm6352_enet_ioctl.\n" );
841 retval = -1;
844 return retval;
848 /* --------------------------------------------------------------------------
849 Name: bcm6352_enet_close
850 Purpose: Uninitialize.
851 -------------------------------------------------------------------------- */
852 static int bcm6352_enet_close(cfe_devctx_t *ctx)
854 bcm6352enet_softc *softc = (bcm6352enet_softc *) ctx->dev_softc;
855 unsigned long sts;
857 printf( "Closing Ethernet.\n" );
859 if (test_bit(0, &softc->dualMacMode))
860 port_control(0, 0);
862 sts = softc->rxDma->intStat;
863 softc->rxDma->intStat = sts;
864 softc->rxDma->intMask = 0;
865 softc->rxDma->cfg = 0;
867 sts = softc->txDma->intStat;
868 softc->txDma->intStat = sts;
869 softc->txDma->intMask = 0;
870 softc->txDma->cfg = 0;
872 return 0;