static int map_memory_window_bar(struct ntb_softc *ntb, struct ntb_pci_bar_info *bar) { int rc; uint8_t bar_size_bits = 0; bar->pci_resource = bus_alloc_resource_any(ntb->device, SYS_RES_MEMORY, &bar->pci_resource_id, RF_ACTIVE); if (bar->pci_resource == NULL) return (ENXIO); save_bar_parameters(bar); /* * Ivytown NTB BAR sizes are misreported by the hardware due to a * hardware issue. To work around this, query the size it should be * configured to by the device and modify the resource to correspond to * this new size. The BIOS on systems with this problem is required to * provide enough address space to allow the driver to make this change * safely. * * Ideally I could have just specified the size when I allocated the * resource like: * bus_alloc_resource(ntb->device, * SYS_RES_MEMORY, &bar->pci_resource_id, 0ul, ~0ul, * 1ul << bar_size_bits, RF_ACTIVE); * but the PCI driver does not honor the size in this call, so we have * to modify it after the fact. */ if (HAS_FEATURE(NTB_BAR_SIZE_4K)) { if (bar->pci_resource_id == PCIR_BAR(2)) bar_size_bits = pci_read_config(ntb->device, XEON_PBAR23SZ_OFFSET, 1); else bar_size_bits = pci_read_config(ntb->device, XEON_PBAR45SZ_OFFSET, 1); rc = bus_adjust_resource(ntb->device, SYS_RES_MEMORY, bar->pci_resource, bar->pbase, bar->pbase + (1ul << bar_size_bits) - 1); if (rc != 0) { device_printf(ntb->device, "unable to resize bar\n"); return (rc); } save_bar_parameters(bar); } /* Mark bar region as write combining to improve performance. */ rc = pmap_change_attr((vm_offset_t)bar->vbase, bar->size, VM_MEMATTR_WRITE_COMBINING); if (rc != 0) { device_printf(ntb->device, "unable to mark bar as WRITE_COMBINING\n"); return (rc); } return (0); }
int vchiq_platform_init(VCHIQ_STATE_T *state) { VCHIQ_SLOT_ZERO_T *vchiq_slot_zero; int frag_mem_size; int err; int i; /* Allocate space for the channels in coherent memory */ g_slot_mem_size = PAGE_ALIGN(TOTAL_SLOTS * VCHIQ_SLOT_SIZE); frag_mem_size = PAGE_ALIGN(sizeof(FRAGMENTS_T) * MAX_FRAGMENTS); err = bus_dma_tag_create( NULL, PAGE_SIZE, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ g_slot_mem_size + frag_mem_size, 1, /* maxsize, nsegments */ g_slot_mem_size + frag_mem_size, 0, /* maxsegsize, flags */ NULL, NULL, /* lockfunc, lockarg */ &dma_tag); err = bus_dmamem_alloc(dma_tag, (void **)&g_slot_mem, 0, &dma_map); if (err) { vcos_log_error("Unable to allocate channel memory"); err = ENOMEM; goto failed_alloc; } err = bus_dmamap_load(dma_tag, dma_map, g_slot_mem, g_slot_mem_size + frag_mem_size, vchiq_dmamap_cb, &g_slot_phys, 0); if (err) { vcos_log_error("cannot load DMA map\n"); goto failed_load; } pmap_change_attr((vm_offset_t)g_slot_mem, g_slot_mem_size + frag_mem_size, BUS_DMA_NOCACHE); vcos_assert(((int)g_slot_mem & (PAGE_SIZE - 1)) == 0); vchiq_slot_zero = vchiq_init_slots(g_slot_mem, g_slot_mem_size); if (!vchiq_slot_zero) { err = EINVAL; goto failed_init_slots; } vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_OFFSET_IDX] = (int)g_slot_phys + g_slot_mem_size; vchiq_slot_zero->platform_data[VCHIQ_PLATFORM_FRAGMENTS_COUNT_IDX] = MAX_FRAGMENTS; g_fragments_base = (FRAGMENTS_T *)(g_slot_mem + g_slot_mem_size); g_slot_mem_size += frag_mem_size; g_free_fragments = g_fragments_base; for (i = 0; i < (MAX_FRAGMENTS - 1); i++) { *(FRAGMENTS_T **) & g_fragments_base[i] = &g_fragments_base[i + 1]; } *(FRAGMENTS_T **) & g_fragments_base[i] = NULL; sema_init(&g_free_fragments_sema, MAX_FRAGMENTS, "Fragments semaphore"); if (vchiq_init_state(state, vchiq_slot_zero, 0/*slave*/) != VCHIQ_SUCCESS) { err = EINVAL; goto failed_vchiq_init; } bcm_mbox_write(BCM2835_MBOX_CHAN_VCHIQ, (unsigned int)g_slot_phys); vcos_log_info("vchiq_init - done (slots %x, phys %x)", (unsigned int)vchiq_slot_zero, g_slot_phys); return 0; failed_request_irq: failed_vchiq_init: failed_init_slots: failed_load: bus_dmamap_unload(dma_tag, dma_map); failed_alloc: bus_dmamap_destroy(dma_tag, dma_map); bus_dma_tag_destroy(dma_tag); return err; }