• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/cfe/cfe/arch/mips/board/bcm97115/src/
1#include "lib_types.h"
2#include "lib_malloc.h"
3#include "lib_string.h"
4#include "lib_printf.h"
5
6#include "cfe_iocb.h"
7#include "cfe_ioctl.h"
8#include "cfe_timer.h"
9#include "cfe_device.h"
10#include "cfe_devfuncs.h"
11
12#include "dev_bcm4413.h"
13#include "dev_bcm4413_mii.h"
14
15#ifdef EBIDMA
16	#include "bcmdma.h"
17#endif
18
19#ifdef __MIPSEB
20	#define SWAP_ENDIAN
21#endif
22
23#ifdef SWAP_ENDIAN
24#define SWAP16(x) ( ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8) )
25#define SWAP32(x) ( (x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24) )
26#endif
27
28
29#define BCM4413ERROR( x, y ... ) xprintf( "BCM4413 ERROR : " x, ##y )
30
31
32#ifdef DEBUG
33
34	#define BCMDEBUG( x, y ... )            xprintf( "BCM4413 : " x, ##y )
35	#define BCM4413TRACE( x, y ... )
36	//#define BCM4413TRACE( x, y ... )      xprintf( "BCM4413 : " x, ##y )
37
38	#define BCM4413INFO( x, y ... )
39	//#define BCM4413INFO( x, y ... ) xprintf( "BCM4413 ERROR : " x, ##y )
40
41#else
42
43	#define BCM4413TRACE( x, y ... )
44
45#endif
46
47
48#define K0_TO_PHYS(p)   ((uint32_t)(p) & ((uint32_t)0x1fffffff))
49
50#define	BCM4412_DEVICE_ID	0x4412		/* bcm44xx family pci enet */
51
52#define PHYS_BCM44XX_BASE  0x1B400000
53#define BCM44XX_BASE       (0xA0000000 | PHYS_BCM44XX_BASE)
54#define BCM44XX_ENET_BASE  (BCM44XX_BASE + 0x1800)
55
56/*
57 * The number of bytes in an ethernet (MAC) address.
58 */
59#define	ETHER_ADDR_LEN		6
60
61/*
62 * The number of bytes in the type field.
63 */
64#define	ETHER_TYPE_LEN		2
65
66/*
67 * The number of bytes in the trailing CRC field.
68 */
69#define	ETHER_CRC_LEN		4
70
71/*
72 * The length of the combined header.
73 */
74#define	ETHER_HDR_LEN		(ETHER_ADDR_LEN*2+ETHER_TYPE_LEN)
75
76
77/* TODO -- This value probably isn't right */
78#define	ETHER_MAX_DATA		1500
79
80/*
81 * The maximum packet length.
82 */
83//#define	ETHER_MAX_LEN		1518
84#define	ETHER_MAX_LEN		1514
85
86/* Broadcom's rxhdr */
87#define HWRXOFF       30
88
89#define DST_BUF_SIZE        1514
90#define BRCM_PACKET_SIZE    DST_BUF_SIZE + HWRXOFF + ETHER_CRC_LEN
91
92
93
94static void bcm4413_ether_probe( cfe_driver_t * drv,    unsigned long probe_a,
95                                 unsigned long probe_b, void * probe_ptr );
96static int bcm4413_ether_open(cfe_devctx_t *ctx);
97static int bcm4413_ether_read(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
98static int bcm4413_ether_inpstat(cfe_devctx_t *ctx,iocb_inpstat_t *inpstat);
99static int bcm4413_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
100static int bcm4413_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer);
101static int bcm4413_ether_close(cfe_devctx_t *ctx);
102
103
104const static cfe_devdisp_t bcm4413_ether_dispatch = {
105	bcm4413_ether_open,
106	bcm4413_ether_read,
107	bcm4413_ether_inpstat,
108	bcm4413_ether_write,
109	bcm4413_ether_ioctl,
110	bcm4413_ether_close,
111	NULL,
112	NULL
113};
114
115const cfe_driver_t bcm4413drv = {
116	"BCM4413 Ethernet",
117	"eth",
118	CFE_DEV_NETWORK,
119	&bcm4413_ether_dispatch,
120	bcm4413_ether_probe
121};
122
123
124typedef struct bcm4413_softc {
125	bcmenetregs_t * regs;
126
127	unsigned char * txbuffer;
128	unsigned char * rxbuffer;
129
130	uint8_t  hwaddr[ETHER_ADDR_LEN];
131} bcm4413_softc;
132
133
134/*
135 * Structure of a 10Mb/s Ethernet header.
136 */
137typedef struct ether_header {
138	uint8_t	 ether_dhost[ETHER_ADDR_LEN];
139	uint8_t	 ether_shost[ETHER_ADDR_LEN];
140	uint16_t ether_type;
141} ether_header __attribute__((packed));
142
143/*
144 * Structure of a 48-bit Ethernet address.
145 */
146struct	ether_addr {
147	uint8_t octet[ETHER_ADDR_LEN];
148} __attribute__((packed));
149
150
151
152static int bcm7115_getmacaddr( char * macaddr )
153{
154	int        retval;
155	uint8_t    chksum;
156	uint32_t   brdtype;
157	uint16_t * src;
158
159	BCM4413TRACE( "getmacaddr entered\n" );
160
161	/* Check checksum */
162	chksum = 0;
163	for( src = (uint16_t *)(0xBAFFF800); src <= (uint16_t *)(0xBAFFF88A); ) {
164		chksum += ((*src) & 0xFF00) >> 8;
165		chksum += (*src) & 0x00FF;
166		src++;
167	}
168
169#ifdef __MIPSEB
170
171	if( chksum != ((*src) & 0x00FF) ) {
172		BCM4413ERROR( "Flash checksum failed.\n" );
173		return 0;
174	}
175
176	brdtype = (((*((uint16_t *)(0xBAFFF800))) & 0x00FF) << 16)
177	        |  ((*((uint16_t *)(0xBAFFF800))) & 0xFF00)
178	        |  ((*((uint16_t *)(0xBAFFF802))) & 0x00FF);
179
180#else
181
182	if( chksum != (((*src) & 0xFF00) >> 8) ) {
183		BCM4413ERROR( "Flash checksum failed.\n" );
184		return 0;
185	}
186
187	brdtype = ( (*((uint16_t *)(0xBAFFF800))) << 8 )
188	        | (((*((uint16_t *)(0xBAFFF802))) & 0xFF00) >> 8);
189
190#endif
191
192	if( brdtype == 0x00097115 ) {
193		for( src = (uint16_t *)(0xBAFFF80C); src < (uint16_t *)(0xBAFFF812); ) {
194			*((uint16_t *)macaddr) = (((*src) & 0xFF00) >> 8)
195			                       | (((*src) & 0x00FF) << 8);
196			macaddr += 2;
197			src++;
198		}
199		retval = 1;
200	} else {
201		BCM4413ERROR( "Wrong board type (0x%X).\n", brdtype );
202		retval = 0;
203	}
204
205	BCM4413TRACE( "getmacaddr exited\n" );
206
207	return retval;
208}
209
210
211static void bcm4413_writecam(bcmenetregs_t * regs, struct ether_addr *ea,
212                             unsigned int camindex);
213static void bcm4413_writecam(bcmenetregs_t * regs, struct ether_addr *ea,
214                             unsigned int camindex)
215{
216	uint32_t w;
217	uint16_t *camcontrol;
218
219	BCM4413TRACE( "bcm4413_writecam entered\n" );
220
221#ifdef DEBUG
222	if( (R_REG(NULL, &regs->camcontrol) & (CC_CB | CC_CE)) != 0 ) {
223		BCM4413ERROR( "Cannot write MAC address to CAM.\n" );
224	}
225#endif
226
227	w = (ea->octet[2] << 24) | (ea->octet[3] << 16) | (ea->octet[4] << 8)
228	  | ea->octet[5];
229	W_REG(NULL,  &regs->camdatalo, w );
230
231	w = CD_V | (ea->octet[0] << 8) | ea->octet[1];
232	W_REG(NULL,  &regs->camdatahi, w );
233
234	w = (camindex << CC_INDEX_SHIFT) | CC_WR;
235
236	camcontrol = (unsigned short *) (&regs->camcontrol);
237	W_REG(NULL,  &camcontrol[1], (w >> 16) & 0xffff );
238	W_REG(NULL,  &camcontrol[0],    w      & 0xffff );
239
240	/* Return when done */
241	while( R_REG(NULL, &regs->camcontrol) & CC_CB ) {
242		cfe_usleep( 10 );
243	}
244
245	BCM4413TRACE( "bcm4413_writecam exited\n" );
246}
247
248
249static void bcm4413_reset( bcmenetregs_t * regs );
250static void bcm4413_reset( bcmenetregs_t * regs )
251{
252	BCM4413TRACE( "bcm4413_reset entered\n" );
253
254	/* Put the chip in a reset state */
255	W_REG(NULL,  &regs->devcontrol, DC_RS );
256
257	/* We have to wait 10 msec before we can reaquire. */
258	/* Update : cached mode needs to wait longer.      */
259	cfe_usleep( 100 );
260
261	/* Bring it back out to a dormant state. */
262	W_REG(NULL,  &regs->devcontrol, 0 );
263
264	cfe_usleep( 100 );
265
266	/*
267	 * We want the phy registers to be accessible even when
268	 * the driver is "downed" so initialize enough for this here.
269	 */
270	W_REG(NULL,  ((unsigned short *) (&regs->mdiocontrol)), (MC_PE | 0x1f) );
271
272	BCM4413TRACE( "bcm4413_reset exited\n" );
273}
274
275
276static void bcm4413_init( bcm4413_softc * softc )
277{
278	bcmenetregs_t * regs;
279
280	BCM4413TRACE( "bcm4413_init entered\n" );
281
282	regs = softc->regs;
283
284	mii_init( regs );
285
286	/* enable crc32 generation */
287	OR_REG(NULL,  &regs->emaccontrol, EMC_CG );
288
289	/* enable 802.3x tx flow control (honor received PAUSE frames) */
290	W_REG(NULL,  &regs->rxcontrol, ERC_FE | ERC_UF );
291
292#ifdef PROMISC
293	OR_REG(NULL,  &regs->rxcontrol, ERC_PE );
294#else
295	/* our local address */
296	bcm4413_writecam(regs, (struct ether_addr *)(softc->hwaddr), 0 );
297
298	/* Accept multicast frames */
299	OR_REG(NULL,  &regs->rxcontrol, ERC_AM );
300
301	/* Enable CAM */
302	OR_REG(NULL,  &regs->camcontrol, CC_CE );
303#endif
304
305	/* set max frame lengths - account for possible vlan tag */
306	W_REG(NULL,  &regs->rxmaxlength, (ETHER_MAX_LEN + 32) );
307	W_REG(NULL,  &regs->txmaxlength, (ETHER_MAX_LEN + 32) );
308
309	/* set tx watermark */
310	W_REG(NULL,  (unsigned short *)(&regs->txwatermark), 56 );
311
312	/* Set TX to full duplex */
313	W_REG(NULL,  &regs->txcontrol, EXC_FD );
314
315	/* turn on the emac */
316	OR_REG(NULL,  &regs->enetcontrol, EC_EE );
317
318	mii_setspeed( regs );
319
320	/* Enable recieves in Fifo Mode */
321	W_REG(NULL,  &regs->rcvcontrol, RC_FM );
322
323#ifdef __MIPSEB
324	OR_REG(NULL,  &regs->devcontrol, DC_BS );
325#endif
326
327	/* Enable transmit and recieve */
328	OR_REG(NULL,  &regs->devcontrol, DC_XE | DC_RE );
329
330	BCM4413TRACE( "bcm4413_init exited\n" );
331}
332
333
334#define	I_ERRORS	(I_PC | I_PD | I_DE | I_RU | I_RO | I_XU)
335static void chiperrors( bcmenetregs_t * regs, bcm4413_softc * softc );
336static void chiperrors( bcmenetregs_t * regs, bcm4413_softc * softc )
337{
338	uint32_t intstatus;
339
340	intstatus = R_REG(NULL,  &regs->intstatus );
341
342	BCM4413INFO( "chiperrors: intstatus 0x%x\n", intstatus );
343
344	if (intstatus & I_PC) {
345		BCM4413INFO( "\tpci descriptor error\n");
346	}
347
348	if (intstatus & I_PD) {
349		BCM4413INFO( "\tpci data error\n");
350	}
351
352	if (intstatus & I_DE) {
353		BCM4413INFO("\tdescriptor protocol error\n");
354	}
355
356	if (intstatus & I_RU) {
357		BCM4413INFO("\treceive descriptor underflow\n");
358	}
359
360	if (intstatus & I_RO) {
361		BCM4413INFO("\treceive fifo overflow\n");
362
363		/* in pio mode, just bang the rx fifo */
364		AND_REG(NULL, &regs->devcontrol, ~DC_RE);
365		cfe_usleep( 10 );
366		OR_REG(NULL, &regs->devcontrol, DC_RE);
367		return;
368	}
369
370	if (intstatus & I_XU) {
371		BCM4413INFO("\ttransmit fifo underflow\n");
372	}
373
374	/* big hammer */
375	bcm4413_reset( regs );
376	bcm4413_init( softc );
377}
378
379
380static void bcm4413_ether_probe( cfe_driver_t * drv,    unsigned long probe_a,
381                                 unsigned long probe_b, void * probe_ptr )
382{
383	bcmenetregs_t * regs;
384	bcm4413_softc * softc;
385	char descr[100];
386
387	BCM4413TRACE( "probe entered\n" );
388
389	softc = (bcm4413_softc *) KMALLOC( sizeof(bcm4413_softc), 0 );
390	if( softc == NULL ) {
391		BCM4413ERROR( "BCM4413 : Failed to allocate softc memory.\n" );
392		return;
393	}
394
395	memset( softc, 0, sizeof(bcm4413_softc) );
396
397	softc->regs = (bcmenetregs_t *)BCM44XX_ENET_BASE;
398	regs = softc->regs;
399
400	bcm4413_reset( regs );
401
402	bcm7115_getmacaddr( softc->hwaddr );
403
404#ifdef DEBUG
405	xprintf( "BCM4413 :\n" );
406	xprintf( "\tvendorID = 0x%X\n", R_REG(NULL, &regs->pcicfg[0]) );
407	xprintf( "\tdeviceID = 0x%X\n", R_REG(NULL, &regs->pcicfg[1]) );
408	xprintf( "\tchiprev  = 0x%X\n", R_REG(NULL, &regs->devstatus) & DS_RI_MASK );
409#endif
410
411	xsprintf( descr, "%s at 0x%X", drv->drv_description, probe_a );
412	cfe_attach( drv, softc, NULL, descr );
413
414	BCM4413TRACE( "probe exited\n" );
415}
416
417
418static int bcm4413_ether_open(cfe_devctx_t *ctx)
419{
420	bcmenetregs_t * regs;
421	bcm4413_softc * softc = (bcm4413_softc *) ctx->dev_softc;
422
423	BCM4413TRACE( "open entered\n" );
424
425	/* THESE BUFFERS MUST BE 4-BYTE ALIGNED */
426	softc->txbuffer = (unsigned char *)KMALLOC( BRCM_PACKET_SIZE, 4 );
427	if( softc->txbuffer == NULL ) {
428		BCM4413ERROR( "BCM4413 : Failed to allocate TX buffer memory.\n" );
429		return 0;
430	}
431
432	softc->rxbuffer = (unsigned char *)KMALLOC( BRCM_PACKET_SIZE, 4 );
433	if( softc->rxbuffer == NULL ) {
434		BCM4413ERROR( "BCM4413 : Failed to allocate RX buffer memory.\n" );
435		KFREE( softc->txbuffer );
436		return 0;
437	}
438
439#ifdef DEBUG
440	memset( softc->txbuffer, 0, BRCM_PACKET_SIZE );
441	memset( softc->rxbuffer, 0, BRCM_PACKET_SIZE );
442#endif
443
444	regs = softc->regs;
445
446#ifdef DEBUG
447	if( (R_REG(NULL, &regs->emaccontrol) & EMC_PD) != 0 ||
448	    (R_REG(NULL, &regs->devcontrol)  &  DC_PD) != 0 ) {
449		BCM4413ERROR( "ERROR : Internal ephy has no power or clock.\n" );
450	}
451#endif
452
453	mii_init( regs );
454
455	/* enable crc32 generation */
456	OR_REG(NULL,  &regs->emaccontrol, EMC_CG );
457
458	/* enable 802.3x tx flow control (honor received PAUSE frames) */
459	W_REG(NULL,  &regs->rxcontrol, ERC_FE | ERC_UF );
460
461#ifdef PROMISC
462	OR_REG(NULL,  &regs->rxcontrol, ERC_PE );
463#else
464
465	/* our local address */
466	bcm4413_writecam(regs, (struct ether_addr *)(softc->hwaddr), 0 );
467
468	/* Accept multicast frames */
469	OR_REG(NULL,  &regs->rxcontrol, ERC_AM );
470
471	/* enable cam */
472	OR_REG(NULL,  &regs->camcontrol, CC_CE );
473#endif
474
475	/* set max frame lengths - account for possible vlan tag */
476	W_REG(NULL,  &regs->rxmaxlength, (ETHER_MAX_LEN + 32) );
477	W_REG(NULL,  &regs->txmaxlength, (ETHER_MAX_LEN + 32) );
478
479	/* set tx watermark */
480	W_REG(NULL,  (unsigned short *)(&regs->txwatermark), 56 );
481
482	/* Set TX to full duplex */
483	W_REG(NULL,  &regs->txcontrol, EXC_FD );
484
485	/* turn on the emac */
486	OR_REG(NULL,  &regs->enetcontrol, EC_EE );
487
488	mii_setspeed( regs );
489
490	/* Enable recieves in Fifo Mode */
491	W_REG(NULL,  &regs->rcvcontrol, RC_FM );
492
493#ifdef __MIPSEB
494	OR_REG(NULL,  &regs->devcontrol, DC_BS );
495#endif
496
497	/* Enable transmit and recieve */
498	OR_REG(NULL,  &regs->devcontrol, DC_XE | DC_RE );
499
500	BCM4413TRACE( "open exited\n" );
501
502	return 0;
503}
504
505
506static int bcm4413_ether_read( cfe_devctx_t * ctx, iocb_buffer_t * buffer )
507{
508	int i;
509	uint16_t type;
510	uint16_t flags;
511	uint16_t rawlen;
512	uint16_t length;
513	uint16_t * dst16;
514	bcmenetregs_t * regs;
515	bcmenetrxhdr_t * hdr;
516	bcm4413_softc  * softc = (bcm4413_softc *) ctx->dev_softc;
517	ether_header   * ethhdr;
518
519	BCM4413TRACE( "read entered\n" );
520
521#ifdef DEBUG
522	/* ============================= ASSERTIONS ============================= */
523
524	if( ctx == NULL ) {
525		xprintf( "No context\n" );
526		return -1;
527	}
528
529	if( buffer == NULL ) {
530		xprintf( "No dst buffer\n" );
531		return -1;
532	}
533
534	if( buffer->buf_length != DST_BUF_SIZE ) {
535		xprintf( "dst buffer too small.\n" );
536		xprintf( "actual size is %d\n", buffer->buf_length );
537		return -1;
538	}
539
540	if( softc == NULL ) {
541		xprintf( "softc has not been initialized.\n" );
542		return -1;
543	}
544
545	/* ====================================================================== */
546#endif
547
548	regs = softc->regs;
549
550#ifdef DEBUG
551	if( !(R_REG(NULL, &regs->rcvfifocontrol) & RFC_FR) ) {
552		BCM4413ERROR( "4413 NOT READY TO RECEIVE!\n" );
553		return -1;
554	}
555#endif
556
557	/* Clear frame ready */
558	W_REG(NULL,  &regs->rcvfifocontrol, RFC_FR );
559
560	/* Wait for the hardware to make the data available */
561	while( !(R_REG(NULL, &regs->rcvfifocontrol) & RFC_DR) ) {}
562
563	rawlen = R_REG(NULL,  &regs->rcvfifodata );
564
565#ifdef SWAP_ENDIAN
566	length = SWAP16( rawlen );
567#else
568	length = rawlen;
569#endif
570
571	/* TODO -- Check this test. */
572	if( length < ETHER_HDR_LEN || length > (BRCM_PACKET_SIZE - HWRXOFF) ) {
573		BCM4413INFO( "Extreme incoming packet size.\n" );
574		BCM4413INFO( "length = %d, rawlen = %d\n", length, rawlen );
575
576		buffer->buf_retlen = 0;
577
578		W_REG(NULL,  &regs->rcvfifocontrol, RFC_DR );
579
580		return 0;
581	}
582
583	/* read the rxheader from the fifo first */
584	dst16 = (uint16_t *)(softc->rxbuffer);
585	*dst16++ = rawlen;
586	i = (RXHDR_LEN / 2) - 1;
587	while (i--) {
588		*dst16++ = R_REG(NULL, &regs->rcvfifodata);
589	}
590
591	/* read the frame */
592	dst16 = (uint16_t *)(softc->rxbuffer + HWRXOFF);
593	i = length / 2;
594	while (i--) {
595		*dst16++ = R_REG(NULL, &regs->rcvfifodata);
596	}
597
598	/* Read the odd byte */
599	if( length & 0x1 ) {
600		*dst16 = R_REG(NULL, &regs->rcvfifodata) & 0xFF;
601	}
602
603	/* Notify the hardware that we're done. */
604	W_REG(NULL,  &regs->rcvfifocontrol, RFC_DR );
605
606	hdr    = (bcmenetrxhdr_t *)(softc->rxbuffer);
607	ethhdr = (struct ether_header *)(softc->rxbuffer + HWRXOFF);
608
609#ifdef SWAP_ENDIAN
610	flags = SWAP16( hdr->flags );
611#else
612	flags = hdr->flags;
613#endif
614
615	/* TODO -- Should we reset the chip here? */
616	if( flags & (RXF_NO | RXF_RXER | RXF_CRC | RXF_OV) ) {
617		BCM4413INFO( "Packet recieve error (0x%X)\n", flags );
618		buffer->buf_retlen = 0;
619		return -1;
620	}
621
622	/* 802.3 4.3.2: discard frames with inconsistent length field value */
623#ifdef SWAP_ENDIAN
624	type = SWAP32( ethhdr->ether_type );
625#else
626	type = ethhdr->ether_type;
627#endif
628	if( (type <= ETHER_MAX_DATA) && (type > (length - ETHER_HDR_LEN)) ) {
629		BCM4413INFO( "Inconsistent length field value.\n" );
630		buffer->buf_retlen = 0;
631		return -1;
632	}
633
634	/* Strip off the CRC */
635	length -= ETHER_CRC_LEN;
636
637	/* TODO -- This check shouldn't be necessary. */
638	if( length >= DST_BUF_SIZE ) {
639		BCM4413INFO( "\nIncoming packet too big : length = %d\n", length );
640		buffer->buf_retlen = 0;
641		return -1;
642	}
643
644	memcpy( buffer->buf_ptr, softc->rxbuffer + HWRXOFF, length );
645
646	buffer->buf_retlen = length;
647
648	/* Check for any error conditions */
649	if( R_REG(NULL, &regs->intstatus) & I_ERRORS ) {
650		chiperrors( regs, softc );
651	}
652
653	BCM4413TRACE( "read exited\n" );
654
655	return 0;
656}
657
658
659static int bcm4413_ether_inpstat( cfe_devctx_t * ctx, iocb_inpstat_t * inpstat )
660{
661	cfe_uint_t stat;
662	bcm4413_softc * softc = (bcm4413_softc *) ctx->dev_softc;
663
664	/* Check whenever a full frame is ready. */
665	stat = (R_REG(NULL, &softc->regs->rcvfifocontrol) & RFC_FR) ? 1 : 0;
666	inpstat->inp_status = stat;
667
668	return 0;
669}
670
671
672static int bcm4413_ether_write(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
673{
674	uint16_t length;
675	uint16_t * src16;
676	bcm4413_softc * softc;
677	bcmenetregs_t * regs;
678
679	BCM4413TRACE( "write entered\n", ctx );
680
681	softc = (bcm4413_softc *) ctx->dev_softc;
682	regs  = softc->regs;
683
684#ifdef DEBUG
685	/* TODO -- Should we wait until the hardware _is_ ready? */
686	if( !(R_REG(NULL, &regs->xmtfifocontrol) & XFC_FR) ) {
687		BCM4413ERROR( "4413 NOT READY TO SEND!\n" );
688		return -1;
689	}
690#endif
691
692	/* Clear frameready */
693	W_REG(NULL,  &regs->xmtfifocontrol, XFC_FR );
694
695	/* When writing 16 bit values, both 8-bit data bytes are valid. */
696	W_REG(NULL,  &regs->xmtfifocontrol, XFC_BOTH );
697
698	length = (buffer->buf_length) & ~1;
699
700	/* SEND IT! */
701	src16 = (uint16_t *)(buffer->buf_ptr);
702	length /= 2;
703	while( length-- ) {
704		W_REG(NULL, &regs->xmtfifodata, *src16++ );
705	}
706
707	/* Write last odd byte. */
708	if( buffer->buf_length & 1 ) {
709		W_REG(NULL,  &regs->xmtfifocontrol, XFC_LO );
710		W_REG(NULL,  &regs->xmtfifodata, *src16 );
711	}
712
713	/* Tell the hardware we're done. */
714	W_REG(NULL,  &regs->xmtfifocontrol, XFC_EF );
715
716	/* Check for any error conditions */
717	if( R_REG(NULL, &regs->intstatus) & I_ERRORS ) {
718		chiperrors( regs, softc );
719	}
720
721	BCM4413TRACE( "write exited\n" );
722
723	return 0;
724}
725
726
727static int bcm4413_ether_ioctl(cfe_devctx_t *ctx,iocb_buffer_t *buffer)
728{
729	int retval = 0;
730	bcm4413_softc * softc = ctx->dev_softc;
731
732	switch( (int)buffer->buf_ioctlcmd ) {
733		case IOCTL_ETHER_GETHWADDR:
734			BCM4413TRACE( "IOCTL_ETHER_GETHWADDR called.\n" );
735			memcpy( buffer->buf_ptr, softc->hwaddr, sizeof(softc->hwaddr) );
736			break;
737		case IOCTL_ETHER_SETHWADDR:
738			BCM4413TRACE( "IOCTL_ETHER_SETHWADDR called.\n" );
739			bcm4413_writecam( softc->regs, (struct ether_addr *)buffer->buf_ptr, 0 );
740			memcpy( softc->hwaddr, buffer->buf_ptr, sizeof(softc->hwaddr)  );
741			break;
742		default:
743			xprintf( "Invalid IOCTL to bcm4413_ether_ioctl.\n" );
744			retval = -1;
745	}
746
747	return retval;
748}
749
750
751static int bcm4413_ether_close(cfe_devctx_t *ctx)
752{
753	bcm4413_softc * softc = (bcm4413_softc *) ctx->dev_softc;
754
755	bcm4413_reset( softc->regs );
756
757	KFREE( softc->rxbuffer );
758	softc->rxbuffer = NULL;
759
760	KFREE( softc->txbuffer );
761	softc->txbuffer = NULL;
762
763	return 0;
764}
765