Replace phys_to_dma()/dma_to_phys() looping algorithm with an O(1) algorithm The approach taken is inspired by the sparse memory implementation: take a certain number of high-order bits off the address them, use this as an index into a table containing an offset to the desired address and add it to the original value. There is a table for mapping physical addresses to DMA addresses and another one for the reverse mapping. The table sizes depend on how fine-grained the mappings need to be; Coarser granularity less to smaller tables. On a processor with 32-bit physical and DMA addresses, with 4 MIB granularity, memory usage is two 2048-byte arrays. Each 32-byte cache line thus covers 64 MiB of address space. Also, renames phys_to_bus() to phys_to_dma() and bus_to_phys() to dma_to_phys() to align with kernel usage. [Ralf: Fixed silly build breakage due to stackoverflow warning caused by huge array on stack.] Signed-off-by: David VomLehn <dvomlehn@cisco.com> To: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/1257/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>tirimbino
parent
36f217d9df
commit
ca36c36b78
@ -0,0 +1,136 @@ |
||||
/*
|
||||
* ioremap.c |
||||
* |
||||
* Support for mapping between dma_addr_t values a phys_addr_t values. |
||||
* |
||||
* Copyright (C) 2005-2009 Scientific-Atlanta, Inc. |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
||||
* |
||||
* Author: David VomLehn <dvomlehn@cisco.com> |
||||
* |
||||
* Description: Defines the platform resources for the SA settop. |
||||
* |
||||
* NOTE: The bootloader allocates persistent memory at an address which is |
||||
* 16 MiB below the end of the highest address in KSEG0. All fixed |
||||
* address memory reservations must avoid this region. |
||||
*/ |
||||
|
||||
#include <linux/kernel.h> |
||||
#include <linux/module.h> |
||||
|
||||
#include <asm/mach-powertv/ioremap.h> |
||||
|
||||
/*
|
||||
* Define the sizes of and masks for grains in physical and DMA space. The |
||||
* values are the same but the types are not. |
||||
*/ |
||||
#define IOR_PHYS_GRAIN ((phys_addr_t) 1 << IOR_LSBITS) |
||||
#define IOR_PHYS_GRAIN_MASK (IOR_PHYS_GRAIN - 1) |
||||
|
||||
#define IOR_DMA_GRAIN ((dma_addr_t) 1 << IOR_LSBITS) |
||||
#define IOR_DMA_GRAIN_MASK (IOR_DMA_GRAIN - 1) |
||||
|
||||
/*
|
||||
* Values that, when accessed by an index derived from a phys_addr_t and |
||||
* added to phys_addr_t value, yield a DMA address |
||||
*/ |
||||
struct ior_phys_to_dma _ior_phys_to_dma[IOR_NUM_PHYS_TO_DMA]; |
||||
EXPORT_SYMBOL(_ior_phys_to_dma); |
||||
|
||||
/*
|
||||
* Values that, when accessed by an index derived from a dma_addr_t and |
||||
* added to that dma_addr_t value, yield a physical address |
||||
*/ |
||||
struct ior_dma_to_phys _ior_dma_to_phys[IOR_NUM_DMA_TO_PHYS]; |
||||
EXPORT_SYMBOL(_ior_dma_to_phys); |
||||
|
||||
/**
|
||||
* setup_dma_to_phys - set up conversion from DMA to physical addresses |
||||
* @dma_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index |
||||
* into the array _dma_to_phys. |
||||
* @delta: Value that, when added to the DMA address, will yield the |
||||
* physical address |
||||
* @s: Number of bytes in the section of memory with the given delta |
||||
* between DMA and physical addresses. |
||||
*/ |
||||
static void setup_dma_to_phys(dma_addr_t dma, phys_addr_t delta, dma_addr_t s) |
||||
{ |
||||
int dma_idx, first_idx, last_idx; |
||||
phys_addr_t first, last; |
||||
|
||||
/*
|
||||
* Calculate the first and last indices, rounding the first up and |
||||
* the second down. |
||||
*/ |
||||
first = dma & ~IOR_DMA_GRAIN_MASK; |
||||
last = (dma + s - 1) & ~IOR_DMA_GRAIN_MASK; |
||||
first_idx = first >> IOR_LSBITS; /* Convert to indices */ |
||||
last_idx = last >> IOR_LSBITS; |
||||
|
||||
for (dma_idx = first_idx; dma_idx <= last_idx; dma_idx++) |
||||
_ior_dma_to_phys[dma_idx].offset = delta >> IOR_DMA_SHIFT; |
||||
} |
||||
|
||||
/**
|
||||
* setup_phys_to_dma - set up conversion from DMA to physical addresses |
||||
* @phys_idx: Top IOR_LSBITS bits of the DMA address, i.e. an index |
||||
* into the array _phys_to_dma. |
||||
* @delta: Value that, when added to the DMA address, will yield the |
||||
* physical address |
||||
* @s: Number of bytes in the section of memory with the given delta |
||||
* between DMA and physical addresses. |
||||
*/ |
||||
static void setup_phys_to_dma(phys_addr_t phys, dma_addr_t delta, phys_addr_t s) |
||||
{ |
||||
int phys_idx, first_idx, last_idx; |
||||
phys_addr_t first, last; |
||||
|
||||
/*
|
||||
* Calculate the first and last indices, rounding the first up and |
||||
* the second down. |
||||
*/ |
||||
first = phys & ~IOR_PHYS_GRAIN_MASK; |
||||
last = (phys + s - 1) & ~IOR_PHYS_GRAIN_MASK; |
||||
first_idx = first >> IOR_LSBITS; /* Convert to indices */ |
||||
last_idx = last >> IOR_LSBITS; |
||||
|
||||
for (phys_idx = first_idx; phys_idx <= last_idx; phys_idx++) |
||||
_ior_phys_to_dma[phys_idx].offset = delta >> IOR_PHYS_SHIFT; |
||||
} |
||||
|
||||
/**
|
||||
* ioremap_add_map - add to the physical and DMA address conversion arrays |
||||
* @phys: Process's view of the address of the start of the memory chunk |
||||
* @dma: DMA address of the start of the memory chunk |
||||
* @size: Size, in bytes, of the chunk of memory |
||||
* |
||||
* NOTE: It might be obvious, but the assumption is that all @size bytes have |
||||
* the same offset between the physical address and the DMA address. |
||||
*/ |
||||
void ioremap_add_map(phys_addr_t phys, phys_addr_t dma, phys_addr_t size) |
||||
{ |
||||
if (size == 0) |
||||
return; |
||||
|
||||
if ((dma & IOR_DMA_GRAIN_MASK) != 0 || |
||||
(phys & IOR_PHYS_GRAIN_MASK) != 0 || |
||||
(size & IOR_PHYS_GRAIN_MASK) != 0) |
||||
pr_crit("Memory allocation must be in chunks of 0x%x bytes\n", |
||||
IOR_PHYS_GRAIN); |
||||
|
||||
setup_dma_to_phys(dma, phys - dma, size); |
||||
setup_phys_to_dma(phys, dma - phys, size); |
||||
} |
Loading…
Reference in new issue