int encdec_init(void) { u64 muid, dma_bus_addr; int result; result = lv1_allocate_memory(ENCDEC_DMA_SIZE, ENCDEC_DMA_PAGE_SIZE, 0, 0, &encdec_buf_lpar_addr, &muid); if (result != 0) return result; result = lv1_allocate_device_dma_region(ENCDEC_BUS_ID, ENCDEC_DEV_ID, ENCDEC_DMA_SIZE, ENCDEC_DMA_PAGE_SIZE, 0, &dma_bus_addr); if (result != 0) return result; result = lv1_map_device_dma_region(ENCDEC_BUS_ID, ENCDEC_DEV_ID, encdec_buf_lpar_addr, dma_bus_addr, ENCDEC_DMA_SIZE, 0xF800000000000000ULL); if (result != 0) return result; MM_LOAD_BASE(encdec_buf, ENCDEC_DMA_OFFSET); result = mm_map_lpar_memory_region(0, MM_EA2VA((u64) encdec_buf), encdec_buf_lpar_addr, ENCDEC_DMA_SIZE, ENCDEC_DMA_PAGE_SIZE, 0, 0); if (result != 0) return result; memset(encdec_buf, 0, ENCDEC_DMA_SIZE); return 0; }
static void map_dma_mem(int bus_id, int dev_id, void *start, size_t len, u64 *real_bus_addr) { s64 result; u64 real_addr = ((u64)start) & 0x0fffffffffffffffUL; u64 real_end = real_addr + len; u64 map_start = real_addr & ~0xfff; u64 map_end = (real_end + 0xfff) & ~0xfff; u64 bus_addr = 0; u64 flags = 0xf800000000000000UL; result = lv1_allocate_device_dma_region(bus_id, dev_id, map_end - map_start, 12, 0, &bus_addr); if (result) lv1_panic(0); result = lv1_map_device_dma_region(bus_id, dev_id, map_start, bus_addr, map_end - map_start, flags); if (result) lv1_panic(0); *real_bus_addr = bus_addr + real_addr - map_start; }
static bus_dma_tag_t ps3bus_get_dma_tag(device_t dev, device_t child) { struct ps3bus_devinfo *dinfo = device_get_ivars(child); struct ps3bus_softc *sc = device_get_softc(dev); int i, err, flags, pagesize; if (dinfo->bustype != PS3_BUSTYPE_SYSBUS && dinfo->bustype != PS3_BUSTYPE_STORAGE) return (bus_get_dma_tag(dev)); mtx_lock(&dinfo->iommu_mtx); if (dinfo->dma_tag != NULL) { mtx_unlock(&dinfo->iommu_mtx); return (dinfo->dma_tag); } flags = 0; /* 32-bit mode */ if (dinfo->bustype == PS3_BUSTYPE_SYSBUS && dinfo->devtype == PS3_DEVTYPE_USB) flags = 2; /* 8-bit mode */ pagesize = 24; /* log_2(16 MB) */ if (dinfo->bustype == PS3_BUSTYPE_STORAGE) pagesize = 12; /* 4 KB */ for (i = 0; i < sc->rcount; i++) { err = lv1_allocate_device_dma_region(dinfo->bus, dinfo->dev, sc->regions[i].mr_size, pagesize, flags, &dinfo->dma_base[i]); if (err != 0) { device_printf(child, "could not allocate DMA region %d: %d\n", i, err); goto fail; } err = lv1_map_device_dma_region(dinfo->bus, dinfo->dev, sc->regions[i].mr_start, dinfo->dma_base[i], sc->regions[i].mr_size, 0xf800000000000800UL /* Cell Handbook Figure 7.3.4.1 */); if (err != 0) { device_printf(child, "could not map DMA region %d: %d\n", i, err); goto fail; } } err = bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, BUS_SPACE_MAXSIZE, 0, BUS_SPACE_MAXSIZE, 0, NULL, NULL, &dinfo->dma_tag); /* * Note: storage devices have IOMMU mappings set up by the hypervisor, * but use physical, non-translated addresses. The above IOMMU * initialization is necessary for the hypervisor to be able to set up * the mappings, but actual DMA mappings should not use the IOMMU * routines. */ if (dinfo->bustype != PS3_BUSTYPE_STORAGE) bus_dma_tag_set_iommu(dinfo->dma_tag, dev, dinfo); fail: mtx_unlock(&dinfo->iommu_mtx); if (err) return (NULL); return (dinfo->dma_tag); }