alpha_pci_io.c revision 1.1
1/* $NetBSD: alpha_pci_io.c,v 1.1 2000/02/26 18:59:36 thorpej Exp $ */ 2 3/*- 4 * Copyright (c) 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. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* 40 * Support for x86-style programmed I/O to PCI/EISA/ISA I/O space. This 41 * is currently used to provide such support for XFree86. In a perfect 42 * world, this would go away in favor of a real bus space mapping framework. 43 */ 44 45#include <sys/param.h> 46 47#include <machine/bwx.h> 48#include <machine/sysarch.h> 49#include <machine/pio.h> 50 51#include <err.h> 52#include <stdlib.h> 53 54struct alpha_bus_window *alpha_pci_io_windows; 55int alpha_pci_io_window_count; 56 57__inline struct alpha_bus_window *alpha_pci_io_findwindow __P((bus_addr_t)); 58__inline u_int32_t *alpha_pci_io_swiz __P((bus_addr_t, int)); 59 60u_int8_t alpha_pci_io_swiz_inb __P((bus_addr_t)); 61u_int16_t alpha_pci_io_swiz_inw __P((bus_addr_t)); 62u_int32_t alpha_pci_io_swiz_inl __P((bus_addr_t)); 63void alpha_pci_io_swiz_outb __P((bus_addr_t, u_int8_t)); 64void alpha_pci_io_swiz_outw __P((bus_addr_t, u_int16_t)); 65void alpha_pci_io_swiz_outl __P((bus_addr_t, u_int32_t)); 66 67const struct alpha_pci_io_ops alpha_pci_io_swiz_ops = { 68 alpha_pci_io_swiz_inb, 69 alpha_pci_io_swiz_inw, 70 alpha_pci_io_swiz_inl, 71 alpha_pci_io_swiz_outb, 72 alpha_pci_io_swiz_outw, 73 alpha_pci_io_swiz_outl, 74}; 75 76u_int8_t alpha_pci_io_bwx_inb __P((bus_addr_t)); 77u_int16_t alpha_pci_io_bwx_inw __P((bus_addr_t)); 78u_int32_t alpha_pci_io_bwx_inl __P((bus_addr_t)); 79void alpha_pci_io_bwx_outb __P((bus_addr_t, u_int8_t)); 80void alpha_pci_io_bwx_outw __P((bus_addr_t, u_int16_t)); 81void alpha_pci_io_bwx_outl __P((bus_addr_t, u_int32_t)); 82 83const struct alpha_pci_io_ops alpha_pci_io_bwx_ops = { 84 alpha_pci_io_bwx_inb, 85 alpha_pci_io_bwx_inw, 86 alpha_pci_io_bwx_inl, 87 alpha_pci_io_bwx_outb, 88 alpha_pci_io_bwx_outw, 89 alpha_pci_io_bwx_outl, 90}; 91 92const struct alpha_pci_io_ops *alpha_pci_io_switch; 93 94int 95alpha_pci_io_enable(onoff) 96 int onoff; 97{ 98 struct alpha_bus_window *abw; 99 int i, count; 100 101 if (onoff == 0 && alpha_pci_io_windows != NULL) { 102 for (i = 0; i < alpha_pci_io_window_count; i++) 103 alpha_bus_unmapwindow(&alpha_pci_io_windows[i]); 104 free(alpha_pci_io_windows); 105 alpha_pci_io_windows = NULL; 106 alpha_pci_io_window_count = 0; 107 alpha_pci_io_switch = NULL; 108 return (0); 109 } else if (onoff == 0) 110 return (0); 111 else if (alpha_pci_io_windows != NULL) 112 return (0); 113 114 count = alpha_bus_getwindows(ALPHA_BUS_TYPE_PCI_IO, &abw); 115 if (count <= 0) 116 return (-1); 117 118 for (i = 0; i < count; i++) { 119 if (alpha_bus_mapwindow(&abw[i]) == -1) { 120 free(abw); 121 return (-1); 122 } 123 } 124 125 alpha_pci_io_windows = abw; 126 alpha_pci_io_window_count = count; 127 128 if (abw->abw_abst.abst_flags & ABST_BWX) 129 alpha_pci_io_switch = &alpha_pci_io_bwx_ops; 130 else 131 alpha_pci_io_switch = &alpha_pci_io_swiz_ops; 132 133 return (0); 134} 135 136__inline struct alpha_bus_window * 137alpha_pci_io_findwindow(ioaddr) 138 bus_addr_t ioaddr; 139{ 140 struct alpha_bus_window *abw; 141 int i; 142 143 /* XXX Cache the last hit? */ 144 145 for (i = 0; i < alpha_pci_io_window_count; i++) { 146 abw = &alpha_pci_io_windows[i]; 147 if (ioaddr >= abw->abw_abst.abst_bus_start && 148 ioaddr <= abw->abw_abst.abst_bus_end) 149 return (abw); 150 } 151 152 warnx("alpha_pci_io_findwindow: no window for 0x%lx, ABORTING!", 153 (u_long) ioaddr); 154 abort(); 155} 156 157__inline u_int32_t * 158alpha_pci_io_swiz(ioaddr, size) 159 bus_addr_t ioaddr; 160 int size; 161{ 162 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 163 u_int32_t *port; 164 165 port = (u_int32_t *) (abw->abw_addr + 166 (((ioaddr - abw->abw_abst.abst_bus_start) << 167 abw->abw_abst.abst_addr_shift) | 168 (size << abw->abw_abst.abst_size_shift))); 169 170 return (port); 171} 172 173u_int8_t 174alpha_pci_io_swiz_inb(ioaddr) 175 bus_addr_t ioaddr; 176{ 177 u_int32_t *port = alpha_pci_io_swiz(ioaddr, 0); 178 int offset = ioaddr & 3; 179 180 alpha_mb(); 181 182 return ((*port >> (8 * offset)) & 0xff); 183} 184 185u_int16_t 186alpha_pci_io_swiz_inw(ioaddr) 187 bus_addr_t ioaddr; 188{ 189 u_int32_t *port = alpha_pci_io_swiz(ioaddr, 1); 190 int offset = ioaddr & 3; 191 192 alpha_mb(); 193 194 return ((*port >> (8 * offset)) & 0xffff); 195} 196 197u_int32_t 198alpha_pci_io_swiz_inl(ioaddr) 199 bus_addr_t ioaddr; 200{ 201 u_int32_t *port = alpha_pci_io_swiz(ioaddr, 3); 202 203 alpha_mb(); 204 205 return (*port); 206} 207 208void 209alpha_pci_io_swiz_outb(ioaddr, val) 210 bus_addr_t ioaddr; 211 u_int8_t val; 212{ 213 u_int32_t *port = alpha_pci_io_swiz(ioaddr, 0); 214 int offset = ioaddr & 3; 215 u_int32_t nval = val << (8 * offset); 216 217 *port = nval; 218 alpha_mb(); 219} 220 221void 222alpha_pci_io_swiz_outw(ioaddr, val) 223 bus_addr_t ioaddr; 224 u_int16_t val; 225{ 226 u_int32_t *port = alpha_pci_io_swiz(ioaddr, 1); 227 int offset = ioaddr & 3; 228 u_int32_t nval = val << (8 * offset); 229 230 *port = nval; 231 alpha_mb(); 232} 233 234void 235alpha_pci_io_swiz_outl(ioaddr, val) 236 bus_addr_t ioaddr; 237 u_int32_t val; 238{ 239 u_int32_t *port = alpha_pci_io_swiz(ioaddr, 3); 240 241 *port = val; 242 alpha_mb(); 243} 244 245/* 246 * The following functions are used only on EV56 and greater CPUs, 247 * and the assembler requires going to EV56 mode in order to emit 248 * these instructions. 249 */ 250__asm(".arch ev56"); 251 252u_int8_t 253alpha_pci_io_bwx_inb(ioaddr) 254 bus_addr_t ioaddr; 255{ 256 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 257 u_int8_t *port = (u_int8_t *) (abw->abw_addr + 258 (ioaddr - abw->abw_abst.abst_bus_start)); 259 260 alpha_mb(); 261 262 return (alpha_ldbu(port)); 263} 264 265u_int16_t 266alpha_pci_io_bwx_inw(ioaddr) 267 bus_addr_t ioaddr; 268{ 269 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 270 u_int16_t *port = (u_int16_t *) (abw->abw_addr + 271 (ioaddr - abw->abw_abst.abst_bus_start)); 272 273 alpha_mb(); 274 275 return (alpha_ldwu(port)); 276} 277 278u_int32_t 279alpha_pci_io_bwx_inl(ioaddr) 280 bus_addr_t ioaddr; 281{ 282 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 283 u_int32_t *port = (u_int32_t *) (abw->abw_addr + 284 (ioaddr - abw->abw_abst.abst_bus_start)); 285 286 alpha_mb(); 287 288 return (*port); 289} 290 291void 292alpha_pci_io_bwx_outb(ioaddr, val) 293 bus_addr_t ioaddr; 294 u_int8_t val; 295{ 296 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 297 u_int8_t *port = (u_int8_t *) (abw->abw_addr + 298 (ioaddr - abw->abw_abst.abst_bus_start)); 299 300 alpha_stb(port, val); 301 alpha_mb(); 302} 303 304void 305alpha_pci_io_bwx_outw(ioaddr, val) 306 bus_addr_t ioaddr; 307 u_int16_t val; 308{ 309 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 310 u_int16_t *port = (u_int16_t *) (abw->abw_addr + 311 (ioaddr - abw->abw_abst.abst_bus_start)); 312 313 alpha_stw(port, val); 314 alpha_mb(); 315} 316 317void 318alpha_pci_io_bwx_outl(ioaddr, val) 319 bus_addr_t ioaddr; 320 u_int32_t val; 321{ 322 struct alpha_bus_window *abw = alpha_pci_io_findwindow(ioaddr); 323 u_int32_t *port = (u_int32_t *) (abw->abw_addr + 324 (ioaddr - abw->abw_abst.abst_bus_start)); 325 326 *port = val; 327 alpha_mb(); 328} 329