1 /*
2 * Mach Operating System
3 * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: lance_mapped.c,v $
29 * Revision 2.22 93/11/17 16:12:02 dbg
30 * Changed mmap routines to return physical address instead of
31 * physical page number. Added prototypes.
32 * [93/06/16 dbg]
33 *
34 * Revision 2.21 93/05/15 19:36:50 mrt
35 * machparam.h -> machspl.h
36 *
37 * Revision 2.20 93/05/10 20:08:11 rvb
38 * No more sys/types.h.
39 * [93/05/06 09:52:53 af]
40 *
41 * Revision 2.19 93/03/26 17:58:07 mrt
42 * Removed dev_t, minor();
43 * [93/03/17 af]
44 *
45 * Revision 2.18 93/03/11 14:06:09 danner
46 * eliminate u_long.
47 * [93/03/09 danner]
48 *
49 * Revision 2.17 93/02/05 08:18:50 danner
50 * Include fixes.
51 * [93/02/04 danner]
52 *
53 * Revision 2.16 93/02/01 09:55:15 danner
54 * Put return types on some functions to quiet warnings.
55 * [93/01/25 jfriedl]
56 *
57 * Revision 2.15 93/01/14 17:16:46 danner
58 * corrected typo.
59 * [93/01/12 danner]
60 * Added LUNA88K and portability support.
61 * [92/12/02 jfriedl]
62 * Proper spl typing.
63 * [92/11/30 af]
64 *
65 * Revision 2.14 92/01/03 20:39:03 dbg
66 * No need to destroy/init the eventcounter all the time.
67 * [91/12/27 af]
68 *
69 * Since we are actually using this, made user-safe.
70 * [91/12/27 af]
71 *
72 * Revision 2.13 91/12/13 14:54:23 jsb
73 * Use eventcounters.
74 * [91/12/12 17:43:08 af]
75 *
76 * Revision 2.12 91/08/24 11:52:17 af
77 * Bugfix: typos, spl for 3min.
78 * [91/08/02 01:52:26 af]
79 *
80 * Revision 2.11 91/06/25 20:54:03 rpd
81 * Tweaks to make gcc happy.
82 *
83 * Revision 2.10 91/06/19 15:19:40 rvb
84 * mips->DECSTATION; vax->VAXSTATION
85 * [91/06/12 14:01:45 rvb]
86 *
87 * File moved here from mips/PMAX since it tries to be generic;
88 * it is used on the PMAX and could be used on the Vax3100.
89 * [91/06/04 rvb]
90 *
91 * Revision 2.9 91/05/14 17:22:24 mrt
92 * Correcting copyright
93 *
94 * Revision 2.8 91/03/16 14:54:00 rpd
95 * Picked up a further spl fix from Sandro.
96 * [91/03/09 rpd]
97 * Updated for new kmem_alloc interface.
98 * [91/03/03 rpd]
99 * Removed thread_swappable.
100 * [91/01/18 rpd]
101 *
102 * Revision 2.7 91/02/14 14:34:16 mrt
103 * In interrupt routine, drop priority as now required.
104 * Also sanity check for spurious interrupts anyways.
105 * [91/02/12 12:41:46 af]
106 *
107 * Revision 2.6 91/02/05 17:41:22 mrt
108 * Added author notices
109 * [91/02/04 11:13:58 mrt]
110 *
111 * Changed to use new Mach copyright
112 * [91/02/02 12:12:01 mrt]
113 *
114 * Revision 2.5 90/12/05 23:31:33 af
115 * Cleanups.
116 * [90/12/03 23:20:13 af]
117 *
118 * Revision 2.3.1.1 90/10/03 12:06:02 af
119 * Made it work with multiple ether boards (e.g. thick ether
120 * on 3maxen). This is the first time a mapped device does
121 * something before the un-mapped one..
122 *
123 * Revision 2.3 90/09/09 23:52:11 rpd
124 * Changed thread_resume_from_kernel to thread_resume.
125 *
126 * Revision 2.2 90/09/09 23:20:35 rpd
127 * Correctly return the ram size for the givem machine: 3maxen
128 * have twice as much ram as pmaxen.
129 * [90/09/09 18:59:41 af]
130 *
131 * Created.
132 * [90/08/22 af]
133 */
134 /*
135 * File: if_se_mapped.c
136 * Author: Alessandro Forin, Carnegie Mellon University
137 * Date: 8/90
138 *
139 * In-kernel side of the user-mapped ethernet driver.
140 */
141
142 #include <ln.h>
143 #if NLN > 0
144 #include <platforms.h>
145
146 #include <mach/machine/vm_types.h>
147 #include <machine/machspl.h> /* spl definitions */
148 #include <ipc/ipc_types.h>
149 #include <kern/kern_io.h>
150 #include <kern/memory.h>
151 #include <chips/lance.h>
152 #include <chips/busses.h>
153
154 #include <device/device_types.h>
155 #include <device/errno.h>
156 #include <device/io_req.h>
157 #include <device/net_status.h>
158 #include <device/net_io.h>
159 #include <device/if_hdr.h>
160 #include <device/if_ether.h>
161
162 #include <vm/vm_kern.h>
163 #include <kern/eventcount.h>
164
165 #include <machine/machspl.h>
166
167 #ifdef DECSTATION
168
169 #define machine_btop mips_btop
170
171 #define kvctophys(v) K0SEG_TO_PHYS((vm_offset_t)(v))
172 /* kernel virtual cached */
173 #define phystokvc(p) PHYS_TO_K0SEG((p)) /* and back */
174 #define kvutophys(v) K1SEG_TO_PHYS((vm_offset_t)(v))
175 /* kernel virtual uncached */
176 #define phystokvu(p) PHYS_TO_K1SEG((p)) /* and back */
177 /* remap from k2 to k0 */
178 #define kvirt(v) ((phystokvc(pmap_extract(pmap_kernel(),v))))
179
180 #include <mips/mips_cpu.h>
181 /*
182 * Wired addresses and sizes
183 */
184 #define SE0_REG_EMRG (se_reg_t)(0xb8000000)
185
186 #define REGBASE(unit) (((u_int)SE_statii[unit].registers) - se_sw->regspace)
187
188 #define SE_REG_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->regspace)
189 #define SE_REG_SIZE PAGE_SIZE
190
191 #define SE_BUF_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->bufspace)
192 #define SE_BUF_SIZE (128*1024)
193
194 #define SE_ADR_PHYS(unit) kvutophys(REGBASE(unit)+se_sw->romspace)
195 #define SE_ADR_SIZE PAGE_SIZE
196 #endif /*DECSTATION*/
197
198 #ifdef VAXSTATION
199 #define machine_btop vax_btop
200 #endif /*VAXSTATION*/
201
202 #ifdef LUNA88K
203 # define machine_btop m88k_btop
204 # define kvirt(v) (v)
205 # define kvctophys(v) pmap_extract(pmap_kernel(),(vm_offset_t)(v))
206 # define SE0_REG_EMRG ((se_reg_t)0xF1000000U)
207 # define REGBASE(unit) (((u_int)SE_statii[unit].registers) - se_sw->regspace)
208 # define SE_REG_PHYS(unit) (REGBASE(unit) + se_sw->regspace)
209 # define SE_REG_SIZE PAGE_SIZE
210 # define SE_BUF_PHYS(unit) (REGBASE(unit) + se_sw->bufspace)
211 # define SE_BUF_SIZE (64*1024)
212 # define SE_ADR_PHYS(unit) kvctophys(REGBASE(unit) + se_sw->romspace)
213 # define SE_ADR_SIZE PAGE_SIZE
214 # define wbflush() /*empty*/
215 #endif /*LUNA88K*/
216
217 /*
218 * Autoconf info
219 */
220
221 static vm_offset_t SEstd[NLN] = { 0 };
222 static struct bus_device *SEinfo[NLN];
223 void SE_attach(struct bus_device *);
224 boolean_t SE_probe(vm_offset_t, struct bus_device *);
225
226 struct bus_driver SEdriver =
227 { SE_probe, 0, SE_attach, 0, SEstd, "SE", SEinfo, };
228
229 /*
230 * Externally visible functions
231 */
232 /* int SE_probe(); */ /* Kernel */
233 void SE_intr(), SE_portdeath();
234 /* User */
235 int SE_open(), SE_close();
236 vm_offset_t SE_mmap();
237
238
239 /* forward declarations */
240
241 static void SE_stop(unsigned int unit);
242
243 /*
244 * Status information for all interfaces
245 */
246 /*static*/ struct SE_status {
247 se_reg_t registers;
248 mapped_ether_info_t info;
249 struct evc eventcounter;
250 } SE_statii[NLN];
251
252
253 /*
254 * Probe the Lance to see (if) that it's there
255 */
256 boolean_t
257 SE_probe(
258 vm_offset_t regbase,
259 register struct bus_device *ui)
260 {
261 int unit = ui->unit;
262 se_reg_t regs;
263 vm_offset_t addr;
264 mapped_ether_info_t info;
265 struct SE_status *self;
266
267
268 if (unit >= NLN)
269 return FALSE;
270
271 self = &SE_statii[unit];
272
273 printf("[mappable] ");
274
275 regs = (se_reg_t) (regbase + se_sw->regspace);
276 self->registers = regs;
277
278 /*
279 * Reset the interface
280 */
281 SE_stop(unit);
282
283 /*
284 * Grab a page to be mapped later to users
285 */
286 (void) kmem_alloc_wired(kernel_map, &addr, PAGE_SIZE);
287 /*
288 on the decstation, kmem_alloc_wired returns virtual addresses
289 in the k2 seg. Since this page is going to get mapped in
290 user space, we need to transform it to a better understood
291 virtual address. The kvirt function does this.
292 */
293 bzero((void *)addr, PAGE_SIZE);
294 info = (mapped_ether_info_t) kvirt(addr);
295 self->info = info;
296
297 /*
298 * Set permanent info
299 */
300 info->rom_stride = se_sw->romstride;
301 info->ram_stride = se_sw->ramstride;
302 info->buffer_size = se_sw->ramsize;
303 info->buffer_physaddr = se_sw->ln_bufspace;
304
305 /*
306 * Synch setup
307 */
308 evc_init(&self->eventcounter);
309 info->wait_event = self->eventcounter.ev_id;
310
311 return TRUE;
312 }
313
314 void
315 SE_attach(
316 register struct bus_device *ui)
317 {
318 }
319
320
321 /*
322 * Shut off the lance
323 */
324 static void SE_stop(unsigned int unit)
325 {
326 register se_reg_t regs = SE_statii[unit].registers;
327
328 if (regs == 0)
329 /* Stray interrupt */
330 regs = SE0_REG_EMRG;
331
332 regs[2] = CSR0_SELECT; /* XXXX rap XXXX */
333 wbflush();
334 regs[0] = LN_CSR0_STOP;
335 wbflush();
336 }
337
338
339 /*
340 * Ethernet interface interrupt routine
341 */
342 void SE_intr(
343 int unit,
344 spl_t spllevel)
345 {
346 register struct SE_status *self = &SE_statii[unit];
347 register se_reg_t regs = self->registers;
348 register csr;
349
350 if (regs == 0) { /* stray */
351 SE_stop(unit);
352 return;
353 }
354
355 /* Acknowledge interrupt request, drop spurious intr */
356 csr = regs[0];
357 if ((csr & LN_CSR0_INTR) == 0)
358 return;
359 regs[0] = csr & LN_CSR0_WTC; /* silence it */
360
361 splx(spllevel); /* drop priority now */
362
363 /* Pass csr state up to user thread */
364 if (self->info) {
365 self->info->interrupt_count++; /* total interrupts */
366 self->info->saved_csr0 = csr;
367 }
368
369 /* Awake user thread */
370 evc_signal(&self->eventcounter);
371 }
372
373
374 extern boolean_t se_use_mapped_interface[NLN];
375
376 /*
377 * Device open procedure
378 */
379 io_return_t
380 SE_open(
381 int dev,
382 int flag,
383 io_req_t ior)
384 {
385 int unit = dev;
386 register struct SE_status *self = &SE_statii[unit];
387
388 if (unit >= NLN)
389 return EINVAL;
390
391 /*
392 * Silence interface, just in case
393 */
394 SE_stop(unit);
395
396 /*
397 * Reset eventcounter
398 */
399 evc_signal(&self->eventcounter);
400
401 se_use_mapped_interface[unit] = 1;
402
403 /*
404 * Do not turn Ether interrupts on. The user can do it when ready
405 * to take them.
406 */
407
408 return 0;
409 }
410
411 /*
412 * Device close procedure
413 */
414 io_return_t SE_close(
415 int dev,
416 int flag)
417 {
418 register struct SE_status *self = &SE_statii[dev];
419
420 if (dev >= NLN)
421 return EINVAL;
422
423 /*
424 * Silence interface, in case user forgot
425 */
426 SE_stop(dev);
427 evc_signal(&self->eventcounter);
428
429 se_normal(dev);
430
431 return 0;
432 }
433
434
435 /*
436 * Get status procedure.
437 * We need to tell that we are mappable.
438 */
439 io_return_t
440 SE_get_status(
441 int dev,
442 dev_flavor_t flavor,
443 dev_status_t status, /* pointer to OUT array */
444 natural_t *status_count) /* OUT */
445 {
446 switch (flavor) {
447 case NET_STATUS:
448 {
449 register struct net_status *ns = (struct net_status *)status;
450
451 ns->min_packet_size = sizeof(struct ether_header);
452 ns->max_packet_size = sizeof(struct ether_header) + ETHERMTU;
453 ns->header_format = HDR_ETHERNET;
454 ns->header_size = sizeof(struct ether_header);
455 ns->address_size = 6;
456 ns->flags = IFF_BROADCAST;
457 ns->mapped_size = SE_BUF_SIZE + (3 * PAGE_SIZE);
458
459 *status_count = NET_STATUS_COUNT;
460 break;
461 }
462 /* case NET_ADDRESS: find it yourself */
463 default:
464 return D_INVALID_OPERATION;
465 }
466 return D_SUCCESS;
467 }
468
469 /*
470 * Should not refuse this either
471 */
472 io_return_t
473 SE_set_status(
474 int dev,
475 dev_flavor_t flavor,
476 dev_status_t status,
477 natural_t status_count)
478 {
479 return D_SUCCESS;
480 }
481
482 /*
483 * Port death notification routine
484 */
485 void SE_portdeath(int dev, ipc_port_t dead_port)
486 {
487 }
488
489
490 /*
491 * Virtual->physical mapping routine.
492 */
493 vm_offset_t
494 SE_mmap(
495 int dev,
496 vm_offset_t off,
497 vm_prot_t prot)
498 {
499 vm_offset_t addr;
500
501 /*
502 * The offset (into the VM object) defines the following layout
503 *
504 * off size what
505 * 0 1pg mapping information (csr & #interrupts)
506 * 1pg 1pg lance registers
507 * 2pg 1pg lance station address (ROM)
508 * 3pg 128k lance buffers
509 */
510 #define S0 PAGE_SIZE
511 #define S1 (S0+SE_REG_SIZE)
512 #define S2 (S1+SE_ADR_SIZE)
513 #define S3 (S2+SE_BUF_SIZE)
514
515 if (off < S0) {
516 addr = kvctophys (SE_statii[dev].info);
517 } else if (off < S1) {
518 addr = (vm_offset_t) SE_REG_PHYS(dev);
519 off -= S0;
520 } else if (off < S2) {
521 addr = (vm_offset_t) SE_ADR_PHYS(dev);
522 off -= S1;
523 } else if (off < S3) {
524 addr = (vm_offset_t) SE_BUF_PHYS(dev);
525 off -= S2;
526 } else
527 return -1;
528
529 return addr + off;
530 }
531
532 #endif /* NLN > 0 */
Cache object: 9d94628cd3db08acf7c663f00f5b0748
|