* Copyright (c) 1992 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
* %sccs.include.redist.c%
* from: $Hdr: if_lance.c,v 4.300 91/06/09 06:25:58 root Rel41 $ SONY
* @(#)if_lance.c 7.3 (Berkeley) %G%
* if_lance: Am7990 LANCE driver
* This driver is available only for single CPU machine.
#include <machine/fix_machine_type.h>
#include <machine/adrsmap.h>
#include <news3400/if/lancereg.h>
#include <news3400/if/if_lance.h>
#define VOLATILE volatile
VOLATILE u_char *p = (u_char *)DEBUG_PORT; \
*p = DP_WRITE | (*p & ~DP_LED2); \
VOLATILE u_char *p = (u_char *)DEBUG_PORT; \
*p = DP_WRITE | (*p | DP_LED2); \
* LANCE memory configuration
#define INIT_BLOCK 0x000000
#define RECV_MSG_DESC 0x000100
#define XMIT_MSG_DESC 0x000200
#define RECV_BUFFER (0x000300 + 2)
/* for data alignment to long word */
#define RECV_BUFFER 0x000300
#define XMIT_BUFFER (RECV_BUFFER+(RECV_BUFFER_SIZE*RECV_BUFFERS))
#define RECV_RING_LEN 3 /* log2(8) */
#define XMIT_RING_LEN 1 /* log2(2) */
#define RECV_BUFFER_SIZE 0x600
#define XMIT_BUFFER_SIZE 0x600
#define RECV_BUFFERS (1 << RECV_RING_LEN)
#define XMIT_BUFFERS (1 << XMIT_RING_LEN)
struct init_block init_block
= {
(RECV_RING_LEN
<< 13) | (RECV_MSG_DESC
>> 16),
(XMIT_RING_LEN
<< 13) | (XMIT_MSG_DESC
>> 16)
Lance_chan lancesw
[NEN
] = {
{ (Lance_reg
*)LANCE_PORT
,
{ (Lance_reg
*)LANCE_PORT1
,
{ (Lance_reg
*)LANCE_PORT2
,
register Lance_chan
*lance
= &lancesw
[chan
];
VOLATILE
int *p
= (VOLATILE
int *)lance
->lance_memory
;
if (badaddr(lance
->lance_addr
, 1))
return (*p
== 0x12345678);
register Lance_chan
*lance
= &lancesw
[chan
];
register recv_msg_desc
*rmd
;
register xmit_msg_desc
*tmd
;
register struct init_block
*ib
;
if ((lance
->lance_flags
& LANCE_ACTIVE
) == 0) {
if (lance
->lance_addr
== (Lance_reg
*)0)
lance_write_reg(chan
, CSR0
, CSR_STOP
);
(RECV_MSG_DESC
+ lance
->lance_memory
);
(lance
->lance_rmd
= rmd
) + RECV_BUFFERS
- 1;
for (i
= 0; i
< RECV_BUFFERS
; i
++) {
rmd
->rmd_ladr
= buffer
& 0xffff;
rmd
->rmd_stat
= RMD_OWN
| (buffer
>> 16);
rmd
->rmd_bcnt
= -RECV_BUFFER_SIZE
;
buffer
+= RECV_BUFFER_SIZE
;
(XMIT_MSG_DESC
+ lance
->lance_memory
);
(lance
->lance_tmd
= tmd
) + XMIT_BUFFERS
- 1;
for (i
= 0; i
< XMIT_BUFFERS
; i
++) {
tmd
->tmd_ladr
= buffer
& 0xffff;
tmd
->tmd_stat
= buffer
>> 16;
buffer
+= XMIT_BUFFER_SIZE
;
get_hard_addr(chan
, lance
->lance_stats
.ens_addr
);
ib
= (struct init_block
*)(INIT_BLOCK
+ lance
->lance_memory
);
ib
->ib_padr
[0] = lance
->lance_stats
.ens_addr
[1];
ib
->ib_padr
[1] = lance
->lance_stats
.ens_addr
[0];
ib
->ib_padr
[2] = lance
->lance_stats
.ens_addr
[3];
ib
->ib_padr
[3] = lance
->lance_stats
.ens_addr
[2];
ib
->ib_padr
[4] = lance
->lance_stats
.ens_addr
[5];
ib
->ib_padr
[5] = lance
->lance_stats
.ens_addr
[4];
if (lance
->lance_flags
& LANCE_PROM
)
lance
->lance_flags
|= LANCE_ACTIVE
;
if (lance_read_reg(chan
, CSR0
) !=
(CSR_INEA
|CSR_RXON
|CSR_TXON
|CSR_STRT
|CSR_INIT
)) {
lance
->lance_flags
&= ~LANCE_ACTIVE
;
register Lance_chan
*lance
= &lancesw
[chan
];
lance_write_reg(chan
, CSR0
, CSR_STOP
);
lance
->lance_flags
&= ~LANCE_ACTIVE
;
#define RECEIVE(lance, rmd) { \
(rmd) = (lance)->lance_last_rmd + 1; \
if ((rmd) >= (lance)->lance_rmd + RECV_BUFFERS) \
(rmd) = (lance)->lance_rmd; \
if (((rmd)->rmd_stat & RMD_OWN) == 0) \
(lance)->lance_last_rmd = (rmd); \
#define RECV_BUF(lance, rmd) (char *)((rmd)->rmd_ladr \
+ (((rmd)->rmd_stat & RMD_HADR) << 16) \
#define RECV_CNT(rmd) ((rmd)->rmd_mcnt - 4)
#define RECV_ERR(rmd) ((rmd)->rmd_stat & RMD_ERR)
#define RELEASE_RECV_BUF(rmd) { \
(rmd)->rmd_stat = ((rmd)->rmd_stat & RMD_HADR) | RMD_OWN; \
register Lance_chan
*lance
= &lancesw
[chan
];
register recv_msg_desc
*rmd
;
return (RECV_BUF(lance
, rmd
));
return (RECV_CNT(lancesw
[chan
].lance_last_rmd
));
register recv_msg_desc
*rmd
= lancesw
[chan
].lance_last_rmd
;
#define GET_XMIT_BUF(lance, tmd) { \
(tmd) = (lance)->lance_last_tmd + 1; \
if ((tmd) >= (lance)->lance_tmd + XMIT_BUFFERS) \
(tmd) = (lance)->lance_tmd; \
if ((tmd)->tmd_stat & TMD_OWN) \
(lance)->lance_last_tmd = (tmd); \
#define XMIT_BUF(lance, tmd) (char *)((tmd)->tmd_ladr \
+ (((tmd)->tmd_stat & TMD_HADR) << 16) \
#define XMIT_ERR(tmd) ((tmd)->tmd_stat & TMD_ERR)
#define TRANSMIT(lance, tmd, count) { \
(tmd)->tmd_bcnt = -(count); \
(tmd)->tmd_stat = ((tmd)->tmd_stat & TMD_HADR) | (TMD_OWN|TMD_STP|TMD_ENP); \
(lance)->lance_addr->rap = CSR0; \
(lance)->lance_addr->rdp = (CSR_INEA|CSR_TDMD); \
register Lance_chan
*lance
= &lancesw
[chan
];
register xmit_msg_desc
*tmd
;
GET_XMIT_BUF(lance
, tmd
);
return (XMIT_BUF(lance
, tmd
));
lance_transmit(chan
, count
)
register Lance_chan
*lance
= &lancesw
[chan
];
register xmit_msg_desc
*tmd
;
tmd
= lance
->lance_last_tmd
;
TRANSMIT(lance
, tmd
, count
);
register Lance_chan
*lance
= &lancesw
[chan
];
register xmit_msg_desc
*tmd
;
tmd
= lance
->lance_last_tmd
;
register Lance_chan
*lance
= &lancesw
[chan
];
if (lance
->lance_last_tmd
->tmd_stat
& (TMD_MORE
|TMD_ONE
)) {
lance
->lance_stats
.ens_collis
++;
lance_get_addr(chan
, addr
)
register Lance_chan
*lance
= &lancesw
[chan
];
bcopy(lance
->lance_stats
.ens_addr
, addr
,
sizeof(lance
->lance_stats
.ens_addr
));
lance_prom_mode(chan
, cmd
)
register Lance_chan
*lance
= &lancesw
[chan
];
lance
->lance_flags
|= LANCE_PROM
;
lance
->lance_flags
&= ~LANCE_PROM
;
lance_get_status(chan
, addr
)
register Lance_chan
*lance
= &lancesw
[chan
];
bcopy(&lance
->lance_stats
.ens_frames
, addr
,
sizeof(lance
->lance_stats
) - sizeof (lance
->lance_stats
.ens_addr
));
bzero(&lance
->lance_stats
.ens_frames
,
sizeof(lance
->lance_stats
) - sizeof (lance
->lance_stats
.ens_addr
));
register Lance_chan
*lance
;
for (chan
= 0, lance
= lancesw
; chan
< NEN
; lance
++, chan
++) {
if ((lance
->lance_flags
& LANCE_ACTIVE
) == 0)
stat
= reg
->rdp
& ~CSR_INEA
;
if ((stat
& CSR_INTR
) == 0)
printf("lance %d error: babl\n", chan
);
lance
->lance_stats
.ens_lost
++;
printf("lance %d error: merr\n", chan
);
lance
->lance_stats
.ens_frames
++;
lance
->lance_stats
.ens_xmit
++;
lance
->lance_flags
|= LANCE_IDON
;
register Lance_chan
*lance
= &lancesw
[chan
];
lance_write_reg(chan
, CSR1
, INIT_BLOCK
& 0xffff);
lance_write_reg(chan
, CSR2
, INIT_BLOCK
>> 16);
lance_write_reg(chan
, CSR3
, CSR_BSWP
|CSR_BCON
);
lance_write_reg(chan
, CSR0
, CSR_INEA
|CSR_STRT
|CSR_INIT
);
while ((lance
->lance_flags
& LANCE_IDON
) == 0)
register Lance_chan
*lance
;
register recv_msg_desc
*rmd
;
register int status
= rmd
->rmd_stat
;
register int chan
= lance
- lancesw
;
lance
->lance_stats
.ens_align
++;
printf("lance %d recv error: overflow\n", chan
);
lance
->lance_stats
.ens_crc
++;
printf("lance %d:recv error: buffer\n", chan
);
register Lance_chan
*lance
;
register xmit_msg_desc
*tmd
;
register int status
= tmd
->tmd_error
;
register int chan
= lance
- lancesw
;
printf("lance %d: xmit error: buffer\n", chan
);
printf("lance %d: xmit error: underflow\n", chan
);
printf("lance %d: xmit error: late collision\n", chan
);
lance
->lance_stats
.ens_owcollis
++;
printf("lance %d: xmit error: loss of carrier\n", chan
);
printf("lance %d: xmit error: retry tdr=%d\n",
lance
->lance_stats
.ens_xcollis
++;
lance_write_reg(chan
, reg
, data
)
register Lance_reg
*lance
= lancesw
[chan
].lance_addr
;
lance_read_reg(chan
, reg
)
register Lance_reg
*lance
= lancesw
[chan
].lance_addr
;
get_hard_addr(chan
, addr
)
register unsigned char *p
, *q
;
register Lance_chan
*lance
= &lancesw
[chan
];
unsigned char hard_addr
[6];
p
= (unsigned char *)lance
->lance_rom
+ 16;
for (i
= 0; i
< 6; i
++) {
bcopy(hard_addr
, (char *)addr
, 6);
#if defined(mips) && defined(CPU_SINGLE)
switch ((((int)s
& 03) << 2) + ((int)d
& 03)) {
blcopy((long *)s
, (long *)d
, n
);
blcopy((long *)(s
+ 1), (long *)(d
+ 1), n
- 1);
*(short *)d
= *(short *)s
;
*(short *)d
= *(short *)s
;
blcopy((long *)(s
+ 2), (long *)(d
+ 2), n
- 2);
*(char *)(d
+ 1) = *(char *)(s
+ 1);
*(short *)(d
+ 1) = *(short *)(s
+ 1);
*(short *)(d
+ 1) = *(short *)(s
+ 1);
blcopy((long *)(s
+ 3), (long *)(d
+ 3), n
- 3);
*(char *)(d
+ 1) = *(char *)(s
+ 1);
bwcopy((short *)(s
+ 1), (short *)(d
+ 1), n
);
bwcopy((short *)s
, (short *)d
, n
);
bbcopy((char *)s
, (char *)d
, n
);
#define COPY(s, d, n, t) \
while ((n) >= 8 * sizeof (t)) { \
int t0, t1, t2, t3, t4, t5, t6, t7; \
while ((n) >= sizeof (t)) { \
*(short *)d
= *(short *)s
;
*(short *)d
= *(short *)s
;
*((char *)d
+ 2) = *((char *)s
+ 2);
#endif /* defined(mips) && defined(CPU_SINGLE) */