Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
* spu_switch.c
*
* (C) Copyright IBM Corp. 2005
*
* Author: Mark Nutter <mnutter@us.ibm.com>
*
* Host-side part of SPU context switch sequence outlined in
* Synergistic Processor Element, Book IV.
*
* A fully premptive switch of an SPE is very expensive in terms
* of time and system resources. SPE Book IV indicates that SPE
* allocation should follow a "serially reusable device" model,
* in which the SPE is assigned a task until it completes. When
* this is not possible, this sequence may be used to premptively
* save, and then later (optionally) restore the context of a
* program executing on an SPE.
*
*
* 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/smp.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
#include <asm/io.h>
#include <asm/spu.h>
#include <asm/spu_priv1.h>
#include <asm/spu_csa.h>
#include <asm/mmu_context.h>
#include "spu_save_dump.h"
#include "spu_restore_dump.h"
#if 0
#define POLL_WHILE_TRUE(_c) { \
do { \
} while (_c); \
}
#else
#define RELAX_SPIN_COUNT 1000
#define POLL_WHILE_TRUE(_c) { \
do { \
int _i; \
for (_i=0; _i<RELAX_SPIN_COUNT && (_c); _i++) { \
cpu_relax(); \
} \
if (unlikely(_c)) yield(); \
else break; \
} while (_c); \
}
#endif /* debug */
#define POLL_WHILE_FALSE(_c) POLL_WHILE_TRUE(!(_c))
static inline void acquire_spu_lock(struct spu *spu)
{
/* Save, Step 1:
* Restore, Step 1:
* Acquire SPU-specific mutual exclusion lock.
* TBD.
*/
}
static inline void release_spu_lock(struct spu *spu)
{
/* Restore, Step 76:
* Release SPU-specific mutual exclusion lock.
* TBD.
*/
}
static inline int check_spu_isolate(struct spu_state *csa, struct spu *spu)
{
struct spu_problem __iomem *prob = spu->problem;
u32 isolate_state;
/* Save, Step 2:
* Save, Step 6:
* If SPU_Status[E,L,IS] any field is '1', this
* SPU is in isolate state and cannot be context
* saved at this time.
*/
isolate_state = SPU_STATUS_ISOLATED_STATE |
SPU_STATUS_ISOLATED_LOAD_STATUS | SPU_STATUS_ISOLATED_EXIT_STATUS;
return (in_be32(&prob->spu_status_R) & isolate_state) ? 1 : 0;
}
static inline void disable_interrupts(struct spu_state *csa, struct spu *spu)
{
/* Save, Step 3:
* Restore, Step 2:
* Save INT_Mask_class0 in CSA.
* Write INT_MASK_class0 with value of 0.
* Save INT_Mask_class1 in CSA.
* Write INT_MASK_class1 with value of 0.
* Save INT_Mask_class2 in CSA.
* Write INT_MASK_class2 with value of 0.
*/
spin_lock_irq(&spu->register_lock);
if (csa) {
csa->priv1.int_mask_class0_RW = spu_int_mask_get(spu, 0);
csa->priv1.int_mask_class1_RW = spu_int_mask_get(spu, 1);
csa->priv1.int_mask_class2_RW = spu_int_mask_get(spu, 2);
spu_int_mask_set(spu, 0, 0ul);
spu_int_mask_set(spu, 1, 0ul);
spu_int_mask_set(spu, 2, 0ul);
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
eieio();
spin_unlock_irq(&spu->register_lock);
}
static inline void set_watchdog_timer(struct spu_state *csa, struct spu *spu)
{
/* Save, Step 4:
* Restore, Step 25.
* Set a software watchdog timer, which specifies the
* maximum allowable time for a context save sequence.
*
* For present, this implementation will not set a global
* watchdog timer, as virtualization & variable system load
* may cause unpredictable execution times.
*/
}
static inline void inhibit_user_access(struct spu_state *csa, struct spu *spu)
{
/* Save, Step 5:
* Restore, Step 3:
* Inhibit user-space access (if provided) to this
* SPU by unmapping the virtual pages assigned to
* the SPU memory-mapped I/O (MMIO) for problem
* state. TBD.
*/
}
static inline void set_switch_pending(struct spu_state *csa, struct spu *spu)
{
/* Save, Step 7:
* Restore, Step 5:
* Set a software context switch pending flag.
*/
set_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags);
mb();
}
static inline void save_mfc_cntl(struct spu_state *csa, struct spu *spu)
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
/* Save, Step 8:
* Suspend DMA and save MFC_CNTL.
switch (in_be64(&priv2->mfc_control_RW) &
MFC_CNTL_SUSPEND_DMA_STATUS_MASK) {
case MFC_CNTL_SUSPEND_IN_PROGRESS:
POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
MFC_CNTL_SUSPEND_COMPLETE);
/* fall through */
case MFC_CNTL_SUSPEND_COMPLETE:
if (csa) {
csa->priv2.mfc_control_RW =
in_be64(&priv2->mfc_control_RW) |
MFC_CNTL_SUSPEND_DMA_QUEUE;
}
break;
case MFC_CNTL_NORMAL_DMA_QUEUE_OPERATION:
out_be64(&priv2->mfc_control_RW, MFC_CNTL_SUSPEND_DMA_QUEUE);
POLL_WHILE_FALSE((in_be64(&priv2->mfc_control_RW) &
MFC_CNTL_SUSPEND_DMA_STATUS_MASK) ==
MFC_CNTL_SUSPEND_COMPLETE);
if (csa) {
csa->priv2.mfc_control_RW =
in_be64(&priv2->mfc_control_RW) &
~MFC_CNTL_SUSPEND_DMA_QUEUE;
}
break;
Loading
Loading full blame...