Home | History | Annotate | Line # | Download | only in isa
isa_machdep.c revision 1.1
      1 /*	$NetBSD: isa_machdep.c,v 1.1 2002/10/12 11:53:38 chris Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1996-1998 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Mark Brinicombe, Charles M. Hannum and by Jason R. Thorpe of the
      9  * Numerical Aerospace Simulation Facility, NASA Ames Research Center.
     10  *
     11  * Redistribution and use in source and binary forms, with or without
     12  * modification, are permitted provided that the following conditions
     13  * are met:
     14  * 1. Redistributions of source code must retain the above copyright
     15  *    notice, this list of conditions and the following disclaimer.
     16  * 2. Redistributions in binary form must reproduce the above copyright
     17  *    notice, this list of conditions and the following disclaimer in the
     18  *    documentation and/or other materials provided with the distribution.
     19  * 3. All advertising materials mentioning features or use of this software
     20  *    must display the following acknowledgement:
     21  *	This product includes software developed by the NetBSD
     22  *	Foundation, Inc. and its contributors.
     23  * 4. Neither the name of The NetBSD Foundation nor the names of its
     24  *    contributors may be used to endorse or promote products derived
     25  *    from this software without specific prior written permission.
     26  *
     27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     37  * POSSIBILITY OF SUCH DAMAGE.
     38  */
     39 
     40 /*-
     41  * Copyright (c) 1991 The Regents of the University of California.
     42  * All rights reserved.
     43  *
     44  * This code is derived from software contributed to Berkeley by
     45  * William Jolitz.
     46  *
     47  * Redistribution and use in source and binary forms, with or without
     48  * modification, are permitted provided that the following conditions
     49  * are met:
     50  * 1. Redistributions of source code must retain the above copyright
     51  *    notice, this list of conditions and the following disclaimer.
     52  * 2. Redistributions in binary form must reproduce the above copyright
     53  *    notice, this list of conditions and the following disclaimer in the
     54  *    documentation and/or other materials provided with the distribution.
     55  * 3. All advertising materials mentioning features or use of this software
     56  *    must display the following acknowledgement:
     57  *	This product includes software developed by the University of
     58  *	California, Berkeley and its contributors.
     59  * 4. Neither the name of the University nor the names of its contributors
     60  *    may be used to endorse or promote products derived from this software
     61  *    without specific prior written permission.
     62  *
     63  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     64  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     65  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     66  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     67  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     68  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     69  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     70  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     71  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     72  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     73  * SUCH DAMAGE.
     74  *
     75  *	@(#)isa.c	7.2 (Berkeley) 5/13/91
     76  */
     77 
     78 #include "opt_irqstats.h"
     79 
     80 #include <sys/param.h>
     81 #include <sys/systm.h>
     82 #include <sys/kernel.h>
     83 #include <sys/syslog.h>
     84 #include <sys/device.h>
     85 #include <sys/malloc.h>
     86 #include <sys/proc.h>
     87 
     88 #define _ARM32_BUS_DMA_PRIVATE
     89 #include <machine/bus.h>
     90 
     91 #include <machine/intr.h>
     92 #include <machine/pio.h>
     93 #include <machine/bootconfig.h>
     94 #include <machine/isa_machdep.h>
     95 
     96 #include <dev/isa/isareg.h>
     97 #include <dev/isa/isavar.h>
     98 #include <dev/isa/isadmareg.h>
     99 #include <dev/isa/isadmavar.h>
    100 #include <arm/footbridge/isa/icu.h>
    101 #include <arm/footbridge/dc21285reg.h>
    102 #include <arm/footbridge/dc21285mem.h>
    103 
    104 #include <uvm/uvm_extern.h>
    105 
    106 #include "isadma.h"
    107 
    108 /* prototypes */
    109 static void isa_icu_init __P((void));
    110 
    111 struct arm32_isa_chipset isa_chipset_tag;
    112 
    113 void isa_strayintr __P((int));
    114 void intr_calculatemasks __P((void));
    115 int fakeintr __P((void *));
    116 
    117 int isa_irqdispatch __P((void *arg));
    118 
    119 u_int imask[IPL_LEVELS];
    120 unsigned imen;
    121 
    122 #ifdef IRQSTATS
    123 u_int isa_intr_count[ICU_LEN];
    124 #endif	/* IRQSTATS */
    125 
    126 #define AUTO_EOI_1
    127 #define AUTO_EOI_2
    128 
    129 /*
    130  * Fill in default interrupt table (in case of spuruious interrupt
    131  * during configuration of kernel, setup interrupt control unit
    132  */
    133 static void
    134 isa_icu_init(void)
    135 {
    136 	/* initialize 8259's */
    137 	outb(IO_ICU1, 0x11);		/* reset; program device, four bytes */
    138 	outb(IO_ICU1+1, ICU_OFFSET);	/* starting at this vector index */
    139 	outb(IO_ICU1+1, 1 << IRQ_SLAVE);	/* slave on line 2 */
    140 #ifdef AUTO_EOI_1
    141 	outb(IO_ICU1+1, 2 | 1);		/* auto EOI, 8086 mode */
    142 #else
    143 	outb(IO_ICU1+1, 1);			/* 8086 mode */
    144 #endif
    145 	outb(IO_ICU1+1, 0xff);		/* leave interrupts masked */
    146 	outb(IO_ICU1, 0x68);		/* special mask mode (if available) */
    147 	outb(IO_ICU1, 0x0a);		/* Read IRR by default. */
    148 #ifdef REORDER_IRQ
    149 	outb(IO_ICU1, 0xc0 | (3 - 1));	/* pri order 3-7, 0-2 (com2 first) */
    150 #endif
    151 
    152 	outb(IO_ICU2, 0x11);		/* reset; program device, four bytes */
    153 	outb(IO_ICU2+1, ICU_OFFSET+8);	/* staring at this vector index */
    154 	outb(IO_ICU2+1, IRQ_SLAVE);
    155 #ifdef AUTO_EOI_2
    156 	outb(IO_ICU2+1, 2 | 1);		/* auto EOI, 8086 mode */
    157 #else
    158 	outb(IO_ICU2+1, 1);			/* 8086 mode */
    159 #endif
    160 	outb(IO_ICU2+1, 0xff);		/* leave interrupts masked */
    161 	outb(IO_ICU2, 0x68);		/* special mask mode (if available) */
    162 	outb(IO_ICU2, 0x0a);		/* Read IRR by default. */
    163 }
    164 
    165 /*
    166  * Caught a stray interrupt, notify
    167  */
    168 void
    169 isa_strayintr(irq)
    170 	int irq;
    171 {
    172 	static u_long strays;
    173 
    174         /*
    175          * Stray interrupts on irq 7 occur when an interrupt line is raised
    176          * and then lowered before the CPU acknowledges it.  This generally
    177          * means either the device is screwed or something is cli'ing too
    178          * long and it's timing out.
    179          */
    180 	if (++strays <= 5)
    181 		log(LOG_ERR, "stray interrupt %d%s\n", irq,
    182 		    strays >= 5 ? "; stopped logging" : "");
    183 }
    184 
    185 int intrtype[ICU_LEN], intrmask[ICU_LEN], intrlevel[ICU_LEN];
    186 struct irqhandler *intrhand[ICU_LEN];
    187 
    188 /*
    189  * Recalculate the interrupt masks from scratch.
    190  * We could code special registry and deregistry versions of this function that
    191  * would be faster, but the code would be nastier, and we don't expect this to
    192  * happen very much anyway.
    193  */
    194 void
    195 intr_calculatemasks()
    196 {
    197 	int irq, level;
    198 	struct irqhandler *q;
    199 
    200 	/* First, figure out which levels each IRQ uses. */
    201 	for (irq = 0; irq < ICU_LEN; irq++) {
    202 		int levels = 0;
    203 		for (q = intrhand[irq]; q; q = q->ih_next)
    204 			levels |= 1 << q->ih_level;
    205 		intrlevel[irq] = levels;
    206 	}
    207 
    208 	/* Then figure out which IRQs use each level. */
    209 	for (level = 0; level < IPL_LEVELS; level++) {
    210 		int irqs = 0;
    211 		for (irq = 0; irq < ICU_LEN; irq++)
    212 			if (intrlevel[irq] & (1 << level))
    213 				irqs |= 1 << irq;
    214 		imask[level] = irqs;
    215 	}
    216 
    217 	/*
    218 	 * IPL_NONE is used for hardware interrupts that are never blocked,
    219 	 * and do not block anything else.
    220 	 */
    221 	imask[IPL_NONE] = 0;
    222 
    223 	/*
    224 	 * Enforce a hierarchy that gives slow devices a better chance at not
    225 	 * dropping data.
    226 	 */
    227 	imask[IPL_BIO] |= imask[IPL_NONE];
    228 	imask[IPL_NET] |= imask[IPL_BIO];
    229 	imask[IPL_TTY] |= imask[IPL_NET];
    230 	/*
    231 	 * There are tty, network and disk drivers that use free() at interrupt
    232 	 * time, so imp > (tty | net | bio).
    233 	 */
    234 	imask[IPL_IMP] |= imask[IPL_TTY];
    235 	imask[IPL_AUDIO] |= imask[IPL_IMP];
    236 
    237 	/*
    238 	 * Since run queues may be manipulated by both the statclock and tty,
    239 	 * network, and disk drivers, clock > imp.
    240 	 */
    241 	imask[IPL_CLOCK] |= imask[IPL_AUDIO];
    242 	imask[IPL_CLOCK] |= imask[IPL_IMP];
    243 
    244 	/*
    245 	 * IPL_HIGH must block everything that can manipulate a run queue.
    246 	 */
    247 	imask[IPL_HIGH] |= imask[IPL_CLOCK];
    248 
    249 	/*
    250 	 * We need serial drivers to run at the absolute highest priority to
    251 	 * avoid overruns, so serial > high.
    252 	 */
    253 	imask[IPL_SERIAL] |= imask[IPL_HIGH];
    254 
    255 	/* And eventually calculate the complete masks. */
    256 	for (irq = 0; irq < ICU_LEN; irq++) {
    257 		int irqs = 1 << irq;
    258 		for (q = intrhand[irq]; q; q = q->ih_next)
    259 			irqs |= imask[q->ih_level];
    260 		intrmask[irq] = irqs;
    261 	}
    262 
    263 	/* Lastly, determine which IRQs are actually in use. */
    264 	{
    265 		int irqs = 0;
    266 		for (irq = 0; irq < ICU_LEN; irq++)
    267 			if (intrhand[irq])
    268 				irqs |= 1 << irq;
    269 		if (irqs >= 0x100) /* any IRQs >= 8 in use */
    270 			irqs |= 1 << IRQ_SLAVE;
    271 		imen = ~irqs;
    272 		SET_ICUS();
    273 	}
    274 #if 0
    275 	printf("type\tmask\tlevel\thand\n");
    276 	for (irq = 0; irq < ICU_LEN; irq++) {
    277 		printf("%x\t%04x\t%x\t%p\n", intrtype[irq], intrmask[irq],
    278 		intrlevel[irq], intrhand[irq]);
    279 	}
    280 	for (level = 0; level < IPL_LEVELS; ++level)
    281 		printf("%d: %08x\n", level, imask[level]);
    282 #endif
    283 }
    284 
    285 int
    286 fakeintr(arg)
    287 	void *arg;
    288 {
    289 
    290 	return 0;
    291 }
    292 
    293 #define	LEGAL_IRQ(x)	((x) >= 0 && (x) < ICU_LEN && (x) != 2)
    294 
    295 int
    296 isa_intr_alloc(ic, mask, type, irq)
    297 	isa_chipset_tag_t ic;
    298 	int mask;
    299 	int type;
    300 	int *irq;
    301 {
    302 	int i, tmp, bestirq, count;
    303 	struct irqhandler **p, *q;
    304 
    305 	if (type == IST_NONE)
    306 		panic("intr_alloc: bogus type");
    307 
    308 	bestirq = -1;
    309 	count = -1;
    310 
    311 	/* some interrupts should never be dynamically allocated */
    312 	mask &= 0xdef8;
    313 
    314 	/*
    315 	 * XXX some interrupts will be used later (6 for fdc, 12 for pms).
    316 	 * the right answer is to do "breadth-first" searching of devices.
    317 	 */
    318 	mask &= 0xefbf;
    319 
    320 	for (i = 0; i < ICU_LEN; i++) {
    321 		if (LEGAL_IRQ(i) == 0 || (mask & (1<<i)) == 0)
    322 			continue;
    323 
    324 		switch(intrtype[i]) {
    325 		case IST_NONE:
    326 			/*
    327 			 * if nothing's using the irq, just return it
    328 			 */
    329 			*irq = i;
    330 			return (0);
    331 
    332 		case IST_EDGE:
    333 		case IST_LEVEL:
    334 			if (type != intrtype[i])
    335 				continue;
    336 			/*
    337 			 * if the irq is shareable, count the number of other
    338 			 * handlers, and if it's smaller than the last irq like
    339 			 * this, remember it
    340 			 *
    341 			 * XXX We should probably also consider the
    342 			 * interrupt level and stick IPL_TTY with other
    343 			 * IPL_TTY, etc.
    344 			 */
    345 			for (p = &intrhand[i], tmp = 0; (q = *p) != NULL;
    346 			     p = &q->ih_next, tmp++)
    347 				;
    348 			if ((bestirq == -1) || (count > tmp)) {
    349 				bestirq = i;
    350 				count = tmp;
    351 			}
    352 			break;
    353 
    354 		case IST_PULSE:
    355 			/* this just isn't shareable */
    356 			continue;
    357 		}
    358 	}
    359 
    360 	if (bestirq == -1)
    361 		return (1);
    362 
    363 	*irq = bestirq;
    364 
    365 	return (0);
    366 }
    367 
    368 const struct evcnt *
    369 isa_intr_evcnt(isa_chipset_tag_t ic, int irq)
    370 {
    371 
    372 	/* XXX for now, no evcnt parent reported */
    373 	return NULL;
    374 }
    375 
    376 /*
    377  * Set up an interrupt handler to start being called.
    378  * XXX PRONE TO RACE CONDITIONS, UGLY, 'INTERESTING' INSERTION ALGORITHM.
    379  */
    380 void *
    381 isa_intr_establish(ic, irq, type, level, ih_fun, ih_arg)
    382 	isa_chipset_tag_t ic;
    383 	int irq;
    384 	int type;
    385 	int level;
    386 	int (*ih_fun) __P((void *));
    387 	void *ih_arg;
    388 {
    389 	struct irqhandler **p, *q, *ih;
    390 	static struct irqhandler fakehand = {fakeintr};
    391 
    392 /*	printf("isa_intr_establish(%d, %d, %d)\n", irq, type, level);*/
    393 
    394 	/* no point in sleeping unless someone can free memory. */
    395 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
    396 	if (ih == NULL)
    397 		panic("isa_intr_establish: can't malloc handler info");
    398 
    399 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
    400 		panic("intr_establish: bogus irq or type");
    401 
    402 	switch (intrtype[irq]) {
    403 	case IST_NONE:
    404 		intrtype[irq] = type;
    405 /*		printf("Setting irq %d to type %d - ", irq, type);*/
    406 		if (irq < 8) {
    407 			outb(0x4d0, (inb(0x4d0) & ~(1 << irq))
    408 			    | ((type == IST_LEVEL) ? (1 << irq) : 0));
    409 /*			printf("%02x\n", inb(0x4d0));*/
    410 		} else {
    411 			outb(0x4d1, (inb(0x4d1) & ~(1 << irq))
    412 			    | ((type == IST_LEVEL) ? (1 << irq) : 0));
    413 /*			printf("%02x\n", inb(0x4d1));*/
    414 		}
    415 		break;
    416 	case IST_EDGE:
    417 	case IST_LEVEL:
    418 		if (type == intrtype[irq])
    419 			break;
    420 	case IST_PULSE:
    421 		if (type != IST_NONE)
    422 			panic("intr_establish: can't share %s with %s",
    423 			    isa_intr_typename(intrtype[irq]),
    424 			    isa_intr_typename(type));
    425 		break;
    426 	}
    427 
    428 	/*
    429 	 * Figure out where to put the handler.
    430 	 * This is O(N^2), but we want to preserve the order, and N is
    431 	 * generally small.
    432 	 */
    433 	for (p = &intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
    434 		;
    435 
    436 	/*
    437 	 * Actually install a fake handler momentarily, since we might be doing
    438 	 * this with interrupts enabled and don't want the real routine called
    439 	 * until masking is set up.
    440 	 */
    441 	fakehand.ih_level = level;
    442 	*p = &fakehand;
    443 
    444 	intr_calculatemasks();
    445 
    446 	/*
    447 	 * Poke the real handler in now.
    448 	 */
    449 	ih->ih_func = ih_fun;
    450 	ih->ih_arg = ih_arg;
    451 /*	ih->ih_count = 0;*/
    452 	ih->ih_next = NULL;
    453 	ih->ih_level = level;
    454 	ih->ih_num = irq;
    455 	*p = ih;
    456 
    457 	return (ih);
    458 }
    459 
    460 /*
    461  * Deregister an interrupt handler.
    462  */
    463 void
    464 isa_intr_disestablish(ic, arg)
    465 	isa_chipset_tag_t ic;
    466 	void *arg;
    467 {
    468 	struct irqhandler *ih = arg;
    469 	int irq = ih->ih_num;
    470 	struct irqhandler **p, *q;
    471 
    472 	if (!LEGAL_IRQ(irq))
    473 		panic("intr_disestablish: bogus irq");
    474 
    475 	/*
    476 	 * Remove the handler from the chain.
    477 	 * This is O(n^2), too.
    478 	 */
    479 	for (p = &intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
    480 		;
    481 	if (q)
    482 		*p = q->ih_next;
    483 	else
    484 		panic("intr_disestablish: handler not registered");
    485 	free(ih, M_DEVBUF);
    486 
    487 	intr_calculatemasks();
    488 
    489 	if (intrhand[irq] == NULL)
    490 		intrtype[irq] = IST_NONE;
    491 }
    492 
    493 /*
    494  * isa_intr_init()
    495  *
    496  * Initialise the ISA ICU and attach an ISA interrupt handler to the
    497  * ISA interrupt line on the footbridge.
    498  */
    499 void
    500 isa_intr_init(void)
    501 {
    502 	static void *isa_ih;
    503 
    504 	isa_icu_init();
    505 	/* something break the build in an informative way */
    506 #ifndef ISA_FOOTBRIDGE_IRQ
    507 #warning Before using isa with footbridge you must define ISA_FOOTBRIDGE_IRQ
    508 #endif
    509 	isa_ih = intr_claim(ISA_FOOTBRIDGE_IRQ, IPL_BIO, "isabus",
    510 	    isa_irqdispatch, NULL);
    511 
    512 }
    513 
    514 /* Static array of ISA DMA segments. We only have one on CATS */
    515 #if NISADMA > 0
    516 struct arm32_dma_range machdep_isa_dma_ranges[1];
    517 #endif
    518 
    519 void
    520 isa_footbridge_init(iobase, membase)
    521 	u_int iobase, membase;
    522 {
    523 #if NISADMA > 0
    524 	extern struct arm32_dma_range *footbridge_isa_dma_ranges;
    525 	extern int footbridge_isa_dma_nranges;
    526 
    527 	machdep_isa_dma_ranges[0].dr_sysbase = bootconfig.dram[0].address;
    528 	machdep_isa_dma_ranges[0].dr_busbase = bootconfig.dram[0].address;
    529 	machdep_isa_dma_ranges[0].dr_len = (16 * 1024 * 1024);
    530 
    531 	footbridge_isa_dma_ranges = machdep_isa_dma_ranges;
    532 	footbridge_isa_dma_nranges = 1;
    533 #endif
    534 
    535 	isa_io_init(iobase, membase);
    536 }
    537 
    538 void
    539 isa_attach_hook(parent, self, iba)
    540 	struct device *parent, *self;
    541 	struct isabus_attach_args *iba;
    542 {
    543 	/*
    544 	 * Since we can only have one ISA bus, we just use a single
    545 	 * statically allocated ISA chipset structure.  Pass it up
    546 	 * now.
    547 	 */
    548 	iba->iba_ic = &isa_chipset_tag;
    549 #if NISADMA > 0
    550 	isa_dma_init();
    551 #endif
    552 }
    553 
    554 int
    555 isa_irqdispatch(arg)
    556 	void *arg;
    557 {
    558 	int irq;
    559 	struct irqhandler *p;
    560 	u_int iack;
    561 	int res;
    562 
    563 	iack = *((u_int *)(DC21285_PCI_IACK_VBASE));
    564 	iack &= 0xff;
    565 	if (iack < 0x20 || iack > 0x2f) {
    566 		printf("isa_irqdispatch: %x\n", iack);
    567 		return(0);
    568 	}
    569 
    570 	irq = iack & 0x0f;
    571 #ifdef IRQSTATS
    572 	++isa_intr_count[irq];
    573 #endif	/* IRQSTATS */
    574 	p = intrhand[irq];
    575 	while (p) {
    576 #ifdef IRQSTATS
    577 /*		++p->ih_count;*/
    578 #endif	/* IRQSTATS */
    579 		res = p->ih_func(p->ih_arg);
    580 		p = p->ih_next;
    581 	}
    582 	return(0);
    583 }
    584 
    585 
    586 void
    587 isa_fillw(val, addr, len)
    588 	u_int val;
    589 	void *addr;
    590 	size_t len;
    591 {
    592 	if ((u_int)addr >= isa_mem_data_vaddr()
    593 	    && (u_int)addr < isa_mem_data_vaddr() + 0x100000) {
    594 		bus_size_t offset = ((u_int)addr) & 0xfffff;
    595 		bus_space_set_region_2(&isa_mem_bs_tag,
    596 		    (bus_space_handle_t)isa_mem_bs_tag.bs_cookie, offset,
    597 		    val, len);
    598 	} else {
    599 		u_short *ptr = addr;
    600 
    601 		while (len > 0) {
    602 			*ptr++ = val;
    603 			--len;
    604 		}
    605 	}
    606 }
    607