Skip to content

Commit

Permalink
Blackfin: cleanup sync handling when enabling/disabling cplbs
Browse files Browse the repository at this point in the history
The handling of updating the [DI]MEM_CONTROL MMRs does not follow proper
sync procedures as laid out in the Blackfin programming manual.  So rather
than audit/fix every call location, create helper functions that do the
right things in order to safely update these MMRs.  Then convert all call
sites to use these new helper functions.

While we're fixing the code, drop the workaround for anomaly 05000125 as
that anomaly applies to old versions of silicon that we do not support.

Signed-off-by: Yi Li <yi.li@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
  • Loading branch information
Yi Li authored and Mike Frysinger committed Sep 17, 2009
1 parent 8312440 commit eb7bd9c
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 166 deletions.
46 changes: 45 additions & 1 deletion arch/blackfin/include/asm/cplb.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,48 @@
#define FAULT_USERSUPV (1 << 17)
#define FAULT_CPLBBITS 0x0000ffff

#endif /* _CPLB_H */
#ifndef __ASSEMBLY__

static inline void _disable_cplb(u32 mmr, u32 mask)
{
u32 ctrl = bfin_read32(mmr) & ~mask;
/* CSYNC to ensure load store ordering */
__builtin_bfin_csync();
bfin_write32(mmr, ctrl);
__builtin_bfin_ssync();
}
static inline void disable_cplb(u32 mmr, u32 mask)
{
u32 ctrl = bfin_read32(mmr) & ~mask;
CSYNC();
bfin_write32(mmr, ctrl);
SSYNC();
}
#define _disable_dcplb() _disable_cplb(DMEM_CONTROL, ENDCPLB)
#define disable_dcplb() disable_cplb(DMEM_CONTROL, ENDCPLB)
#define _disable_icplb() _disable_cplb(IMEM_CONTROL, ENICPLB)
#define disable_icplb() disable_cplb(IMEM_CONTROL, ENICPLB)

static inline void _enable_cplb(u32 mmr, u32 mask)
{
u32 ctrl = bfin_read32(mmr) | mask;
/* CSYNC to ensure load store ordering */
__builtin_bfin_csync();
bfin_write32(mmr, ctrl);
__builtin_bfin_ssync();
}
static inline void enable_cplb(u32 mmr, u32 mask)
{
u32 ctrl = bfin_read32(mmr) | mask;
CSYNC();
bfin_write32(mmr, ctrl);
SSYNC();
}
#define _enable_dcplb() _enable_cplb(DMEM_CONTROL, ENDCPLB)
#define enable_dcplb() enable_cplb(DMEM_CONTROL, ENDCPLB)
#define _enable_icplb() _enable_cplb(IMEM_CONTROL, ENICPLB)
#define enable_icplb() enable_cplb(IMEM_CONTROL, ENICPLB)

#endif /* __ASSEMBLY__ */

#endif /* _CPLB_H */
6 changes: 4 additions & 2 deletions arch/blackfin/kernel/cplb-mpu/cacheinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ void __cpuinit bfin_icache_init(struct cplb_entry *icplb_tbl)
unsigned long ctrl;
int i;

SSYNC();
for (i = 0; i < MAX_CPLBS; i++) {
bfin_write32(ICPLB_ADDR0 + i * 4, icplb_tbl[i].addr);
bfin_write32(ICPLB_DATA0 + i * 4, icplb_tbl[i].data);
}
ctrl = bfin_read_IMEM_CONTROL();
ctrl |= IMC | ENICPLB;
/* CSYNC to ensure load store ordering */
CSYNC();
bfin_write_IMEM_CONTROL(ctrl);
SSYNC();
}
Expand All @@ -48,7 +49,6 @@ void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
unsigned long ctrl;
int i;

SSYNC();
for (i = 0; i < MAX_CPLBS; i++) {
bfin_write32(DCPLB_ADDR0 + i * 4, dcplb_tbl[i].addr);
bfin_write32(DCPLB_DATA0 + i * 4, dcplb_tbl[i].data);
Expand All @@ -63,6 +63,8 @@ void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
* to port B
*/
ctrl |= DMEM_CNTR | PORT_PREF0 | (ANOMALY_05000287 ? PORT_PREF1 : 0);
/* CSYNC to ensure load store ordering */
CSYNC();
bfin_write_DMEM_CONTROL(ctrl);
SSYNC();
}
Expand Down
61 changes: 11 additions & 50 deletions arch/blackfin/kernel/cplb-mpu/cplbmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <asm/blackfin.h>
#include <asm/cacheflush.h>
#include <asm/cplb.h>
#include <asm/cplbinit.h>
#include <asm/mmu_context.h>

Expand All @@ -41,46 +42,6 @@ int nr_dcplb_miss[NR_CPUS], nr_icplb_miss[NR_CPUS];
int nr_icplb_supv_miss[NR_CPUS], nr_dcplb_prot[NR_CPUS];
int nr_cplb_flush[NR_CPUS];

static inline void disable_dcplb(void)
{
unsigned long ctrl;
SSYNC();
ctrl = bfin_read_DMEM_CONTROL();
ctrl &= ~ENDCPLB;
bfin_write_DMEM_CONTROL(ctrl);
SSYNC();
}

static inline void enable_dcplb(void)
{
unsigned long ctrl;
SSYNC();
ctrl = bfin_read_DMEM_CONTROL();
ctrl |= ENDCPLB;
bfin_write_DMEM_CONTROL(ctrl);
SSYNC();
}

static inline void disable_icplb(void)
{
unsigned long ctrl;
SSYNC();
ctrl = bfin_read_IMEM_CONTROL();
ctrl &= ~ENICPLB;
bfin_write_IMEM_CONTROL(ctrl);
SSYNC();
}

static inline void enable_icplb(void)
{
unsigned long ctrl;
SSYNC();
ctrl = bfin_read_IMEM_CONTROL();
ctrl |= ENICPLB;
bfin_write_IMEM_CONTROL(ctrl);
SSYNC();
}

/*
* Given the contents of the status register, return the index of the
* CPLB that caused the fault.
Expand Down Expand Up @@ -198,10 +159,10 @@ static noinline int dcplb_miss(unsigned int cpu)
dcplb_tbl[cpu][idx].addr = addr;
dcplb_tbl[cpu][idx].data = d_data;

disable_dcplb();
_disable_dcplb();
bfin_write32(DCPLB_DATA0 + idx * 4, d_data);
bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
enable_dcplb();
_enable_dcplb();

return 0;
}
Expand Down Expand Up @@ -288,10 +249,10 @@ static noinline int icplb_miss(unsigned int cpu)
icplb_tbl[cpu][idx].addr = addr;
icplb_tbl[cpu][idx].data = i_data;

disable_icplb();
_disable_icplb();
bfin_write32(ICPLB_DATA0 + idx * 4, i_data);
bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
enable_icplb();
_enable_icplb();

return 0;
}
Expand Down Expand Up @@ -340,19 +301,19 @@ void flush_switched_cplbs(unsigned int cpu)
nr_cplb_flush[cpu]++;

local_irq_save_hw(flags);
disable_icplb();
_disable_icplb();
for (i = first_switched_icplb; i < MAX_CPLBS; i++) {
icplb_tbl[cpu][i].data = 0;
bfin_write32(ICPLB_DATA0 + i * 4, 0);
}
enable_icplb();
_enable_icplb();

disable_dcplb();
_disable_dcplb();
for (i = first_switched_dcplb; i < MAX_CPLBS; i++) {
dcplb_tbl[cpu][i].data = 0;
bfin_write32(DCPLB_DATA0 + i * 4, 0);
}
enable_dcplb();
_enable_dcplb();
local_irq_restore_hw(flags);

}
Expand Down Expand Up @@ -385,14 +346,14 @@ void set_mask_dcplbs(unsigned long *masks, unsigned int cpu)
#endif
}

disable_dcplb();
_disable_dcplb();
for (i = first_mask_dcplb; i < first_switched_dcplb; i++) {
dcplb_tbl[cpu][i].addr = addr;
dcplb_tbl[cpu][i].data = d_data;
bfin_write32(DCPLB_DATA0 + i * 4, d_data);
bfin_write32(DCPLB_ADDR0 + i * 4, addr);
addr += PAGE_SIZE;
}
enable_dcplb();
_enable_dcplb();
local_irq_restore_hw(flags);
}
6 changes: 4 additions & 2 deletions arch/blackfin/kernel/cplb-nompu/cacheinit.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ void __cpuinit bfin_icache_init(struct cplb_entry *icplb_tbl)
unsigned long ctrl;
int i;

SSYNC();
for (i = 0; i < MAX_CPLBS; i++) {
bfin_write32(ICPLB_ADDR0 + i * 4, icplb_tbl[i].addr);
bfin_write32(ICPLB_DATA0 + i * 4, icplb_tbl[i].data);
}
ctrl = bfin_read_IMEM_CONTROL();
ctrl |= IMC | ENICPLB;
/* CSYNC to ensure load store ordering */
CSYNC();
bfin_write_IMEM_CONTROL(ctrl);
SSYNC();
}
Expand All @@ -48,7 +49,6 @@ void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
unsigned long ctrl;
int i;

SSYNC();
for (i = 0; i < MAX_CPLBS; i++) {
bfin_write32(DCPLB_ADDR0 + i * 4, dcplb_tbl[i].addr);
bfin_write32(DCPLB_DATA0 + i * 4, dcplb_tbl[i].data);
Expand All @@ -63,6 +63,8 @@ void __cpuinit bfin_dcache_init(struct cplb_entry *dcplb_tbl)
* to port B
*/
ctrl |= DMEM_CNTR | PORT_PREF0 | (ANOMALY_05000287 ? PORT_PREF1 : 0);
/* CSYNC to ensure load store ordering */
CSYNC();
bfin_write_DMEM_CONTROL(ctrl);
SSYNC();
}
Expand Down
33 changes: 4 additions & 29 deletions arch/blackfin/kernel/cplb-nompu/cplbmgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,36 +48,13 @@ int nr_cplb_flush[NR_CPUS], nr_dcplb_prot[NR_CPUS];
#define MGR_ATTR
#endif

/*
* We're in an exception handler. The normal cli nop nop workaround
* isn't going to do very much, as the only thing that can interrupt
* us is an NMI, and the cli isn't going to stop that.
*/
#define NOWA_SSYNC __asm__ __volatile__ ("ssync;")

/* Anomaly handlers provide SSYNCs, so avoid extra if anomaly is present */
#if ANOMALY_05000125

#define bfin_write_DMEM_CONTROL_SSYNC(v) bfin_write_DMEM_CONTROL(v)
#define bfin_write_IMEM_CONTROL_SSYNC(v) bfin_write_IMEM_CONTROL(v)

#else

#define bfin_write_DMEM_CONTROL_SSYNC(v) \
do { NOWA_SSYNC; bfin_write_DMEM_CONTROL(v); NOWA_SSYNC; } while (0)
#define bfin_write_IMEM_CONTROL_SSYNC(v) \
do { NOWA_SSYNC; bfin_write_IMEM_CONTROL(v); NOWA_SSYNC; } while (0)

#endif

static inline void write_dcplb_data(int cpu, int idx, unsigned long data,
unsigned long addr)
{
unsigned long ctrl = bfin_read_DMEM_CONTROL();
bfin_write_DMEM_CONTROL_SSYNC(ctrl & ~ENDCPLB);
_disable_dcplb();
bfin_write32(DCPLB_DATA0 + idx * 4, data);
bfin_write32(DCPLB_ADDR0 + idx * 4, addr);
bfin_write_DMEM_CONTROL_SSYNC(ctrl);
_enable_dcplb();

#ifdef CONFIG_CPLB_INFO
dcplb_tbl[cpu][idx].addr = addr;
Expand All @@ -88,12 +65,10 @@ static inline void write_dcplb_data(int cpu, int idx, unsigned long data,
static inline void write_icplb_data(int cpu, int idx, unsigned long data,
unsigned long addr)
{
unsigned long ctrl = bfin_read_IMEM_CONTROL();

bfin_write_IMEM_CONTROL_SSYNC(ctrl & ~ENICPLB);
_disable_icplb();
bfin_write32(ICPLB_DATA0 + idx * 4, data);
bfin_write32(ICPLB_ADDR0 + idx * 4, addr);
bfin_write_IMEM_CONTROL_SSYNC(ctrl);
_enable_icplb();

#ifdef CONFIG_CPLB_INFO
icplb_tbl[cpu][idx].addr = addr;
Expand Down
20 changes: 4 additions & 16 deletions arch/blackfin/mach-bf561/secondary.S
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,10 @@ ENTRY(_coreb_trampoline_start)
R0 = ~ENICPLB;
R0 = R0 & R1;

/* Anomaly 05000125 */
#ifdef ANOMALY_05000125
CLI R2;
SSYNC;
#endif
/* Disabling of CPLBs should be proceeded by a CSYNC */
CSYNC;
[p0] = R0;
SSYNC;
#ifdef ANOMALY_05000125
STI R2;
#endif

/* Turn off the dcache */
p0.l = LO(DMEM_CONTROL);
Expand All @@ -103,16 +97,10 @@ ENTRY(_coreb_trampoline_start)
R0 = ~ENDCPLB;
R0 = R0 & R1;

/* Anomaly 05000125 */
#ifdef ANOMALY_05000125
CLI R2;
SSYNC;
#endif
/* Disabling of CPLBs should be proceeded by a CSYNC */
CSYNC;
[p0] = R0;
SSYNC;
#ifdef ANOMALY_05000125
STI R2;
#endif

/* in case of double faults, save a few things */
p0.l = _init_retx_coreb;
Expand Down
14 changes: 4 additions & 10 deletions arch/blackfin/mach-common/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -397,17 +397,15 @@ ENTRY(_double_fault)

R5 = [P4]; /* Control Register*/
BITCLR(R5,ENICPLB_P);
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
.align 8;
CSYNC; /* Disabling of CPLBs should be proceeded by a CSYNC */
[P4] = R5;
SSYNC;

P4.L = LO(DMEM_CONTROL);
P4.H = HI(DMEM_CONTROL);
R5 = [P4];
BITCLR(R5,ENDCPLB_P);
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
.align 8;
CSYNC; /* Disabling of CPLBs should be proceeded by a CSYNC */
[P4] = R5;
SSYNC;

Expand Down Expand Up @@ -1146,21 +1144,17 @@ ENTRY(_early_trap)

R5 = [P4]; /* Control Register*/
BITCLR(R5,ENICPLB_P);
CLI R1;
SSYNC; /* SSYNC required before writing to IMEM_CONTROL. */
.align 8;
CSYNC; /* Disabling of CPLBs should be proceeded by a CSYNC */
[P4] = R5;
SSYNC;

P4.L = LO(DMEM_CONTROL);
P4.H = HI(DMEM_CONTROL);
R5 = [P4];
BITCLR(R5,ENDCPLB_P);
SSYNC; /* SSYNC required before writing to DMEM_CONTROL. */
.align 8;
CSYNC; /* Disabling of CPLBs should be proceeded by a CSYNC */
[P4] = R5;
SSYNC;
STI R1;

r0 = sp; /* stack frame pt_regs pointer argument ==> r0 */
r1 = RETX;
Expand Down
Loading

0 comments on commit eb7bd9c

Please sign in to comment.