static void copy_val(u32 *dest, u32 *src, int naddr)
{
- memset(dest, 0, (MAX_ADDR_CELLS - naddr) * 4);
- memcpy(dest, src, naddr * 4);
+ int pad = MAX_ADDR_CELLS - naddr;
+
+ memset(dest, 0, pad * 4);
+ memcpy(dest + pad, src, naddr * 4);
}
static int sub_reg(u32 *reg, u32 *sub)
{
int i, borrow = 0;
- for (i = 0; i < MAX_ADDR_CELLS; i++) {
+ for (i = MAX_ADDR_CELLS - 1; i >= 0; i--) {
int prev_borrow = borrow;
borrow = reg[i] < sub[i] + prev_borrow;
reg[i] -= sub[i] + prev_borrow;
return !borrow;
}
-static int add_reg(u32 *reg, u32 *add)
+static int add_reg(u32 *reg, u32 *add, int naddr)
{
int i, carry = 0;
- for (i = 0; i < MAX_ADDR_CELLS; i++) {
+ for (i = MAX_ADDR_CELLS - 1; i >= MAX_ADDR_CELLS - naddr; i--) {
u64 tmp = (u64)reg[i] + add[i] + carry;
carry = tmp >> 32;
reg[i] = (u32)tmp;
* In particular, PCI is not supported. Also, only the beginning of the
* reg block is tracked; size is ignored except in ranges.
*/
-int dt_xlate_reg(void *node, int res, unsigned long *addr,
- unsigned long *size)
+static u32 dt_xlate_buf[MAX_ADDR_CELLS * MAX_RANGES * 3];
+
+static int dt_xlate(void *node, int res, int reglen, unsigned long *addr,
+ unsigned long *size)
{
u32 last_addr[MAX_ADDR_CELLS];
u32 this_addr[MAX_ADDR_CELLS];
- u32 buf[MAX_ADDR_CELLS * MAX_RANGES * 3];
void *parent;
u64 ret_addr, ret_size;
u32 naddr, nsize, prev_naddr;
if (nsize > 2)
return 0;
- buflen = getprop(node, "reg", buf, sizeof(buf)) / 4;
offset = (naddr + nsize) * res;
- if (buflen < offset + naddr + nsize)
+ if (reglen < offset + naddr + nsize ||
+ sizeof(dt_xlate_buf) < offset + naddr + nsize)
return 0;
- copy_val(last_addr, buf + offset, naddr);
+ copy_val(last_addr, dt_xlate_buf + offset, naddr);
- ret_size = buf[offset + naddr];
+ ret_size = dt_xlate_buf[offset + naddr];
if (nsize == 2) {
ret_size <<= 32;
- ret_size |= buf[offset + naddr + 1];
+ ret_size |= dt_xlate_buf[offset + naddr + 1];
}
while ((node = get_parent(node))) {
get_reg_format(node, &naddr, &nsize);
- buflen = getprop(node, "ranges", buf, sizeof(buf));
+ buflen = getprop(node, "ranges", dt_xlate_buf,
+ sizeof(dt_xlate_buf));
if (buflen < 0)
continue;
- if (buflen > sizeof(buf))
+ if (buflen > sizeof(dt_xlate_buf))
return 0;
- offset = find_range(last_addr, buf, prev_naddr,
+ offset = find_range(last_addr, dt_xlate_buf, prev_naddr,
naddr, nsize, buflen / 4);
if (offset < 0)
return 0;
- copy_val(this_addr, buf + offset, prev_naddr);
+ copy_val(this_addr, dt_xlate_buf + offset, prev_naddr);
if (!sub_reg(last_addr, this_addr))
return 0;
- copy_val(this_addr, buf + offset + prev_naddr, naddr);
+ copy_val(this_addr, dt_xlate_buf + offset + prev_naddr, naddr);
- if (!add_reg(last_addr, this_addr))
+ if (!add_reg(last_addr, this_addr, naddr))
return 0;
}
if (naddr > 2)
return 0;
- ret_addr = last_addr[0];
- if (naddr == 2) {
- ret_addr <<= 32;
- ret_addr |= last_addr[1];
- }
+ ret_addr = ((u64)last_addr[2] << 32) | last_addr[3];
if (sizeof(void *) == 4 &&
(ret_addr >= 0x100000000ULL || ret_size > 0x100000000ULL ||
return 1;
}
+
+int dt_xlate_reg(void *node, int res, unsigned long *addr, unsigned long *size)
+{
+ int reglen;
+
+ reglen = getprop(node, "reg", dt_xlate_buf, sizeof(dt_xlate_buf)) / 4;
+ return dt_xlate(node, res, reglen, addr, size);
+}
+
+int dt_xlate_addr(void *node, u32 *buf, int buflen, unsigned long *xlated_addr)
+{
+
+ if (buflen > sizeof(dt_xlate_buf))
+ return 0;
+
+ memcpy(dt_xlate_buf, buf, buflen);
+ return dt_xlate(node, 0, buflen / 4, xlated_addr, NULL);
+}