Hi Dave, On 03.06.19 01:12, John David Anglin wrote: > Most I/O in the kernel is done using the kernel offset mapping. However, there > is one API that uses aliased kernel address ranges: > >> The final category of APIs is for I/O to deliberately aliased address >> ranges inside the kernel. Such aliases are set up by use of the >> vmap/vmalloc API. Since kernel I/O goes via physical pages, the I/O >> subsystem assumes that the user mapping and kernel offset mapping are >> the only aliases. This isn't true for vmap aliases, so anything in >> the kernel trying to do I/O to vmap areas must manually manage >> coherency. It must do this by flushing the vmap range before doing >> I/O and invalidating it after the I/O returns. > > For this reason, we should use the hardware lpa instruction to load the physical address > of kernel virtual addresses in the driver code. > > I believe we only use the vmap/vmalloc API with old PA 1.x processors which don't have > a sba, so we don't hit this problem. > > Tested on c3750, c8000 and rp3440. > > This patch includes the previous change to use implicit space register access in loading > the coherence index as the two changes conflict. Actually, I think it makes sense to push the drop-sr1/use-lci-without-sr1 change backward to the stable kernel series. After that, in the second step, we could add the code to use lpa(), which I don't think should go to stable series. Would it be OK for you if we split it up into two patches? Helge > > Signed-off-by: John David Anglin <dave.anglin@xxxxxxxx> > --- > diff --git a/arch/parisc/include/asm/special_insns.h b/arch/parisc/include/asm/special_insns.h > index 3d4dd68e181b..a303ae9a77f4 100644 > --- a/arch/parisc/include/asm/special_insns.h > +++ b/arch/parisc/include/asm/special_insns.h > @@ -2,6 +2,30 @@ > #ifndef __PARISC_SPECIAL_INSNS_H > #define __PARISC_SPECIAL_INSNS_H > > +#define lpa(va) ({ \ > + unsigned long pa; \ > + __asm__ __volatile__( \ > + "copy %%r0,%0\n\t" \ > + "lpa %%r0(%1),%0" \ > + : "=r" (pa) \ > + : "r" (va) \ > + : "memory" \ > + ); \ > + pa; \ > +}) > + > +#define lpa_user(va) ({ \ > + unsigned long pa; \ > + __asm__ __volatile__( \ > + "copy %%r0,%0\n\t" \ > + "lpa %%r0(%%sr3,%1),%0" \ > + : "=r" (pa) \ > + : "r" (va) \ > + : "memory" \ > + ); \ > + pa; \ > +}) > + > #define mfctl(reg) ({ \ > unsigned long cr; \ > __asm__ __volatile__( \ > diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c > index 121f7603a595..217f15aafa4a 100644 > --- a/drivers/parisc/ccio-dma.c > +++ b/drivers/parisc/ccio-dma.c > @@ -562,14 +562,12 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, > /* We currently only support kernel addresses */ > BUG_ON(sid != KERNEL_SPACE); > > - mtsp(sid,1); > - > /* > ** WORD 1 - low order word > ** "hints" parm includes the VALID bit! > ** "dep" clobbers the physical address offset bits as well. > */ > - pa = virt_to_phys(vba); > + pa = lpa(vba); > asm volatile("depw %1,31,12,%0" : "+r" (pa) : "r" (hints)); > ((u32 *)pdir_ptr)[1] = (u32) pa; > > @@ -594,7 +592,7 @@ ccio_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, > ** Grab virtual index [0:11] > ** Deposit virt_idx bits into I/O PDIR word > */ > - asm volatile ("lci %%r0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); > + asm volatile ("lci %%r0(%1), %0" : "=r" (ci) : "r" (vba)); > asm volatile ("extru %1,19,12,%0" : "+r" (ci) : "r" (ci)); > asm volatile ("depw %1,15,12,%0" : "+r" (pa) : "r" (ci)); > > diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c > index 8a9ea9bd050c..296668caf7e5 100644 > --- a/drivers/parisc/sba_iommu.c > +++ b/drivers/parisc/sba_iommu.c > @@ -569,11 +569,10 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, > u64 pa; /* physical address */ > register unsigned ci; /* coherent index */ > > - pa = virt_to_phys(vba); > + pa = lpa(vba); > pa &= IOVP_MASK; > > - mtsp(sid,1); > - asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); > + asm("lci 0(%1), %0" : "=r" (ci) : "r" (vba)); > pa |= (ci >> PAGE_SHIFT) & 0xff; /* move CI (8 bits) into lowest byte */ > > pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ >