|
|
GNU Mach 1.0
/*
* Mach Operating System
* Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or [email protected]
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* File: if_se_mapped.c
* Author: Alessandro Forin, Carnegie Mellon University
* Date: 8/90
*
* In-kernel side of the user-mapped ethernet driver.
*/
#include <ln.h>
#if NLN > 0
#include <platforms.h>
#include <mach/machine/vm_types.h>
#include <machine/machspl.h> /* spl definitions */
#include <chips/lance.h>
#include <chips/busses.h>
#include <device/device_types.h>
#include <device/errno.h>
#include <device/io_req.h>
#include <device/net_status.h>
#include <device/net_io.h>
#include <device/if_hdr.h>
#include <device/if_ether.h>
#include <vm/vm_kern.h>
#include <kern/eventcount.h>
#include <machine/machspl.h>
#ifdef DECSTATION
#define machine_btop mips_btop
#define kvctophys(v) K0SEG_TO_PHYS((v)) /* kernel virtual cached */
#define phystokvc(p) PHYS_TO_K0SEG((p)) /* and back */
#define kvutophys(v) K1SEG_TO_PHYS((v)) /* kernel virtual uncached */
#define phystokvu(p) PHYS_TO_K1SEG((p)) /* and back */
/* remap from k2 to k0 */
#define kvirt(v) ((phystokvc(pmap_extract(pmap_kernel(),v))))
#include <mips/mips_cpu.h>
/*
* Wired addresses and sizes
*/
#define SE0_REG_EMRG (se_reg_t)(0xb8000000)
#define REGBASE(unit) (((u_int)SE_statii[unit].registers) - se_sw->regspace)
#define SE_REG_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->regspace)
#define SE_REG_SIZE PAGE_SIZE
#define SE_BUF_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->bufspace)
#define SE_BUF_SIZE (128*1024)
#define SE_ADR_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->romspace)
#define SE_ADR_SIZE PAGE_SIZE
#endif /*DECSTATION*/
#ifdef VAXSTATION
#define machine_btop vax_btop
#endif /*VAXSTATION*/
#ifdef LUNA88K
# define machine_btop m88k_btop
# define kvirt(v) (v)
# define kvctophys(v) pmap_extract(pmap_kernel(),(v))
# define SE0_REG_EMRG ((se_reg_t)0xF1000000U)
# define REGBASE(unit) (((u_int)SE_statii[unit].registers) - se_sw->regspace)
# define SE_REG_PHYS(unit) (REGBASE(unit) + se_sw->regspace)
# define SE_REG_SIZE PAGE_SIZE
# define SE_BUF_PHYS(unit) (REGBASE(unit) + se_sw->bufspace)
# define SE_BUF_SIZE (64*1024)
# define SE_ADR_PHYS(unit) kvctophys(REGBASE(unit) + se_sw->romspace)
# define SE_ADR_SIZE PAGE_SIZE
# define wbflush() /*empty*/
#endif /*LUNA88K*/
/*
* Autoconf info
*/
static vm_offset_t SEstd[NLN] = { 0 };
static struct bus_device *SEinfo[NLN];
void SE_attach();
int SE_probe();
struct bus_driver SEdriver =
{ SE_probe, 0, SE_attach, 0, SEstd, "SE", SEinfo, };
/*
* Externally visible functions
*/
int SE_probe(); /* Kernel */
void SE_intr(), SE_portdeath();
/* User */
int SE_open(), SE_close();
vm_offset_t SE_mmap();
/* forward declarations */
static void SE_stop(unsigned int unit);
/*
* Status information for all interfaces
*/
/*static*/ struct SE_status {
se_reg_t registers;
mapped_ether_info_t info;
struct evc eventcounter;
} SE_statii[NLN];
/*
* Probe the Lance to see (if) that it's there
*/
int
SE_probe(regbase, ui)
vm_offset_t regbase;
register struct bus_device *ui;
{
int unit = ui->unit;
se_reg_t regs;
vm_offset_t addr;
mapped_ether_info_t info;
struct SE_status *self;
if (unit >= NLN)
return 0;
self = &SE_statii[unit];
printf("[mappable] ");
regs = (se_reg_t) (regbase + se_sw->regspace);
self->registers = regs;
/*
* Reset the interface
*/
SE_stop(unit);
/*
* Grab a page to be mapped later to users
*/
(void) kmem_alloc_wired(kernel_map, &addr, PAGE_SIZE);
/*
on the decstation, kmem_alloc_wired returns virtual addresses
in the k2 seg. Since this page is going to get mapped in
user space, we need to transform it to a better understood
virtual address. The kvirt function does this.
*/
bzero(addr, PAGE_SIZE);
info = (mapped_ether_info_t) kvirt(addr);
self->info = info;
/*
* Set permanent info
*/
info->rom_stride = se_sw->romstride;
info->ram_stride = se_sw->ramstride;
info->buffer_size = se_sw->ramsize;
info->buffer_physaddr = se_sw->ln_bufspace;
/*
* Synch setup
*/
evc_init(&self->eventcounter);
info->wait_event = self->eventcounter.ev_id;
return 1;
}
void
SE_attach(ui)
register struct bus_device *ui;
{
}
/*
* Shut off the lance
*/
static void SE_stop(unsigned int unit)
{
register se_reg_t regs = SE_statii[unit].registers;
if (regs == 0)
/* Stray interrupt */
regs = SE0_REG_EMRG;
regs[2] = CSR0_SELECT; /* XXXX rap XXXX */
wbflush();
regs[0] = LN_CSR0_STOP;
wbflush();
}
/*
* Ethernet interface interrupt routine
*/
void SE_intr(unit,spllevel)
int unit;
spl_t spllevel;
{
register struct SE_status *self = &SE_statii[unit];
register se_reg_t regs = self->registers;
register csr;
if (regs == 0) { /* stray */
SE_stop(unit);
return;
}
/* Acknowledge interrupt request, drop spurious intr */
csr = regs[0];
if ((csr & LN_CSR0_INTR) == 0)
return;
regs[0] = csr & LN_CSR0_WTC; /* silence it */
splx(spllevel); /* drop priority now */
/* Pass csr state up to user thread */
if (self->info) {
self->info->interrupt_count++; /* total interrupts */
self->info->saved_csr0 = csr;
}
/* Awake user thread */
evc_signal(&self->eventcounter);
}
extern boolean_t se_use_mapped_interface[NLN];
/*
* Device open procedure
*/
int SE_open(dev, flag, ior)
io_req_t ior;
{
int unit = dev;
register struct SE_status *self = &SE_statii[unit];
if (unit >= NLN)
return EINVAL;
/*
* Silence interface, just in case
*/
SE_stop(unit);
/*
* Reset eventcounter
*/
evc_signal(&self->eventcounter);
se_use_mapped_interface[unit] = 1;
/*
* Do not turn Ether interrupts on. The user can do it when ready
* to take them.
*/
return 0;
}
/*
* Device close procedure
*/
int SE_close(dev, flag)
{
int unit = dev;
register struct SE_status *self = &SE_statii[unit];
if (unit >= NLN)
return EINVAL;
/*
* Silence interface, in case user forgot
*/
SE_stop(unit);
evc_signal(&self->eventcounter);
se_normal(unit);
return 0;
}
/*
* Get status procedure.
* We need to tell that we are mappable.
*/
io_return_t
SE_get_status(ifp, flavor, status, status_count)
/* struct ifnet *ifp; not really..*/
int flavor;
dev_status_t status; /* pointer to OUT array */
unsigned int *status_count; /* OUT */
{
switch (flavor) {
case NET_STATUS:
{
register struct net_status *ns = (struct net_status *)status;
ns->min_packet_size = sizeof(struct ether_header);
ns->max_packet_size = sizeof(struct ether_header) + ETHERMTU;
ns->header_format = HDR_ETHERNET;
ns->header_size = sizeof(struct ether_header);
ns->address_size = 6;
ns->flags = IFF_BROADCAST;
ns->mapped_size = SE_BUF_SIZE + (3 * PAGE_SIZE);
*status_count = NET_STATUS_COUNT;
break;
}
/* case NET_ADDRESS: find it yourself */
default:
return (D_INVALID_OPERATION);
}
return (D_SUCCESS);
}
/*
* Should not refuse this either
*/
int SE_set_status(dev, flavor, status, status_count)
int dev;
int flavor;
dev_status_t status;
unsigned int status_count;
{
return (D_SUCCESS);
}
/*
* Port death notification routine
*/
void SE_portdeath(dev, dead_port)
{
}
/*
* Virtual->physical mapping routine.
*/
vm_offset_t
SE_mmap(dev, off, prot)
int dev;
vm_offset_t off;
vm_prot_t prot;
{
vm_offset_t page;
vm_offset_t addr;
int unit = dev;
/*
* The offset (into the VM object) defines the following layout
*
* off size what
* 0 1pg mapping information (csr & #interrupts)
* 1pg 1pg lance registers
* 2pg 1pg lance station address (ROM)
* 3pg 128k lance buffers
*/
#define S0 PAGE_SIZE
#define S1 (S0+SE_REG_SIZE)
#define S2 (S1+SE_ADR_SIZE)
#define S3 (S2+SE_BUF_SIZE)
if (off < S0) {
addr = kvctophys (SE_statii[unit].info);
} else if (off < S1) {
addr = (vm_offset_t) SE_REG_PHYS(unit);
off -= S0;
} else if (off < S2) {
addr = (vm_offset_t) SE_ADR_PHYS(unit);
off -= S1;
} else if (off < S3) {
addr = (vm_offset_t) SE_BUF_PHYS(unit);
off -= S2;
} else
return (EINVAL);
page = machine_btop(addr + off);
return (page);
}
#endif NLN > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.