diff options
author | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
---|---|---|
committer | Thomas Bushnell <thomas@gnu.org> | 1997-02-25 21:28:37 +0000 |
commit | f07a4c844da9f0ecae5bbee1ab94be56505f26f7 (patch) | |
tree | 12b07c7e578fc1a5f53dbfde2632408491ff2a70 /chips/lance_mapped.c |
Initial source
Diffstat (limited to 'chips/lance_mapped.c')
-rw-r--r-- | chips/lance_mapped.c | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/chips/lance_mapped.c b/chips/lance_mapped.c new file mode 100644 index 0000000..26096bd --- /dev/null +++ b/chips/lance_mapped.c @@ -0,0 +1,417 @@ +/* + * 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 Software.Distribution@CS.CMU.EDU + * 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 |