提交 524b494f 创建 作者: Frans Kaashoek's avatar Frans Kaashoek

Merge branch 'scale-amd64' of ssh://amsterdam.csail.mit.edu/home/am0/6.828/xv6 into scale-amd64

Conflicts: kernel.h
...@@ -32,6 +32,7 @@ OBJS = \ ...@@ -32,6 +32,7 @@ OBJS = \
condvar.o \ condvar.o \
console.o \ console.o \
crange.o \ crange.o \
e1000.o \
exec.o \ exec.o \
file.o \ file.o \
fs.o \ fs.o \
...@@ -44,7 +45,9 @@ OBJS = \ ...@@ -44,7 +45,9 @@ OBJS = \
main.o \ main.o \
memide.o \ memide.o \
mp.o \ mp.o \
net.o \
ns.o \ ns.o \
pci.o \
picirq.o \ picirq.o \
pipe.o \ pipe.o \
proc.o \ proc.o \
...@@ -84,6 +87,10 @@ UPROGS= \ ...@@ -84,6 +87,10 @@ UPROGS= \
_halt _halt
UPROGS := $(addprefix $(O)/, $(UPROGS)) UPROGS := $(addprefix $(O)/, $(UPROGS))
all: $(O)/kernel
include net.mk
$(O)/kernel: $(O) $(O)/boot.o $(OBJS) $(O)/kernel: $(O) $(O)/boot.o $(OBJS)
@echo " LD $@" @echo " LD $@"
$(Q)$(LD) $(LDFLAGS) -T kernel.ld -z max-page-size=4096 -e start \ $(Q)$(LD) $(LDFLAGS) -T kernel.ld -z max-page-size=4096 -e start \
...@@ -141,7 +148,9 @@ $(O)/mscan.kern: $(O)/kernel ...@@ -141,7 +148,9 @@ $(O)/mscan.kern: $(O)/kernel
## ##
## qemu ## qemu
## ##
QEMUOPTS = -smp $(QEMUSMP) -m 512 -serial mon:stdio -nographic QEMUOPTS = -smp $(QEMUSMP) -m 512 -serial mon:stdio -nographic \
-net user -net nic,model=e1000 \
-net dump,file=qemu.pcap
qemu: $(O)/kernel qemu: $(O)/kernel
$(QEMU) $(QEMUOPTS) -kernel $(O)/kernel $(QEMU) $(QEMUOPTS) -kernel $(O)/kernel
......
...@@ -28,6 +28,15 @@ inb(u16 port) ...@@ -28,6 +28,15 @@ inb(u16 port)
return data; return data;
} }
static inline u32
inl(u16 port)
{
u32 data = 0;
__asm volatile("inl %w1,%0" : "=a" (data) : "d" (port));
return data;
}
static inline void static inline void
outb(u16 port, u8 data) outb(u16 port, u8 data)
{ {
...@@ -35,6 +44,12 @@ outb(u16 port, u8 data) ...@@ -35,6 +44,12 @@ outb(u16 port, u8 data)
} }
static inline void static inline void
outl(u16 port, u32 data)
{
__asm volatile("outl %0,%w1" : : "a" (data), "d" (port));
}
static inline void
stosb(void *addr, int data, int cnt) stosb(void *addr, int data, int cnt)
{ {
__asm volatile("cld; rep stosb" : __asm volatile("cld; rep stosb" :
......
...@@ -134,9 +134,9 @@ tramp64: ...@@ -134,9 +134,9 @@ tramp64:
.comm stack, STACK .comm stack, STACK
# Page tables. See section 4.5 of 253668.pdf. # Page tables. See section 4.5 of 253668.pdf.
# We map the first GB of physical memory at 0 and at -2 GB (or 2 GB before # We map the first GB of physical memory at 0 and at KBASE. At boot
# the end of physical memory). At boot time we are using the mapping at 0 # time we are using the mapping at 0 but during ordinary execution we
# but during ordinary execution we use the high mapping. # use the high mapping.
# The intent is that after bootstrap the kernel can expand this mapping # The intent is that after bootstrap the kernel can expand this mapping
# to cover all the available physical memory. # to cover all the available physical memory.
# This would be easier if we could use the PS bit to create GB-sized entries # This would be easier if we could use the PS bit to create GB-sized entries
......
...@@ -8,15 +8,60 @@ ...@@ -8,15 +8,60 @@
#include "kernel.h" #include "kernel.h"
#include "cpu.h" #include "cpu.h"
void struct spinlock tickslock __mpalign__;
initcondvar(struct condvar *cv, char *n) struct condvar cv_ticks __mpalign__;
u64 ticks __mpalign__;
LIST_HEAD(sleepers, proc) sleepers __mpalign__;
struct spinlock sleepers_lock;
static void
wakeup(struct proc *p)
{ {
initlock(&cv->lock, n); LIST_REMOVE(p, cv_waiters);
cv->waiters = 0; p->oncv = 0;
addrun(p);
p->state = RUNNABLE;
} }
void void
cv_sleep(struct condvar *cv, struct spinlock *lk) cv_tick(void)
{
struct proc *p, *tmp;
int again;
u64 now;
acquire(&tickslock);
ticks++;
cv_wakeup(&cv_ticks);
release(&tickslock);
now = nsectime();
again = 0;
do {
acquire(&sleepers_lock);
LIST_FOREACH_SAFE(p, &sleepers, cv_sleep, tmp) {
if (p->cv_wakeup <= now) {
if (tryacquire(&p->lock)) {
if (tryacquire(&p->oncv->lock)) {
LIST_REMOVE(p, cv_sleep);
p->cv_wakeup = 0;
wakeup(p);
release(&p->lock);
release(&p->oncv->lock);
continue;
} else {
release(&p->lock);
}
}
again = 1;
}
}
release(&sleepers_lock);
} while (again);
}
void cv_sleepto(struct condvar *cv, struct spinlock *lk, u64 timeout)
{ {
if(myproc() == 0) if(myproc() == 0)
panic("sleep"); panic("sleep");
...@@ -31,44 +76,61 @@ cv_sleep(struct condvar *cv, struct spinlock *lk) ...@@ -31,44 +76,61 @@ cv_sleep(struct condvar *cv, struct spinlock *lk)
acquire(&myproc()->lock); acquire(&myproc()->lock);
if(myproc()->cv_next || myproc()->oncv) if(myproc()->oncv)
panic("cv_sleep cv_next"); panic("cv_sleep oncv");
myproc()->cv_next = cv->waiters;
cv->waiters = myproc(); LIST_INSERT_HEAD(&cv->waiters, myproc(), cv_waiters);
myproc()->state = SLEEPING;
myproc()->oncv = cv; myproc()->oncv = cv;
myproc()->state = SLEEPING;
if (timeout) {
acquire(&sleepers_lock);
myproc()->cv_wakeup = timeout;
LIST_INSERT_HEAD(&sleepers, myproc(), cv_sleep);
release(&sleepers_lock);
}
release(&cv->lock); release(&cv->lock);
sched(); sched();
release(&myproc()->lock); release(&myproc()->lock);
// Reacquire original lock. // Reacquire original lock.
acquire(lk); acquire(lk);
} }
void
cv_sleep(struct condvar *cv, struct spinlock *lk)
{
cv_sleepto(cv, lk, 0);
}
// Wake up all processes sleeping on this condvar. // Wake up all processes sleeping on this condvar.
void void
cv_wakeup(struct condvar *cv) cv_wakeup(struct condvar *cv)
{ {
// XXX race with cv_sleep() struct proc *p, *tmp;
// if (!cv->waiters)
// return;
acquire(&cv->lock); acquire(&cv->lock);
while(cv->waiters) { LIST_FOREACH_SAFE(p, &cv->waiters, cv_waiters, tmp) {
struct proc *p = cv->waiters;
acquire(&p->lock); acquire(&p->lock);
if(p->state != SLEEPING || p->oncv != cv) if(p->state != SLEEPING || p->oncv != cv)
panic("cv_wakeup"); panic("cv_wakeup");
struct proc *nxt = p->cv_next; if (p->cv_wakeup) {
p->cv_next = 0; acquire(&sleepers_lock);
p->oncv = 0; LIST_REMOVE(p, cv_sleep);
addrun(p); p->cv_wakeup = 0;
p->state = RUNNABLE; release(&sleepers_lock);
}
wakeup(p);
release(&p->lock); release(&p->lock);
cv->waiters = nxt;
} }
release(&cv->lock); release(&cv->lock);
} }
void
initcondvar(struct condvar *cv, char *n)
{
initlock(&cv->lock, n);
LIST_INIT(&cv->waiters);
}
#include "queue.h"
struct condvar { struct condvar {
struct spinlock lock; struct spinlock lock;
struct proc *waiters; LIST_HEAD(waiters, proc) waiters;
}; };
#include "types.h"
#include "amd64.h"
#include "kernel.h"
#include "pci.h"
#include "e1000reg.h"
#define TX_RING_SIZE 64
#define RX_RING_SIZE 64
int e1000irq;
static struct {
u32 membase;
u32 iobase;
u16 pcidevid;
u32 txclean;
u32 txinuse;
u32 rxclean;
u32 rxuse;
struct wiseman_txdesc txd[TX_RING_SIZE] __attribute__((aligned (16)));
struct wiseman_rxdesc rxd[RX_RING_SIZE] __attribute__((aligned (16)));
} e1000;
static inline u32
erd(u32 reg)
{
paddr pa = e1000.membase + reg;
volatile u32 *ptr = p2v(pa);
return *ptr;
}
static inline void
ewr(u32 reg, u32 val)
{
paddr pa = e1000.membase + reg;
volatile u32 *ptr = p2v(pa);
*ptr = val;
}
static int
eeprom_eerd_read(u16 off)
{
u32 reg;
int x;
// [E1000 5.3.1] Software EEPROM access
ewr(WMREG_EERD, (off<<EERD_ADDR_SHIFT) | EERD_START);
for (x = 0; x < 5; x++) {
reg = erd(WMREG_EERD);
if (reg & EERD_DONE)
return (reg&EERD_DATA_MASK) >> EERD_DATA_SHIFT;
microdelay(50000);
}
return -1;
}
static int
eeprom_read(u16 *buf, int off, int count)
{
for (int i = 0; i < count; i++) {
int r = eeprom_eerd_read(off+i);
if (r < 0) {
cprintf("eeprom_read: cannot read\n");
return -1;
}
buf[i] = r;
}
return 0;
}
int
e1000tx(void *buf, u32 len)
{
struct wiseman_txdesc *desc;
u32 tail;
// WMREG_TDT should only equal WMREG_TDH when we have
// nothing to transmit. Therefore, we can accomodate
// TX_RING_SIZE-1 buffers.
if (e1000.txinuse == TX_RING_SIZE-1) {
cprintf("TX ring overflow\n");
return -1;
}
tail = erd(WMREG_TDT);
desc = &e1000.txd[tail];
if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD))
panic("oops");
desc->wtx_addr = v2p(buf);
desc->wtx_cmdlen = len | WTX_CMD_RS | WTX_CMD_EOP | WTX_CMD_IFCS;
memset(&desc->wtx_fields, 0, sizeof(&desc->wtx_fields));
ewr(WMREG_TDT, (tail+1) % TX_RING_SIZE);
e1000.txinuse++;
return 0;
}
static void
cleantx(void)
{
struct wiseman_txdesc *desc;
void *va;
while (e1000.txinuse) {
desc = &e1000.txd[e1000.txclean];
if (!(desc->wtx_fields.wtxu_status & WTX_ST_DD))
break;
va = p2v(desc->wtx_addr);
netfree(va);
desc->wtx_fields.wtxu_status = 0;
e1000.txclean = (e1000.txclean+1) % TX_RING_SIZE;
desc = &e1000.txd[e1000.txclean];
e1000.txinuse--;
}
}
static void
allocrx(void)
{
struct wiseman_rxdesc *desc;
void *buf;
u32 i;
i = erd(WMREG_RDT);
desc = &e1000.rxd[i];
if (desc->wrx_status & WRX_ST_DD)
panic("allocrx");
buf = netalloc();
if (buf == NULL)
panic("Oops");
desc->wrx_addr = v2p(buf);
ewr(WMREG_RDT, (i+1) % RX_RING_SIZE);
}
static void
cleanrx(void)
{
struct wiseman_rxdesc *desc;
void *va;
u16 len;
u32 i;
i = e1000.rxclean;
desc = &e1000.rxd[i];
while (desc->wrx_status & WRX_ST_DD) {
va = p2v(desc->wrx_addr);
len = desc->wrx_len;
desc->wrx_status = 0;
allocrx();
netrx(va, len);
i = (i+1) % RX_RING_SIZE;
desc = &e1000.rxd[i];
}
e1000.rxclean = i;
}
void
e1000intr(void)
{
u32 icr = erd(WMREG_ICR);
while (icr & (ICR_TXDW|ICR_RXO|ICR_RXT0)) {
if (icr & ICR_TXDW)
cleantx();
if (icr & ICR_RXT0)
cleanrx();
if (icr & ICR_RXO)
panic("ICR_RXO");
icr = erd(WMREG_ICR);
}
}
static
void e1000reset(void)
{
u32 ctrl;
paddr tpa;
paddr rpa;
ctrl = erd(WMREG_CTRL);
// [E1000 13.4.1] Assert PHY_RESET then delay as much as 10 msecs
// before clearing PHY_RESET.
ewr(WMREG_CTRL, ctrl|CTRL_PHY_RESET);
microdelay(10000);
ewr(WMREG_CTRL, ctrl);
// [E1000 13.4.1] Delay 1 usec after reset
ewr(WMREG_CTRL, ctrl|CTRL_RST);
microdelay(1);
// [E1000 13.4.41] Transmit Interrupt Delay Value of 1 usec.
// A value of 0 is not allowed. Enabled on a per-TX decriptor basis.
ewr(WMREG_TIDV, 1);
// [E1000 13.4.44] Delay TX interrupts a max of 1 usec.
ewr(WMREG_TADV, 1);
for (int i = 0; i < TX_RING_SIZE; i++)
e1000.txd[i].wtx_fields.wtxu_status = WTX_ST_DD;
// [E1000 14.5] Transmit Initialization
tpa = v2p(e1000.txd);
ewr(WMREG_TDBAH, tpa >> 32);
ewr(WMREG_TDBAL, tpa & 0xffffffff);
ewr(WMREG_TDLEN, sizeof(e1000.txd));
ewr(WMREG_TDH, 0);
ewr(WMREG_TDT, 0);
ewr(WMREG_TCTL, TCTL_EN|TCTL_PSP|TCTL_CT(0x10)|TCTL_COLD(0x40));
ewr(WMREG_TIPG, TIPG_IPGT(10)|TIPG_IPGR1(8)|TIPG_IPGR2(6));
for (int i = 0; i < RX_RING_SIZE>>1; i++) {
void *buf = netalloc();
e1000.rxd[i].wrx_addr = v2p(buf);
}
rpa = v2p(e1000.rxd);
ewr(WMREG_RDBAH, rpa >> 32);
ewr(WMREG_RDBAL, rpa & 0xffffffff);
ewr(WMREG_RDLEN, sizeof(e1000.rxd));
ewr(WMREG_RDH, 0);
ewr(WMREG_RDT, RX_RING_SIZE>>1);
ewr(WMREG_RDTR, 0);
ewr(WMREG_RADV, 0);
ewr(WMREG_RCTL,
RCTL_EN | RCTL_RDMTS_1_2 | RCTL_DPF | RCTL_BAM | RCTL_2k);
ewr(WMREG_RDT, RX_RING_SIZE-1);
// [E1000 13.4.20]
ewr(WMREG_IMC, ~0);
ewr(WMREG_IMS, ICR_TXDW | ICR_RXO | ICR_RXT0);
}
//#define E1000_WRITE_FLUSH() erd(WMREG_STATUS)
int
e1000attach(struct pci_func *pcif)
{
int r;
pci_func_enable(pcif);
e1000.membase = pcif->reg_base[0];
e1000.iobase = pcif->reg_base[2];
e1000.pcidevid = pcif->dev_id;
e1000irq = pcif->irq_line;
picenable(e1000irq);
ioapicenable(e1000irq, 0);
e1000reset();
// Get the MAC address
u16 myaddr[3];
r = eeprom_read(&myaddr[0], EEPROM_OFF_MACADDR, 3);
if (r < 0)
return 0;
u8 *addr = (u8*) &myaddr[0];
cprintf("%x:%x:%x:%x:%x:%x\n",
addr[0], addr[1], addr[2],
addr[3], addr[4], addr[5]);
return 0;
}
/* $NetBSD: if_wmreg.h,v 1.14.4.1 2005/08/28 09:49:37 tron Exp $ */
/*
* Copyright (c) 2001 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Jason R. Thorpe for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Register description for the Intel i82542 (``Wiseman''),
* i82543 (``Livengood''), and i82544 (``Cordova'') Gigabit
* Ethernet chips.
*/
/*
* The Wiseman receive descriptor.
*
* The receive descriptor ring must be aligned to a 4K boundary,
* and there must be an even multiple of 8 descriptors in the ring.
*/
typedef struct wiseman_rxdesc {
u64 wrx_addr; /* buffer address */
u16 wrx_len; /* buffer length */
u16 wrx_cksum; /* checksum (starting at PCSS) */
u8 wrx_status; /* Rx status */
u8 wrx_errors; /* Rx errors */
u16 wrx_special; /* special field (VLAN, etc.) */
} __attribute__((__packed__)) wiseman_rxdesc_t;
/* wrx_status bits */
#define WRX_ST_DD (1U << 0) /* descriptor done */
#define WRX_ST_EOP (1U << 1) /* end of packet */
#define WRX_ST_IXSM (1U << 2) /* ignore checksum indication */
#define WRX_ST_VP (1U << 3) /* VLAN packet */
#define WRX_ST_BPDU (1U << 4) /* ??? */
#define WRX_ST_TCPCS (1U << 5) /* TCP checksum performed */
#define WRX_ST_IPCS (1U << 6) /* IP checksum performed */
#define WRX_ST_PIF (1U << 7) /* passed in-exact filter */
/* wrx_error bits */
#define WRX_ER_CE (1U << 0) /* CRC error */
#define WRX_ER_SE (1U << 1) /* symbol error */
#define WRX_ER_SEQ (1U << 2) /* sequence error */
#define WRX_ER_ICE (1U << 3) /* ??? */
#define WRX_ER_CXE (1U << 4) /* carrier extension error */
#define WRX_ER_TCPE (1U << 5) /* TCP checksum error */
#define WRX_ER_IPE (1U << 6) /* IP checksum error */
#define WRX_ER_RXE (1U << 7) /* Rx data error */
/* wrx_special field for VLAN packets */
#define WRX_VLAN_ID(x) ((x) & 0x0fff) /* VLAN identifier */
#define WRX_VLAN_CFI (1U << 12) /* Canonical Form Indicator */
#define WRX_VLAN_PRI(x) (((x) >> 13) & 7)/* VLAN priority field */
/*
* The Wiseman transmit descriptor.
*
* The transmit descriptor ring must be aligned to a 4K boundary,
* and there must be an even multiple of 8 descriptors in the ring.
*/
typedef struct wiseman_tx_fields {
u8 wtxu_status; /* Tx status */
u8 wtxu_options; /* options */
u16 wtxu_vlan; /* VLAN info */
} __attribute__((__packed__)) wiseman_txfields_t;
typedef struct wiseman_txdesc {
u64 wtx_addr; /* buffer address */
u32 wtx_cmdlen; /* command and length */
wiseman_txfields_t wtx_fields; /* fields; see below */
} __attribute__((__packed__)) wiseman_txdesc_t;
/* Commands for wtx_cmdlen */
#define WTX_CMD_EOP (1U << 24) /* end of packet */
#define WTX_CMD_IFCS (1U << 25) /* insert FCS */
#define WTX_CMD_RS (1U << 27) /* report status */
#define WTX_CMD_RPS (1U << 28) /* report packet sent */
#define WTX_CMD_DEXT (1U << 29) /* descriptor extension */
#define WTX_CMD_VLE (1U << 30) /* VLAN enable */
#define WTX_CMD_IDE (1U << 31) /* interrupt delay enable */
/* Descriptor types (if DEXT is set) */
#define WTX_DTYP_C (0U << 20) /* context */
#define WTX_DTYP_D (1U << 20) /* data */
/* wtx_fields status bits */
#define WTX_ST_DD (1U << 0) /* descriptor done */
#define WTX_ST_EC (1U << 1) /* excessive collisions */
#define WTX_ST_LC (1U << 2) /* late collision */
#define WTX_ST_TU (1U << 3) /* transmit underrun */
/* wtx_fields option bits for IP/TCP/UDP checksum offload */
#define WTX_IXSM (1U << 0) /* IP checksum offload */
#define WTX_TXSM (1U << 1) /* TCP/UDP checksum offload */
/* Maximum payload per Tx descriptor */
#define WTX_MAX_LEN 4096
/*
* The Livengood TCP/IP context descriptor.
*/
struct livengood_tcpip_ctxdesc {
u32 tcpip_ipcs; /* IP checksum context */
u32 tcpip_tucs; /* TCP/UDP checksum context */
u32 tcpip_cmdlen;
u32 tcpip_seg; /* TCP segmentation context */
};
/* commands for context descriptors */
#define WTX_TCPIP_CMD_TCP (1U << 24) /* 1 = TCP, 0 = UDP */
#define WTX_TCPIP_CMD_IP (1U << 25) /* 1 = IPv4, 0 = IPv6 */
#define WTX_TCPIP_CMD_TSE (1U << 26) /* segmentation context valid */
#define WTX_TCPIP_IPCSS(x) ((x) << 0) /* checksum start */
#define WTX_TCPIP_IPCSO(x) ((x) << 8) /* checksum value offset */
#define WTX_TCPIP_IPCSE(x) ((x) << 16) /* checksum end */
#define WTX_TCPIP_TUCSS(x) ((x) << 0) /* checksum start */
#define WTX_TCPIP_TUCSO(x) ((x) << 8) /* checksum value offset */
#define WTX_TCPIP_TUCSE(x) ((x) << 16) /* checksum end */
#define WTX_TCPIP_SEG_STATUS(x) ((x) << 0)
#define WTX_TCPIP_SEG_HDRLEN(x) ((x) << 8)
#define WTX_TCPIP_SEG_MSS(x) ((x) << 16)
/*
* PCI config registers used by the Wiseman.
*/
#define WM_PCI_MMBA PCI_MAPREG_START
/*
* Wiseman Control/Status Registers.
*/
#define WMREG_CTRL 0x0000 /* Device Control Register */
#define CTRL_FD (1U << 0) /* full duplex */
#define CTRL_BEM (1U << 1) /* big-endian mode */
#define CTRL_PRIOR (1U << 2) /* 0 = receive, 1 = fair */
#define CTRL_LRST (1U << 3) /* link reset */
#define CTRL_ASDE (1U << 5) /* auto speed detect enable */
#define CTRL_SLU (1U << 6) /* set link up */
#define CTRL_ILOS (1U << 7) /* invert loss of signal */
#define CTRL_SPEED(x) ((x) << 8) /* speed (Livengood) */
#define CTRL_SPEED_10 CTRL_SPEED(0)
#define CTRL_SPEED_100 CTRL_SPEED(1)
#define CTRL_SPEED_1000 CTRL_SPEED(2)
#define CTRL_SPEED_MASK CTRL_SPEED(3)
#define CTRL_FRCSPD (1U << 11) /* force speed (Livengood) */
#define CTRL_FRCFDX (1U << 12) /* force full-duplex (Livengood) */
#define CTRL_SWDPINS_SHIFT 18
#define CTRL_SWDPINS_MASK 0x0f
#define CTRL_SWDPIN(x) (1U << (CTRL_SWDPINS_SHIFT + (x)))
#define CTRL_SWDPIO_SHIFT 22
#define CTRL_SWDPIO_MASK 0x0f
#define CTRL_SWDPIO(x) (1U << (CTRL_SWDPIO_SHIFT + (x)))
#define CTRL_RST (1U << 26) /* device reset */
#define CTRL_RFCE (1U << 27) /* Rx flow control enable */
#define CTRL_TFCE (1U << 28) /* Tx flow control enable */
#define CTRL_VME (1U << 30) /* VLAN Mode Enable */
#define CTRL_PHY_RESET (1U << 31) /* PHY reset (Cordova) */
#define WMREG_CTRL_SHADOW 0x0004 /* Device Control Register (shadow) */
#define WMREG_STATUS 0x0008 /* Device Status Register */
#define STATUS_FD (1U << 0) /* full duplex */
#define STATUS_LU (1U << 1) /* link up */
#define STATUS_TCKOK (1U << 2) /* Tx clock running */
#define STATUS_RBCOK (1U << 3) /* Rx clock running */
#define STATUS_FUNCID_SHIFT 2 /* 82546 function ID */
#define STATUS_FUNCID_MASK 3 /* ... */
#define STATUS_TXOFF (1U << 4) /* Tx paused */
#define STATUS_TBIMODE (1U << 5) /* fiber mode (Livengood) */
#define STATUS_SPEED(x) ((x) << 6) /* speed indication */
#define STATUS_SPEED_10 STATUS_SPEED(0)
#define STATUS_SPEED_100 STATUS_SPEED(1)
#define STATUS_SPEED_1000 STATUS_SPEED(2)
#define STATUS_ASDV(x) ((x) << 8) /* auto speed det. val. (Livengood) */
#define STATUS_MTXCKOK (1U << 10) /* MTXD clock running */
#define STATUS_PCI66 (1U << 11) /* 66MHz bus (Livengood) */
#define STATUS_BUS64 (1U << 12) /* 64-bit bus (Livengood) */
#define STATUS_PCIX_MODE (1U << 13) /* PCIX mode (Cordova) */
#define STATUS_PCIXSPD(x) ((x) << 14) /* PCIX speed indication (Cordova) */
#define STATUS_PCIXSPD_50_66 STATUS_PCIXSPD(0)
#define STATUS_PCIXSPD_66_100 STATUS_PCIXSPD(1)
#define STATUS_PCIXSPD_100_133 STATUS_PCIXSPD(2)
#define STATUS_PCIXSPD_MASK STATUS_PCIXSPD(3)
#define WMREG_EECD 0x0010 /* EEPROM Control Register */
#define EECD_SK (1U << 0) /* clock */
#define EECD_CS (1U << 1) /* chip select */
#define EECD_DI (1U << 2) /* data in */
#define EECD_DO (1U << 3) /* data out */
#define EECD_FWE(x) ((x) << 4) /* flash write enable control */
#define EECD_FWE_DISABLED EECD_FWE(1)
#define EECD_FWE_ENABLED EECD_FWE(2)
#define EECD_EE_REQ (1U << 6) /* (shared) EEPROM request */
#define EECD_EE_GNT (1U << 7) /* (shared) EEPROM grant */
#define EECD_EE_PRES (1U << 8) /* EEPROM present */
#define EECD_EE_SIZE (1U << 9) /* EEPROM size
(0 = 64 word, 1 = 256 word) */
#define EECD_EE_ABITS (1U << 10) /* EEPROM address bits
(based on type) */
#define EECD_EE_TYPE (1U << 13) /* EEPROM type
(0 = Microwire, 1 = SPI) */
#define UWIRE_OPC_ERASE 0x04 /* MicroWire "erase" opcode */
#define UWIRE_OPC_WRITE 0x05 /* MicroWire "write" opcode */
#define UWIRE_OPC_READ 0x06 /* MicroWire "read" opcode */
#define SPI_OPC_WRITE 0x02 /* SPI "write" opcode */
#define SPI_OPC_READ 0x03 /* SPI "read" opcode */
#define SPI_OPC_A8 0x08 /* opcode bit 3 == address bit 8 */
#define SPI_OPC_WREN 0x06 /* SPI "set write enable" opcode */
#define SPI_OPC_WRDI 0x04 /* SPI "clear write enable" opcode */
#define SPI_OPC_RDSR 0x05 /* SPI "read status" opcode */
#define SPI_OPC_WRSR 0x01 /* SPI "write status" opcode */
#define SPI_MAX_RETRIES 5000 /* max wait of 5ms for RDY signal */
#define SPI_SR_RDY 0x01
#define SPI_SR_WEN 0x02
#define SPI_SR_BP0 0x04
#define SPI_SR_BP1 0x08
#define SPI_SR_WPEN 0x80
#define EEPROM_OFF_MACADDR 0x00 /* MAC address offset */
#define EEPROM_OFF_CFG1 0x0a /* config word 1 */
#define EEPROM_OFF_CFG2 0x0f /* config word 2 */
#define EEPROM_OFF_SWDPIN 0x20 /* SWD Pins (Cordova) */
#define EEPROM_CFG1_LVDID (1U << 0)
#define EEPROM_CFG1_LSSID (1U << 1)
#define EEPROM_CFG1_PME_CLOCK (1U << 2)
#define EEPROM_CFG1_PM (1U << 3)
#define EEPROM_CFG1_ILOS (1U << 4)
#define EEPROM_CFG1_SWDPIO_SHIFT 5
#define EEPROM_CFG1_SWDPIO_MASK (0xf << EEPROM_CFG1_SWDPIO_SHIFT)
#define EEPROM_CFG1_IPS1 (1U << 8)
#define EEPROM_CFG1_LRST (1U << 9)
#define EEPROM_CFG1_FD (1U << 10)
#define EEPROM_CFG1_FRCSPD (1U << 11)
#define EEPROM_CFG1_IPS0 (1U << 12)
#define EEPROM_CFG1_64_32_BAR (1U << 13)
#define EEPROM_CFG2_CSR_RD_SPLIT (1U << 1)
#define EEPROM_CFG2_APM_EN (1U << 2)
#define EEPROM_CFG2_64_BIT (1U << 3)
#define EEPROM_CFG2_MAX_READ (1U << 4)
#define EEPROM_CFG2_DMCR_MAP (1U << 5)
#define EEPROM_CFG2_133_CAP (1U << 6)
#define EEPROM_CFG2_MSI_DIS (1U << 7)
#define EEPROM_CFG2_FLASH_DIS (1U << 8)
#define EEPROM_CFG2_FLASH_SIZE(x) (((x) & 3) >> 9)
#define EEPROM_CFG2_ANE (1U << 11)
#define EEPROM_CFG2_PAUSE(x) (((x) & 3) >> 12)
#define EEPROM_CFG2_ASDE (1U << 14)
#define EEPROM_CFG2_APM_PME (1U << 15)
#define EEPROM_CFG2_SWDPIO_SHIFT 4
#define EEPROM_CFG2_SWDPIO_MASK (0xf << EEPROM_CFG2_SWDPIO_SHIFT)
#define EEPROM_SWDPIN_MASK 0xdf
#define EEPROM_SWDPIN_SWDPIN_SHIFT 0
#define EEPROM_SWDPIN_SWDPIO_SHIFT 8
#define WMREG_EERD 0x0014 /* EEPROM read register */
#define EERD_START 0x00000001
#define EERD_DONE 0x00000010
#define EERD_ADDR_SHIFT 8
#define EERD_ADDR_MASK 0x0000ff00
#define EERD_DATA_SHIFT 16
#define EERD_DATA_MASK 0xffff0000
#define WMREG_CTRL_EXT 0x0018 /* Extended Device Control Register */
#define CTRL_EXT_GPI_EN(x) (1U << (x)) /* gpin interrupt enable */
#define CTRL_EXT_SWDPINS_SHIFT 4
#define CTRL_EXT_SWDPINS_MASK 0x0d
#define CTRL_EXT_SWDPIN(x) (1U << (CTRL_EXT_SWDPINS_SHIFT + (x) - 4))
#define CTRL_EXT_SWDPIO_SHIFT 8
#define CTRL_EXT_SWDPIO_MASK 0x0d
#define CTRL_EXT_SWDPIO(x) (1U << (CTRL_EXT_SWDPIO_SHIFT + (x) - 4))
#define CTRL_EXT_ASDCHK (1U << 12) /* ASD check */
#define CTRL_EXT_EE_RST (1U << 13) /* EEPROM reset */
#define CTRL_EXT_IPS (1U << 14) /* invert power state bit 0 */
#define CTRL_EXT_SPD_BYPS (1U << 15) /* speed select bypass */
#define CTRL_EXT_IPS1 (1U << 16) /* invert power state bit 1 */
#define CTRL_EXT_RO_DIS (1U << 17) /* relaxed ordering disabled */
#define WMREG_MDIC 0x0020 /* MDI Control Register */
#define MDIC_DATA(x) ((x) & 0xffff)
#define MDIC_REGADD(x) ((x) << 16)
#define MDIC_PHYADD(x) ((x) << 21)
#define MDIC_OP_WRITE (1U << 26)
#define MDIC_OP_READ (2U << 26)
#define MDIC_READY (1U << 28)
#define MDIC_I (1U << 29) /* interrupt on MDI complete */
#define MDIC_E (1U << 30) /* MDI error */
#define WMREG_FCAL 0x0028 /* Flow Control Address Low */
#define FCAL_CONST 0x00c28001 /* Flow Control MAC addr low */
#define WMREG_FCAH 0x002c /* Flow Control Address High */
#define FCAH_CONST 0x00000100 /* Flow Control MAC addr high */
#define WMREG_FCT 0x0030 /* Flow Control Type */
#define WMREG_VET 0x0038 /* VLAN Ethertype */
#define WMREG_RAL_BASE 0x0040 /* Receive Address List */
#define WMREG_CORDOVA_RAL_BASE 0x5400
#define WMREG_RAL_LO(b, x) ((b) + ((x) << 3))
#define WMREG_RAL_HI(b, x) (WMREG_RAL_LO(b, x) + 4)
/*
* Receive Address List: The LO part is the low-order 32-bits
* of the MAC address. The HI part is the high-order 16-bits
* along with a few control bits.
*/
#define RAL_AS(x) ((x) << 16) /* address select */
#define RAL_AS_DEST RAL_AS(0) /* (cordova?) */
#define RAL_AS_SOURCE RAL_AS(1) /* (cordova?) */
#define RAL_RDR1 (1U << 30) /* put packet in alt. rx ring */
#define RAL_AV (1U << 31) /* entry is valid */
#define WM_RAL_TABSIZE 16
#define WMREG_ICR 0x00c0 /* Interrupt Cause Register */
#define ICR_TXDW (1U << 0) /* Tx desc written back */
#define ICR_TXQE (1U << 1) /* Tx queue empty */
#define ICR_LSC (1U << 2) /* link status change */
#define ICR_RXSEQ (1U << 3) /* receive sequence error */
#define ICR_RXDMT0 (1U << 4) /* Rx ring 0 nearly empty */
#define ICR_RXO (1U << 6) /* Rx overrun */
#define ICR_RXT0 (1U << 7) /* Rx ring 0 timer */
#define ICR_MDAC (1U << 9) /* MDIO access complete */
#define ICR_RXCFG (1U << 10) /* Receiving /C/ */
#define ICR_GPI(x) (1U << (x)) /* general purpose interrupts */
#define WMREG_ITR 0x00c4 /* Interrupt Throttling Register */
#define ITR_IVAL_MASK 0xffff /* Interval mask */
#define ITR_IVAL_SHIFT 0 /* Interval shift */
#define WMREG_ICS 0x00c8 /* Interrupt Cause Set Register */
/* See ICR bits. */
#define WMREG_IMS 0x00d0 /* Interrupt Mask Set Register */
/* See ICR bits. */
#define WMREG_IMC 0x00d8 /* Interrupt Mask Clear Register */
/* See ICR bits. */
#define WMREG_RCTL 0x0100 /* Receive Control */
#define RCTL_EN (1U << 1) /* receiver enable */
#define RCTL_SBP (1U << 2) /* store bad packets */
#define RCTL_UPE (1U << 3) /* unicast promisc. enable */
#define RCTL_MPE (1U << 4) /* multicast promisc. enable */
#define RCTL_LPE (1U << 5) /* large packet enable */
#define RCTL_LBM(x) ((x) << 6) /* loopback mode */
#define RCTL_LBM_NONE RCTL_LBM(0)
#define RCTL_LBM_PHY RCTL_LBM(3)
#define RCTL_RDMTS(x) ((x) << 8) /* receive desc. min thresh size */
#define RCTL_RDMTS_1_2 RCTL_RDMTS(0)
#define RCTL_RDMTS_1_4 RCTL_RDMTS(1)
#define RCTL_RDMTS_1_8 RCTL_RDMTS(2)
#define RCTL_RDMTS_MASK RCTL_RDMTS(3)
#define RCTL_MO(x) ((x) << 12) /* multicast offset */
#define RCTL_BAM (1U << 15) /* broadcast accept mode */
#define RCTL_2k (0 << 16) /* 2k Rx buffers */
#define RCTL_1k (1 << 16) /* 1k Rx buffers */
#define RCTL_512 (2 << 16) /* 512 byte Rx buffers */
#define RCTL_256 (3 << 16) /* 256 byte Rx buffers */
#define RCTL_BSEX_16k (1 << 16) /* 16k Rx buffers (BSEX) */
#define RCTL_BSEX_8k (2 << 16) /* 8k Rx buffers (BSEX) */
#define RCTL_BSEX_4k (3 << 16) /* 4k Rx buffers (BSEX) */
#define RCTL_DPF (1U << 22) /* discard pause frames */
#define RCTL_PMCF (1U << 23) /* pass MAC control frames */
#define RCTL_BSEX (1U << 25) /* buffer size extension (Livengood) */
#define RCTL_SECRC (1U << 26) /* strip Ethernet CRC */
#define WMREG_OLD_RDTR0 0x0108 /* Receive Delay Timer (ring 0) */
#define WMREG_RDTR 0x2820
#define RDTR_FPD (1U << 31) /* flush partial descriptor */
#define WMREG_RADV 0x282c /* Receive Interrupt Absolute Delay Timer */
#define WMREG_OLD_RDBAL0 0x0110 /* Receive Descriptor Base Low (ring 0) */
#define WMREG_RDBAL 0x2800
#define WMREG_OLD_RDBAH0 0x0114 /* Receive Descriptor Base High (ring 0) */
#define WMREG_RDBAH 0x2804
#define WMREG_OLD_RDLEN0 0x0118 /* Receive Descriptor Length (ring 0) */
#define WMREG_RDLEN 0x2808
#define WMREG_OLD_RDH0 0x0120 /* Receive Descriptor Head (ring 0) */
#define WMREG_RDH 0x2810
#define WMREG_OLD_RDT0 0x0128 /* Receive Descriptor Tail (ring 0) */
#define WMREG_RDT 0x2818
#define WMREG_RXDCTL 0x2828 /* Receive Descriptor Control */
#define RXDCTL_PTHRESH(x) ((x) << 0) /* prefetch threshold */
#define RXDCTL_HTHRESH(x) ((x) << 8) /* host threshold */
#define RXDCTL_WTHRESH(x) ((x) << 16) /* write back threshold */
#define RXDCTL_GRAN (1U << 24) /* 0 = cacheline, 1 = descriptor */
#define WMREG_OLD_RDTR1 0x0130 /* Receive Delay Timer (ring 1) */
#define WMREG_OLD_RDBA1_LO 0x0138 /* Receive Descriptor Base Low (ring 1) */
#define WMREG_OLD_RDBA1_HI 0x013c /* Receive Descriptor Base High (ring 1) */
#define WMREG_OLD_RDLEN1 0x0140 /* Receive Drscriptor Length (ring 1) */
#define WMREG_OLD_RDH1 0x0148
#define WMREG_OLD_RDT1 0x0150
#define WMREG_OLD_FCRTH 0x0160 /* Flow Control Rx Threshold Hi (OLD) */
#define WMREG_FCRTL 0x2160 /* Flow Control Rx Threshold Lo */
#define FCRTH_DFLT 0x00008000
#define WMREG_OLD_FCRTL 0x0168 /* Flow Control Rx Threshold Lo (OLD) */
#define WMREG_FCRTH 0x2168 /* Flow Control Rx Threhsold Hi */
#define FCRTL_DFLT 0x00004000
#define FCRTL_XONE 0x80000000 /* Enable XON frame transmission */
#define WMREG_FCTTV 0x0170 /* Flow Control Transmit Timer Value */
#define FCTTV_DFLT 0x00000600
#define WMREG_TXCW 0x0178 /* Transmit Configuration Word (TBI mode) */
/* See MII ANAR_X bits. */
#define TXCW_TxConfig (1U << 30) /* Tx Config */
#define TXCW_ANE (1U << 31) /* Autonegotiate */
#define WMREG_RXCW 0x0180 /* Receive Configuration Word (TBI mode) */
/* See MII ANLPAR_X bits. */
#define RXCW_NC (1U << 26) /* no carrier */
#define RXCW_IV (1U << 27) /* config invalid */
#define RXCW_CC (1U << 28) /* config change */
#define RXCW_C (1U << 29) /* /C/ reception */
#define RXCW_SYNCH (1U << 30) /* synchronized */
#define RXCW_ANC (1U << 31) /* autonegotiation complete */
#define WMREG_MTA 0x0200 /* Multicast Table Array */
#define WMREG_CORDOVA_MTA 0x5200
#define WMREG_TCTL 0x0400 /* Transmit Control Register */
#define TCTL_EN (1U << 1) /* transmitter enable */
#define TCTL_PSP (1U << 3) /* pad short packets */
#define TCTL_CT(x) (((x) & 0xff) << 4) /* 4:11 - collision threshold */
#define TCTL_COLD(x) (((x) & 0x3ff) << 12) /* 12:21 - collision distance */
#define TCTL_SWXOFF (1U << 22) /* software XOFF */
#define TCTL_RTLC (1U << 24) /* retransmit on late collision */
#define TCTL_NRTU (1U << 25) /* no retransmit on underrun */
#define TX_COLLISION_THRESHOLD 15
#define TX_COLLISION_DISTANCE_HDX 64
#define TX_COLLISION_DISTANCE_FDX 512
#define WMREG_TQSA_LO 0x0408
#define WMREG_TQSA_HI 0x040c
#define WMREG_TIPG 0x0410 /* Transmit IPG Register */
#define TIPG_IPGT(x) (x) /* IPG transmit time */
#define TIPG_IPGR1(x) ((x) << 10) /* IPG receive time 1 */
#define TIPG_IPGR2(x) ((x) << 20) /* IPG receive time 2 */
#define TIPG_WM_DFLT (TIPG_IPGT(0x0a) | TIPG_IPGR1(0x02) | TIPG_IPGR2(0x0a))
#define TIPG_LG_DFLT (TIPG_IPGT(0x06) | TIPG_IPGR1(0x08) | TIPG_IPGR2(0x06))
#define TIPG_1000T_DFLT (TIPG_IPGT(0x08) | TIPG_IPGR1(0x08) | TIPG_IPGR2(0x06))
#define WMREG_TQC 0x0418
#define WMREG_RDFH 0x2410 /* Receive Data FIFO Head */
#define WMREG_RDFT 0x2418 /* Receive Data FIFO Tail */
#define WMREG_RDFHS 0x2420 /* Receive Data FIFO Head Saved */
#define WMREG_RDFTS 0x2428 /* Receive Data FIFO Tail Saved */
#define WMREG_TDFH 0x3410 /* Transmit Data FIFO Head */
#define WMREG_TDFT 0x3418 /* Transmit Data FIFO Tail */
#define WMREG_TDFHS 0x3420 /* Transmit Data FIFO Head Saved */
#define WMREG_TDFTS 0x3428 /* Transmit Data FIFO Tail Saved */
#define WMREG_TDFPC 0x3430 /* Transmit Data FIFO Packet Count */
#define WMREG_OLD_TDBAL 0x0420 /* Transmit Descriptor Base Lo */
#define WMREG_TDBAL 0x3800
#define WMREG_OLD_TDBAH 0x0424 /* Transmit Descriptor Base Hi */
#define WMREG_TDBAH 0x3804
#define WMREG_OLD_TDLEN 0x0428 /* Transmit Descriptor Length */
#define WMREG_TDLEN 0x3808
#define WMREG_OLD_TDH 0x0430 /* Transmit Descriptor Head */
#define WMREG_TDH 0x3810
#define WMREG_OLD_TDT 0x0438 /* Transmit Descriptor Tail */
#define WMREG_TDT 0x3818
#define WMREG_OLD_TIDV 0x0440 /* Transmit Delay Interrupt Value */
#define WMREG_TIDV 0x3820
#define WMREG_TXDCTL 0x3828 /* Trandmit Descriptor Control */
#define TXDCTL_PTHRESH(x) ((x) << 0) /* prefetch threshold */
#define TXDCTL_HTHRESH(x) ((x) << 8) /* host threshold */
#define TXDCTL_WTHRESH(x) ((x) << 16) /* write back threshold */
#define WMREG_TADV 0x382c /* Transmit Absolute Interrupt Delay Timer */
#define WMREG_AIT 0x0458 /* Adaptive IFS Throttle */
#define WMREG_VFTA 0x0600
#define WM_MC_TABSIZE 128
#define WM_VLAN_TABSIZE 128
#define WMREG_PBA 0x1000 /* Packet Buffer Allocation */
#define PBA_RX_MASK 0xffff
#define PBA_RX_SHIFT 0
#define PBA_TX_MASK 0xffff
#define PBA_TX_SHIFT 16
#define WMREG_TXDMAC 0x3000 /* Transfer DMA Control */
#define TXDMAC_DPP (1U << 0) /* disable packet prefetch */
#define WMREG_TSPMT 0x3830 /* TCP Segmentation Pad and Minimum
Threshold (Cordova) */
#define TSPMT_TSMT(x) (x) /* TCP seg min transfer */
#define TSPMT_TSPBP(x) ((x) << 16) /* TCP seg pkt buf padding */
#define WMREG_RXCSUM 0x5000 /* Receive Checksum register */
#define RXCSUM_PCSS 0x000000ff /* Packet Checksum Start */
#define RXCSUM_IPOFL (1U << 8) /* IP checksum offload */
#define RXCSUM_TUOFL (1U << 9) /* TCP/UDP checksum offload */
#define WMREG_XONRXC 0x4048 /* XON Rx Count - R/clr */
#define WMREG_XONTXC 0x404c /* XON Tx Count - R/clr */
#define WMREG_XOFFRXC 0x4050 /* XOFF Rx Count - R/clr */
#define WMREG_XOFFTXC 0x4054 /* XOFF Tx Count - R/clr */
#define WMREG_FCRUC 0x4058 /* Flow Control Rx Unsupported Count - R/clr */
#define WMREG_MANC 0x5820 /* Management control */
#define MANC_ARP_REQ 0x00002000 /* ARP request filtering */
#define MANC_ARP_RES 0x00008000 /* ARP response filtering */
#define MANC_MNG2HOST 0x00200000 /* Management packets to host */
#define WMREG_MANC2H 0x5860 /* Management control to host */
#define MANC2H_PORT_623 0x0020
#define MANC2H_PORT_664 0x0040
...@@ -123,12 +123,8 @@ gc(void) ...@@ -123,12 +123,8 @@ gc(void)
void void
gc_worker(void) gc_worker(void *x)
{ {
release(&myproc()->lock); // initially held by scheduler
mtstart(rcu_gc_worker, myproc());
struct spinlock wl; struct spinlock wl;
initlock(&wl, "rcu_gc_worker"); // dummy lock initlock(&wl, "rcu_gc_worker"); // dummy lock
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "types.h" #include "types.h"
#include "amd64.h" #include "amd64.h"
#include "kernel.h"
#define IO_TIMER1 0x040 // 8253 Timer #1 #define IO_TIMER1 0x040 // 8253 Timer #1
#define TIMER_FREQ 1193182 #define TIMER_FREQ 1193182
...@@ -25,6 +26,13 @@ microdelay(u64 delay) ...@@ -25,6 +26,13 @@ microdelay(u64 delay)
nop_pause(); nop_pause();
} }
u64
nsectime(void)
{
u64 msec = ticks*QUANTUM;
return msec*1000000;
}
void void
inithz(void) inithz(void)
{ {
......
...@@ -57,9 +57,14 @@ void tree_test(void); ...@@ -57,9 +57,14 @@ void tree_test(void);
void cgaputc(int c); void cgaputc(int c);
// condvar.c // condvar.c
extern u64 ticks;
extern struct spinlock tickslock;
extern struct condvar cv_ticks;
void initcondvar(struct condvar *, char *); void initcondvar(struct condvar *, char *);
void cv_sleep(struct condvar *cv, struct spinlock*); void cv_sleep(struct condvar *cv, struct spinlock*);
void cv_sleepto(struct condvar *cv, struct spinlock*, u64);
void cv_wakeup(struct condvar *cv); void cv_wakeup(struct condvar *cv);
void cv_tick(void);
// console.c // console.c
void cprintf(const char*, ...); void cprintf(const char*, ...);
...@@ -67,6 +72,7 @@ void panic(const char*) __attribute__((noreturn)); ...@@ -67,6 +72,7 @@ void panic(const char*) __attribute__((noreturn));
void snprintf(char *buf, u32 n, char *fmt, ...); void snprintf(char *buf, u32 n, char *fmt, ...);
void consoleintr(int(*)(void)); void consoleintr(int(*)(void));
// crange.c // crange.c
struct clist_range { struct clist_range {
...@@ -89,6 +95,11 @@ struct clist_range* crange_search(struct crange *cr, u64 k); ...@@ -89,6 +95,11 @@ struct clist_range* crange_search(struct crange *cr, u64 k);
int crange_foreach(struct crange *crk, int (*f)(struct clist_range *r, void *st), void *st); int crange_foreach(struct crange *crk, int (*f)(struct clist_range *r, void *st), void *st);
void crange_print(struct crange *cr, int); void crange_print(struct crange *cr, int);
// e1000.c
extern int e1000irq;
void e1000intr(void);
int e1000tx(void *buf, u32 len);
// exec.c // exec.c
int exec(char*, char**); int exec(char*, char**);
...@@ -127,8 +138,7 @@ void gc_begin_epoch(); ...@@ -127,8 +138,7 @@ void gc_begin_epoch();
void gc_end_epoch(); void gc_end_epoch();
void gc_delayed(void*, void (*dofree)(void*)); void gc_delayed(void*, void (*dofree)(void*));
void gc_delayed2(int, u64, void (*dofree)(int, u64)); void gc_delayed2(int, u64, void (*dofree)(int, u64));
void gc_start(void); void gc_start(void);
void gc_worker(void);
// hwvm.c // hwvm.c
void freevm(pml4e_t*); void freevm(pml4e_t*);
...@@ -137,6 +147,7 @@ pme_t * walkpgdir(pml4e_t*, const void*, int); ...@@ -137,6 +147,7 @@ pme_t * walkpgdir(pml4e_t*, const void*, int);
// hz.c // hz.c
void microdelay(u64); void microdelay(u64);
u64 nsectime(void);
// ide.c // ide.c
void ideinit(void); void ideinit(void);
...@@ -172,6 +183,11 @@ void lapicpc(char mask); ...@@ -172,6 +183,11 @@ void lapicpc(char mask);
extern int ncpu; extern int ncpu;
int mpbcpu(void); int mpbcpu(void);
// net.c
void netfree(void *va);
void* netalloc(void);
void netrx(void *va, u16 len);
// ns.c // ns.c
enum { enum {
nskey_int = 1, nskey_int = 1,
...@@ -242,6 +258,7 @@ void userinit(void); ...@@ -242,6 +258,7 @@ void userinit(void);
int wait(void); int wait(void);
void yield(void); void yield(void);
void migrate(struct proc *); void migrate(struct proc *);
struct proc* threadalloc(void (*fn)(void*), void *arg);
// prof.c // prof.c
extern int profenable; extern int profenable;
...@@ -260,6 +277,7 @@ void sampconf(void); ...@@ -260,6 +277,7 @@ void sampconf(void);
// spinlock.c // spinlock.c
void acquire(struct spinlock*); void acquire(struct spinlock*);
int tryacquire(struct spinlock*);
void getcallerpcs(void*, uptr*); void getcallerpcs(void*, uptr*);
int holding(struct spinlock*); int holding(struct spinlock*);
void initlock(struct spinlock*, char*); void initlock(struct spinlock*, char*);
...@@ -291,9 +309,6 @@ void swtch(struct context**, struct context*); ...@@ -291,9 +309,6 @@ void swtch(struct context**, struct context*);
// trap.c // trap.c
extern struct segdesc bootgdt[NSEGS]; extern struct segdesc bootgdt[NSEGS];
extern u64 ticks;
extern struct spinlock tickslock;
extern struct condvar cv_ticks;
// uart.c // uart.c
void uartputc(char c); void uartputc(char c);
......
...@@ -91,9 +91,9 @@ initlapic(void) ...@@ -91,9 +91,9 @@ initlapic(void)
lapichz = 100 * (ccr0 - ccr1); lapichz = 100 * (ccr0 - ccr1);
} }
count = (QUANTUN*lapichz) / 1000; count = (QUANTUM*lapichz) / 1000;
if (count > 0xffffffff) if (count > 0xffffffff)
panic("initlapic: QUANTUN too large"); panic("initlapic: QUANTUM too large");
// The timer repeatedly counts down at bus frequency // The timer repeatedly counts down at bus frequency
// from lapic[TICR] and then issues an interrupt. // from lapic[TICR] and then issues an interrupt.
......
...@@ -25,6 +25,7 @@ extern void inituser(void); ...@@ -25,6 +25,7 @@ extern void inituser(void);
extern void inithz(void); extern void inithz(void);
extern void initwq(void); extern void initwq(void);
extern void initsamp(void); extern void initsamp(void);
extern void initpci(void);
static volatile int bstate; static volatile int bstate;
...@@ -102,6 +103,7 @@ cmain(u64 mbmagic, u64 mbaddr) ...@@ -102,6 +103,7 @@ cmain(u64 mbmagic, u64 mbaddr)
initwq(); // work queues initwq(); // work queues
#endif #endif
initsamp(); initsamp();
initpci();
cprintf("ncpu %d %lu MHz\n", ncpu, cpuhz / 1000000); cprintf("ncpu %d %lu MHz\n", ncpu, cpuhz / 1000000);
......
#include "types.h"
#include "kernel.h"
#ifdef LWIP
#include "lwip/tcpip.h"
#endif
static u8 ping_packet[] = {
0x52, 0x55, 0x0a, 0x00, 0x02, 0x02, 0x52, 0x54, 0x00, 0x12,
0x34, 0x56, 0x08, 0x00, 0x45, 0x00, 0x00, 0x54, 0x00, 0x00,
0x40, 0x00, 0x40, 0x01, 0x22, 0x99, 0x0a, 0x00, 0x02, 0x0f,
0x0a, 0x00, 0x02, 0x02, 0x08, 0x00, 0x94, 0xa0, 0x03, 0x07,
0x00, 0x01, 0x71, 0xfc, 0xec, 0x4e, 0x00, 0x00, 0x00, 0x00,
0x3b, 0x39, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11,
0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37
};
void
netfree(void *va)
{
kfree(va);
}
void *
netalloc(void)
{
return kalloc();
}
void
netrx(void *va, u16 len)
{
cprintf("netrx %lx len %x\n", va, len);
}
void
nettest(void)
{
void *ping;
u32 len;
ping = netalloc();
len = sizeof(ping_packet);
memmove(ping, ping_packet, len);
e1000tx(ping, len);
//e1000tx(ping_packet, sizeof(ping_packet));
}
#ifdef LWIP
int errno;
static void
tcpip_init_done(void *arg)
{
cprintf("tcpip_init_done: %lx\n", arg);
}
void
initnet(void)
{
tcpip_init(&tcpip_init_done, NULL);
cprintf("initnet:\n");
}
#else
void
initnet(void)
{
}
#endif
HAVE_LWIP = $(shell (cd lwip 2> /dev/null && echo y) || echo n)
ifeq ($(HAVE_LWIP),y)
-include $(O)/lwip/src/api/*.d
-include $(O)/lwip/src/netif/*.d
-include $(O)/lwip/src/core/*.d
-include $(O)/net/*.d
OBJS += $(O)/liblwip.a
CFLAGS += -Ilwip/src/include -Inet -Ilwip/src/include/ipv4 -I. -DLWIP
LWIP_CFLAGS = -fno-pic -static -fno-builtin -fno-strict-aliasing -O2 -Wall -MD -ggdb \
-m64 -Werror -std=c99 -fms-extensions -mno-sse -mcmodel=large -I$(QEMUSRC) \
-fno-omit-frame-pointer -DHW_$(HW) -include param.h \
-Wno-attributes -Wno-address -Wno-char-subscripts
LWIP_CFLAGS += $(shell $(CC) -fno-stack-protector -E -x c /dev/null >/dev/null 2>&1 && echo -fno-stack-protector)
LWIP_INCLUDES := \
-Ilwip/src/include \
-Ilwip/src/include/ipv4 \
-Inet \
-Inet/arch \
-I.
LWIP_SRCFILES += \
lwip/src/api/api_lib.c \
lwip/src/api/api_msg.c \
lwip/src/api/err.c \
lwip/src/api/sockets.c \
lwip/src/api/tcpip.c \
lwip/src/api/netbuf.c \
lwip/src/core/init.c \
lwip/src/core/tcp_in.c \
lwip/src/core/dhcp.c \
lwip/src/core/def.c \
lwip/src/core/mem.c \
lwip/src/core/memp.c \
lwip/src/core/netif.c \
lwip/src/core/pbuf.c \
lwip/src/core/raw.c \
lwip/src/core/stats.c \
lwip/src/core/sys.c \
lwip/src/core/tcp.c \
lwip/src/core/timers.c \
lwip/src/core/ipv4/ip_addr.c \
lwip/src/core/ipv4/icmp.c \
lwip/src/core/ipv4/ip.c \
lwip/src/core/ipv4/ip_frag.c \
lwip/src/core/ipv4/inet_chksum.c \
lwip/src/core/ipv4/inet.c \
lwip/src/core/tcp_out.c \
lwip/src/core/udp.c \
lwip/src/netif/etharp.c \
net/sys_arch.c \
LWIP_OBJFILES := $(patsubst %.c, $(O)/%.o, $(LWIP_SRCFILES))
LWIP_OBJFILES := $(patsubst %.S, $(O)/%.o, $(LWIP_OBJFILES))
$(O)/net/%.o: net/%.c
@echo " CC $@"
$(Q)mkdir -p $(@D)
$(Q)$(CC) $(LWIP_CFLAGS) $(LWIP_INCLUDES) -c -o $@ $<
$(O)/lwip/src/%.o: lwip/src/%.c
@echo " CC $@"
$(Q)mkdir -p $(@D)
$(Q)$(CC) $(LWIP_CFLAGS) $(LWIP_INCLUDES) -c -o $@ $<
$(O)/liblwip.a: $(LWIP_OBJFILES)
@echo " AR $@"
$(Q)mkdir -p $(@D)
$(Q)$(AR) r $@ $(LWIP_OBJFILES)
endif
#ifndef LWIP_ARCH_CC_H
#define LWIP_ARCH_CC_H
#include <types.h>
void panic(const char*) __attribute__((noreturn));
void cprintf(const char*, ...);
typedef u32 u32_t;
typedef s32 s32_t;
typedef u64 u64_t;
typedef s64 s64_t;
typedef u16 u16_t;
typedef s16 s16_t;
typedef u8 u8_t;
typedef s8 s8_t;
typedef uptr mem_ptr_t;
#define PACK_STRUCT_FIELD(x) x __attribute__((packed))
#define PACK_STRUCT_STRUCT __attribute__((packed))
#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_END
#define S16_F "d"
#define U16_F "u"
#define X16_F "x"
#define S32_F "d"
#define U32_F "u"
#define X32_F "x"
#define LWIP_PLATFORM_DIAG(x) cprintf x
#define LWIP_PLATFORM_ASSERT(x) panic(x)
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif
#endif
#ifndef LWIP_ARCH_PERF_H
#define LWIP_ARCH_PERF_H
#define PERF_START
#define PERF_STOP(x)
#endif
#ifndef LWIP_ARCH_SYS_ARCH_H
#define LWIP_ARCH_SYS_ARCH_H
#include "spinlock.h"
#include "condvar.h"
typedef int sys_thread_t;
typedef struct sys_mbox {
#define MBOXSLOTS 32
void *msg[MBOXSLOTS];
} sys_mbox_t;
typedef struct sys_sem {
struct spinlock s;
struct condvar c;
u8 count;
} sys_sem_t;
typedef struct sys_mutex {
struct spinlock s;
} sys_mutex_t;
#define SYS_MBOX_NULL (-1)
#define SYS_SEM_NULL (-1)
void lwip_core_lock(void);
void lwip_core_unlock(void);
void lwip_core_init(void);
#define SYS_ARCH_DECL_PROTECT(lev)
#define SYS_ARCH_PROTECT(lev)
#define SYS_ARCH_UNPROTECT(lev)
#define SYS_ARCH_NOWAIT 0xfffffffe
#endif
#ifndef XV6_LWIPOPTS_H
#define XV6_LWIPOPTS_H
#define LWIP_STATS 0
#define LWIP_STATS_DISPLAY 0
#define LWIP_DHCP 1
#define LWIP_COMPAT_SOCKETS 0
//#define SYS_LIGHTWEIGHT_PROT 1
#define LWIP_PROVIDE_ERRNO 1
#define MEM_ALIGNMENT 4
#define MEMP_NUM_PBUF 64
#define MEMP_NUM_UDP_PCB 8
#define MEMP_NUM_TCP_PCB 32
#define MEMP_NUM_TCP_PCB_LISTEN 16
#define MEMP_NUM_TCP_SEG TCP_SND_QUEUELEN// at least as big as TCP_SND_QUEUELEN
#define MEMP_NUM_NETBUF 128
#define MEMP_NUM_NETCONN 32
#define MEMP_NUM_SYS_TIMEOUT 6
#define PER_TCP_PCB_BUFFER (16 * 4096)
#define MEM_SIZE (PER_TCP_PCB_BUFFER*MEMP_NUM_TCP_SEG + 4096*MEMP_NUM_TCP_SEG)
#define PBUF_POOL_SIZE 512
#define PBUF_POOL_BUFSIZE 2000
#define TCP_MSS 1460
#define TCP_WND 24000
#define TCP_SND_BUF (16 * TCP_MSS)
// lwip prints a warning if TCP_SND_QUEUELEN < (2 * TCP_SND_BUF/TCP_MSS),
// but 16 is faster..
#define TCP_SND_QUEUELEN (2 * TCP_SND_BUF/TCP_MSS)
//#define TCP_SND_QUEUELEN 16
// Print error messages when we run out of memory
#define LWIP_DEBUG 1
//#define TCP_DEBUG LWIP_DBG_ON
//#define MEMP_DEBUG LWIP_DBG_ON
//#define SOCKETS_DEBUG LWIP_DBG_ON
//#define DBG_TYPES_ON LWIP_DBG_ON
//#define PBUF_DEBUG LWIP_DBG_ON
//#define API_LIB_DEBUG LWIP_DBG_ON
#define DBG_MIN_LEVEL DBG_LEVEL_SERIOUS
#define LWIP_DBG_MIN_LEVEL 0
#define MEMP_SANITY_CHECK 0
#endif
void* memset(void*, int, unsigned int);
void* memcpy(void *dst, const void *src, unsigned int n);
void* memset(void*, int, unsigned int);
unsigned int strlen(const char* str);
#include "lwip/sys.h"
#include "arch/sys_arch.h"
#include "kernel.h"
#define DIE panic(__func__)
//
// mbox
//
err_t
sys_mbox_new(sys_mbox_t *mbox, int size)
{
if (size > MBOXSLOTS) {
cprintf("sys_mbox_new: size %u\n", size);
return ERR_MEM;
}
return ERR_OK;
}
void
sys_mbox_set_invalid(sys_mbox_t *mbox)
{
DIE;
}
err_t
sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{
DIE;
}
int
sys_mbox_valid(sys_mbox_t *mbox)
{
DIE;
}
void
sys_mbox_post(sys_mbox_t *mbox, void *msg)
{
DIE;
}
void
sys_mbox_free(sys_mbox_t *mbox)
{
DIE;
}
u32_t
sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
{
DIE;
}
u32_t
sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
{
DIE;
}
//
// sem
//
err_t
sys_sem_new(sys_sem_t *sem, u8_t count)
{
initlock(&sem->s, "lwIP sem");
initcondvar(&sem->c, "lwIP condvar");
sem->count = count;
return ERR_OK;
}
void
sys_sem_free(sys_sem_t *sem)
{
DIE;
}
void
sys_sem_set_invalid(sys_sem_t *sem)
{
DIE;
}
int
sys_sem_valid(sys_sem_t *sem)
{
DIE;
}
void
sys_sem_signal(sys_sem_t *sem)
{
DIE;
}
u32_t
sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
{
DIE;
}
//
// mutex
//
err_t
sys_mutex_new(sys_mutex_t *mutex)
{
initlock(&mutex->s, "lwIP mutex");
return ERR_OK;
}
void
sys_mutex_lock(sys_mutex_t *mutex)
{
DIE;
}
void
sys_mutex_unlock(sys_mutex_t *mutex)
{
DIE;
}
void
sys_mutex_free(sys_mutex_t *mutex)
{
DIE;
}
//
// thread
//
sys_thread_t
sys_thread_new(const char *name, lwip_thread_fn thread, void *arg,
int stacksize, int prio)
{
DIE;
}
//
// init
//
void
sys_init(void)
{
}
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#define INF (~0UL) #define INF (~0UL)
#define CACHELINE 64 // cache line size #define CACHELINE 64 // cache line size
#define CPUKSTACKS (NPROC + NCPU) #define CPUKSTACKS (NPROC + NCPU)
#define QUANTUN 10 // scheduling time quantum and tick length (in msec) #define QUANTUM 10 // scheduling time quantum and tick length (in msec)
#define WQSHIFT 4 // 2^WORKSHIFT work queue slots #define WQSHIFT 4 // 2^WORKSHIFT work queue slots
#define VICTIMAGE 1000000 // cycles a proc executes before an eligible victim #define VICTIMAGE 1000000 // cycles a proc executes before an eligible victim
#if defined(HW_josmp) #if defined(HW_josmp)
......
#include "types.h"
#include "amd64.h"
#include "kernel.h"
#include "pci.h"
#include "pcireg.h"
extern int e1000attach(struct pci_func *pcif);
// Flag to do "lspci" at bootup
static int pci_show_devs = 1;
static int pci_show_addrs = 1;
// PCI "configuration mechanism one"
static u32 pci_conf1_addr_ioport = 0x0cf8;
static u32 pci_conf1_data_ioport = 0x0cfc;
// PCI driver table
struct pci_driver {
u32 key1, key2;
int (*attachfn) (struct pci_func *pcif);
};
// Forward declarations
static int pci_bridge_attach(struct pci_func *pcif);
// pci_attach_class matches the class and subclass of a PCI device
struct pci_driver pci_attach_class[] = {
{ PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI, &pci_bridge_attach },
{ 0, 0, 0 },
};
// pci_attach_vendor matches the vendor ID and device ID of a PCI device
// http://www.intel.com/products/ethernet/resource.htm?wapkw=software%20manual%20pcie#s1=Gigabit%20Ethernet&s2=all&s3=Manual
struct pci_driver pci_attach_vendor[] = {
// [E1000 5.2]
// QEMU emulates an 82540EM, specifically.
{ 0x8086, 0x100e, &e1000attach },
// Both of ud0's e1000e (82573E, 82573L)
{ 0x8086, 0x108c, &e1000attach },
{ 0x8086, 0x109A, &e1000attach },
{ 0, 0, 0 },
};
static const char *pci_class[] =
{
[0x0] = "Unknown",
[0x1] = "Storage controller",
[0x2] = "Network controller",
[0x3] = "Display controller",
[0x4] = "Multimedia device",
[0x5] = "Memory controller",
[0x6] = "Bridge device",
};
static void
pci_print_func(struct pci_func *f)
{
const char *class = pci_class[0];
if (PCI_CLASS(f->dev_class) < sizeof(pci_class) / sizeof(pci_class[0]))
class = pci_class[PCI_CLASS(f->dev_class)];
cprintf("PCI: %x:%x.%d: %x:%x: class: %x.%x (%s) irq: %d\n",
f->bus->busno, f->dev, f->func,
PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
PCI_CLASS(f->dev_class), PCI_SUBCLASS(f->dev_class), class,
f->irq_line);
}
static void
pci_conf1_set_addr(u32 bus,
u32 dev,
u32 func,
u32 offset)
{
if (!(bus < 256 &&
dev < 32 &&
func < 8 &&
offset < 256 &&
(offset&0x3) == 0))
panic("pci_conf1_set_addr");
u32 v = (1 << 31) | // config-space
(bus << 16) | (dev << 11) | (func << 8) | (offset);
outl(pci_conf1_addr_ioport, v);
}
static u32
pci_conf_read(struct pci_func *f, u32 off)
{
pci_conf1_set_addr(f->bus->busno, f->dev, f->func, off);
return inl(pci_conf1_data_ioport);
}
static void
pci_conf_write(struct pci_func *f, u32 off, u32 v)
{
pci_conf1_set_addr(f->bus->busno, f->dev, f->func, off);
outl(pci_conf1_data_ioport, v);
}
static int __attribute__((warn_unused_result))
pci_attach_match(u32 key1, u32 key2,
struct pci_driver *list, struct pci_func *pcif)
{
u32 i;
for (i = 0; list[i].attachfn; i++) {
if (list[i].key1 == key1 && list[i].key2 == key2) {
int r = list[i].attachfn(pcif);
if (r > 0)
return r;
if (r < 0)
cprintf("pci_attach_match: attaching "
"%x.%x (%p): e\n",
key1, key2, list[i].attachfn, r);
}
}
return 0;
}
static int
pci_attach(struct pci_func *f)
{
return
pci_attach_match(PCI_CLASS(f->dev_class),
PCI_SUBCLASS(f->dev_class),
&pci_attach_class[0], f) ||
pci_attach_match(PCI_VENDOR(f->dev_id),
PCI_PRODUCT(f->dev_id),
&pci_attach_vendor[0], f);
}
static int
pci_scan_bus(struct pci_bus *bus)
{
int totaldev = 0;
struct pci_func df;
memset(&df, 0, sizeof(df));
df.bus = bus;
for (df.dev = 0; df.dev < 32; df.dev++) {
u32 bhlc = pci_conf_read(&df, PCI_BHLC_REG);
if (PCI_HDRTYPE_TYPE(bhlc) > 1) // Unsupported or no device
continue;
totaldev++;
struct pci_func f = df;
for (f.func = 0; f.func < (PCI_HDRTYPE_MULTIFN(bhlc) ? 8 : 1);
f.func++) {
struct pci_func af = f;
af.dev_id = pci_conf_read(&f, PCI_ID_REG);
if (PCI_VENDOR(af.dev_id) == 0xffff)
continue;
u32 intr = pci_conf_read(&af, PCI_INTERRUPT_REG);
af.irq_line = PCI_INTERRUPT_LINE(intr);
af.dev_class = pci_conf_read(&af, PCI_CLASS_REG);
if (pci_show_devs)
pci_print_func(&af);
pci_attach(&af);
}
}
return totaldev;
}
static int
pci_bridge_attach(struct pci_func *pcif)
{
u32 ioreg = pci_conf_read(pcif, PCI_BRIDGE_STATIO_REG);
u32 busreg = pci_conf_read(pcif, PCI_BRIDGE_BUS_REG);
if (PCI_BRIDGE_IO_32BITS(ioreg)) {
cprintf("PCI: %x:%x.%d: 32-bit bridge IO not supported.\n",
pcif->bus->busno, pcif->dev, pcif->func);
return 0;
}
struct pci_bus nbus;
memset(&nbus, 0, sizeof(nbus));
nbus.parent_bridge = pcif;
nbus.busno = (busreg >> PCI_BRIDGE_BUS_SECONDARY_SHIFT) & 0xff;
if (pci_show_devs)
cprintf("PCI: %x:%x.%d: bridge to PCI bus %d--%d\n",
pcif->bus->busno, pcif->dev, pcif->func,
nbus.busno,
(busreg >> PCI_BRIDGE_BUS_SUBORDINATE_SHIFT) & 0xff);
pci_scan_bus(&nbus);
return 1;
}
void
pci_func_enable(struct pci_func *f)
{
pci_conf_write(f, PCI_COMMAND_STATUS_REG,
PCI_COMMAND_IO_ENABLE |
PCI_COMMAND_MEM_ENABLE |
PCI_COMMAND_MASTER_ENABLE);
u32 bar_width;
u32 bar;
for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END;
bar += bar_width)
{
u32 oldv = pci_conf_read(f, bar);
bar_width = 4;
pci_conf_write(f, bar, 0xffffffff);
u32 rv = pci_conf_read(f, bar);
if (rv == 0)
continue;
int regnum = PCI_MAPREG_NUM(bar);
u32 base, size;
if (PCI_MAPREG_TYPE(rv) == PCI_MAPREG_TYPE_MEM) {
if (PCI_MAPREG_MEM_TYPE(rv) == PCI_MAPREG_MEM_TYPE_64BIT)
bar_width = 8;
size = PCI_MAPREG_MEM_SIZE(rv);
base = PCI_MAPREG_MEM_ADDR(oldv);
if (pci_show_addrs)
cprintf(" mem region %d: %d bytes at 0x%x\n",
regnum, size, base);
} else {
size = PCI_MAPREG_IO_SIZE(rv);
base = PCI_MAPREG_IO_ADDR(oldv);
if (pci_show_addrs)
cprintf(" io region %d: %d bytes at 0x%x\n",
regnum, size, base);
}
pci_conf_write(f, bar, oldv);
f->reg_base[regnum] = base;
f->reg_size[regnum] = size;
if (size && !base)
cprintf("PCI device %02x:%02x.%d (%04x:%04x) "
"may be misconfigured: "
"region %d: base 0x%x, size %d\n",
f->bus->busno, f->dev, f->func,
PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id),
regnum, base, size);
}
cprintf("PCI function %x:%x.%d (%x:%x) enabled\n",
f->bus->busno, f->dev, f->func,
PCI_VENDOR(f->dev_id), PCI_PRODUCT(f->dev_id));
}
void
initpci(void)
{
static struct pci_bus root_bus;
memset(&root_bus, 0, sizeof(root_bus));
pci_scan_bus(&root_bus);
}
// PCI subsystem interface
enum { pci_res_bus, pci_res_mem, pci_res_io, pci_res_max };
struct pci_bus;
struct pci_func {
struct pci_bus *bus; // Primary bus for bridges
u32 dev;
u32 func;
u32 dev_id;
u32 dev_class;
u32 reg_base[6];
u32 reg_size[6];
u8 irq_line;
};
struct pci_bus {
struct pci_func *parent_bridge;
u32 busno;
};
int pci_init(void);
void pci_func_enable(struct pci_func *f);
/* $NetBSD: pcireg.h,v 1.45 2004/02/04 06:58:24 soren Exp $ */
/*
* Copyright (c) 1995, 1996, 1999, 2000
* Christopher G. Demetriou. All rights reserved.
* Copyright (c) 1994, 1996 Charles M. Hannum. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Charles M. Hannum.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _DEV_PCI_PCIREG_H_
#define _DEV_PCI_PCIREG_H_
/*
* Standardized PCI configuration information
*
* XXX This is not complete.
*/
/*
* Device identification register; contains a vendor ID and a device ID.
*/
#define PCI_ID_REG 0x00
typedef u16 pci_vendor_id_t;
typedef u16 pci_product_id_t;
#define PCI_VENDOR_SHIFT 0
#define PCI_VENDOR_MASK 0xffff
#define PCI_VENDOR(id) \
(((id) >> PCI_VENDOR_SHIFT) & PCI_VENDOR_MASK)
#define PCI_PRODUCT_SHIFT 16
#define PCI_PRODUCT_MASK 0xffff
#define PCI_PRODUCT(id) \
(((id) >> PCI_PRODUCT_SHIFT) & PCI_PRODUCT_MASK)
#define PCI_ID_CODE(vid,pid) \
((((vid) & PCI_VENDOR_MASK) << PCI_VENDOR_SHIFT) | \
(((pid) & PCI_PRODUCT_MASK) << PCI_PRODUCT_SHIFT)) \
/*
* Command and status register.
*/
#define PCI_COMMAND_STATUS_REG 0x04
#define PCI_COMMAND_SHIFT 0
#define PCI_COMMAND_MASK 0xffff
#define PCI_STATUS_SHIFT 16
#define PCI_STATUS_MASK 0xffff
#define PCI_COMMAND_STATUS_CODE(cmd,stat) \
((((cmd) & PCI_COMMAND_MASK) >> PCI_COMMAND_SHIFT) | \
(((stat) & PCI_STATUS_MASK) >> PCI_STATUS_SHIFT)) \
#define PCI_COMMAND_IO_ENABLE 0x00000001
#define PCI_COMMAND_MEM_ENABLE 0x00000002
#define PCI_COMMAND_MASTER_ENABLE 0x00000004
#define PCI_COMMAND_SPECIAL_ENABLE 0x00000008
#define PCI_COMMAND_INVALIDATE_ENABLE 0x00000010
#define PCI_COMMAND_PALETTE_ENABLE 0x00000020
#define PCI_COMMAND_PARITY_ENABLE 0x00000040
#define PCI_COMMAND_STEPPING_ENABLE 0x00000080
#define PCI_COMMAND_SERR_ENABLE 0x00000100
#define PCI_COMMAND_BACKTOBACK_ENABLE 0x00000200
#define PCI_STATUS_CAPLIST_SUPPORT 0x00100000
#define PCI_STATUS_66MHZ_SUPPORT 0x00200000
#define PCI_STATUS_UDF_SUPPORT 0x00400000
#define PCI_STATUS_BACKTOBACK_SUPPORT 0x00800000
#define PCI_STATUS_PARITY_ERROR 0x01000000
#define PCI_STATUS_DEVSEL_FAST 0x00000000
#define PCI_STATUS_DEVSEL_MEDIUM 0x02000000
#define PCI_STATUS_DEVSEL_SLOW 0x04000000
#define PCI_STATUS_DEVSEL_MASK 0x06000000
#define PCI_STATUS_TARGET_TARGET_ABORT 0x08000000
#define PCI_STATUS_MASTER_TARGET_ABORT 0x10000000
#define PCI_STATUS_MASTER_ABORT 0x20000000
#define PCI_STATUS_SPECIAL_ERROR 0x40000000
#define PCI_STATUS_PARITY_DETECT 0x80000000
/*
* PCI Class and Revision Register; defines type and revision of device.
*/
#define PCI_CLASS_REG 0x08
typedef u8 pci_class_t;
typedef u8 pci_subclass_t;
typedef u8 pci_interface_t;
typedef u8 pci_revision_t;
#define PCI_CLASS_SHIFT 24
#define PCI_CLASS_MASK 0xff
#define PCI_CLASS(cr) \
(((cr) >> PCI_CLASS_SHIFT) & PCI_CLASS_MASK)
#define PCI_SUBCLASS_SHIFT 16
#define PCI_SUBCLASS_MASK 0xff
#define PCI_SUBCLASS(cr) \
(((cr) >> PCI_SUBCLASS_SHIFT) & PCI_SUBCLASS_MASK)
#define PCI_INTERFACE_SHIFT 8
#define PCI_INTERFACE_MASK 0xff
#define PCI_INTERFACE(cr) \
(((cr) >> PCI_INTERFACE_SHIFT) & PCI_INTERFACE_MASK)
#define PCI_REVISION_SHIFT 0
#define PCI_REVISION_MASK 0xff
#define PCI_REVISION(cr) \
(((cr) >> PCI_REVISION_SHIFT) & PCI_REVISION_MASK)
#define PCI_CLASS_CODE(mainclass, subclass, interface) \
((((mainclass) & PCI_CLASS_MASK) << PCI_CLASS_SHIFT) | \
(((subclass) & PCI_SUBCLASS_MASK) << PCI_SUBCLASS_SHIFT) | \
(((interface) & PCI_INTERFACE_MASK) << PCI_INTERFACE_SHIFT))
/* base classes */
#define PCI_CLASS_PREHISTORIC 0x00
#define PCI_CLASS_MASS_STORAGE 0x01
#define PCI_CLASS_NETWORK 0x02
#define PCI_CLASS_DISPLAY 0x03
#define PCI_CLASS_MULTIMEDIA 0x04
#define PCI_CLASS_MEMORY 0x05
#define PCI_CLASS_BRIDGE 0x06
#define PCI_CLASS_COMMUNICATIONS 0x07
#define PCI_CLASS_SYSTEM 0x08
#define PCI_CLASS_INPUT 0x09
#define PCI_CLASS_DOCK 0x0a
#define PCI_CLASS_PROCESSOR 0x0b
#define PCI_CLASS_SERIALBUS 0x0c
#define PCI_CLASS_WIRELESS 0x0d
#define PCI_CLASS_I2O 0x0e
#define PCI_CLASS_SATCOM 0x0f
#define PCI_CLASS_CRYPTO 0x10
#define PCI_CLASS_DASP 0x11
#define PCI_CLASS_UNDEFINED 0xff
/* 0x00 prehistoric subclasses */
#define PCI_SUBCLASS_PREHISTORIC_MISC 0x00
#define PCI_SUBCLASS_PREHISTORIC_VGA 0x01
/* 0x01 mass storage subclasses */
#define PCI_SUBCLASS_MASS_STORAGE_SCSI 0x00
#define PCI_SUBCLASS_MASS_STORAGE_IDE 0x01
#define PCI_SUBCLASS_MASS_STORAGE_FLOPPY 0x02
#define PCI_SUBCLASS_MASS_STORAGE_IPI 0x03
#define PCI_SUBCLASS_MASS_STORAGE_RAID 0x04
#define PCI_SUBCLASS_MASS_STORAGE_ATA 0x05
#define PCI_SUBCLASS_MASS_STORAGE_SATA 0x06
#define PCI_SUBCLASS_MASS_STORAGE_MISC 0x80
/* 0x02 network subclasses */
#define PCI_SUBCLASS_NETWORK_ETHERNET 0x00
#define PCI_SUBCLASS_NETWORK_TOKENRING 0x01
#define PCI_SUBCLASS_NETWORK_FDDI 0x02
#define PCI_SUBCLASS_NETWORK_ATM 0x03
#define PCI_SUBCLASS_NETWORK_ISDN 0x04
#define PCI_SUBCLASS_NETWORK_WORLDFIP 0x05
#define PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP 0x06
#define PCI_SUBCLASS_NETWORK_MISC 0x80
/* 0x03 display subclasses */
#define PCI_SUBCLASS_DISPLAY_VGA 0x00
#define PCI_SUBCLASS_DISPLAY_XGA 0x01
#define PCI_SUBCLASS_DISPLAY_3D 0x02
#define PCI_SUBCLASS_DISPLAY_MISC 0x80
/* 0x04 multimedia subclasses */
#define PCI_SUBCLASS_MULTIMEDIA_VIDEO 0x00
#define PCI_SUBCLASS_MULTIMEDIA_AUDIO 0x01
#define PCI_SUBCLASS_MULTIMEDIA_TELEPHONY 0x02
#define PCI_SUBCLASS_MULTIMEDIA_MISC 0x80
/* 0x05 memory subclasses */
#define PCI_SUBCLASS_MEMORY_RAM 0x00
#define PCI_SUBCLASS_MEMORY_FLASH 0x01
#define PCI_SUBCLASS_MEMORY_MISC 0x80
/* 0x06 bridge subclasses */
#define PCI_SUBCLASS_BRIDGE_HOST 0x00
#define PCI_SUBCLASS_BRIDGE_ISA 0x01
#define PCI_SUBCLASS_BRIDGE_EISA 0x02
#define PCI_SUBCLASS_BRIDGE_MC 0x03 /* XXX _MCA? */
#define PCI_SUBCLASS_BRIDGE_PCI 0x04
#define PCI_SUBCLASS_BRIDGE_PCMCIA 0x05
#define PCI_SUBCLASS_BRIDGE_NUBUS 0x06
#define PCI_SUBCLASS_BRIDGE_CARDBUS 0x07
#define PCI_SUBCLASS_BRIDGE_RACEWAY 0x08
#define PCI_SUBCLASS_BRIDGE_STPCI 0x09
#define PCI_SUBCLASS_BRIDGE_INFINIBAND 0x0a
#define PCI_SUBCLASS_BRIDGE_MISC 0x80
/* 0x07 communications subclasses */
#define PCI_SUBCLASS_COMMUNICATIONS_SERIAL 0x00
#define PCI_SUBCLASS_COMMUNICATIONS_PARALLEL 0x01
#define PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL 0x02
#define PCI_SUBCLASS_COMMUNICATIONS_MODEM 0x03
#define PCI_SUBCLASS_COMMUNICATIONS_GPIB 0x04
#define PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD 0x05
#define PCI_SUBCLASS_COMMUNICATIONS_MISC 0x80
/* 0x08 system subclasses */
#define PCI_SUBCLASS_SYSTEM_PIC 0x00
#define PCI_SUBCLASS_SYSTEM_DMA 0x01
#define PCI_SUBCLASS_SYSTEM_TIMER 0x02
#define PCI_SUBCLASS_SYSTEM_RTC 0x03
#define PCI_SUBCLASS_SYSTEM_PCIHOTPLUG 0x04
#define PCI_SUBCLASS_SYSTEM_MISC 0x80
/* 0x09 input subclasses */
#define PCI_SUBCLASS_INPUT_KEYBOARD 0x00
#define PCI_SUBCLASS_INPUT_DIGITIZER 0x01
#define PCI_SUBCLASS_INPUT_MOUSE 0x02
#define PCI_SUBCLASS_INPUT_SCANNER 0x03
#define PCI_SUBCLASS_INPUT_GAMEPORT 0x04
#define PCI_SUBCLASS_INPUT_MISC 0x80
/* 0x0a dock subclasses */
#define PCI_SUBCLASS_DOCK_GENERIC 0x00
#define PCI_SUBCLASS_DOCK_MISC 0x80
/* 0x0b processor subclasses */
#define PCI_SUBCLASS_PROCESSOR_386 0x00
#define PCI_SUBCLASS_PROCESSOR_486 0x01
#define PCI_SUBCLASS_PROCESSOR_PENTIUM 0x02
#define PCI_SUBCLASS_PROCESSOR_ALPHA 0x10
#define PCI_SUBCLASS_PROCESSOR_POWERPC 0x20
#define PCI_SUBCLASS_PROCESSOR_MIPS 0x30
#define PCI_SUBCLASS_PROCESSOR_COPROC 0x40
/* 0x0c serial bus subclasses */
#define PCI_SUBCLASS_SERIALBUS_FIREWIRE 0x00
#define PCI_SUBCLASS_SERIALBUS_ACCESS 0x01
#define PCI_SUBCLASS_SERIALBUS_SSA 0x02
#define PCI_SUBCLASS_SERIALBUS_USB 0x03
#define PCI_SUBCLASS_SERIALBUS_FIBER 0x04 /* XXX _FIBRECHANNEL */
#define PCI_SUBCLASS_SERIALBUS_SMBUS 0x05
#define PCI_SUBCLASS_SERIALBUS_INFINIBAND 0x06
#define PCI_SUBCLASS_SERIALBUS_IPMI 0x07
#define PCI_SUBCLASS_SERIALBUS_SERCOS 0x08
#define PCI_SUBCLASS_SERIALBUS_CANBUS 0x09
/* 0x0d wireless subclasses */
#define PCI_SUBCLASS_WIRELESS_IRDA 0x00
#define PCI_SUBCLASS_WIRELESS_CONSUMERIR 0x01
#define PCI_SUBCLASS_WIRELESS_RF 0x10
#define PCI_SUBCLASS_WIRELESS_BLUETOOTH 0x11
#define PCI_SUBCLASS_WIRELESS_BROADBAND 0x12
#define PCI_SUBCLASS_WIRELESS_802_11A 0x20
#define PCI_SUBCLASS_WIRELESS_802_11B 0x21
#define PCI_SUBCLASS_WIRELESS_MISC 0x80
/* 0x0e I2O (Intelligent I/O) subclasses */
#define PCI_SUBCLASS_I2O_STANDARD 0x00
/* 0x0f satellite communication subclasses */
/* PCI_SUBCLASS_SATCOM_??? 0x00 / * XXX ??? */
#define PCI_SUBCLASS_SATCOM_TV 0x01
#define PCI_SUBCLASS_SATCOM_AUDIO 0x02
#define PCI_SUBCLASS_SATCOM_VOICE 0x03
#define PCI_SUBCLASS_SATCOM_DATA 0x04
/* 0x10 encryption/decryption subclasses */
#define PCI_SUBCLASS_CRYPTO_NETCOMP 0x00
#define PCI_SUBCLASS_CRYPTO_ENTERTAINMENT 0x10
#define PCI_SUBCLASS_CRYPTO_MISC 0x80
/* 0x11 data acquisition and signal processing subclasses */
#define PCI_SUBCLASS_DASP_DPIO 0x00
#define PCI_SUBCLASS_DASP_TIMEFREQ 0x01
#define PCI_SUBCLASS_DASP_SYNC 0x10
#define PCI_SUBCLASS_DASP_MGMT 0x20
#define PCI_SUBCLASS_DASP_MISC 0x80
/*
* PCI BIST/Header Type/Latency Timer/Cache Line Size Register.
*/
#define PCI_BHLC_REG 0x0c
#define PCI_BIST_SHIFT 24
#define PCI_BIST_MASK 0xff
#define PCI_BIST(bhlcr) \
(((bhlcr) >> PCI_BIST_SHIFT) & PCI_BIST_MASK)
#define PCI_HDRTYPE_SHIFT 16
#define PCI_HDRTYPE_MASK 0xff
#define PCI_HDRTYPE(bhlcr) \
(((bhlcr) >> PCI_HDRTYPE_SHIFT) & PCI_HDRTYPE_MASK)
#define PCI_HDRTYPE_TYPE(bhlcr) \
(PCI_HDRTYPE(bhlcr) & 0x7f)
#define PCI_HDRTYPE_MULTIFN(bhlcr) \
((PCI_HDRTYPE(bhlcr) & 0x80) != 0)
#define PCI_LATTIMER_SHIFT 8
#define PCI_LATTIMER_MASK 0xff
#define PCI_LATTIMER(bhlcr) \
(((bhlcr) >> PCI_LATTIMER_SHIFT) & PCI_LATTIMER_MASK)
#define PCI_CACHELINE_SHIFT 0
#define PCI_CACHELINE_MASK 0xff
#define PCI_CACHELINE(bhlcr) \
(((bhlcr) >> PCI_CACHELINE_SHIFT) & PCI_CACHELINE_MASK)
#define PCI_BHLC_CODE(bist,type,multi,latency,cacheline) \
((((bist) & PCI_BIST_MASK) << PCI_BIST_SHIFT) | \
(((type) & PCI_HDRTYPE_MASK) << PCI_HDRTYPE_SHIFT) | \
(((multi)?0x80:0) << PCI_HDRTYPE_SHIFT) | \
(((latency) & PCI_LATTIMER_MASK) << PCI_LATTIMER_SHIFT) | \
(((cacheline) & PCI_CACHELINE_MASK) << PCI_CACHELINE_SHIFT))
/*
* PCI header type
*/
#define PCI_HDRTYPE_DEVICE 0
#define PCI_HDRTYPE_PPB 1
#define PCI_HDRTYPE_PCB 2
/*
* Mapping registers
*/
#define PCI_MAPREG_START 0x10
#define PCI_MAPREG_END 0x28
#define PCI_MAPREG_ROM 0x30
#define PCI_MAPREG_PPB_END 0x18
#define PCI_MAPREG_PCB_END 0x14
#define PCI_MAPREG_TYPE(mr) \
((mr) & PCI_MAPREG_TYPE_MASK)
#define PCI_MAPREG_TYPE_MASK 0x00000001
#define PCI_MAPREG_TYPE_MEM 0x00000000
#define PCI_MAPREG_TYPE_IO 0x00000001
#define PCI_MAPREG_ROM_ENABLE 0x00000001
#define PCI_MAPREG_MEM_TYPE(mr) \
((mr) & PCI_MAPREG_MEM_TYPE_MASK)
#define PCI_MAPREG_MEM_TYPE_MASK 0x00000006
#define PCI_MAPREG_MEM_TYPE_32BIT 0x00000000
#define PCI_MAPREG_MEM_TYPE_32BIT_1M 0x00000002
#define PCI_MAPREG_MEM_TYPE_64BIT 0x00000004
#define PCI_MAPREG_MEM_PREFETCHABLE(mr) \
(((mr) & PCI_MAPREG_MEM_PREFETCHABLE_MASK) != 0)
#define PCI_MAPREG_MEM_PREFETCHABLE_MASK 0x00000008
#define PCI_MAPREG_MEM_ADDR(mr) \
((mr) & PCI_MAPREG_MEM_ADDR_MASK)
#define PCI_MAPREG_MEM_SIZE(mr) \
(PCI_MAPREG_MEM_ADDR(mr) & -PCI_MAPREG_MEM_ADDR(mr))
#define PCI_MAPREG_MEM_ADDR_MASK 0xfffffff0
#define PCI_MAPREG_MEM64_ADDR(mr) \
((mr) & PCI_MAPREG_MEM64_ADDR_MASK)
#define PCI_MAPREG_MEM64_SIZE(mr) \
(PCI_MAPREG_MEM64_ADDR(mr) & -PCI_MAPREG_MEM64_ADDR(mr))
#define PCI_MAPREG_MEM64_ADDR_MASK 0xfffffffffffffff0ULL
#define PCI_MAPREG_IO_ADDR(mr) \
((mr) & PCI_MAPREG_IO_ADDR_MASK)
#define PCI_MAPREG_IO_SIZE(mr) \
(PCI_MAPREG_IO_ADDR(mr) & -PCI_MAPREG_IO_ADDR(mr))
#define PCI_MAPREG_IO_ADDR_MASK 0xfffffffc
#define PCI_MAPREG_SIZE_TO_MASK(size) \
(-(size))
#define PCI_MAPREG_NUM(offset) \
(((unsigned)(offset)-PCI_MAPREG_START)/4)
/*
* Cardbus CIS pointer (PCI rev. 2.1)
*/
#define PCI_CARDBUS_CIS_REG 0x28
/*
* Subsystem identification register; contains a vendor ID and a device ID.
* Types/macros for PCI_ID_REG apply.
* (PCI rev. 2.1)
*/
#define PCI_SUBSYS_ID_REG 0x2c
/*
* Capabilities link list (PCI rev. 2.2)
*/
#define PCI_CAPLISTPTR_REG 0x34 /* header type 0 */
#define PCI_CARDBUS_CAPLISTPTR_REG 0x14 /* header type 2 */
#define PCI_CAPLIST_PTR(cpr) ((cpr) & 0xff)
#define PCI_CAPLIST_NEXT(cr) (((cr) >> 8) & 0xff)
#define PCI_CAPLIST_CAP(cr) ((cr) & 0xff)
#define PCI_CAP_RESERVED0 0x00
#define PCI_CAP_PWRMGMT 0x01
#define PCI_CAP_AGP 0x02
#define PCI_CAP_AGP_MAJOR(cr) (((cr) >> 20) & 0xf)
#define PCI_CAP_AGP_MINOR(cr) (((cr) >> 16) & 0xf)
#define PCI_CAP_VPD 0x03
#define PCI_CAP_SLOTID 0x04
#define PCI_CAP_MSI 0x05
#define PCI_CAP_CPCI_HOTSWAP 0x06
#define PCI_CAP_PCIX 0x07
#define PCI_CAP_LDT 0x08
#define PCI_CAP_VENDSPEC 0x09
#define PCI_CAP_DEBUGPORT 0x0a
#define PCI_CAP_CPCI_RSRCCTL 0x0b
#define PCI_CAP_HOTPLUG 0x0c
#define PCI_CAP_AGP8 0x0e
#define PCI_CAP_SECURE 0x0f
#define PCI_CAP_PCIEXPRESS 0x10
#define PCI_CAP_MSIX 0x11
/*
* Vital Product Data; access via capability pointer (PCI rev 2.2).
*/
#define PCI_VPD_ADDRESS_MASK 0x7fff
#define PCI_VPD_ADDRESS_SHIFT 16
#define PCI_VPD_ADDRESS(ofs) \
(((ofs) & PCI_VPD_ADDRESS_MASK) << PCI_VPD_ADDRESS_SHIFT)
#define PCI_VPD_DATAREG(ofs) ((ofs) + 4)
#define PCI_VPD_OPFLAG 0x80000000
/*
* Power Management Capability; access via capability pointer.
*/
/* Power Management Capability Register */
#define PCI_PMCR 0x02
#define PCI_PMCR_D1SUPP 0x0200
#define PCI_PMCR_D2SUPP 0x0400
/* Power Management Control Status Register */
#define PCI_PMCSR 0x04
#define PCI_PMCSR_STATE_MASK 0x03
#define PCI_PMCSR_STATE_D0 0x00
#define PCI_PMCSR_STATE_D1 0x01
#define PCI_PMCSR_STATE_D2 0x02
#define PCI_PMCSR_STATE_D3 0x03
/*
* PCI-X capability.
*/
/*
* Command. 16 bits at offset 2 (e.g. upper 16 bits of the first 32-bit
* word at the capability; the lower 16 bits are the capability ID and
* next capability pointer).
*
* Since we always read PCI config space in 32-bit words, we define these
* as 32-bit values, offset and shifted appropriately. Make sure you perform
* the appropriate R/M/W cycles!
*/
#define PCI_PCIX_CMD 0x00
#define PCI_PCIX_CMD_PERR_RECOVER 0x00010000
#define PCI_PCIX_CMD_RELAXED_ORDER 0x00020000
#define PCI_PCIX_CMD_BYTECNT_MASK 0x000c0000
#define PCI_PCIX_CMD_BYTECNT_SHIFT 18
#define PCI_PCIX_CMD_BCNT_512 0x00000000
#define PCI_PCIX_CMD_BCNT_1024 0x00040000
#define PCI_PCIX_CMD_BCNT_2048 0x00080000
#define PCI_PCIX_CMD_BCNT_4096 0x000c0000
#define PCI_PCIX_CMD_SPLTRANS_MASK 0x00700000
#define PCI_PCIX_CMD_SPLTRANS_1 0x00000000
#define PCI_PCIX_CMD_SPLTRANS_2 0x00100000
#define PCI_PCIX_CMD_SPLTRANS_3 0x00200000
#define PCI_PCIX_CMD_SPLTRANS_4 0x00300000
#define PCI_PCIX_CMD_SPLTRANS_8 0x00400000
#define PCI_PCIX_CMD_SPLTRANS_12 0x00500000
#define PCI_PCIX_CMD_SPLTRANS_16 0x00600000
#define PCI_PCIX_CMD_SPLTRANS_32 0x00700000
/*
* Status. 32 bits at offset 4.
*/
#define PCI_PCIX_STATUS 0x04
#define PCI_PCIX_STATUS_FN_MASK 0x00000007
#define PCI_PCIX_STATUS_DEV_MASK 0x000000f8
#define PCI_PCIX_STATUS_BUS_MASK 0x0000ff00
#define PCI_PCIX_STATUS_64BIT 0x00010000
#define PCI_PCIX_STATUS_133 0x00020000
#define PCI_PCIX_STATUS_SPLDISC 0x00040000
#define PCI_PCIX_STATUS_SPLUNEX 0x00080000
#define PCI_PCIX_STATUS_DEVCPLX 0x00100000
#define PCI_PCIX_STATUS_MAXB_MASK 0x00600000
#define PCI_PCIX_STATUS_MAXB_SHIFT 21
#define PCI_PCIX_STATUS_MAXB_512 0x00000000
#define PCI_PCIX_STATUS_MAXB_1024 0x00200000
#define PCI_PCIX_STATUS_MAXB_2048 0x00400000
#define PCI_PCIX_STATUS_MAXB_4096 0x00600000
#define PCI_PCIX_STATUS_MAXST_MASK 0x03800000
#define PCI_PCIX_STATUS_MAXST_1 0x00000000
#define PCI_PCIX_STATUS_MAXST_2 0x00800000
#define PCI_PCIX_STATUS_MAXST_3 0x01000000
#define PCI_PCIX_STATUS_MAXST_4 0x01800000
#define PCI_PCIX_STATUS_MAXST_8 0x02000000
#define PCI_PCIX_STATUS_MAXST_12 0x02800000
#define PCI_PCIX_STATUS_MAXST_16 0x03000000
#define PCI_PCIX_STATUS_MAXST_32 0x03800000
#define PCI_PCIX_STATUS_MAXRS_MASK 0x1c000000
#define PCI_PCIX_STATUS_MAXRS_1K 0x00000000
#define PCI_PCIX_STATUS_MAXRS_2K 0x04000000
#define PCI_PCIX_STATUS_MAXRS_4K 0x08000000
#define PCI_PCIX_STATUS_MAXRS_8K 0x0c000000
#define PCI_PCIX_STATUS_MAXRS_16K 0x10000000
#define PCI_PCIX_STATUS_MAXRS_32K 0x14000000
#define PCI_PCIX_STATUS_MAXRS_64K 0x18000000
#define PCI_PCIX_STATUS_MAXRS_128K 0x1c000000
#define PCI_PCIX_STATUS_SCERR 0x20000000
/*
* Interrupt Configuration Register; contains interrupt pin and line.
*/
#define PCI_INTERRUPT_REG 0x3c
typedef u8 pci_intr_latency_t;
typedef u8 pci_intr_grant_t;
typedef u8 pci_intr_pin_t;
typedef u8 pci_intr_line_t;
#define PCI_MAX_LAT_SHIFT 24
#define PCI_MAX_LAT_MASK 0xff
#define PCI_MAX_LAT(icr) \
(((icr) >> PCI_MAX_LAT_SHIFT) & PCI_MAX_LAT_MASK)
#define PCI_MIN_GNT_SHIFT 16
#define PCI_MIN_GNT_MASK 0xff
#define PCI_MIN_GNT(icr) \
(((icr) >> PCI_MIN_GNT_SHIFT) & PCI_MIN_GNT_MASK)
#define PCI_INTERRUPT_GRANT_SHIFT 24
#define PCI_INTERRUPT_GRANT_MASK 0xff
#define PCI_INTERRUPT_GRANT(icr) \
(((icr) >> PCI_INTERRUPT_GRANT_SHIFT) & PCI_INTERRUPT_GRANT_MASK)
#define PCI_INTERRUPT_LATENCY_SHIFT 16
#define PCI_INTERRUPT_LATENCY_MASK 0xff
#define PCI_INTERRUPT_LATENCY(icr) \
(((icr) >> PCI_INTERRUPT_LATENCY_SHIFT) & PCI_INTERRUPT_LATENCY_MASK)
#define PCI_INTERRUPT_PIN_SHIFT 8
#define PCI_INTERRUPT_PIN_MASK 0xff
#define PCI_INTERRUPT_PIN(icr) \
(((icr) >> PCI_INTERRUPT_PIN_SHIFT) & PCI_INTERRUPT_PIN_MASK)
#define PCI_INTERRUPT_LINE_SHIFT 0
#define PCI_INTERRUPT_LINE_MASK 0xff
#define PCI_INTERRUPT_LINE(icr) \
(((icr) >> PCI_INTERRUPT_LINE_SHIFT) & PCI_INTERRUPT_LINE_MASK)
#define PCI_INTERRUPT_CODE(lat,gnt,pin,line) \
((((lat)&PCI_INTERRUPT_LATENCY_MASK)<<PCI_INTERRUPT_LATENCY_SHIFT)| \
(((gnt)&PCI_INTERRUPT_GRANT_MASK) <<PCI_INTERRUPT_GRANT_SHIFT) | \
(((pin)&PCI_INTERRUPT_PIN_MASK) <<PCI_INTERRUPT_PIN_SHIFT) | \
(((line)&PCI_INTERRUPT_LINE_MASK) <<PCI_INTERRUPT_LINE_SHIFT))
#define PCI_INTERRUPT_PIN_NONE 0x00
#define PCI_INTERRUPT_PIN_A 0x01
#define PCI_INTERRUPT_PIN_B 0x02
#define PCI_INTERRUPT_PIN_C 0x03
#define PCI_INTERRUPT_PIN_D 0x04
#define PCI_INTERRUPT_PIN_MAX 0x04
/* Header Type 1 (Bridge) configuration registers */
#define PCI_BRIDGE_BUS_REG 0x18
#define PCI_BRIDGE_BUS_PRIMARY_SHIFT 0
#define PCI_BRIDGE_BUS_SECONDARY_SHIFT 8
#define PCI_BRIDGE_BUS_SUBORDINATE_SHIFT 16
#define PCI_BRIDGE_STATIO_REG 0x1C
#define PCI_BRIDGE_STATIO_IOBASE_SHIFT 0
#define PCI_BRIDGE_STATIO_IOLIMIT_SHIFT 8
#define PCI_BRIDGE_STATIO_STATUS_SHIFT 16
#define PCI_BRIDGE_STATIO_IOBASE_MASK 0xf0
#define PCI_BRIDGE_STATIO_IOLIMIT_MASK 0xf0
#define PCI_BRIDGE_STATIO_STATUS_MASK 0xffff
#define PCI_BRIDGE_IO_32BITS(reg) (((reg) & 0xf) == 1)
#define PCI_BRIDGE_MEMORY_REG 0x20
#define PCI_BRIDGE_MEMORY_BASE_SHIFT 4
#define PCI_BRIDGE_MEMORY_LIMIT_SHIFT 20
#define PCI_BRIDGE_MEMORY_BASE_MASK 0xffff
#define PCI_BRIDGE_MEMORY_LIMIT_MASK 0xffff
#define PCI_BRIDGE_PREFETCHMEM_REG 0x24
#define PCI_BRIDGE_PREFETCHMEM_BASE_SHIFT 4
#define PCI_BRIDGE_PREFETCHMEM_LIMIT_SHIFT 20
#define PCI_BRIDGE_PREFETCHMEM_BASE_MASK 0xffff
#define PCI_BRIDGE_PREFETCHMEM_LIMIT_MASK 0xffff
#define PCI_BRIDGE_PREFETCHMEM_64BITS(reg) ((reg) & 0xf)
#define PCI_BRIDGE_PREFETCHBASE32_REG 0x28
#define PCI_BRIDGE_PREFETCHLIMIT32_REG 0x2C
#define PCI_BRIDGE_IOHIGH_REG 0x30
#define PCI_BRIDGE_IOHIGH_BASE_SHIFT 0
#define PCI_BRIDGE_IOHIGH_LIMIT_SHIFT 16
#define PCI_BRIDGE_IOHIGH_BASE_MASK 0xffff
#define PCI_BRIDGE_IOHIGH_LIMIT_MASK 0xffff
#define PCI_BRIDGE_CONTROL_REG 0x3C
#define PCI_BRIDGE_CONTROL_SHIFT 16
#define PCI_BRIDGE_CONTROL_MASK 0xffff
#define PCI_BRIDGE_CONTROL_PERE (1 << 0)
#define PCI_BRIDGE_CONTROL_SERR (1 << 1)
#define PCI_BRIDGE_CONTROL_ISA (1 << 2)
#define PCI_BRIDGE_CONTROL_VGA (1 << 3)
/* Reserved (1 << 4) */
#define PCI_BRIDGE_CONTROL_MABRT (1 << 5)
#define PCI_BRIDGE_CONTROL_SECBR (1 << 6)
#define PCI_BRIDGE_CONTROL_SECFASTB2B (1 << 7)
#define PCI_BRIDGE_CONTROL_PRI_DISC_TIMER (1 << 8)
#define PCI_BRIDGE_CONTROL_SEC_DISC_TIMER (1 << 9)
#define PCI_BRIDGE_CONTROL_DISC_TIMER_STAT (1 << 10)
#define PCI_BRIDGE_CONTROL_DISC_TIMER_SERR (1 << 11)
/* Reserved (1 << 12) - (1 << 15) */
/*
* Vital Product Data resource tags.
*/
struct pci_vpd_smallres {
u8 vpdres_byte0; /* length of data + tag */
/* Actual data. */
} __attribute__((__packed__));
struct pci_vpd_largeres {
u8 vpdres_byte0;
u8 vpdres_len_lsb; /* length of data only */
u8 vpdres_len_msb;
/* Actual data. */
} __attribute__((__packed__));
#define PCI_VPDRES_ISLARGE(x) ((x) & 0x80)
#define PCI_VPDRES_SMALL_LENGTH(x) ((x) & 0x7)
#define PCI_VPDRES_SMALL_NAME(x) (((x) >> 3) & 0xf)
#define PCI_VPDRES_LARGE_NAME(x) ((x) & 0x7f)
#define PCI_VPDRES_TYPE_COMPATIBLE_DEVICE_ID 0x3 /* small */
#define PCI_VPDRES_TYPE_VENDOR_DEFINED 0xe /* small */
#define PCI_VPDRES_TYPE_END_TAG 0xf /* small */
#define PCI_VPDRES_TYPE_IDENTIFIER_STRING 0x02 /* large */
#define PCI_VPDRES_TYPE_VPD 0x10 /* large */
struct pci_vpd {
u8 vpd_key0;
u8 vpd_key1;
u8 vpd_len; /* length of data only */
/* Actual data. */
} __attribute__((__packed__));
/*
* Recommended VPD fields:
*
* PN Part number of assembly
* FN FRU part number
* EC EC level of assembly
* MN Manufacture ID
* SN Serial Number
*
* Conditionally recommended VPD fields:
*
* LI Load ID
* RL ROM Level
* RM Alterable ROM Level
* NA Network Address
* DD Device Driver Level
* DG Diagnostic Level
* LL Loadable Microcode Level
* VI Vendor ID/Device ID
* FU Function Number
* SI Subsystem Vendor ID/Subsystem ID
*
* Additional VPD fields:
*
* Z0-ZZ User/Product Specific
*/
/*
* Threshold below which 32bit PCI DMA needs bouncing.
*/
#define PCI32_DMA_BOUNCE_THRESHOLD 0x100000000ULL
#endif /* _DEV_PCI_PCIREG_H_ */
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include "vm.h" #include "vm.h"
#include "sched.h" #include "sched.h"
extern void threadstub(void);
int __mpalign__ idle[NCPU]; int __mpalign__ idle[NCPU];
struct ns *nspid __mpalign__; struct ns *nspid __mpalign__;
static struct proc *bootproc __mpalign__; static struct proc *bootproc __mpalign__;
...@@ -267,17 +269,19 @@ inituser(void) ...@@ -267,17 +269,19 @@ inituser(void)
release(&p->lock); release(&p->lock);
for (u32 c = 0; c < NCPU; c++) { for (u32 c = 0; c < NCPU; c++) {
struct proc *rcup = allocproc(); extern void gc_worker(void*);
rcup->vmap = vmap_alloc(); struct proc *gcp;
rcup->context->rip = (u64) gc_worker;
rcup->cwd = 0; gcp = threadalloc(gc_worker, NULL);
rcup->cpuid = c; if (gcp == NULL)
rcup->cpu_pin = 1; panic("threadalloc: gc_worker");
acquire(&rcup->lock); gcp->cpuid = c;
rcup->state = RUNNABLE; gcp->cpu_pin = 1;
addrun(rcup); acquire(&gcp->lock);
release(&rcup->lock); gcp->state = RUNNABLE;
addrun(gcp);
release(&gcp->lock);
} }
} }
...@@ -352,7 +356,7 @@ scheduler(void) ...@@ -352,7 +356,7 @@ scheduler(void)
mtpause(schedp); mtpause(schedp);
if (p->context->rip != (uptr)forkret && if (p->context->rip != (uptr)forkret &&
p->context->rip != (uptr)gc_worker) p->context->rip != (uptr)threadstub)
{ {
mtresume(p); mtresume(p);
} }
...@@ -663,3 +667,34 @@ wait(void) ...@@ -663,3 +667,34 @@ wait(void)
release(&myproc()->lock); release(&myproc()->lock);
} }
} }
void
threadhelper(void (*fn)(void *), void *arg)
{
release(&myproc()->lock); // initially held by scheduler
mtstart(fn, myproc());
fn(arg);
exit();
}
struct proc*
threadalloc(void (*fn)(void *), void *arg)
{
struct proc *p;
p = allocproc();
if (p == NULL)
return NULL;
p->vmap = vmap_alloc();
if (p->vmap == NULL) {
gc_delayed(p, kmfree);
return NULL;
}
p->context->rip = (u64)threadstub;
p->context->r12 = (u64)fn;
p->context->r13 = (u64)arg;
p->cwd = 0;
return p;
}
...@@ -42,8 +42,6 @@ struct proc { ...@@ -42,8 +42,6 @@ struct proc {
struct proc *parent; // Parent process struct proc *parent; // Parent process
struct trapframe *tf; // Trap frame for current syscall struct trapframe *tf; // Trap frame for current syscall
struct context *context; // swtch() here to run process struct context *context; // swtch() here to run process
struct condvar *oncv; // Where it is sleeping, for kill()
struct proc *cv_next; // Linked list of processes waiting for oncv
int killed; // If non-zero, have been killed int killed; // If non-zero, have been killed
struct file *ofile[NOFILE]; // Open files struct file *ofile[NOFILE]; // Open files
struct inode *cwd; // Current directory struct inode *cwd; // Current directory
...@@ -66,6 +64,11 @@ struct proc { ...@@ -66,6 +64,11 @@ struct proc {
struct runq *runq; struct runq *runq;
struct wqframe wqframe; struct wqframe wqframe;
STAILQ_ENTRY(proc) runqlink; STAILQ_ENTRY(proc) runqlink;
struct condvar *oncv; // Where it is sleeping, for kill()
u64 cv_wakeup; // Wakeup time for this process
LIST_ENTRY(proc) cv_waiters; // Linked list of processes waiting for oncv
LIST_ENTRY(proc) cv_sleep; // Linked list of processes sleeping on a cv
}; };
extern struct ns *nspid; extern struct ns *nspid;
...@@ -18,6 +18,33 @@ initlock(struct spinlock *lk, char *name) ...@@ -18,6 +18,33 @@ initlock(struct spinlock *lk, char *name)
lk->locked = 0; lk->locked = 0;
} }
int
tryacquire(struct spinlock *lk)
{
pushcli(); // disable interrupts to avoid deadlock.
#if SPINLOCK_DEBUG
if(holding(lk)) {
cprintf("%lx\n", __builtin_return_address(0));
panic("acquire");
}
#endif
mtlock(lk);
if (xchg32(&lk->locked, 1) != 0) {
popcli();
return 0;
}
mtacquired(lk);
#if SPINLOCK_DEBUG
// Record info about lock acquisition for debugging.
lk->cpu = mycpu();
getcallerpcs(&lk, lk->pcs);
#endif
return 1;
}
// Acquire the lock. // Acquire the lock.
// Loops (spins) until the lock is acquired. // Loops (spins) until the lock is acquired.
// Holding a lock for a long time may cause // Holding a lock for a long time may cause
......
...@@ -24,3 +24,9 @@ swtch: ...@@ -24,3 +24,9 @@ swtch:
popq %rbp popq %rbp
popq %rbx popq %rbx
ret ret
.globl threadstub
threadstub:
movq %r12, %rdi
movq %r13, %rsi
jmp threadhelper
...@@ -11,11 +11,6 @@ ...@@ -11,11 +11,6 @@
#include "kmtrace.h" #include "kmtrace.h"
#include "bits.h" #include "bits.h"
u64 ticks __mpalign__;
struct spinlock tickslock __mpalign__;
struct condvar cv_ticks __mpalign__;
struct segdesc __attribute__((aligned(16))) bootgdt[NSEGS] = { struct segdesc __attribute__((aligned(16))) bootgdt[NSEGS] = {
// null // null
[0]=SEGDESC(0, 0, 0), [0]=SEGDESC(0, 0, 0),
...@@ -76,12 +71,8 @@ trap(struct trapframe *tf) ...@@ -76,12 +71,8 @@ trap(struct trapframe *tf)
switch(tf->trapno){ switch(tf->trapno){
case T_IRQ0 + IRQ_TIMER: case T_IRQ0 + IRQ_TIMER:
if(mycpu()->id == 0){ if (mycpu()->id == 0)
acquire(&tickslock); cv_tick();
ticks++;
cv_wakeup(&cv_ticks);
release(&tickslock);
}
lapiceoi(); lapiceoi();
break; break;
case T_IRQ0 + IRQ_IDE: case T_IRQ0 + IRQ_IDE:
...@@ -117,6 +108,13 @@ trap(struct trapframe *tf) ...@@ -117,6 +108,13 @@ trap(struct trapframe *tf)
sampconf(); sampconf();
break; break;
default: default:
if (tf->trapno == T_IRQ0+e1000irq) {
e1000intr();
lapiceoi();
piceoi();
break;
}
if(myproc() == 0 || (tf->cs&3) == 0){ if(myproc() == 0 || (tf->cs&3) == 0){
// In kernel, it must be our mistake. // In kernel, it must be our mistake.
cprintf("unexpected trap %d from cpu %d rip %lx (cr2=0x%lx)\n", cprintf("unexpected trap %d from cpu %d rip %lx (cr2=0x%lx)\n",
......
...@@ -6,6 +6,7 @@ typedef unsigned char uint8; ...@@ -6,6 +6,7 @@ typedef unsigned char uint8;
typedef uint64 uintptr; typedef uint64 uintptr;
typedef uint8 u8; typedef uint8 u8;
typedef char s8;
typedef uint16 u16; typedef uint16 u16;
typedef short s16; typedef short s16;
typedef uint32 u32; typedef uint32 u32;
......
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论