pci_mace.c revision 1.5
1/* $NetBSD: pci_mace.c,v 1.5 2004/09/29 04:06:52 sekiya Exp $ */ 2 3/* 4 * Copyright (c) 2001,2003 Christopher Sekiya 5 * Copyright (c) 2000 Soren S. Jorvang 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed for the 19 * NetBSD Project. See http://www.NetBSD.org/ for 20 * information about NetBSD. 21 * 4. The name of the author may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36#include <sys/cdefs.h> 37__KERNEL_RCSID(0, "$NetBSD: pci_mace.c,v 1.5 2004/09/29 04:06:52 sekiya Exp $"); 38 39#include <sys/param.h> 40#include <sys/device.h> 41#include <sys/systm.h> 42 43#include <machine/cpu.h> 44#include <machine/locore.h> 45#include <machine/autoconf.h> 46#include <machine/vmparam.h> 47#include <machine/bus.h> 48#include <machine/machtype.h> 49 50#include <dev/pci/pcivar.h> 51#include <dev/pci/pcireg.h> 52#include <dev/pci/pcidevs.h> 53 54#include <sgimips/mace/macereg.h> 55#include <sgimips/mace/macevar.h> 56 57#include <sgimips/mace/pcireg_mace.h> 58#include <sgimips/pci/pci_addr_fixup.h> 59 60#define PCIBIOS_PRINTV(arg) \ 61 do { \ 62 printf arg; \ 63 } while (0) 64#define PCIBIOS_PRINTVN(n, arg) \ 65 do { \ 66 printf arg; \ 67 } while (0) 68 69 70#define PAGE_ALIGN(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) 71#define MEG_ALIGN(x) (((x) + 0x100000 - 1) & ~(0x100000 - 1)) 72 73#include "pci.h" 74 75struct macepci_softc { 76 struct device sc_dev; 77 78 struct sgimips_pci_chipset sc_pc; 79}; 80 81static int macepci_match(struct device *, struct cfdata *, void *); 82static void macepci_attach(struct device *, struct device *, void *); 83pcireg_t macepci_conf_read(pci_chipset_tag_t, pcitag_t, int); 84void macepci_conf_write(pci_chipset_tag_t, pcitag_t, int, pcireg_t); 85int macepci_intr(void *); 86 87struct pciaddr pciaddr; 88 89bus_addr_t pciaddr_ioaddr(u_int32_t val); 90 91int pciaddr_do_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag, int mapreg, void *ctx, int type, bus_addr_t *addr, bus_size_t size); 92 93unsigned int ioaddr_base = 0x1000; 94unsigned int memaddr_base = 0x80100000; 95 96CFATTACH_DECL(macepci, sizeof(struct macepci_softc), 97 macepci_match, macepci_attach, NULL, NULL); 98 99static int 100macepci_match(struct device *parent, struct cfdata *match, void *aux) 101{ 102 103 return (1); 104} 105 106static void 107macepci_attach(struct device *parent, struct device *self, void *aux) 108{ 109 struct macepci_softc *sc = (struct macepci_softc *)self; 110 pci_chipset_tag_t pc = &sc->sc_pc; 111 struct mace_attach_args *maa = aux; 112 struct pcibus_attach_args pba; 113 u_int32_t control; 114 pcitag_t devtag; 115 int device, rev; 116 117 if (bus_space_subregion(maa->maa_st, maa->maa_sh, 118 maa->maa_offset, 0, &pc->ioh) ) 119 panic("macepci_attach: couldn't map"); 120 121 pc->iot = maa->maa_st; 122 123 rev = bus_space_read_4(pc->iot, pc->ioh, MACEPCI_REVISION); 124 printf(": rev %d\n", rev); 125 126 pc->pc_conf_read = macepci_conf_read; 127 pc->pc_conf_write = macepci_conf_write; 128 pc->intr_establish = mace_intr_establish; 129 pc->intr_disestablish = mace_intr_disestablish; 130 131 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_ERROR_ADDR, 0); 132 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_ERROR_FLAGS, 0); 133 134 /* Turn on PCI error interrupts */ 135 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONTROL, 136 MACE_PCI_CONTROL_SERR_ENA | 137 MACE_PCI_CONTROL_PARITY_ERR | 138 MACE_PCI_CONTROL_PARK_LIU | 139 MACE_PCI_CONTROL_OVERRUN_INT | 140 MACE_PCI_CONTROL_PARITY_INT | 141 MACE_PCI_CONTROL_SERR_INT | 142 MACE_PCI_CONTROL_IT_INT | 143 MACE_PCI_CONTROL_RE_INT | 144 MACE_PCI_CONTROL_DPED_INT | 145 MACE_PCI_CONTROL_TAR_INT | 146 MACE_PCI_CONTROL_MAR_INT); 147 148 /* Must fix up all PCI devices, ahc_pci expects proper i/o mapping */ 149 for (device = 1; device < 4; device++) { 150 const struct pci_quirkdata *qd; 151 int function, nfuncs; 152 pcireg_t bhlcr, id; 153 154 devtag = pci_make_tag(pc, 0, device, 0); 155 id = pci_conf_read(pc, devtag, PCI_ID_REG); 156 157 /* Invalid vendor ID value? */ 158 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 159 continue; 160 /* XXX Not invalid, but we've done this ~forever. */ 161 if (PCI_VENDOR(id) == 0) 162 continue; 163 164 qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); 165 bhlcr = pci_conf_read(pc, devtag, PCI_BHLC_REG); 166 167 if (PCI_HDRTYPE_MULTIFN(bhlcr) || 168 (qd != NULL && 169 (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0)) 170 nfuncs = 8; 171 else 172 nfuncs = 1; 173 174 for (function = 0; function < nfuncs; function++) { 175 devtag = pci_make_tag(pc, 0, device, function); 176 id = pci_conf_read(pc, devtag, PCI_ID_REG); 177 178 /* Invalid vendor ID value? */ 179 if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) 180 continue; 181 /* Not invalid, but we've done this ~forever */ 182 if (PCI_VENDOR(id) == 0) 183 continue; 184 185 pciaddr_resource_manage(pc, devtag, NULL, NULL); 186 } 187 } 188 189 /* 190 * Enable all MACE PCI interrupts. They will be masked by 191 * the CRIME code. 192 */ 193 control = bus_space_read_4(pc->iot, pc->ioh, MACEPCI_CONTROL); 194 control |= CONTROL_INT_MASK; 195 bus_space_write_4(pc->iot, pc->ioh, MACEPCI_CONTROL, control); 196 197#if NPCI > 0 198 memset(&pba, 0, sizeof pba); 199/*XXX*/ pba.pba_iot = SGIMIPS_BUS_SPACE_IO; 200/*XXX*/ pba.pba_memt = SGIMIPS_BUS_SPACE_MEM; 201 pba.pba_dmat = &pci_bus_dma_tag; 202 pba.pba_dmat64 = NULL; 203 pba.pba_bus = 0; 204 pba.pba_bridgetag = NULL; 205 pba.pba_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED | 206 PCI_FLAGS_MRL_OKAY | PCI_FLAGS_MRM_OKAY | PCI_FLAGS_MWI_OKAY; 207 pba.pba_pc = pc; 208 209#ifdef MACEPCI_IO_WAS_BUGGY 210 if (rev == 0) 211 pba.pba_flags &= ~PCI_FLAGS_IO_ENABLED; /* Buggy? */ 212#endif 213 214 cpu_intr_establish(maa->maa_intr, IPL_NONE, macepci_intr, sc); 215 216 config_found_ia(self, "pcibus", &pba, pcibusprint); 217#endif 218} 219 220pcireg_t 221macepci_conf_read(pci_chipset_tag_t pc, pcitag_t tag, int reg) 222{ 223 pcireg_t data; 224 225 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, (tag | reg)); 226 data = bus_space_read_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_DATA); 227 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, 0); 228 229 return data; 230} 231 232void 233macepci_conf_write(pci_chipset_tag_t pc, pcitag_t tag, int reg, pcireg_t data) 234{ 235 /* XXX O2 soren */ 236 if (tag == 0) 237 return; 238 239 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, (tag | reg)); 240 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_DATA, data); 241 bus_space_write_4(pc->iot, pc->ioh, MACE_PCI_CONFIG_ADDR, 0); 242} 243 244 245/* 246 * Handle PCI error interrupts. 247 */ 248int 249macepci_intr(void *arg) 250{ 251 struct macepci_softc *sc = (struct macepci_softc *)arg; 252 pci_chipset_tag_t pc = &sc->sc_pc; 253 u_int32_t error, address; 254 255 error = bus_space_read_4(pc->iot, pc->ioh, MACE_PCI_ERROR_FLAGS); 256 address = bus_space_read_4(pc->iot, pc->ioh, MACE_PCI_ERROR_ADDR); 257 while (error & 0xffc00000) { 258 if (error & MACE_PERR_MASTER_ABORT) { 259 /* 260 * this seems to be a more-or-less normal error 261 * condition (e.g., "pcictl pci0 list" generates 262 * a _lot_ of these errors, so no message for now 263 * while I figure out if I missed a trick somewhere. 264 */ 265 error &= ~MACE_PERR_MASTER_ABORT; 266 bus_space_write_4(pc->iot, pc->ioh, 267 MACE_PCI_ERROR_FLAGS, error); 268 } 269 270 if (error & MACE_PERR_TARGET_ABORT) { 271 printf("mace: target abort at %x\n", address); 272 error &= ~MACE_PERR_TARGET_ABORT; 273 bus_space_write_4(pc->iot, pc->ioh, 274 MACE_PCI_ERROR_FLAGS, error); 275 } 276 277 if (error & MACE_PERR_DATA_PARITY_ERR) { 278 printf("mace: parity error at %x\n", address); 279 error &= ~MACE_PERR_DATA_PARITY_ERR; 280 bus_space_write_4(pc->iot, pc->ioh, 281 MACE_PCI_ERROR_FLAGS, error); 282 } 283 284 if (error & MACE_PERR_RETRY_ERR) { 285 printf("mace: retry error at %x\n", address); 286 error &= ~MACE_PERR_RETRY_ERR; 287 bus_space_write_4(pc->iot, pc->ioh, 288 MACE_PCI_ERROR_FLAGS, error); 289 } 290 291 if (error & MACE_PERR_ILLEGAL_CMD) { 292 printf("mace: illegal command at %x\n", address); 293 error &= ~MACE_PERR_ILLEGAL_CMD; 294 bus_space_write_4(pc->iot, pc->ioh, 295 MACE_PCI_ERROR_FLAGS, error); 296 } 297 298 if (error & MACE_PERR_SYSTEM_ERR) { 299 printf("mace: system error at %x\n", address); 300 error &= ~MACE_PERR_SYSTEM_ERR; 301 bus_space_write_4(pc->iot, pc->ioh, 302 MACE_PCI_ERROR_FLAGS, error); 303 } 304 305 if (error & MACE_PERR_INTERRUPT_TEST) { 306 printf("mace: interrupt test at %x\n", address); 307 error &= ~MACE_PERR_INTERRUPT_TEST; 308 bus_space_write_4(pc->iot, pc->ioh, 309 MACE_PCI_ERROR_FLAGS, error); 310 } 311 312 if (error & MACE_PERR_PARITY_ERR) { 313 printf("mace: parity error at %x\n", address); 314 error &= ~MACE_PERR_PARITY_ERR; 315 bus_space_write_4(pc->iot, pc->ioh, 316 MACE_PCI_ERROR_FLAGS, error); 317 } 318 319 if (error & MACE_PERR_RSVD) { 320 printf("mace: reserved condition at %x\n", address); 321 error &= ~MACE_PERR_RSVD; 322 bus_space_write_4(pc->iot, pc->ioh, 323 MACE_PCI_ERROR_FLAGS, error); 324 } 325 326 if (error & MACE_PERR_OVERRUN) { 327 printf("mace: overrun at %x\n", address); 328 error &= ~MACE_PERR_OVERRUN; 329 bus_space_write_4(pc->iot, pc->ioh, 330 MACE_PCI_ERROR_FLAGS, error); 331 } 332 } 333 return 0; 334} 335 336/* PCI Address fixup routines */ 337 338void 339pciaddr_resource_manage(pci_chipset_tag_t pc, pcitag_t tag, 340 pciaddr_resource_manage_func_t func, void *ctx) 341{ 342 pcireg_t val, mask; 343 bus_addr_t addr; 344 bus_size_t size; 345 int error, mapreg, type, reg_start, reg_end, width; 346 347 val = macepci_conf_read(pc, tag, PCI_BHLC_REG); 348 switch (PCI_HDRTYPE_TYPE(val)) { 349 default: 350 printf("WARNING: unknown PCI device header."); 351 pciaddr.nbogus++; 352 return; 353 case 0: 354 reg_start = PCI_MAPREG_START; 355 reg_end = PCI_MAPREG_END; 356 break; 357 case 1: /* PCI-PCI bridge */ 358 reg_start = PCI_MAPREG_START; 359 reg_end = PCI_MAPREG_PPB_END; 360 break; 361 case 2: /* PCI-CardBus bridge */ 362 reg_start = PCI_MAPREG_START; 363 reg_end = PCI_MAPREG_PCB_END; 364 break; 365 } 366 error = 0; 367 368 for (mapreg = reg_start; mapreg < reg_end; mapreg += width) { 369 /* inquire PCI device bus space requirement */ 370 val = macepci_conf_read(pc, tag, mapreg); 371 macepci_conf_write(pc, tag, mapreg, ~0); 372 373 mask = macepci_conf_read(pc, tag, mapreg); 374 macepci_conf_write(pc, tag, mapreg, val); 375 376 type = PCI_MAPREG_TYPE(val); 377 width = 4; 378 379 if (type == PCI_MAPREG_TYPE_MEM) { 380 size = PCI_MAPREG_MEM_SIZE(mask); 381 382 /* 383 * XXXrkb: for MEM64 BARs, to be totally kosher 384 * about the requested size, need to read mask 385 * from top 32bits of BAR and stir that into the 386 * size calculation, like so: 387 * 388 * case PCI_MAPREG_MEM_TYPE_64BIT: 389 * bar64 = pci_conf_read(pb->pc, tag, br + 4); 390 * pci_conf_write(pb->pc, tag, br + 4, 0xffffffff); 391 * mask64 = pci_conf_read(pb->pc, tag, br + 4); 392 * pci_conf_write(pb->pc, tag, br + 4, bar64); 393 * size = (u_int64_t) PCI_MAPREG_MEM64_SIZE( 394 * (((u_int64_t) mask64) << 32) | mask); 395 * width = 8; 396 * 397 * Fortunately, anything with all-zeros mask in the 398 * lower 32-bits will have size no less than 1 << 32, 399 * which we're not prepared to deal with, so I don't 400 * feel bad punting on it... 401 */ 402 if (PCI_MAPREG_MEM_TYPE(val) == 403 PCI_MAPREG_MEM_TYPE_64BIT) { 404 /* 405 * XXX We could examine the upper 32 bits 406 * XXX of the BAR here, but we are totally 407 * XXX unprepared to handle a non-zero value, 408 * XXX either here or anywhere else in the 409 * XXX sgimips code (not sure about MI code). 410 * XXX 411 * XXX So just arrange to skip the top 32 412 * XXX bits of the BAR and zero then out 413 * XXX if the BAR is in use. 414 */ 415 width = 8; 416 417 if (size != 0) 418 macepci_conf_write(pc, tag, 419 mapreg + 4, 0); 420 } 421 } else { 422 /* 423 * Upper 16 bits must be one. Devices may hardwire 424 * them to zero, though, per PCI 2.2, 6.2.5.1, p 203. 425 */ 426 mask |= 0xffff0000; 427 size = PCI_MAPREG_IO_SIZE(mask); 428 } 429 430 if (size == 0) /* unused register */ 431 continue; 432 433 addr = pciaddr_ioaddr(val); 434 435 /* reservation/allocation phase */ 436 error += pciaddr_do_resource_allocate(pc, tag, mapreg, 437 ctx, type, &addr, size); 438 439#if 0 440 PCIBIOS_PRINTV(("\n\t%02xh %s 0x%08x 0x%08x", 441 mapreg, type ? "port" : "mem ", 442 (unsigned int)addr, (unsigned int)size)); 443#endif 444 } 445 446 /* enable/disable PCI device */ 447 val = macepci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); 448 449 if (error == 0) 450 val |= (PCI_COMMAND_IO_ENABLE | 451 PCI_COMMAND_MEM_ENABLE | 452 PCI_COMMAND_MASTER_ENABLE | 453 PCI_COMMAND_SPECIAL_ENABLE | 454 PCI_COMMAND_INVALIDATE_ENABLE | 455 PCI_COMMAND_PARITY_ENABLE); 456 else 457 val &= ~(PCI_COMMAND_IO_ENABLE | 458 PCI_COMMAND_MEM_ENABLE | 459 PCI_COMMAND_MASTER_ENABLE); 460 461 macepci_conf_write(pc, tag, PCI_COMMAND_STATUS_REG, val); 462 463 if (error) 464 pciaddr.nbogus++; 465} 466 467bus_addr_t 468pciaddr_ioaddr(u_int32_t val) 469{ 470 471 return ((PCI_MAPREG_TYPE(val) == PCI_MAPREG_TYPE_MEM) ? 472 PCI_MAPREG_MEM_ADDR(val) : PCI_MAPREG_IO_ADDR(val)); 473} 474 475int 476pciaddr_do_resource_allocate(pci_chipset_tag_t pc, pcitag_t tag, int mapreg, 477 void *ctx, int type, bus_addr_t *addr, bus_size_t size) 478{ 479 480 switch (type) { 481 case PCI_MAPREG_TYPE_IO: 482 *addr = ioaddr_base; 483 ioaddr_base += PAGE_ALIGN(size); 484 break; 485 486 case PCI_MAPREG_TYPE_MEM: 487 *addr = memaddr_base; 488 memaddr_base += MEG_ALIGN(size); 489 break; 490 491 default: 492 PCIBIOS_PRINTV(("attempt to remap unknown region (addr 0x%lx, " 493 "size 0x%lx, type %d)\n", *addr, size, type)); 494 return 0; 495 } 496 497 498 /* write new address to PCI device configuration header */ 499 macepci_conf_write(pc, tag, mapreg, *addr); 500 501 /* check */ 502#ifdef PCIBIOSVERBOSE 503 if (!pcibiosverbose) 504#endif 505 { 506 printf("pci_addr_fixup: "); 507 pciaddr_print_devid(pc, tag); 508 } 509 if (pciaddr_ioaddr(macepci_conf_read(pc, tag, mapreg)) != *addr) { 510 macepci_conf_write(pc, tag, mapreg, 0); /* clear */ 511 printf("fixup failed. (new address=%#x)\n", (unsigned)*addr); 512 return (1); 513 } 514#ifdef PCIBIOSVERBOSE 515 if (!pcibiosverbose) 516#endif 517 printf("new address 0x%08x (size 0x%x)\n", (unsigned)*addr, 518 (unsigned)size); 519 520 return (0); 521} 522 523void 524pciaddr_print_devid(pci_chipset_tag_t pc, pcitag_t tag) 525{ 526 int bus, device, function; 527 pcireg_t id; 528 529 id = macepci_conf_read(pc, tag, PCI_ID_REG); 530 pci_decompose_tag(pc, tag, &bus, &device, &function); 531 printf("%03d:%02d:%d 0x%04x 0x%04x ", bus, device, function, 532 PCI_VENDOR(id), PCI_PRODUCT(id)); 533} 534