|  | /* pci_sun4v.c: SUN4V specific PCI controller support. | 
|  | * | 
|  | * Copyright (C) 2006 David S. Miller (davem@davemloft.net) | 
|  | */ | 
|  |  | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/types.h> | 
|  | #include <linux/pci.h> | 
|  | #include <linux/init.h> | 
|  | #include <linux/slab.h> | 
|  | #include <linux/interrupt.h> | 
|  | #include <linux/percpu.h> | 
|  |  | 
|  | #include <asm/pbm.h> | 
|  | #include <asm/iommu.h> | 
|  | #include <asm/irq.h> | 
|  | #include <asm/upa.h> | 
|  | #include <asm/pstate.h> | 
|  | #include <asm/oplib.h> | 
|  | #include <asm/hypervisor.h> | 
|  | #include <asm/prom.h> | 
|  |  | 
|  | #include "pci_impl.h" | 
|  | #include "iommu_common.h" | 
|  |  | 
|  | #include "pci_sun4v.h" | 
|  |  | 
|  | #define PGLIST_NENTS	(PAGE_SIZE / sizeof(u64)) | 
|  |  | 
|  | struct pci_iommu_batch { | 
|  | struct pci_dev	*pdev;		/* Device mapping is for.	*/ | 
|  | unsigned long	prot;		/* IOMMU page protections	*/ | 
|  | unsigned long	entry;		/* Index into IOTSB.		*/ | 
|  | u64		*pglist;	/* List of physical pages	*/ | 
|  | unsigned long	npages;		/* Number of pages in list.	*/ | 
|  | }; | 
|  |  | 
|  | static DEFINE_PER_CPU(struct pci_iommu_batch, pci_iommu_batch); | 
|  |  | 
|  | /* Interrupts must be disabled.  */ | 
|  | static inline void pci_iommu_batch_start(struct pci_dev *pdev, unsigned long prot, unsigned long entry) | 
|  | { | 
|  | struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); | 
|  |  | 
|  | p->pdev		= pdev; | 
|  | p->prot		= prot; | 
|  | p->entry	= entry; | 
|  | p->npages	= 0; | 
|  | } | 
|  |  | 
|  | /* Interrupts must be disabled.  */ | 
|  | static long pci_iommu_batch_flush(struct pci_iommu_batch *p) | 
|  | { | 
|  | struct pcidev_cookie *pcp = p->pdev->sysdata; | 
|  | unsigned long devhandle = pcp->pbm->devhandle; | 
|  | unsigned long prot = p->prot; | 
|  | unsigned long entry = p->entry; | 
|  | u64 *pglist = p->pglist; | 
|  | unsigned long npages = p->npages; | 
|  |  | 
|  | while (npages != 0) { | 
|  | long num; | 
|  |  | 
|  | num = pci_sun4v_iommu_map(devhandle, HV_PCI_TSBID(0, entry), | 
|  | npages, prot, __pa(pglist)); | 
|  | if (unlikely(num < 0)) { | 
|  | if (printk_ratelimit()) | 
|  | printk("pci_iommu_batch_flush: IOMMU map of " | 
|  | "[%08lx:%08lx:%lx:%lx:%lx] failed with " | 
|  | "status %ld\n", | 
|  | devhandle, HV_PCI_TSBID(0, entry), | 
|  | npages, prot, __pa(pglist), num); | 
|  | return -1; | 
|  | } | 
|  |  | 
|  | entry += num; | 
|  | npages -= num; | 
|  | pglist += num; | 
|  | } | 
|  |  | 
|  | p->entry = entry; | 
|  | p->npages = 0; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Interrupts must be disabled.  */ | 
|  | static inline long pci_iommu_batch_add(u64 phys_page) | 
|  | { | 
|  | struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); | 
|  |  | 
|  | BUG_ON(p->npages >= PGLIST_NENTS); | 
|  |  | 
|  | p->pglist[p->npages++] = phys_page; | 
|  | if (p->npages == PGLIST_NENTS) | 
|  | return pci_iommu_batch_flush(p); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Interrupts must be disabled.  */ | 
|  | static inline long pci_iommu_batch_end(void) | 
|  | { | 
|  | struct pci_iommu_batch *p = &__get_cpu_var(pci_iommu_batch); | 
|  |  | 
|  | BUG_ON(p->npages >= PGLIST_NENTS); | 
|  |  | 
|  | return pci_iommu_batch_flush(p); | 
|  | } | 
|  |  | 
|  | static long pci_arena_alloc(struct pci_iommu_arena *arena, unsigned long npages) | 
|  | { | 
|  | unsigned long n, i, start, end, limit; | 
|  | int pass; | 
|  |  | 
|  | limit = arena->limit; | 
|  | start = arena->hint; | 
|  | pass = 0; | 
|  |  | 
|  | again: | 
|  | n = find_next_zero_bit(arena->map, limit, start); | 
|  | end = n + npages; | 
|  | if (unlikely(end >= limit)) { | 
|  | if (likely(pass < 1)) { | 
|  | limit = start; | 
|  | start = 0; | 
|  | pass++; | 
|  | goto again; | 
|  | } else { | 
|  | /* Scanned the whole thing, give up. */ | 
|  | return -1; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = n; i < end; i++) { | 
|  | if (test_bit(i, arena->map)) { | 
|  | start = i + 1; | 
|  | goto again; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (i = n; i < end; i++) | 
|  | __set_bit(i, arena->map); | 
|  |  | 
|  | arena->hint = end; | 
|  |  | 
|  | return n; | 
|  | } | 
|  |  | 
|  | static void pci_arena_free(struct pci_iommu_arena *arena, unsigned long base, unsigned long npages) | 
|  | { | 
|  | unsigned long i; | 
|  |  | 
|  | for (i = base; i < (base + npages); i++) | 
|  | __clear_bit(i, arena->map); | 
|  | } | 
|  |  | 
|  | static void *pci_4v_alloc_consistent(struct pci_dev *pdev, size_t size, dma_addr_t *dma_addrp, gfp_t gfp) | 
|  | { | 
|  | struct pcidev_cookie *pcp; | 
|  | struct pci_iommu *iommu; | 
|  | unsigned long flags, order, first_page, npages, n; | 
|  | void *ret; | 
|  | long entry; | 
|  |  | 
|  | size = IO_PAGE_ALIGN(size); | 
|  | order = get_order(size); | 
|  | if (unlikely(order >= MAX_ORDER)) | 
|  | return NULL; | 
|  |  | 
|  | npages = size >> IO_PAGE_SHIFT; | 
|  |  | 
|  | first_page = __get_free_pages(gfp, order); | 
|  | if (unlikely(first_page == 0UL)) | 
|  | return NULL; | 
|  |  | 
|  | memset((char *)first_page, 0, PAGE_SIZE << order); | 
|  |  | 
|  | pcp = pdev->sysdata; | 
|  | iommu = pcp->pbm->iommu; | 
|  |  | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  | entry = pci_arena_alloc(&iommu->arena, npages); | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | if (unlikely(entry < 0L)) | 
|  | goto arena_alloc_fail; | 
|  |  | 
|  | *dma_addrp = (iommu->page_table_map_base + | 
|  | (entry << IO_PAGE_SHIFT)); | 
|  | ret = (void *) first_page; | 
|  | first_page = __pa(first_page); | 
|  |  | 
|  | local_irq_save(flags); | 
|  |  | 
|  | pci_iommu_batch_start(pdev, | 
|  | (HV_PCI_MAP_ATTR_READ | | 
|  | HV_PCI_MAP_ATTR_WRITE), | 
|  | entry); | 
|  |  | 
|  | for (n = 0; n < npages; n++) { | 
|  | long err = pci_iommu_batch_add(first_page + (n * PAGE_SIZE)); | 
|  | if (unlikely(err < 0L)) | 
|  | goto iommu_map_fail; | 
|  | } | 
|  |  | 
|  | if (unlikely(pci_iommu_batch_end() < 0L)) | 
|  | goto iommu_map_fail; | 
|  |  | 
|  | local_irq_restore(flags); | 
|  |  | 
|  | return ret; | 
|  |  | 
|  | iommu_map_fail: | 
|  | /* Interrupts are disabled.  */ | 
|  | spin_lock(&iommu->lock); | 
|  | pci_arena_free(&iommu->arena, entry, npages); | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | arena_alloc_fail: | 
|  | free_pages(first_page, order); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | static void pci_4v_free_consistent(struct pci_dev *pdev, size_t size, void *cpu, dma_addr_t dvma) | 
|  | { | 
|  | struct pcidev_cookie *pcp; | 
|  | struct pci_iommu *iommu; | 
|  | unsigned long flags, order, npages, entry; | 
|  | u32 devhandle; | 
|  |  | 
|  | npages = IO_PAGE_ALIGN(size) >> IO_PAGE_SHIFT; | 
|  | pcp = pdev->sysdata; | 
|  | iommu = pcp->pbm->iommu; | 
|  | devhandle = pcp->pbm->devhandle; | 
|  | entry = ((dvma - iommu->page_table_map_base) >> IO_PAGE_SHIFT); | 
|  |  | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  |  | 
|  | pci_arena_free(&iommu->arena, entry, npages); | 
|  |  | 
|  | do { | 
|  | unsigned long num; | 
|  |  | 
|  | num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), | 
|  | npages); | 
|  | entry += num; | 
|  | npages -= num; | 
|  | } while (npages != 0); | 
|  |  | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | order = get_order(size); | 
|  | if (order < 10) | 
|  | free_pages((unsigned long)cpu, order); | 
|  | } | 
|  |  | 
|  | static dma_addr_t pci_4v_map_single(struct pci_dev *pdev, void *ptr, size_t sz, int direction) | 
|  | { | 
|  | struct pcidev_cookie *pcp; | 
|  | struct pci_iommu *iommu; | 
|  | unsigned long flags, npages, oaddr; | 
|  | unsigned long i, base_paddr; | 
|  | u32 bus_addr, ret; | 
|  | unsigned long prot; | 
|  | long entry; | 
|  |  | 
|  | pcp = pdev->sysdata; | 
|  | iommu = pcp->pbm->iommu; | 
|  |  | 
|  | if (unlikely(direction == PCI_DMA_NONE)) | 
|  | goto bad; | 
|  |  | 
|  | oaddr = (unsigned long)ptr; | 
|  | npages = IO_PAGE_ALIGN(oaddr + sz) - (oaddr & IO_PAGE_MASK); | 
|  | npages >>= IO_PAGE_SHIFT; | 
|  |  | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  | entry = pci_arena_alloc(&iommu->arena, npages); | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | if (unlikely(entry < 0L)) | 
|  | goto bad; | 
|  |  | 
|  | bus_addr = (iommu->page_table_map_base + | 
|  | (entry << IO_PAGE_SHIFT)); | 
|  | ret = bus_addr | (oaddr & ~IO_PAGE_MASK); | 
|  | base_paddr = __pa(oaddr & IO_PAGE_MASK); | 
|  | prot = HV_PCI_MAP_ATTR_READ; | 
|  | if (direction != PCI_DMA_TODEVICE) | 
|  | prot |= HV_PCI_MAP_ATTR_WRITE; | 
|  |  | 
|  | local_irq_save(flags); | 
|  |  | 
|  | pci_iommu_batch_start(pdev, prot, entry); | 
|  |  | 
|  | for (i = 0; i < npages; i++, base_paddr += IO_PAGE_SIZE) { | 
|  | long err = pci_iommu_batch_add(base_paddr); | 
|  | if (unlikely(err < 0L)) | 
|  | goto iommu_map_fail; | 
|  | } | 
|  | if (unlikely(pci_iommu_batch_end() < 0L)) | 
|  | goto iommu_map_fail; | 
|  |  | 
|  | local_irq_restore(flags); | 
|  |  | 
|  | return ret; | 
|  |  | 
|  | bad: | 
|  | if (printk_ratelimit()) | 
|  | WARN_ON(1); | 
|  | return PCI_DMA_ERROR_CODE; | 
|  |  | 
|  | iommu_map_fail: | 
|  | /* Interrupts are disabled.  */ | 
|  | spin_lock(&iommu->lock); | 
|  | pci_arena_free(&iommu->arena, entry, npages); | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | return PCI_DMA_ERROR_CODE; | 
|  | } | 
|  |  | 
|  | static void pci_4v_unmap_single(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) | 
|  | { | 
|  | struct pcidev_cookie *pcp; | 
|  | struct pci_iommu *iommu; | 
|  | unsigned long flags, npages; | 
|  | long entry; | 
|  | u32 devhandle; | 
|  |  | 
|  | if (unlikely(direction == PCI_DMA_NONE)) { | 
|  | if (printk_ratelimit()) | 
|  | WARN_ON(1); | 
|  | return; | 
|  | } | 
|  |  | 
|  | pcp = pdev->sysdata; | 
|  | iommu = pcp->pbm->iommu; | 
|  | devhandle = pcp->pbm->devhandle; | 
|  |  | 
|  | npages = IO_PAGE_ALIGN(bus_addr + sz) - (bus_addr & IO_PAGE_MASK); | 
|  | npages >>= IO_PAGE_SHIFT; | 
|  | bus_addr &= IO_PAGE_MASK; | 
|  |  | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  |  | 
|  | entry = (bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT; | 
|  | pci_arena_free(&iommu->arena, entry, npages); | 
|  |  | 
|  | do { | 
|  | unsigned long num; | 
|  |  | 
|  | num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), | 
|  | npages); | 
|  | entry += num; | 
|  | npages -= num; | 
|  | } while (npages != 0); | 
|  |  | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  | } | 
|  |  | 
|  | #define SG_ENT_PHYS_ADDRESS(SG)	\ | 
|  | (__pa(page_address((SG)->page)) + (SG)->offset) | 
|  |  | 
|  | static inline long fill_sg(long entry, struct pci_dev *pdev, | 
|  | struct scatterlist *sg, | 
|  | int nused, int nelems, unsigned long prot) | 
|  | { | 
|  | struct scatterlist *dma_sg = sg; | 
|  | struct scatterlist *sg_end = sg + nelems; | 
|  | unsigned long flags; | 
|  | int i; | 
|  |  | 
|  | local_irq_save(flags); | 
|  |  | 
|  | pci_iommu_batch_start(pdev, prot, entry); | 
|  |  | 
|  | for (i = 0; i < nused; i++) { | 
|  | unsigned long pteval = ~0UL; | 
|  | u32 dma_npages; | 
|  |  | 
|  | dma_npages = ((dma_sg->dma_address & (IO_PAGE_SIZE - 1UL)) + | 
|  | dma_sg->dma_length + | 
|  | ((IO_PAGE_SIZE - 1UL))) >> IO_PAGE_SHIFT; | 
|  | do { | 
|  | unsigned long offset; | 
|  | signed int len; | 
|  |  | 
|  | /* If we are here, we know we have at least one | 
|  | * more page to map.  So walk forward until we | 
|  | * hit a page crossing, and begin creating new | 
|  | * mappings from that spot. | 
|  | */ | 
|  | for (;;) { | 
|  | unsigned long tmp; | 
|  |  | 
|  | tmp = SG_ENT_PHYS_ADDRESS(sg); | 
|  | len = sg->length; | 
|  | if (((tmp ^ pteval) >> IO_PAGE_SHIFT) != 0UL) { | 
|  | pteval = tmp & IO_PAGE_MASK; | 
|  | offset = tmp & (IO_PAGE_SIZE - 1UL); | 
|  | break; | 
|  | } | 
|  | if (((tmp ^ (tmp + len - 1UL)) >> IO_PAGE_SHIFT) != 0UL) { | 
|  | pteval = (tmp + IO_PAGE_SIZE) & IO_PAGE_MASK; | 
|  | offset = 0UL; | 
|  | len -= (IO_PAGE_SIZE - (tmp & (IO_PAGE_SIZE - 1UL))); | 
|  | break; | 
|  | } | 
|  | sg++; | 
|  | } | 
|  |  | 
|  | pteval = (pteval & IOPTE_PAGE); | 
|  | while (len > 0) { | 
|  | long err; | 
|  |  | 
|  | err = pci_iommu_batch_add(pteval); | 
|  | if (unlikely(err < 0L)) | 
|  | goto iommu_map_failed; | 
|  |  | 
|  | pteval += IO_PAGE_SIZE; | 
|  | len -= (IO_PAGE_SIZE - offset); | 
|  | offset = 0; | 
|  | dma_npages--; | 
|  | } | 
|  |  | 
|  | pteval = (pteval & IOPTE_PAGE) + len; | 
|  | sg++; | 
|  |  | 
|  | /* Skip over any tail mappings we've fully mapped, | 
|  | * adjusting pteval along the way.  Stop when we | 
|  | * detect a page crossing event. | 
|  | */ | 
|  | while (sg < sg_end && | 
|  | (pteval << (64 - IO_PAGE_SHIFT)) != 0UL && | 
|  | (pteval == SG_ENT_PHYS_ADDRESS(sg)) && | 
|  | ((pteval ^ | 
|  | (SG_ENT_PHYS_ADDRESS(sg) + sg->length - 1UL)) >> IO_PAGE_SHIFT) == 0UL) { | 
|  | pteval += sg->length; | 
|  | sg++; | 
|  | } | 
|  | if ((pteval << (64 - IO_PAGE_SHIFT)) == 0UL) | 
|  | pteval = ~0UL; | 
|  | } while (dma_npages != 0); | 
|  | dma_sg++; | 
|  | } | 
|  |  | 
|  | if (unlikely(pci_iommu_batch_end() < 0L)) | 
|  | goto iommu_map_failed; | 
|  |  | 
|  | local_irq_restore(flags); | 
|  | return 0; | 
|  |  | 
|  | iommu_map_failed: | 
|  | local_irq_restore(flags); | 
|  | return -1L; | 
|  | } | 
|  |  | 
|  | static int pci_4v_map_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | 
|  | { | 
|  | struct pcidev_cookie *pcp; | 
|  | struct pci_iommu *iommu; | 
|  | unsigned long flags, npages, prot; | 
|  | u32 dma_base; | 
|  | struct scatterlist *sgtmp; | 
|  | long entry, err; | 
|  | int used; | 
|  |  | 
|  | /* Fast path single entry scatterlists. */ | 
|  | if (nelems == 1) { | 
|  | sglist->dma_address = | 
|  | pci_4v_map_single(pdev, | 
|  | (page_address(sglist->page) + sglist->offset), | 
|  | sglist->length, direction); | 
|  | if (unlikely(sglist->dma_address == PCI_DMA_ERROR_CODE)) | 
|  | return 0; | 
|  | sglist->dma_length = sglist->length; | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | pcp = pdev->sysdata; | 
|  | iommu = pcp->pbm->iommu; | 
|  |  | 
|  | if (unlikely(direction == PCI_DMA_NONE)) | 
|  | goto bad; | 
|  |  | 
|  | /* Step 1: Prepare scatter list. */ | 
|  | npages = prepare_sg(sglist, nelems); | 
|  |  | 
|  | /* Step 2: Allocate a cluster and context, if necessary. */ | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  | entry = pci_arena_alloc(&iommu->arena, npages); | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | if (unlikely(entry < 0L)) | 
|  | goto bad; | 
|  |  | 
|  | dma_base = iommu->page_table_map_base + | 
|  | (entry << IO_PAGE_SHIFT); | 
|  |  | 
|  | /* Step 3: Normalize DMA addresses. */ | 
|  | used = nelems; | 
|  |  | 
|  | sgtmp = sglist; | 
|  | while (used && sgtmp->dma_length) { | 
|  | sgtmp->dma_address += dma_base; | 
|  | sgtmp++; | 
|  | used--; | 
|  | } | 
|  | used = nelems - used; | 
|  |  | 
|  | /* Step 4: Create the mappings. */ | 
|  | prot = HV_PCI_MAP_ATTR_READ; | 
|  | if (direction != PCI_DMA_TODEVICE) | 
|  | prot |= HV_PCI_MAP_ATTR_WRITE; | 
|  |  | 
|  | err = fill_sg(entry, pdev, sglist, used, nelems, prot); | 
|  | if (unlikely(err < 0L)) | 
|  | goto iommu_map_failed; | 
|  |  | 
|  | return used; | 
|  |  | 
|  | bad: | 
|  | if (printk_ratelimit()) | 
|  | WARN_ON(1); | 
|  | return 0; | 
|  |  | 
|  | iommu_map_failed: | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  | pci_arena_free(&iommu->arena, entry, npages); | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static void pci_4v_unmap_sg(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | 
|  | { | 
|  | struct pcidev_cookie *pcp; | 
|  | struct pci_iommu *iommu; | 
|  | unsigned long flags, i, npages; | 
|  | long entry; | 
|  | u32 devhandle, bus_addr; | 
|  |  | 
|  | if (unlikely(direction == PCI_DMA_NONE)) { | 
|  | if (printk_ratelimit()) | 
|  | WARN_ON(1); | 
|  | } | 
|  |  | 
|  | pcp = pdev->sysdata; | 
|  | iommu = pcp->pbm->iommu; | 
|  | devhandle = pcp->pbm->devhandle; | 
|  |  | 
|  | bus_addr = sglist->dma_address & IO_PAGE_MASK; | 
|  |  | 
|  | for (i = 1; i < nelems; i++) | 
|  | if (sglist[i].dma_length == 0) | 
|  | break; | 
|  | i--; | 
|  | npages = (IO_PAGE_ALIGN(sglist[i].dma_address + sglist[i].dma_length) - | 
|  | bus_addr) >> IO_PAGE_SHIFT; | 
|  |  | 
|  | entry = ((bus_addr - iommu->page_table_map_base) >> IO_PAGE_SHIFT); | 
|  |  | 
|  | spin_lock_irqsave(&iommu->lock, flags); | 
|  |  | 
|  | pci_arena_free(&iommu->arena, entry, npages); | 
|  |  | 
|  | do { | 
|  | unsigned long num; | 
|  |  | 
|  | num = pci_sun4v_iommu_demap(devhandle, HV_PCI_TSBID(0, entry), | 
|  | npages); | 
|  | entry += num; | 
|  | npages -= num; | 
|  | } while (npages != 0); | 
|  |  | 
|  | spin_unlock_irqrestore(&iommu->lock, flags); | 
|  | } | 
|  |  | 
|  | static void pci_4v_dma_sync_single_for_cpu(struct pci_dev *pdev, dma_addr_t bus_addr, size_t sz, int direction) | 
|  | { | 
|  | /* Nothing to do... */ | 
|  | } | 
|  |  | 
|  | static void pci_4v_dma_sync_sg_for_cpu(struct pci_dev *pdev, struct scatterlist *sglist, int nelems, int direction) | 
|  | { | 
|  | /* Nothing to do... */ | 
|  | } | 
|  |  | 
|  | struct pci_iommu_ops pci_sun4v_iommu_ops = { | 
|  | .alloc_consistent		= pci_4v_alloc_consistent, | 
|  | .free_consistent		= pci_4v_free_consistent, | 
|  | .map_single			= pci_4v_map_single, | 
|  | .unmap_single			= pci_4v_unmap_single, | 
|  | .map_sg				= pci_4v_map_sg, | 
|  | .unmap_sg			= pci_4v_unmap_sg, | 
|  | .dma_sync_single_for_cpu	= pci_4v_dma_sync_single_for_cpu, | 
|  | .dma_sync_sg_for_cpu		= pci_4v_dma_sync_sg_for_cpu, | 
|  | }; | 
|  |  | 
|  | /* SUN4V PCI configuration space accessors. */ | 
|  |  | 
|  | struct pdev_entry { | 
|  | struct pdev_entry	*next; | 
|  | u32			devhandle; | 
|  | unsigned int		bus; | 
|  | unsigned int		device; | 
|  | unsigned int		func; | 
|  | }; | 
|  |  | 
|  | #define PDEV_HTAB_SIZE	16 | 
|  | #define PDEV_HTAB_MASK	(PDEV_HTAB_SIZE - 1) | 
|  | static struct pdev_entry *pdev_htab[PDEV_HTAB_SIZE]; | 
|  |  | 
|  | static inline unsigned int pdev_hashfn(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) | 
|  | { | 
|  | unsigned int val; | 
|  |  | 
|  | val = (devhandle ^ (devhandle >> 4)); | 
|  | val ^= bus; | 
|  | val ^= device; | 
|  | val ^= func; | 
|  |  | 
|  | return val & PDEV_HTAB_MASK; | 
|  | } | 
|  |  | 
|  | static int pdev_htab_add(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) | 
|  | { | 
|  | struct pdev_entry *p = kmalloc(sizeof(*p), GFP_KERNEL); | 
|  | struct pdev_entry **slot; | 
|  |  | 
|  | if (!p) | 
|  | return -ENOMEM; | 
|  |  | 
|  | slot = &pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; | 
|  | p->next = *slot; | 
|  | *slot = p; | 
|  |  | 
|  | p->devhandle = devhandle; | 
|  | p->bus = bus; | 
|  | p->device = device; | 
|  | p->func = func; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Recursively descend into the OBP device tree, rooted at toplevel_node, | 
|  | * looking for a PCI device matching bus and devfn. | 
|  | */ | 
|  | static int obp_find(struct device_node *toplevel_node, unsigned int bus, unsigned int devfn) | 
|  | { | 
|  | toplevel_node = toplevel_node->child; | 
|  |  | 
|  | while (toplevel_node != NULL) { | 
|  | struct linux_prom_pci_registers *regs; | 
|  | struct property *prop; | 
|  | int ret; | 
|  |  | 
|  | ret = obp_find(toplevel_node, bus, devfn); | 
|  | if (ret != 0) | 
|  | return ret; | 
|  |  | 
|  | prop = of_find_property(toplevel_node, "reg", NULL); | 
|  | if (!prop) | 
|  | goto next_sibling; | 
|  |  | 
|  | regs = prop->value; | 
|  | if (((regs->phys_hi >> 16) & 0xff) == bus && | 
|  | ((regs->phys_hi >> 8) & 0xff) == devfn) | 
|  | break; | 
|  |  | 
|  | next_sibling: | 
|  | toplevel_node = toplevel_node->sibling; | 
|  | } | 
|  |  | 
|  | return toplevel_node != NULL; | 
|  | } | 
|  |  | 
|  | static int pdev_htab_populate(struct pci_pbm_info *pbm) | 
|  | { | 
|  | u32 devhandle = pbm->devhandle; | 
|  | unsigned int bus; | 
|  |  | 
|  | for (bus = pbm->pci_first_busno; bus <= pbm->pci_last_busno; bus++) { | 
|  | unsigned int devfn; | 
|  |  | 
|  | for (devfn = 0; devfn < 256; devfn++) { | 
|  | unsigned int device = PCI_SLOT(devfn); | 
|  | unsigned int func = PCI_FUNC(devfn); | 
|  |  | 
|  | if (obp_find(pbm->prom_node, bus, devfn)) { | 
|  | int err = pdev_htab_add(devhandle, bus, | 
|  | device, func); | 
|  | if (err) | 
|  | return err; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static struct pdev_entry *pdev_find(u32 devhandle, unsigned int bus, unsigned int device, unsigned int func) | 
|  | { | 
|  | struct pdev_entry *p; | 
|  |  | 
|  | p = pdev_htab[pdev_hashfn(devhandle, bus, device, func)]; | 
|  | while (p) { | 
|  | if (p->devhandle == devhandle && | 
|  | p->bus == bus && | 
|  | p->device == device && | 
|  | p->func == func) | 
|  | break; | 
|  |  | 
|  | p = p->next; | 
|  | } | 
|  |  | 
|  | return p; | 
|  | } | 
|  |  | 
|  | static inline int pci_sun4v_out_of_range(struct pci_pbm_info *pbm, unsigned int bus, unsigned int device, unsigned int func) | 
|  | { | 
|  | if (bus < pbm->pci_first_busno || | 
|  | bus > pbm->pci_last_busno) | 
|  | return 1; | 
|  | return pdev_find(pbm->devhandle, bus, device, func) == NULL; | 
|  | } | 
|  |  | 
|  | static int pci_sun4v_read_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 
|  | int where, int size, u32 *value) | 
|  | { | 
|  | struct pci_pbm_info *pbm = bus_dev->sysdata; | 
|  | u32 devhandle = pbm->devhandle; | 
|  | unsigned int bus = bus_dev->number; | 
|  | unsigned int device = PCI_SLOT(devfn); | 
|  | unsigned int func = PCI_FUNC(devfn); | 
|  | unsigned long ret; | 
|  |  | 
|  | if (pci_sun4v_out_of_range(pbm, bus, device, func)) { | 
|  | ret = ~0UL; | 
|  | } else { | 
|  | ret = pci_sun4v_config_get(devhandle, | 
|  | HV_PCI_DEVICE_BUILD(bus, device, func), | 
|  | where, size); | 
|  | #if 0 | 
|  | printk("rcfg: [%x:%x:%x:%d]=[%lx]\n", | 
|  | devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), | 
|  | where, size, ret); | 
|  | #endif | 
|  | } | 
|  | switch (size) { | 
|  | case 1: | 
|  | *value = ret & 0xff; | 
|  | break; | 
|  | case 2: | 
|  | *value = ret & 0xffff; | 
|  | break; | 
|  | case 4: | 
|  | *value = ret & 0xffffffff; | 
|  | break; | 
|  | }; | 
|  |  | 
|  |  | 
|  | return PCIBIOS_SUCCESSFUL; | 
|  | } | 
|  |  | 
|  | static int pci_sun4v_write_pci_cfg(struct pci_bus *bus_dev, unsigned int devfn, | 
|  | int where, int size, u32 value) | 
|  | { | 
|  | struct pci_pbm_info *pbm = bus_dev->sysdata; | 
|  | u32 devhandle = pbm->devhandle; | 
|  | unsigned int bus = bus_dev->number; | 
|  | unsigned int device = PCI_SLOT(devfn); | 
|  | unsigned int func = PCI_FUNC(devfn); | 
|  | unsigned long ret; | 
|  |  | 
|  | if (pci_sun4v_out_of_range(pbm, bus, device, func)) { | 
|  | /* Do nothing. */ | 
|  | } else { | 
|  | ret = pci_sun4v_config_put(devhandle, | 
|  | HV_PCI_DEVICE_BUILD(bus, device, func), | 
|  | where, size, value); | 
|  | #if 0 | 
|  | printk("wcfg: [%x:%x:%x:%d] v[%x] == [%lx]\n", | 
|  | devhandle, HV_PCI_DEVICE_BUILD(bus, device, func), | 
|  | where, size, value, ret); | 
|  | #endif | 
|  | } | 
|  | return PCIBIOS_SUCCESSFUL; | 
|  | } | 
|  |  | 
|  | static struct pci_ops pci_sun4v_ops = { | 
|  | .read =		pci_sun4v_read_pci_cfg, | 
|  | .write =	pci_sun4v_write_pci_cfg, | 
|  | }; | 
|  |  | 
|  |  | 
|  | static void pbm_scan_bus(struct pci_controller_info *p, | 
|  | struct pci_pbm_info *pbm) | 
|  | { | 
|  | struct pcidev_cookie *cookie = kmalloc(sizeof(*cookie), GFP_KERNEL); | 
|  |  | 
|  | if (!cookie) { | 
|  | prom_printf("%s: Critical allocation failure.\n", pbm->name); | 
|  | prom_halt(); | 
|  | } | 
|  |  | 
|  | /* All we care about is the PBM. */ | 
|  | memset(cookie, 0, sizeof(*cookie)); | 
|  | cookie->pbm = pbm; | 
|  |  | 
|  | pbm->pci_bus = pci_scan_bus(pbm->pci_first_busno, p->pci_ops, pbm); | 
|  | #if 0 | 
|  | pci_fixup_host_bridge_self(pbm->pci_bus); | 
|  | pbm->pci_bus->self->sysdata = cookie; | 
|  | #endif | 
|  | pci_fill_in_pbm_cookies(pbm->pci_bus, pbm, pbm->prom_node); | 
|  | pci_record_assignments(pbm, pbm->pci_bus); | 
|  | pci_assign_unassigned(pbm, pbm->pci_bus); | 
|  | pci_fixup_irq(pbm, pbm->pci_bus); | 
|  | pci_determine_66mhz_disposition(pbm, pbm->pci_bus); | 
|  | pci_setup_busmastering(pbm, pbm->pci_bus); | 
|  | } | 
|  |  | 
|  | static void pci_sun4v_scan_bus(struct pci_controller_info *p) | 
|  | { | 
|  | struct property *prop; | 
|  | struct device_node *dp; | 
|  |  | 
|  | if ((dp = p->pbm_A.prom_node) != NULL) { | 
|  | prop = of_find_property(dp, "66mhz-capable", NULL); | 
|  | p->pbm_A.is_66mhz_capable = (prop != NULL); | 
|  |  | 
|  | pbm_scan_bus(p, &p->pbm_A); | 
|  | } | 
|  | if ((dp = p->pbm_B.prom_node) != NULL) { | 
|  | prop = of_find_property(dp, "66mhz-capable", NULL); | 
|  | p->pbm_B.is_66mhz_capable = (prop != NULL); | 
|  |  | 
|  | pbm_scan_bus(p, &p->pbm_B); | 
|  | } | 
|  |  | 
|  | /* XXX register error interrupt handlers XXX */ | 
|  | } | 
|  |  | 
|  | static void pci_sun4v_base_address_update(struct pci_dev *pdev, int resource) | 
|  | { | 
|  | struct pcidev_cookie *pcp = pdev->sysdata; | 
|  | struct pci_pbm_info *pbm = pcp->pbm; | 
|  | struct resource *res, *root; | 
|  | u32 reg; | 
|  | int where, size, is_64bit; | 
|  |  | 
|  | res = &pdev->resource[resource]; | 
|  | if (resource < 6) { | 
|  | where = PCI_BASE_ADDRESS_0 + (resource * 4); | 
|  | } else if (resource == PCI_ROM_RESOURCE) { | 
|  | where = pdev->rom_base_reg; | 
|  | } else { | 
|  | /* Somebody might have asked allocation of a non-standard resource */ | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* XXX 64-bit MEM handling is not %100 correct... XXX */ | 
|  | is_64bit = 0; | 
|  | if (res->flags & IORESOURCE_IO) | 
|  | root = &pbm->io_space; | 
|  | else { | 
|  | root = &pbm->mem_space; | 
|  | if ((res->flags & PCI_BASE_ADDRESS_MEM_TYPE_MASK) | 
|  | == PCI_BASE_ADDRESS_MEM_TYPE_64) | 
|  | is_64bit = 1; | 
|  | } | 
|  |  | 
|  | size = res->end - res->start; | 
|  | pci_read_config_dword(pdev, where, ®); | 
|  | reg = ((reg & size) | | 
|  | (((u32)(res->start - root->start)) & ~size)); | 
|  | if (resource == PCI_ROM_RESOURCE) { | 
|  | reg |= PCI_ROM_ADDRESS_ENABLE; | 
|  | res->flags |= IORESOURCE_ROM_ENABLE; | 
|  | } | 
|  | pci_write_config_dword(pdev, where, reg); | 
|  |  | 
|  | /* This knows that the upper 32-bits of the address | 
|  | * must be zero.  Our PCI common layer enforces this. | 
|  | */ | 
|  | if (is_64bit) | 
|  | pci_write_config_dword(pdev, where + 4, 0); | 
|  | } | 
|  |  | 
|  | static void pci_sun4v_resource_adjust(struct pci_dev *pdev, | 
|  | struct resource *res, | 
|  | struct resource *root) | 
|  | { | 
|  | res->start += root->start; | 
|  | res->end += root->start; | 
|  | } | 
|  |  | 
|  | /* Use ranges property to determine where PCI MEM, I/O, and Config | 
|  | * space are for this PCI bus module. | 
|  | */ | 
|  | static void pci_sun4v_determine_mem_io_space(struct pci_pbm_info *pbm) | 
|  | { | 
|  | int i, saw_mem, saw_io; | 
|  |  | 
|  | saw_mem = saw_io = 0; | 
|  | for (i = 0; i < pbm->num_pbm_ranges; i++) { | 
|  | struct linux_prom_pci_ranges *pr = &pbm->pbm_ranges[i]; | 
|  | unsigned long a; | 
|  | int type; | 
|  |  | 
|  | type = (pr->child_phys_hi >> 24) & 0x3; | 
|  | a = (((unsigned long)pr->parent_phys_hi << 32UL) | | 
|  | ((unsigned long)pr->parent_phys_lo  <<  0UL)); | 
|  |  | 
|  | switch (type) { | 
|  | case 1: | 
|  | /* 16-bit IO space, 16MB */ | 
|  | pbm->io_space.start = a; | 
|  | pbm->io_space.end = a + ((16UL*1024UL*1024UL) - 1UL); | 
|  | pbm->io_space.flags = IORESOURCE_IO; | 
|  | saw_io = 1; | 
|  | break; | 
|  |  | 
|  | case 2: | 
|  | /* 32-bit MEM space, 2GB */ | 
|  | pbm->mem_space.start = a; | 
|  | pbm->mem_space.end = a + (0x80000000UL - 1UL); | 
|  | pbm->mem_space.flags = IORESOURCE_MEM; | 
|  | saw_mem = 1; | 
|  | break; | 
|  |  | 
|  | case 3: | 
|  | /* XXX 64-bit MEM handling XXX */ | 
|  |  | 
|  | default: | 
|  | break; | 
|  | }; | 
|  | } | 
|  |  | 
|  | if (!saw_io || !saw_mem) { | 
|  | prom_printf("%s: Fatal error, missing %s PBM range.\n", | 
|  | pbm->name, | 
|  | (!saw_io ? "IO" : "MEM")); | 
|  | prom_halt(); | 
|  | } | 
|  |  | 
|  | printk("%s: PCI IO[%lx] MEM[%lx]\n", | 
|  | pbm->name, | 
|  | pbm->io_space.start, | 
|  | pbm->mem_space.start); | 
|  | } | 
|  |  | 
|  | static void pbm_register_toplevel_resources(struct pci_controller_info *p, | 
|  | struct pci_pbm_info *pbm) | 
|  | { | 
|  | pbm->io_space.name = pbm->mem_space.name = pbm->name; | 
|  |  | 
|  | request_resource(&ioport_resource, &pbm->io_space); | 
|  | request_resource(&iomem_resource, &pbm->mem_space); | 
|  | pci_register_legacy_regions(&pbm->io_space, | 
|  | &pbm->mem_space); | 
|  | } | 
|  |  | 
|  | static unsigned long probe_existing_entries(struct pci_pbm_info *pbm, | 
|  | struct pci_iommu *iommu) | 
|  | { | 
|  | struct pci_iommu_arena *arena = &iommu->arena; | 
|  | unsigned long i, cnt = 0; | 
|  | u32 devhandle; | 
|  |  | 
|  | devhandle = pbm->devhandle; | 
|  | for (i = 0; i < arena->limit; i++) { | 
|  | unsigned long ret, io_attrs, ra; | 
|  |  | 
|  | ret = pci_sun4v_iommu_getmap(devhandle, | 
|  | HV_PCI_TSBID(0, i), | 
|  | &io_attrs, &ra); | 
|  | if (ret == HV_EOK) { | 
|  | if (page_in_phys_avail(ra)) { | 
|  | pci_sun4v_iommu_demap(devhandle, | 
|  | HV_PCI_TSBID(0, i), 1); | 
|  | } else { | 
|  | cnt++; | 
|  | __set_bit(i, arena->map); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return cnt; | 
|  | } | 
|  |  | 
|  | static void pci_sun4v_iommu_init(struct pci_pbm_info *pbm) | 
|  | { | 
|  | struct pci_iommu *iommu = pbm->iommu; | 
|  | struct property *prop; | 
|  | unsigned long num_tsb_entries, sz; | 
|  | u32 vdma[2], dma_mask, dma_offset; | 
|  | int tsbsize; | 
|  |  | 
|  | prop = of_find_property(pbm->prom_node, "virtual-dma", NULL); | 
|  | if (prop) { | 
|  | u32 *val = prop->value; | 
|  |  | 
|  | vdma[0] = val[0]; | 
|  | vdma[1] = val[1]; | 
|  | } else { | 
|  | /* No property, use default values. */ | 
|  | vdma[0] = 0x80000000; | 
|  | vdma[1] = 0x80000000; | 
|  | } | 
|  |  | 
|  | dma_mask = vdma[0]; | 
|  | switch (vdma[1]) { | 
|  | case 0x20000000: | 
|  | dma_mask |= 0x1fffffff; | 
|  | tsbsize = 64; | 
|  | break; | 
|  |  | 
|  | case 0x40000000: | 
|  | dma_mask |= 0x3fffffff; | 
|  | tsbsize = 128; | 
|  | break; | 
|  |  | 
|  | case 0x80000000: | 
|  | dma_mask |= 0x7fffffff; | 
|  | tsbsize = 256; | 
|  | break; | 
|  |  | 
|  | default: | 
|  | prom_printf("PCI-SUN4V: strange virtual-dma size.\n"); | 
|  | prom_halt(); | 
|  | }; | 
|  |  | 
|  | tsbsize *= (8 * 1024); | 
|  |  | 
|  | num_tsb_entries = tsbsize / sizeof(iopte_t); | 
|  |  | 
|  | dma_offset = vdma[0]; | 
|  |  | 
|  | /* Setup initial software IOMMU state. */ | 
|  | spin_lock_init(&iommu->lock); | 
|  | iommu->ctx_lowest_free = 1; | 
|  | iommu->page_table_map_base = dma_offset; | 
|  | iommu->dma_addr_mask = dma_mask; | 
|  |  | 
|  | /* Allocate and initialize the free area map.  */ | 
|  | sz = num_tsb_entries / 8; | 
|  | sz = (sz + 7UL) & ~7UL; | 
|  | iommu->arena.map = kmalloc(sz, GFP_KERNEL); | 
|  | if (!iommu->arena.map) { | 
|  | prom_printf("PCI_IOMMU: Error, kmalloc(arena.map) failed.\n"); | 
|  | prom_halt(); | 
|  | } | 
|  | memset(iommu->arena.map, 0, sz); | 
|  | iommu->arena.limit = num_tsb_entries; | 
|  |  | 
|  | sz = probe_existing_entries(pbm, iommu); | 
|  | if (sz) | 
|  | printk("%s: Imported %lu TSB entries from OBP\n", | 
|  | pbm->name, sz); | 
|  | } | 
|  |  | 
|  | static void pci_sun4v_get_bus_range(struct pci_pbm_info *pbm) | 
|  | { | 
|  | struct property *prop; | 
|  | unsigned int *busrange; | 
|  |  | 
|  | prop = of_find_property(pbm->prom_node, "bus-range", NULL); | 
|  |  | 
|  | busrange = prop->value; | 
|  |  | 
|  | pbm->pci_first_busno = busrange[0]; | 
|  | pbm->pci_last_busno = busrange[1]; | 
|  |  | 
|  | } | 
|  |  | 
|  | static void pci_sun4v_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 devhandle) | 
|  | { | 
|  | struct pci_pbm_info *pbm; | 
|  | struct property *prop; | 
|  | int len, i; | 
|  |  | 
|  | if (devhandle & 0x40) | 
|  | pbm = &p->pbm_B; | 
|  | else | 
|  | pbm = &p->pbm_A; | 
|  |  | 
|  | pbm->parent = p; | 
|  | pbm->prom_node = dp; | 
|  | pbm->pci_first_slot = 1; | 
|  |  | 
|  | pbm->devhandle = devhandle; | 
|  |  | 
|  | pbm->name = dp->full_name; | 
|  |  | 
|  | printk("%s: SUN4V PCI Bus Module\n", pbm->name); | 
|  |  | 
|  | prop = of_find_property(dp, "ranges", &len); | 
|  | pbm->pbm_ranges = prop->value; | 
|  | pbm->num_pbm_ranges = | 
|  | (len / sizeof(struct linux_prom_pci_ranges)); | 
|  |  | 
|  | /* Mask out the top 8 bits of the ranges, leaving the real | 
|  | * physical address. | 
|  | */ | 
|  | for (i = 0; i < pbm->num_pbm_ranges; i++) | 
|  | pbm->pbm_ranges[i].parent_phys_hi &= 0x0fffffff; | 
|  |  | 
|  | pci_sun4v_determine_mem_io_space(pbm); | 
|  | pbm_register_toplevel_resources(p, pbm); | 
|  |  | 
|  | prop = of_find_property(dp, "interrupt-map", &len); | 
|  | pbm->pbm_intmap = prop->value; | 
|  | pbm->num_pbm_intmap = | 
|  | (len / sizeof(struct linux_prom_pci_intmap)); | 
|  |  | 
|  | prop = of_find_property(dp, "interrupt-map-mask", NULL); | 
|  | pbm->pbm_intmask = prop->value; | 
|  |  | 
|  | pci_sun4v_get_bus_range(pbm); | 
|  | pci_sun4v_iommu_init(pbm); | 
|  |  | 
|  | pdev_htab_populate(pbm); | 
|  | } | 
|  |  | 
|  | void sun4v_pci_init(struct device_node *dp, char *model_name) | 
|  | { | 
|  | struct pci_controller_info *p; | 
|  | struct pci_iommu *iommu; | 
|  | struct property *prop; | 
|  | struct linux_prom64_registers *regs; | 
|  | u32 devhandle; | 
|  | int i; | 
|  |  | 
|  | prop = of_find_property(dp, "reg", NULL); | 
|  | regs = prop->value; | 
|  |  | 
|  | devhandle = (regs->phys_addr >> 32UL) & 0x0fffffff; | 
|  |  | 
|  | for (p = pci_controller_root; p; p = p->next) { | 
|  | struct pci_pbm_info *pbm; | 
|  |  | 
|  | if (p->pbm_A.prom_node && p->pbm_B.prom_node) | 
|  | continue; | 
|  |  | 
|  | pbm = (p->pbm_A.prom_node ? | 
|  | &p->pbm_A : | 
|  | &p->pbm_B); | 
|  |  | 
|  | if (pbm->devhandle == (devhandle ^ 0x40)) { | 
|  | pci_sun4v_pbm_init(p, dp, devhandle); | 
|  | return; | 
|  | } | 
|  | } | 
|  |  | 
|  | for_each_possible_cpu(i) { | 
|  | unsigned long page = get_zeroed_page(GFP_ATOMIC); | 
|  |  | 
|  | if (!page) | 
|  | goto fatal_memory_error; | 
|  |  | 
|  | per_cpu(pci_iommu_batch, i).pglist = (u64 *) page; | 
|  | } | 
|  |  | 
|  | p = kmalloc(sizeof(struct pci_controller_info), GFP_ATOMIC); | 
|  | if (!p) | 
|  | goto fatal_memory_error; | 
|  |  | 
|  | memset(p, 0, sizeof(*p)); | 
|  |  | 
|  | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | 
|  | if (!iommu) | 
|  | goto fatal_memory_error; | 
|  |  | 
|  | memset(iommu, 0, sizeof(*iommu)); | 
|  | p->pbm_A.iommu = iommu; | 
|  |  | 
|  | iommu = kmalloc(sizeof(struct pci_iommu), GFP_ATOMIC); | 
|  | if (!iommu) | 
|  | goto fatal_memory_error; | 
|  |  | 
|  | memset(iommu, 0, sizeof(*iommu)); | 
|  | p->pbm_B.iommu = iommu; | 
|  |  | 
|  | p->next = pci_controller_root; | 
|  | pci_controller_root = p; | 
|  |  | 
|  | p->index = pci_num_controllers++; | 
|  | p->pbms_same_domain = 0; | 
|  |  | 
|  | p->scan_bus = pci_sun4v_scan_bus; | 
|  | p->base_address_update = pci_sun4v_base_address_update; | 
|  | p->resource_adjust = pci_sun4v_resource_adjust; | 
|  | p->pci_ops = &pci_sun4v_ops; | 
|  |  | 
|  | /* Like PSYCHO and SCHIZO we have a 2GB aligned area | 
|  | * for memory space. | 
|  | */ | 
|  | pci_memspace_mask = 0x7fffffffUL; | 
|  |  | 
|  | pci_sun4v_pbm_init(p, dp, devhandle); | 
|  | return; | 
|  |  | 
|  | fatal_memory_error: | 
|  | prom_printf("SUN4V_PCI: Fatal memory allocation error.\n"); | 
|  | prom_halt(); | 
|  | } |