add cycv ethernet driver
This commit is contained in:
parent
17ebe55031
commit
d64f76c96c
6 changed files with 482 additions and 2 deletions
|
@ -24,6 +24,7 @@ dev
|
||||||
segment
|
segment
|
||||||
|
|
||||||
link
|
link
|
||||||
|
ethercycv
|
||||||
ethermedium
|
ethermedium
|
||||||
loopbackmedium
|
loopbackmedium
|
||||||
netdevmedium
|
netdevmedium
|
||||||
|
|
|
@ -200,3 +200,5 @@ struct DevConf
|
||||||
};
|
};
|
||||||
|
|
||||||
#define mpcore ((ulong*)MPCORE_BASE)
|
#define mpcore ((ulong*)MPCORE_BASE)
|
||||||
|
#define resetmgr ((ulong*)RESETMGR_BASE)
|
||||||
|
#define sysmgr ((ulong*)SYSMGR_BASE)
|
||||||
|
|
438
sys/src/9/cycv/ethercycv.c
Normal file
438
sys/src/9/cycv/ethercycv.c
Normal file
|
@ -0,0 +1,438 @@
|
||||||
|
#include "u.h"
|
||||||
|
#include "../port/lib.h"
|
||||||
|
#include "mem.h"
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "../port/netif.h"
|
||||||
|
#include "../port/etherif.h"
|
||||||
|
|
||||||
|
#define Rbsz ROUNDUP(sizeof(Etherpkt)+16, 64)
|
||||||
|
|
||||||
|
enum {
|
||||||
|
Linkdelay = 500,
|
||||||
|
RXRING = 512,
|
||||||
|
TXRING = 512
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
PERMODRST_EMAC1 = 1<<1,
|
||||||
|
|
||||||
|
SYSMGR_EMAC_CTRL = 0x60/4,
|
||||||
|
|
||||||
|
MAC_CONFIG = 0x0/4,
|
||||||
|
MAC_FRAME_FILTER = 0x4/4,
|
||||||
|
|
||||||
|
GMII_ADDRESS = 0x10/4,
|
||||||
|
GMII_DATA = 0x14/4,
|
||||||
|
|
||||||
|
INTERRUPT_STATUS = 0x38/4,
|
||||||
|
INTERRUPT_MASK = 0x3C/4,
|
||||||
|
|
||||||
|
MAC_ADDRESS = 0x40/4,
|
||||||
|
HASH_TABLE = 0x500/4,
|
||||||
|
|
||||||
|
DMA_BUS_MODE = 0x1000/4,
|
||||||
|
DMA_BUS_MODE_SWR = 1<<0,
|
||||||
|
DMA_TX_POLL = 0x1004/4,
|
||||||
|
DMA_RX_POLL = 0x1008/4,
|
||||||
|
DMA_STATUS = 0x1014/4,
|
||||||
|
DMA_OPERATION_MODE = 0x1018/4,
|
||||||
|
DMA_INTERRUPT_ENABLE = 0x101C/4,
|
||||||
|
DMA_AXI_STATUS = 0x102C/4,
|
||||||
|
|
||||||
|
RXRING_ADDRESS = 0x100C/4,
|
||||||
|
TXRING_ADDRESS = 0x1010/4,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MDCTRL,
|
||||||
|
MDSTATUS,
|
||||||
|
MDID1,
|
||||||
|
MDID2,
|
||||||
|
MDAUTOADV,
|
||||||
|
MDAUTOPART,
|
||||||
|
MDAUTOEX,
|
||||||
|
MDAUTONEXT,
|
||||||
|
MDAUTOLINK,
|
||||||
|
MDGCTRL,
|
||||||
|
MDGSTATUS,
|
||||||
|
MDPHYCTRL = 0x1f,
|
||||||
|
|
||||||
|
/* MDCTRL */
|
||||||
|
MDRESET = 1<<15,
|
||||||
|
AUTONEG = 1<<12,
|
||||||
|
FULLDUP = 1<<8,
|
||||||
|
/* MDSTATUS */
|
||||||
|
LINK = 1<<2,
|
||||||
|
/* MDGSTATUS */
|
||||||
|
RECVOK = 3<<12,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct Ctlr Ctlr;
|
||||||
|
|
||||||
|
struct Ctlr {
|
||||||
|
ulong *r;
|
||||||
|
ulong *rxr, *txr;
|
||||||
|
Block **rxs, **txs;
|
||||||
|
int rxprodi, rxconsi, txi;
|
||||||
|
int attach;
|
||||||
|
Lock txlock;
|
||||||
|
uchar (*mc)[6];
|
||||||
|
int nmc;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
mdwrite(Ctlr *c, int r, u16int v)
|
||||||
|
{
|
||||||
|
while((c->r[GMII_ADDRESS] & 1<<0) != 0);
|
||||||
|
c->r[GMII_DATA] = v;
|
||||||
|
c->r[GMII_ADDRESS] = 1<<11 | (r&31)<<6 | 1<<1 | 1<<0;
|
||||||
|
while((c->r[GMII_ADDRESS] & 1<<0) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u16int
|
||||||
|
mdread(Ctlr *c, int r)
|
||||||
|
{
|
||||||
|
while((c->r[GMII_ADDRESS] & 1<<0) != 0);
|
||||||
|
c->r[GMII_ADDRESS] = 1<<11 | (r&31)<<6 | 1<<0;
|
||||||
|
while((c->r[GMII_ADDRESS] & 1<<0) != 0);
|
||||||
|
return c->r[GMII_DATA];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethproc(void *ved)
|
||||||
|
{
|
||||||
|
Ether *edev;
|
||||||
|
Ctlr *c;
|
||||||
|
char *sp, *dpl;
|
||||||
|
u16int v;
|
||||||
|
|
||||||
|
edev = ved;
|
||||||
|
c = edev->ctlr;
|
||||||
|
|
||||||
|
mdwrite(c, MDCTRL, AUTONEG);
|
||||||
|
for(;;){
|
||||||
|
if((mdread(c, MDSTATUS) & LINK) == 0){
|
||||||
|
edev->link = 0;
|
||||||
|
print("eth: no link\n");
|
||||||
|
while((mdread(c, MDSTATUS) & LINK) == 0)
|
||||||
|
tsleep(&up->sleep, return0, nil, Linkdelay);
|
||||||
|
}
|
||||||
|
v = mdread(c, MDPHYCTRL);
|
||||||
|
if((v & 0x40) != 0){
|
||||||
|
sp = "1000BASE-T";
|
||||||
|
while((mdread(c, MDGSTATUS) & RECVOK) != RECVOK)
|
||||||
|
;
|
||||||
|
edev->mbps = 1000;
|
||||||
|
c->r[MAC_CONFIG] &= ~(1<<15);
|
||||||
|
|
||||||
|
}else if((v & 0x20) != 0){
|
||||||
|
sp = "100BASE-TX";
|
||||||
|
edev->mbps = 100;
|
||||||
|
c->r[MAC_CONFIG] = c->r[MAC_CONFIG] | (1<<15|1<<14);
|
||||||
|
}else if((v & 0x10) != 0){
|
||||||
|
sp = "10BASE-T";
|
||||||
|
edev->mbps = 10;
|
||||||
|
c->r[MAC_CONFIG] = c->r[MAC_CONFIG] & ~(1<<14) | 1<<15;
|
||||||
|
}else
|
||||||
|
sp = "???";
|
||||||
|
if((v & 0x08) != 0){
|
||||||
|
dpl = "full";
|
||||||
|
c->r[MAC_CONFIG] |= 1<<11;
|
||||||
|
}else{
|
||||||
|
dpl = "half";
|
||||||
|
c->r[MAC_CONFIG] &= ~(1<<11);
|
||||||
|
}
|
||||||
|
edev->link = 1;
|
||||||
|
print("eth: %s %s duplex link\n", sp, dpl);
|
||||||
|
c->r[MAC_CONFIG] |= 1<<3 | 1<<2;
|
||||||
|
while((mdread(c, MDSTATUS) & LINK) != 0)
|
||||||
|
tsleep(&up->sleep, return0, nil, Linkdelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
replenish(Ctlr *c)
|
||||||
|
{
|
||||||
|
Block *bp;
|
||||||
|
int i;
|
||||||
|
ulong *r;
|
||||||
|
|
||||||
|
while(c->rxprodi != c->rxconsi){
|
||||||
|
i = c->rxprodi;
|
||||||
|
bp = iallocb(Rbsz);
|
||||||
|
if(bp == nil){
|
||||||
|
print("eth: out of memory for receive buffers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
c->rxs[i] = bp;
|
||||||
|
r = &c->rxr[4 * i];
|
||||||
|
r[0] = 0;
|
||||||
|
cleandse(bp->base, bp->lim);
|
||||||
|
r[1] = Rbsz;
|
||||||
|
if(i == RXRING - 1) r[1] |= 1<<15;
|
||||||
|
r[2] = PADDR(bp->rp);
|
||||||
|
r[3] = 0;
|
||||||
|
r[0] |= 1<<31;
|
||||||
|
c->rxprodi = (c->rxprodi + 1) & (RXRING - 1);
|
||||||
|
}
|
||||||
|
c->r[DMA_RX_POLL] = 0xBA5EBA11;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethrx(Ether *edev)
|
||||||
|
{
|
||||||
|
Ctlr *c;
|
||||||
|
ulong *r;
|
||||||
|
Block *bp;
|
||||||
|
|
||||||
|
c = edev->ctlr;
|
||||||
|
for(;;){
|
||||||
|
r = &c->rxr[4 * c->rxconsi];
|
||||||
|
if((r[0] >> 31) != 0)
|
||||||
|
break;
|
||||||
|
if((r[0] & 1<<15) != 0)
|
||||||
|
iprint("eth: error frame\n");
|
||||||
|
if((r[0] & (3<<8)) != (3<<8))
|
||||||
|
iprint("eth: lilu dallas multidescriptor\n");
|
||||||
|
bp = c->rxs[c->rxconsi];
|
||||||
|
bp->wp = bp->rp + (r[0] >> 16 & 0x3fff);
|
||||||
|
invaldse(bp->rp, bp->wp);
|
||||||
|
etheriq(edev, bp);
|
||||||
|
c->rxconsi = (c->rxconsi + 1) & (RXRING - 1);
|
||||||
|
replenish(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethtx(Ether *edev)
|
||||||
|
{
|
||||||
|
Ctlr *c;
|
||||||
|
ulong *r;
|
||||||
|
Block *bp;
|
||||||
|
|
||||||
|
c = edev->ctlr;
|
||||||
|
ilock(&c->txlock);
|
||||||
|
for(;;){
|
||||||
|
r = &c->txr[4 * c->txi];
|
||||||
|
if((r[0] >> 31) != 0){
|
||||||
|
print("eth: transmit buffer full\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bp = qget(edev->oq);
|
||||||
|
if(bp == nil)
|
||||||
|
break;
|
||||||
|
if(c->txs[c->txi] != nil)
|
||||||
|
freeb(c->txs[c->txi]);
|
||||||
|
c->txs[c->txi] = bp;
|
||||||
|
cleandse(bp->rp, bp->wp);
|
||||||
|
r[0] = 1<<30 | 1<<29 | 1<<28;
|
||||||
|
if(c->txi == TXRING - 1)
|
||||||
|
r[0] |= 1<<21;
|
||||||
|
r[1] = BLEN(bp);
|
||||||
|
r[2] = PADDR(bp->rp);
|
||||||
|
r[3] = 0;
|
||||||
|
r[0] |= 1<<31;
|
||||||
|
coherence();
|
||||||
|
c->r[DMA_TX_POLL] = 0xBA5EBA11;
|
||||||
|
c->txi = (c->txi + 1) & (TXRING - 1);
|
||||||
|
}
|
||||||
|
iunlock(&c->txlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethirq(Ureg *, void *arg)
|
||||||
|
{
|
||||||
|
Ether *edev;
|
||||||
|
Ctlr *c;
|
||||||
|
ulong fl;
|
||||||
|
|
||||||
|
edev = arg;
|
||||||
|
c = edev->ctlr;
|
||||||
|
fl = c->r[DMA_STATUS];
|
||||||
|
c->r[DMA_STATUS] = fl;
|
||||||
|
if((fl & 1<<1) != 0)
|
||||||
|
iprint("eth: transmit stop\n");
|
||||||
|
if((fl & (1<<0|1<<2)) != 0)
|
||||||
|
ethtx(edev);
|
||||||
|
if((fl & 1<<4) != 0)
|
||||||
|
iprint("eth: receive overflow\n");
|
||||||
|
if((fl & (1<<6|1<<7)) != 0)
|
||||||
|
ethrx(edev);
|
||||||
|
if((fl & 1<<8) != 0)
|
||||||
|
iprint("eth: receive stop\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ethinit(Ether *edev)
|
||||||
|
{
|
||||||
|
Ctlr *c;
|
||||||
|
|
||||||
|
c = edev->ctlr;
|
||||||
|
resetmgr[PERMODRST] |= PERMODRST_EMAC1;
|
||||||
|
/* assume bootloader set up clock */
|
||||||
|
sysmgr[SYSMGR_EMAC_CTRL] = 1<<2 | 1; /* RGMII */
|
||||||
|
sysmgr[FPGA_MODULE] = sysmgr[FPGA_MODULE] & ~(1<<2 | 1<<3);
|
||||||
|
microdelay(1);
|
||||||
|
resetmgr[PERMODRST] &= ~PERMODRST_EMAC1;
|
||||||
|
|
||||||
|
/* reset DMA */
|
||||||
|
c->r[DMA_BUS_MODE] |= DMA_BUS_MODE_SWR;
|
||||||
|
do microdelay(1);
|
||||||
|
while((c->r[DMA_BUS_MODE] & DMA_BUS_MODE_SWR) != 0);
|
||||||
|
/* wait for AXI transactions to finish */
|
||||||
|
while((c->r[DMA_AXI_STATUS] & 3) != 0)
|
||||||
|
microdelay(1);
|
||||||
|
/* set up bus mode (32 beat bursts) */
|
||||||
|
c->r[DMA_BUS_MODE] |= 32 << 8;
|
||||||
|
|
||||||
|
c->r[MAC_ADDRESS] = 1<<31 | edev->ea[5] << 8 | edev->ea[4];
|
||||||
|
c->r[MAC_ADDRESS+1] = edev->ea[3] << 24 | edev->ea[2] << 16 | edev->ea[1] << 8 | edev->ea[0];
|
||||||
|
c->r[MAC_FRAME_FILTER] = 0;
|
||||||
|
|
||||||
|
c->rxr = ucalloc(16 * RXRING);
|
||||||
|
c->txr = ucalloc(16 * TXRING);
|
||||||
|
c->rxs = xspanalloc(4 * RXRING, 4, 0);
|
||||||
|
c->txs = xspanalloc(4 * TXRING, 4, 0);
|
||||||
|
memset(c->rxr, 0, 16 * RXRING);
|
||||||
|
memset(c->txr, 0, 16 * TXRING);
|
||||||
|
c->rxconsi = 1;
|
||||||
|
replenish(c);
|
||||||
|
c->rxconsi = 0;
|
||||||
|
replenish(c);
|
||||||
|
|
||||||
|
c->r[RXRING_ADDRESS] = PADDR(c->rxr);
|
||||||
|
c->r[TXRING_ADDRESS] = PADDR(c->txr);
|
||||||
|
c->r[DMA_STATUS] = -1;
|
||||||
|
c->r[INTERRUPT_MASK] = -1;
|
||||||
|
c->r[DMA_INTERRUPT_ENABLE] = 1<<16 | 1<<15 | 1<<8 | 1<<6 | 1<<2 | 1<<1 | 1<<0;
|
||||||
|
c->r[DMA_OPERATION_MODE] = 1<<1 | 1<<13;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethattach(Ether *edev)
|
||||||
|
{
|
||||||
|
Ctlr *c;
|
||||||
|
|
||||||
|
c = edev->ctlr;
|
||||||
|
if(c->attach)
|
||||||
|
return;
|
||||||
|
c->attach = 1;
|
||||||
|
kproc("ethproc", ethproc, edev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethprom(void *arg, int on)
|
||||||
|
{
|
||||||
|
Ether *edev;
|
||||||
|
Ctlr *c;
|
||||||
|
|
||||||
|
edev = arg;
|
||||||
|
c = edev->ctlr;
|
||||||
|
if(on)
|
||||||
|
c->r[MAC_FRAME_FILTER] |= 0x80000001;
|
||||||
|
else
|
||||||
|
c->r[MAC_FRAME_FILTER] &= ~0x80000001;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
sethash(uchar *ea, ulong *hash)
|
||||||
|
{
|
||||||
|
ulong crc;
|
||||||
|
int i;
|
||||||
|
uchar n;
|
||||||
|
|
||||||
|
crc = ethercrc(ea, 6);
|
||||||
|
n = 0;
|
||||||
|
for(i = 0; i < 8; i++){
|
||||||
|
n = n << 1 | crc & 1;
|
||||||
|
crc >>= 1;
|
||||||
|
}
|
||||||
|
n ^= 0xff;
|
||||||
|
hash[n>>5] |= (1<<(n & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
ethmcast(void *arg, uchar *ea, int on)
|
||||||
|
{
|
||||||
|
enum { MCSlots = 31 };
|
||||||
|
Ether *edev;
|
||||||
|
Ctlr *c;
|
||||||
|
int i, p;
|
||||||
|
ulong hash[8];
|
||||||
|
|
||||||
|
edev = arg;
|
||||||
|
c = edev->ctlr;
|
||||||
|
if(on){
|
||||||
|
c->mc = realloc(c->mc, (c->nmc + 1) * 6);
|
||||||
|
memmove(c->mc[c->nmc++], ea, 6);
|
||||||
|
}else{
|
||||||
|
for(i = 0; i < c->nmc; i++)
|
||||||
|
if(memcmp(c->mc[i], ea, 6) == 0)
|
||||||
|
break;
|
||||||
|
if(i == c->nmc)
|
||||||
|
return;
|
||||||
|
memmove(c->mc[i], c->mc[i+1], (c->nmc - i - 1) * 6);
|
||||||
|
}
|
||||||
|
p = c->r[MAC_FRAME_FILTER];
|
||||||
|
/* set promiscuous in order to not lose packets while updating */
|
||||||
|
c->r[MAC_FRAME_FILTER] = p | 0x80000001;
|
||||||
|
if(c->nmc <= MCSlots){
|
||||||
|
for(i = 0; i < c->nmc; i++){
|
||||||
|
c->r[MAC_ADDRESS + 2 * (i + 1)] = 1<<31 | c->mc[i][5] << 8 | c->mc[i][4];
|
||||||
|
c->r[MAC_ADDRESS + 2 * (i + 1) + 1] = c->mc[i][3] << 24 | c->mc[i][2] << 16 | c->mc[i][1] << 8 | c->mc[i][0];
|
||||||
|
}
|
||||||
|
for(i = 2 * i; i < 2*MCSlots; i++)
|
||||||
|
c->r[MAC_ADDRESS + 2 + i] = 0;
|
||||||
|
c->r[MAC_FRAME_FILTER] = p & ~(1<<2);
|
||||||
|
}else{
|
||||||
|
memset(hash, 0, sizeof(hash));
|
||||||
|
for(i = 0; i < c->nmc; i++)
|
||||||
|
sethash(c->mc[i], hash);
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
c->r[HASH_TABLE + i] = hash[i];
|
||||||
|
c->r[MAC_FRAME_FILTER] = p | 1<<2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
etherpnp(Ether *edev)
|
||||||
|
{
|
||||||
|
static Ctlr ct;
|
||||||
|
static uchar mac[] = {0x0e, 0xa7, 0xde, 0xad, 0xca, 0xfe};
|
||||||
|
|
||||||
|
if(ct.r != nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memmove(edev->ea, mac, 6);
|
||||||
|
edev->ctlr = &ct;
|
||||||
|
edev->port = EMAC1_BASE;
|
||||||
|
ct.r = (ulong *) edev->port;
|
||||||
|
edev->irq = EMAC1IRQ;
|
||||||
|
edev->ctlr = &ct;
|
||||||
|
edev->attach = ethattach;
|
||||||
|
edev->transmit = ethtx;
|
||||||
|
edev->arg = edev;
|
||||||
|
edev->mbps = 1000;
|
||||||
|
edev->promiscuous = ethprom;
|
||||||
|
edev->multicast = ethmcast;
|
||||||
|
|
||||||
|
if(ethinit(edev) < 0){
|
||||||
|
edev->ctlr = nil;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
intrenable(edev->irq, ethirq, edev, LEVEL, edev->name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ethercycvlink(void)
|
||||||
|
{
|
||||||
|
addethercard("eth", etherpnp);
|
||||||
|
}
|
|
@ -2,11 +2,21 @@
|
||||||
#define MPCORE_BASE 0xFFFEC000
|
#define MPCORE_BASE 0xFFFEC000
|
||||||
#define L2_BASE 0xFFFEF000
|
#define L2_BASE 0xFFFEF000
|
||||||
#define CLOCKMGR_BASE 0xFFD04000
|
#define CLOCKMGR_BASE 0xFFD04000
|
||||||
|
#define EMAC1_BASE 0xFF702000
|
||||||
|
#define RESETMGR_BASE 0xFFD05000
|
||||||
|
#define SYSMGR_BASE 0xFFD08000
|
||||||
|
#define OCRAM 0xFFFF0000
|
||||||
|
|
||||||
|
/*RESETMGR*/
|
||||||
|
#define PERMODRST (0x14/4)
|
||||||
|
/*SYSMGR*/
|
||||||
|
#define FPGA_MODULE (0x28/4)
|
||||||
|
|
||||||
#define HPS_CLK 25
|
#define HPS_CLK 25
|
||||||
|
|
||||||
#define TIMERIRQ 29
|
#define TIMERIRQ 29
|
||||||
#define UART0IRQ 194
|
#define UART0IRQ 194
|
||||||
|
#define EMAC1IRQ 152
|
||||||
|
|
||||||
#define LEVEL 0
|
#define LEVEL 0
|
||||||
#define EDGE 1
|
#define EDGE 1
|
||||||
|
|
|
@ -7,6 +7,12 @@ TEXT _start(SB), $-4
|
||||||
MOVW $(KTZERO-KZERO), R13
|
MOVW $(KTZERO-KZERO), R13
|
||||||
MOVW $(UART_BASE), R8
|
MOVW $(UART_BASE), R8
|
||||||
|
|
||||||
|
/* disable watchdog */
|
||||||
|
MOVW $(RESETMGR_BASE + 4*PERMODRST), R1
|
||||||
|
MOVW (R1), R0
|
||||||
|
ORR $(3<<6), R0
|
||||||
|
MOVW R0, (R1)
|
||||||
|
|
||||||
/* disable L2 cache */
|
/* disable L2 cache */
|
||||||
MOVW $0, R0
|
MOVW $0, R0
|
||||||
MOVW $(L2_BASE+0x100), R1
|
MOVW $(L2_BASE+0x100), R1
|
||||||
|
@ -24,10 +30,10 @@ TEXT _start0(SB), $-4
|
||||||
ISB
|
ISB
|
||||||
PUTC('l')
|
PUTC('l')
|
||||||
|
|
||||||
/* clean up to KTZERO */
|
/* clean up to CONFADDR */
|
||||||
MOVW $0, R0
|
MOVW $0, R0
|
||||||
MOVW R0, R1
|
MOVW R0, R1
|
||||||
MOVW $(KTZERO-KZERO), R2
|
MOVW $(CONFADDR-KZERO), R2
|
||||||
_clrstart:
|
_clrstart:
|
||||||
MOVW.P R0, 4(R1)
|
MOVW.P R0, 4(R1)
|
||||||
CMP.S R1, R2
|
CMP.S R1, R2
|
||||||
|
|
|
@ -374,3 +374,26 @@ tmpunmap(void *v)
|
||||||
coherence();
|
coherence();
|
||||||
flushpg(v);
|
flushpg(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *
|
||||||
|
ucalloc(ulong len)
|
||||||
|
{
|
||||||
|
static Lock l;
|
||||||
|
static uchar *free = nil;
|
||||||
|
uchar *va;
|
||||||
|
|
||||||
|
if(len == 0)
|
||||||
|
panic("ucalloc: len == 0");
|
||||||
|
ilock(&l);
|
||||||
|
if(free == nil)
|
||||||
|
free = (uchar*)-BY2PG;
|
||||||
|
len = PGROUND(len);
|
||||||
|
free -= len;
|
||||||
|
if(free < (uchar*)OCRAM)
|
||||||
|
panic("ucalloc: out of uncached memory");
|
||||||
|
va = free;
|
||||||
|
iunlock(&l);
|
||||||
|
|
||||||
|
invaldse(va, va + len);
|
||||||
|
return (void *) va;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue