int ahd_pci_map_registers(struct ahd_softc *ahd) { struct resource *regs; struct resource *regs2; int regs_type; int regs_id; int regs_id2; int allow_memio; regs = NULL; regs2 = NULL; regs_type = 0; regs_id = 0; /* Retrieve the per-device 'allow_memio' hint */ if (resource_int_value(device_get_name(ahd->dev_softc), device_get_unit(ahd->dev_softc), "allow_memio", &allow_memio) != 0) { if (bootverbose) device_printf(ahd->dev_softc, "Defaulting to MEMIO on\n"); allow_memio = 1; } if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) == 0 && allow_memio != 0) { regs_type = SYS_RES_MEMORY; regs_id = AHD_PCI_MEMADDR; regs = bus_alloc_resource_any(ahd->dev_softc, regs_type, ®s_id, RF_ACTIVE); if (regs != NULL) { int error; ahd->tags[0] = rman_get_bustag(regs); ahd->bshs[0] = rman_get_bushandle(regs); ahd->tags[1] = ahd->tags[0]; error = bus_space_subregion(ahd->tags[0], ahd->bshs[0], /*offset*/0x100, /*size*/0x100, &ahd->bshs[1]); /* * Do a quick test to see if memory mapped * I/O is functioning correctly. */ if (error != 0 || ahd_pci_test_register_access(ahd) != 0) { device_printf(ahd->dev_softc, "PCI Device %d:%d:%d failed memory " "mapped test. Using PIO.\n", aic_get_pci_bus(ahd->dev_softc), aic_get_pci_slot(ahd->dev_softc), aic_get_pci_function(ahd->dev_softc)); bus_release_resource(ahd->dev_softc, regs_type, regs_id, regs); regs = NULL; AHD_CORRECTABLE_ERROR(ahd); } } } if (regs == NULL) { regs_type = SYS_RES_IOPORT; regs_id = AHD_PCI_IOADDR0; regs = bus_alloc_resource_any(ahd->dev_softc, regs_type, ®s_id, RF_ACTIVE); if (regs == NULL) { device_printf(ahd->dev_softc, "can't allocate register resources\n"); AHD_UNCORRECTABLE_ERROR(ahd); return (ENOMEM); } ahd->tags[0] = rman_get_bustag(regs); ahd->bshs[0] = rman_get_bushandle(regs); /* And now the second BAR */ regs_id2 = AHD_PCI_IOADDR1; regs2 = bus_alloc_resource_any(ahd->dev_softc, regs_type, ®s_id2, RF_ACTIVE); if (regs2 == NULL) { device_printf(ahd->dev_softc, "can't allocate register resources\n"); AHD_UNCORRECTABLE_ERROR(ahd); return (ENOMEM); } ahd->tags[1] = rman_get_bustag(regs2); ahd->bshs[1] = rman_get_bushandle(regs2); ahd->platform_data->regs_res_type[1] = regs_type; ahd->platform_data->regs_res_id[1] = regs_id2; ahd->platform_data->regs[1] = regs2; } ahd->platform_data->regs_res_type[0] = regs_type; ahd->platform_data->regs_res_id[0] = regs_id; ahd->platform_data->regs[0] = regs; return (0); }
int ahd_pci_map_registers(struct ahd_softc *ahd) { uint32_t command; u_long base; uint8_t __iomem *maddr; int error; /* * If its allowed, we prefer memory mapped access. */ command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4); command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN); base = 0; maddr = NULL; error = ahd_linux_pci_reserve_mem_region(ahd, &base, &maddr); if (error == 0) { ahd->platform_data->mem_busaddr = base; ahd->tags[0] = BUS_SPACE_MEMIO; ahd->bshs[0].maddr = maddr; ahd->tags[1] = BUS_SPACE_MEMIO; ahd->bshs[1].maddr = maddr + 0x100; ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command | PCIM_CMD_MEMEN, 4); if (ahd_pci_test_register_access(ahd) != 0) { printf("aic79xx: PCI Device %d:%d:%d " "failed memory mapped test. Using PIO.\n", ahd_get_pci_bus(ahd->dev_softc), ahd_get_pci_slot(ahd->dev_softc), ahd_get_pci_function(ahd->dev_softc)); iounmap(maddr); release_mem_region(ahd->platform_data->mem_busaddr, 0x1000); ahd->bshs[0].maddr = NULL; maddr = NULL; } else command |= PCIM_CMD_MEMEN; } else if (bootverbose) { printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx " "unavailable. Cannot memory map device.\n", ahd_get_pci_bus(ahd->dev_softc), ahd_get_pci_slot(ahd->dev_softc), ahd_get_pci_function(ahd->dev_softc), base); } if (maddr == NULL) { u_long base2; error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2); if (error == 0) { ahd->tags[0] = BUS_SPACE_PIO; ahd->tags[1] = BUS_SPACE_PIO; ahd->bshs[0].ioport = base; ahd->bshs[1].ioport = base2; command |= PCIM_CMD_PORTEN; } else { printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx" "unavailable. Cannot map device.\n", ahd_get_pci_bus(ahd->dev_softc), ahd_get_pci_slot(ahd->dev_softc), ahd_get_pci_function(ahd->dev_softc), base, base2); } } ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4); return (error); }
static void ahd_pci_attach(device_t parent, device_t self, void *aux) { struct pci_attach_args *pa = aux; struct ahd_softc *ahd = device_private(self); const struct ahd_pci_identity *entry; uint32_t devconfig; pcireg_t command; int error; pcireg_t subid; uint16_t subvendor; pcireg_t reg; int ioh_valid, ioh2_valid, memh_valid; pcireg_t memtype; pci_intr_handle_t ih; const char *intrstr; struct ahd_pci_busdata *bd; ahd->sc_dev = self; ahd_set_name(ahd, device_xname(self)); ahd->parent_dmat = pa->pa_dmat; command = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); subid = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_SUBSYS_ID_REG); entry = ahd_find_pci_device(pa->pa_id, subid); if (entry == NULL) return; /* Keep information about the PCI bus */ bd = malloc(sizeof (struct ahd_pci_busdata), M_DEVBUF, M_NOWAIT); if (bd == NULL) { aprint_error("%s: unable to allocate bus-specific data\n", ahd_name(ahd)); return; } memset(bd, 0, sizeof(struct ahd_pci_busdata)); bd->pc = pa->pa_pc; bd->tag = pa->pa_tag; bd->func = pa->pa_function; bd->dev = pa->pa_device; ahd->bus_data = bd; ahd->description = entry->name; ahd->seep_config = malloc(sizeof(*ahd->seep_config), M_DEVBUF, M_NOWAIT); if (ahd->seep_config == NULL) { aprint_error("%s: cannot malloc seep_config!\n", ahd_name(ahd)); return; } memset(ahd->seep_config, 0, sizeof(*ahd->seep_config)); LIST_INIT(&ahd->pending_scbs); ahd_timer_init(&ahd->reset_timer); ahd_timer_init(&ahd->stat_timer); ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT; ahd->int_coalescing_stop_threshold = AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; if (ahd_platform_alloc(ahd, NULL) != 0) { ahd_free(ahd); return; } /* * Record if this is an HP board. */ subvendor = PCI_VENDOR(subid); if (subvendor == SUBID_HP) ahd->flags |= AHD_HP_BOARD; error = entry->setup(ahd, pa); if (error != 0) return; devconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG); if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) { ahd->chip |= AHD_PCI; /* Disable PCIX workarounds when running in PCI mode. */ ahd->bugs &= ~AHD_PCIX_BUG_MASK; } else { ahd->chip |= AHD_PCIX; } ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)]; memh_valid = ioh_valid = ioh2_valid = 0; if (!pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_PCIX, &bd->pcix_off, NULL)) { if (ahd->chip & AHD_PCIX) aprint_error_dev(self, "warning: can't find PCI-X capability\n"); ahd->chip &= ~AHD_PCIX; ahd->chip |= AHD_PCI; ahd->bugs &= ~AHD_PCIX_BUG_MASK; } /* * Map PCI Registers */ if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) == 0) { memtype = pci_mapreg_type(pa->pa_pc, pa->pa_tag, AHD_PCI_MEMADDR); switch (memtype) { case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: memh_valid = (pci_mapreg_map(pa, AHD_PCI_MEMADDR, memtype, 0, &ahd->tags[0], &ahd->bshs[0], NULL, NULL) == 0); if (memh_valid) { ahd->tags[1] = ahd->tags[0]; bus_space_subregion(ahd->tags[0], ahd->bshs[0], /*offset*/0x100, /*size*/0x100, &ahd->bshs[1]); if (ahd_pci_test_register_access(ahd) != 0) memh_valid = 0; } break; default: memh_valid = 0; aprint_error("%s: unknown memory type: 0x%x\n", ahd_name(ahd), memtype); break; } if (memh_valid) { command &= ~PCI_COMMAND_IO_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); } #ifdef AHD_DEBUG printf("%s: doing memory mapping shs0 0x%lx, shs1 0x%lx\n", ahd_name(ahd), ahd->bshs[0], ahd->bshs[1]); #endif } if (command & PCI_COMMAND_IO_ENABLE) { /* First BAR */ ioh_valid = (pci_mapreg_map(pa, AHD_PCI_IOADDR, PCI_MAPREG_TYPE_IO, 0, &ahd->tags[0], &ahd->bshs[0], NULL, NULL) == 0); /* 2nd BAR */ ioh2_valid = (pci_mapreg_map(pa, AHD_PCI_IOADDR1, PCI_MAPREG_TYPE_IO, 0, &ahd->tags[1], &ahd->bshs[1], NULL, NULL) == 0); if (ioh_valid && ioh2_valid) { KASSERT(memh_valid == 0); command &= ~PCI_COMMAND_MEM_ENABLE; pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, command); } #ifdef AHD_DEBUG printf("%s: doing io mapping shs0 0x%lx, shs1 0x%lx\n", ahd_name(ahd), ahd->bshs[0], ahd->bshs[1]); #endif } if (memh_valid == 0 && (ioh_valid == 0 || ioh2_valid == 0)) { aprint_error("%s: unable to map registers\n", ahd_name(ahd)); return; } aprint_normal("\n"); aprint_naive("\n"); /* power up chip */ if ((error = pci_activate(pa->pa_pc, pa->pa_tag, self, pci_activate_null)) && error != EOPNOTSUPP) { aprint_error_dev(self, "cannot activate %d\n", error); return; } /* * Should we bother disabling 39Bit addressing * based on installed memory? */ if (sizeof(bus_addr_t) > 4) ahd->flags |= AHD_39BIT_ADDRESSING; /* * If we need to support high memory, enable dual * address cycles. This bit must be set to enable * high address bit generation even if we are on a * 64bit bus (PCI64BIT set in devconfig). */ if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) { uint32_t dvconfig; aprint_normal("%s: Enabling 39Bit Addressing\n", ahd_name(ahd)); dvconfig = pci_conf_read(pa->pa_pc, pa->pa_tag, DEVCONFIG); dvconfig |= DACEN; pci_conf_write(pa->pa_pc, pa->pa_tag, DEVCONFIG, dvconfig); } /* Ensure busmastering is enabled */ reg = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG); pci_conf_write(pa->pa_pc, pa->pa_tag, PCI_COMMAND_STATUS_REG, reg | PCI_COMMAND_MASTER_ENABLE); ahd_softc_init(ahd); /* * Map the interrupt routines */ ahd->bus_intr = ahd_pci_intr; error = ahd_reset(ahd, /*reinit*/FALSE); if (error != 0) { ahd_free(ahd); return; } if (pci_intr_map(pa, &ih)) { aprint_error("%s: couldn't map interrupt\n", ahd_name(ahd)); ahd_free(ahd); return; } intrstr = pci_intr_string(pa->pa_pc, ih); ahd->ih = pci_intr_establish(pa->pa_pc, ih, IPL_BIO, ahd_intr, ahd); if (ahd->ih == NULL) { aprint_error("%s: couldn't establish interrupt", ahd_name(ahd)); if (intrstr != NULL) aprint_error(" at %s", intrstr); aprint_error("\n"); ahd_free(ahd); return; } if (intrstr != NULL) aprint_normal("%s: interrupting at %s\n", ahd_name(ahd), intrstr); /* Get the size of the cache */ ahd->pci_cachesize = pci_conf_read(pa->pa_pc, pa->pa_tag, PCI_BHLC_REG); ahd->pci_cachesize *= 4; ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); /* See if we have a SEEPROM and perform auto-term */ error = ahd_check_extport(ahd); if (error != 0) return; /* Core initialization */ error = ahd_init(ahd); if (error != 0) return; /* * Link this softc in with all other ahd instances. */ ahd_attach(ahd); }