Hi Jimi,

> Some processors, like embedded, that already have a PID register that
> is managed by the system.  This patch separates the ACOP and PID
> processing into separate files so that the ACOP code can be shared.
> 
> Signed-off-by: Jimi Xenidis <ji...@pobox.com>

Looks good.

Acked-by: Anton Blanchard <an...@samba.org>

Anton

> ---
> Re: ga...@kernel.crashing.org
>     Fix typo in arch/powerpc/mm/Makefile
> 
> Re: an...@samba.org
>     merge in: powerpc: Fix deadlock in icswx code
> ---
>  arch/powerpc/mm/Makefile               |    2 +
>  arch/powerpc/mm/icswx.c                |  162
> ++++++++++++++++++++++++++ arch/powerpc/mm/icswx.h                |
> 34 ++++++ arch/powerpc/mm/icswx_pid.c            |   87 ++++++++++++++
>  arch/powerpc/mm/mmu_context_hash64.c   |  195
> --------------------------------
> arch/powerpc/platforms/Kconfig.cputype |   10 ++- 6 files changed,
> 294 insertions(+), 196 deletions(-) create mode 100644
> arch/powerpc/mm/icswx.c create mode 100644 arch/powerpc/mm/icswx.h
>  create mode 100644 arch/powerpc/mm/icswx_pid.c
> 
> diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile
> index bdca46e..fb7976f 100644
> --- a/arch/powerpc/mm/Makefile
> +++ b/arch/powerpc/mm/Makefile
> @@ -21,6 +21,8 @@ obj-$(CONFIG_PPC_STD_MMU_32)        += ppc_mmu_32.o
>  obj-$(CONFIG_PPC_STD_MMU)    += hash_low_$(CONFIG_WORD_SIZE).o \
>                                  tlb_hash$(CONFIG_WORD_SIZE).o \
>                                  mmu_context_hash$(CONFIG_WORD_SIZE).o
> +obj-$(CONFIG_PPC_ICSWX)              += icswx.o
> +obj-$(CONFIG_PPC_ICSWX_PID)  += icswx_pid.o
>  obj-$(CONFIG_40x)            += 40x_mmu.o
>  obj-$(CONFIG_44x)            += 44x_mmu.o
>  obj-$(CONFIG_PPC_FSL_BOOK3E) += fsl_booke_mmu.o
> diff --git a/arch/powerpc/mm/icswx.c b/arch/powerpc/mm/icswx.c
> new file mode 100644
> index 0000000..2f1dd29
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx.c
> @@ -0,0 +1,162 @@
> +/*
> + *  ICSWX and ACOP Management
> + *
> + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <an...@samba.org>
> + *
> + *  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 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/spinlock.h>
> +#include <linux/module.h>
> +#include "icswx.h"
> +
> +
> +/*
> + * The processor and its L2 cache cause the icswx instruction to
> + * generate a COP_REQ transaction on PowerBus. The transaction has no
> + * address, and the processor does not perform an MMU access to
> + * authenticate the transaction. The command portion of the PowerBus
> + * COP_REQ transaction includes the LPAR_ID (LPID) and the
> coprocessor
> + * Process ID (PID), which the coprocessor compares to the authorized
> + * LPID and PID held in the coprocessor, to determine if the process
> + * is authorized to generate the transaction.  The data of the
> COP_REQ
> + * transaction is cache block or less, typically 64 or 128 bytes in
> + * size, and is placed in cacheable memory on a 128-byte boundary
> + * _always_.
> + *
> + * The task to use a coprocessor should use use_cop() mark the use of
> + * the coprocessor type (CT) and context swithing.  On a server
> + * processor the PID register is used only for coprocessor management
> + * and so a coprocessor PID is allocated before executing icswx
> + * instruction. Drop_cop() is used to free the resources created by
> + * use_cop().
> + *
> + * Example:
> + * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> + * Each HFI have multiple windows. Each HFI window serves as a
> + * network device sending to and receiving from HFI network.
> + * HFI immediate send function uses icswx instruction. The immediate
> + * send function allows small (single cache-line) packets be sent
> + * without using the regular HFI send FIFO and doorbell, which are
> + * much slower than immediate send.
> + *
> + * For each task intending to use HFI immediate send, the HFI driver
> + * calls use_cop() to obtain a coprocessor PID for the task.
> + * The HFI driver then allocate a free HFI window and save the
> + * coprocessor PID to the HFI window to allow the task to use the
> + * HFI window.
> + *
> + * The HFI driver repeatedly creates immediate send packets and
> + * issues icswx instruction to send data through the HFI window.
> + * The HFI compares the coprocessor PID in the CPU PID register
> + * to the PID held in the HFI window to determine if the transaction
> + * is allowed.
> + *
> + * When the task to release the HFI window, the HFI driver calls
> + * drop_cop() to release the coprocessor PID.
> + */
> +
> +void switch_cop(struct mm_struct *next)
> +{
> +#ifdef CONFIG_ICSWX_PID
> +     mtspr(SPRN_PID, next->context.cop_pid);
> +#endif
> +     mtspr(SPRN_ACOP, next->context.acop);
> +}
> +
> +/**
> + * Start using a coprocessor.
> + * @acop: mask of coprocessor to be used.
> + * @mm: The mm the coprocessor to associate with. Most likely
> current mm.
> + *
> + * Return a positive PID if successful. Negative errno otherwise.
> + * The returned PID will be fed to the coprocessor to determine if an
> + * icswx transaction is authenticated.
> + */
> +int use_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +     int ret;
> +
> +     if (!cpu_has_feature(CPU_FTR_ICSWX))
> +             return -ENODEV;
> +
> +     if (!mm || !acop)
> +             return -EINVAL;
> +
> +     /* The page_table_lock ensures mm_users won't change under
> us */
> +     spin_lock(&mm->page_table_lock);
> +     spin_lock(mm->context.cop_lockp);
> +
> +     ret = get_cop_pid(mm);
> +     if (ret < 0)
> +             goto out;
> +
> +     /* update acop */
> +     mm->context.acop |= acop;
> +
> +     sync_cop(mm);
> +
> +     /*
> +      * If this is a threaded process then there might be other
> threads
> +      * running. We need to send an IPI to force them to pick up
> any
> +      * change in PID and ACOP.
> +      */
> +     if (atomic_read(&mm->mm_users) > 1)
> +             smp_call_function(sync_cop, mm, 1);
> +
> +out:
> +     spin_unlock(mm->context.cop_lockp);
> +     spin_unlock(&mm->page_table_lock);
> +
> +     return ret;
> +}
> +EXPORT_SYMBOL_GPL(use_cop);
> +
> +/**
> + * Stop using a coprocessor.
> + * @acop: mask of coprocessor to be stopped.
> + * @mm: The mm the coprocessor associated with.
> + */
> +void drop_cop(unsigned long acop, struct mm_struct *mm)
> +{
> +     int free_pid;
> +
> +     if (!cpu_has_feature(CPU_FTR_ICSWX))
> +             return;
> +
> +     if (WARN_ON_ONCE(!mm))
> +             return;
> +
> +     /* The page_table_lock ensures mm_users won't change under
> us */
> +     spin_lock(&mm->page_table_lock);
> +     spin_lock(mm->context.cop_lockp);
> +
> +     mm->context.acop &= ~acop;
> +
> +     free_pid = disable_cop_pid(mm);
> +     sync_cop(mm);
> +
> +     /*
> +      * If this is a threaded process then there might be other
> threads
> +      * running. We need to send an IPI to force them to pick up
> any
> +      * change in PID and ACOP.
> +      */
> +     if (atomic_read(&mm->mm_users) > 1)
> +             smp_call_function(sync_cop, mm, 1);
> +
> +     if (free_pid != COP_PID_NONE)
> +             free_cop_pid(free_pid);
> +
> +     spin_unlock(mm->context.cop_lockp);
> +     spin_unlock(&mm->page_table_lock);
> +}
> +EXPORT_SYMBOL_GPL(drop_cop);
> diff --git a/arch/powerpc/mm/icswx.h b/arch/powerpc/mm/icswx.h
> new file mode 100644
> index 0000000..5121ddd
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx.h
> @@ -0,0 +1,34 @@
> +/*
> + *  ICSWX and ACOP Management
> + *
> + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <an...@samba.org>
> + *
> + *  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 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <asm/mmu_context.h>
> +
> +/* also used to denote that PIDs are not used */
> +#define COP_PID_NONE 0
> +
> +static inline void sync_cop(void *arg)
> +{
> +     struct mm_struct *mm = arg;
> +
> +     if (mm == current->active_mm)
> +             switch_cop(current->active_mm);
> +}
> +
> +#ifdef CONFIG_PPC_ICSWX_PID
> +extern int get_cop_pid(struct mm_struct *mm);
> +extern int disable_cop_pid(struct mm_struct *mm);
> +extern void free_cop_pid(int free_pid);
> +#else
> +#define get_cop_pid(m) (COP_PID_NONE)
> +#define disable_cop_pid(m) (COP_PID_NONE)
> +#define free_cop_pid(p)
> +#endif
> diff --git a/arch/powerpc/mm/icswx_pid.c b/arch/powerpc/mm/icswx_pid.c
> new file mode 100644
> index 0000000..91e30eb
> --- /dev/null
> +++ b/arch/powerpc/mm/icswx_pid.c
> @@ -0,0 +1,87 @@
> +/*
> + *  ICSWX and ACOP/PID Management
> + *
> + *  Copyright (C) 2011 Anton Blanchard, IBM Corp. <an...@samba.org>
> + *
> + *  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 of the License, or (at your option) any later version.
> + *
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/types.h>
> +#include <linux/mm.h>
> +#include <linux/spinlock.h>
> +#include <linux/idr.h>
> +#include <linux/module.h>
> +#include "icswx.h"
> +
> +#define COP_PID_MIN (COP_PID_NONE + 1)
> +#define COP_PID_MAX (0xFFFF)
> +
> +static DEFINE_SPINLOCK(mmu_context_acop_lock);
> +static DEFINE_IDA(cop_ida);
> +
> +static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> +                    spinlock_t *lock)
> +{
> +     int index;
> +     int err;
> +
> +again:
> +     if (!ida_pre_get(ida, GFP_KERNEL))
> +             return -ENOMEM;
> +
> +     spin_lock(lock);
> +     err = ida_get_new_above(ida, min_id, &index);
> +     spin_unlock(lock);
> +
> +     if (err == -EAGAIN)
> +             goto again;
> +     else if (err)
> +             return err;
> +
> +     if (index > max_id) {
> +             spin_lock(lock);
> +             ida_remove(ida, index);
> +             spin_unlock(lock);
> +             return -ENOMEM;
> +     }
> +
> +     return index;
> +}
> +
> +int get_cop_pid(struct mm_struct *mm)
> +{
> +     int pid;
> +
> +     if (mm->context.cop_pid == COP_PID_NONE) {
> +             pid = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> +                               &mmu_context_acop_lock);
> +             if (pid >= 0)
> +                     mm->context.cop_pid = pid;
> +     }
> +     return mm->context.cop_pid;
> +}
> +
> +int disable_cop_pid(struct mm_struct *mm)
> +{
> +     int free_pid = COP_PID_NONE;
> +
> +     if ((!mm->context.acop) && (mm->context.cop_pid !=
> COP_PID_NONE)) {
> +             free_pid = mm->context.cop_pid;
> +             mm->context.cop_pid = COP_PID_NONE;
> +     }
> +     return free_pid;
> +}
> +
> +void free_cop_pid(int free_pid)
> +{
> +     spin_lock(&mmu_context_acop_lock);
> +     ida_remove(&cop_ida, free_pid);
> +     spin_unlock(&mmu_context_acop_lock);
> +}
> diff --git a/arch/powerpc/mm/mmu_context_hash64.c
> b/arch/powerpc/mm/mmu_context_hash64.c index 3bafc3d..a75832c 100644
> --- a/arch/powerpc/mm/mmu_context_hash64.c
> +++ b/arch/powerpc/mm/mmu_context_hash64.c
> @@ -24,201 +24,6 @@
>  
>  #include <asm/mmu_context.h>
>  
> -#ifdef CONFIG_PPC_ICSWX
> -/*
> - * The processor and its L2 cache cause the icswx instruction to
> - * generate a COP_REQ transaction on PowerBus. The transaction has
> - * no address, and the processor does not perform an MMU access
> - * to authenticate the transaction. The command portion of the
> - * PowerBus COP_REQ transaction includes the LPAR_ID (LPID) and
> - * the coprocessor Process ID (PID), which the coprocessor compares
> - * to the authorized LPID and PID held in the coprocessor, to
> determine
> - * if the process is authorized to generate the transaction.
> - * The data of the COP_REQ transaction is 128-byte or less and is
> - * placed in cacheable memory on a 128-byte cache line boundary.
> - *
> - * The task to use a coprocessor should use use_cop() to allocate
> - * a coprocessor PID before executing icswx instruction. use_cop()
> - * also enables the coprocessor context switching. Drop_cop() is
> - * used to free the coprocessor PID.
> - *
> - * Example:
> - * Host Fabric Interface (HFI) is a PowerPC network coprocessor.
> - * Each HFI have multiple windows. Each HFI window serves as a
> - * network device sending to and receiving from HFI network.
> - * HFI immediate send function uses icswx instruction. The immediate
> - * send function allows small (single cache-line) packets be sent
> - * without using the regular HFI send FIFO and doorbell, which are
> - * much slower than immediate send.
> - *
> - * For each task intending to use HFI immediate send, the HFI driver
> - * calls use_cop() to obtain a coprocessor PID for the task.
> - * The HFI driver then allocate a free HFI window and save the
> - * coprocessor PID to the HFI window to allow the task to use the
> - * HFI window.
> - *
> - * The HFI driver repeatedly creates immediate send packets and
> - * issues icswx instruction to send data through the HFI window.
> - * The HFI compares the coprocessor PID in the CPU PID register
> - * to the PID held in the HFI window to determine if the transaction
> - * is allowed.
> - *
> - * When the task to release the HFI window, the HFI driver calls
> - * drop_cop() to release the coprocessor PID.
> - */
> -
> -#define COP_PID_NONE 0
> -#define COP_PID_MIN (COP_PID_NONE + 1)
> -#define COP_PID_MAX (0xFFFF)
> -
> -static DEFINE_SPINLOCK(mmu_context_acop_lock);
> -static DEFINE_IDA(cop_ida);
> -
> -void switch_cop(struct mm_struct *next)
> -{
> -     mtspr(SPRN_PID, next->context.cop_pid);
> -     mtspr(SPRN_ACOP, next->context.acop);
> -}
> -
> -static int new_cop_pid(struct ida *ida, int min_id, int max_id,
> -                    spinlock_t *lock)
> -{
> -     int index;
> -     int err;
> -
> -again:
> -     if (!ida_pre_get(ida, GFP_KERNEL))
> -             return -ENOMEM;
> -
> -     spin_lock(lock);
> -     err = ida_get_new_above(ida, min_id, &index);
> -     spin_unlock(lock);
> -
> -     if (err == -EAGAIN)
> -             goto again;
> -     else if (err)
> -             return err;
> -
> -     if (index > max_id) {
> -             spin_lock(lock);
> -             ida_remove(ida, index);
> -             spin_unlock(lock);
> -             return -ENOMEM;
> -     }
> -
> -     return index;
> -}
> -
> -static void sync_cop(void *arg)
> -{
> -     struct mm_struct *mm = arg;
> -
> -     if (mm == current->active_mm)
> -             switch_cop(current->active_mm);
> -}
> -
> -/**
> - * Start using a coprocessor.
> - * @acop: mask of coprocessor to be used.
> - * @mm: The mm the coprocessor to associate with. Most likely
> current mm.
> - *
> - * Return a positive PID if successful. Negative errno otherwise.
> - * The returned PID will be fed to the coprocessor to determine if an
> - * icswx transaction is authenticated.
> - */
> -int use_cop(unsigned long acop, struct mm_struct *mm)
> -{
> -     int ret;
> -
> -     if (!cpu_has_feature(CPU_FTR_ICSWX))
> -             return -ENODEV;
> -
> -     if (!mm || !acop)
> -             return -EINVAL;
> -
> -     /* We need to make sure mm_users doesn't change */
> -     down_read(&mm->mmap_sem);
> -     spin_lock(mm->context.cop_lockp);
> -
> -     if (mm->context.cop_pid == COP_PID_NONE) {
> -             ret = new_cop_pid(&cop_ida, COP_PID_MIN, COP_PID_MAX,
> -                               &mmu_context_acop_lock);
> -             if (ret < 0)
> -                     goto out;
> -
> -             mm->context.cop_pid = ret;
> -     }
> -     mm->context.acop |= acop;
> -
> -     sync_cop(mm);
> -
> -     /*
> -      * If this is a threaded process then there might be other
> threads
> -      * running. We need to send an IPI to force them to pick up
> any
> -      * change in PID and ACOP.
> -      */
> -     if (atomic_read(&mm->mm_users) > 1)
> -             smp_call_function(sync_cop, mm, 1);
> -
> -     ret = mm->context.cop_pid;
> -
> -out:
> -     spin_unlock(mm->context.cop_lockp);
> -     up_read(&mm->mmap_sem);
> -
> -     return ret;
> -}
> -EXPORT_SYMBOL_GPL(use_cop);
> -
> -/**
> - * Stop using a coprocessor.
> - * @acop: mask of coprocessor to be stopped.
> - * @mm: The mm the coprocessor associated with.
> - */
> -void drop_cop(unsigned long acop, struct mm_struct *mm)
> -{
> -     int free_pid = COP_PID_NONE;
> -
> -     if (!cpu_has_feature(CPU_FTR_ICSWX))
> -             return;
> -
> -     if (WARN_ON_ONCE(!mm))
> -             return;
> -
> -     /* We need to make sure mm_users doesn't change */
> -     down_read(&mm->mmap_sem);
> -     spin_lock(mm->context.cop_lockp);
> -
> -     mm->context.acop &= ~acop;
> -
> -     if ((!mm->context.acop) && (mm->context.cop_pid !=
> COP_PID_NONE)) {
> -             free_pid = mm->context.cop_pid;
> -             mm->context.cop_pid = COP_PID_NONE;
> -     }
> -
> -     sync_cop(mm);
> -
> -     /*
> -      * If this is a threaded process then there might be other
> threads
> -      * running. We need to send an IPI to force them to pick up
> any
> -      * change in PID and ACOP.
> -      */
> -     if (atomic_read(&mm->mm_users) > 1)
> -             smp_call_function(sync_cop, mm, 1);
> -
> -     if (free_pid != COP_PID_NONE) {
> -             spin_lock(&mmu_context_acop_lock);
> -             ida_remove(&cop_ida, free_pid);
> -             spin_unlock(&mmu_context_acop_lock);
> -     }
> -
> -     spin_unlock(mm->context.cop_lockp);
> -     up_read(&mm->mmap_sem);
> -}
> -EXPORT_SYMBOL_GPL(drop_cop);
> -
> -#endif /* CONFIG_PPC_ICSWX */
> -
>  static DEFINE_SPINLOCK(mmu_context_lock);
>  static DEFINE_IDA(mmu_context_ida);
>  
> diff --git a/arch/powerpc/platforms/Kconfig.cputype
> b/arch/powerpc/platforms/Kconfig.cputype index e06e395..3cd22e5 100644
> --- a/arch/powerpc/platforms/Kconfig.cputype
> +++ b/arch/powerpc/platforms/Kconfig.cputype
> @@ -234,7 +234,7 @@ config VSX
>  
>  config PPC_ICSWX
>       bool "Support for PowerPC icswx coprocessor instruction"
> -     depends on POWER4
> +     depends on POWER4 || PPC_A2
>       default n
>       ---help---
>  
> @@ -250,6 +250,14 @@ config PPC_ICSWX
>  
>         If in doubt, say N here.
>  
> +config PPC_ICSWX_PID
> +     bool "icswx requires direct PID management"
> +     depends on PPC_ICSWX && POWER4
> +     default y
> +     ---help---
> +       PID register in server is used explicitly for ICSWX.  In
> +       embedded systems PID managment is done by the system.
> +
>  config SPE
>       bool "SPE Support"
>       depends on E200 || (E500 && !PPC_E500MC)

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to