1/* $NetBSD: pci_bwx_bus_io_chipdep.c,v 1.24 2023/12/06 01:46:34 thorpej Exp $ */
2
3/*-
4 * Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * 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 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/*
34 * Copyright (c) 1995, 1996 Carnegie-Mellon University.
35 * All rights reserved.
36 *
37 * Author: Chris G. Demetriou
38 *
39 * Permission to use, copy, modify and distribute this software and
40 * its documentation is hereby granted, provided that both the copyright
41 * notice and this permission notice appear in all copies of the
42 * software, derivative works or modified versions, and any portions
43 * thereof, and that both notices appear in supporting documentation.
44 *
45 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
46 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
47 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 *
49 * Carnegie Mellon requests users of this software to return to
50 *
51 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
52 *  School of Computer Science
53 *  Carnegie Mellon University
54 *  Pittsburgh PA 15213-3890
55 *
56 * any improvements or extensions that they make and grant Carnegie the
57 * rights to redistribute these changes.
58 */
59
60/*
61 * Common PCI Chipset "bus I/O" functions, for chipsets which have to
62 * deal with only a single PCI interface chip in a machine.
63 *
64 * uses:
65 *	CHIP		name of the 'chip' it's being compiled for.
66 *	CHIP_IO_BASE	I/O space base to use.
67 *	CHIP_IO_ARENA_STORE
68 *			If defined, device-provided static storage area
69 *			for the I/O space arena.  If this is defined,
70 *			CHIP_IO_BTAG_STORE and CHIP_IO_BTAG_COUNT must
71 *			also be defined.  If this is not defined, a
72 *			static area will be declared.
73 *	CHIP_IO_BTAG_STORE
74 *			Device-provided static storage area for the
75 *			I/O space arena's boundary tags.  Ignored
76 *			unless CHIP_IO_ARENA_STORE is defined.
77 *	CHIP_IO_BTAG_COUNT
78 *			The number of device-provided static I/O
79 *			space boundary tags.  Ignored unless
80 *			CHIP_IO_ARENA_STORE is defined.
81 */
82
83#include <sys/cdefs.h>
84__KERNEL_RCSID(1, "$NetBSD: pci_bwx_bus_io_chipdep.c,v 1.24 2023/12/06 01:46:34 thorpej Exp $");
85
86#include <sys/vmem_impl.h>
87
88#include <machine/bwx.h>
89
90#define	__C(A,B)	__CONCAT(A,B)
91#define	__S(S)		__STRING(S)
92
93/* mapping/unmapping */
94static int	__C(CHIP,_io_map)(void *, bus_addr_t, bus_size_t, int,
95		    bus_space_handle_t *, int);
96static void	__C(CHIP,_io_unmap)(void *, bus_space_handle_t,
97		    bus_size_t, int);
98static int	__C(CHIP,_io_subregion)(void *, bus_space_handle_t,
99		    bus_size_t, bus_size_t, bus_space_handle_t *);
100
101static int	__C(CHIP,_io_translate)(void *, bus_addr_t, bus_size_t,
102		    int, struct alpha_bus_space_translation *);
103static int	__C(CHIP,_io_get_window)(void *, int,
104		    struct alpha_bus_space_translation *);
105
106/* allocation/deallocation */
107static int	__C(CHIP,_io_alloc)(void *, bus_addr_t, bus_addr_t,
108		    bus_size_t, bus_size_t, bus_addr_t, int, bus_addr_t *,
109	            bus_space_handle_t *);
110static void	__C(CHIP,_io_free)(void *, bus_space_handle_t,
111		    bus_size_t);
112
113/* get kernel virtual address */
114static void *	__C(CHIP,_io_vaddr)(void *, bus_space_handle_t);
115
116/* mmap for user */
117static paddr_t	__C(CHIP,_io_mmap)(void *, bus_addr_t, off_t, int, int);
118
119/* barrier */
120static inline void __C(CHIP,_io_barrier)(void *, bus_space_handle_t,
121		    bus_size_t, bus_size_t, int);
122
123/* read (single) */
124static inline uint8_t __C(CHIP,_io_read_1)(void *, bus_space_handle_t,
125		    bus_size_t);
126static inline uint16_t __C(CHIP,_io_read_2)(void *, bus_space_handle_t,
127		    bus_size_t);
128static inline uint32_t __C(CHIP,_io_read_4)(void *, bus_space_handle_t,
129		    bus_size_t);
130static inline uint64_t __C(CHIP,_io_read_8)(void *, bus_space_handle_t,
131		    bus_size_t);
132
133/* read multiple */
134static void	__C(CHIP,_io_read_multi_1)(void *, bus_space_handle_t,
135		    bus_size_t, uint8_t *, bus_size_t);
136static void	__C(CHIP,_io_read_multi_2)(void *, bus_space_handle_t,
137		    bus_size_t, uint16_t *, bus_size_t);
138static void	__C(CHIP,_io_read_multi_4)(void *, bus_space_handle_t,
139		    bus_size_t, uint32_t *, bus_size_t);
140static void	__C(CHIP,_io_read_multi_8)(void *, bus_space_handle_t,
141		    bus_size_t, uint64_t *, bus_size_t);
142
143/* read region */
144static void	__C(CHIP,_io_read_region_1)(void *, bus_space_handle_t,
145		    bus_size_t, uint8_t *, bus_size_t);
146static void	__C(CHIP,_io_read_region_2)(void *, bus_space_handle_t,
147		    bus_size_t, uint16_t *, bus_size_t);
148static void	__C(CHIP,_io_read_region_4)(void *, bus_space_handle_t,
149		    bus_size_t, uint32_t *, bus_size_t);
150static void	__C(CHIP,_io_read_region_8)(void *, bus_space_handle_t,
151		    bus_size_t, uint64_t *, bus_size_t);
152
153/* write (single) */
154static inline void __C(CHIP,_io_write_1)(void *, bus_space_handle_t,
155		    bus_size_t, uint8_t);
156static inline void __C(CHIP,_io_write_2)(void *, bus_space_handle_t,
157		    bus_size_t, uint16_t);
158static inline void __C(CHIP,_io_write_4)(void *, bus_space_handle_t,
159		    bus_size_t, uint32_t);
160static inline void __C(CHIP,_io_write_8)(void *, bus_space_handle_t,
161		    bus_size_t, uint64_t);
162
163/* write multiple */
164static void	__C(CHIP,_io_write_multi_1)(void *, bus_space_handle_t,
165		    bus_size_t, const uint8_t *, bus_size_t);
166static void	__C(CHIP,_io_write_multi_2)(void *, bus_space_handle_t,
167		    bus_size_t, const uint16_t *, bus_size_t);
168static void	__C(CHIP,_io_write_multi_4)(void *, bus_space_handle_t,
169		    bus_size_t, const uint32_t *, bus_size_t);
170static void	__C(CHIP,_io_write_multi_8)(void *, bus_space_handle_t,
171		    bus_size_t, const uint64_t *, bus_size_t);
172
173/* write region */
174static void	__C(CHIP,_io_write_region_1)(void *, bus_space_handle_t,
175		    bus_size_t, const uint8_t *, bus_size_t);
176static void	__C(CHIP,_io_write_region_2)(void *, bus_space_handle_t,
177		    bus_size_t, const uint16_t *, bus_size_t);
178static void	__C(CHIP,_io_write_region_4)(void *, bus_space_handle_t,
179		    bus_size_t, const uint32_t *, bus_size_t);
180static void	__C(CHIP,_io_write_region_8)(void *, bus_space_handle_t,
181		    bus_size_t, const uint64_t *, bus_size_t);
182
183/* set multiple */
184static void	__C(CHIP,_io_set_multi_1)(void *, bus_space_handle_t,
185		    bus_size_t, uint8_t, bus_size_t);
186static void	__C(CHIP,_io_set_multi_2)(void *, bus_space_handle_t,
187		    bus_size_t, uint16_t, bus_size_t);
188static void	__C(CHIP,_io_set_multi_4)(void *, bus_space_handle_t,
189		    bus_size_t, uint32_t, bus_size_t);
190static void	__C(CHIP,_io_set_multi_8)(void *, bus_space_handle_t,
191		    bus_size_t, uint64_t, bus_size_t);
192
193/* set region */
194static void	__C(CHIP,_io_set_region_1)(void *, bus_space_handle_t,
195		    bus_size_t, uint8_t, bus_size_t);
196static void	__C(CHIP,_io_set_region_2)(void *, bus_space_handle_t,
197		    bus_size_t, uint16_t, bus_size_t);
198static void	__C(CHIP,_io_set_region_4)(void *, bus_space_handle_t,
199		    bus_size_t, uint32_t, bus_size_t);
200static void	__C(CHIP,_io_set_region_8)(void *, bus_space_handle_t,
201		    bus_size_t, uint64_t, bus_size_t);
202
203/* copy */
204static void	__C(CHIP,_io_copy_region_1)(void *, bus_space_handle_t,
205		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
206static void	__C(CHIP,_io_copy_region_2)(void *, bus_space_handle_t,
207		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
208static void	__C(CHIP,_io_copy_region_4)(void *, bus_space_handle_t,
209		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
210static void	__C(CHIP,_io_copy_region_8)(void *, bus_space_handle_t,
211		    bus_size_t, bus_space_handle_t, bus_size_t, bus_size_t);
212
213#ifndef CHIP_IO_ARENA_STORE
214#define	CHIP_IO_BTAG_COUNT(v)	VMEM_EST_BTCOUNT(1, 8)
215#define	CHIP_IO_BTAG_STORE(v)	__C(CHIP,_io_btag_store)
216#define	CHIP_IO_ARENA_STORE(v)	(&(__C(CHIP,_io_arena_store)))
217
218static struct vmem __C(CHIP,_io_arena_store);
219static struct vmem_btag __C(CHIP,_io_btag_store)[CHIP_IO_BTAG_COUNT(xxx)];
220#endif /* CHIP_IO_ARENA_STORE */
221
222void
223__C(CHIP,_bus_io_init)(
224	bus_space_tag_t t,
225	void *v)
226{
227	vmem_t *vm;
228	int error __diagused;
229
230	/*
231	 * Initialize the bus space tag.
232	 */
233
234	/* cookie */
235	t->abs_cookie =		v;
236
237	/* mapping/unmapping */
238	t->abs_map =		__C(CHIP,_io_map);
239	t->abs_unmap =		__C(CHIP,_io_unmap);
240	t->abs_subregion =	__C(CHIP,_io_subregion);
241
242	t->abs_translate =	__C(CHIP,_io_translate);
243	t->abs_get_window =	__C(CHIP,_io_get_window);
244
245	/* allocation/deallocation */
246	t->abs_alloc =		__C(CHIP,_io_alloc);
247	t->abs_free = 		__C(CHIP,_io_free);
248
249	/* get kernel virtual address */
250	t->abs_vaddr =		__C(CHIP,_io_vaddr);
251
252	/* mmap for user */
253	t->abs_mmap =		__C(CHIP,_io_mmap);
254
255	/* barrier */
256	t->abs_barrier =	__C(CHIP,_io_barrier);
257
258	/* read (single) */
259	t->abs_r_1 =		__C(CHIP,_io_read_1);
260	t->abs_r_2 =		__C(CHIP,_io_read_2);
261	t->abs_r_4 =		__C(CHIP,_io_read_4);
262	t->abs_r_8 =		__C(CHIP,_io_read_8);
263
264	/* read multiple */
265	t->abs_rm_1 =		__C(CHIP,_io_read_multi_1);
266	t->abs_rm_2 =		__C(CHIP,_io_read_multi_2);
267	t->abs_rm_4 =		__C(CHIP,_io_read_multi_4);
268	t->abs_rm_8 =		__C(CHIP,_io_read_multi_8);
269
270	/* read region */
271	t->abs_rr_1 =		__C(CHIP,_io_read_region_1);
272	t->abs_rr_2 =		__C(CHIP,_io_read_region_2);
273	t->abs_rr_4 =		__C(CHIP,_io_read_region_4);
274	t->abs_rr_8 =		__C(CHIP,_io_read_region_8);
275
276	/* write (single) */
277	t->abs_w_1 =		__C(CHIP,_io_write_1);
278	t->abs_w_2 =		__C(CHIP,_io_write_2);
279	t->abs_w_4 =		__C(CHIP,_io_write_4);
280	t->abs_w_8 =		__C(CHIP,_io_write_8);
281
282	/* write multiple */
283	t->abs_wm_1 =		__C(CHIP,_io_write_multi_1);
284	t->abs_wm_2 =		__C(CHIP,_io_write_multi_2);
285	t->abs_wm_4 =		__C(CHIP,_io_write_multi_4);
286	t->abs_wm_8 =		__C(CHIP,_io_write_multi_8);
287
288	/* write region */
289	t->abs_wr_1 =		__C(CHIP,_io_write_region_1);
290	t->abs_wr_2 =		__C(CHIP,_io_write_region_2);
291	t->abs_wr_4 =		__C(CHIP,_io_write_region_4);
292	t->abs_wr_8 =		__C(CHIP,_io_write_region_8);
293
294	/* set multiple */
295	t->abs_sm_1 =		__C(CHIP,_io_set_multi_1);
296	t->abs_sm_2 =		__C(CHIP,_io_set_multi_2);
297	t->abs_sm_4 =		__C(CHIP,_io_set_multi_4);
298	t->abs_sm_8 =		__C(CHIP,_io_set_multi_8);
299
300	/* set region */
301	t->abs_sr_1 =		__C(CHIP,_io_set_region_1);
302	t->abs_sr_2 =		__C(CHIP,_io_set_region_2);
303	t->abs_sr_4 =		__C(CHIP,_io_set_region_4);
304	t->abs_sr_8 =		__C(CHIP,_io_set_region_8);
305
306	/* copy */
307	t->abs_c_1 =		__C(CHIP,_io_copy_region_1);
308	t->abs_c_2 =		__C(CHIP,_io_copy_region_2);
309	t->abs_c_4 =		__C(CHIP,_io_copy_region_4);
310	t->abs_c_8 =		__C(CHIP,_io_copy_region_8);
311
312	vm = vmem_init(CHIP_IO_ARENA_STORE(v),
313		       __S(__C(CHIP,_bus_io)),		/* name */
314		       0,				/* addr */
315		       0,				/* size */
316		       1,				/* quantum */
317		       NULL,				/* importfn */
318		       NULL,				/* releasefn */
319		       NULL,				/* source */
320		       0,				/* qcache_max */
321		       VM_NOSLEEP | VM_PRIVTAGS,
322		       IPL_NONE);
323	KASSERT(vm != NULL);
324
325	vmem_add_bts(vm, CHIP_IO_BTAG_STORE(v), CHIP_IO_BTAG_COUNT(v));
326	error = vmem_add(vm, 0, 0x100000000UL, VM_NOSLEEP);
327	KASSERT(error == 0);
328
329	CHIP_IO_ARENA(v) = vm;
330}
331
332static int
333__C(CHIP,_io_translate)(
334	void *v,
335	bus_addr_t ioaddr,
336	bus_size_t iolen,
337	int flags,
338	struct alpha_bus_space_translation *abst)
339{
340	int linear = flags & BUS_SPACE_MAP_LINEAR;
341
342	/*
343	 * Can't map i/o space linearly.
344	 */
345	if (linear)
346		return (EOPNOTSUPP);
347
348	return (__C(CHIP,_io_get_window)(v, 0, abst));
349}
350
351static int
352__C(CHIP,_io_get_window)(
353	void *v,
354	int window,
355	struct alpha_bus_space_translation *abst)
356{
357
358	switch (window) {
359	case 0:
360		abst->abst_bus_start = 0;
361		abst->abst_bus_end = 0xffffffffUL;
362		abst->abst_sys_start = CHIP_IO_SYS_START(v);
363		abst->abst_sys_end = CHIP_IO_SYS_START(v) + abst->abst_bus_end;
364		abst->abst_addr_shift = 0;
365		abst->abst_size_shift = 0;
366		abst->abst_flags = ABST_DENSE|ABST_BWX;
367		break;
368
369	default:
370		panic(__S(__C(CHIP,_io_get_window)) ": invalid window %d",
371		    window);
372	}
373
374	return (0);
375}
376
377static int
378__C(CHIP,_io_map)(
379	void *v,
380	bus_addr_t ioaddr,
381	bus_size_t iosize,
382	int flags,
383	bus_space_handle_t *iohp,
384	int acct)
385{
386	struct alpha_bus_space_translation abst;
387	int error;
388
389	/*
390	 * Get the translation for this address.
391	 */
392	error = __C(CHIP,_io_translate)(v, ioaddr, iosize, flags, &abst);
393	if (error)
394		return (error);
395
396	if (acct == 0)
397		goto mapit;
398
399#ifdef EXTENT_DEBUG
400	printf("io: allocating 0x%lx to 0x%lx\n", ioaddr, ioaddr + iosize - 1);
401#endif
402	error = vmem_xalloc_addr(CHIP_IO_ARENA(v), ioaddr, iosize, VM_NOSLEEP);
403	if (error) {
404#ifdef EXTENT_DEBUG
405		printf("io: allocation failed (%d)\n", error);
406		/* vmem_print(CHIP_IO_ARENA(v));	XXX */
407#endif
408		return (error);
409	}
410
411 mapit:
412	*iohp = ALPHA_PHYS_TO_K0SEG(abst.abst_sys_start + ioaddr);
413
414	return (0);
415}
416
417static void
418__C(CHIP,_io_unmap)(
419	void *v,
420	bus_space_handle_t ioh,
421	bus_size_t iosize,
422	int acct)
423{
424	bus_addr_t ioaddr;
425
426	if (acct == 0)
427		return;
428
429#ifdef EXTENT_DEBUG
430	printf("io: freeing handle 0x%lx for 0x%lx\n", ioh, iosize);
431#endif
432
433	ioaddr = ioh - ALPHA_PHYS_TO_K0SEG(CHIP_IO_SYS_START(v));
434
435#ifdef EXTENT_DEBUG
436	printf("io: freeing 0x%lx to 0x%lx\n", ioaddr, ioaddr + iosize - 1);
437#endif
438	vmem_xfree(CHIP_IO_ARENA(v), ioaddr, iosize);
439}
440
441static int
442__C(CHIP,_io_subregion)(
443	void *v,
444	bus_space_handle_t ioh,
445	bus_size_t offset,
446	bus_size_t size,
447	bus_space_handle_t *nioh)
448{
449
450	*nioh = ioh + offset;
451	return (0);
452}
453
454static int
455__C(CHIP,_io_alloc)(
456	void *v,
457	bus_addr_t rstart,
458	bus_addr_t rend,
459	bus_size_t size,
460	bus_size_t align,
461	bus_size_t boundary,
462	int flags,
463	bus_addr_t *addrp,
464	bus_space_handle_t *bshp)
465{
466	struct alpha_bus_space_translation abst;
467	int linear = flags & BUS_SPACE_MAP_LINEAR;
468	vmem_addr_t ioaddr;
469	int error;
470
471	/*
472	 * Can't map i/o space linearly.
473	 */
474	if (linear)
475		return (EOPNOTSUPP);
476
477	/*
478	 * Do the requested allocation.
479	 */
480#ifdef EXTENT_DEBUG
481	printf("io: allocating from 0x%lx to 0x%lx\n", rstart, rend);
482#endif
483	error = vmem_xalloc(CHIP_IO_ARENA(v), size,
484			    align,		/* align */
485			    0,			/* phase */
486			    boundary,		/* nocross */
487			    rstart,		/* minaddr */
488			    rend,		/* maxaddr */
489			    VM_BESTFIT | VM_NOSLEEP,
490			    &ioaddr);
491	if (error) {
492#ifdef EXTENT_DEBUG
493		printf("io: allocation failed (%d)\n", error);
494		/* vmem_print(CHIP_IO_ARENA(v));	XXX */
495#endif
496		return (error);
497	}
498
499#ifdef EXTENT_DEBUG
500	printf("io: allocated 0x%lx to 0x%lx\n", ioaddr, ioaddr + size - 1);
501#endif
502
503	error = __C(CHIP,_io_translate)(v, ioaddr, size, flags, &abst);
504	if (error) {
505		vmem_xfree(CHIP_IO_ARENA(v), ioaddr, size);
506		return (error);
507	}
508
509	*addrp = ioaddr;
510	*bshp = ALPHA_PHYS_TO_K0SEG(abst.abst_sys_start + ioaddr);
511
512	return (0);
513}
514
515static void
516__C(CHIP,_io_free)(
517	void *v,
518	bus_space_handle_t bsh,
519	bus_size_t size)
520{
521
522	/* Unmap does all we need to do. */
523	__C(CHIP,_io_unmap)(v, bsh, size, 1);
524}
525
526static void *
527__C(CHIP,_io_vaddr)(
528	void *v,
529	bus_space_handle_t bsh)
530{
531	/*
532	 * _io_translate() catches BUS_SPACE_MAP_LINEAR,
533	 * so we shouldn't get here
534	 */
535	panic("_io_vaddr");
536}
537
538static paddr_t
539__C(CHIP,_io_mmap)(
540	void *v,
541	bus_addr_t addr,
542	off_t off,
543	int prot,
544	int flags)
545{
546
547	/* Not supported for I/O space. */
548	return (-1);
549}
550
551static inline void
552__C(CHIP,_io_barrier)(
553	void *v,
554	bus_space_handle_t h,
555	bus_size_t o,
556	bus_size_t l,
557	int f)
558{
559
560	if ((f & BUS_SPACE_BARRIER_READ) != 0)
561		alpha_mb();
562	else if ((f & BUS_SPACE_BARRIER_WRITE) != 0)
563		alpha_wmb();
564}
565
566static inline uint8_t
567__C(CHIP,_io_read_1)(
568	void *v,
569	bus_space_handle_t ioh,
570	bus_size_t off)
571{
572	bus_addr_t addr;
573
574	addr = ioh + off;
575	alpha_mb();
576	return (alpha_ldbu((uint8_t *)addr));
577}
578
579static inline uint16_t
580__C(CHIP,_io_read_2)(
581	void *v,
582	bus_space_handle_t ioh,
583	bus_size_t off)
584{
585	bus_addr_t addr;
586
587	addr = ioh + off;
588#ifdef DIAGNOSTIC
589	if (addr & 1)
590		panic(__S(__C(CHIP,_io_read_2)) ": addr 0x%lx not aligned",
591		    addr);
592#endif
593	alpha_mb();
594	return (alpha_ldwu((uint16_t *)addr));
595}
596
597static inline uint32_t
598__C(CHIP,_io_read_4)(
599	void *v,
600	bus_space_handle_t ioh,
601	bus_size_t off)
602{
603	bus_addr_t addr;
604
605	addr = ioh + off;
606#ifdef DIAGNOSTIC
607	if (addr & 3)
608		panic(__S(__C(CHIP,_io_read_4)) ": addr 0x%lx not aligned",
609		    addr);
610#endif
611	alpha_mb();
612	return (*(uint32_t *)addr);
613}
614
615static inline uint64_t
616__C(CHIP,_io_read_8)(
617	void *v,
618	bus_space_handle_t ioh,
619	bus_size_t off)
620{
621
622	/* XXX XXX XXX */
623	panic("%s not implemented", __S(__C(CHIP,_io_read_8)));
624}
625
626#define CHIP_io_read_multi_N(BYTES,TYPE)				\
627static void								\
628__C(__C(CHIP,_io_read_multi_),BYTES)(					\
629	void *v,							\
630	bus_space_handle_t h,						\
631	bus_size_t o,							\
632	TYPE *a,							\
633	bus_size_t c)							\
634{									\
635									\
636	while (c-- > 0) {						\
637		__C(CHIP,_io_barrier)(v, h, o, sizeof *a,		\
638		    BUS_SPACE_BARRIER_READ);				\
639		*a++ = __C(__C(CHIP,_io_read_),BYTES)(v, h, o);		\
640	}								\
641}
642CHIP_io_read_multi_N(1,uint8_t)
643CHIP_io_read_multi_N(2,uint16_t)
644CHIP_io_read_multi_N(4,uint32_t)
645CHIP_io_read_multi_N(8,uint64_t)
646
647#define CHIP_io_read_region_N(BYTES,TYPE)				\
648static void								\
649__C(__C(CHIP,_io_read_region_),BYTES)(					\
650	void *v,							\
651	bus_space_handle_t h,						\
652	bus_size_t o,							\
653	TYPE *a,							\
654	bus_size_t c)							\
655{									\
656									\
657	while (c-- > 0) {						\
658		*a++ = __C(__C(CHIP,_io_read_),BYTES)(v, h, o);		\
659		o += sizeof *a;						\
660	}								\
661}
662CHIP_io_read_region_N(1,uint8_t)
663CHIP_io_read_region_N(2,uint16_t)
664CHIP_io_read_region_N(4,uint32_t)
665CHIP_io_read_region_N(8,uint64_t)
666
667static inline void
668__C(CHIP,_io_write_1)(
669	void *v,
670	bus_space_handle_t ioh,
671	bus_size_t off,
672	uint8_t val)
673{
674	bus_addr_t addr;
675
676	addr = ioh + off;
677	alpha_stb((uint8_t *)addr, val);
678	alpha_mb();
679}
680
681static inline void
682__C(CHIP,_io_write_2)(
683	void *v,
684	bus_space_handle_t ioh,
685	bus_size_t off,
686	uint16_t val)
687{
688	bus_addr_t addr;
689
690	addr = ioh + off;
691#ifdef DIAGNOSTIC
692	if (addr & 1)
693		panic(__S(__C(CHIP,_io_write_2)) ": addr 0x%lx not aligned",
694		    addr);
695#endif
696	alpha_stw((uint16_t *)addr, val);
697	alpha_mb();
698}
699
700static inline void
701__C(CHIP,_io_write_4)(
702	void *v,
703	bus_space_handle_t ioh,
704	bus_size_t off,
705	uint32_t val)
706{
707	bus_addr_t addr;
708
709	addr = ioh + off;
710#ifdef DIAGNOSTIC
711	if (addr & 3)
712		panic(__S(__C(CHIP,_io_write_4)) ": addr 0x%lx not aligned",
713		    addr);
714#endif
715	*(uint32_t *)addr = val;
716	alpha_mb();
717}
718
719static inline void
720__C(CHIP,_io_write_8)(
721	void *v,
722	bus_space_handle_t ioh,
723	bus_size_t off,
724	uint64_t val)
725{
726
727	/* XXX XXX XXX */
728	panic("%s not implemented", __S(__C(CHIP,_io_write_8)));
729	alpha_mb();
730}
731
732#define CHIP_io_write_multi_N(BYTES,TYPE)				\
733static void								\
734__C(__C(CHIP,_io_write_multi_),BYTES)(					\
735	void *v,							\
736	bus_space_handle_t h,						\
737	bus_size_t o,							\
738	const TYPE *a,							\
739	bus_size_t c)							\
740{									\
741									\
742	while (c-- > 0) {						\
743		__C(__C(CHIP,_io_write_),BYTES)(v, h, o, *a++);		\
744		__C(CHIP,_io_barrier)(v, h, o, sizeof *a,		\
745		    BUS_SPACE_BARRIER_WRITE);				\
746	}								\
747}
748CHIP_io_write_multi_N(1,uint8_t)
749CHIP_io_write_multi_N(2,uint16_t)
750CHIP_io_write_multi_N(4,uint32_t)
751CHIP_io_write_multi_N(8,uint64_t)
752
753#define CHIP_io_write_region_N(BYTES,TYPE)				\
754static void								\
755__C(__C(CHIP,_io_write_region_),BYTES)(					\
756	void *v,							\
757	bus_space_handle_t h,						\
758	bus_size_t o,							\
759	const TYPE *a,							\
760	bus_size_t c)							\
761{									\
762									\
763	while (c-- > 0) {						\
764		__C(__C(CHIP,_io_write_),BYTES)(v, h, o, *a++);		\
765		o += sizeof *a;						\
766	}								\
767}
768CHIP_io_write_region_N(1,uint8_t)
769CHIP_io_write_region_N(2,uint16_t)
770CHIP_io_write_region_N(4,uint32_t)
771CHIP_io_write_region_N(8,uint64_t)
772
773#define CHIP_io_set_multi_N(BYTES,TYPE)					\
774static void								\
775__C(__C(CHIP,_io_set_multi_),BYTES)(					\
776	void *v,							\
777	bus_space_handle_t h,						\
778	bus_size_t o,							\
779	TYPE val,							\
780	bus_size_t c)							\
781{									\
782									\
783	while (c-- > 0) {						\
784		__C(__C(CHIP,_io_write_),BYTES)(v, h, o, val);		\
785		__C(CHIP,_io_barrier)(v, h, o, sizeof val,		\
786		    BUS_SPACE_BARRIER_WRITE);				\
787	}								\
788}
789CHIP_io_set_multi_N(1,uint8_t)
790CHIP_io_set_multi_N(2,uint16_t)
791CHIP_io_set_multi_N(4,uint32_t)
792CHIP_io_set_multi_N(8,uint64_t)
793
794#define CHIP_io_set_region_N(BYTES,TYPE)				\
795static void								\
796__C(__C(CHIP,_io_set_region_),BYTES)(					\
797	void *v,							\
798	bus_space_handle_t h,						\
799	bus_size_t o,							\
800	TYPE val,							\
801	bus_size_t c)							\
802{									\
803									\
804	while (c-- > 0) {						\
805		__C(__C(CHIP,_io_write_),BYTES)(v, h, o, val);		\
806		o += sizeof val;					\
807	}								\
808}
809CHIP_io_set_region_N(1,uint8_t)
810CHIP_io_set_region_N(2,uint16_t)
811CHIP_io_set_region_N(4,uint32_t)
812CHIP_io_set_region_N(8,uint64_t)
813
814#define	CHIP_io_copy_region_N(BYTES)					\
815static void								\
816__C(__C(CHIP,_io_copy_region_),BYTES)(					\
817	void *v,							\
818	bus_space_handle_t h1,						\
819	bus_size_t o1,							\
820	bus_space_handle_t h2,						\
821	bus_size_t o2,							\
822	bus_size_t c)							\
823{									\
824	bus_size_t o;							\
825									\
826	if ((h1 + o1) >= (h2 + o2)) {					\
827		/* src after dest: copy forward */			\
828		for (o = 0; c != 0; c--, o += BYTES) {			\
829			__C(__C(CHIP,_io_write_),BYTES)(v, h2, o2 + o,	\
830			    __C(__C(CHIP,_io_read_),BYTES)(v, h1, o1 + o)); \
831		}							\
832	} else {							\
833		/* dest after src: copy backwards */			\
834		for (o = (c - 1) * BYTES; c != 0; c--, o -= BYTES) {	\
835			__C(__C(CHIP,_io_write_),BYTES)(v, h2, o2 + o,	\
836			    __C(__C(CHIP,_io_read_),BYTES)(v, h1, o1 + o)); \
837		}							\
838	}								\
839}
840CHIP_io_copy_region_N(1)
841CHIP_io_copy_region_N(2)
842CHIP_io_copy_region_N(4)
843CHIP_io_copy_region_N(8)
844