Minix1.5/amoeba/kernel/dp8390.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
}