linux-parisc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
@ 2019-04-28 17:34 Helge Deller
  2019-05-01 14:22 ` Mikulas Patocka
  0 siblings, 1 reply; 10+ messages in thread
From: Helge Deller @ 2019-04-28 17:34 UTC (permalink / raw)
  To: Mikulas Patocka, John David Anglin, linux-parisc

This is a revised patch of the "per-pagetable spinlock patch" from
Mikulas, with additional edits from Dave Anglin and myself.
I've sucessfully (lightly) tested it on my L3000 (rp5470) machine which is based
on the Merced bus and needs TLB flush serialization.
Dave has sent an additional patch to fix the hugepages.
Please review and test....


PA-RISC uses a global spinlock to protect pagetable updates in the TLB
fault handlers. When multiple cores are taking TLB faults
simultaneously, the cache line containing the spinlock becomes a
bottleneck.

This patch embeds the spinlock in the top level page directory, so that
every process has its own lock. It improves performance by 30% when
doing parallel compilations.

At least on the N class systems, only one PxTLB inter processor
broadcast can be active at any one time on the Merced bus. If a Merced
bus is found, this patch serializes the TLB flushes with the
pa_tlb_flush_lock spinlock.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: John David Anglin <dave.anglin@bell.net>
Signed-off-by: Helge Deller <deller@gmx.de>

diff --git a/arch/parisc/include/asm/hardware.h b/arch/parisc/include/asm/hardware.h
index d6e1ed145031..9d3d7737c58b 100644
--- a/arch/parisc/include/asm/hardware.h
+++ b/arch/parisc/include/asm/hardware.h
@@ -120,7 +120,7 @@ extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
 extern void init_parisc_bus(void);
 extern struct device *hwpath_to_device(struct hardware_path *modpath);
 extern void device_to_hwpath(struct device *dev, struct hardware_path *path);
-
+extern int machine_has_merced_bus(void);

 /* inventory.c: */
 extern void do_memory_inventory(void);
diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h
index d05c678c77c4..ea75cc966dae 100644
--- a/arch/parisc/include/asm/pgalloc.h
+++ b/arch/parisc/include/asm/pgalloc.h
@@ -41,6 +41,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 		__pgd_val_set(*pgd, PxD_FLAG_ATTACHED);
 #endif
 	}
+	spin_lock_init(pgd_spinlock(actual_pgd));
 	return actual_pgd;
 }

diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
index c7bb74e22436..a39b079e73f2 100644
--- a/arch/parisc/include/asm/pgtable.h
+++ b/arch/parisc/include/asm/pgtable.h
@@ -17,7 +17,7 @@
 #include <asm/processor.h>
 #include <asm/cache.h>

-extern spinlock_t pa_tlb_lock;
+static inline spinlock_t *pgd_spinlock(pgd_t *);

 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
@@ -34,16 +34,46 @@ extern spinlock_t pa_tlb_lock;
  */
 #define kern_addr_valid(addr)	(1)

-/* Purge data and instruction TLB entries.  Must be called holding
- * the pa_tlb_lock.  The TLB purge instructions are slow on SMP
- * machines since the purge must be broadcast to all CPUs.
+/* This is for the serialization of PxTLB broadcasts. At least on the N class
+ * systems, only one PxTLB inter processor broadcast can be active at any one
+ * time on the Merced bus.
+
+ * PTE updates are protected by locks in the PMD.
+ */
+extern spinlock_t pa_tlb_flush_lock;
+extern spinlock_t pa_swapper_pg_lock;
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+extern int pa_serialize_tlb_flushes;
+#else
+#define pa_serialize_tlb_flushes        (0)
+#endif
+
+#define purge_tlb_start(flags)  do { \
+	if (pa_serialize_tlb_flushes)	\
+		spin_lock_irqsave(&pa_tlb_flush_lock, flags); \
+	else \
+		local_irq_save(flags);	\
+	} while (0)
+#define purge_tlb_end(flags)	do { \
+	if (pa_serialize_tlb_flushes)	\
+		spin_unlock_irqrestore(&pa_tlb_flush_lock, flags); \
+	else \
+		local_irq_restore(flags); \
+	} while (0)
+
+/* Purge data and instruction TLB entries. The TLB purge instructions
+ * are slow on SMP machines since the purge must be broadcast to all CPUs.
  */

 static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 {
+	unsigned long flags;
+
+	purge_tlb_start(flags);
 	mtsp(mm->context, 1);
 	pdtlb(addr);
 	pitlb(addr);
+	purge_tlb_end(flags);
 }

 /* Certain architectures need to do special things when PTEs
@@ -59,11 +89,11 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 	do {							\
 		pte_t old_pte;					\
 		unsigned long flags;				\
-		spin_lock_irqsave(&pa_tlb_lock, flags);		\
+		spin_lock_irqsave(pgd_spinlock((mm)->pgd), flags);\
 		old_pte = *ptep;				\
 		set_pte(ptep, pteval);				\
 		purge_tlb_entries(mm, addr);			\
-		spin_unlock_irqrestore(&pa_tlb_lock, flags);	\
+		spin_unlock_irqrestore(pgd_spinlock((mm)->pgd), flags);\
 	} while (0)

 #endif /* !__ASSEMBLY__ */
@@ -88,10 +118,10 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
 #if CONFIG_PGTABLE_LEVELS == 3
 #define PGD_ORDER	1 /* Number of pages per pgd */
 #define PMD_ORDER	1 /* Number of pages per pmd */
-#define PGD_ALLOC_ORDER	2 /* first pgd contains pmd */
+#define PGD_ALLOC_ORDER	(2 + 1) /* first pgd contains pmd */
 #else
 #define PGD_ORDER	1 /* Number of pages per pgd */
-#define PGD_ALLOC_ORDER	PGD_ORDER
+#define PGD_ALLOC_ORDER	(PGD_ORDER + 1)
 #endif

 /* Definitions for 3rd level (we use PLD here for Page Lower directory
@@ -459,6 +489,15 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
 #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
 #define __swp_entry_to_pte(x)		((pte_t) { (x).val })

+
+static inline spinlock_t *pgd_spinlock(pgd_t *pgd)
+{
+	if (unlikely(pgd == swapper_pg_dir))
+		return &pa_swapper_pg_lock;
+	return (spinlock_t *)((char *)pgd + (PAGE_SIZE << (PGD_ALLOC_ORDER - 1)));
+}
+
+
 static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
 {
 	pte_t pte;
@@ -467,15 +506,15 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
 	if (!pte_young(*ptep))
 		return 0;

-	spin_lock_irqsave(&pa_tlb_lock, flags);
+	spin_lock_irqsave(pgd_spinlock(vma->vm_mm->pgd), flags);
 	pte = *ptep;
 	if (!pte_young(pte)) {
-		spin_unlock_irqrestore(&pa_tlb_lock, flags);
+		spin_unlock_irqrestore(pgd_spinlock(vma->vm_mm->pgd), flags);
 		return 0;
 	}
 	set_pte(ptep, pte_mkold(pte));
 	purge_tlb_entries(vma->vm_mm, addr);
-	spin_unlock_irqrestore(&pa_tlb_lock, flags);
+	spin_unlock_irqrestore(pgd_spinlock(vma->vm_mm->pgd), flags);
 	return 1;
 }

@@ -485,11 +524,11 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 	pte_t old_pte;
 	unsigned long flags;

-	spin_lock_irqsave(&pa_tlb_lock, flags);
+	spin_lock_irqsave(pgd_spinlock(mm->pgd), flags);
 	old_pte = *ptep;
 	set_pte(ptep, __pte(0));
 	purge_tlb_entries(mm, addr);
-	spin_unlock_irqrestore(&pa_tlb_lock, flags);
+	spin_unlock_irqrestore(pgd_spinlock(mm->pgd), flags);

 	return old_pte;
 }
@@ -497,10 +536,10 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
 static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
 	unsigned long flags;
-	spin_lock_irqsave(&pa_tlb_lock, flags);
+	spin_lock_irqsave(pgd_spinlock(mm->pgd), flags);
 	set_pte(ptep, pte_wrprotect(*ptep));
 	purge_tlb_entries(mm, addr);
-	spin_unlock_irqrestore(&pa_tlb_lock, flags);
+	spin_unlock_irqrestore(pgd_spinlock(mm->pgd), flags);
 }

 #define pte_same(A,B)	(pte_val(A) == pte_val(B))
diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
index 6804374efa66..c5ded01d45be 100644
--- a/arch/parisc/include/asm/tlbflush.h
+++ b/arch/parisc/include/asm/tlbflush.h
@@ -8,21 +8,6 @@
 #include <linux/sched.h>
 #include <asm/mmu_context.h>

-
-/* This is for the serialisation of PxTLB broadcasts.  At least on the
- * N class systems, only one PxTLB inter processor broadcast can be
- * active at any one time on the Merced bus.  This tlb purge
- * synchronisation is fairly lightweight and harmless so we activate
- * it on all systems not just the N class.
-
- * It is also used to ensure PTE updates are atomic and consistent
- * with the TLB.
- */
-extern spinlock_t pa_tlb_lock;
-
-#define purge_tlb_start(flags)	spin_lock_irqsave(&pa_tlb_lock, flags)
-#define purge_tlb_end(flags)	spin_unlock_irqrestore(&pa_tlb_lock, flags)
-
 extern void flush_tlb_all(void);
 extern void flush_tlb_all_local(void *);

@@ -79,13 +64,6 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
 static inline void flush_tlb_page(struct vm_area_struct *vma,
 	unsigned long addr)
 {
-	unsigned long flags, sid;
-
-	sid = vma->vm_mm->context;
-	purge_tlb_start(flags);
-	mtsp(sid, 1);
-	pdtlb(addr);
-	pitlb(addr);
-	purge_tlb_end(flags);
+	purge_tlb_entries(vma->vm_mm, addr);
 }
 #endif
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index 804880efa11e..0338561968a4 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -40,12 +40,19 @@ void purge_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
 void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr);


-/* On some machines (e.g. ones with the Merced bus), there can be
+/* On some machines (i.e., ones with the Merced bus), there can be
  * only a single PxTLB broadcast at a time; this must be guaranteed
- * by software.  We put a spinlock around all TLB flushes  to
- * ensure this.
+ * by software. We need a spinlock around all TLB flushes to ensure
+ * this.
  */
-DEFINE_SPINLOCK(pa_tlb_lock);
+DEFINE_SPINLOCK(pa_tlb_flush_lock);
+
+/* Swapper page setup lock. */
+DEFINE_SPINLOCK(pa_swapper_pg_lock);
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+int pa_serialize_tlb_flushes __read_mostly;
+#endif

 struct pdc_cache_info cache_info __read_mostly;
 #ifndef CONFIG_PA20
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 5eb979d04b90..15e7b3be7b6b 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -38,6 +38,7 @@
 #include <asm/io.h>
 #include <asm/pdc.h>
 #include <asm/parisc-device.h>
+#include <asm/ropes.h>

 /* See comments in include/asm-parisc/pci.h */
 const struct dma_map_ops *hppa_dma_ops __read_mostly;
@@ -257,6 +258,30 @@ static struct parisc_device *find_device_by_addr(unsigned long hpa)
 	return ret ? d.dev : NULL;
 }

+static int __init is_IKE_device(struct device *dev, void *data)
+{
+	struct parisc_device *pdev = to_parisc_device(dev);
+
+	if (!check_dev(dev))
+		return 0;
+	if (pdev->id.hw_type != HPHW_BCPORT)
+		return 0;
+	if (IS_IKE(pdev) ||
+		(pdev->id.hversion == REO_MERCED_PORT) ||
+		(pdev->id.hversion == REOG_MERCED_PORT)) {
+			return 1;
+	}
+	return 0;
+}
+
+int __init machine_has_merced_bus(void)
+{
+	int ret;
+
+	ret = for_each_padev(is_IKE_device, NULL);
+	return ret ? 1 : 0;
+}
+
 /**
  * find_pa_parent_type - Find a parent of a specific type
  * @dev: The device to start searching from
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 5796524a3137..a1fc04570ade 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -50,12 +50,8 @@

 	.import		pa_tlb_lock,data
 	.macro  load_pa_tlb_lock reg
-#if __PA_LDCW_ALIGNMENT > 4
-	load32	PA(pa_tlb_lock) + __PA_LDCW_ALIGNMENT-1, \reg
-	depi	0,31,__PA_LDCW_ALIGN_ORDER, \reg
-#else
-	load32	PA(pa_tlb_lock), \reg
-#endif
+	mfctl		%cr25,\reg
+	addil		L%(PAGE_SIZE << (PGD_ALLOC_ORDER - 1)),\reg
 	.endm

 	/* space_to_prot macro creates a prot id from a space id */
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
index 35d05fdd7483..6f2d611347a1 100644
--- a/arch/parisc/kernel/inventory.c
+++ b/arch/parisc/kernel/inventory.c
@@ -31,6 +31,7 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/parisc-device.h>
+#include <asm/tlbflush.h>

 /*
 ** Debug options
@@ -638,4 +639,10 @@ void __init do_device_inventory(void)
 	}
 	printk(KERN_INFO "Found devices:\n");
 	print_parisc_devices();
+
+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+	pa_serialize_tlb_flushes = machine_has_merced_bus();
+	if (pa_serialize_tlb_flushes)
+		pr_info("Merced bus found: Enable PxTLB serialization.\n");
+#endif
 }
diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
index d908058d05c1..e05cb2a5c16d 100644
--- a/arch/parisc/kernel/setup.c
+++ b/arch/parisc/kernel/setup.c
@@ -343,6 +343,12 @@ static int __init parisc_init(void)
 			boot_cpu_data.cpu_hz / 1000000,
 			boot_cpu_data.cpu_hz % 1000000	);

+#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
+	/* Don't serialize TLB flushes if we run on one CPU only. */
+	if (num_online_cpus() == 1)
+		pa_serialize_tlb_flushes = 0;
+#endif
+
 	apply_alternatives_all();
 	parisc_setup_cache_timing();


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-04-28 17:34 [PATCH][RFC] parisc: Use per-pagetable spinlock (v2) Helge Deller
@ 2019-05-01 14:22 ` Mikulas Patocka
  2019-05-01 14:34   ` Helge Deller
  0 siblings, 1 reply; 10+ messages in thread
From: Mikulas Patocka @ 2019-05-01 14:22 UTC (permalink / raw)
  To: Helge Deller; +Cc: John David Anglin, linux-parisc

Hi

I tested it on C8000 and confim that it works.

Mikulas


On Sun, 28 Apr 2019, Helge Deller wrote:

> This is a revised patch of the "per-pagetable spinlock patch" from
> Mikulas, with additional edits from Dave Anglin and myself.
> I've sucessfully (lightly) tested it on my L3000 (rp5470) machine which is based
> on the Merced bus and needs TLB flush serialization.
> Dave has sent an additional patch to fix the hugepages.
> Please review and test....
> 
> 
> PA-RISC uses a global spinlock to protect pagetable updates in the TLB
> fault handlers. When multiple cores are taking TLB faults
> simultaneously, the cache line containing the spinlock becomes a
> bottleneck.
> 
> This patch embeds the spinlock in the top level page directory, so that
> every process has its own lock. It improves performance by 30% when
> doing parallel compilations.
> 
> At least on the N class systems, only one PxTLB inter processor
> broadcast can be active at any one time on the Merced bus. If a Merced
> bus is found, this patch serializes the TLB flushes with the
> pa_tlb_flush_lock spinlock.
> 
> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
> Signed-off-by: John David Anglin <dave.anglin@bell.net>
> Signed-off-by: Helge Deller <deller@gmx.de>
> 
> diff --git a/arch/parisc/include/asm/hardware.h b/arch/parisc/include/asm/hardware.h
> index d6e1ed145031..9d3d7737c58b 100644
> --- a/arch/parisc/include/asm/hardware.h
> +++ b/arch/parisc/include/asm/hardware.h
> @@ -120,7 +120,7 @@ extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
>  extern void init_parisc_bus(void);
>  extern struct device *hwpath_to_device(struct hardware_path *modpath);
>  extern void device_to_hwpath(struct device *dev, struct hardware_path *path);
> -
> +extern int machine_has_merced_bus(void);
> 
>  /* inventory.c: */
>  extern void do_memory_inventory(void);
> diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h
> index d05c678c77c4..ea75cc966dae 100644
> --- a/arch/parisc/include/asm/pgalloc.h
> +++ b/arch/parisc/include/asm/pgalloc.h
> @@ -41,6 +41,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
>  		__pgd_val_set(*pgd, PxD_FLAG_ATTACHED);
>  #endif
>  	}
> +	spin_lock_init(pgd_spinlock(actual_pgd));
>  	return actual_pgd;
>  }
> 
> diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
> index c7bb74e22436..a39b079e73f2 100644
> --- a/arch/parisc/include/asm/pgtable.h
> +++ b/arch/parisc/include/asm/pgtable.h
> @@ -17,7 +17,7 @@
>  #include <asm/processor.h>
>  #include <asm/cache.h>
> 
> -extern spinlock_t pa_tlb_lock;
> +static inline spinlock_t *pgd_spinlock(pgd_t *);
> 
>  /*
>   * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
> @@ -34,16 +34,46 @@ extern spinlock_t pa_tlb_lock;
>   */
>  #define kern_addr_valid(addr)	(1)
> 
> -/* Purge data and instruction TLB entries.  Must be called holding
> - * the pa_tlb_lock.  The TLB purge instructions are slow on SMP
> - * machines since the purge must be broadcast to all CPUs.
> +/* This is for the serialization of PxTLB broadcasts. At least on the N class
> + * systems, only one PxTLB inter processor broadcast can be active at any one
> + * time on the Merced bus.
> +
> + * PTE updates are protected by locks in the PMD.
> + */
> +extern spinlock_t pa_tlb_flush_lock;
> +extern spinlock_t pa_swapper_pg_lock;
> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
> +extern int pa_serialize_tlb_flushes;
> +#else
> +#define pa_serialize_tlb_flushes        (0)
> +#endif
> +
> +#define purge_tlb_start(flags)  do { \
> +	if (pa_serialize_tlb_flushes)	\
> +		spin_lock_irqsave(&pa_tlb_flush_lock, flags); \
> +	else \
> +		local_irq_save(flags);	\
> +	} while (0)
> +#define purge_tlb_end(flags)	do { \
> +	if (pa_serialize_tlb_flushes)	\
> +		spin_unlock_irqrestore(&pa_tlb_flush_lock, flags); \
> +	else \
> +		local_irq_restore(flags); \
> +	} while (0)
> +
> +/* Purge data and instruction TLB entries. The TLB purge instructions
> + * are slow on SMP machines since the purge must be broadcast to all CPUs.
>   */
> 
>  static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
>  {
> +	unsigned long flags;
> +
> +	purge_tlb_start(flags);
>  	mtsp(mm->context, 1);
>  	pdtlb(addr);
>  	pitlb(addr);
> +	purge_tlb_end(flags);
>  }
> 
>  /* Certain architectures need to do special things when PTEs
> @@ -59,11 +89,11 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
>  	do {							\
>  		pte_t old_pte;					\
>  		unsigned long flags;				\
> -		spin_lock_irqsave(&pa_tlb_lock, flags);		\
> +		spin_lock_irqsave(pgd_spinlock((mm)->pgd), flags);\
>  		old_pte = *ptep;				\
>  		set_pte(ptep, pteval);				\
>  		purge_tlb_entries(mm, addr);			\
> -		spin_unlock_irqrestore(&pa_tlb_lock, flags);	\
> +		spin_unlock_irqrestore(pgd_spinlock((mm)->pgd), flags);\
>  	} while (0)
> 
>  #endif /* !__ASSEMBLY__ */
> @@ -88,10 +118,10 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
>  #if CONFIG_PGTABLE_LEVELS == 3
>  #define PGD_ORDER	1 /* Number of pages per pgd */
>  #define PMD_ORDER	1 /* Number of pages per pmd */
> -#define PGD_ALLOC_ORDER	2 /* first pgd contains pmd */
> +#define PGD_ALLOC_ORDER	(2 + 1) /* first pgd contains pmd */
>  #else
>  #define PGD_ORDER	1 /* Number of pages per pgd */
> -#define PGD_ALLOC_ORDER	PGD_ORDER
> +#define PGD_ALLOC_ORDER	(PGD_ORDER + 1)
>  #endif
> 
>  /* Definitions for 3rd level (we use PLD here for Page Lower directory
> @@ -459,6 +489,15 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
>  #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
>  #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
> 
> +
> +static inline spinlock_t *pgd_spinlock(pgd_t *pgd)
> +{
> +	if (unlikely(pgd == swapper_pg_dir))
> +		return &pa_swapper_pg_lock;
> +	return (spinlock_t *)((char *)pgd + (PAGE_SIZE << (PGD_ALLOC_ORDER - 1)));
> +}
> +
> +
>  static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
>  {
>  	pte_t pte;
> @@ -467,15 +506,15 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
>  	if (!pte_young(*ptep))
>  		return 0;
> 
> -	spin_lock_irqsave(&pa_tlb_lock, flags);
> +	spin_lock_irqsave(pgd_spinlock(vma->vm_mm->pgd), flags);
>  	pte = *ptep;
>  	if (!pte_young(pte)) {
> -		spin_unlock_irqrestore(&pa_tlb_lock, flags);
> +		spin_unlock_irqrestore(pgd_spinlock(vma->vm_mm->pgd), flags);
>  		return 0;
>  	}
>  	set_pte(ptep, pte_mkold(pte));
>  	purge_tlb_entries(vma->vm_mm, addr);
> -	spin_unlock_irqrestore(&pa_tlb_lock, flags);
> +	spin_unlock_irqrestore(pgd_spinlock(vma->vm_mm->pgd), flags);
>  	return 1;
>  }
> 
> @@ -485,11 +524,11 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
>  	pte_t old_pte;
>  	unsigned long flags;
> 
> -	spin_lock_irqsave(&pa_tlb_lock, flags);
> +	spin_lock_irqsave(pgd_spinlock(mm->pgd), flags);
>  	old_pte = *ptep;
>  	set_pte(ptep, __pte(0));
>  	purge_tlb_entries(mm, addr);
> -	spin_unlock_irqrestore(&pa_tlb_lock, flags);
> +	spin_unlock_irqrestore(pgd_spinlock(mm->pgd), flags);
> 
>  	return old_pte;
>  }
> @@ -497,10 +536,10 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
>  static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
>  {
>  	unsigned long flags;
> -	spin_lock_irqsave(&pa_tlb_lock, flags);
> +	spin_lock_irqsave(pgd_spinlock(mm->pgd), flags);
>  	set_pte(ptep, pte_wrprotect(*ptep));
>  	purge_tlb_entries(mm, addr);
> -	spin_unlock_irqrestore(&pa_tlb_lock, flags);
> +	spin_unlock_irqrestore(pgd_spinlock(mm->pgd), flags);
>  }
> 
>  #define pte_same(A,B)	(pte_val(A) == pte_val(B))
> diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
> index 6804374efa66..c5ded01d45be 100644
> --- a/arch/parisc/include/asm/tlbflush.h
> +++ b/arch/parisc/include/asm/tlbflush.h
> @@ -8,21 +8,6 @@
>  #include <linux/sched.h>
>  #include <asm/mmu_context.h>
> 
> -
> -/* This is for the serialisation of PxTLB broadcasts.  At least on the
> - * N class systems, only one PxTLB inter processor broadcast can be
> - * active at any one time on the Merced bus.  This tlb purge
> - * synchronisation is fairly lightweight and harmless so we activate
> - * it on all systems not just the N class.
> -
> - * It is also used to ensure PTE updates are atomic and consistent
> - * with the TLB.
> - */
> -extern spinlock_t pa_tlb_lock;
> -
> -#define purge_tlb_start(flags)	spin_lock_irqsave(&pa_tlb_lock, flags)
> -#define purge_tlb_end(flags)	spin_unlock_irqrestore(&pa_tlb_lock, flags)
> -
>  extern void flush_tlb_all(void);
>  extern void flush_tlb_all_local(void *);
> 
> @@ -79,13 +64,6 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
>  static inline void flush_tlb_page(struct vm_area_struct *vma,
>  	unsigned long addr)
>  {
> -	unsigned long flags, sid;
> -
> -	sid = vma->vm_mm->context;
> -	purge_tlb_start(flags);
> -	mtsp(sid, 1);
> -	pdtlb(addr);
> -	pitlb(addr);
> -	purge_tlb_end(flags);
> +	purge_tlb_entries(vma->vm_mm, addr);
>  }
>  #endif
> diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
> index 804880efa11e..0338561968a4 100644
> --- a/arch/parisc/kernel/cache.c
> +++ b/arch/parisc/kernel/cache.c
> @@ -40,12 +40,19 @@ void purge_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
>  void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr);
> 
> 
> -/* On some machines (e.g. ones with the Merced bus), there can be
> +/* On some machines (i.e., ones with the Merced bus), there can be
>   * only a single PxTLB broadcast at a time; this must be guaranteed
> - * by software.  We put a spinlock around all TLB flushes  to
> - * ensure this.
> + * by software. We need a spinlock around all TLB flushes to ensure
> + * this.
>   */
> -DEFINE_SPINLOCK(pa_tlb_lock);
> +DEFINE_SPINLOCK(pa_tlb_flush_lock);
> +
> +/* Swapper page setup lock. */
> +DEFINE_SPINLOCK(pa_swapper_pg_lock);
> +
> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
> +int pa_serialize_tlb_flushes __read_mostly;
> +#endif
> 
>  struct pdc_cache_info cache_info __read_mostly;
>  #ifndef CONFIG_PA20
> diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
> index 5eb979d04b90..15e7b3be7b6b 100644
> --- a/arch/parisc/kernel/drivers.c
> +++ b/arch/parisc/kernel/drivers.c
> @@ -38,6 +38,7 @@
>  #include <asm/io.h>
>  #include <asm/pdc.h>
>  #include <asm/parisc-device.h>
> +#include <asm/ropes.h>
> 
>  /* See comments in include/asm-parisc/pci.h */
>  const struct dma_map_ops *hppa_dma_ops __read_mostly;
> @@ -257,6 +258,30 @@ static struct parisc_device *find_device_by_addr(unsigned long hpa)
>  	return ret ? d.dev : NULL;
>  }
> 
> +static int __init is_IKE_device(struct device *dev, void *data)
> +{
> +	struct parisc_device *pdev = to_parisc_device(dev);
> +
> +	if (!check_dev(dev))
> +		return 0;
> +	if (pdev->id.hw_type != HPHW_BCPORT)
> +		return 0;
> +	if (IS_IKE(pdev) ||
> +		(pdev->id.hversion == REO_MERCED_PORT) ||
> +		(pdev->id.hversion == REOG_MERCED_PORT)) {
> +			return 1;
> +	}
> +	return 0;
> +}
> +
> +int __init machine_has_merced_bus(void)
> +{
> +	int ret;
> +
> +	ret = for_each_padev(is_IKE_device, NULL);
> +	return ret ? 1 : 0;
> +}
> +
>  /**
>   * find_pa_parent_type - Find a parent of a specific type
>   * @dev: The device to start searching from
> diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
> index 5796524a3137..a1fc04570ade 100644
> --- a/arch/parisc/kernel/entry.S
> +++ b/arch/parisc/kernel/entry.S
> @@ -50,12 +50,8 @@
> 
>  	.import		pa_tlb_lock,data
>  	.macro  load_pa_tlb_lock reg
> -#if __PA_LDCW_ALIGNMENT > 4
> -	load32	PA(pa_tlb_lock) + __PA_LDCW_ALIGNMENT-1, \reg
> -	depi	0,31,__PA_LDCW_ALIGN_ORDER, \reg
> -#else
> -	load32	PA(pa_tlb_lock), \reg
> -#endif
> +	mfctl		%cr25,\reg
> +	addil		L%(PAGE_SIZE << (PGD_ALLOC_ORDER - 1)),\reg
>  	.endm
> 
>  	/* space_to_prot macro creates a prot id from a space id */
> diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
> index 35d05fdd7483..6f2d611347a1 100644
> --- a/arch/parisc/kernel/inventory.c
> +++ b/arch/parisc/kernel/inventory.c
> @@ -31,6 +31,7 @@
>  #include <asm/processor.h>
>  #include <asm/page.h>
>  #include <asm/parisc-device.h>
> +#include <asm/tlbflush.h>
> 
>  /*
>  ** Debug options
> @@ -638,4 +639,10 @@ void __init do_device_inventory(void)
>  	}
>  	printk(KERN_INFO "Found devices:\n");
>  	print_parisc_devices();
> +
> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
> +	pa_serialize_tlb_flushes = machine_has_merced_bus();
> +	if (pa_serialize_tlb_flushes)
> +		pr_info("Merced bus found: Enable PxTLB serialization.\n");
> +#endif
>  }
> diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
> index d908058d05c1..e05cb2a5c16d 100644
> --- a/arch/parisc/kernel/setup.c
> +++ b/arch/parisc/kernel/setup.c
> @@ -343,6 +343,12 @@ static int __init parisc_init(void)
>  			boot_cpu_data.cpu_hz / 1000000,
>  			boot_cpu_data.cpu_hz % 1000000	);
> 
> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
> +	/* Don't serialize TLB flushes if we run on one CPU only. */
> +	if (num_online_cpus() == 1)
> +		pa_serialize_tlb_flushes = 0;
> +#endif
> +
>  	apply_alternatives_all();
>  	parisc_setup_cache_timing();
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-01 14:22 ` Mikulas Patocka
@ 2019-05-01 14:34   ` Helge Deller
  2019-05-01 16:21     ` Mikulas Patocka
  0 siblings, 1 reply; 10+ messages in thread
From: Helge Deller @ 2019-05-01 14:34 UTC (permalink / raw)
  To: Mikulas Patocka; +Cc: John David Anglin, linux-parisc

Hi Mikulas,

On 01.05.19 16:22, Mikulas Patocka wrote:
> I tested it on C8000 and confim that it works.

Thanks for testing!

By the way, I made you the author of the patch in git:
https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next&id=f1abe94b271807902d5b286c7216b812645713e2

In general, there are so many new cool features and patches pending
in the for-next tree, so I appreciate every kind of testing:
https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next

Helge

> On Sun, 28 Apr 2019, Helge Deller wrote:
>
>> This is a revised patch of the "per-pagetable spinlock patch" from
>> Mikulas, with additional edits from Dave Anglin and myself.
>> I've sucessfully (lightly) tested it on my L3000 (rp5470) machine which is based
>> on the Merced bus and needs TLB flush serialization.
>> Dave has sent an additional patch to fix the hugepages.
>> Please review and test....
>>
>>
>> PA-RISC uses a global spinlock to protect pagetable updates in the TLB
>> fault handlers. When multiple cores are taking TLB faults
>> simultaneously, the cache line containing the spinlock becomes a
>> bottleneck.
>>
>> This patch embeds the spinlock in the top level page directory, so that
>> every process has its own lock. It improves performance by 30% when
>> doing parallel compilations.
>>
>> At least on the N class systems, only one PxTLB inter processor
>> broadcast can be active at any one time on the Merced bus. If a Merced
>> bus is found, this patch serializes the TLB flushes with the
>> pa_tlb_flush_lock spinlock.
>>
>> Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
>> Signed-off-by: John David Anglin <dave.anglin@bell.net>
>> Signed-off-by: Helge Deller <deller@gmx.de>
>>
>> diff --git a/arch/parisc/include/asm/hardware.h b/arch/parisc/include/asm/hardware.h
>> index d6e1ed145031..9d3d7737c58b 100644
>> --- a/arch/parisc/include/asm/hardware.h
>> +++ b/arch/parisc/include/asm/hardware.h
>> @@ -120,7 +120,7 @@ extern void get_pci_node_path(struct pci_dev *dev, struct hardware_path *path);
>>  extern void init_parisc_bus(void);
>>  extern struct device *hwpath_to_device(struct hardware_path *modpath);
>>  extern void device_to_hwpath(struct device *dev, struct hardware_path *path);
>> -
>> +extern int machine_has_merced_bus(void);
>>
>>  /* inventory.c: */
>>  extern void do_memory_inventory(void);
>> diff --git a/arch/parisc/include/asm/pgalloc.h b/arch/parisc/include/asm/pgalloc.h
>> index d05c678c77c4..ea75cc966dae 100644
>> --- a/arch/parisc/include/asm/pgalloc.h
>> +++ b/arch/parisc/include/asm/pgalloc.h
>> @@ -41,6 +41,7 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
>>  		__pgd_val_set(*pgd, PxD_FLAG_ATTACHED);
>>  #endif
>>  	}
>> +	spin_lock_init(pgd_spinlock(actual_pgd));
>>  	return actual_pgd;
>>  }
>>
>> diff --git a/arch/parisc/include/asm/pgtable.h b/arch/parisc/include/asm/pgtable.h
>> index c7bb74e22436..a39b079e73f2 100644
>> --- a/arch/parisc/include/asm/pgtable.h
>> +++ b/arch/parisc/include/asm/pgtable.h
>> @@ -17,7 +17,7 @@
>>  #include <asm/processor.h>
>>  #include <asm/cache.h>
>>
>> -extern spinlock_t pa_tlb_lock;
>> +static inline spinlock_t *pgd_spinlock(pgd_t *);
>>
>>  /*
>>   * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
>> @@ -34,16 +34,46 @@ extern spinlock_t pa_tlb_lock;
>>   */
>>  #define kern_addr_valid(addr)	(1)
>>
>> -/* Purge data and instruction TLB entries.  Must be called holding
>> - * the pa_tlb_lock.  The TLB purge instructions are slow on SMP
>> - * machines since the purge must be broadcast to all CPUs.
>> +/* This is for the serialization of PxTLB broadcasts. At least on the N class
>> + * systems, only one PxTLB inter processor broadcast can be active at any one
>> + * time on the Merced bus.
>> +
>> + * PTE updates are protected by locks in the PMD.
>> + */
>> +extern spinlock_t pa_tlb_flush_lock;
>> +extern spinlock_t pa_swapper_pg_lock;
>> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
>> +extern int pa_serialize_tlb_flushes;
>> +#else
>> +#define pa_serialize_tlb_flushes        (0)
>> +#endif
>> +
>> +#define purge_tlb_start(flags)  do { \
>> +	if (pa_serialize_tlb_flushes)	\
>> +		spin_lock_irqsave(&pa_tlb_flush_lock, flags); \
>> +	else \
>> +		local_irq_save(flags);	\
>> +	} while (0)
>> +#define purge_tlb_end(flags)	do { \
>> +	if (pa_serialize_tlb_flushes)	\
>> +		spin_unlock_irqrestore(&pa_tlb_flush_lock, flags); \
>> +	else \
>> +		local_irq_restore(flags); \
>> +	} while (0)
>> +
>> +/* Purge data and instruction TLB entries. The TLB purge instructions
>> + * are slow on SMP machines since the purge must be broadcast to all CPUs.
>>   */
>>
>>  static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
>>  {
>> +	unsigned long flags;
>> +
>> +	purge_tlb_start(flags);
>>  	mtsp(mm->context, 1);
>>  	pdtlb(addr);
>>  	pitlb(addr);
>> +	purge_tlb_end(flags);
>>  }
>>
>>  /* Certain architectures need to do special things when PTEs
>> @@ -59,11 +89,11 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
>>  	do {							\
>>  		pte_t old_pte;					\
>>  		unsigned long flags;				\
>> -		spin_lock_irqsave(&pa_tlb_lock, flags);		\
>> +		spin_lock_irqsave(pgd_spinlock((mm)->pgd), flags);\
>>  		old_pte = *ptep;				\
>>  		set_pte(ptep, pteval);				\
>>  		purge_tlb_entries(mm, addr);			\
>> -		spin_unlock_irqrestore(&pa_tlb_lock, flags);	\
>> +		spin_unlock_irqrestore(pgd_spinlock((mm)->pgd), flags);\
>>  	} while (0)
>>
>>  #endif /* !__ASSEMBLY__ */
>> @@ -88,10 +118,10 @@ static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
>>  #if CONFIG_PGTABLE_LEVELS == 3
>>  #define PGD_ORDER	1 /* Number of pages per pgd */
>>  #define PMD_ORDER	1 /* Number of pages per pmd */
>> -#define PGD_ALLOC_ORDER	2 /* first pgd contains pmd */
>> +#define PGD_ALLOC_ORDER	(2 + 1) /* first pgd contains pmd */
>>  #else
>>  #define PGD_ORDER	1 /* Number of pages per pgd */
>> -#define PGD_ALLOC_ORDER	PGD_ORDER
>> +#define PGD_ALLOC_ORDER	(PGD_ORDER + 1)
>>  #endif
>>
>>  /* Definitions for 3rd level (we use PLD here for Page Lower directory
>> @@ -459,6 +489,15 @@ extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t *);
>>  #define __pte_to_swp_entry(pte)		((swp_entry_t) { pte_val(pte) })
>>  #define __swp_entry_to_pte(x)		((pte_t) { (x).val })
>>
>> +
>> +static inline spinlock_t *pgd_spinlock(pgd_t *pgd)
>> +{
>> +	if (unlikely(pgd == swapper_pg_dir))
>> +		return &pa_swapper_pg_lock;
>> +	return (spinlock_t *)((char *)pgd + (PAGE_SIZE << (PGD_ALLOC_ORDER - 1)));
>> +}
>> +
>> +
>>  static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
>>  {
>>  	pte_t pte;
>> @@ -467,15 +506,15 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
>>  	if (!pte_young(*ptep))
>>  		return 0;
>>
>> -	spin_lock_irqsave(&pa_tlb_lock, flags);
>> +	spin_lock_irqsave(pgd_spinlock(vma->vm_mm->pgd), flags);
>>  	pte = *ptep;
>>  	if (!pte_young(pte)) {
>> -		spin_unlock_irqrestore(&pa_tlb_lock, flags);
>> +		spin_unlock_irqrestore(pgd_spinlock(vma->vm_mm->pgd), flags);
>>  		return 0;
>>  	}
>>  	set_pte(ptep, pte_mkold(pte));
>>  	purge_tlb_entries(vma->vm_mm, addr);
>> -	spin_unlock_irqrestore(&pa_tlb_lock, flags);
>> +	spin_unlock_irqrestore(pgd_spinlock(vma->vm_mm->pgd), flags);
>>  	return 1;
>>  }
>>
>> @@ -485,11 +524,11 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
>>  	pte_t old_pte;
>>  	unsigned long flags;
>>
>> -	spin_lock_irqsave(&pa_tlb_lock, flags);
>> +	spin_lock_irqsave(pgd_spinlock(mm->pgd), flags);
>>  	old_pte = *ptep;
>>  	set_pte(ptep, __pte(0));
>>  	purge_tlb_entries(mm, addr);
>> -	spin_unlock_irqrestore(&pa_tlb_lock, flags);
>> +	spin_unlock_irqrestore(pgd_spinlock(mm->pgd), flags);
>>
>>  	return old_pte;
>>  }
>> @@ -497,10 +536,10 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
>>  static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
>>  {
>>  	unsigned long flags;
>> -	spin_lock_irqsave(&pa_tlb_lock, flags);
>> +	spin_lock_irqsave(pgd_spinlock(mm->pgd), flags);
>>  	set_pte(ptep, pte_wrprotect(*ptep));
>>  	purge_tlb_entries(mm, addr);
>> -	spin_unlock_irqrestore(&pa_tlb_lock, flags);
>> +	spin_unlock_irqrestore(pgd_spinlock(mm->pgd), flags);
>>  }
>>
>>  #define pte_same(A,B)	(pte_val(A) == pte_val(B))
>> diff --git a/arch/parisc/include/asm/tlbflush.h b/arch/parisc/include/asm/tlbflush.h
>> index 6804374efa66..c5ded01d45be 100644
>> --- a/arch/parisc/include/asm/tlbflush.h
>> +++ b/arch/parisc/include/asm/tlbflush.h
>> @@ -8,21 +8,6 @@
>>  #include <linux/sched.h>
>>  #include <asm/mmu_context.h>
>>
>> -
>> -/* This is for the serialisation of PxTLB broadcasts.  At least on the
>> - * N class systems, only one PxTLB inter processor broadcast can be
>> - * active at any one time on the Merced bus.  This tlb purge
>> - * synchronisation is fairly lightweight and harmless so we activate
>> - * it on all systems not just the N class.
>> -
>> - * It is also used to ensure PTE updates are atomic and consistent
>> - * with the TLB.
>> - */
>> -extern spinlock_t pa_tlb_lock;
>> -
>> -#define purge_tlb_start(flags)	spin_lock_irqsave(&pa_tlb_lock, flags)
>> -#define purge_tlb_end(flags)	spin_unlock_irqrestore(&pa_tlb_lock, flags)
>> -
>>  extern void flush_tlb_all(void);
>>  extern void flush_tlb_all_local(void *);
>>
>> @@ -79,13 +64,6 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
>>  static inline void flush_tlb_page(struct vm_area_struct *vma,
>>  	unsigned long addr)
>>  {
>> -	unsigned long flags, sid;
>> -
>> -	sid = vma->vm_mm->context;
>> -	purge_tlb_start(flags);
>> -	mtsp(sid, 1);
>> -	pdtlb(addr);
>> -	pitlb(addr);
>> -	purge_tlb_end(flags);
>> +	purge_tlb_entries(vma->vm_mm, addr);
>>  }
>>  #endif
>> diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
>> index 804880efa11e..0338561968a4 100644
>> --- a/arch/parisc/kernel/cache.c
>> +++ b/arch/parisc/kernel/cache.c
>> @@ -40,12 +40,19 @@ void purge_dcache_page_asm(unsigned long phys_addr, unsigned long vaddr);
>>  void flush_icache_page_asm(unsigned long phys_addr, unsigned long vaddr);
>>
>>
>> -/* On some machines (e.g. ones with the Merced bus), there can be
>> +/* On some machines (i.e., ones with the Merced bus), there can be
>>   * only a single PxTLB broadcast at a time; this must be guaranteed
>> - * by software.  We put a spinlock around all TLB flushes  to
>> - * ensure this.
>> + * by software. We need a spinlock around all TLB flushes to ensure
>> + * this.
>>   */
>> -DEFINE_SPINLOCK(pa_tlb_lock);
>> +DEFINE_SPINLOCK(pa_tlb_flush_lock);
>> +
>> +/* Swapper page setup lock. */
>> +DEFINE_SPINLOCK(pa_swapper_pg_lock);
>> +
>> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
>> +int pa_serialize_tlb_flushes __read_mostly;
>> +#endif
>>
>>  struct pdc_cache_info cache_info __read_mostly;
>>  #ifndef CONFIG_PA20
>> diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
>> index 5eb979d04b90..15e7b3be7b6b 100644
>> --- a/arch/parisc/kernel/drivers.c
>> +++ b/arch/parisc/kernel/drivers.c
>> @@ -38,6 +38,7 @@
>>  #include <asm/io.h>
>>  #include <asm/pdc.h>
>>  #include <asm/parisc-device.h>
>> +#include <asm/ropes.h>
>>
>>  /* See comments in include/asm-parisc/pci.h */
>>  const struct dma_map_ops *hppa_dma_ops __read_mostly;
>> @@ -257,6 +258,30 @@ static struct parisc_device *find_device_by_addr(unsigned long hpa)
>>  	return ret ? d.dev : NULL;
>>  }
>>
>> +static int __init is_IKE_device(struct device *dev, void *data)
>> +{
>> +	struct parisc_device *pdev = to_parisc_device(dev);
>> +
>> +	if (!check_dev(dev))
>> +		return 0;
>> +	if (pdev->id.hw_type != HPHW_BCPORT)
>> +		return 0;
>> +	if (IS_IKE(pdev) ||
>> +		(pdev->id.hversion == REO_MERCED_PORT) ||
>> +		(pdev->id.hversion == REOG_MERCED_PORT)) {
>> +			return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +int __init machine_has_merced_bus(void)
>> +{
>> +	int ret;
>> +
>> +	ret = for_each_padev(is_IKE_device, NULL);
>> +	return ret ? 1 : 0;
>> +}
>> +
>>  /**
>>   * find_pa_parent_type - Find a parent of a specific type
>>   * @dev: The device to start searching from
>> diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
>> index 5796524a3137..a1fc04570ade 100644
>> --- a/arch/parisc/kernel/entry.S
>> +++ b/arch/parisc/kernel/entry.S
>> @@ -50,12 +50,8 @@
>>
>>  	.import		pa_tlb_lock,data
>>  	.macro  load_pa_tlb_lock reg
>> -#if __PA_LDCW_ALIGNMENT > 4
>> -	load32	PA(pa_tlb_lock) + __PA_LDCW_ALIGNMENT-1, \reg
>> -	depi	0,31,__PA_LDCW_ALIGN_ORDER, \reg
>> -#else
>> -	load32	PA(pa_tlb_lock), \reg
>> -#endif
>> +	mfctl		%cr25,\reg
>> +	addil		L%(PAGE_SIZE << (PGD_ALLOC_ORDER - 1)),\reg
>>  	.endm
>>
>>  	/* space_to_prot macro creates a prot id from a space id */
>> diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c
>> index 35d05fdd7483..6f2d611347a1 100644
>> --- a/arch/parisc/kernel/inventory.c
>> +++ b/arch/parisc/kernel/inventory.c
>> @@ -31,6 +31,7 @@
>>  #include <asm/processor.h>
>>  #include <asm/page.h>
>>  #include <asm/parisc-device.h>
>> +#include <asm/tlbflush.h>
>>
>>  /*
>>  ** Debug options
>> @@ -638,4 +639,10 @@ void __init do_device_inventory(void)
>>  	}
>>  	printk(KERN_INFO "Found devices:\n");
>>  	print_parisc_devices();
>> +
>> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
>> +	pa_serialize_tlb_flushes = machine_has_merced_bus();
>> +	if (pa_serialize_tlb_flushes)
>> +		pr_info("Merced bus found: Enable PxTLB serialization.\n");
>> +#endif
>>  }
>> diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
>> index d908058d05c1..e05cb2a5c16d 100644
>> --- a/arch/parisc/kernel/setup.c
>> +++ b/arch/parisc/kernel/setup.c
>> @@ -343,6 +343,12 @@ static int __init parisc_init(void)
>>  			boot_cpu_data.cpu_hz / 1000000,
>>  			boot_cpu_data.cpu_hz % 1000000	);
>>
>> +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP)
>> +	/* Don't serialize TLB flushes if we run on one CPU only. */
>> +	if (num_online_cpus() == 1)
>> +		pa_serialize_tlb_flushes = 0;
>> +#endif
>> +
>>  	apply_alternatives_all();
>>  	parisc_setup_cache_timing();
>>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-01 14:34   ` Helge Deller
@ 2019-05-01 16:21     ` Mikulas Patocka
  2019-05-02  1:27       ` John David Anglin
  0 siblings, 1 reply; 10+ messages in thread
From: Mikulas Patocka @ 2019-05-01 16:21 UTC (permalink / raw)
  To: Helge Deller; +Cc: John David Anglin, linux-parisc



On Wed, 1 May 2019, Helge Deller wrote:

> Hi Mikulas,
> 
> On 01.05.19 16:22, Mikulas Patocka wrote:
> > I tested it on C8000 and confim that it works.
> 
> Thanks for testing!
> 
> By the way, I made you the author of the patch in git:
> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next&id=f1abe94b271807902d5b286c7216b812645713e2
> 
> In general, there are so many new cool features and patches pending
> in the for-next tree, so I appreciate every kind of testing:
> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next
> 
> Helge

The new kernel hangs on boot here:

Command line for kernel: 'root=/dev/sda5 console=ttyB0 HOME=/ panic=1 panic_on_oops=1 palo_kernel=2/vmlinux-5.1.0-rc5'
Selected kernel: /vmlinux-5.1.0-rc5 from partition 2
ELF64 executable

Entry 00100000 first 00100000 n 2
Segment 0 load 00100000 size 153800 mediaptr 0x1000
Segment 1 load 00126000 size 8997176 mediaptr 0x27000
Branching to kernel entry point 0x00100000.  If this is the last
message you see, you may need to switch your console.  This is
a common symptom -- search the FAQ and mailing list at parisc-linux.org

[    0.000000] Linux version 5.1.0-rc5 (root@phoebe) (gcc version 8.3.0 (GCC)) #1 SMP Wed May 1 17:55:46 CEST 2019
[    0.000000] CPU0: thread -1, cpu 0, socket 0
[    0.000000] FP[0] enabled: Rev 1 Model 20
[    0.000000] The 64-bit Kernel has started...
[    0.000000] Kernel default page size is 4 KB. Huge pages disabled.
[    0.000000] printk: bootconsole [ttyB0] enabled
[    0.000000] Initialized PDC Console for debugging.
[    0.000000] Determining PDC firmware type: 64 bit PAT.
[    0.000000] PAT: Running on cell 0 and location 1.
[    0.000000] PAT: legacy revision 0x24, pat_rev 0x201, pdc_cap 0x132, S-PTLB 0, HPMC_RENDEZ 0.
[    0.000000] model 000089b0 00000491 00000000 00000002 56bbf1abce93405d 100000f0 00000008 000000b2 000000b2
[    0.000000] vers  00000401
[    0.000000] CPUID vers 20 rev 10 (0x0000028a)
[    0.000000] capabilities 0x35
[    0.000000] model 9000/785/C8000
[    0.000000] product n/a, original product AB629A, S/N: SG51828565
[    0.000000] parisc_cache_init: Only equivalent aliasing supported!
[    0.000000] Memory Ranges:
[    0.000000]  0) Start 0x0000000000000000 End 0x000000003fffffff Size   1024 MB
[    0.000000]  1) Start 0x0000000100000000 End 0x00000001bfdfffff Size   3070 MB
[    0.000000]  2) Start 0x0000004040000000 End 0x00000040ffffffff Size   3072 MB
[    0.000000] Total Memory: 7166 MB
[    0.000000] PDT: type PDT_PAT_NEW, size 3000, entries 0, status 0, dbe_loc 0xffffffffffffffff, good_mem 0 MB
[    0.000000] PDT: Firmware reports all memory OK.

Mikulas

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-01 16:21     ` Mikulas Patocka
@ 2019-05-02  1:27       ` John David Anglin
  2019-05-02 13:43         ` Mikulas Patocka
  0 siblings, 1 reply; 10+ messages in thread
From: John David Anglin @ 2019-05-02  1:27 UTC (permalink / raw)
  To: Mikulas Patocka, Helge Deller; +Cc: linux-parisc

On 2019-05-01 12:21 p.m., Mikulas Patocka wrote:
> On Wed, 1 May 2019, Helge Deller wrote:
>
>> Hi Mikulas,
>>
>> On 01.05.19 16:22, Mikulas Patocka wrote:
>>> I tested it on C8000 and confim that it works.
>> Thanks for testing!
>>
>> By the way, I made you the author of the patch in git:
>> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next&id=f1abe94b271807902d5b286c7216b812645713e2
>>
>> In general, there are so many new cool features and patches pending
>> in the for-next tree, so I appreciate every kind of testing:
>> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next
>>
>> Helge
> The new kernel hangs on boot here:
My c8000 booted okay using above tree.

Dave

-- 
John David Anglin  dave.anglin@bell.net


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-02  1:27       ` John David Anglin
@ 2019-05-02 13:43         ` Mikulas Patocka
  2019-05-02 14:34           ` John David Anglin
  0 siblings, 1 reply; 10+ messages in thread
From: Mikulas Patocka @ 2019-05-02 13:43 UTC (permalink / raw)
  To: John David Anglin; +Cc: Helge Deller, linux-parisc



On Wed, 1 May 2019, John David Anglin wrote:

> On 2019-05-01 12:21 p.m., Mikulas Patocka wrote:
> > On Wed, 1 May 2019, Helge Deller wrote:
> >
> >> Hi Mikulas,
> >>
> >> On 01.05.19 16:22, Mikulas Patocka wrote:
> >>> I tested it on C8000 and confim that it works.
> >> Thanks for testing!
> >>
> >> By the way, I made you the author of the patch in git:
> >> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/commit/?h=for-next&id=f1abe94b271807902d5b286c7216b812645713e2
> >>
> >> In general, there are so many new cool features and patches pending
> >> in the for-next tree, so I appreciate every kind of testing:
> >> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next
> >>
> >> Helge
> > The new kernel hangs on boot here:
> My c8000 booted okay using above tree.
> 
> Dave

My obeservation is:

CONFIG_FLATMEM_MANUAL=y - doesn't compile. With the Helge's patch, it 
compiles and works - but it only sees the first 1GiB of memory.

CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=n - works.
CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=y - hangs on boot.

Mikulas

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-02 13:43         ` Mikulas Patocka
@ 2019-05-02 14:34           ` John David Anglin
  2019-05-02 16:14             ` Helge Deller
  0 siblings, 1 reply; 10+ messages in thread
From: John David Anglin @ 2019-05-02 14:34 UTC (permalink / raw)
  To: Mikulas Patocka; +Cc: Helge Deller, linux-parisc

On 2019-05-02 9:43 a.m., Mikulas Patocka wrote:
> My obeservation is:
>
> CONFIG_FLATMEM_MANUAL=y - doesn't compile. With the Helge's patch, it 
> compiles and works - but it only sees the first 1GiB of memory.
I didn't test FLATMEM.
>
> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=n - works.
> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=y - hangs on boot.
I thought I selected CONFIG_SPARSEMEM_VMEMMAP but will check.  Have multiple
builds with original SPARSEMEM patch that were okay.

Dave

-- 
John David Anglin  dave.anglin@bell.net



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-02 14:34           ` John David Anglin
@ 2019-05-02 16:14             ` Helge Deller
  2019-05-02 17:40               ` Mikulas Patocka
  2019-05-03 11:58               ` John David Anglin
  0 siblings, 2 replies; 10+ messages in thread
From: Helge Deller @ 2019-05-02 16:14 UTC (permalink / raw)
  To: John David Anglin, Mikulas Patocka; +Cc: linux-parisc

On 02.05.19 16:34, John David Anglin wrote:
> On 2019-05-02 9:43 a.m., Mikulas Patocka wrote:
>> My obeservation is:
>>
>> CONFIG_FLATMEM_MANUAL=y - doesn't compile. With the Helge's patch, it
>> compiles and works - but it only sees the first 1GiB of memory.
> I didn't test FLATMEM.

It should compile now if you check out the for-next branch again.
And it only sees 1GiB of memory, which is correct for FLATMEM.
Instead it tells you to turn on CONFIG_SPARSEMEM:

[0.000000] Large gap in memory detected (786432 pages). Consider turning on CONFIG_SPARSEMEM
[0.000000] Memory Ranges:
[0.000000]  0) Start 0x0000000000000000 End 0x000000003fffffff Size   1024 MB
[0.000000] Total Memory: 1024 MB
..

>> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=n - works.
>> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=y - hangs on boot.
> I thought I selected CONFIG_SPARSEMEM_VMEMMAP but will check.  Have multiple
> builds with original SPARSEMEM patch that were okay.

It sometimes hung for me too.
I think my VMEMMAP patch overwrites other memory and thus only sometimes crashes the machine...

By the way, I've rebased my for-next tree, fixed a few small issues and dropped the VMEMMAP patch for now.
Please give it a new try:
https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next

In addition I addded a for-next-testing branch for further testing of the remaining patches (VMEMMAP, JUMP_LABEL, ...).

Helge

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-02 16:14             ` Helge Deller
@ 2019-05-02 17:40               ` Mikulas Patocka
  2019-05-03 11:58               ` John David Anglin
  1 sibling, 0 replies; 10+ messages in thread
From: Mikulas Patocka @ 2019-05-02 17:40 UTC (permalink / raw)
  To: Helge Deller; +Cc: John David Anglin, linux-parisc

[-- Attachment #1: Type: TEXT/PLAIN, Size: 1609 bytes --]



On Thu, 2 May 2019, Helge Deller wrote:

> On 02.05.19 16:34, John David Anglin wrote:
> > On 2019-05-02 9:43 a.m., Mikulas Patocka wrote:
> >> My obeservation is:
> >>
> >> CONFIG_FLATMEM_MANUAL=y - doesn't compile. With the Helge's patch, it
> >> compiles and works - but it only sees the first 1GiB of memory.
> > I didn't test FLATMEM.
> 
> It should compile now if you check out the for-next branch again.
> And it only sees 1GiB of memory, which is correct for FLATMEM.
> Instead it tells you to turn on CONFIG_SPARSEMEM:
> 
> [0.000000] Large gap in memory detected (786432 pages). Consider turning on CONFIG_SPARSEMEM
> [0.000000] Memory Ranges:
> [0.000000]  0) Start 0x0000000000000000 End 0x000000003fffffff Size   1024 MB
> [0.000000] Total Memory: 1024 MB
> ..
> 
> >> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=n - works.
> >> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=y - hangs on boot.
> > I thought I selected CONFIG_SPARSEMEM_VMEMMAP but will check.  Have multiple
> > builds with original SPARSEMEM patch that were okay.
> 
> It sometimes hung for me too.
> I think my VMEMMAP patch overwrites other memory and thus only sometimes crashes the machine...
> 
> By the way, I've rebased my for-next tree, fixed a few small issues and dropped the VMEMMAP patch for now.
> Please give it a new try:
> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next

OK. I confirm that this branch works.

Mikulas

> In addition I addded a for-next-testing branch for further testing of the remaining patches (VMEMMAP, JUMP_LABEL, ...).
> 
> Helge
> 

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH][RFC] parisc: Use per-pagetable spinlock (v2)
  2019-05-02 16:14             ` Helge Deller
  2019-05-02 17:40               ` Mikulas Patocka
@ 2019-05-03 11:58               ` John David Anglin
  1 sibling, 0 replies; 10+ messages in thread
From: John David Anglin @ 2019-05-03 11:58 UTC (permalink / raw)
  To: Helge Deller, Mikulas Patocka; +Cc: linux-parisc

On 2019-05-02 12:14 p.m., Helge Deller wrote:
>>> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=n - works.
>>> CONFIG_SPARSEMEM_MANUAL=y, CONFIG_SPARSEMEM_VMEMMAP=y - hangs on boot.
>> I thought I selected CONFIG_SPARSEMEM_VMEMMAP but will check.  Have multiple
>> builds with original SPARSEMEM patch that were okay.
> It sometimes hung for me too.
> I think my VMEMMAP patch overwrites other memory and thus only sometimes crashes the machine...
>
> By the way, I've rebased my for-next tree, fixed a few small issues and dropped the VMEMMAP patch for now.
> Please give it a new try:
> https://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux.git/log/?h=for-next
I had selected CONFIG_SPARSEMEM_VMEMMAP=y.  My c8000 seemed to cold boot okay.  But
I built the above rebased tree using the CONFIG_SPARSEMEM_VMEMMAP=y kernel.  The new kernel
failed to boot when I tried to reboot.  It did boot boot okay when I tried a cold reboot with console
connected.

I then rebuilt the above tree, installed it and it booted okay.  So, I tend to think the memory corruption (?)
carries across a hot reboot.

Dave

-- 
John David Anglin  dave.anglin@bell.net


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2019-05-03 11:58 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-28 17:34 [PATCH][RFC] parisc: Use per-pagetable spinlock (v2) Helge Deller
2019-05-01 14:22 ` Mikulas Patocka
2019-05-01 14:34   ` Helge Deller
2019-05-01 16:21     ` Mikulas Patocka
2019-05-02  1:27       ` John David Anglin
2019-05-02 13:43         ` Mikulas Patocka
2019-05-02 14:34           ` John David Anglin
2019-05-02 16:14             ` Helge Deller
2019-05-02 17:40               ` Mikulas Patocka
2019-05-03 11:58               ` John David Anglin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).