if (verbose) \
pr_info(PFX fmt, ##__VA_ARGS__)
+#define SECTION_SIZE 0x100000
#define MAX_CACHEOP_RANGE 16384
/* assume RAM starts at phys addr 0 (this is really machine specific) */
static int do_set_cb_virt(int in_cb, int is_set, u32 addr, u32 size)
{
int count = 0, bits = 0;
- u32 desc1, desc2;
- u32 *pgtable, *cpt;
+ u32 desc1, desc2 = 0;
+ u32 *pgtable, *cpt = NULL;
u32 start, end;
+ u32 mask;
if (in_cb & WCB_C_BIT)
bits |= 8;
if (in_cb & WCB_B_BIT)
bits |= 4;
- size += addr & (PAGE_SIZE - 1);
- size = ALIGN(size, PAGE_SIZE);
+ mask = PAGE_SIZE - 1;
+ size += addr & mask;
+ size = (size + mask) & ~mask;
addr &= ~(PAGE_SIZE - 1);
start = addr;
pgtable = get_pgtable();
- for (; addr < end; addr += PAGE_SIZE)
+ while (addr < end)
{
desc1 = pgtable[addr >> 20];
- if ((desc1 & 3) != 1) {
- printk(KERN_WARNING PFX "not coarse table? %08x %08x\n", desc1, addr);
+ switch (desc1 & 3) {
+ case 0:
+ printk(KERN_WARNING PFX "address %08x not mapped.\n", addr);
return -EINVAL;
+ case 1:
+ /* coarse table */
+ cpt = __va(desc1 & 0xfffffc00);
+ desc2 = cpt[(addr >> 12) & 0xff];
+ break;
+ case 2:
+ /* section */
+ if (is_set)
+ desc1 |= bits;
+ else
+ desc1 &= ~bits;
+ pgtable[addr >> 20] = desc1;
+ addr += SECTION_SIZE;
+ count++;
+ continue;
+ case 3:
+ cpt = __va(desc1 & 0xfffff000);
+ desc2 = cpt[(addr >> 10) & 0x3ff];
+ break;
}
- cpt = __va(desc1 & 0xfffffc00);
- desc2 = cpt[(addr >> 12) & 0xff];
- if ((desc2 & 3) != 2) {
- printk(KERN_WARNING PFX "not small page? %08x %08x\n", desc2, addr);
+ if ((desc2 & 3) == 0) {
+ printk(KERN_WARNING PFX "address %08x not mapped (%08x)\n",
+ addr, desc2);
return -EINVAL;
}
desc2 |= bits;
else
desc2 &= ~bits;
- desc2 |= 0xff0;
- cpt[(addr >> 12) & 0xff] = desc2;
+ /* this might be bad idea, better let it fault so that Linux does
+ * it's accounting, but that will drop CB bits, so keep this
+ * for compatibility */
+ if ((desc2 & 3) == 2)
+ desc2 |= 0xff0;
+
+ switch (desc1 & 3) {
+ case 1:
+ cpt[(addr >> 12) & 0xff] = desc2;
+ break;
+ case 3:
+ cpt[(addr >> 10) & 0x3ff] = desc2;
+ break;
+ }
+
+ addr += PAGE_SIZE;
count++;
}
case 3: /* fine table */
cpt = __va(desc1 & 0xfffff000);
desc2 = cpt[(addr >> 10) & 0x3ff];
+ break;
default:
return -EINVAL;
}
-
-
+
switch (desc2 & 3) {
case 1: /* large page */
- *_addr = (desc2 & 0xffff0000) | (addr & 0xffff);
+ *_addr = (desc2 & ~0xffff) | (addr & 0xffff);
break;
case 2: /* small page */
- *_addr = (desc2 & 0xfffff000) | (addr & 0x0fff);
+ *_addr = (desc2 & ~0x0fff) | (addr & 0x0fff);
break;
case 3: /* tiny page */
- *_addr = (desc2 & 0xfffffc00) | (addr & 0x03ff);
+ *_addr = (desc2 & ~0x03ff) | (addr & 0x03ff);
break;
default:
return -EINVAL;