* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#define DEBUG 1
+#undef DEBUG
#include <linux/interrupt.h>
#include <linux/list.h>
#include <asm/io.h>
#include <asm/prom.h>
-#include <asm/semaphore.h>
+#include <linux/mutex.h>
#include <asm/spu.h>
#include <asm/mmu_context.h>
{
struct spu_priv2 __iomem *priv2 = spu->priv2;
- if (!test_bit(SPU_CONTEXT_SWITCH_PENDING_nr, &spu->flags))
+ if (!test_bit(SPU_CONTEXT_SWITCH_PENDING, &spu->flags))
out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
}
pr_debug("%s\n", __FUNCTION__);
- if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+ if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
/* SLBs are pre-loaded for context switch, so
* we should never get here!
*/
extern int hash_page(unsigned long ea, unsigned long access, unsigned long trap); //XXX
static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
{
- pr_debug("%s\n", __FUNCTION__);
+ pr_debug("%s, %lx, %lx\n", __FUNCTION__, dsisr, ea);
/* Handle kernel space hash faults immediately.
User hash faults need to be deferred to process context. */
return 0;
}
- if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE_nr, &spu->flags)) {
+ if (test_bit(SPU_CONTEXT_SWITCH_ACTIVE, &spu->flags)) {
printk("%s: invalid access during switch!\n", __func__);
return 1;
}
spu->dar = ea;
spu->dsisr = dsisr;
mb();
- wake_up(&spu->stop_wq);
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
return 0;
}
/* atomically disable SPU mailbox interrupts */
spin_lock(&spu->register_lock);
- out_be64(&spu->priv1->int_mask_class2_RW,
- in_be64(&spu->priv1->int_mask_class2_RW) & ~0x1);
+ spu_int_mask_and(spu, 2, ~0x1);
spin_unlock(&spu->register_lock);
return 0;
}
{
pr_debug("%s\n", __FUNCTION__);
spu->stop_code = in_be32(&spu->problem->spu_status_R);
- wake_up(&spu->stop_wq);
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
return 0;
}
{
pr_debug("%s\n", __FUNCTION__);
spu->stop_code = in_be32(&spu->problem->spu_status_R);
- wake_up(&spu->stop_wq);
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
return 0;
}
static int __spu_trap_tag_group(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
- /* wake_up(&spu->dma_wq); */
+ spu->mfc_callback(spu);
return 0;
}
/* atomically disable SPU mailbox interrupts */
spin_lock(&spu->register_lock);
- out_be64(&spu->priv1->int_mask_class2_RW,
- in_be64(&spu->priv1->int_mask_class2_RW) & ~0x10);
+ spu_int_mask_and(spu, 2, ~0x10);
spin_unlock(&spu->register_lock);
return 0;
}
spu = data;
spu->class_0_pending = 1;
- wake_up(&spu->stop_wq);
+ if (spu->stop_callback)
+ spu->stop_callback(spu);
return IRQ_HANDLED;
}
-static int
+int
spu_irq_class_0_bottom(struct spu *spu)
{
- unsigned long stat;
+ unsigned long stat, mask;
spu->class_0_pending = 0;
- stat = in_be64(&spu->priv1->int_stat_class0_RW);
+ mask = spu_int_mask_get(spu, 0);
+ stat = spu_int_stat_get(spu, 0);
+
+ stat &= mask;
if (stat & 1) /* invalid MFC DMA */
__spu_trap_invalid_dma(spu);
if (stat & 4) /* error on SPU */
__spu_trap_error(spu);
- out_be64(&spu->priv1->int_stat_class0_RW, stat);
- return 0;
+ spu_int_stat_clear(spu, 0, stat);
+
+ return (stat & 0x7) ? -EIO : 0;
}
+EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
static irqreturn_t
spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
/* atomically read & clear class1 status. */
spin_lock(&spu->register_lock);
- mask = in_be64(&spu->priv1->int_mask_class1_RW);
- stat = in_be64(&spu->priv1->int_stat_class1_RW) & mask;
- dar = in_be64(&spu->priv1->mfc_dar_RW);
- dsisr = in_be64(&spu->priv1->mfc_dsisr_RW);
- out_be64(&spu->priv1->mfc_dsisr_RW, 0UL);
- out_be64(&spu->priv1->int_stat_class1_RW, stat);
+ mask = spu_int_mask_get(spu, 1);
+ stat = spu_int_stat_get(spu, 1) & mask;
+ dar = spu_mfc_dar_get(spu);
+ dsisr = spu_mfc_dsisr_get(spu);
+ if (stat & 2) /* mapping fault */
+ spu_mfc_dsisr_set(spu, 0ul);
+ spu_int_stat_clear(spu, 1, stat);
spin_unlock(&spu->register_lock);
+ pr_debug("%s: %lx %lx %lx %lx\n", __FUNCTION__, mask, stat,
+ dar, dsisr);
if (stat & 1) /* segment fault */
__spu_trap_data_seg(spu, dar);
return stat ? IRQ_HANDLED : IRQ_NONE;
}
+EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
static irqreturn_t
spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
{
struct spu *spu;
unsigned long stat;
+ unsigned long mask;
spu = data;
- stat = in_be64(&spu->priv1->int_stat_class2_RW);
+ stat = spu_int_stat_get(spu, 2);
+ mask = spu_int_mask_get(spu, 2);
- pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat,
- in_be64(&spu->priv1->int_mask_class2_RW));
+ pr_debug("class 2 interrupt %d, %lx, %lx\n", irq, stat, mask);
+ stat &= mask;
if (stat & 1) /* PPC core mailbox */
__spu_trap_mailbox(spu);
if (stat & 0x10) /* SPU mailbox threshold */
__spu_trap_spubox(spu);
- out_be64(&spu->priv1->int_stat_class2_RW, stat);
+ spu_int_stat_clear(spu, 2, stat);
return stat ? IRQ_HANDLED : IRQ_NONE;
}
spu_irq_class_0, 0, spu->irq_c0, spu);
if (ret)
goto out;
- out_be64(&spu->priv1->int_mask_class0_RW, 0x7);
snprintf(spu->irq_c1, sizeof (spu->irq_c1), "spe%02d.1", spu->number);
ret = request_irq(irq_base + IIC_CLASS_STRIDE + spu->isrc,
spu_irq_class_1, 0, spu->irq_c1, spu);
if (ret)
goto out1;
- out_be64(&spu->priv1->int_mask_class1_RW, 0x3);
snprintf(spu->irq_c2, sizeof (spu->irq_c2), "spe%02d.2", spu->number);
ret = request_irq(irq_base + 2*IIC_CLASS_STRIDE + spu->isrc,
spu_irq_class_2, 0, spu->irq_c2, spu);
if (ret)
goto out2;
- out_be64(&spu->priv1->int_mask_class2_RW, 0xe);
goto out;
out2:
}
static LIST_HEAD(spu_list);
-static DECLARE_MUTEX(spu_mutex);
+static DEFINE_MUTEX(spu_mutex);
static void spu_init_channels(struct spu *spu)
{
{ 0x17, 1, }, { 0x18, 0, }, { 0x19, 0, }, { 0x1b, 0, },
{ 0x1c, 1, }, { 0x1d, 0, }, { 0x1e, 1, },
};
- struct spu_priv2 *priv2;
+ struct spu_priv2 __iomem *priv2;
int i;
priv2 = spu->priv2;
}
}
-static void spu_init_regs(struct spu *spu)
-{
- out_be64(&spu->priv1->int_mask_class0_RW, 0x7);
- out_be64(&spu->priv1->int_mask_class1_RW, 0x3);
- out_be64(&spu->priv1->int_mask_class2_RW, 0xe);
-}
-
struct spu *spu_alloc(void)
{
struct spu *spu;
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
if (!list_empty(&spu_list)) {
spu = list_entry(spu_list.next, struct spu, list);
list_del_init(&spu->list);
pr_debug("No SPU left\n");
spu = NULL;
}
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
- if (spu) {
+ if (spu)
spu_init_channels(spu);
- spu_init_regs(spu);
- }
return spu;
}
void spu_free(struct spu *spu)
{
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
list_add_tail(&spu->list, &spu_list);
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
}
EXPORT_SYMBOL_GPL(spu_free);
return -EFAULT;
}
-static int spu_handle_pte_fault(struct spu *spu)
+int spu_irq_class_1_bottom(struct spu *spu)
{
u64 ea, dsisr, access, error = 0UL;
int ret = 0;
ea = spu->dar;
dsisr = spu->dsisr;
- if (dsisr & MFC_DSISR_PTE_NOT_FOUND) {
+ if (dsisr & (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED)) {
access = (_PAGE_PRESENT | _PAGE_USER);
access |= (dsisr & MFC_DSISR_ACCESS_PUT) ? _PAGE_RW : 0UL;
if (hash_page(ea, access, 0x300) != 0)
error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
}
- if ((error & CLASS1_ENABLE_STORAGE_FAULT_INTR) ||
- (dsisr & MFC_DSISR_ACCESS_DENIED)) {
+ if (error & CLASS1_ENABLE_STORAGE_FAULT_INTR) {
if ((ret = spu_handle_mm_fault(spu)) != 0)
error |= CLASS1_ENABLE_STORAGE_FAULT_INTR;
else
return ret;
}
-static inline int spu_pending(struct spu *spu, u32 * stat)
+void spu_irq_setaffinity(struct spu *spu, int cpu)
{
- struct spu_problem __iomem *prob = spu->problem;
- u64 pte_fault;
-
- *stat = in_be32(&prob->spu_status_R);
- pte_fault = spu->dsisr &
- (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED);
- return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
+ u64 target = iic_get_target_id(cpu);
+ u64 route = target << 48 | target << 32 | target << 16;
+ spu_int_route_set(spu, route);
}
-
-int spu_run(struct spu *spu)
-{
- struct spu_problem __iomem *prob;
- struct spu_priv1 __iomem *priv1;
- struct spu_priv2 __iomem *priv2;
- u32 status;
- int ret;
-
- prob = spu->problem;
- priv1 = spu->priv1;
- priv2 = spu->priv2;
-
- /* Let SPU run. */
- eieio();
- out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_RUNNABLE);
-
- do {
- ret = wait_event_interruptible(spu->stop_wq,
- spu_pending(spu, &status));
-
- if (spu->dsisr &
- (MFC_DSISR_PTE_NOT_FOUND | MFC_DSISR_ACCESS_DENIED))
- ret = spu_handle_pte_fault(spu);
-
- if (spu->class_0_pending)
- spu_irq_class_0_bottom(spu);
-
- if (!ret && signal_pending(current))
- ret = -ERESTARTSYS;
-
- } while (!ret && !(status &
- (SPU_STATUS_STOPPED_BY_STOP |
- SPU_STATUS_STOPPED_BY_HALT)));
-
- /* Ensure SPU is stopped. */
- out_be32(&prob->spu_runcntl_RW, SPU_RUNCNTL_STOP);
- eieio();
- while (in_be32(&prob->spu_status_R) & SPU_STATUS_RUNNING)
- cpu_relax();
-
- out_be64(&priv2->slb_invalidate_all_W, 0);
- out_be64(&priv1->tlb_invalidate_entry_W, 0UL);
- eieio();
-
- /* Check for SPU breakpoint. */
- if (unlikely(current->ptrace & PT_PTRACED)) {
- status = in_be32(&prob->spu_status_R);
-
- if ((status & SPU_STATUS_STOPPED_BY_STOP)
- && status >> SPU_STOP_STATUS_SHIFT == 0x3fff) {
- force_sig(SIGTRAP, current);
- ret = -ERESTARTSYS;
- }
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(spu_run);
+EXPORT_SYMBOL_GPL(spu_irq_setaffinity);
static void __iomem * __init map_spe_prop(struct device_node *n,
const char *name)
if (!spu->local_store)
goto out;
+ prop = get_property(spe, "problem", NULL);
+ if (!prop)
+ goto out_unmap;
+ spu->problem_phys = *(unsigned long *)prop;
+
spu->problem= map_spe_prop(spe, "problem");
if (!spu->problem)
goto out_unmap;
spu->priv1= map_spe_prop(spe, "priv1");
- if (!spu->priv1)
- goto out_unmap;
+ /* priv1 is not available on a hypervisor */
spu->priv2= map_spe_prop(spe, "priv2");
if (!spu->priv2)
spu->dsisr = 0UL;
spin_lock_init(&spu->register_lock);
- out_be64(&spu->priv1->mfc_sdr_RW, mfspr(SPRN_SDR1));
- out_be64(&spu->priv1->mfc_sr1_RW, 0x33);
+ spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
+ spu_mfc_sr1_set(spu, 0x33);
- init_waitqueue_head(&spu->stop_wq);
spu->ibox_callback = NULL;
spu->wbox_callback = NULL;
+ spu->stop_callback = NULL;
+ spu->mfc_callback = NULL;
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
spu->number = number++;
ret = spu_request_irqs(spu);
if (ret)
goto out_unmap;
list_add(&spu->list, &spu_list);
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
spu->name, spu->isrc, spu->local_store,
goto out;
out_unmap:
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
spu_unmap(spu);
out_free:
kfree(spu);
static void cleanup_spu_base(void)
{
struct spu *spu, *tmp;
- down(&spu_mutex);
+ mutex_lock(&spu_mutex);
list_for_each_entry_safe(spu, tmp, &spu_list, list)
destroy_spu(spu);
- up(&spu_mutex);
+ mutex_unlock(&spu_mutex);
}
module_exit(cleanup_spu_base);