#include <sys/param.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <lib/libsa/netif.h>
#include <lib/libsa/stand.h>
#include "lib/libkern/libkern.h"
#include <dev/qbus/if_qereg.h>
#include "../include/rpb.h"
#include "vaxstand.h"
static int qe_get(struct iodesc *desc, void *pkt, size_t, saseconds_t timeout);
static int qe_put(struct iodesc *desc, void *pkt, size_t);
static void qe_init(u_char *eaddr);
struct netif_driver qe_driver = {
0, 0, 0, 0, qe_get, qe_put,
};
#define NRCV 1
#define NXMT 1
#define QE_INTS (QE_RCV_INT | QE_XMIT_INT)
#define MAXPACKETSIZE 0x800
static struct qe_softc {
struct qe_ring rring[NRCV+2];
struct qe_ring tring[NXMT+2];
u_char setup_pkt[16][8];
char qein[2048], qeout[2048];
} qe_softc;
static struct qe_softc *sc = &qe_softc, *psc;
static int addr, ubaddr;
#define QE_WCSR(csr, val) \
(*((volatile u_short *)(addr + (csr))) = (val))
#define QE_RCSR(csr) \
*((volatile u_short *)(addr + (csr)))
#define DELAY(x) {volatile int i = x;while (--i);}
#define LOWORD(x) ((int)(x) & 0xffff)
#define HIWORD(x) (((int)(x) >> 16) & 0x3f)
#define qereg(x) ((x) & 017777)
int
qeopen(struct open_file *f, int adapt, int ctlr, int unit, int part) {
u_char eaddr[6];
if (askname == 0)
addr = bootrpb.csrphy;
else {
addr = 0x20000000;
if (unit == 0)
addr += qereg(0774440);
else if (unit == 1)
addr += qereg(0174460);
else
return ECTLR;
}
qe_init(eaddr);
net_devinit(f, &qe_driver, eaddr);
return 0;
}
void
qe_init(u_char *eaddr)
{
int i,j;
QE_WCSR(QE_CSR_CSR, QE_RESET);
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RESET);
ubaddr = ubmap(0, (int)sc, sizeof(struct qe_softc));
psc = (struct qe_softc *)ubaddr;
for (i = 0; i < 6; i++) {
sc->setup_pkt[i][1] = QE_RCSR(i * 2);
sc->setup_pkt[i+8][1] = QE_RCSR(i * 2);
sc->setup_pkt[i][2] = 0xff;
sc->setup_pkt[i+8][2] = QE_RCSR(i * 2);
for (j=3; j < 8; j++) {
sc->setup_pkt[i][j] = QE_RCSR(i * 2);
sc->setup_pkt[i+8][j] = QE_RCSR(i * 2);
}
eaddr[i] = QE_RCSR(i * 2);
}
memset((void *)sc->rring, 0, sizeof(struct qe_ring));
sc->rring->qe_buf_len = -64;
sc->rring->qe_addr_lo = LOWORD(psc->setup_pkt);
sc->rring->qe_addr_hi = HIWORD(psc->setup_pkt);
memset((void *)sc->tring, 0, sizeof(struct qe_ring));
sc->tring->qe_buf_len = -64;
sc->tring->qe_addr_lo = LOWORD(psc->setup_pkt);
sc->tring->qe_addr_hi = HIWORD(psc->setup_pkt);
sc->rring[0].qe_flag = sc->rring[0].qe_status1 = QE_NOTYET;
sc->rring->qe_addr_hi |= QE_VALID;
sc->tring[0].qe_flag = sc->tring[0].qe_status1 = QE_NOTYET;
sc->tring->qe_addr_hi |= QE_VALID | QE_SETUP | QE_EOMSG;
QE_WCSR(QE_CSR_CSR, QE_XMIT_INT | QE_RCV_INT);
QE_WCSR(QE_CSR_RCLL, LOWORD(psc->rring));
QE_WCSR(QE_CSR_RCLH, HIWORD(psc->rring));
QE_WCSR(QE_CSR_XMTL, LOWORD(psc->tring));
QE_WCSR(QE_CSR_XMTH, HIWORD(psc->tring));
while ((QE_RCSR(QE_CSR_CSR) & QE_INTS) != QE_INTS)
;
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_INTS);
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~(QE_INT_ENABLE|QE_ELOOP));
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_ILOOP);
sc->rring[0].qe_addr_lo = LOWORD(psc->qein);
sc->rring[0].qe_addr_hi = HIWORD(psc->qein);
sc->rring[0].qe_buf_len = -MAXPACKETSIZE/2;
sc->rring[0].qe_addr_hi |= QE_VALID;
sc->rring[0].qe_flag = sc->rring[0].qe_status1 = QE_NOTYET;
sc->rring[0].qe_status2 = 1;
sc->rring[1].qe_addr_lo = 0;
sc->rring[1].qe_addr_hi = 0;
sc->rring[1].qe_flag=sc->rring[1].qe_status1=QE_NOTYET;
sc->rring[1].qe_status2=1;
sc->tring[0].qe_addr_lo = LOWORD(psc->qeout);
sc->tring[0].qe_addr_hi = HIWORD(psc->qeout);
sc->tring[0].qe_buf_len = 0;
sc->tring[0].qe_flag = sc->tring[0].qe_status1 = QE_NOTYET;
sc->tring[0].qe_addr_hi |= QE_EOMSG|QE_VALID;
sc->tring[1].qe_flag = sc->tring[1].qe_status1 = QE_NOTYET;
sc->tring[1].qe_addr_lo = 0;
sc->tring[1].qe_addr_hi = 0;
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_RCV_ENABLE);
QE_WCSR(QE_CSR_RCLL, LOWORD(psc->rring));
QE_WCSR(QE_CSR_RCLH, HIWORD(psc->rring));
}
int
qe_get(struct iodesc *desc, void *pkt, size_t maxlen, saseconds_t timeout) {
int len, j;
retry:
for(j = 0x10000;j && (QE_RCSR(QE_CSR_CSR) & QE_RCV_INT) == 0; j--)
;
if ((QE_RCSR(QE_CSR_CSR) & QE_RCV_INT) == 0)
goto fail;
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~(QE_RCV_ENABLE|QE_XMIT_INT));
len= ((sc->rring[0].qe_status1 & QE_RBL_HI) |
(sc->rring[0].qe_status2 & QE_RBL_LO)) + 60;
if (sc->rring[0].qe_status1 & 0xc000)
goto fail;
if (len == 0)
goto retry;
memcpy(pkt, (void*)sc->qein,len);
end:
sc->rring[0].qe_status2 = sc->rring[1].qe_status2 = 1;
sc->rring[0].qe_flag = sc->rring[0].qe_status1 = QE_NOTYET;
sc->rring[1].qe_flag = sc->rring[1].qe_status1 = QE_NOTYET;
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) | QE_RCV_ENABLE);
QE_WCSR(QE_CSR_RCLL, LOWORD(psc->rring));
QE_WCSR(QE_CSR_RCLH, HIWORD(psc->rring));
return len;
fail: len = -1;
goto end;
}
int
qe_put(struct iodesc *desc, void *pkt, size_t len) {
int j;
memcpy((char *)sc->qeout, pkt, len);
sc->tring[0].qe_buf_len = -len/2;
sc->tring[0].qe_flag = sc->tring[0].qe_status1 = QE_NOTYET;
sc->tring[1].qe_flag = sc->tring[1].qe_status1 = QE_NOTYET;
QE_WCSR(QE_CSR_XMTL, LOWORD(psc->tring));
QE_WCSR(QE_CSR_XMTH, HIWORD(psc->tring));
for(j = 0; (j < 0x10000) && ((QE_RCSR(QE_CSR_CSR) & QE_XMIT_INT) == 0); j++)
;
if ((QE_RCSR(QE_CSR_CSR) & QE_XMIT_INT) == 0) {
u_char eaddr[6];
qe_init(eaddr);
return -1;
}
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RCV_INT);
if (sc->tring[0].qe_status1 & 0xc000) {
u_char eaddr[6];
qe_init(eaddr);
return -1;
}
return len;
}
int
qeclose(struct open_file *nif)
{
QE_WCSR(QE_CSR_CSR, QE_RESET);
QE_WCSR(QE_CSR_CSR, QE_RCSR(QE_CSR_CSR) & ~QE_RESET);
return 0;
}