345 lines
7.9 KiB
C
345 lines
7.9 KiB
C
|
|
#include "kernel.h"
|
|
|
|
#ifndef NONET
|
|
|
|
#include "minix/com.h"
|
|
#include "internet.h"
|
|
#include "etherformat.h"
|
|
#include "dp8390.h"
|
|
#include "dp8390info.h"
|
|
#include "dp8390stat.h"
|
|
#include "assert.h"
|
|
|
|
/* macros for device I/O */
|
|
|
|
#define input(devaddr, dp_register) \
|
|
in_byte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg0rd.dp_register)
|
|
#define input1(devaddr, dp_register) \
|
|
in_byte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg1rdwr.dp_register)
|
|
#define output(devaddr, dp_register, value) \
|
|
out_byte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg0wr.dp_register, value)
|
|
#define output1(devaddr, dp_register, value) \
|
|
out_byte((vir_bytes)&((union dp8390reg *) devaddr)->dp_pg1rdwr.dp_register, value)
|
|
|
|
#define MAX_WAIT 10000
|
|
|
|
#ifdef DPSTAT
|
|
struct dpstat dpstat;
|
|
#endif
|
|
|
|
static int (*bufread)(); /* call when packet came in */
|
|
static int (*bufwritten)(); /* call when packet has been written */
|
|
|
|
static disabled;
|
|
static phys_bytes curopacket; /* packet being transmitted */
|
|
static phys_bytes Curbuff; /* address of next read buffer to release */
|
|
|
|
static
|
|
chipinit(myaddr)
|
|
Eth_addr *myaddr;
|
|
{
|
|
register vir_bytes device;
|
|
|
|
device = dp8390info.dpi_devaddr;
|
|
output(device, dp_cr, CR_PS_P0|CR_DM_ABORT); /* back to main register set */
|
|
output(device, dp_pstart, dp8390info.dpi_pstart);
|
|
output(device, dp_pstop, dp8390info.dpi_pstop);
|
|
output(device, dp_bnry, dp8390info.dpi_pstart);
|
|
output(device, dp_rcr, RCR_MON);
|
|
output(device, dp_tcr, TCR_NORMAL);
|
|
output(device, dp_dcr, DCR_BYTEWIDE|DCR_8BYTES);
|
|
output(device, dp_rbcr0, 0);
|
|
output(device, dp_rbcr1, 0);
|
|
output(device, dp_isr, 0xFF);
|
|
output(device, dp_cr, CR_PS_P1|CR_DM_ABORT); /* switch to register set 1 */
|
|
output1(device, dp_par0, myaddr->e[0]);
|
|
output1(device, dp_par1, myaddr->e[1]);
|
|
output1(device, dp_par2, myaddr->e[2]);
|
|
output1(device, dp_par3, myaddr->e[3]);
|
|
output1(device, dp_par4, myaddr->e[4]);
|
|
output1(device, dp_par5, myaddr->e[5]);
|
|
output1(device, dp_curr, dp8390info.dpi_pstart+1);
|
|
output1(device, dp_cr, CR_PS_P0|CR_DM_ABORT);
|
|
output(device, dp_rcr, RCR_AB);
|
|
input(device, dp_cntr0);
|
|
input(device, dp_cntr1);
|
|
input(device, dp_cntr2);
|
|
|
|
#ifdef TRMTINT
|
|
output(device, dp_imr, IMR_TXEE|IMR_PTXE|IMR_PRXE|IMR_CNTE|IMR_OVWE);
|
|
#endif
|
|
output(device, dp_imr, IMR_PRXE|IMR_CNTE|IMR_OVWE);
|
|
output(device, dp_cr, CR_STA|CR_DM_ABORT); /* fire it up */
|
|
}
|
|
|
|
/*
|
|
|
|
* Interrupt handling
|
|
*/
|
|
|
|
static
|
|
dp_xmit_intr()
|
|
#ifdef TRMTINT
|
|
{
|
|
register tsr;
|
|
|
|
if (curopacket == 0) {
|
|
printf("Bogus transmit interrupt\n");
|
|
STINC(ds_btint);
|
|
return;
|
|
}
|
|
tsr = input(dp8390info.dpi_devaddr, dp_tsr);
|
|
if (tsr&TSR_PTX)
|
|
STINC(ds_written); /* It went OK! */
|
|
if (tsr&TSR_DFR)
|
|
STINC(ds_deferred);
|
|
if (tsr&TSR_COL)
|
|
STINC(ds_collisions);
|
|
if (tsr&TSR_ABT)
|
|
STINC(ds_xcollisions);
|
|
if (tsr&TSR_CRS) {
|
|
printf("Ethernet carrier sense lost\n");
|
|
STINC(ds_carlost);
|
|
}
|
|
if (tsr&TSR_FU) {
|
|
printf("Ethernet Fifo Underrun\n");
|
|
STINC(ds_fifo);
|
|
}
|
|
if (tsr&TSR_CDH) {
|
|
printf("Ethernet Heartbeat failure\n");
|
|
STINC(ds_heartbeat);
|
|
}
|
|
if (tsr&TSR_OWC) {
|
|
printf("Ethernet late collision\n");
|
|
STINC(ds_lcol);
|
|
}
|
|
(*bufwritten)(curopacket);
|
|
curopacket = 0;
|
|
}
|
|
#else
|
|
{}
|
|
#endif
|
|
|
|
|
|
static
|
|
recvintr()
|
|
{
|
|
register vir_bytes device;
|
|
register phys_bytes paddr;
|
|
struct rcvdheader pkthead;
|
|
char pageno, curr, next;
|
|
int length;
|
|
|
|
device = dp8390info.dpi_devaddr;
|
|
pageno=input(device, dp_bnry)+1;
|
|
if (pageno == dp8390info.dpi_pstop)
|
|
pageno = dp8390info.dpi_pstart;
|
|
while (!(disabled)) {
|
|
output(device, dp_cr, CR_PS_P1);/* switch to register set 1 */
|
|
curr = input1(device, dp_curr);
|
|
output1(device, dp_cr, CR_PS_P0);/* back to main register set*/
|
|
if (pageno==curr){
|
|
break;
|
|
}
|
|
STINC(ds_read);
|
|
paddr = dp8390info.dpi_membase+(pageno<<8);
|
|
getheader(paddr, &pkthead);
|
|
|
|
next = pkthead.rp_next;
|
|
if (pkthead.rp_status&RSR_PRX) {
|
|
if (next < pageno && next > dp8390info.dpi_pstart) {
|
|
/*
|
|
* We copy end of packet to avoid break.
|
|
*/
|
|
phys_copy(dp8390info.dpi_membase+
|
|
(dp8390info.dpi_pstart<<8),
|
|
dp8390info.dpi_membase+
|
|
(dp8390info.dpi_pstop<<8),
|
|
(phys_bytes) (next-dp8390info.dpi_pstart)<<8);
|
|
}
|
|
length = (pkthead.rp_rbcl&0xFF)|(pkthead.rp_rbch<<8);
|
|
Curbuff = paddr + sizeof (pkthead);
|
|
disabled = 1;
|
|
(*bufread)(Curbuff, length-4);
|
|
}
|
|
pageno = pkthead.rp_next;
|
|
if (pageno >= dp8390info.dpi_pstop ||
|
|
pageno < dp8390info.dpi_pstart)
|
|
printf("page no %x\n", pageno);
|
|
/* assert(pageno >= dp8390info.dpi_pstart);
|
|
assert(pageno < dp8390info.dpi_pstop);*/
|
|
}
|
|
}
|
|
|
|
static
|
|
cntintr()
|
|
{
|
|
register vir_bytes device;
|
|
int n;
|
|
|
|
printf("dp8390: counter overflow\n"); /*DEBUG*/
|
|
device = dp8390info.dpi_devaddr;
|
|
n = input(device, dp_cntr0);
|
|
STADD(ds_fram, n);
|
|
n = input(device, dp_cntr1);
|
|
STADD(ds_crc, n);
|
|
n =input(device, dp_cntr2);
|
|
STADD(ds_lost, n);
|
|
}
|
|
|
|
PUBLIC void
|
|
dp8390_int()
|
|
{
|
|
register isr;
|
|
register vir_bytes device;
|
|
|
|
device = dp8390info.dpi_devaddr;
|
|
for(isr=input(device, dp_isr); isr&(ISR_OVW|ISR_PRX|ISR_PTX|ISR_CNT);
|
|
isr=input(device, dp_isr)) {
|
|
if (isr&ISR_OVW) {
|
|
printf("OVW, do something\n");
|
|
output(device, dp_isr, ISR_OVW); /* ack */
|
|
}
|
|
if (isr&ISR_PTX) {
|
|
dp_xmit_intr();
|
|
output(device, dp_isr, ISR_PTX); /* ack */
|
|
}
|
|
if (isr&ISR_TXE) {
|
|
dp_xmit_intr();
|
|
output(device, dp_isr, ISR_TXE); /* ack */
|
|
}
|
|
if (isr&ISR_PRX) {
|
|
/*recvintr();*/
|
|
got_packet();
|
|
output(device, dp_isr, ISR_PRX); /* ack */
|
|
}
|
|
if (isr&ISR_CNT) {
|
|
cntintr();
|
|
output(device, dp_isr, ISR_CNT); /* ack */
|
|
}
|
|
}
|
|
}
|
|
|
|
eth_init(etheraddr, br, bw)
|
|
Eth_addr *etheraddr;
|
|
int (*br)(), (*bw)();
|
|
{
|
|
bufread = br;
|
|
bufwritten = bw;
|
|
epl_init(); /* activate on board memory */
|
|
chipinit(etheraddr); /* start ethernet controller chip */
|
|
}
|
|
|
|
|
|
|
|
eth_write(bufaddr, bufcnt)
|
|
phys_bytes bufaddr;
|
|
{
|
|
int bpageno;
|
|
register vir_bytes device;
|
|
|
|
|
|
device = dp8390info.dpi_devaddr;
|
|
/* assert(curopacket==0); */
|
|
assert(((bufaddr-dp8390info.dpi_membase)&0xFF)==0);
|
|
assert(bufcnt >= 60); /* magic Ethernet requirement */
|
|
/* assert(bufcnt <= 1514); /* another one */
|
|
bpageno = ((bufaddr-dp8390info.dpi_membase)>>8) & 0xFF;
|
|
curopacket = bufaddr;
|
|
output(device, dp_tpsr, bpageno);
|
|
output(device, dp_tbcr1, bufcnt>>8);
|
|
output(device, dp_tbcr0, bufcnt&0xFF);
|
|
output(device, dp_cr, CR_TXP); /* there it goes */
|
|
}
|
|
|
|
eth_release(bufaddr)
|
|
phys_bytes bufaddr;
|
|
{
|
|
register vir_bytes device;
|
|
register phys_bytes paddr;
|
|
struct rcvdheader pkthead;
|
|
char pageno;
|
|
|
|
device = dp8390info.dpi_devaddr;
|
|
paddr = bufaddr-sizeof(pkthead);
|
|
assert(((paddr-dp8390info.dpi_membase)&0xFF)==0);
|
|
getheader(paddr, &pkthead);
|
|
pageno = pkthead.rp_next;
|
|
if (pageno == dp8390info.dpi_pstart)
|
|
pageno = dp8390info.dpi_pstop;
|
|
if (bufaddr != Curbuff)
|
|
panic("eth_release: bad order", NO_NUM);
|
|
output(device, dp_bnry, pageno-1);
|
|
disabled = 0;
|
|
/* recvintr(); */
|
|
}
|
|
|
|
phys_bytes
|
|
eth_getbuf()
|
|
{
|
|
int t_cnt;
|
|
register vir_bytes device;
|
|
register tsr;
|
|
|
|
device = dp8390info.dpi_devaddr;
|
|
|
|
t_cnt = 0;
|
|
while (input(device,dp_cr)&CR_TXP) {
|
|
if (t_cnt++ > MAX_WAIT)
|
|
printf("transmitter frozen\n");
|
|
return (phys_bytes)0;
|
|
}
|
|
|
|
#ifndef TRMTINT
|
|
#ifdef DPSTAT
|
|
tsr = input(device, dp_tsr);
|
|
if (tsr&TSR_PTX)
|
|
STINC(ds_written); /* It went OK! */
|
|
if (tsr&TSR_DFR)
|
|
STINC(ds_deferred);
|
|
if (tsr&TSR_COL)
|
|
STINC(ds_collisions);
|
|
if (tsr&TSR_ABT)
|
|
STINC(ds_xcollisions);
|
|
if (tsr&TSR_CRS) {
|
|
printf("Ethernet carrier sense lost\n");
|
|
STINC(ds_carlost);
|
|
}
|
|
if (tsr&TSR_FU) {
|
|
printf("Ethernet Fifo Underrun\n");
|
|
STINC(ds_fifo);
|
|
}
|
|
if (tsr&TSR_CDH) {
|
|
printf("Ethernet Heartbeat failure\n");
|
|
STINC(ds_heartbeat);
|
|
}
|
|
if (tsr&TSR_OWC) {
|
|
printf("Ethernet late collision\n");
|
|
STINC(ds_lcol);
|
|
}
|
|
#endif
|
|
#endif
|
|
return dp8390info.dpi_tbuf; /* return pointer to xmit buffer */
|
|
}
|
|
|
|
#else NONET
|
|
|
|
PUBLIC void
|
|
dp8390_int()
|
|
{
|
|
}
|
|
|
|
#endif NONET
|
|
|
|
PUBLIC void
|
|
eth_stp()
|
|
{
|
|
/* called from reboot() (klib88.s) to stop the ethernet */
|
|
#ifndef NONET
|
|
output(dp8390info.dpi_devaddr, dp_cr, CR_STP|CR_DM_ABORT);
|
|
|
|
#endif
|
|
}
|
|
|