/* * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive * for more details. * * Copyright (C) 2001-2003 Silicon Graphics, Inc. All rights reserved. */ #include #include #include #include #include #include /* * functions */ int pcibr_ate_alloc(pcibr_soft_t, int, struct resource *); void pcibr_ate_free(pcibr_soft_t, int, int, struct resource *); bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t, unsigned); bridge_ate_p pcibr_ate_addr(pcibr_soft_t, int); void ate_write(pcibr_soft_t, int, int, bridge_ate_t); int pcibr_invalidate_ate; /* by default don't invalidate ATE on free */ /* * Allocate "count" contiguous Bridge Address Translation Entries * on the specified bridge to be used for PCI to XTALK mappings. * Indices in rm map range from 1..num_entries. Indicies returned * to caller range from 0..num_entries-1. * * Return the start index on success, -1 on failure. */ int pcibr_ate_alloc(pcibr_soft_t pcibr_soft, int count, struct resource *res) { int status = 0; unsigned long flag; memset(res, 0, sizeof(struct resource)); flag = pcibr_lock(pcibr_soft); status = allocate_resource( &pcibr_soft->bs_int_ate_resource, res, count, pcibr_soft->bs_int_ate_resource.start, pcibr_soft->bs_int_ate_resource.end, 1, NULL, NULL); if (status) { /* Failed to allocate */ pcibr_unlock(pcibr_soft, flag); return -1; } /* Save the resource for freeing */ pcibr_unlock(pcibr_soft, flag); return res->start; } void pcibr_ate_free(pcibr_soft_t pcibr_soft, int index, int count, struct resource *res) { bridge_ate_t ate; int status = 0; unsigned long flags; if (pcibr_invalidate_ate) { /* For debugging purposes, clear the valid bit in the ATE */ ate = *pcibr_ate_addr(pcibr_soft, index); ate_write(pcibr_soft, index, count, (ate & ~ATE_V)); } flags = pcibr_lock(pcibr_soft); status = release_resource(res); pcibr_unlock(pcibr_soft, flags); if (status) BUG(); /* Ouch .. */ } /* * Convert PCI-generic software flags and Bridge-specific software flags * into Bridge-specific Address Translation Entry attribute bits. */ bridge_ate_t pcibr_flags_to_ate(pcibr_soft_t pcibr_soft, unsigned flags) { bridge_ate_t attributes; /* default if nothing specified: * NOBARRIER * NOPREFETCH * NOPRECISE * COHERENT * Plus the valid bit */ attributes = ATE_CO | ATE_V; /* Generic macro flags */ if (flags & PCIIO_DMA_DATA) { /* standard data channel */ attributes &= ~ATE_BAR; /* no barrier */ attributes |= ATE_PREF; /* prefetch on */ } if (flags & PCIIO_DMA_CMD) { /* standard command channel */ attributes |= ATE_BAR; /* barrier bit on */ attributes &= ~ATE_PREF; /* disable prefetch */ } /* Generic detail flags */ if (flags & PCIIO_PREFETCH) attributes |= ATE_PREF; if (flags & PCIIO_NOPREFETCH) attributes &= ~ATE_PREF; /* Provider-specific flags */ if (flags & PCIBR_BARRIER) attributes |= ATE_BAR; if (flags & PCIBR_NOBARRIER) attributes &= ~ATE_BAR; if (flags & PCIBR_PREFETCH) attributes |= ATE_PREF; if (flags & PCIBR_NOPREFETCH) attributes &= ~ATE_PREF; if (flags & PCIBR_PRECISE) attributes |= ATE_PREC; if (flags & PCIBR_NOPRECISE) attributes &= ~ATE_PREC; /* In PCI-X mode, Prefetch & Precise not supported */ if (IS_PCIX(pcibr_soft)) { attributes &= ~(ATE_PREC | ATE_PREF); } return (attributes); } /* * Setup an Address Translation Entry as specified. Use either the Bridge * internal maps or the external map RAM, as appropriate. */ bridge_ate_p pcibr_ate_addr(pcibr_soft_t pcibr_soft, int ate_index) { if (ate_index < pcibr_soft->bs_int_ate_size) { return (pcireg_int_ate_addr(pcibr_soft, ate_index)); } else { printk("pcibr_ate_addr(): INVALID ate_index 0x%x", ate_index); return (bridge_ate_p)0; } } /* * Write the ATE. */ void ate_write(pcibr_soft_t pcibr_soft, int ate_index, int count, bridge_ate_t ate) { while (count-- > 0) { if (ate_index < pcibr_soft->bs_int_ate_size) { pcireg_int_ate_set(pcibr_soft, ate_index, ate); PCIBR_DEBUG((PCIBR_DEBUG_DMAMAP, pcibr_soft->bs_vhdl, "ate_write(): ate_index=0x%x, ate=0x%lx\n", ate_index, (uint64_t)ate)); } else { printk("ate_write(): INVALID ate_index 0x%x", ate_index); return; } ate_index++; ate += IOPGSIZE; } pcireg_tflush_get(pcibr_soft); /* wait until Bridge PIO complete */ }