Commit 052db7ec authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc

Pull sparc updates from David Miller:

 1) Move to 4-level page tables on sparc64 and support up to 53-bits of
    physical addressing.  Kernel static image BSS size reduced by
    several megabytes.

 2) M6/M7 cpu support, from Allan Pais.

 3) Move to sparse IRQs, handle hypervisor TLB call errors more
    gracefully, and add T5 perf_event support.  From Bob Picco.

 4) Recognize cdroms and compute geometry from capacity in virtual disk
    driver, also from Allan Pais.

 5) Fix memset() return value on sparc32, from Andreas Larsson.

 6) Respect gfp flags in dma_alloc_coherent on sparc32, from Daniel
    Hellstrom.

 7) Fix handling of compound pages in virtual disk driver, from Dwight
    Engen.

 8) Fix lockdep warnings in LDC layer by moving IRQ requesting to
    ldc_alloc() from ldc_bind().

 9) Increase boot string length to 1024 bytes, from Dave Kleikamp.

* git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc: (31 commits)
  sparc64: Fix lockdep warnings on reboot on Ultra-5
  sparc64: Increase size of boot string to 1024 bytes
  sparc64: Kill unnecessary tables and increase MAX_BANKS.
  sparc64: sparse irq
  sparc64: Adjust vmalloc region size based upon available virtual address bits.
  sparc64: Increase MAX_PHYS_ADDRESS_BITS to 53.
  sparc64: Use kernel page tables for vmemmap.
  sparc64: Fix physical memory management regressions with large max_phys_bits.
  sparc64: Adjust KTSB assembler to support larger physical addresses.
  sparc64: Define VA hole at run time, rather than at compile time.
  sparc64: Switch to 4-level page tables.
  sparc64: Fix reversed start/end in flush_tlb_kernel_range()
  sparc64: Add vio_set_intr() to enable/disable Rx interrupts
  vio: fix reuse of vio_dring slot
  sunvdc: limit each sg segment to a page
  sunvdc: compute vdisk geometry from capacity
  sunvdc: add cdrom and v1.1 protocol support
  sparc: VIO protocol version 1.6
  sparc64: Fix hibernation code refrence to PAGE_OFFSET.
  sparc64: Move request_irq() from ldc_bind() to ldc_alloc()
  ...
parents fd9879b9 bdcf81b6
...@@ -67,6 +67,7 @@ config SPARC64 ...@@ -67,6 +67,7 @@ config SPARC64
select HAVE_SYSCALL_TRACEPOINTS select HAVE_SYSCALL_TRACEPOINTS
select HAVE_CONTEXT_TRACKING select HAVE_CONTEXT_TRACKING
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select SPARSE_IRQ
select RTC_DRV_CMOS select RTC_DRV_CMOS
select RTC_DRV_BQ4802 select RTC_DRV_BQ4802
select RTC_DRV_SUN4V select RTC_DRV_SUN4V
......
...@@ -20,10 +20,12 @@ extern struct bus_type pci_bus_type; ...@@ -20,10 +20,12 @@ extern struct bus_type pci_bus_type;
static inline struct dma_map_ops *get_dma_ops(struct device *dev) static inline struct dma_map_ops *get_dma_ops(struct device *dev)
{ {
#if defined(CONFIG_SPARC32) && defined(CONFIG_PCI) #ifdef CONFIG_SPARC_LEON
if (sparc_cpu_model == sparc_leon) if (sparc_cpu_model == sparc_leon)
return leon_dma_ops; return leon_dma_ops;
else if (dev->bus == &pci_bus_type) #endif
#if defined(CONFIG_SPARC32) && defined(CONFIG_PCI)
if (dev->bus == &pci_bus_type)
return &pci32_dma_ops; return &pci32_dma_ops;
#endif #endif
return dma_ops; return dma_ops;
......
...@@ -2947,6 +2947,16 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, ...@@ -2947,6 +2947,16 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num,
unsigned long reg_val); unsigned long reg_val);
#endif #endif
#define HV_FAST_T5_GET_PERFREG 0x1a8
#define HV_FAST_T5_SET_PERFREG 0x1a9
#ifndef __ASSEMBLY__
unsigned long sun4v_t5_get_perfreg(unsigned long reg_num,
unsigned long *reg_val);
unsigned long sun4v_t5_set_perfreg(unsigned long reg_num,
unsigned long reg_val);
#endif
/* Function numbers for HV_CORE_TRAP. */ /* Function numbers for HV_CORE_TRAP. */
#define HV_CORE_SET_VER 0x00 #define HV_CORE_SET_VER 0x00
#define HV_CORE_PUTCHAR 0x01 #define HV_CORE_PUTCHAR 0x01
...@@ -2978,6 +2988,7 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num, ...@@ -2978,6 +2988,7 @@ unsigned long sun4v_vt_set_perfreg(unsigned long reg_num,
#define HV_GRP_VF_CPU 0x0205 #define HV_GRP_VF_CPU 0x0205
#define HV_GRP_KT_CPU 0x0209 #define HV_GRP_KT_CPU 0x0209
#define HV_GRP_VT_CPU 0x020c #define HV_GRP_VT_CPU 0x020c
#define HV_GRP_T5_CPU 0x0211
#define HV_GRP_DIAG 0x0300 #define HV_GRP_DIAG 0x0300
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* ino_bucket->irq allocation is made during {sun4v_,}build_irq(). * ino_bucket->irq allocation is made during {sun4v_,}build_irq().
*/ */
#define NR_IRQS 255 #define NR_IRQS (2048)
void irq_install_pre_handler(int irq, void irq_install_pre_handler(int irq,
void (*func)(unsigned int, void *, void *), void (*func)(unsigned int, void *, void *),
...@@ -57,11 +57,8 @@ unsigned int sun4u_build_msi(u32 portid, unsigned int *irq_p, ...@@ -57,11 +57,8 @@ unsigned int sun4u_build_msi(u32 portid, unsigned int *irq_p,
unsigned long iclr_base); unsigned long iclr_base);
void sun4u_destroy_msi(unsigned int irq); void sun4u_destroy_msi(unsigned int irq);
unsigned char irq_alloc(unsigned int dev_handle, unsigned int irq_alloc(unsigned int dev_handle, unsigned int dev_ino);
unsigned int dev_ino);
#ifdef CONFIG_PCI_MSI
void irq_free(unsigned int irq); void irq_free(unsigned int irq);
#endif
void __init init_IRQ(void); void __init init_IRQ(void);
void fixup_irqs(void); void fixup_irqs(void);
......
...@@ -53,13 +53,14 @@ struct ldc_channel; ...@@ -53,13 +53,14 @@ struct ldc_channel;
/* Allocate state for a channel. */ /* Allocate state for a channel. */
struct ldc_channel *ldc_alloc(unsigned long id, struct ldc_channel *ldc_alloc(unsigned long id,
const struct ldc_channel_config *cfgp, const struct ldc_channel_config *cfgp,
void *event_arg); void *event_arg,
const char *name);
/* Shut down and free state for a channel. */ /* Shut down and free state for a channel. */
void ldc_free(struct ldc_channel *lp); void ldc_free(struct ldc_channel *lp);
/* Register TX and RX queues of the link with the hypervisor. */ /* Register TX and RX queues of the link with the hypervisor. */
int ldc_bind(struct ldc_channel *lp, const char *name); int ldc_bind(struct ldc_channel *lp);
/* For non-RAW protocols we need to complete a handshake before /* For non-RAW protocols we need to complete a handshake before
* communication can proceed. ldc_connect() does that, if the * communication can proceed. ldc_connect() does that, if the
......
...@@ -57,18 +57,21 @@ void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *topa ...@@ -57,18 +57,21 @@ void copy_user_page(void *to, void *from, unsigned long vaddr, struct page *topa
typedef struct { unsigned long pte; } pte_t; typedef struct { unsigned long pte; } pte_t;
typedef struct { unsigned long iopte; } iopte_t; typedef struct { unsigned long iopte; } iopte_t;
typedef struct { unsigned long pmd; } pmd_t; typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pud; } pud_t;
typedef struct { unsigned long pgd; } pgd_t; typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t; typedef struct { unsigned long pgprot; } pgprot_t;
#define pte_val(x) ((x).pte) #define pte_val(x) ((x).pte)
#define iopte_val(x) ((x).iopte) #define iopte_val(x) ((x).iopte)
#define pmd_val(x) ((x).pmd) #define pmd_val(x) ((x).pmd)
#define pud_val(x) ((x).pud)
#define pgd_val(x) ((x).pgd) #define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot) #define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } ) #define __pte(x) ((pte_t) { (x) } )
#define __iopte(x) ((iopte_t) { (x) } ) #define __iopte(x) ((iopte_t) { (x) } )
#define __pmd(x) ((pmd_t) { (x) } ) #define __pmd(x) ((pmd_t) { (x) } )
#define __pud(x) ((pud_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } ) #define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } )
...@@ -77,18 +80,21 @@ typedef struct { unsigned long pgprot; } pgprot_t; ...@@ -77,18 +80,21 @@ typedef struct { unsigned long pgprot; } pgprot_t;
typedef unsigned long pte_t; typedef unsigned long pte_t;
typedef unsigned long iopte_t; typedef unsigned long iopte_t;
typedef unsigned long pmd_t; typedef unsigned long pmd_t;
typedef unsigned long pud_t;
typedef unsigned long pgd_t; typedef unsigned long pgd_t;
typedef unsigned long pgprot_t; typedef unsigned long pgprot_t;
#define pte_val(x) (x) #define pte_val(x) (x)
#define iopte_val(x) (x) #define iopte_val(x) (x)
#define pmd_val(x) (x) #define pmd_val(x) (x)
#define pud_val(x) (x)
#define pgd_val(x) (x) #define pgd_val(x) (x)
#define pgprot_val(x) (x) #define pgprot_val(x) (x)
#define __pte(x) (x) #define __pte(x) (x)
#define __iopte(x) (x) #define __iopte(x) (x)
#define __pmd(x) (x) #define __pmd(x) (x)
#define __pud(x) (x)
#define __pgd(x) (x) #define __pgd(x) (x)
#define __pgprot(x) (x) #define __pgprot(x) (x)
...@@ -96,21 +102,14 @@ typedef unsigned long pgprot_t; ...@@ -96,21 +102,14 @@ typedef unsigned long pgprot_t;
typedef pte_t *pgtable_t; typedef pte_t *pgtable_t;
/* These two values define the virtual address space range in which we extern unsigned long sparc64_va_hole_top;
* must forbid 64-bit user processes from making mappings. It used to extern unsigned long sparc64_va_hole_bottom;
* represent precisely the virtual address space hole present in most
* early sparc64 chips including UltraSPARC-I. But now it also is
* further constrained by the limits of our page tables, which is
* 43-bits of virtual address.
*/
#define SPARC64_VA_HOLE_TOP _AC(0xfffffc0000000000,UL)
#define SPARC64_VA_HOLE_BOTTOM _AC(0x0000040000000000,UL)
/* The next two defines specify the actual exclusion region we /* The next two defines specify the actual exclusion region we
* enforce, wherein we use a 4GB red zone on each side of the VA hole. * enforce, wherein we use a 4GB red zone on each side of the VA hole.
*/ */
#define VA_EXCLUDE_START (SPARC64_VA_HOLE_BOTTOM - (1UL << 32UL)) #define VA_EXCLUDE_START (sparc64_va_hole_bottom - (1UL << 32UL))
#define VA_EXCLUDE_END (SPARC64_VA_HOLE_TOP + (1UL << 32UL)) #define VA_EXCLUDE_END (sparc64_va_hole_top + (1UL << 32UL))
#define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \ #define TASK_UNMAPPED_BASE (test_thread_flag(TIF_32BIT) ? \
_AC(0x0000000070000000,UL) : \ _AC(0x0000000070000000,UL) : \
...@@ -118,20 +117,16 @@ typedef pte_t *pgtable_t; ...@@ -118,20 +117,16 @@ typedef pte_t *pgtable_t;
#include <asm-generic/memory_model.h> #include <asm-generic/memory_model.h>
#define PAGE_OFFSET_BY_BITS(X) (-(_AC(1,UL) << (X)))
extern unsigned long PAGE_OFFSET; extern unsigned long PAGE_OFFSET;
#endif /* !(__ASSEMBLY__) */ #endif /* !(__ASSEMBLY__) */
/* The maximum number of physical memory address bits we support, this /* The maximum number of physical memory address bits we support. The
* is used to size various tables used to manage kernel TLB misses and * largest value we can support is whatever "KPGD_SHIFT + KPTE_BITS"
* also the sparsemem code. * evaluates to.
*/ */
#define MAX_PHYS_ADDRESS_BITS 47 #define MAX_PHYS_ADDRESS_BITS 53
/* These two shift counts are used when indexing sparc64_valid_addr_bitmap
* and kpte_linear_bitmap.
*/
#define ILOG2_4MB 22 #define ILOG2_4MB 22
#define ILOG2_256MB 28 #define ILOG2_256MB 28
......
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
extern struct kmem_cache *pgtable_cache; extern struct kmem_cache *pgtable_cache;
static inline void __pgd_populate(pgd_t *pgd, pud_t *pud)
{
pgd_set(pgd, pud);
}
#define pgd_populate(MM, PGD, PUD) __pgd_populate(PGD, PUD)
static inline pgd_t *pgd_alloc(struct mm_struct *mm) static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{ {
return kmem_cache_alloc(pgtable_cache, GFP_KERNEL); return kmem_cache_alloc(pgtable_cache, GFP_KERNEL);
...@@ -25,7 +32,23 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd) ...@@ -25,7 +32,23 @@ static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
kmem_cache_free(pgtable_cache, pgd); kmem_cache_free(pgtable_cache, pgd);
} }
#define pud_populate(MM, PUD, PMD) pud_set(PUD, PMD) static inline void __pud_populate(pud_t *pud, pmd_t *pmd)
{
pud_set(pud, pmd);
}
#define pud_populate(MM, PUD, PMD) __pud_populate(PUD, PMD)
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
return kmem_cache_alloc(pgtable_cache,
GFP_KERNEL|__GFP_REPEAT);
}
static inline void pud_free(struct mm_struct *mm, pud_t *pud)
{
kmem_cache_free(pgtable_cache, pud);
}
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr) static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{ {
...@@ -91,4 +114,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pte_t *pte, ...@@ -91,4 +114,7 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pte_t *pte,
#define __pmd_free_tlb(tlb, pmd, addr) \ #define __pmd_free_tlb(tlb, pmd, addr) \
pgtable_free_tlb(tlb, pmd, false) pgtable_free_tlb(tlb, pmd, false)
#define __pud_free_tlb(tlb, pud, addr) \
pgtable_free_tlb(tlb, pud, false)
#endif /* _SPARC64_PGALLOC_H */ #endif /* _SPARC64_PGALLOC_H */
...@@ -20,8 +20,6 @@ ...@@ -20,8 +20,6 @@
#include <asm/page.h> #include <asm/page.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm-generic/pgtable-nopud.h>
/* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB). /* The kernel image occupies 0x4000000 to 0x6000000 (4MB --> 96MB).
* The page copy blockops can use 0x6000000 to 0x8000000. * The page copy blockops can use 0x6000000 to 0x8000000.
* The 8K TSB is mapped in the 0x8000000 to 0x8400000 range. * The 8K TSB is mapped in the 0x8000000 to 0x8400000 range.
...@@ -42,10 +40,7 @@ ...@@ -42,10 +40,7 @@
#define LOW_OBP_ADDRESS _AC(0x00000000f0000000,UL) #define LOW_OBP_ADDRESS _AC(0x00000000f0000000,UL)
#define HI_OBP_ADDRESS _AC(0x0000000100000000,UL) #define HI_OBP_ADDRESS _AC(0x0000000100000000,UL)
#define VMALLOC_START _AC(0x0000000100000000,UL) #define VMALLOC_START _AC(0x0000000100000000,UL)
#define VMALLOC_END _AC(0x0000010000000000,UL) #define VMEMMAP_BASE VMALLOC_END
#define VMEMMAP_BASE _AC(0x0000010000000000,UL)
#define vmemmap ((struct page *)VMEMMAP_BASE)
/* PMD_SHIFT determines the size of the area a second-level page /* PMD_SHIFT determines the size of the area a second-level page
* table can map * table can map
...@@ -55,13 +50,25 @@ ...@@ -55,13 +50,25 @@
#define PMD_MASK (~(PMD_SIZE-1)) #define PMD_MASK (~(PMD_SIZE-1))
#define PMD_BITS (PAGE_SHIFT - 3) #define PMD_BITS (PAGE_SHIFT - 3)
/* PGDIR_SHIFT determines what a third-level page table entry can map */ /* PUD_SHIFT determines the size of the area a third-level page
#define PGDIR_SHIFT (PAGE_SHIFT + (PAGE_SHIFT-3) + PMD_BITS) * table can map
*/
#define PUD_SHIFT (PMD_SHIFT + PMD_BITS)
#define PUD_SIZE (_AC(1,UL) << PUD_SHIFT)
#define PUD_MASK (~(PUD_SIZE-1))
#define PUD_BITS (PAGE_SHIFT - 3)
/* PGDIR_SHIFT determines what a fourth-level page table entry can map */
#define PGDIR_SHIFT (PUD_SHIFT + PUD_BITS)
#define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT) #define PGDIR_SIZE (_AC(1,UL) << PGDIR_SHIFT)
#define PGDIR_MASK (~(PGDIR_SIZE-1)) #define PGDIR_MASK (~(PGDIR_SIZE-1))
#define PGDIR_BITS (PAGE_SHIFT - 3) #define PGDIR_BITS (PAGE_SHIFT - 3)
#if (PGDIR_SHIFT + PGDIR_BITS) != 43 #if (MAX_PHYS_ADDRESS_BITS > PGDIR_SHIFT + PGDIR_BITS)
#error MAX_PHYS_ADDRESS_BITS exceeds what kernel page tables can support
#endif
#if (PGDIR_SHIFT + PGDIR_BITS) != 53
#error Page table parameters do not cover virtual address space properly. #error Page table parameters do not cover virtual address space properly.
#endif #endif
...@@ -71,28 +78,18 @@ ...@@ -71,28 +78,18 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <linux/sched.h> extern unsigned long VMALLOC_END;
extern unsigned long sparc64_valid_addr_bitmap[];
/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ #define vmemmap ((struct page *)VMEMMAP_BASE)
static inline bool __kern_addr_valid(unsigned long paddr)
{
if ((paddr >> MAX_PHYS_ADDRESS_BITS) != 0UL)
return false;
return test_bit(paddr >> ILOG2_4MB, sparc64_valid_addr_bitmap);
}
static inline bool kern_addr_valid(unsigned long addr) #include <linux/sched.h>
{
unsigned long paddr = __pa(addr);
return __kern_addr_valid(paddr); bool kern_addr_valid(unsigned long addr);
}
/* Entries per page directory level. */ /* Entries per page directory level. */
#define PTRS_PER_PTE (1UL << (PAGE_SHIFT-3)) #define PTRS_PER_PTE (1UL << (PAGE_SHIFT-3))
#define PTRS_PER_PMD (1UL << PMD_BITS) #define PTRS_PER_PMD (1UL << PMD_BITS)
#define PTRS_PER_PUD (1UL << PUD_BITS)
#define PTRS_PER_PGD (1UL << PGDIR_BITS) #define PTRS_PER_PGD (1UL << PGDIR_BITS)
/* Kernel has a separate 44bit address space. */ /* Kernel has a separate 44bit address space. */
...@@ -101,6 +98,9 @@ static inline bool kern_addr_valid(unsigned long addr) ...@@ -101,6 +98,9 @@ static inline bool kern_addr_valid(unsigned long addr)
#define pmd_ERROR(e) \ #define pmd_ERROR(e) \
pr_err("%s:%d: bad pmd %p(%016lx) seen at (%pS)\n", \ pr_err("%s:%d: bad pmd %p(%016lx) seen at (%pS)\n", \
__FILE__, __LINE__, &(e), pmd_val(e), __builtin_return_address(0)) __FILE__, __LINE__, &(e), pmd_val(e), __builtin_return_address(0))
#define pud_ERROR(e) \
pr_err("%s:%d: bad pud %p(%016lx) seen at (%pS)\n", \
__FILE__, __LINE__, &(e), pud_val(e), __builtin_return_address(0))
#define pgd_ERROR(e) \ #define pgd_ERROR(e) \
pr_err("%s:%d: bad pgd %p(%016lx) seen at (%pS)\n", \ pr_err("%s:%d: bad pgd %p(%016lx) seen at (%pS)\n", \
__FILE__, __LINE__, &(e), pgd_val(e), __builtin_return_address(0)) __FILE__, __LINE__, &(e), pgd_val(e), __builtin_return_address(0))
...@@ -112,6 +112,7 @@ static inline bool kern_addr_valid(unsigned long addr) ...@@ -112,6 +112,7 @@ static inline bool kern_addr_valid(unsigned long addr)
#define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/ #define _PAGE_R _AC(0x8000000000000000,UL) /* Keep ref bit uptodate*/
#define _PAGE_SPECIAL _AC(0x0200000000000000,UL) /* Special page */ #define _PAGE_SPECIAL _AC(0x0200000000000000,UL) /* Special page */
#define _PAGE_PMD_HUGE _AC(0x0100000000000000,UL) /* Huge page */ #define _PAGE_PMD_HUGE _AC(0x0100000000000000,UL) /* Huge page */
#define _PAGE_PUD_HUGE _PAGE_PMD_HUGE
/* Advertise support for _PAGE_SPECIAL */ /* Advertise support for _PAGE_SPECIAL */
#define __HAVE_ARCH_PTE_SPECIAL #define __HAVE_ARCH_PTE_SPECIAL
...@@ -658,26 +659,26 @@ static inline unsigned long pmd_large(pmd_t pmd) ...@@ -658,26 +659,26 @@ static inline unsigned long pmd_large(pmd_t pmd)
return pte_val(pte) & _PAGE_PMD_HUGE; return pte_val(pte) & _PAGE_PMD_HUGE;
} }
#ifdef CONFIG_TRANSPARENT_HUGEPAGE static inline unsigned long pmd_pfn(pmd_t pmd)
static inline unsigned long pmd_young(pmd_t pmd)
{ {
pte_t pte = __pte(pmd_val(pmd)); pte_t pte = __pte(pmd_val(pmd));
return pte_young(pte); return pte_pfn(pte);
} }
static inline unsigned long pmd_write(pmd_t pmd) #ifdef CONFIG_TRANSPARENT_HUGEPAGE
static inline unsigned long pmd_young(pmd_t pmd)
{ {
pte_t pte = __pte(pmd_val(pmd)); pte_t pte = __pte(pmd_val(pmd));
return pte_write(pte); return pte_young(pte);
} }
static inline unsigned long pmd_pfn(pmd_t pmd) static inline unsigned long pmd_write(pmd_t pmd)
{ {
pte_t pte = __pte(pmd_val(pmd)); pte_t pte = __pte(pmd_val(pmd));
return pte_pfn(pte); return pte_write(pte);
} }
static inline unsigned long pmd_trans_huge(pmd_t pmd) static inline unsigned long pmd_trans_huge(pmd_t pmd)
...@@ -771,13 +772,15 @@ static inline int pmd_present(pmd_t pmd) ...@@ -771,13 +772,15 @@ static inline int pmd_present(pmd_t pmd)
* the top bits outside of the range of any physical address size we * the top bits outside of the range of any physical address size we
* support are clear as well. We also validate the physical itself. * support are clear as well. We also validate the physical itself.
*/ */
#define pmd_bad(pmd) ((pmd_val(pmd) & ~PAGE_MASK) || \ #define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK)
!__kern_addr_valid(pmd_val(pmd)))
#define pud_none(pud) (!pud_val(pud)) #define pud_none(pud) (!pud_val(pud))
#define pud_bad(pud) ((pud_val(pud) & ~PAGE_MASK) || \ #define pud_bad(pud) (pud_val(pud) & ~PAGE_MASK)
!__kern_addr_valid(pud_val(pud)))
#define pgd_none(pgd) (!pgd_val(pgd))
#define pgd_bad(pgd) (pgd_val(pgd) & ~PAGE_MASK)
#ifdef CONFIG_TRANSPARENT_HUGEPAGE #ifdef CONFIG_TRANSPARENT_HUGEPAGE
void set_pmd_at(struct mm_struct *mm, unsigned long addr, void set_pmd_at(struct mm_struct *mm, unsigned long addr,
...@@ -815,10 +818,31 @@ static inline unsigned long __pmd_page(pmd_t pmd) ...@@ -815,10 +818,31 @@ static inline unsigned long __pmd_page(pmd_t pmd)
#define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL) #define pmd_clear(pmdp) (pmd_val(*(pmdp)) = 0UL)
#define pud_present(pud) (pud_val(pud) != 0U) #define pud_present(pud) (pud_val(pud) != 0U)
#define pud_clear(pudp) (pud_val(*(pudp)) = 0UL) #define pud_clear(pudp) (pud_val(*(pudp)) = 0UL)
#define pgd_page_vaddr(pgd) \
((unsigned long) __va(pgd_val(pgd)))
#define pgd_present(pgd) (pgd_val(pgd) != 0U)
#define pgd_clear(pgdp) (pgd_val(*(pgd)) = 0UL)
static inline unsigned long pud_large(pud_t pud)
{
pte_t pte = __pte(pud_val(pud));
return pte_val(pte) & _PAGE_PMD_HUGE;
}
static inline unsigned long pud_pfn(pud_t pud)
{
pte_t pte = __pte(pud_val(pud));
return pte_pfn(pte);
}
/* Same in both SUN4V and SUN4U. */ /* Same in both SUN4V and SUN4U. */
#define pte_none(pte) (!pte_val(pte)) #define pte_none(pte) (!pte_val(pte))
#define pgd_set(pgdp, pudp) \
(pgd_val(*(pgdp)) = (__pa((unsigned long) (pudp))))
/* to find an entry in a page-table-directory. */ /* to find an entry in a page-table-directory. */
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) #define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) #define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address))
...@@ -826,6 +850,11 @@ static inline unsigned long __pmd_page(pmd_t pmd) ...@@ -826,6 +850,11 @@ static inline unsigned long __pmd_page(pmd_t pmd)
/* to find an entry in a kernel page-table-directory */ /* to find an entry in a kernel page-table-directory */
#define pgd_offset_k(address) pgd_offset(&init_mm, address) #define pgd_offset_k(address) pgd_offset(&init_mm, address)
/* Find an entry in the third-level page table.. */
#define pud_index(address) (((address) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
#define pud_offset(pgdp, address) \
((pud_t *) pgd_page_vaddr(*(pgdp)) + pud_index(address))
/* Find an entry in the second-level page table.. */ /* Find an entry in the second-level page table.. */
#define pmd_offset(pudp, address) \ #define pmd_offset(pudp, address) \
((pmd_t *) pud_page_vaddr(*(pudp)) + \ ((pmd_t *) pud_page_vaddr(*(pudp)) + \
...@@ -898,7 +927,6 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr, ...@@ -898,7 +927,6 @@ static inline void __set_pte_at(struct mm_struct *mm, unsigned long addr,
#endif #endif
extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern pmd_t swapper_low_pmd_dir[PTRS_PER_PMD];
void paging_init(void); void paging_init(void);
unsigned long find_ecache_flush_span(unsigned long size); unsigned long find_ecache_flush_span(unsigned long size);
......
...@@ -45,6 +45,8 @@ ...@@ -45,6 +45,8 @@
#define SUN4V_CHIP_NIAGARA3 0x03 #define SUN4V_CHIP_NIAGARA3 0x03
#define SUN4V_CHIP_NIAGARA4 0x04 #define SUN4V_CHIP_NIAGARA4 0x04
#define SUN4V_CHIP_NIAGARA5 0x05 #define SUN4V_CHIP_NIAGARA5 0x05
#define SUN4V_CHIP_SPARC_M6 0x06
#define SUN4V_CHIP_SPARC_M7 0x07
#define SUN4V_CHIP_SPARC64X 0x8a #define SUN4V_CHIP_SPARC64X 0x8a
#define SUN4V_CHIP_UNKNOWN 0xff #define SUN4V_CHIP_UNKNOWN 0xff
......
...@@ -102,6 +102,7 @@ struct thread_info { ...@@ -102,6 +102,7 @@ struct thread_info {
#define FAULT_CODE_ITLB 0x04 /* Miss happened in I-TLB */ #define FAULT_CODE_ITLB 0x04 /* Miss happened in I-TLB */
#define FAULT_CODE_WINFIXUP 0x08 /* Miss happened during spill/fill */ #define FAULT_CODE_WINFIXUP 0x08 /* Miss happened during spill/fill */
#define FAULT_CODE_BLKCOMMIT 0x10 /* Use blk-commit ASI in copy_page */ #define FAULT_CODE_BLKCOMMIT 0x10 /* Use blk-commit ASI in copy_page */
#define FAULT_CODE_BAD_RA 0x20 /* Bad RA for sun4v */
#if PAGE_SHIFT == 13 #if PAGE_SHIFT == 13
#define THREAD_SIZE (2*PAGE_SIZE) #define THREAD_SIZE (2*PAGE_SIZE)
......
...@@ -133,9 +133,24 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; ...@@ -133,9 +133,24 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
sub TSB, 0x8, TSB; \ sub TSB, 0x8, TSB; \
TSB_STORE(TSB, TAG); TSB_STORE(TSB, TAG);
/* Do a kernel page table walk. Leaves physical PTE pointer in /* Do a kernel page table walk. Leaves valid PTE value in
* REG1. Jumps to FAIL_LABEL on early page table walk termination. * REG1. Jumps to FAIL_LABEL on early page table walk
* VADDR will not be clobbered, but REG2 will. * termination. VADDR will not be clobbered, but REG2 will.
*
* There are two masks we must apply to propagate bits from
* the virtual address into the PTE physical address field
* when dealing with huge pages. This is because the page
* table boundaries do not match the huge page size(s) the
* hardware supports.
*
* In these cases we propagate the bits that are below the
* page table level where we saw the huge page mapping, but
* are still within the relevant physical bits for the huge
* page size in question. So for PMD mappings (which fall on
* bit 23, for 8MB per PMD) we must propagate bit 22 for a
* 4MB huge page. For huge PUDs (which fall on bit 33, for
* 8GB per PUD), we have to accomodate 256MB and 2GB huge
* pages. So for those we propagate bits 32 to 28.
*/ */
#define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \ #define KERN_PGTABLE_WALK(VADDR, REG1, REG2, FAIL_LABEL) \
sethi %hi(swapper_pg_dir), REG1; \ sethi %hi(swapper_pg_dir), REG1; \
...@@ -145,15 +160,40 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; ...@@ -145,15 +160,40 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
andn REG2, 0x7, REG2; \ andn REG2, 0x7, REG2; \
ldx [REG1 + REG2], REG1; \ ldx [REG1 + REG2], REG1; \
brz,pn REG1, FAIL_LABEL; \ brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - (PUD_SHIFT + PUD_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x7, REG2; \
ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
brz,pn REG1, FAIL_LABEL; \
sethi %uhi(_PAGE_PUD_HUGE), REG2; \
brz,pn REG1, FAIL_LABEL; \
sllx REG2, 32, REG2; \
andcc REG1, REG2, %g0; \
sethi %hi(0xf8000000), REG2; \
bne,pt %xcc, 697f; \
sllx REG2, 1, REG2; \
sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \ srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x7, REG2; \ andn REG2, 0x7, REG2; \
ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \ ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
sethi %uhi(_PAGE_PMD_HUGE), REG2; \
brz,pn REG1, FAIL_LABEL; \ brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - PMD_SHIFT, REG2; \ sllx REG2, 32, REG2; \
andcc REG1, REG2, %g0; \
be,pn %xcc, 698f; \
sethi %hi(0x400000), REG2; \
697: brgez,pn REG1, FAIL_LABEL; \
andn REG1, REG2, REG1; \
and VADDR, REG2, REG2; \
ba,pt %xcc, 699f; \
or REG1, REG2, REG1; \
698: sllx VADDR, 64 - PMD_SHIFT, REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \ srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x7, REG2; \ andn REG2, 0x7, REG2; \
add REG1, REG2, REG1; ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
brgez,pn REG1, FAIL_LABEL; \
nop; \
699:
/* PMD has been loaded into REG1, interpret the value, seeing /* PMD has been loaded into REG1, interpret the value, seeing
* if it is a HUGE PMD or a normal one. If it is not valid * if it is a HUGE PMD or a normal one. If it is not valid
...@@ -197,6 +237,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; ...@@ -197,6 +237,11 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
srlx REG2, 64 - PAGE_SHIFT, REG2; \ srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x7, REG2; \ andn REG2, 0x7, REG2; \
ldxa [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \ ldxa [PHYS_PGD + REG2] ASI_PHYS_USE_EC, REG1; \
brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - (PUD_SHIFT + PUD_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \
andn REG2, 0x7, REG2; \
ldxa [REG1 + REG2] ASI_PHYS_USE_EC, REG1; \
brz,pn REG1, FAIL_LABEL; \ brz,pn REG1, FAIL_LABEL; \
sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \ sllx VADDR, 64 - (PMD_SHIFT + PMD_BITS), REG2; \
srlx REG2, 64 - PAGE_SHIFT, REG2; \ srlx REG2, 64 - PAGE_SHIFT, REG2; \
...@@ -246,8 +291,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; ...@@ -246,8 +291,6 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
(KERNEL_TSB_SIZE_BYTES / 16) (KERNEL_TSB_SIZE_BYTES / 16)
#define KERNEL_TSB4M_NENTRIES 4096 #define KERNEL_TSB4M_NENTRIES 4096
#define KTSB_PHYS_SHIFT 15
/* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL /* Do a kernel TSB lookup at tl>0 on VADDR+TAG, branch to OK_LABEL
* on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries * on TSB hit. REG1, REG2, REG3, and REG4 are used as temporaries
* and the found TTE will be left in REG1. REG3 and REG4 must * and the found TTE will be left in REG1. REG3 and REG4 must
...@@ -256,17 +299,15 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; ...@@ -256,17 +299,15 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
* VADDR and TAG will be preserved and not clobbered by this macro. * VADDR and TAG will be preserved and not clobbered by this macro.
*/ */
#define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ #define KERN_TSB_LOOKUP_TL1(VADDR, TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
661: sethi %hi(swapper_tsb), REG1; \ 661: sethi %uhi(swapper_tsb), REG1; \
or REG1, %lo(swapper_tsb), REG1; \ sethi %hi(swapper_tsb), REG2; \
or REG1, %ulo(swapper_tsb), REG1; \
or REG2, %lo(swapper_tsb), REG2; \
.section .swapper_tsb_phys_patch, "ax"; \ .section .swapper_tsb_phys_patch, "ax"; \
.word 661b; \ .word 661b; \
.previous; \ .previous; \
661: nop; \ sllx REG1, 32, REG1; \
.section .tsb_ldquad_phys_patch, "ax"; \ or REG1, REG2, REG1; \
.word 661b; \
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
.previous; \
srlx VADDR, PAGE_SHIFT, REG2; \ srlx VADDR, PAGE_SHIFT, REG2; \
and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \ and REG2, (KERNEL_TSB_NENTRIES - 1), REG2; \
sllx REG2, 4, REG2; \ sllx REG2, 4, REG2; \
...@@ -281,17 +322,15 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end; ...@@ -281,17 +322,15 @@ extern struct tsb_phys_patch_entry __tsb_phys_patch, __tsb_phys_patch_end;
* we can make use of that for the index computation. * we can make use of that for the index computation.
*/ */
#define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \ #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
661: sethi %hi(swapper_4m_tsb), REG1; \ 661: sethi %uhi(swapper_4m_tsb), REG1; \
or REG1, %lo(swapper_4m_tsb), REG1; \ sethi %hi(swapper_4m_tsb), REG2; \
or REG1, %ulo(swapper_4m_tsb), REG1; \
or REG2, %lo(swapper_4m_tsb), REG2; \
.section .swapper_4m_tsb_phys_patch, "ax"; \ .section .swapper_4m_tsb_phys_patch, "ax"; \
.word 661b; \ .word 661b; \
.previous; \ .previous; \
661: nop; \ sllx REG1, 32, REG1; \
.section .tsb_ldquad_phys_patch, "ax"; \ or REG1, REG2, REG1; \
.word 661b; \
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
sllx REG1, KTSB_PHYS_SHIFT, REG1; \
.previous; \
and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \ and TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
sllx REG2, 4, REG2; \ sllx REG2, 4, REG2; \
add REG1, REG2, REG2; \ add REG1, REG2, REG2; \
......
...@@ -121,12 +121,18 @@ struct vio_disk_attr_info { ...@@ -121,12 +121,18 @@ struct vio_disk_attr_info {
u8 vdisk_type; u8 vdisk_type;
#define VD_DISK_TYPE_SLICE 0x01 /* Slice in block device */ #define VD_DISK_TYPE_SLICE 0x01 /* Slice in block device */
#define VD_DISK_TYPE_DISK 0x02 /* Entire block device */ #define VD_DISK_TYPE_DISK 0x02 /* Entire block device */
u16 resv1; u8 vdisk_mtype; /* v1.1 */
#define VD_MEDIA_TYPE_FIXED 0x01 /* Fixed device */
#define VD_MEDIA_TYPE_CD 0x02 /* CD Device */
#define VD_MEDIA_TYPE_DVD 0x03 /* DVD Device */
u8 resv1;
u32 vdisk_block_size; u32 vdisk_block_size;
u64 operations; u64 operations;
u64 vdisk_size; u64 vdisk_size; /* v1.1 */
u64 max_xfer_size; u64 max_xfer_size;
u64 resv2[2]; u32 phys_block_size; /* v1.2 */
u32 resv2;
u64 resv3[1];
}; };
struct vio_disk_desc { struct vio_disk_desc {
...@@ -272,7 +278,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr, ...@@ -272,7 +278,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
unsigned int ring_size) unsigned int ring_size)
{ {
return (dr->pending - return (dr->pending -
((dr->prod - dr->cons) & (ring_size - 1))); ((dr->prod - dr->cons) & (ring_size - 1)) - 1);
} }
#define VIO_MAX_TYPE_LEN 32 #define VIO_MAX_TYPE_LEN 32
...@@ -292,6 +298,7 @@ struct vio_dev { ...@@ -292,6 +298,7 @@ struct vio_dev {
unsigned int tx_irq; unsigned int tx_irq;
unsigned int rx_irq; unsigned int rx_irq;
u64 rx_ino;
struct device dev; struct device dev;
}; };
...@@ -447,5 +454,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev, ...@@ -447,5 +454,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,
char *name); char *name);
void vio_port_up(struct vio_driver_state *vio); void vio_port_up(struct vio_driver_state *vio);
int vio_set_intr(unsigned long dev_ino, int state);
#endif /* _SPARC64_VIO_H */ #endif /* _SPARC64_VIO_H */
...@@ -494,6 +494,18 @@ static void __init sun4v_cpu_probe(void) ...@@ -494,6 +494,18 @@ static void __init sun4v_cpu_probe(void)
sparc_pmu_type = "niagara5"; sparc_pmu_type = "niagara5";
break; break;
case SUN4V_CHIP_SPARC_M6:
sparc_cpu_type = "SPARC-M6";
sparc_fpu_type = "SPARC-M6 integrated FPU";
sparc_pmu_type = "sparc-m6";
break;
case SUN4V_CHIP_SPARC_M7:
sparc_cpu_type = "SPARC-M7";
sparc_fpu_type = "SPARC-M7 integrated FPU";
sparc_pmu_type = "sparc-m7";
break;
case SUN4V_CHIP_SPARC64X: case SUN4V_CHIP_SPARC64X:
sparc_cpu_type = "SPARC64-X"; sparc_cpu_type = "SPARC64-X";
sparc_fpu_type = "SPARC64-X integrated FPU"; sparc_fpu_type = "SPARC64-X integrated FPU";
......
...@@ -326,6 +326,8 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index) ...@@ -326,6 +326,8 @@ static int iterate_cpu(struct cpuinfo_tree *t, unsigned int root_index)
case SUN4V_CHIP_NIAGARA3: case SUN4V_CHIP_NIAGARA3:
case SUN4V_CHIP_NIAGARA4: case SUN4V_CHIP_NIAGARA4:
case SUN4V_CHIP_NIAGARA5: case SUN4V_CHIP_NIAGARA5:
case SUN4V_CHIP_SPARC_M6:
case SUN4V_CHIP_SPARC_M7:
case SUN4V_CHIP_SPARC64X: case SUN4V_CHIP_SPARC64X:
rover_inc_table = niagara_iterate_method; rover_inc_table = niagara_iterate_method;
break; break;
......
...@@ -1200,14 +1200,14 @@ static int ds_probe(struct vio_dev *vdev, const struct vio_device_id *id) ...@@ -1200,14 +1200,14 @@ static int ds_probe(struct vio_dev *vdev, const struct vio_device_id *id)
ds_cfg.tx_irq = vdev->tx_irq; ds_cfg.tx_irq = vdev->tx_irq;
ds_cfg.rx_irq = vdev->rx_irq; ds_cfg.rx_irq = vdev->rx_irq;
lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp); lp = ldc_alloc(vdev->channel_id, &ds_cfg, dp, "DS");
if (IS_ERR(lp)) { if (IS_ERR(lp)) {
err = PTR_ERR(lp); err = PTR_ERR(lp);
goto out_free_ds_states; goto out_free_ds_states;
} }
dp->lp = lp; dp->lp = lp;
err = ldc_bind(lp, "DS"); err = ldc_bind(lp);
if (err) if (err)
goto out_free_ldc; goto out_free_ldc;
......
...@@ -427,6 +427,12 @@ sun4v_chip_type: ...@@ -427,6 +427,12 @@ sun4v_chip_type:
cmp %g2, '5' cmp %g2, '5'
be,pt %xcc, 5f be,pt %xcc, 5f
mov SUN4V_CHIP_NIAGARA5, %g4 mov SUN4V_CHIP_NIAGARA5, %g4
cmp %g2, '6'
be,pt %xcc, 5f
mov SUN4V_CHIP_SPARC_M6, %g4
cmp %g2, '7'
be,pt %xcc, 5f
mov SUN4V_CHIP_SPARC_M7, %g4
ba,pt %xcc, 49f ba,pt %xcc, 49f
nop nop
...@@ -583,6 +589,12 @@ niagara_tlb_fixup: ...@@ -583,6 +589,12 @@ niagara_tlb_fixup:
be,pt %xcc, niagara4_patch be,pt %xcc, niagara4_patch
nop nop
cmp %g1, SUN4V_CHIP_NIAGARA5 cmp %g1, SUN4V_CHIP_NIAGARA5
be,pt %xcc, niagara4_patch
nop
cmp %g1, SUN4V_CHIP_SPARC_M6
be,pt %xcc, niagara4_patch
nop
cmp %g1, SUN4V_CHIP_SPARC_M7
be,pt %xcc, niagara4_patch be,pt %xcc, niagara4_patch
nop nop
......
...@@ -46,6 +46,7 @@ static struct api_info api_table[] = { ...@@ -46,6 +46,7 @@ static struct api_info api_table[] = {
{ .group = HV_GRP_VF_CPU, }, { .group = HV_GRP_VF_CPU, },
{ .group = HV_GRP_KT_CPU, }, { .group = HV_GRP_KT_CPU, },
{ .group = HV_GRP_VT_CPU, }, { .group = HV_GRP_VT_CPU, },
{ .group = HV_GRP_T5_CPU, },
{ .group = HV_GRP_DIAG, .flags = FLAG_PRE_API }, { .group = HV_GRP_DIAG, .flags = FLAG_PRE_API },
}; };
......
...@@ -821,3 +821,19 @@ ENTRY(sun4v_vt_set_perfreg) ...@@ -821,3 +821,19 @@ ENTRY(sun4v_vt_set_perfreg)
retl retl
nop nop
ENDPROC(sun4v_vt_set_perfreg) ENDPROC(sun4v_vt_set_perfreg)
ENTRY(sun4v_t5_get_perfreg)
mov %o1, %o4
mov HV_FAST_T5_GET_PERFREG, %o5
ta HV_FAST_TRAP
stx %o1, [%o4]
retl
nop
ENDPROC(sun4v_t5_get_perfreg)
ENTRY(sun4v_t5_set_perfreg)
mov HV_FAST_T5_SET_PERFREG, %o5
ta HV_FAST_TRAP
retl
nop
ENDPROC(sun4v_t5_set_perfreg)
...@@ -278,7 +278,8 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len, ...@@ -278,7 +278,8 @@ static void *sbus_alloc_coherent(struct device *dev, size_t len,
} }
order = get_order(len_total); order = get_order(len_total);
if ((va = __get_free_pages(GFP_KERNEL|__GFP_COMP, order)) == 0) va = __get_free_pages(gfp, order);
if (va == 0)
goto err_nopages; goto err_nopages;
if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL) if ((res = kzalloc(sizeof(struct resource), GFP_KERNEL)) == NULL)
...@@ -443,7 +444,7 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len, ...@@ -443,7 +444,7 @@ static void *pci32_alloc_coherent(struct device *dev, size_t len,
} }
order = get_order(len_total); order = get_order(len_total);
va = (void *) __get_free_pages(GFP_KERNEL, order); va = (void *) __get_free_pages(gfp, order);
if (va == NULL) { if (va == NULL) {
printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT); printk("pci_alloc_consistent: no %ld pages\n", len_total>>PAGE_SHIFT);
goto err_nopages; goto err_nopages;
......
This diff is collapsed.
...@@ -47,14 +47,6 @@ kvmap_itlb_vmalloc_addr: ...@@ -47,14 +47,6 @@ kvmap_itlb_vmalloc_addr:
KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath) KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_itlb_longpath)
TSB_LOCK_TAG(%g1, %g2, %g7) TSB_LOCK_TAG(%g1, %g2, %g7)
/* Load and check PTE. */
ldxa [%g5] ASI_PHYS_USE_EC, %g5
mov 1, %g7
sllx %g7, TSB_TAG_INVALID_BIT, %g7
brgez,a,pn %g5, kvmap_itlb_longpath
TSB_STORE(%g1, %g7)
TSB_WRITE(%g1, %g5, %g6) TSB_WRITE(%g1, %g5, %g6)
/* fallthrough to TLB load */ /* fallthrough to TLB load */
...@@ -118,6 +110,12 @@ kvmap_dtlb_obp: ...@@ -118,6 +110,12 @@ kvmap_dtlb_obp:
ba,pt %xcc, kvmap_dtlb_load ba,pt %xcc, kvmap_dtlb_load
nop nop
kvmap_linear_early:
sethi %hi(kern_linear_pte_xor), %g7
ldx [%g7 + %lo(kern_linear_pte_xor)], %g2
ba,pt %xcc, kvmap_dtlb_tsb4m_load
xor %g2, %g4, %g5
.align 32 .align 32
kvmap_dtlb_tsb4m_load: kvmap_dtlb_tsb4m_load:
TSB_LOCK_TAG(%g1, %g2, %g7) TSB_LOCK_TAG(%g1, %g2, %g7)
...@@ -146,105 +144,17 @@ kvmap_dtlb_4v: ...@@ -146,105 +144,17 @@ kvmap_dtlb_4v:
/* Correct TAG_TARGET is already in %g6, check 4mb TSB. */ /* Correct TAG_TARGET is already in %g6, check 4mb TSB. */
KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load) KERN_TSB4M_LOOKUP_TL1(%g6, %g5, %g1, %g2, %g3, kvmap_dtlb_load)
#endif #endif
/* TSB entry address left in %g1, lookup linear PTE. /* Linear mapping TSB lookup failed. Fallthrough to kernel
* Must preserve %g1 and %g6 (TAG). * page table based lookup.
*/
kvmap_dtlb_tsb4m_miss:
/* Clear the PAGE_OFFSET top virtual bits, shift
* down to get PFN, and make sure PFN is in range.
*/
661: sllx %g4, 0, %g5
.section .page_offset_shift_patch, "ax"
.word 661b
.previous
/* Check to see if we know about valid memory at the 4MB
* chunk this physical address will reside within.
*/ */
661: srlx %g5, MAX_PHYS_ADDRESS_BITS, %g2
.section .page_offset_shift_patch, "ax"
.word 661b
.previous
brnz,pn %g2, kvmap_dtlb_longpath
nop
/* This unconditional branch and delay-slot nop gets patched
* by the sethi sequence once the bitmap is properly setup.
*/
.globl valid_addr_bitmap_insn
valid_addr_bitmap_insn:
ba,pt %xcc, 2f
nop
.subsection 2
.globl valid_addr_bitmap_patch
valid_addr_bitmap_patch:
sethi %hi(sparc64_valid_addr_bitmap), %g7
or %g7, %lo(sparc64_valid_addr_bitmap), %g7
.previous
661: srlx %g5, ILOG2_4MB, %g2
.section .page_offset_shift_patch, "ax"
.word 661b
.previous
srlx %g2, 6, %g5
and %g2, 63, %g2
sllx %g5, 3, %g5
ldx [%g7 + %g5], %g5
mov 1, %g7
sllx %g7, %g2, %g7
andcc %g5, %g7, %g0
be,pn %xcc, kvmap_dtlb_longpath
2: sethi %hi(kpte_linear_bitmap), %g2
/* Get the 256MB physical address index. */
661: sllx %g4, 0, %g5
.section .page_offset_shift_patch, "ax"
.word 661b
.previous
or %g2, %lo(kpte_linear_bitmap), %g2
661: srlx %g5, ILOG2_256MB, %g5
.section .page_offset_shift_patch, "ax"
.word 661b
.previous
and %g5, (32 - 1), %g7
/* Divide by 32 to get the offset into the bitmask. */
srlx %g5, 5, %g5
add %g7, %g7, %g7
sllx %g5, 3, %g5
/* kern_linear_pte_xor[(mask >> shift) & 3)] */
ldx [%g2 + %g5], %g2
srlx %g2, %g7, %g7
sethi %hi(kern_linear_pte_xor), %g5
and %g7, 3, %g7
or %g5, %lo(kern_linear_pte_xor), %g5
sllx %g7, 3, %g7
ldx [%g5 + %g7], %g2
.globl kvmap_linear_patch .globl kvmap_linear_patch
kvmap_linear_patch: kvmap_linear_patch:
ba,pt %xcc, kvmap_dtlb_tsb4m_load ba,a,pt %xcc, kvmap_linear_early
xor %g2, %g4, %g5
kvmap_dtlb_vmalloc_addr: kvmap_dtlb_vmalloc_addr:
KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath) KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
TSB_LOCK_TAG(%g1, %g2, %g7) TSB_LOCK_TAG(%g1, %g2, %g7)
/* Load and check PTE. */
ldxa [%g5] ASI_PHYS_USE_EC, %g5
mov 1, %g7
sllx %g7, TSB_TAG_INVALID_BIT, %g7
brgez,a,pn %g5, kvmap_dtlb_longpath
TSB_STORE(%g1, %g7)
TSB_WRITE(%g1, %g5, %g6) TSB_WRITE(%g1, %g5, %g6)
/* fallthrough to TLB load */ /* fallthrough to TLB load */
...@@ -276,13 +186,8 @@ kvmap_dtlb_load: ...@@ -276,13 +186,8 @@ kvmap_dtlb_load:
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
kvmap_vmemmap: kvmap_vmemmap:
sub %g4, %g5, %g5 KERN_PGTABLE_WALK(%g4, %g5, %g2, kvmap_dtlb_longpath)
srlx %g5, ILOG2_4MB, %g5 ba,a,pt %xcc, kvmap_dtlb_load
sethi %hi(vmemmap_table), %g1
sllx %g5, 3, %g5
or %g1, %lo(vmemmap_table), %g1
ba,pt %xcc, kvmap_dtlb_load
ldx [%g1 + %g5], %g5
#endif #endif
kvmap_dtlb_nonlinear: kvmap_dtlb_nonlinear:
...@@ -294,8 +199,8 @@ kvmap_dtlb_nonlinear: ...@@ -294,8 +199,8 @@ kvmap_dtlb_nonlinear:
#ifdef CONFIG_SPARSEMEM_VMEMMAP #ifdef CONFIG_SPARSEMEM_VMEMMAP
/* Do not use the TSB for vmemmap. */ /* Do not use the TSB for vmemmap. */
mov (VMEMMAP_BASE >> 40), %g5 sethi %hi(VMEMMAP_BASE), %g5
sllx %g5, 40, %g5 ldx [%g5 + %lo(VMEMMAP_BASE)], %g5
cmp %g4,%g5 cmp %g4,%g5
bgeu,pn %xcc, kvmap_vmemmap bgeu,pn %xcc, kvmap_vmemmap
nop nop
...@@ -307,8 +212,8 @@ kvmap_dtlb_tsbmiss: ...@@ -307,8 +212,8 @@ kvmap_dtlb_tsbmiss:
sethi %hi(MODULES_VADDR), %g5 sethi %hi(MODULES_VADDR), %g5
cmp %g4, %g5 cmp %g4, %g5
blu,pn %xcc, kvmap_dtlb_longpath blu,pn %xcc, kvmap_dtlb_longpath
mov (VMALLOC_END >> 40), %g5 sethi %hi(VMALLOC_END), %g5
sllx %g5, 40, %g5 ldx [%g5 + %lo(VMALLOC_END)], %g5
cmp %g4, %g5 cmp %g4, %g5
bgeu,pn %xcc, kvmap_dtlb_longpath bgeu,pn %xcc, kvmap_dtlb_longpath
nop nop
......
...@@ -1078,7 +1078,8 @@ static void ldc_iommu_release(struct ldc_channel *lp) ...@@ -1078,7 +1078,8 @@ static void ldc_iommu_release(struct ldc_channel *lp)
struct ldc_channel *ldc_alloc(unsigned long id, struct ldc_channel *ldc_alloc(unsigned long id,
const struct ldc_channel_config *cfgp, const struct ldc_channel_config *cfgp,
void *event_arg) void *event_arg,
const char *name)
{ {
struct ldc_channel *lp; struct ldc_channel *lp;
const struct ldc_mode_ops *mops; const struct ldc_mode_ops *mops;
...@@ -1093,6 +1094,8 @@ struct ldc_channel *ldc_alloc(unsigned long id, ...@@ -1093,6 +1094,8 @@ struct ldc_channel *ldc_alloc(unsigned long id,
err = -EINVAL; err = -EINVAL;
if (!cfgp) if (!cfgp)
goto out_err; goto out_err;
if (!name)
goto out_err;
switch (cfgp->mode) { switch (cfgp->mode) {
case LDC_MODE_RAW: case LDC_MODE_RAW:
...@@ -1185,6 +1188,21 @@ struct ldc_channel *ldc_alloc(unsigned long id, ...@@ -1185,6 +1188,21 @@ struct ldc_channel *ldc_alloc(unsigned long id,
INIT_HLIST_HEAD(&lp->mh_list); INIT_HLIST_HEAD(&lp->mh_list);
snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
err = request_irq(lp->cfg.rx_irq, ldc_rx, 0,
lp->rx_irq_name, lp);
if (err)
goto out_free_txq;
err = request_irq(lp->cfg.tx_irq, ldc_tx, 0,
lp->tx_irq_name, lp);
if (err) {
free_irq(lp->cfg.rx_irq, lp);
goto out_free_txq;
}
return lp; return lp;
out_free_txq: out_free_txq:
...@@ -1237,31 +1255,14 @@ EXPORT_SYMBOL(ldc_free); ...@@ -1237,31 +1255,14 @@ EXPORT_SYMBOL(ldc_free);
* state. This does not initiate a handshake, ldc_connect() does * state. This does not initiate a handshake, ldc_connect() does
* that. * that.
*/ */
int ldc_bind(struct ldc_channel *lp, const char *name) int ldc_bind(struct ldc_channel *lp)
{ {
unsigned long hv_err, flags; unsigned long hv_err, flags;
int err = -EINVAL; int err = -EINVAL;
if (!name || if (lp->state != LDC_STATE_INIT)
(lp->state != LDC_STATE_INIT))
return -EINVAL; return -EINVAL;
snprintf(lp->rx_irq_name, LDC_IRQ_NAME_MAX, "%s RX", name);
snprintf(lp->tx_irq_name, LDC_IRQ_NAME_MAX, "%s TX", name);
err = request_irq(lp->cfg.rx_irq, ldc_rx, 0,
lp->rx_irq_name, lp);
if (err)
return err;
err = request_irq(lp->cfg.tx_irq, ldc_tx, 0,
lp->tx_irq_name, lp);
if (err) {
free_irq(lp->cfg.rx_irq, lp);
return err;
}
spin_lock_irqsave(&lp->lock, flags); spin_lock_irqsave(&lp->lock, flags);
enable_irq(lp->cfg.rx_irq); enable_irq(lp->cfg.rx_irq);
......
...@@ -37,6 +37,7 @@ unsigned long amba_system_id; ...@@ -37,6 +37,7 @@ unsigned long amba_system_id;
static DEFINE_SPINLOCK(leon_irq_lock); static DEFINE_SPINLOCK(leon_irq_lock);
static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */ static unsigned long leon3_gptimer_idx; /* Timer Index (0..6) within Timer Core */
static unsigned long leon3_gptimer_ackmask; /* For clearing pending bit */
unsigned long leon3_gptimer_irq; /* interrupt controller irq number */ unsigned long leon3_gptimer_irq; /* interrupt controller irq number */
unsigned int sparc_leon_eirq; unsigned int sparc_leon_eirq;
#define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu]) #define LEON_IMASK(cpu) (&leon3_irqctrl_regs->mask[cpu])
...@@ -260,11 +261,19 @@ void leon_update_virq_handling(unsigned int virq, ...@@ -260,11 +261,19 @@ void leon_update_virq_handling(unsigned int virq,
static u32 leon_cycles_offset(void) static u32 leon_cycles_offset(void)
{ {
u32 rld, val, off; u32 rld, val, ctrl, off;
rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld); rld = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld);
val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val); val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
if (LEON3_GPTIMER_CTRL_ISPENDING(ctrl)) {
val = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val);
off = 2 * rld - val;
} else {
off = rld - val; off = rld - val;
return rld - val; }
return off;
} }
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
...@@ -302,6 +311,7 @@ void __init leon_init_timers(void) ...@@ -302,6 +311,7 @@ void __init leon_init_timers(void)
int ampopts; int ampopts;
int err; int err;
u32 config; u32 config;
u32 ctrl;
sparc_config.get_cycles_offset = leon_cycles_offset; sparc_config.get_cycles_offset = leon_cycles_offset;
sparc_config.cs_period = 1000000 / HZ; sparc_config.cs_period = 1000000 / HZ;
...@@ -374,6 +384,16 @@ void __init leon_init_timers(void) ...@@ -374,6 +384,16 @@ void __init leon_init_timers(void)
if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq)) if (!(leon3_gptimer_regs && leon3_irqctrl_regs && leon3_gptimer_irq))
goto bad; goto bad;
ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
ctrl | LEON3_GPTIMER_CTRL_PENDING);
ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
if ((ctrl & LEON3_GPTIMER_CTRL_PENDING) != 0)
leon3_gptimer_ackmask = ~LEON3_GPTIMER_CTRL_PENDING;
else
leon3_gptimer_ackmask = ~0;
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0); LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].val, 0);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld, LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].rld,
(((1000000 / HZ) - 1))); (((1000000 / HZ) - 1)));
...@@ -452,6 +472,11 @@ void __init leon_init_timers(void) ...@@ -452,6 +472,11 @@ void __init leon_init_timers(void)
static void leon_clear_clock_irq(void) static void leon_clear_clock_irq(void)
{ {
u32 ctrl;
ctrl = LEON3_BYPASS_LOAD_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl);
LEON3_BYPASS_STORE_PA(&leon3_gptimer_regs->e[leon3_gptimer_idx].ctrl,
ctrl & leon3_gptimer_ackmask);
} }
static void leon_load_profile_irq(int cpu, unsigned int limit) static void leon_load_profile_irq(int cpu, unsigned int limit)
......
...@@ -191,12 +191,41 @@ static const struct pcr_ops n4_pcr_ops = { ...@@ -191,12 +191,41 @@ static const struct pcr_ops n4_pcr_ops = {
.pcr_nmi_disable = PCR_N4_PICNPT, .pcr_nmi_disable = PCR_N4_PICNPT,
}; };
static u64 n5_pcr_read(unsigned long reg_num)
{
unsigned long val;
(void) sun4v_t5_get_perfreg(reg_num, &val);
return val;
}
static void n5_pcr_write(unsigned long reg_num, u64 val)
{
(void) sun4v_t5_set_perfreg(reg_num, val);
}
static const struct pcr_ops n5_pcr_ops = {
.read_pcr = n5_pcr_read,
.write_pcr = n5_pcr_write,
.read_pic = n4_pic_read,
.write_pic = n4_pic_write,
.nmi_picl_value = n4_picl_value,
.pcr_nmi_enable = (PCR_N4_PICNPT | PCR_N4_STRACE |
PCR_N4_UTRACE | PCR_N4_TOE |
(26 << PCR_N4_SL_SHIFT)),
.pcr_nmi_disable = PCR_N4_PICNPT,
};
static unsigned long perf_hsvc_group; static unsigned long perf_hsvc_group;
static unsigned long perf_hsvc_major; static unsigned long perf_hsvc_major;
static unsigned long perf_hsvc_minor; static unsigned long perf_hsvc_minor;
static int __init register_perf_hsvc(void) static int __init register_perf_hsvc(void)
{ {
unsigned long hverror;
if (tlb_type == hypervisor) { if (tlb_type == hypervisor) {
switch (sun4v_chip_type) { switch (sun4v_chip_type) {
case SUN4V_CHIP_NIAGARA1: case SUN4V_CHIP_NIAGARA1:
...@@ -215,6 +244,10 @@ static int __init register_perf_hsvc(void) ...@@ -215,6 +244,10 @@ static int __init register_perf_hsvc(void)
perf_hsvc_group = HV_GRP_VT_CPU; perf_hsvc_group = HV_GRP_VT_CPU;
break; break;
case SUN4V_CHIP_NIAGARA5:
perf_hsvc_group = HV_GRP_T5_CPU;
break;
default: default:
return -ENODEV; return -ENODEV;
} }
...@@ -222,10 +255,12 @@ static int __init register_perf_hsvc(void) ...@@ -222,10 +255,12 @@ static int __init register_perf_hsvc(void)
perf_hsvc_major = 1; perf_hsvc_major = 1;
perf_hsvc_minor = 0; perf_hsvc_minor = 0;
if (sun4v_hvapi_register(perf_hsvc_group, hverror = sun4v_hvapi_register(perf_hsvc_group,
perf_hsvc_major, perf_hsvc_major,
&perf_hsvc_minor)) { &perf_hsvc_minor);
printk("perfmon: Could not register hvapi.\n"); if (hverror) {
pr_err("perfmon: Could not register hvapi(0x%lx).\n",
hverror);
return -ENODEV; return -ENODEV;
} }
} }
...@@ -254,6 +289,10 @@ static int __init setup_sun4v_pcr_ops(void) ...@@ -254,6 +289,10 @@ static int __init setup_sun4v_pcr_ops(void)
pcr_ops = &n4_pcr_ops; pcr_ops = &n4_pcr_ops;
break; break;
case SUN4V_CHIP_NIAGARA5:
pcr_ops = &n5_pcr_ops;
break;
default: default:
ret = -ENODEV; ret = -ENODEV;
break; break;
......
...@@ -1662,7 +1662,8 @@ static bool __init supported_pmu(void) ...@@ -1662,7 +1662,8 @@ static bool __init supported_pmu(void)
sparc_pmu = &niagara2_pmu; sparc_pmu = &niagara2_pmu;
return true; return true;
} }
if (!strcmp(sparc_pmu_type, "niagara4")) { if (!strcmp(sparc_pmu_type, "niagara4") ||
!strcmp(sparc_pmu_type, "niagara5")) {
sparc_pmu = &niagara4_pmu; sparc_pmu = &niagara4_pmu;
return true; return true;
} }
......
...@@ -141,21 +141,9 @@ static void __init boot_flags_init(char *commands) ...@@ -141,21 +141,9 @@ static void __init boot_flags_init(char *commands)
process_switch(*commands++); process_switch(*commands++);
continue; continue;
} }
if (!strncmp(commands, "mem=", 4)) { if (!strncmp(commands, "mem=", 4))
/* cmdline_memory_size = memparse(commands + 4, &commands);
* "mem=XXX[kKmM]" overrides the PROM-reported
* memory size.
*/
cmdline_memory_size = simple_strtoul(commands + 4,
&commands, 0);
if (*commands == 'K' || *commands == 'k') {
cmdline_memory_size <<= 10;
commands++;
} else if (*commands=='M' || *commands=='m') {
cmdline_memory_size <<= 20;
commands++;
}
}
while (*commands && *commands != ' ') while (*commands && *commands != ' ')
commands++; commands++;
} }
...@@ -500,12 +488,16 @@ static void __init init_sparc64_elf_hwcap(void) ...@@ -500,12 +488,16 @@ static void __init init_sparc64_elf_hwcap(void)
sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA5 || sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
sun4v_chip_type == SUN4V_CHIP_SPARC64X) sun4v_chip_type == SUN4V_CHIP_SPARC64X)
cap |= HWCAP_SPARC_BLKINIT; cap |= HWCAP_SPARC_BLKINIT;
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 || if (sun4v_chip_type == SUN4V_CHIP_NIAGARA2 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA5 || sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
sun4v_chip_type == SUN4V_CHIP_SPARC64X) sun4v_chip_type == SUN4V_CHIP_SPARC64X)
cap |= HWCAP_SPARC_N2; cap |= HWCAP_SPARC_N2;
} }
...@@ -533,6 +525,8 @@ static void __init init_sparc64_elf_hwcap(void) ...@@ -533,6 +525,8 @@ static void __init init_sparc64_elf_hwcap(void)
sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA5 || sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
sun4v_chip_type == SUN4V_CHIP_SPARC64X) sun4v_chip_type == SUN4V_CHIP_SPARC64X)
cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 | cap |= (AV_SPARC_VIS | AV_SPARC_VIS2 |
AV_SPARC_ASI_BLK_INIT | AV_SPARC_ASI_BLK_INIT |
...@@ -540,6 +534,8 @@ static void __init init_sparc64_elf_hwcap(void) ...@@ -540,6 +534,8 @@ static void __init init_sparc64_elf_hwcap(void)
if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 || if (sun4v_chip_type == SUN4V_CHIP_NIAGARA3 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA4 || sun4v_chip_type == SUN4V_CHIP_NIAGARA4 ||
sun4v_chip_type == SUN4V_CHIP_NIAGARA5 || sun4v_chip_type == SUN4V_CHIP_NIAGARA5 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M6 ||
sun4v_chip_type == SUN4V_CHIP_SPARC_M7 ||
sun4v_chip_type == SUN4V_CHIP_SPARC64X) sun4v_chip_type == SUN4V_CHIP_SPARC64X)
cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC | cap |= (AV_SPARC_VIS3 | AV_SPARC_HPC |
AV_SPARC_FMAF); AV_SPARC_FMAF);
......
...@@ -1467,6 +1467,13 @@ static void __init pcpu_populate_pte(unsigned long addr) ...@@ -1467,6 +1467,13 @@ static void __init pcpu_populate_pte(unsigned long addr)
pud_t *pud; pud_t *pud;
pmd_t *pmd; pmd_t *pmd;
if (pgd_none(*pgd)) {
pud_t *new;
new = __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, PAGE_SIZE);
pgd_populate(&init_mm, pgd, new);
}
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
if (pud_none(*pud)) { if (pud_none(*pud)) {
pmd_t *new; pmd_t *new;
......
...@@ -195,6 +195,11 @@ sun4v_tsb_miss_common: ...@@ -195,6 +195,11 @@ sun4v_tsb_miss_common:
ldx [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7 ldx [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
sun4v_itlb_error: sun4v_itlb_error:
rdpr %tl, %g1
cmp %g1, 1
ble,pt %icc, sun4v_bad_ra
or %g0, FAULT_CODE_BAD_RA | FAULT_CODE_ITLB, %g1
sethi %hi(sun4v_err_itlb_vaddr), %g1 sethi %hi(sun4v_err_itlb_vaddr), %g1
stx %g4, [%g1 + %lo(sun4v_err_itlb_vaddr)] stx %g4, [%g1 + %lo(sun4v_err_itlb_vaddr)]
sethi %hi(sun4v_err_itlb_ctx), %g1 sethi %hi(sun4v_err_itlb_ctx), %g1
...@@ -206,15 +211,10 @@ sun4v_itlb_error: ...@@ -206,15 +211,10 @@ sun4v_itlb_error:
sethi %hi(sun4v_err_itlb_error), %g1 sethi %hi(sun4v_err_itlb_error), %g1
stx %o0, [%g1 + %lo(sun4v_err_itlb_error)] stx %o0, [%g1 + %lo(sun4v_err_itlb_error)]
sethi %hi(1f), %g7
rdpr %tl, %g4 rdpr %tl, %g4
cmp %g4, 1
ble,pt %icc, 1f
sethi %hi(2f), %g7
ba,pt %xcc, etraptl1 ba,pt %xcc, etraptl1
or %g7, %lo(2f), %g7 1: or %g7, %lo(1f), %g7
1: ba,pt %xcc, etrap
2: or %g7, %lo(2b), %g7
mov %l4, %o1 mov %l4, %o1
call sun4v_itlb_error_report call sun4v_itlb_error_report
add %sp, PTREGS_OFF, %o0 add %sp, PTREGS_OFF, %o0
...@@ -222,6 +222,11 @@ sun4v_itlb_error: ...@@ -222,6 +222,11 @@ sun4v_itlb_error:
/* NOTREACHED */ /* NOTREACHED */
sun4v_dtlb_error: sun4v_dtlb_error:
rdpr %tl, %g1
cmp %g1, 1
ble,pt %icc, sun4v_bad_ra
or %g0, FAULT_CODE_BAD_RA | FAULT_CODE_DTLB, %g1
sethi %hi(sun4v_err_dtlb_vaddr), %g1 sethi %hi(sun4v_err_dtlb_vaddr), %g1
stx %g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)] stx %g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)]
sethi %hi(sun4v_err_dtlb_ctx), %g1 sethi %hi(sun4v_err_dtlb_ctx), %g1
...@@ -233,21 +238,23 @@ sun4v_dtlb_error: ...@@ -233,21 +238,23 @@ sun4v_dtlb_error:
sethi %hi(sun4v_err_dtlb_error), %g1 sethi %hi(sun4v_err_dtlb_error), %g1
stx %o0, [%g1 + %lo(sun4v_err_dtlb_error)] stx %o0, [%g1 + %lo(sun4v_err_dtlb_error)]
sethi %hi(1f), %g7
rdpr %tl, %g4 rdpr %tl, %g4
cmp %g4, 1
ble,pt %icc, 1f
sethi %hi(2f), %g7
ba,pt %xcc, etraptl1 ba,pt %xcc, etraptl1
or %g7, %lo(2f), %g7 1: or %g7, %lo(1f), %g7
1: ba,pt %xcc, etrap
2: or %g7, %lo(2b), %g7
mov %l4, %o1 mov %l4, %o1
call sun4v_dtlb_error_report call sun4v_dtlb_error_report
add %sp, PTREGS_OFF, %o0 add %sp, PTREGS_OFF, %o0
/* NOTREACHED */ /* NOTREACHED */
sun4v_bad_ra:
or %g0, %g4, %g5
ba,pt %xcc, sparc64_realfault_common
or %g1, %g0, %g4
/* NOTREACHED */
/* Instruction Access Exception, tl0. */ /* Instruction Access Exception, tl0. */
sun4v_iacc: sun4v_iacc:
ldxa [%g0] ASI_SCRATCHPAD, %g2 ldxa [%g0] ASI_SCRATCHPAD, %g2
......
...@@ -2104,6 +2104,11 @@ void sun4v_nonresum_overflow(struct pt_regs *regs) ...@@ -2104,6 +2104,11 @@ void sun4v_nonresum_overflow(struct pt_regs *regs)
atomic_inc(&sun4v_nonresum_oflow_cnt); atomic_inc(&sun4v_nonresum_oflow_cnt);
} }
static void sun4v_tlb_error(struct pt_regs *regs)
{
die_if_kernel("TLB/TSB error", regs);
}
unsigned long sun4v_err_itlb_vaddr; unsigned long sun4v_err_itlb_vaddr;
unsigned long sun4v_err_itlb_ctx; unsigned long sun4v_err_itlb_ctx;
unsigned long sun4v_err_itlb_pte; unsigned long sun4v_err_itlb_pte;
...@@ -2111,7 +2116,6 @@ unsigned long sun4v_err_itlb_error; ...@@ -2111,7 +2116,6 @@ unsigned long sun4v_err_itlb_error;
void sun4v_itlb_error_report(struct pt_regs *regs, int tl) void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
{ {
if (tl > 1)
dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n", printk(KERN_EMERG "SUN4V-ITLB: Error at TPC[%lx], tl %d\n",
...@@ -2125,7 +2129,7 @@ void sun4v_itlb_error_report(struct pt_regs *regs, int tl) ...@@ -2125,7 +2129,7 @@ void sun4v_itlb_error_report(struct pt_regs *regs, int tl)
sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx, sun4v_err_itlb_vaddr, sun4v_err_itlb_ctx,
sun4v_err_itlb_pte, sun4v_err_itlb_error); sun4v_err_itlb_pte, sun4v_err_itlb_error);
prom_halt(); sun4v_tlb_error(regs);
} }
unsigned long sun4v_err_dtlb_vaddr; unsigned long sun4v_err_dtlb_vaddr;
...@@ -2135,7 +2139,6 @@ unsigned long sun4v_err_dtlb_error; ...@@ -2135,7 +2139,6 @@ unsigned long sun4v_err_dtlb_error;
void sun4v_dtlb_error_report(struct pt_regs *regs, int tl) void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
{ {
if (tl > 1)
dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n", printk(KERN_EMERG "SUN4V-DTLB: Error at TPC[%lx], tl %d\n",
...@@ -2149,7 +2152,7 @@ void sun4v_dtlb_error_report(struct pt_regs *regs, int tl) ...@@ -2149,7 +2152,7 @@ void sun4v_dtlb_error_report(struct pt_regs *regs, int tl)
sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx, sun4v_err_dtlb_vaddr, sun4v_err_dtlb_ctx,
sun4v_err_dtlb_pte, sun4v_err_dtlb_error); sun4v_err_dtlb_pte, sun4v_err_dtlb_error);
prom_halt(); sun4v_tlb_error(regs);
} }
void hypervisor_tlbop_error(unsigned long err, unsigned long op) void hypervisor_tlbop_error(unsigned long err, unsigned long op)
......
...@@ -180,8 +180,10 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, ...@@ -180,8 +180,10 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq); vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
irq = mdesc_get_property(hp, target, "rx-ino", NULL); irq = mdesc_get_property(hp, target, "rx-ino", NULL);
if (irq) if (irq) {
vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq); vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
vdev->rx_ino = *irq;
}
chan_id = mdesc_get_property(hp, target, "id", NULL); chan_id = mdesc_get_property(hp, target, "id", NULL);
if (chan_id) if (chan_id)
...@@ -189,6 +191,15 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, ...@@ -189,6 +191,15 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
} }
} }
int vio_set_intr(unsigned long dev_ino, int state)
{
int err;
err = sun4v_vintr_set_valid(cdev_cfg_handle, dev_ino, state);
return err;
}
EXPORT_SYMBOL(vio_set_intr);
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
struct device *parent) struct device *parent)
{ {
......
...@@ -724,7 +724,7 @@ int vio_ldc_alloc(struct vio_driver_state *vio, ...@@ -724,7 +724,7 @@ int vio_ldc_alloc(struct vio_driver_state *vio,
cfg.tx_irq = vio->vdev->tx_irq; cfg.tx_irq = vio->vdev->tx_irq;
cfg.rx_irq = vio->vdev->rx_irq; cfg.rx_irq = vio->vdev->rx_irq;
lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg); lp = ldc_alloc(vio->vdev->channel_id, &cfg, event_arg, vio->name);
if (IS_ERR(lp)) if (IS_ERR(lp))
return PTR_ERR(lp); return PTR_ERR(lp);
...@@ -756,7 +756,7 @@ void vio_port_up(struct vio_driver_state *vio) ...@@ -756,7 +756,7 @@ void vio_port_up(struct vio_driver_state *vio)
err = 0; err = 0;
if (state == LDC_STATE_INIT) { if (state == LDC_STATE_INIT) {
err = ldc_bind(vio->lp, vio->name); err = ldc_bind(vio->lp);
if (err) if (err)
printk(KERN_WARNING "%s: Port %lu bind failed, " printk(KERN_WARNING "%s: Port %lu bind failed, "
"err=%d\n", "err=%d\n",
......
...@@ -35,8 +35,9 @@ jiffies = jiffies_64; ...@@ -35,8 +35,9 @@ jiffies = jiffies_64;
SECTIONS SECTIONS
{ {
/* swapper_low_pmd_dir is sparc64 only */ #ifdef CONFIG_SPARC64
swapper_low_pmd_dir = 0x0000000000402000; swapper_pg_dir = 0x0000000000402000;
#endif
. = INITIAL_ADDRESS; . = INITIAL_ADDRESS;
.text TEXTSTART : .text TEXTSTART :
{ {
...@@ -122,11 +123,6 @@ SECTIONS ...@@ -122,11 +123,6 @@ SECTIONS
*(.swapper_4m_tsb_phys_patch) *(.swapper_4m_tsb_phys_patch)
__swapper_4m_tsb_phys_patch_end = .; __swapper_4m_tsb_phys_patch_end = .;
} }
.page_offset_shift_patch : {
__page_offset_shift_patch = .;
*(.page_offset_shift_patch)
__page_offset_shift_patch_end = .;
}
.popc_3insn_patch : { .popc_3insn_patch : {
__popc_3insn_patch = .; __popc_3insn_patch = .;
*(.popc_3insn_patch) *(.popc_3insn_patch)
......
...@@ -3,8 +3,9 @@ ...@@ -3,8 +3,9 @@
* Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
* *
* Returns 0, if ok, and number of bytes not yet set if exception * Calls to memset returns initial %o0. Calls to bzero returns 0, if ok, and
* occurs and we were called as clear_user. * number of bytes not yet set if exception occurs and we were called as
* clear_user.
*/ */
#include <asm/ptrace.h> #include <asm/ptrace.h>
...@@ -65,6 +66,8 @@ __bzero_begin: ...@@ -65,6 +66,8 @@ __bzero_begin:
.globl __memset_start, __memset_end .globl __memset_start, __memset_end
__memset_start: __memset_start:
memset: memset:
mov %o0, %g1
mov 1, %g4
and %o1, 0xff, %g3 and %o1, 0xff, %g3
sll %g3, 8, %g2 sll %g3, 8, %g2
or %g3, %g2, %g3 or %g3, %g2, %g3
...@@ -89,6 +92,7 @@ memset: ...@@ -89,6 +92,7 @@ memset:
sub %o0, %o2, %o0 sub %o0, %o2, %o0
__bzero: __bzero:
clr %g4
mov %g0, %g3 mov %g0, %g3
1: 1:
cmp %o1, 7 cmp %o1, 7
...@@ -151,8 +155,8 @@ __bzero: ...@@ -151,8 +155,8 @@ __bzero:
bne,a 8f bne,a 8f
EX(stb %g3, [%o0], and %o1, 1) EX(stb %g3, [%o0], and %o1, 1)
8: 8:
retl b 0f
clr %o0 nop
7: 7:
be 13b be 13b
orcc %o1, 0, %g0 orcc %o1, 0, %g0
...@@ -164,6 +168,12 @@ __bzero: ...@@ -164,6 +168,12 @@ __bzero:
bne 8b bne 8b
EX(stb %g3, [%o0 - 1], add %o1, 1) EX(stb %g3, [%o0 - 1], add %o1, 1)
0: 0:
andcc %g4, 1, %g0
be 5f
nop
retl
mov %g1, %o0
5:
retl retl
clr %o0 clr %o0
__memset_end: __memset_end:
......
...@@ -346,6 +346,9 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) ...@@ -346,6 +346,9 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
down_read(&mm->mmap_sem); down_read(&mm->mmap_sem);
} }
if (fault_code & FAULT_CODE_BAD_RA)
goto do_sigbus;
vma = find_vma(mm, address); vma = find_vma(mm, address);
if (!vma) if (!vma)
goto bad_area; goto bad_area;
......
This diff is collapsed.
...@@ -8,15 +8,8 @@ ...@@ -8,15 +8,8 @@
*/ */
#define MAX_PHYS_ADDRESS (1UL << MAX_PHYS_ADDRESS_BITS) #define MAX_PHYS_ADDRESS (1UL << MAX_PHYS_ADDRESS_BITS)
#define KPTE_BITMAP_CHUNK_SZ (256UL * 1024UL * 1024UL)
#define KPTE_BITMAP_BYTES \
((MAX_PHYS_ADDRESS / KPTE_BITMAP_CHUNK_SZ) / 4)
#define VALID_ADDR_BITMAP_CHUNK_SZ (4UL * 1024UL * 1024UL)
#define VALID_ADDR_BITMAP_BYTES \
((MAX_PHYS_ADDRESS / VALID_ADDR_BITMAP_CHUNK_SZ) / 8)
extern unsigned long kern_linear_pte_xor[4]; extern unsigned long kern_linear_pte_xor[4];
extern unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
extern unsigned int sparc64_highest_unlocked_tlb_ent; extern unsigned int sparc64_highest_unlocked_tlb_ent;
extern unsigned long sparc64_kern_pri_context; extern unsigned long sparc64_kern_pri_context;
extern unsigned long sparc64_kern_pri_nuc_bits; extern unsigned long sparc64_kern_pri_nuc_bits;
...@@ -38,15 +31,4 @@ extern unsigned long kern_locked_tte_data; ...@@ -38,15 +31,4 @@ extern unsigned long kern_locked_tte_data;
void prom_world(int enter); void prom_world(int enter);
#ifdef CONFIG_SPARSEMEM_VMEMMAP
#define VMEMMAP_CHUNK_SHIFT 22
#define VMEMMAP_CHUNK (1UL << VMEMMAP_CHUNK_SHIFT)
#define VMEMMAP_CHUNK_MASK ~(VMEMMAP_CHUNK - 1UL)
#define VMEMMAP_ALIGN(x) (((x)+VMEMMAP_CHUNK-1UL)&VMEMMAP_CHUNK_MASK)
#define VMEMMAP_SIZE ((((1UL << MAX_PHYSADDR_BITS) >> PAGE_SHIFT) * \
sizeof(struct page)) >> VMEMMAP_CHUNK_SHIFT)
extern unsigned long vmemmap_table[VMEMMAP_SIZE];
#endif
#endif /* _SPARC64_MM_INIT_H */ #endif /* _SPARC64_MM_INIT_H */
...@@ -54,8 +54,8 @@ ENTRY(swsusp_arch_resume) ...@@ -54,8 +54,8 @@ ENTRY(swsusp_arch_resume)
nop nop
/* Write PAGE_OFFSET to %g7 */ /* Write PAGE_OFFSET to %g7 */
sethi %uhi(PAGE_OFFSET), %g7 sethi %hi(PAGE_OFFSET), %g7
sllx %g7, 32, %g7 ldx [%g7 + %lo(PAGE_OFFSET)], %g7
setuw (PAGE_SIZE-8), %g3 setuw (PAGE_SIZE-8), %g3
......
...@@ -14,7 +14,10 @@ ...@@ -14,7 +14,10 @@
* the .bss section or it will break things. * the .bss section or it will break things.
*/ */
#define BARG_LEN 256 /* We limit BARG_LEN to 1024 because this is the size of the
* 'barg_out' command line buffer in the SILO bootloader.
*/
#define BARG_LEN 1024
struct { struct {
int bootstr_len; int bootstr_len;
int bootstr_valid; int bootstr_valid;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/irqflags.h>
#include <asm/openprom.h> #include <asm/openprom.h>
#include <asm/oplib.h> #include <asm/oplib.h>
...@@ -36,8 +37,8 @@ void p1275_cmd_direct(unsigned long *args) ...@@ -36,8 +37,8 @@ void p1275_cmd_direct(unsigned long *args)
{ {
unsigned long flags; unsigned long flags;
raw_local_save_flags(flags); local_save_flags(flags);
raw_local_irq_restore((unsigned long)PIL_NMI); local_irq_restore((unsigned long)PIL_NMI);
raw_spin_lock(&prom_entry_lock); raw_spin_lock(&prom_entry_lock);
prom_world(1); prom_world(1);
...@@ -45,7 +46,7 @@ void p1275_cmd_direct(unsigned long *args) ...@@ -45,7 +46,7 @@ void p1275_cmd_direct(unsigned long *args)
prom_world(0); prom_world(0);
raw_spin_unlock(&prom_entry_lock); raw_spin_unlock(&prom_entry_lock);
raw_local_irq_restore(flags); local_irq_restore(flags);
} }
void prom_cif_init(void *cif_handler, void *cif_stack) void prom_cif_init(void *cif_handler, void *cif_stack)
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/hdreg.h> #include <linux/hdreg.h>
#include <linux/genhd.h> #include <linux/genhd.h>
#include <linux/cdrom.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/completion.h> #include <linux/completion.h>
...@@ -22,8 +23,8 @@ ...@@ -22,8 +23,8 @@
#define DRV_MODULE_NAME "sunvdc" #define DRV_MODULE_NAME "sunvdc"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.0" #define DRV_MODULE_VERSION "1.1"
#define DRV_MODULE_RELDATE "June 25, 2007" #define DRV_MODULE_RELDATE "February 13, 2013"
static char version[] = static char version[] =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
...@@ -32,7 +33,7 @@ MODULE_DESCRIPTION("Sun LDOM virtual disk client driver"); ...@@ -32,7 +33,7 @@ MODULE_DESCRIPTION("Sun LDOM virtual disk client driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION); MODULE_VERSION(DRV_MODULE_VERSION);
#define VDC_TX_RING_SIZE 256 #define VDC_TX_RING_SIZE 512
#define WAITING_FOR_LINK_UP 0x01 #define WAITING_FOR_LINK_UP 0x01
#define WAITING_FOR_TX_SPACE 0x02 #define WAITING_FOR_TX_SPACE 0x02
...@@ -65,10 +66,10 @@ struct vdc_port { ...@@ -65,10 +66,10 @@ struct vdc_port {
u64 operations; u64 operations;
u32 vdisk_size; u32 vdisk_size;
u8 vdisk_type; u8 vdisk_type;
u8 vdisk_mtype;
char disk_name[32]; char disk_name[32];
struct vio_disk_geom geom;
struct vio_disk_vtoc label; struct vio_disk_vtoc label;
}; };
...@@ -79,9 +80,16 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) ...@@ -79,9 +80,16 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
/* Ordered from largest major to lowest */ /* Ordered from largest major to lowest */
static struct vio_version vdc_versions[] = { static struct vio_version vdc_versions[] = {
{ .major = 1, .minor = 1 },
{ .major = 1, .minor = 0 }, { .major = 1, .minor = 0 },
}; };
static inline int vdc_version_supported(struct vdc_port *port,
u16 major, u16 minor)
{
return port->vio.ver.major == major && port->vio.ver.minor >= minor;
}
#define VDCBLK_NAME "vdisk" #define VDCBLK_NAME "vdisk"
static int vdc_major; static int vdc_major;
#define PARTITION_SHIFT 3 #define PARTITION_SHIFT 3
...@@ -94,18 +102,54 @@ static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr) ...@@ -94,18 +102,54 @@ static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr)
static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo) static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
{ {
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
struct vdc_port *port = disk->private_data; sector_t nsect = get_capacity(disk);
sector_t cylinders = nsect;
geo->heads = (u8) port->geom.num_hd; geo->heads = 0xff;
geo->sectors = (u8) port->geom.num_sec; geo->sectors = 0x3f;
geo->cylinders = port->geom.num_cyl; sector_div(cylinders, geo->heads * geo->sectors);
geo->cylinders = cylinders;
if ((sector_t)(geo->cylinders + 1) * geo->heads * geo->sectors < nsect)
geo->cylinders = 0xffff;
return 0; return 0;
} }
/* Add ioctl/CDROM_GET_CAPABILITY to support cdrom_id in udev
* when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD.
* Needed to be able to install inside an ldom from an iso image.
*/
static int vdc_ioctl(struct block_device *bdev, fmode_t mode,
unsigned command, unsigned long argument)
{
int i;
struct gendisk *disk;
switch (command) {
case CDROMMULTISESSION:
pr_debug(PFX "Multisession CDs not supported\n");
for (i = 0; i < sizeof(struct cdrom_multisession); i++)
if (put_user(0, (char __user *)(argument + i)))
return -EFAULT;
return 0;
case CDROM_GET_CAPABILITY:
disk = bdev->bd_disk;
if (bdev->bd_disk && (disk->flags & GENHD_FL_CD))
return 0;
return -EINVAL;
default:
pr_debug(PFX "ioctl %08x not supported\n", command);
return -EINVAL;
}
}
static const struct block_device_operations vdc_fops = { static const struct block_device_operations vdc_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.getgeo = vdc_getgeo, .getgeo = vdc_getgeo,
.ioctl = vdc_ioctl,
}; };
static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
...@@ -165,9 +209,9 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg) ...@@ -165,9 +209,9 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
struct vio_disk_attr_info *pkt = arg; struct vio_disk_attr_info *pkt = arg;
viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] " viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] "
"xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n", "mtype[0x%x] xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n",
pkt->tag.stype, pkt->operations, pkt->tag.stype, pkt->operations,
pkt->vdisk_size, pkt->vdisk_type, pkt->vdisk_size, pkt->vdisk_type, pkt->vdisk_mtype,
pkt->xfer_mode, pkt->vdisk_block_size, pkt->xfer_mode, pkt->vdisk_block_size,
pkt->max_xfer_size); pkt->max_xfer_size);
...@@ -192,8 +236,11 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg) ...@@ -192,8 +236,11 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
} }
port->operations = pkt->operations; port->operations = pkt->operations;
port->vdisk_size = pkt->vdisk_size;
port->vdisk_type = pkt->vdisk_type; port->vdisk_type = pkt->vdisk_type;
if (vdc_version_supported(port, 1, 1)) {
port->vdisk_size = pkt->vdisk_size;
port->vdisk_mtype = pkt->vdisk_mtype;
}
if (pkt->max_xfer_size < port->max_xfer_size) if (pkt->max_xfer_size < port->max_xfer_size)
port->max_xfer_size = pkt->max_xfer_size; port->max_xfer_size = pkt->max_xfer_size;
port->vdisk_block_size = pkt->vdisk_block_size; port->vdisk_block_size = pkt->vdisk_block_size;
...@@ -236,7 +283,9 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, ...@@ -236,7 +283,9 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
__blk_end_request(req, (desc->status ? -EIO : 0), desc->size); __blk_end_request(req, (desc->status ? -EIO : 0), desc->size);
if (blk_queue_stopped(port->disk->queue)) /* restart blk queue when ring is half emptied */
if (blk_queue_stopped(port->disk->queue) &&
vdc_tx_dring_avail(dr) * 100 / VDC_TX_RING_SIZE >= 50)
blk_start_queue(port->disk->queue); blk_start_queue(port->disk->queue);
} }
...@@ -388,12 +437,6 @@ static int __send_request(struct request *req) ...@@ -388,12 +437,6 @@ static int __send_request(struct request *req)
for (i = 0; i < nsg; i++) for (i = 0; i < nsg; i++)
len += sg[i].length; len += sg[i].length;
if (unlikely(vdc_tx_dring_avail(dr) < 1)) {
blk_stop_queue(port->disk->queue);
err = -ENOMEM;
goto out;
}
desc = vio_dring_cur(dr); desc = vio_dring_cur(dr);
err = ldc_map_sg(port->vio.lp, sg, nsg, err = ldc_map_sg(port->vio.lp, sg, nsg,
...@@ -433,21 +476,32 @@ static int __send_request(struct request *req) ...@@ -433,21 +476,32 @@ static int __send_request(struct request *req)
port->req_id++; port->req_id++;
dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1);
} }
out:
return err; return err;
} }
static void do_vdc_request(struct request_queue *q) static void do_vdc_request(struct request_queue *rq)
{ {
while (1) { struct request *req;
struct request *req = blk_fetch_request(q);
if (!req) while ((req = blk_peek_request(rq)) != NULL) {
break; struct vdc_port *port;
struct vio_dring_state *dr;
port = req->rq_disk->private_data;
dr = &port->vio.drings[VIO_DRIVER_TX_RING];
if (unlikely(vdc_tx_dring_avail(dr) < 1))
goto wait;
if (__send_request(req) < 0) blk_start_request(req);
__blk_end_request_all(req, -EIO);
if (__send_request(req) < 0) {
blk_requeue_request(rq, req);
wait:
/* Avoid pointless unplugs. */
blk_stop_queue(rq);
break;
}
} }
} }
...@@ -663,17 +717,26 @@ static int probe_disk(struct vdc_port *port) ...@@ -663,17 +717,26 @@ static int probe_disk(struct vdc_port *port)
return err; return err;
} }
if (vdc_version_supported(port, 1, 1)) {
/* vdisk_size should be set during the handshake, if it wasn't
* then the underlying disk is reserved by another system
*/
if (port->vdisk_size == -1)
return -ENODEV;
} else {
struct vio_disk_geom geom;
err = generic_request(port, VD_OP_GET_DISKGEOM, err = generic_request(port, VD_OP_GET_DISKGEOM,
&port->geom, sizeof(port->geom)); &geom, sizeof(geom));
if (err < 0) { if (err < 0) {
printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
"error %d\n", err); "error %d\n", err);
return err; return err;
} }
port->vdisk_size = ((u64)geom.num_cyl *
port->vdisk_size = ((u64)port->geom.num_cyl * (u64)geom.num_hd *
(u64)port->geom.num_hd * (u64)geom.num_sec);
(u64)port->geom.num_sec); }
q = blk_init_queue(do_vdc_request, &port->vio.lock); q = blk_init_queue(do_vdc_request, &port->vio.lock);
if (!q) { if (!q) {
...@@ -691,6 +754,10 @@ static int probe_disk(struct vdc_port *port) ...@@ -691,6 +754,10 @@ static int probe_disk(struct vdc_port *port)
port->disk = g; port->disk = g;
/* Each segment in a request is up to an aligned page in size. */
blk_queue_segment_boundary(q, PAGE_SIZE - 1);
blk_queue_max_segment_size(q, PAGE_SIZE);
blk_queue_max_segments(q, port->ring_cookies); blk_queue_max_segments(q, port->ring_cookies);
blk_queue_max_hw_sectors(q, port->max_xfer_size); blk_queue_max_hw_sectors(q, port->max_xfer_size);
g->major = vdc_major; g->major = vdc_major;
...@@ -704,9 +771,32 @@ static int probe_disk(struct vdc_port *port) ...@@ -704,9 +771,32 @@ static int probe_disk(struct vdc_port *port)
set_capacity(g, port->vdisk_size); set_capacity(g, port->vdisk_size);
printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n", if (vdc_version_supported(port, 1, 1)) {
switch (port->vdisk_mtype) {
case VD_MEDIA_TYPE_CD:
pr_info(PFX "Virtual CDROM %s\n", port->disk_name);
g->flags |= GENHD_FL_CD;
g->flags |= GENHD_FL_REMOVABLE;
set_disk_ro(g, 1);
break;
case VD_MEDIA_TYPE_DVD:
pr_info(PFX "Virtual DVD %s\n", port->disk_name);
g->flags |= GENHD_FL_CD;
g->flags |= GENHD_FL_REMOVABLE;
set_disk_ro(g, 1);
break;
case VD_MEDIA_TYPE_FIXED:
pr_info(PFX "Virtual Hard disk %s\n", port->disk_name);
break;
}
}
pr_info(PFX "%s: %u sectors (%u MB) protocol %d.%d\n",
g->disk_name, g->disk_name,
port->vdisk_size, (port->vdisk_size >> (20 - 9))); port->vdisk_size, (port->vdisk_size >> (20 - 9)),
port->vio.ver.major, port->vio.ver.minor);
add_disk(g); add_disk(g);
...@@ -765,6 +855,7 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) ...@@ -765,6 +855,7 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
else else
snprintf(port->disk_name, sizeof(port->disk_name), snprintf(port->disk_name, sizeof(port->disk_name),
VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26)); VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
port->vdisk_size = -1;
err = vio_driver_init(&port->vio, vdev, VDEV_DISK, err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
vdc_versions, ARRAY_SIZE(vdc_versions), vdc_versions, ARRAY_SIZE(vdc_versions),
......
...@@ -954,7 +954,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -954,7 +954,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irqsave(&port->vio.lock, flags); spin_lock_irqsave(&port->vio.lock, flags);
dr = &port->vio.drings[VIO_DRIVER_TX_RING]; dr = &port->vio.drings[VIO_DRIVER_TX_RING];
if (unlikely(vnet_tx_dring_avail(dr) < 2)) { if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
if (!netif_queue_stopped(dev)) { if (!netif_queue_stopped(dev)) {
netif_stop_queue(dev); netif_stop_queue(dev);
...@@ -1049,7 +1049,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -1049,7 +1049,7 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
dev->stats.tx_bytes += port->tx_bufs[txi].skb->len; dev->stats.tx_bytes += port->tx_bufs[txi].skb->len;
dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1);
if (unlikely(vnet_tx_dring_avail(dr) < 2)) { if (unlikely(vnet_tx_dring_avail(dr) < 1)) {
netif_stop_queue(dev); netif_stop_queue(dev);
if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr)) if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr))
netif_wake_queue(dev); netif_wake_queue(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment