Fixes for omaps, all dts changes except for one:

- Fix up LCD panel name for overo boards
 
 - Three fixes for pepper board for regulators, freqeuncy
   scaling and audio input. Note that there is still one
   issue being worked on for booting with multi_v7_defconfig
 
 - Add missing #iommu-cells for omap4 and 5
 
 - Add missing HAVE_ARM_SCU for am43xx
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJVpjAqAAoJEBvUPslcq6VzSQoQALWv6NEgBqmhSNQOCLHAj2DA
 EHutZNPZW20WXupnaMJvAYFCDyQ/xFzz8u9JCyDO1HyfLiXzkCohTxY/FrJD8Iml
 y4TwIiDLGlZI4cghsQN5uQs9meGIl7xnAcdO8nzReCi+F/sm/wuTYmvZ35YHXz7Y
 DC6n2k3Hp2N8kj/NdKscR4OGryMcBT38YLGPn5hq/hcQdvEEUu6A4drq3lWiKmD6
 IXxJZR1IbEquiwDR3nBdZ7oEiz97cZLZgitL0+6tJFWKNQMtJ2Y/XDPd1+paVULZ
 13y38YFOakD0wVyvf8dq+JiFScFh+dUi5oEjA+Bc/2H/yRShsNc5ykmlMWGcC1A3
 LHH85FAW4qF+3yTjAw6x79wGFV3krVXs2YkwM60xujHtPsKJEXdEHpC+pM1B2/Yn
 slvGNobiy7LpIMy/PmazN+UnEf3Anr+8YFY4I2K50WhqGjy/E1BvpQeYfEow5ANT
 bEP1h9KVH3Fmw/w/NDbZkLxlMdAHdBScSXe1qH2RQUsz2Mj2+682wSSccViBrSIy
 VVF7kbzbKe+p/CRJO5HdHVxtyLky7ptF4fIWA3ewccIezgMJjMMzX/b3vV1glM+l
 TTbGm/GZ4vjUOFUxvyBI73o7cFCg2Q6TcdtuQNw4UZAzvbFHEMsz9KrqocMV6FY+
 8n43diT9rPAwJa9Lr5dO
 =MPTh
 -----END PGP SIGNATURE-----

Merge tag 'omap-for-v4.2/fixes-rc2-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap into fixes

Fixes for omaps, all dts changes except for one:

- Fix up LCD panel name for overo boards

- Three fixes for pepper board for regulators, freqeuncy
  scaling and audio input. Note that there is still one
  issue being worked on for booting with multi_v7_defconfig

- Add missing #iommu-cells for omap4 and 5

- Add missing HAVE_ARM_SCU for am43xx

* tag 'omap-for-v4.2/fixes-rc2-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tmlind/linux-omap: (210 commits)
  ARM: dts: Correct audio input route & set mic bias for am335x-pepper
  ARM: OMAP2+: Add HAVE_ARM_SCU for AM43XX
  ARM: dts: OMAP5: Add #iommu-cells property to IOMMUs
  ARM: dts: OMAP4: Add #iommu-cells property to IOMMUs
  ARM: dts: Fix frequency scaling on Gumstix Pepper
  ARM: dts: configure regulators for Gumstix Pepper
  ARM: dts: omap3: overo: Update LCD panel names
  + Linux 4.2-rc2

Signed-off-by: Olof Johansson <olof@lixom.net>
This commit is contained in:
Olof Johansson 2015-07-15 07:02:33 -04:00
commit e0ea136525
229 changed files with 4424 additions and 1904 deletions

View File

@ -410,8 +410,17 @@ Documentation/usb/persist.txt.
Q: Can I suspend-to-disk using a swap partition under LVM? Q: Can I suspend-to-disk using a swap partition under LVM?
A: No. You can suspend successfully, but you'll not be able to A: Yes and No. You can suspend successfully, but the kernel will not be able
resume. uswsusp should be able to work with LVM. See suspend.sf.net. to resume on its own. You need an initramfs that can recognize the resume
situation, activate the logical volume containing the swap volume (but not
touch any filesystems!), and eventually call
echo -n "$major:$minor" > /sys/power/resume
where $major and $minor are the respective major and minor device numbers of
the swap volume.
uswsusp works with LVM, too. See http://suspend.sourceforge.net/
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
compiled with the similar configuration files. Anyway I found that compiled with the similar configuration files. Anyway I found that

View File

@ -2564,19 +2564,31 @@ F: arch/powerpc/include/uapi/asm/spu*.h
F: arch/powerpc/oprofile/*cell* F: arch/powerpc/oprofile/*cell*
F: arch/powerpc/platforms/cell/ F: arch/powerpc/platforms/cell/
CEPH DISTRIBUTED FILE SYSTEM CLIENT CEPH COMMON CODE (LIBCEPH)
M: Ilya Dryomov <idryomov@gmail.com>
M: "Yan, Zheng" <zyan@redhat.com> M: "Yan, Zheng" <zyan@redhat.com>
M: Sage Weil <sage@redhat.com> M: Sage Weil <sage@redhat.com>
L: ceph-devel@vger.kernel.org L: ceph-devel@vger.kernel.org
W: http://ceph.com/ W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
T: git git://github.com/ceph/ceph-client.git
S: Supported S: Supported
F: Documentation/filesystems/ceph.txt
F: fs/ceph/
F: net/ceph/ F: net/ceph/
F: include/linux/ceph/ F: include/linux/ceph/
F: include/linux/crush/ F: include/linux/crush/
CEPH DISTRIBUTED FILE SYSTEM CLIENT (CEPH)
M: "Yan, Zheng" <zyan@redhat.com>
M: Sage Weil <sage@redhat.com>
M: Ilya Dryomov <idryomov@gmail.com>
L: ceph-devel@vger.kernel.org
W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
T: git git://github.com/ceph/ceph-client.git
S: Supported
F: Documentation/filesystems/ceph.txt
F: fs/ceph/
CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM: CERTIFIED WIRELESS USB (WUSB) SUBSYSTEM:
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
S: Orphan S: Orphan
@ -6149,6 +6161,7 @@ L: linux-nvdimm@lists.01.org
Q: https://patchwork.kernel.org/project/linux-nvdimm/list/ Q: https://patchwork.kernel.org/project/linux-nvdimm/list/
S: Supported S: Supported
F: drivers/nvdimm/pmem.c F: drivers/nvdimm/pmem.c
F: include/linux/pmem.h
LINUX FOR IBM pSERIES (RS/6000) LINUX FOR IBM pSERIES (RS/6000)
M: Paul Mackerras <paulus@au.ibm.com> M: Paul Mackerras <paulus@au.ibm.com>
@ -6163,7 +6176,7 @@ M: Michael Ellerman <mpe@ellerman.id.au>
W: http://www.penguinppc.org/ W: http://www.penguinppc.org/
L: linuxppc-dev@lists.ozlabs.org L: linuxppc-dev@lists.ozlabs.org
Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/ Q: http://patchwork.ozlabs.org/project/linuxppc-dev/list/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git
S: Supported S: Supported
F: Documentation/powerpc/ F: Documentation/powerpc/
F: arch/powerpc/ F: arch/powerpc/
@ -8368,10 +8381,12 @@ RADOS BLOCK DEVICE (RBD)
M: Ilya Dryomov <idryomov@gmail.com> M: Ilya Dryomov <idryomov@gmail.com>
M: Sage Weil <sage@redhat.com> M: Sage Weil <sage@redhat.com>
M: Alex Elder <elder@kernel.org> M: Alex Elder <elder@kernel.org>
M: ceph-devel@vger.kernel.org L: ceph-devel@vger.kernel.org
W: http://ceph.com/ W: http://ceph.com/
T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
T: git git://github.com/ceph/ceph-client.git
S: Supported S: Supported
F: Documentation/ABI/testing/sysfs-bus-rbd
F: drivers/block/rbd.c F: drivers/block/rbd.c
F: drivers/block/rbd_types.h F: drivers/block/rbd_types.h

View File

@ -1,7 +1,7 @@
VERSION = 4 VERSION = 4
PATCHLEVEL = 2 PATCHLEVEL = 2
SUBLEVEL = 0 SUBLEVEL = 0
EXTRAVERSION = -rc1 EXTRAVERSION = -rc2
NAME = Hurr durr I'ma sheep NAME = Hurr durr I'ma sheep
# *DOCUMENTATION* # *DOCUMENTATION*

View File

@ -1693,6 +1693,12 @@ config HIGHMEM
config HIGHPTE config HIGHPTE
bool "Allocate 2nd-level pagetables from highmem" bool "Allocate 2nd-level pagetables from highmem"
depends on HIGHMEM depends on HIGHMEM
help
The VM uses one page of physical memory for each page table.
For systems with a lot of processes, this can use a lot of
precious low memory, eventually leading to low memory being
consumed by page tables. Setting this option will allow
user-space 2nd level page tables to reside in high memory.
config HW_PERF_EVENTS config HW_PERF_EVENTS
bool "Enable hardware performance counter support for perf events" bool "Enable hardware performance counter support for perf events"

View File

@ -1635,7 +1635,7 @@ config PID_IN_CONTEXTIDR
config DEBUG_SET_MODULE_RONX config DEBUG_SET_MODULE_RONX
bool "Set loadable kernel module data as NX and text as RO" bool "Set loadable kernel module data as NX and text as RO"
depends on MODULES depends on MODULES && MMU
---help--- ---help---
This option helps catch unintended modifications to loadable This option helps catch unintended modifications to loadable
kernel module's text and read-only data. It also prevents execution kernel module's text and read-only data. It also prevents execution

View File

@ -74,6 +74,7 @@
audio_codec: tlv320aic3106@1b { audio_codec: tlv320aic3106@1b {
compatible = "ti,tlv320aic3106"; compatible = "ti,tlv320aic3106";
reg = <0x1b>; reg = <0x1b>;
ai3x-micbias-vg = <0x2>;
}; };
accel: lis331dlh@1d { accel: lis331dlh@1d {
@ -153,7 +154,7 @@
ti,audio-routing = ti,audio-routing =
"Headphone Jack", "HPLOUT", "Headphone Jack", "HPLOUT",
"Headphone Jack", "HPROUT", "Headphone Jack", "HPROUT",
"LINE1L", "Line In"; "MIC3L", "Mic3L Switch";
}; };
&mcasp0 { &mcasp0 {
@ -438,41 +439,50 @@
regulators { regulators {
dcdc1_reg: regulator@0 { dcdc1_reg: regulator@0 {
/* VDD_1V8 system supply */ /* VDD_1V8 system supply */
regulator-always-on;
}; };
dcdc2_reg: regulator@1 { dcdc2_reg: regulator@1 {
/* VDD_CORE voltage limits 0.95V - 1.26V with +/-4% tolerance */ /* VDD_CORE voltage limits 0.95V - 1.26V with +/-4% tolerance */
regulator-name = "vdd_core"; regulator-name = "vdd_core";
regulator-min-microvolt = <925000>; regulator-min-microvolt = <925000>;
regulator-max-microvolt = <1325000>; regulator-max-microvolt = <1150000>;
regulator-boot-on; regulator-boot-on;
regulator-always-on;
}; };
dcdc3_reg: regulator@2 { dcdc3_reg: regulator@2 {
/* VDD_MPU voltage limits 0.95V - 1.1V with +/-4% tolerance */ /* VDD_MPU voltage limits 0.95V - 1.1V with +/-4% tolerance */
regulator-name = "vdd_mpu"; regulator-name = "vdd_mpu";
regulator-min-microvolt = <925000>; regulator-min-microvolt = <925000>;
regulator-max-microvolt = <1150000>; regulator-max-microvolt = <1325000>;
regulator-boot-on; regulator-boot-on;
regulator-always-on;
}; };
ldo1_reg: regulator@3 { ldo1_reg: regulator@3 {
/* VRTC 1.8V always-on supply */ /* VRTC 1.8V always-on supply */
regulator-name = "vrtc,vdds";
regulator-always-on; regulator-always-on;
}; };
ldo2_reg: regulator@4 { ldo2_reg: regulator@4 {
/* 3.3V rail */ /* 3.3V rail */
regulator-name = "vdd_3v3aux";
regulator-always-on;
}; };
ldo3_reg: regulator@5 { ldo3_reg: regulator@5 {
/* VDD_3V3A 3.3V rail */ /* VDD_3V3A 3.3V rail */
regulator-name = "vdd_3v3a";
regulator-min-microvolt = <3300000>; regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>; regulator-max-microvolt = <3300000>;
}; };
ldo4_reg: regulator@6 { ldo4_reg: regulator@6 {
/* VDD_3V3B 3.3V rail */ /* VDD_3V3B 3.3V rail */
regulator-name = "vdd_3v3b";
regulator-always-on;
}; };
}; };
}; };

View File

@ -120,7 +120,7 @@
lcd0: display@0 { lcd0: display@0 {
compatible = "lgphilips,lb035q02"; compatible = "lgphilips,lb035q02";
label = "lcd"; label = "lcd35";
reg = <1>; /* CS1 */ reg = <1>; /* CS1 */
spi-max-frequency = <10000000>; spi-max-frequency = <10000000>;

View File

@ -98,7 +98,7 @@
lcd0: display@0 { lcd0: display@0 {
compatible = "samsung,lte430wq-f0c", "panel-dpi"; compatible = "samsung,lte430wq-f0c", "panel-dpi";
label = "lcd"; label = "lcd43";
pinctrl-names = "default"; pinctrl-names = "default";
pinctrl-0 = <&lte430_pins>; pinctrl-0 = <&lte430_pins>;

View File

@ -551,6 +551,7 @@
reg = <0x4a066000 0x100>; reg = <0x4a066000 0x100>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mmu_dsp"; ti,hwmods = "mmu_dsp";
#iommu-cells = <0>;
}; };
mmu_ipu: mmu@55082000 { mmu_ipu: mmu@55082000 {
@ -558,6 +559,7 @@
reg = <0x55082000 0x100>; reg = <0x55082000 0x100>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mmu_ipu"; ti,hwmods = "mmu_ipu";
#iommu-cells = <0>;
ti,iommu-bus-err-back; ti,iommu-bus-err-back;
}; };

View File

@ -612,6 +612,7 @@
reg = <0x4a066000 0x100>; reg = <0x4a066000 0x100>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mmu_dsp"; ti,hwmods = "mmu_dsp";
#iommu-cells = <0>;
}; };
mmu_ipu: mmu@55082000 { mmu_ipu: mmu@55082000 {
@ -619,6 +620,7 @@
reg = <0x55082000 0x100>; reg = <0x55082000 0x100>;
interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>; interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mmu_ipu"; ti,hwmods = "mmu_ipu";
#iommu-cells = <0>;
ti,iommu-bus-err-back; ti,iommu-bus-err-back;
}; };

View File

@ -140,16 +140,11 @@ static inline u32 __raw_readl(const volatile void __iomem *addr)
* The _caller variety takes a __builtin_return_address(0) value for * The _caller variety takes a __builtin_return_address(0) value for
* /proc/vmalloc to use - and should only be used in non-inline functions. * /proc/vmalloc to use - and should only be used in non-inline functions.
*/ */
extern void __iomem *__arm_ioremap_pfn_caller(unsigned long, unsigned long,
size_t, unsigned int, void *);
extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int, extern void __iomem *__arm_ioremap_caller(phys_addr_t, size_t, unsigned int,
void *); void *);
extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int); extern void __iomem *__arm_ioremap_pfn(unsigned long, unsigned long, size_t, unsigned int);
extern void __iomem *__arm_ioremap(phys_addr_t, size_t, unsigned int);
extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached); extern void __iomem *__arm_ioremap_exec(phys_addr_t, size_t, bool cached);
extern void __iounmap(volatile void __iomem *addr); extern void __iounmap(volatile void __iomem *addr);
extern void __arm_iounmap(volatile void __iomem *addr);
extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, extern void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
unsigned int, void *); unsigned int, void *);
@ -321,21 +316,24 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
static inline void memset_io(volatile void __iomem *dst, unsigned c, static inline void memset_io(volatile void __iomem *dst, unsigned c,
size_t count) size_t count)
{ {
memset((void __force *)dst, c, count); extern void mmioset(void *, unsigned int, size_t);
mmioset((void __force *)dst, c, count);
} }
#define memset_io(dst,c,count) memset_io(dst,c,count) #define memset_io(dst,c,count) memset_io(dst,c,count)
static inline void memcpy_fromio(void *to, const volatile void __iomem *from, static inline void memcpy_fromio(void *to, const volatile void __iomem *from,
size_t count) size_t count)
{ {
memcpy(to, (const void __force *)from, count); extern void mmiocpy(void *, const void *, size_t);
mmiocpy(to, (const void __force *)from, count);
} }
#define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count) #define memcpy_fromio(to,from,count) memcpy_fromio(to,from,count)
static inline void memcpy_toio(volatile void __iomem *to, const void *from, static inline void memcpy_toio(volatile void __iomem *to, const void *from,
size_t count) size_t count)
{ {
memcpy((void __force *)to, from, count); extern void mmiocpy(void *, const void *, size_t);
mmiocpy((void __force *)to, from, count);
} }
#define memcpy_toio(to,from,count) memcpy_toio(to,from,count) #define memcpy_toio(to,from,count) memcpy_toio(to,from,count)
@ -348,18 +346,61 @@ static inline void memcpy_toio(volatile void __iomem *to, const void *from,
#endif /* readl */ #endif /* readl */
/* /*
* ioremap and friends. * ioremap() and friends.
* *
* ioremap takes a PCI memory address, as specified in * ioremap() takes a resource address, and size. Due to the ARM memory
* Documentation/io-mapping.txt. * types, it is important to use the correct ioremap() function as each
* mapping has specific properties.
* *
* Function Memory type Cacheability Cache hint
* ioremap() Device n/a n/a
* ioremap_nocache() Device n/a n/a
* ioremap_cache() Normal Writeback Read allocate
* ioremap_wc() Normal Non-cacheable n/a
* ioremap_wt() Normal Non-cacheable n/a
*
* All device mappings have the following properties:
* - no access speculation
* - no repetition (eg, on return from an exception)
* - number, order and size of accesses are maintained
* - unaligned accesses are "unpredictable"
* - writes may be delayed before they hit the endpoint device
*
* ioremap_nocache() is the same as ioremap() as there are too many device
* drivers using this for device registers, and documentation which tells
* people to use it for such for this to be any different. This is not a
* safe fallback for memory-like mappings, or memory regions where the
* compiler may generate unaligned accesses - eg, via inlining its own
* memcpy.
*
* All normal memory mappings have the following properties:
* - reads can be repeated with no side effects
* - repeated reads return the last value written
* - reads can fetch additional locations without side effects
* - writes can be repeated (in certain cases) with no side effects
* - writes can be merged before accessing the target
* - unaligned accesses can be supported
* - ordering is not guaranteed without explicit dependencies or barrier
* instructions
* - writes may be delayed before they hit the endpoint memory
*
* The cache hint is only a performance hint: CPUs may alias these hints.
* Eg, a CPU not implementing read allocate but implementing write allocate
* will provide a write allocate mapping instead.
*/ */
#define ioremap(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) void __iomem *ioremap(resource_size_t res_cookie, size_t size);
#define ioremap_nocache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) #define ioremap ioremap
#define ioremap_cache(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_CACHED) #define ioremap_nocache ioremap
#define ioremap_wc(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE_WC)
#define ioremap_wt(cookie,size) __arm_ioremap((cookie), (size), MT_DEVICE) void __iomem *ioremap_cache(resource_size_t res_cookie, size_t size);
#define iounmap __arm_iounmap #define ioremap_cache ioremap_cache
void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size);
#define ioremap_wc ioremap_wc
#define ioremap_wt ioremap_wc
void iounmap(volatile void __iomem *iomem_cookie);
#define iounmap iounmap
/* /*
* io{read,write}{16,32}be() macros * io{read,write}{16,32}be() macros

View File

@ -275,7 +275,7 @@ static inline void *phys_to_virt(phys_addr_t x)
*/ */
#define __pa(x) __virt_to_phys((unsigned long)(x)) #define __pa(x) __virt_to_phys((unsigned long)(x))
#define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x))) #define __va(x) ((void *)__phys_to_virt((phys_addr_t)(x)))
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT) #define pfn_to_kaddr(pfn) __va((phys_addr_t)(pfn) << PAGE_SHIFT)
extern phys_addr_t (*arch_virt_to_idmap)(unsigned long x); extern phys_addr_t (*arch_virt_to_idmap)(unsigned long x);

View File

@ -129,7 +129,36 @@
/* /*
* These are the memory types, defined to be compatible with * These are the memory types, defined to be compatible with
* pre-ARMv6 CPUs cacheable and bufferable bits: XXCB * pre-ARMv6 CPUs cacheable and bufferable bits: n/a,n/a,C,B
* ARMv6+ without TEX remapping, they are a table index.
* ARMv6+ with TEX remapping, they correspond to n/a,TEX(0),C,B
*
* MT type Pre-ARMv6 ARMv6+ type / cacheable status
* UNCACHED Uncached Strongly ordered
* BUFFERABLE Bufferable Normal memory / non-cacheable
* WRITETHROUGH Writethrough Normal memory / write through
* WRITEBACK Writeback Normal memory / write back, read alloc
* MINICACHE Minicache N/A
* WRITEALLOC Writeback Normal memory / write back, write alloc
* DEV_SHARED Uncached Device memory (shared)
* DEV_NONSHARED Uncached Device memory (non-shared)
* DEV_WC Bufferable Normal memory / non-cacheable
* DEV_CACHED Writeback Normal memory / write back, read alloc
* VECTORS Variable Normal memory / variable
*
* All normal memory mappings have the following properties:
* - reads can be repeated with no side effects
* - repeated reads return the last value written
* - reads can fetch additional locations without side effects
* - writes can be repeated (in certain cases) with no side effects
* - writes can be merged before accessing the target
* - unaligned accesses can be supported
*
* All device mappings have the following properties:
* - no access speculation
* - no repetition (eg, on return from an exception)
* - number, order and size of accesses are maintained
* - unaligned accesses are "unpredictable"
*/ */
#define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << 2) /* 0000 */ #define L_PTE_MT_UNCACHED (_AT(pteval_t, 0x00) << 2) /* 0000 */
#define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << 2) /* 0001 */ #define L_PTE_MT_BUFFERABLE (_AT(pteval_t, 0x01) << 2) /* 0001 */

View File

@ -50,6 +50,9 @@ extern void __aeabi_ulcmp(void);
extern void fpundefinstr(void); extern void fpundefinstr(void);
void mmioset(void *, unsigned int, size_t);
void mmiocpy(void *, const void *, size_t);
/* platform dependent support */ /* platform dependent support */
EXPORT_SYMBOL(arm_delay_ops); EXPORT_SYMBOL(arm_delay_ops);
@ -88,6 +91,9 @@ EXPORT_SYMBOL(memmove);
EXPORT_SYMBOL(memchr); EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(__memzero); EXPORT_SYMBOL(__memzero);
EXPORT_SYMBOL(mmioset);
EXPORT_SYMBOL(mmiocpy);
#ifdef CONFIG_MMU #ifdef CONFIG_MMU
EXPORT_SYMBOL(copy_page); EXPORT_SYMBOL(copy_page);

View File

@ -410,7 +410,7 @@ ENDPROC(__fiq_abt)
zero_fp zero_fp
.if \trace .if \trace
#ifdef CONFIG_IRQSOFF_TRACER #ifdef CONFIG_TRACE_IRQFLAGS
bl trace_hardirqs_off bl trace_hardirqs_off
#endif #endif
ct_user_exit save = 0 ct_user_exit save = 0

View File

@ -578,7 +578,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
struct pt_regs *old_regs = set_irq_regs(regs); struct pt_regs *old_regs = set_irq_regs(regs);
if ((unsigned)ipinr < NR_IPI) { if ((unsigned)ipinr < NR_IPI) {
trace_ipi_entry(ipi_types[ipinr]); trace_ipi_entry_rcuidle(ipi_types[ipinr]);
__inc_irq_stat(cpu, ipi_irqs[ipinr]); __inc_irq_stat(cpu, ipi_irqs[ipinr]);
} }
@ -637,7 +637,7 @@ void handle_IPI(int ipinr, struct pt_regs *regs)
} }
if ((unsigned)ipinr < NR_IPI) if ((unsigned)ipinr < NR_IPI)
trace_ipi_exit(ipi_types[ipinr]); trace_ipi_exit_rcuidle(ipi_types[ipinr]);
set_irq_regs(old_regs); set_irq_regs(old_regs);
} }

View File

@ -61,8 +61,10 @@
/* Prototype: void *memcpy(void *dest, const void *src, size_t n); */ /* Prototype: void *memcpy(void *dest, const void *src, size_t n); */
ENTRY(mmiocpy)
ENTRY(memcpy) ENTRY(memcpy)
#include "copy_template.S" #include "copy_template.S"
ENDPROC(memcpy) ENDPROC(memcpy)
ENDPROC(mmiocpy)

View File

@ -16,6 +16,7 @@
.text .text
.align 5 .align 5
ENTRY(mmioset)
ENTRY(memset) ENTRY(memset)
UNWIND( .fnstart ) UNWIND( .fnstart )
ands r3, r0, #3 @ 1 unaligned? ands r3, r0, #3 @ 1 unaligned?
@ -133,3 +134,4 @@ UNWIND( .fnstart )
b 1b b 1b
UNWIND( .fnend ) UNWIND( .fnend )
ENDPROC(memset) ENDPROC(memset)
ENDPROC(mmioset)

View File

@ -60,6 +60,7 @@ config SOC_AM43XX
select ARM_GIC select ARM_GIC
select MACH_OMAP_GENERIC select MACH_OMAP_GENERIC
select MIGHT_HAVE_CACHE_L2X0 select MIGHT_HAVE_CACHE_L2X0
select HAVE_ARM_SCU
config SOC_DRA7XX config SOC_DRA7XX
bool "TI DRA7XX" bool "TI DRA7XX"

View File

@ -255,7 +255,7 @@ remap_area_supersections(unsigned long virt, unsigned long pfn,
} }
#endif #endif
void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn, static void __iomem * __arm_ioremap_pfn_caller(unsigned long pfn,
unsigned long offset, size_t size, unsigned int mtype, void *caller) unsigned long offset, size_t size, unsigned int mtype, void *caller)
{ {
const struct mem_type *type; const struct mem_type *type;
@ -363,7 +363,7 @@ __arm_ioremap_pfn(unsigned long pfn, unsigned long offset, size_t size,
unsigned int mtype) unsigned int mtype)
{ {
return __arm_ioremap_pfn_caller(pfn, offset, size, mtype, return __arm_ioremap_pfn_caller(pfn, offset, size, mtype,
__builtin_return_address(0)); __builtin_return_address(0));
} }
EXPORT_SYMBOL(__arm_ioremap_pfn); EXPORT_SYMBOL(__arm_ioremap_pfn);
@ -371,13 +371,26 @@ void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t,
unsigned int, void *) = unsigned int, void *) =
__arm_ioremap_caller; __arm_ioremap_caller;
void __iomem * void __iomem *ioremap(resource_size_t res_cookie, size_t size)
__arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{ {
return arch_ioremap_caller(phys_addr, size, mtype, return arch_ioremap_caller(res_cookie, size, MT_DEVICE,
__builtin_return_address(0)); __builtin_return_address(0));
} }
EXPORT_SYMBOL(__arm_ioremap); EXPORT_SYMBOL(ioremap);
void __iomem *ioremap_cache(resource_size_t res_cookie, size_t size)
{
return arch_ioremap_caller(res_cookie, size, MT_DEVICE_CACHED,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_cache);
void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size)
{
return arch_ioremap_caller(res_cookie, size, MT_DEVICE_WC,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_wc);
/* /*
* Remap an arbitrary physical address space into the kernel virtual * Remap an arbitrary physical address space into the kernel virtual
@ -431,11 +444,11 @@ void __iounmap(volatile void __iomem *io_addr)
void (*arch_iounmap)(volatile void __iomem *) = __iounmap; void (*arch_iounmap)(volatile void __iomem *) = __iounmap;
void __arm_iounmap(volatile void __iomem *io_addr) void iounmap(volatile void __iomem *cookie)
{ {
arch_iounmap(io_addr); arch_iounmap(cookie);
} }
EXPORT_SYMBOL(__arm_iounmap); EXPORT_SYMBOL(iounmap);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static int pci_ioremap_mem_type = MT_DEVICE; static int pci_ioremap_mem_type = MT_DEVICE;

View File

@ -1072,6 +1072,7 @@ void __init sanity_check_meminfo(void)
int highmem = 0; int highmem = 0;
phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1; phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
struct memblock_region *reg; struct memblock_region *reg;
bool should_use_highmem = false;
for_each_memblock(memory, reg) { for_each_memblock(memory, reg) {
phys_addr_t block_start = reg->base; phys_addr_t block_start = reg->base;
@ -1090,6 +1091,7 @@ void __init sanity_check_meminfo(void)
pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n", pr_notice("Ignoring RAM at %pa-%pa (!CONFIG_HIGHMEM)\n",
&block_start, &block_end); &block_start, &block_end);
memblock_remove(reg->base, reg->size); memblock_remove(reg->base, reg->size);
should_use_highmem = true;
continue; continue;
} }
@ -1100,6 +1102,7 @@ void __init sanity_check_meminfo(void)
&block_start, &block_end, &vmalloc_limit); &block_start, &block_end, &vmalloc_limit);
memblock_remove(vmalloc_limit, overlap_size); memblock_remove(vmalloc_limit, overlap_size);
block_end = vmalloc_limit; block_end = vmalloc_limit;
should_use_highmem = true;
} }
} }
@ -1134,6 +1137,9 @@ void __init sanity_check_meminfo(void)
} }
} }
if (should_use_highmem)
pr_notice("Consider using a HIGHMEM enabled kernel.\n");
high_memory = __va(arm_lowmem_limit - 1) + 1; high_memory = __va(arm_lowmem_limit - 1) + 1;
/* /*
@ -1494,6 +1500,7 @@ void __init paging_init(const struct machine_desc *mdesc)
build_mem_type_table(); build_mem_type_table();
prepare_page_table(); prepare_page_table();
map_lowmem(); map_lowmem();
memblock_set_current_limit(arm_lowmem_limit);
dma_contiguous_remap(); dma_contiguous_remap();
devicemaps_init(mdesc); devicemaps_init(mdesc);
kmap_init(); kmap_init();

View File

@ -351,30 +351,43 @@ void __iomem *__arm_ioremap_pfn(unsigned long pfn, unsigned long offset,
} }
EXPORT_SYMBOL(__arm_ioremap_pfn); EXPORT_SYMBOL(__arm_ioremap_pfn);
void __iomem *__arm_ioremap_pfn_caller(unsigned long pfn, unsigned long offset,
size_t size, unsigned int mtype, void *caller)
{
return __arm_ioremap_pfn(pfn, offset, size, mtype);
}
void __iomem *__arm_ioremap(phys_addr_t phys_addr, size_t size,
unsigned int mtype)
{
return (void __iomem *)phys_addr;
}
EXPORT_SYMBOL(__arm_ioremap);
void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, unsigned int, void *);
void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size, void __iomem *__arm_ioremap_caller(phys_addr_t phys_addr, size_t size,
unsigned int mtype, void *caller) unsigned int mtype, void *caller)
{ {
return __arm_ioremap(phys_addr, size, mtype); return (void __iomem *)phys_addr;
} }
void __iomem * (*arch_ioremap_caller)(phys_addr_t, size_t, unsigned int, void *);
void __iomem *ioremap(resource_size_t res_cookie, size_t size)
{
return __arm_ioremap_caller(res_cookie, size, MT_DEVICE,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap);
void __iomem *ioremap_cache(resource_size_t res_cookie, size_t size)
{
return __arm_ioremap_caller(res_cookie, size, MT_DEVICE_CACHED,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_cache);
void __iomem *ioremap_wc(resource_size_t res_cookie, size_t size)
{
return __arm_ioremap_caller(res_cookie, size, MT_DEVICE_WC,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_wc);
void __iounmap(volatile void __iomem *addr)
{
}
EXPORT_SYMBOL(__iounmap);
void (*arch_iounmap)(volatile void __iomem *); void (*arch_iounmap)(volatile void __iomem *);
void __arm_iounmap(volatile void __iomem *addr) void iounmap(volatile void __iomem *addr)
{ {
} }
EXPORT_SYMBOL(__arm_iounmap); EXPORT_SYMBOL(iounmap);

View File

@ -45,13 +45,11 @@
* it does. * it does.
*/ */
#define _GNU_SOURCE
#include <byteswap.h> #include <byteswap.h>
#include <elf.h> #include <elf.h>
#include <errno.h> #include <errno.h>
#include <error.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -82,11 +80,25 @@
#define EF_ARM_ABI_FLOAT_HARD 0x400 #define EF_ARM_ABI_FLOAT_HARD 0x400
#endif #endif
static int failed;
static const char *argv0;
static const char *outfile; static const char *outfile;
static void fail(const char *fmt, ...)
{
va_list ap;
failed = 1;
fprintf(stderr, "%s: ", argv0);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
static void cleanup(void) static void cleanup(void)
{ {
if (error_message_count > 0 && outfile != NULL) if (failed && outfile != NULL)
unlink(outfile); unlink(outfile);
} }
@ -119,68 +131,66 @@ int main(int argc, char **argv)
int infd; int infd;
atexit(cleanup); atexit(cleanup);
argv0 = argv[0];
if (argc != 3) if (argc != 3)
error(EXIT_FAILURE, 0, "Usage: %s [infile] [outfile]", argv[0]); fail("Usage: %s [infile] [outfile]\n", argv[0]);
infile = argv[1]; infile = argv[1];
outfile = argv[2]; outfile = argv[2];
infd = open(infile, O_RDONLY); infd = open(infile, O_RDONLY);
if (infd < 0) if (infd < 0)
error(EXIT_FAILURE, errno, "Cannot open %s", infile); fail("Cannot open %s: %s\n", infile, strerror(errno));
if (fstat(infd, &stat) != 0) if (fstat(infd, &stat) != 0)
error(EXIT_FAILURE, errno, "Failed stat for %s", infile); fail("Failed stat for %s: %s\n", infile, strerror(errno));
inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0); inbuf = mmap(NULL, stat.st_size, PROT_READ, MAP_PRIVATE, infd, 0);
if (inbuf == MAP_FAILED) if (inbuf == MAP_FAILED)
error(EXIT_FAILURE, errno, "Failed to map %s", infile); fail("Failed to map %s: %s\n", infile, strerror(errno));
close(infd); close(infd);
inhdr = inbuf; inhdr = inbuf;
if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0) if (memcmp(&inhdr->e_ident, ELFMAG, SELFMAG) != 0)
error(EXIT_FAILURE, 0, "Not an ELF file"); fail("Not an ELF file\n");
if (inhdr->e_ident[EI_CLASS] != ELFCLASS32) if (inhdr->e_ident[EI_CLASS] != ELFCLASS32)
error(EXIT_FAILURE, 0, "Unsupported ELF class"); fail("Unsupported ELF class\n");
swap = inhdr->e_ident[EI_DATA] != HOST_ORDER; swap = inhdr->e_ident[EI_DATA] != HOST_ORDER;
if (read_elf_half(inhdr->e_type, swap) != ET_DYN) if (read_elf_half(inhdr->e_type, swap) != ET_DYN)
error(EXIT_FAILURE, 0, "Not a shared object"); fail("Not a shared object\n");
if (read_elf_half(inhdr->e_machine, swap) != EM_ARM) { if (read_elf_half(inhdr->e_machine, swap) != EM_ARM)
error(EXIT_FAILURE, 0, "Unsupported architecture %#x", fail("Unsupported architecture %#x\n", inhdr->e_machine);
inhdr->e_machine);
}
e_flags = read_elf_word(inhdr->e_flags, swap); e_flags = read_elf_word(inhdr->e_flags, swap);
if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) { if (EF_ARM_EABI_VERSION(e_flags) != EF_ARM_EABI_VER5) {
error(EXIT_FAILURE, 0, "Unsupported EABI version %#x", fail("Unsupported EABI version %#x\n",
EF_ARM_EABI_VERSION(e_flags)); EF_ARM_EABI_VERSION(e_flags));
} }
if (e_flags & EF_ARM_ABI_FLOAT_HARD) if (e_flags & EF_ARM_ABI_FLOAT_HARD)
error(EXIT_FAILURE, 0, fail("Unexpected hard-float flag set in e_flags\n");
"Unexpected hard-float flag set in e_flags");
clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT); clear_soft_float = !!(e_flags & EF_ARM_ABI_FLOAT_SOFT);
outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); outfd = open(outfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
if (outfd < 0) if (outfd < 0)
error(EXIT_FAILURE, errno, "Cannot open %s", outfile); fail("Cannot open %s: %s\n", outfile, strerror(errno));
if (ftruncate(outfd, stat.st_size) != 0) if (ftruncate(outfd, stat.st_size) != 0)
error(EXIT_FAILURE, errno, "Cannot truncate %s", outfile); fail("Cannot truncate %s: %s\n", outfile, strerror(errno));
outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, outbuf = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,
outfd, 0); outfd, 0);
if (outbuf == MAP_FAILED) if (outbuf == MAP_FAILED)
error(EXIT_FAILURE, errno, "Failed to map %s", outfile); fail("Failed to map %s: %s\n", outfile, strerror(errno));
close(outfd); close(outfd);
@ -195,7 +205,7 @@ int main(int argc, char **argv)
} }
if (msync(outbuf, stat.st_size, MS_SYNC) != 0) if (msync(outbuf, stat.st_size, MS_SYNC) != 0)
error(EXIT_FAILURE, errno, "Failed to sync %s", outfile); fail("Failed to sync %s: %s\n", outfile, strerror(errno));
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -23,9 +23,9 @@ config ARM64
select BUILDTIME_EXTABLE_SORT select BUILDTIME_EXTABLE_SORT
select CLONE_BACKWARDS select CLONE_BACKWARDS
select COMMON_CLK select COMMON_CLK
select EDAC_SUPPORT
select CPU_PM if (SUSPEND || CPU_IDLE) select CPU_PM if (SUSPEND || CPU_IDLE)
select DCACHE_WORD_ACCESS select DCACHE_WORD_ACCESS
select EDAC_SUPPORT
select GENERIC_ALLOCATOR select GENERIC_ALLOCATOR
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select GENERIC_CLOCKEVENTS_BROADCAST if SMP select GENERIC_CLOCKEVENTS_BROADCAST if SMP

View File

@ -83,6 +83,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y CONFIG_ATA=y
CONFIG_SATA_AHCI=y CONFIG_SATA_AHCI=y
CONFIG_SATA_AHCI_PLATFORM=y CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_AHCI_CEVA=y
CONFIG_AHCI_XGENE=y CONFIG_AHCI_XGENE=y
CONFIG_PATA_PLATFORM=y CONFIG_PATA_PLATFORM=y
CONFIG_PATA_OF_PLATFORM=y CONFIG_PATA_OF_PLATFORM=y

View File

@ -19,6 +19,14 @@
#include <asm/psci.h> #include <asm/psci.h>
#include <asm/smp_plat.h> #include <asm/smp_plat.h>
/* Macros for consistency checks of the GICC subtable of MADT */
#define ACPI_MADT_GICC_LENGTH \
(acpi_gbl_FADT.header.revision < 6 ? 76 : 80)
#define BAD_MADT_GICC_ENTRY(entry, end) \
(!(entry) || (unsigned long)(entry) + sizeof(*(entry)) > (end) || \
(entry)->header.length != ACPI_MADT_GICC_LENGTH)
/* Basic configuration for ACPI */ /* Basic configuration for ACPI */
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
/* ACPI table mapping after acpi_gbl_permanent_mmap is set */ /* ACPI table mapping after acpi_gbl_permanent_mmap is set */

View File

@ -352,8 +352,8 @@ el1_inv:
// TODO: add support for undefined instructions in kernel mode // TODO: add support for undefined instructions in kernel mode
enable_dbg enable_dbg
mov x0, sp mov x0, sp
mov x2, x1
mov x1, #BAD_SYNC mov x1, #BAD_SYNC
mrs x2, esr_el1
b bad_mode b bad_mode
ENDPROC(el1_sync) ENDPROC(el1_sync)
@ -553,7 +553,7 @@ el0_inv:
ct_user_exit ct_user_exit
mov x0, sp mov x0, sp
mov x1, #BAD_SYNC mov x1, #BAD_SYNC
mrs x2, esr_el1 mov x2, x25
bl bad_mode bl bad_mode
b ret_to_user b ret_to_user
ENDPROC(el0_sync) ENDPROC(el0_sync)

View File

@ -32,13 +32,11 @@
ENTRY(compat_sys_sigreturn_wrapper) ENTRY(compat_sys_sigreturn_wrapper)
mov x0, sp mov x0, sp
mov x27, #0 // prevent syscall restart handling (why)
b compat_sys_sigreturn b compat_sys_sigreturn
ENDPROC(compat_sys_sigreturn_wrapper) ENDPROC(compat_sys_sigreturn_wrapper)
ENTRY(compat_sys_rt_sigreturn_wrapper) ENTRY(compat_sys_rt_sigreturn_wrapper)
mov x0, sp mov x0, sp
mov x27, #0 // prevent syscall restart handling (why)
b compat_sys_rt_sigreturn b compat_sys_rt_sigreturn
ENDPROC(compat_sys_rt_sigreturn_wrapper) ENDPROC(compat_sys_rt_sigreturn_wrapper)

View File

@ -438,7 +438,7 @@ acpi_parse_gic_cpu_interface(struct acpi_subtable_header *header,
struct acpi_madt_generic_interrupt *processor; struct acpi_madt_generic_interrupt *processor;
processor = (struct acpi_madt_generic_interrupt *)header; processor = (struct acpi_madt_generic_interrupt *)header;
if (BAD_MADT_ENTRY(processor, end)) if (BAD_MADT_GICC_ENTRY(processor, end))
return -EINVAL; return -EINVAL;
acpi_table_print_madt_entry(header); acpi_table_print_madt_entry(header);

View File

@ -4,5 +4,3 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
context.o proc.o pageattr.o context.o proc.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
obj-$(CONFIG_ARM64_PTDUMP) += dump.o obj-$(CONFIG_ARM64_PTDUMP) += dump.o
CFLAGS_mmu.o := -I$(srctree)/scripts/dtc/libfdt/

View File

@ -1464,7 +1464,7 @@ static inline void handle_rx_packet(struct sync_port *port)
if (port->write_ts_idx == NBR_IN_DESCR) if (port->write_ts_idx == NBR_IN_DESCR)
port->write_ts_idx = 0; port->write_ts_idx = 0;
idx = port->write_ts_idx++; idx = port->write_ts_idx++;
do_posix_clock_monotonic_gettime(&port->timestamp[idx]); ktime_get_ts(&port->timestamp[idx]);
port->in_buffer_len += port->inbufchunk; port->in_buffer_len += port->inbufchunk;
} }
spin_unlock_irqrestore(&port->lock, flags); spin_unlock_irqrestore(&port->lock, flags);

View File

@ -2231,7 +2231,7 @@ config MIPS_CMP
config MIPS_CPS config MIPS_CPS
bool "MIPS Coherent Processing System support" bool "MIPS Coherent Processing System support"
depends on SYS_SUPPORTS_MIPS_CPS && !64BIT depends on SYS_SUPPORTS_MIPS_CPS
select MIPS_CM select MIPS_CM
select MIPS_CPC select MIPS_CPC
select MIPS_CPS_PM if HOTPLUG_CPU select MIPS_CPS_PM if HOTPLUG_CPU

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2010 Loongson Inc. & Lemote Inc. & * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
* Insititute of Computing Technology * Institute of Computing Technology
* Author: Xiang Gao, gaoxiang@ict.ac.cn * Author: Xiang Gao, gaoxiang@ict.ac.cn
* Huacai Chen, chenhc@lemote.com * Huacai Chen, chenhc@lemote.com
* Xiaofu Meng, Shuangshuang Zhang * Xiaofu Meng, Shuangshuang Zhang

View File

@ -23,6 +23,7 @@
extern int smp_num_siblings; extern int smp_num_siblings;
extern cpumask_t cpu_sibling_map[]; extern cpumask_t cpu_sibling_map[];
extern cpumask_t cpu_core_map[]; extern cpumask_t cpu_core_map[];
extern cpumask_t cpu_foreign_map;
#define raw_smp_processor_id() (current_thread_info()->cpu) #define raw_smp_processor_id() (current_thread_info()->cpu)

View File

@ -600,7 +600,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
break; break;
case blezl_op: /* not really i_format */ case blezl_op: /* not really i_format */
if (NO_R6EMU) if (!insn.i_format.rt && NO_R6EMU)
goto sigill_r6; goto sigill_r6;
case blez_op: case blez_op:
/* /*
@ -635,7 +635,7 @@ int __compute_return_epc_for_insn(struct pt_regs *regs,
break; break;
case bgtzl_op: case bgtzl_op:
if (NO_R6EMU) if (!insn.i_format.rt && NO_R6EMU)
goto sigill_r6; goto sigill_r6;
case bgtz_op: case bgtz_op:
/* /*

View File

@ -60,7 +60,7 @@ LEAF(mips_cps_core_entry)
nop nop
/* This is an NMI */ /* This is an NMI */
la k0, nmi_handler PTR_LA k0, nmi_handler
jr k0 jr k0
nop nop
@ -107,10 +107,10 @@ not_nmi:
mul t1, t1, t0 mul t1, t1, t0
mul t1, t1, t2 mul t1, t1, t2
li a0, KSEG0 li a0, CKSEG0
add a1, a0, t1 PTR_ADD a1, a0, t1
1: cache Index_Store_Tag_I, 0(a0) 1: cache Index_Store_Tag_I, 0(a0)
add a0, a0, t0 PTR_ADD a0, a0, t0
bne a0, a1, 1b bne a0, a1, 1b
nop nop
icache_done: icache_done:
@ -134,12 +134,12 @@ icache_done:
mul t1, t1, t0 mul t1, t1, t0
mul t1, t1, t2 mul t1, t1, t2
li a0, KSEG0 li a0, CKSEG0
addu a1, a0, t1 PTR_ADDU a1, a0, t1
subu a1, a1, t0 PTR_SUBU a1, a1, t0
1: cache Index_Store_Tag_D, 0(a0) 1: cache Index_Store_Tag_D, 0(a0)
bne a0, a1, 1b bne a0, a1, 1b
add a0, a0, t0 PTR_ADD a0, a0, t0
dcache_done: dcache_done:
/* Set Kseg0 CCA to that in s0 */ /* Set Kseg0 CCA to that in s0 */
@ -152,11 +152,11 @@ dcache_done:
/* Enter the coherent domain */ /* Enter the coherent domain */
li t0, 0xff li t0, 0xff
sw t0, GCR_CL_COHERENCE_OFS(v1) PTR_S t0, GCR_CL_COHERENCE_OFS(v1)
ehb ehb
/* Jump to kseg0 */ /* Jump to kseg0 */
la t0, 1f PTR_LA t0, 1f
jr t0 jr t0
nop nop
@ -178,9 +178,9 @@ dcache_done:
nop nop
/* Off we go! */ /* Off we go! */
lw t1, VPEBOOTCFG_PC(v0) PTR_L t1, VPEBOOTCFG_PC(v0)
lw gp, VPEBOOTCFG_GP(v0) PTR_L gp, VPEBOOTCFG_GP(v0)
lw sp, VPEBOOTCFG_SP(v0) PTR_L sp, VPEBOOTCFG_SP(v0)
jr t1 jr t1
nop nop
END(mips_cps_core_entry) END(mips_cps_core_entry)
@ -217,7 +217,7 @@ LEAF(excep_intex)
.org 0x480 .org 0x480
LEAF(excep_ejtag) LEAF(excep_ejtag)
la k0, ejtag_debug_handler PTR_LA k0, ejtag_debug_handler
jr k0 jr k0
nop nop
END(excep_ejtag) END(excep_ejtag)
@ -229,7 +229,7 @@ LEAF(mips_cps_core_init)
nop nop
.set push .set push
.set mips32r2 .set mips64r2
.set mt .set mt
/* Only allow 1 TC per VPE to execute... */ /* Only allow 1 TC per VPE to execute... */
@ -237,7 +237,7 @@ LEAF(mips_cps_core_init)
/* ...and for the moment only 1 VPE */ /* ...and for the moment only 1 VPE */
dvpe dvpe
la t1, 1f PTR_LA t1, 1f
jr.hb t1 jr.hb t1
nop nop
@ -250,25 +250,25 @@ LEAF(mips_cps_core_init)
mfc0 t0, CP0_MVPCONF0 mfc0 t0, CP0_MVPCONF0
srl t0, t0, MVPCONF0_PVPE_SHIFT srl t0, t0, MVPCONF0_PVPE_SHIFT
andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT) andi t0, t0, (MVPCONF0_PVPE >> MVPCONF0_PVPE_SHIFT)
addiu t7, t0, 1 addiu ta3, t0, 1
/* If there's only 1, we're done */ /* If there's only 1, we're done */
beqz t0, 2f beqz t0, 2f
nop nop
/* Loop through each VPE within this core */ /* Loop through each VPE within this core */
li t5, 1 li ta1, 1
1: /* Operate on the appropriate TC */ 1: /* Operate on the appropriate TC */
mtc0 t5, CP0_VPECONTROL mtc0 ta1, CP0_VPECONTROL
ehb ehb
/* Bind TC to VPE (1:1 TC:VPE mapping) */ /* Bind TC to VPE (1:1 TC:VPE mapping) */
mttc0 t5, CP0_TCBIND mttc0 ta1, CP0_TCBIND
/* Set exclusive TC, non-active, master */ /* Set exclusive TC, non-active, master */
li t0, VPECONF0_MVP li t0, VPECONF0_MVP
sll t1, t5, VPECONF0_XTC_SHIFT sll t1, ta1, VPECONF0_XTC_SHIFT
or t0, t0, t1 or t0, t0, t1
mttc0 t0, CP0_VPECONF0 mttc0 t0, CP0_VPECONF0
@ -280,8 +280,8 @@ LEAF(mips_cps_core_init)
mttc0 t0, CP0_TCHALT mttc0 t0, CP0_TCHALT
/* Next VPE */ /* Next VPE */
addiu t5, t5, 1 addiu ta1, ta1, 1
slt t0, t5, t7 slt t0, ta1, ta3
bnez t0, 1b bnez t0, 1b
nop nop
@ -298,19 +298,19 @@ LEAF(mips_cps_core_init)
LEAF(mips_cps_boot_vpes) LEAF(mips_cps_boot_vpes)
/* Retrieve CM base address */ /* Retrieve CM base address */
la t0, mips_cm_base PTR_LA t0, mips_cm_base
lw t0, 0(t0) PTR_L t0, 0(t0)
/* Calculate a pointer to this cores struct core_boot_config */ /* Calculate a pointer to this cores struct core_boot_config */
lw t0, GCR_CL_ID_OFS(t0) PTR_L t0, GCR_CL_ID_OFS(t0)
li t1, COREBOOTCFG_SIZE li t1, COREBOOTCFG_SIZE
mul t0, t0, t1 mul t0, t0, t1
la t1, mips_cps_core_bootcfg PTR_LA t1, mips_cps_core_bootcfg
lw t1, 0(t1) PTR_L t1, 0(t1)
addu t0, t0, t1 PTR_ADDU t0, t0, t1
/* Calculate this VPEs ID. If the core doesn't support MT use 0 */ /* Calculate this VPEs ID. If the core doesn't support MT use 0 */
has_mt t6, 1f has_mt ta2, 1f
li t9, 0 li t9, 0
/* Find the number of VPEs present in the core */ /* Find the number of VPEs present in the core */
@ -334,24 +334,24 @@ LEAF(mips_cps_boot_vpes)
1: /* Calculate a pointer to this VPEs struct vpe_boot_config */ 1: /* Calculate a pointer to this VPEs struct vpe_boot_config */
li t1, VPEBOOTCFG_SIZE li t1, VPEBOOTCFG_SIZE
mul v0, t9, t1 mul v0, t9, t1
lw t7, COREBOOTCFG_VPECONFIG(t0) PTR_L ta3, COREBOOTCFG_VPECONFIG(t0)
addu v0, v0, t7 PTR_ADDU v0, v0, ta3
#ifdef CONFIG_MIPS_MT #ifdef CONFIG_MIPS_MT
/* If the core doesn't support MT then return */ /* If the core doesn't support MT then return */
bnez t6, 1f bnez ta2, 1f
nop nop
jr ra jr ra
nop nop
.set push .set push
.set mips32r2 .set mips64r2
.set mt .set mt
1: /* Enter VPE configuration state */ 1: /* Enter VPE configuration state */
dvpe dvpe
la t1, 1f PTR_LA t1, 1f
jr.hb t1 jr.hb t1
nop nop
1: mfc0 t1, CP0_MVPCONTROL 1: mfc0 t1, CP0_MVPCONTROL
@ -360,12 +360,12 @@ LEAF(mips_cps_boot_vpes)
ehb ehb
/* Loop through each VPE */ /* Loop through each VPE */
lw t6, COREBOOTCFG_VPEMASK(t0) PTR_L ta2, COREBOOTCFG_VPEMASK(t0)
move t8, t6 move t8, ta2
li t5, 0 li ta1, 0
/* Check whether the VPE should be running. If not, skip it */ /* Check whether the VPE should be running. If not, skip it */
1: andi t0, t6, 1 1: andi t0, ta2, 1
beqz t0, 2f beqz t0, 2f
nop nop
@ -373,7 +373,7 @@ LEAF(mips_cps_boot_vpes)
mfc0 t0, CP0_VPECONTROL mfc0 t0, CP0_VPECONTROL
ori t0, t0, VPECONTROL_TARGTC ori t0, t0, VPECONTROL_TARGTC
xori t0, t0, VPECONTROL_TARGTC xori t0, t0, VPECONTROL_TARGTC
or t0, t0, t5 or t0, t0, ta1
mtc0 t0, CP0_VPECONTROL mtc0 t0, CP0_VPECONTROL
ehb ehb
@ -384,8 +384,8 @@ LEAF(mips_cps_boot_vpes)
/* Calculate a pointer to the VPEs struct vpe_boot_config */ /* Calculate a pointer to the VPEs struct vpe_boot_config */
li t0, VPEBOOTCFG_SIZE li t0, VPEBOOTCFG_SIZE
mul t0, t0, t5 mul t0, t0, ta1
addu t0, t0, t7 addu t0, t0, ta3
/* Set the TC restart PC */ /* Set the TC restart PC */
lw t1, VPEBOOTCFG_PC(t0) lw t1, VPEBOOTCFG_PC(t0)
@ -423,9 +423,9 @@ LEAF(mips_cps_boot_vpes)
mttc0 t0, CP0_VPECONF0 mttc0 t0, CP0_VPECONF0
/* Next VPE */ /* Next VPE */
2: srl t6, t6, 1 2: srl ta2, ta2, 1
addiu t5, t5, 1 addiu ta1, ta1, 1
bnez t6, 1b bnez ta2, 1b
nop nop
/* Leave VPE configuration state */ /* Leave VPE configuration state */
@ -445,7 +445,7 @@ LEAF(mips_cps_boot_vpes)
/* This VPE should be offline, halt the TC */ /* This VPE should be offline, halt the TC */
li t0, TCHALT_H li t0, TCHALT_H
mtc0 t0, CP0_TCHALT mtc0 t0, CP0_TCHALT
la t0, 1f PTR_LA t0, 1f
1: jr.hb t0 1: jr.hb t0
nop nop
@ -466,10 +466,10 @@ LEAF(mips_cps_boot_vpes)
.set noat .set noat
lw $1, TI_CPU(gp) lw $1, TI_CPU(gp)
sll $1, $1, LONGLOG sll $1, $1, LONGLOG
la \dest, __per_cpu_offset PTR_LA \dest, __per_cpu_offset
addu $1, $1, \dest addu $1, $1, \dest
lw $1, 0($1) lw $1, 0($1)
la \dest, cps_cpu_state PTR_LA \dest, cps_cpu_state
addu \dest, \dest, $1 addu \dest, \dest, $1
.set pop .set pop
.endm .endm

View File

@ -73,10 +73,11 @@ NESTED(handle_sys, PT_SIZE, sp)
.set noreorder .set noreorder
.set nomacro .set nomacro
1: user_lw(t5, 16(t0)) # argument #5 from usp load_a4: user_lw(t5, 16(t0)) # argument #5 from usp
4: user_lw(t6, 20(t0)) # argument #6 from usp load_a5: user_lw(t6, 20(t0)) # argument #6 from usp
3: user_lw(t7, 24(t0)) # argument #7 from usp load_a6: user_lw(t7, 24(t0)) # argument #7 from usp
2: user_lw(t8, 28(t0)) # argument #8 from usp load_a7: user_lw(t8, 28(t0)) # argument #8 from usp
loads_done:
sw t5, 16(sp) # argument #5 to ksp sw t5, 16(sp) # argument #5 to ksp
sw t6, 20(sp) # argument #6 to ksp sw t6, 20(sp) # argument #6 to ksp
@ -85,10 +86,10 @@ NESTED(handle_sys, PT_SIZE, sp)
.set pop .set pop
.section __ex_table,"a" .section __ex_table,"a"
PTR 1b,bad_stack PTR load_a4, bad_stack_a4
PTR 2b,bad_stack PTR load_a5, bad_stack_a5
PTR 3b,bad_stack PTR load_a6, bad_stack_a6
PTR 4b,bad_stack PTR load_a7, bad_stack_a7
.previous .previous
lw t0, TI_FLAGS($28) # syscall tracing enabled? lw t0, TI_FLAGS($28) # syscall tracing enabled?
@ -153,8 +154,8 @@ syscall_trace_entry:
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
/* /*
* The stackpointer for a call with more than 4 arguments is bad. * Our open-coded access area sanity test for the stack pointer
* We probably should handle this case a bit more drastic. * failed. We probably should handle this case a bit more drastic.
*/ */
bad_stack: bad_stack:
li v0, EFAULT li v0, EFAULT
@ -163,6 +164,22 @@ bad_stack:
sw t0, PT_R7(sp) sw t0, PT_R7(sp)
j o32_syscall_exit j o32_syscall_exit
bad_stack_a4:
li t5, 0
b load_a5
bad_stack_a5:
li t6, 0
b load_a6
bad_stack_a6:
li t7, 0
b load_a7
bad_stack_a7:
li t8, 0
b loads_done
/* /*
* The system call does not exist in this kernel * The system call does not exist in this kernel
*/ */

View File

@ -69,16 +69,17 @@ NESTED(handle_sys, PT_SIZE, sp)
daddu t1, t0, 32 daddu t1, t0, 32
bltz t1, bad_stack bltz t1, bad_stack
1: lw a4, 16(t0) # argument #5 from usp load_a4: lw a4, 16(t0) # argument #5 from usp
2: lw a5, 20(t0) # argument #6 from usp load_a5: lw a5, 20(t0) # argument #6 from usp
3: lw a6, 24(t0) # argument #7 from usp load_a6: lw a6, 24(t0) # argument #7 from usp
4: lw a7, 28(t0) # argument #8 from usp (for indirect syscalls) load_a7: lw a7, 28(t0) # argument #8 from usp
loads_done:
.section __ex_table,"a" .section __ex_table,"a"
PTR 1b, bad_stack PTR load_a4, bad_stack_a4
PTR 2b, bad_stack PTR load_a5, bad_stack_a5
PTR 3b, bad_stack PTR load_a6, bad_stack_a6
PTR 4b, bad_stack PTR load_a7, bad_stack_a7
.previous .previous
li t1, _TIF_WORK_SYSCALL_ENTRY li t1, _TIF_WORK_SYSCALL_ENTRY
@ -167,6 +168,22 @@ bad_stack:
sd t0, PT_R7(sp) sd t0, PT_R7(sp)
j o32_syscall_exit j o32_syscall_exit
bad_stack_a4:
li a4, 0
b load_a5
bad_stack_a5:
li a5, 0
b load_a6
bad_stack_a6:
li a6, 0
b load_a7
bad_stack_a7:
li a7, 0
b loads_done
not_o32_scall: not_o32_scall:
/* /*
* This is not an o32 compatibility syscall, pass it on * This is not an o32 compatibility syscall, pass it on
@ -383,7 +400,7 @@ EXPORT(sys32_call_table)
PTR sys_connect /* 4170 */ PTR sys_connect /* 4170 */
PTR sys_getpeername PTR sys_getpeername
PTR sys_getsockname PTR sys_getsockname
PTR sys_getsockopt PTR compat_sys_getsockopt
PTR sys_listen PTR sys_listen
PTR compat_sys_recv /* 4175 */ PTR compat_sys_recv /* 4175 */
PTR compat_sys_recvfrom PTR compat_sys_recvfrom

View File

@ -337,6 +337,11 @@ static void __init bootmem_init(void)
min_low_pfn = start; min_low_pfn = start;
if (end <= reserved_end) if (end <= reserved_end)
continue; continue;
#ifdef CONFIG_BLK_DEV_INITRD
/* mapstart should be after initrd_end */
if (initrd_end && end <= (unsigned long)PFN_UP(__pa(initrd_end)))
continue;
#endif
if (start >= mapstart) if (start >= mapstart)
continue; continue;
mapstart = max(reserved_end, start); mapstart = max(reserved_end, start);
@ -366,14 +371,6 @@ static void __init bootmem_init(void)
max_low_pfn = PFN_DOWN(HIGHMEM_START); max_low_pfn = PFN_DOWN(HIGHMEM_START);
} }
#ifdef CONFIG_BLK_DEV_INITRD
/*
* mapstart should be after initrd_end
*/
if (initrd_end)
mapstart = max(mapstart, (unsigned long)PFN_UP(__pa(initrd_end)));
#endif
/* /*
* Initialize the boot-time allocator with low memory only. * Initialize the boot-time allocator with low memory only.
*/ */

View File

@ -133,7 +133,7 @@ static void __init cps_prepare_cpus(unsigned int max_cpus)
/* /*
* Patch the start of mips_cps_core_entry to provide: * Patch the start of mips_cps_core_entry to provide:
* *
* v0 = CM base address * v1 = CM base address
* s0 = kseg0 CCA * s0 = kseg0 CCA
*/ */
entry_code = (u32 *)&mips_cps_core_entry; entry_code = (u32 *)&mips_cps_core_entry;
@ -369,7 +369,7 @@ void play_dead(void)
static void wait_for_sibling_halt(void *ptr_cpu) static void wait_for_sibling_halt(void *ptr_cpu)
{ {
unsigned cpu = (unsigned)ptr_cpu; unsigned cpu = (unsigned long)ptr_cpu;
unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]); unsigned vpe_id = cpu_vpe_id(&cpu_data[cpu]);
unsigned halted; unsigned halted;
unsigned long flags; unsigned long flags;
@ -430,7 +430,7 @@ static void cps_cpu_die(unsigned int cpu)
*/ */
err = smp_call_function_single(cpu_death_sibling, err = smp_call_function_single(cpu_death_sibling,
wait_for_sibling_halt, wait_for_sibling_halt,
(void *)cpu, 1); (void *)(unsigned long)cpu, 1);
if (err) if (err)
panic("Failed to call remote sibling CPU\n"); panic("Failed to call remote sibling CPU\n");
} }

View File

@ -63,6 +63,13 @@ EXPORT_SYMBOL(cpu_sibling_map);
cpumask_t cpu_core_map[NR_CPUS] __read_mostly; cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
EXPORT_SYMBOL(cpu_core_map); EXPORT_SYMBOL(cpu_core_map);
/*
* A logcal cpu mask containing only one VPE per core to
* reduce the number of IPIs on large MT systems.
*/
cpumask_t cpu_foreign_map __read_mostly;
EXPORT_SYMBOL(cpu_foreign_map);
/* representing cpus for which sibling maps can be computed */ /* representing cpus for which sibling maps can be computed */
static cpumask_t cpu_sibling_setup_map; static cpumask_t cpu_sibling_setup_map;
@ -103,6 +110,29 @@ static inline void set_cpu_core_map(int cpu)
} }
} }
/*
* Calculate a new cpu_foreign_map mask whenever a
* new cpu appears or disappears.
*/
static inline void calculate_cpu_foreign_map(void)
{
int i, k, core_present;
cpumask_t temp_foreign_map;
/* Re-calculate the mask */
for_each_online_cpu(i) {
core_present = 0;
for_each_cpu(k, &temp_foreign_map)
if (cpu_data[i].package == cpu_data[k].package &&
cpu_data[i].core == cpu_data[k].core)
core_present = 1;
if (!core_present)
cpumask_set_cpu(i, &temp_foreign_map);
}
cpumask_copy(&cpu_foreign_map, &temp_foreign_map);
}
struct plat_smp_ops *mp_ops; struct plat_smp_ops *mp_ops;
EXPORT_SYMBOL(mp_ops); EXPORT_SYMBOL(mp_ops);
@ -146,6 +176,8 @@ asmlinkage void start_secondary(void)
set_cpu_sibling_map(cpu); set_cpu_sibling_map(cpu);
set_cpu_core_map(cpu); set_cpu_core_map(cpu);
calculate_cpu_foreign_map();
cpumask_set_cpu(cpu, &cpu_callin_map); cpumask_set_cpu(cpu, &cpu_callin_map);
synchronise_count_slave(cpu); synchronise_count_slave(cpu);
@ -173,9 +205,18 @@ void __irq_entry smp_call_function_interrupt(void)
static void stop_this_cpu(void *dummy) static void stop_this_cpu(void *dummy)
{ {
/* /*
* Remove this CPU: * Remove this CPU. Be a bit slow here and
* set the bits for every online CPU so we don't miss
* any IPI whilst taking this VPE down.
*/ */
cpumask_copy(&cpu_foreign_map, cpu_online_mask);
/* Make it visible to every other CPU */
smp_mb();
set_cpu_online(smp_processor_id(), false); set_cpu_online(smp_processor_id(), false);
calculate_cpu_foreign_map();
local_irq_disable(); local_irq_disable();
while (1); while (1);
} }
@ -197,6 +238,7 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
mp_ops->prepare_cpus(max_cpus); mp_ops->prepare_cpus(max_cpus);
set_cpu_sibling_map(0); set_cpu_sibling_map(0);
set_cpu_core_map(0); set_cpu_core_map(0);
calculate_cpu_foreign_map();
#ifndef CONFIG_HOTPLUG_CPU #ifndef CONFIG_HOTPLUG_CPU
init_cpu_present(cpu_possible_mask); init_cpu_present(cpu_possible_mask);
#endif #endif

View File

@ -2130,10 +2130,10 @@ void per_cpu_trap_init(bool is_boot_cpu)
BUG_ON(current->mm); BUG_ON(current->mm);
enter_lazy_tlb(&init_mm, current); enter_lazy_tlb(&init_mm, current);
/* Boot CPU's cache setup in setup_arch(). */ /* Boot CPU's cache setup in setup_arch(). */
if (!is_boot_cpu) if (!is_boot_cpu)
cpu_cache_init(); cpu_cache_init();
tlb_init(); tlb_init();
TLBMISS_HANDLER_SETUP(); TLBMISS_HANDLER_SETUP();
} }

View File

@ -3,7 +3,7 @@
* Author: Jun Sun, jsun@mvista.com or jsun@junsun.net * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
* Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org) * Copyright (C) 2000, 2001 Ralf Baechle (ralf@gnu.org)
* *
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Fuxin Zhang, zhangfx@lemote.com * Author: Fuxin Zhang, zhangfx@lemote.com
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -6,7 +6,7 @@
* Copyright 2003 ICT CAS * Copyright 2003 ICT CAS
* Author: Michael Guo <guoyi@ict.ac.cn> * Author: Michael Guo <guoyi@ict.ac.cn>
* *
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Fuxin Zhang, zhangfx@lemote.com * Author: Fuxin Zhang, zhangfx@lemote.com
* *
* Copyright (C) 2009 Lemote Inc. * Copyright (C) 2009 Lemote Inc.

View File

@ -1,7 +1,7 @@
/* /*
* CS5536 General timer functions * CS5536 General timer functions
* *
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Yanhua, yanh@lemote.com * Author: Yanhua, yanh@lemote.com
* *
* Copyright (C) 2009 Lemote Inc. * Copyright (C) 2009 Lemote Inc.

View File

@ -6,7 +6,7 @@
* Copyright 2003 ICT CAS * Copyright 2003 ICT CAS
* Author: Michael Guo <guoyi@ict.ac.cn> * Author: Michael Guo <guoyi@ict.ac.cn>
* *
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Fuxin Zhang, zhangfx@lemote.com * Author: Fuxin Zhang, zhangfx@lemote.com
* *
* Copyright (C) 2009 Lemote Inc. * Copyright (C) 2009 Lemote Inc.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Fuxin Zhang, zhangfx@lemote.com * Author: Fuxin Zhang, zhangfx@lemote.com
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Fuxin Zhang, zhangfx@lemote.com * Author: Fuxin Zhang, zhangfx@lemote.com
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2007 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2007 Lemote Inc. & Institute of Computing Technology
* Author: Fuxin Zhang, zhangfx@lemote.com * Author: Fuxin Zhang, zhangfx@lemote.com
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology * Copyright (C) 2006 - 2008 Lemote Inc. & Institute of Computing Technology
* Author: Yanhua, yanh@lemote.com * Author: Yanhua, yanh@lemote.com
* *
* This file is subject to the terms and conditions of the GNU General Public * This file is subject to the terms and conditions of the GNU General Public
@ -15,7 +15,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <asm/clock.h> #include <asm/clock.h>
#include <asm/mach-loongson/loongson.h> #include <asm/mach-loongson64/loongson.h>
static LIST_HEAD(clock_list); static LIST_HEAD(clock_list);
static DEFINE_SPINLOCK(clock_lock); static DEFINE_SPINLOCK(clock_lock);

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (C) 2010 Loongson Inc. & Lemote Inc. & * Copyright (C) 2010 Loongson Inc. & Lemote Inc. &
* Insititute of Computing Technology * Institute of Computing Technology
* Author: Xiang Gao, gaoxiang@ict.ac.cn * Author: Xiang Gao, gaoxiang@ict.ac.cn
* Huacai Chen, chenhc@lemote.com * Huacai Chen, chenhc@lemote.com
* Xiaofu Meng, Shuangshuang Zhang * Xiaofu Meng, Shuangshuang Zhang

View File

@ -451,7 +451,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
/* Fall through */ /* Fall through */
case jr_op: case jr_op:
/* For R6, JR already emulated in jalr_op */ /* For R6, JR already emulated in jalr_op */
if (NO_R6EMU && insn.r_format.opcode == jr_op) if (NO_R6EMU && insn.r_format.func == jr_op)
break; break;
*contpc = regs->regs[insn.r_format.rs]; *contpc = regs->regs[insn.r_format.rs];
return 1; return 1;
@ -551,7 +551,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
return 1; return 1;
case blezl_op: case blezl_op:
if (NO_R6EMU) if (!insn.i_format.rt && NO_R6EMU)
break; break;
case blez_op: case blez_op:
@ -588,7 +588,7 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
dec_insn.next_pc_inc; dec_insn.next_pc_inc;
return 1; return 1;
case bgtzl_op: case bgtzl_op:
if (NO_R6EMU) if (!insn.i_format.rt && NO_R6EMU)
break; break;
case bgtz_op: case bgtz_op:
/* /*

View File

@ -37,6 +37,7 @@
#include <asm/cacheflush.h> /* for run_uncached() */ #include <asm/cacheflush.h> /* for run_uncached() */
#include <asm/traps.h> #include <asm/traps.h>
#include <asm/dma-coherence.h> #include <asm/dma-coherence.h>
#include <asm/mips-cm.h>
/* /*
* Special Variant of smp_call_function for use by cache functions: * Special Variant of smp_call_function for use by cache functions:
@ -51,9 +52,16 @@ static inline void r4k_on_each_cpu(void (*func) (void *info), void *info)
{ {
preempt_disable(); preempt_disable();
#ifndef CONFIG_MIPS_MT_SMP /*
smp_call_function(func, info, 1); * The Coherent Manager propagates address-based cache ops to other
#endif * cores but not index-based ops. However, r4k_on_each_cpu is used
* in both cases so there is no easy way to tell what kind of op is
* executed to the other cores. The best we can probably do is
* to restrict that call when a CM is not present because both
* CM-based SMP protocols (CMP & CPS) restrict index-based cache ops.
*/
if (!mips_cm_present())
smp_call_function_many(&cpu_foreign_map, func, info, 1);
func(info); func(info);
preempt_enable(); preempt_enable();
} }
@ -937,7 +945,9 @@ static void b5k_instruction_hazard(void)
} }
static char *way_string[] = { NULL, "direct mapped", "2-way", static char *way_string[] = { NULL, "direct mapped", "2-way",
"3-way", "4-way", "5-way", "6-way", "7-way", "8-way" "3-way", "4-way", "5-way", "6-way", "7-way", "8-way",
"9-way", "10-way", "11-way", "12-way",
"13-way", "14-way", "15-way", "16-way",
}; };
static void probe_pcache(void) static void probe_pcache(void)

View File

@ -119,18 +119,24 @@ void read_persistent_clock(struct timespec *ts)
int get_c0_fdc_int(void) int get_c0_fdc_int(void)
{ {
int mips_cpu_fdc_irq; /*
* Some cores claim the FDC is routable through the GIC, but it doesn't
* actually seem to be connected for those Malta bitstreams.
*/
switch (current_cpu_type()) {
case CPU_INTERAPTIV:
case CPU_PROAPTIV:
return -1;
};
if (cpu_has_veic) if (cpu_has_veic)
mips_cpu_fdc_irq = -1; return -1;
else if (gic_present) else if (gic_present)
mips_cpu_fdc_irq = gic_get_c0_fdc_int(); return gic_get_c0_fdc_int();
else if (cp0_fdc_irq >= 0) else if (cp0_fdc_irq >= 0)
mips_cpu_fdc_irq = MIPS_CPU_IRQ_BASE + cp0_fdc_irq; return MIPS_CPU_IRQ_BASE + cp0_fdc_irq;
else else
mips_cpu_fdc_irq = -1; return -1;
return mips_cpu_fdc_irq;
} }
int get_c0_perfcount_int(void) int get_c0_perfcount_int(void)

View File

@ -63,13 +63,19 @@ void __init plat_mem_setup(void)
plat_setup_iocoherency(); plat_setup_iocoherency();
} }
#define DEFAULT_CPC_BASE_ADDR 0x1bde0000 #define DEFAULT_CPC_BASE_ADDR 0x1bde0000
#define DEFAULT_CDMM_BASE_ADDR 0x1bdd0000
phys_addr_t mips_cpc_default_phys_base(void) phys_addr_t mips_cpc_default_phys_base(void)
{ {
return DEFAULT_CPC_BASE_ADDR; return DEFAULT_CPC_BASE_ADDR;
} }
phys_addr_t mips_cdmm_phys_base(void)
{
return DEFAULT_CDMM_BASE_ADDR;
}
static void __init mips_nmi_setup(void) static void __init mips_nmi_setup(void)
{ {
void *base; void *base;

View File

@ -27,6 +27,11 @@ int get_c0_perfcount_int(void)
return gic_get_c0_perfcount_int(); return gic_get_c0_perfcount_int();
} }
int get_c0_fdc_int(void)
{
return gic_get_c0_fdc_int();
}
void __init plat_time_init(void) void __init plat_time_init(void)
{ {
struct device_node *np; struct device_node *np;

View File

@ -16,7 +16,7 @@
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/cache.h> #include <asm/cache.h>
extern spinlock_t pa_dbit_lock; extern spinlock_t pa_tlb_lock;
/* /*
* kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
@ -33,6 +33,19 @@ extern spinlock_t pa_dbit_lock;
*/ */
#define kern_addr_valid(addr) (1) #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.
*/
static inline void purge_tlb_entries(struct mm_struct *mm, unsigned long addr)
{
mtsp(mm->context, 1);
pdtlb(addr);
if (unlikely(split_tlb))
pitlb(addr);
}
/* Certain architectures need to do special things when PTEs /* Certain architectures need to do special things when PTEs
* within a page table are directly modified. Thus, the following * within a page table are directly modified. Thus, the following
* hook is made available. * hook is made available.
@ -42,15 +55,20 @@ extern spinlock_t pa_dbit_lock;
*(pteptr) = (pteval); \ *(pteptr) = (pteval); \
} while(0) } while(0)
extern void purge_tlb_entries(struct mm_struct *, unsigned long); #define pte_inserted(x) \
((pte_val(x) & (_PAGE_PRESENT|_PAGE_ACCESSED)) \
== (_PAGE_PRESENT|_PAGE_ACCESSED))
#define set_pte_at(mm, addr, ptep, pteval) \ #define set_pte_at(mm, addr, ptep, pteval) \
do { \ do { \
pte_t old_pte; \
unsigned long flags; \ unsigned long flags; \
spin_lock_irqsave(&pa_dbit_lock, flags); \ spin_lock_irqsave(&pa_tlb_lock, flags); \
set_pte(ptep, pteval); \ old_pte = *ptep; \
purge_tlb_entries(mm, addr); \ set_pte(ptep, pteval); \
spin_unlock_irqrestore(&pa_dbit_lock, flags); \ if (pte_inserted(old_pte)) \
purge_tlb_entries(mm, addr); \
spin_unlock_irqrestore(&pa_tlb_lock, flags); \
} while (0) } while (0)
#endif /* !__ASSEMBLY__ */ #endif /* !__ASSEMBLY__ */
@ -268,7 +286,7 @@ extern unsigned long *empty_zero_page;
#define pte_none(x) (pte_val(x) == 0) #define pte_none(x) (pte_val(x) == 0)
#define pte_present(x) (pte_val(x) & _PAGE_PRESENT) #define pte_present(x) (pte_val(x) & _PAGE_PRESENT)
#define pte_clear(mm,addr,xp) do { pte_val(*(xp)) = 0; } while (0) #define pte_clear(mm, addr, xp) set_pte_at(mm, addr, xp, __pte(0))
#define pmd_flag(x) (pmd_val(x) & PxD_FLAG_MASK) #define pmd_flag(x) (pmd_val(x) & PxD_FLAG_MASK)
#define pmd_address(x) ((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT) #define pmd_address(x) ((unsigned long)(pmd_val(x) &~ PxD_FLAG_MASK) << PxD_VALUE_SHIFT)
@ -435,15 +453,15 @@ static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned
if (!pte_young(*ptep)) if (!pte_young(*ptep))
return 0; return 0;
spin_lock_irqsave(&pa_dbit_lock, flags); spin_lock_irqsave(&pa_tlb_lock, flags);
pte = *ptep; pte = *ptep;
if (!pte_young(pte)) { if (!pte_young(pte)) {
spin_unlock_irqrestore(&pa_dbit_lock, flags); spin_unlock_irqrestore(&pa_tlb_lock, flags);
return 0; return 0;
} }
set_pte(ptep, pte_mkold(pte)); set_pte(ptep, pte_mkold(pte));
purge_tlb_entries(vma->vm_mm, addr); purge_tlb_entries(vma->vm_mm, addr);
spin_unlock_irqrestore(&pa_dbit_lock, flags); spin_unlock_irqrestore(&pa_tlb_lock, flags);
return 1; return 1;
} }
@ -453,11 +471,12 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
pte_t old_pte; pte_t old_pte;
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pa_dbit_lock, flags); spin_lock_irqsave(&pa_tlb_lock, flags);
old_pte = *ptep; old_pte = *ptep;
pte_clear(mm,addr,ptep); set_pte(ptep, __pte(0));
purge_tlb_entries(mm, addr); if (pte_inserted(old_pte))
spin_unlock_irqrestore(&pa_dbit_lock, flags); purge_tlb_entries(mm, addr);
spin_unlock_irqrestore(&pa_tlb_lock, flags);
return old_pte; return old_pte;
} }
@ -465,10 +484,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) static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{ {
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&pa_dbit_lock, flags); spin_lock_irqsave(&pa_tlb_lock, flags);
set_pte(ptep, pte_wrprotect(*ptep)); set_pte(ptep, pte_wrprotect(*ptep));
purge_tlb_entries(mm, addr); purge_tlb_entries(mm, addr);
spin_unlock_irqrestore(&pa_dbit_lock, flags); spin_unlock_irqrestore(&pa_tlb_lock, flags);
} }
#define pte_same(A,B) (pte_val(A) == pte_val(B)) #define pte_same(A,B) (pte_val(A) == pte_val(B))

View File

@ -13,6 +13,9 @@
* active at any one time on the Merced bus. This tlb purge * active at any one time on the Merced bus. This tlb purge
* synchronisation is fairly lightweight and harmless so we activate * synchronisation is fairly lightweight and harmless so we activate
* it on all systems not just the N class. * 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; extern spinlock_t pa_tlb_lock;
@ -24,20 +27,24 @@ extern void flush_tlb_all_local(void *);
#define smp_flush_tlb_all() flush_tlb_all() #define smp_flush_tlb_all() flush_tlb_all()
int __flush_tlb_range(unsigned long sid,
unsigned long start, unsigned long end);
#define flush_tlb_range(vma, start, end) \
__flush_tlb_range((vma)->vm_mm->context, start, end)
#define flush_tlb_kernel_range(start, end) \
__flush_tlb_range(0, start, end)
/* /*
* flush_tlb_mm() * flush_tlb_mm()
* *
* XXX This code is NOT valid for HP-UX compatibility processes, * The code to switch to a new context is NOT valid for processes
* (although it will probably work 99% of the time). HP-UX * which play with the space id's. Thus, we have to preserve the
* processes are free to play with the space id's and save them * space and just flush the entire tlb. However, the compilers,
* over long periods of time, etc. so we have to preserve the * dynamic linker, etc, do not manipulate space id's, so there
* space and just flush the entire tlb. We need to check the * could be a significant performance benefit in switching contexts
* personality in order to do that, but the personality is not * and not flushing the whole tlb.
* currently being set correctly.
*
* Of course, Linux processes could do the same thing, but
* we don't support that (and the compilers, dynamic linker,
* etc. do not do that).
*/ */
static inline void flush_tlb_mm(struct mm_struct *mm) static inline void flush_tlb_mm(struct mm_struct *mm)
@ -45,10 +52,18 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
BUG_ON(mm == &init_mm); /* Should never happen */ BUG_ON(mm == &init_mm); /* Should never happen */
#if 1 || defined(CONFIG_SMP) #if 1 || defined(CONFIG_SMP)
/* Except for very small threads, flushing the whole TLB is
* faster than using __flush_tlb_range. The pdtlb and pitlb
* instructions are very slow because of the TLB broadcast.
* It might be faster to do local range flushes on all CPUs
* on PA 2.0 systems.
*/
flush_tlb_all(); flush_tlb_all();
#else #else
/* FIXME: currently broken, causing space id and protection ids /* FIXME: currently broken, causing space id and protection ids
* to go out of sync, resulting in faults on userspace accesses. * to go out of sync, resulting in faults on userspace accesses.
* This approach needs further investigation since running many
* small applications (e.g., GCC testsuite) is faster on HP-UX.
*/ */
if (mm) { if (mm) {
if (mm->context != 0) if (mm->context != 0)
@ -65,22 +80,12 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,
{ {
unsigned long flags, sid; unsigned long flags, sid;
/* For one page, it's not worth testing the split_tlb variable */
mb();
sid = vma->vm_mm->context; sid = vma->vm_mm->context;
purge_tlb_start(flags); purge_tlb_start(flags);
mtsp(sid, 1); mtsp(sid, 1);
pdtlb(addr); pdtlb(addr);
pitlb(addr); if (unlikely(split_tlb))
pitlb(addr);
purge_tlb_end(flags); purge_tlb_end(flags);
} }
void __flush_tlb_range(unsigned long sid,
unsigned long start, unsigned long end);
#define flush_tlb_range(vma,start,end) __flush_tlb_range((vma)->vm_mm->context,start,end)
#define flush_tlb_kernel_range(start, end) __flush_tlb_range(0,start,end)
#endif #endif

View File

@ -342,12 +342,15 @@ EXPORT_SYMBOL(flush_data_cache_local);
EXPORT_SYMBOL(flush_kernel_icache_range_asm); EXPORT_SYMBOL(flush_kernel_icache_range_asm);
#define FLUSH_THRESHOLD 0x80000 /* 0.5MB */ #define FLUSH_THRESHOLD 0x80000 /* 0.5MB */
int parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD; static unsigned long parisc_cache_flush_threshold __read_mostly = FLUSH_THRESHOLD;
#define FLUSH_TLB_THRESHOLD (2*1024*1024) /* 2MB initial TLB threshold */
static unsigned long parisc_tlb_flush_threshold __read_mostly = FLUSH_TLB_THRESHOLD;
void __init parisc_setup_cache_timing(void) void __init parisc_setup_cache_timing(void)
{ {
unsigned long rangetime, alltime; unsigned long rangetime, alltime;
unsigned long size; unsigned long size, start;
alltime = mfctl(16); alltime = mfctl(16);
flush_data_cache(); flush_data_cache();
@ -364,14 +367,43 @@ void __init parisc_setup_cache_timing(void)
/* Racy, but if we see an intermediate value, it's ok too... */ /* Racy, but if we see an intermediate value, it's ok too... */
parisc_cache_flush_threshold = size * alltime / rangetime; parisc_cache_flush_threshold = size * alltime / rangetime;
parisc_cache_flush_threshold = (parisc_cache_flush_threshold + L1_CACHE_BYTES - 1) &~ (L1_CACHE_BYTES - 1); parisc_cache_flush_threshold = L1_CACHE_ALIGN(parisc_cache_flush_threshold);
if (!parisc_cache_flush_threshold) if (!parisc_cache_flush_threshold)
parisc_cache_flush_threshold = FLUSH_THRESHOLD; parisc_cache_flush_threshold = FLUSH_THRESHOLD;
if (parisc_cache_flush_threshold > cache_info.dc_size) if (parisc_cache_flush_threshold > cache_info.dc_size)
parisc_cache_flush_threshold = cache_info.dc_size; parisc_cache_flush_threshold = cache_info.dc_size;
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); printk(KERN_INFO "Setting cache flush threshold to %lu kB\n",
parisc_cache_flush_threshold/1024);
/* calculate TLB flush threshold */
alltime = mfctl(16);
flush_tlb_all();
alltime = mfctl(16) - alltime;
size = PAGE_SIZE;
start = (unsigned long) _text;
rangetime = mfctl(16);
while (start < (unsigned long) _end) {
flush_tlb_kernel_range(start, start + PAGE_SIZE);
start += PAGE_SIZE;
size += PAGE_SIZE;
}
rangetime = mfctl(16) - rangetime;
printk(KERN_DEBUG "Whole TLB flush %lu cycles, flushing %lu bytes %lu cycles\n",
alltime, size, rangetime);
parisc_tlb_flush_threshold = size * alltime / rangetime;
parisc_tlb_flush_threshold *= num_online_cpus();
parisc_tlb_flush_threshold = PAGE_ALIGN(parisc_tlb_flush_threshold);
if (!parisc_tlb_flush_threshold)
parisc_tlb_flush_threshold = FLUSH_TLB_THRESHOLD;
printk(KERN_INFO "Setting TLB flush threshold to %lu kB\n",
parisc_tlb_flush_threshold/1024);
} }
extern void purge_kernel_dcache_page_asm(unsigned long); extern void purge_kernel_dcache_page_asm(unsigned long);
@ -403,48 +435,45 @@ void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
} }
EXPORT_SYMBOL(copy_user_page); EXPORT_SYMBOL(copy_user_page);
void purge_tlb_entries(struct mm_struct *mm, unsigned long addr) /* __flush_tlb_range()
*
* returns 1 if all TLBs were flushed.
*/
int __flush_tlb_range(unsigned long sid, unsigned long start,
unsigned long end)
{ {
unsigned long flags; unsigned long flags, size;
/* Note: purge_tlb_entries can be called at startup with size = (end - start);
no context. */ if (size >= parisc_tlb_flush_threshold) {
purge_tlb_start(flags);
mtsp(mm->context, 1);
pdtlb(addr);
pitlb(addr);
purge_tlb_end(flags);
}
EXPORT_SYMBOL(purge_tlb_entries);
void __flush_tlb_range(unsigned long sid, unsigned long start,
unsigned long end)
{
unsigned long npages;
npages = ((end - (start & PAGE_MASK)) + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
if (npages >= 512) /* 2MB of space: arbitrary, should be tuned */
flush_tlb_all(); flush_tlb_all();
else { return 1;
unsigned long flags; }
/* Purge TLB entries for small ranges using the pdtlb and
pitlb instructions. These instructions execute locally
but cause a purge request to be broadcast to other TLBs. */
if (likely(!split_tlb)) {
while (start < end) {
purge_tlb_start(flags);
mtsp(sid, 1);
pdtlb(start);
purge_tlb_end(flags);
start += PAGE_SIZE;
}
return 0;
}
/* split TLB case */
while (start < end) {
purge_tlb_start(flags); purge_tlb_start(flags);
mtsp(sid, 1); mtsp(sid, 1);
if (split_tlb) { pdtlb(start);
while (npages--) { pitlb(start);
pdtlb(start);
pitlb(start);
start += PAGE_SIZE;
}
} else {
while (npages--) {
pdtlb(start);
start += PAGE_SIZE;
}
}
purge_tlb_end(flags); purge_tlb_end(flags);
start += PAGE_SIZE;
} }
return 0;
} }
static void cacheflush_h_tmp_function(void *dummy) static void cacheflush_h_tmp_function(void *dummy)

View File

@ -45,7 +45,7 @@
.level 2.0 .level 2.0
#endif #endif
.import pa_dbit_lock,data .import pa_tlb_lock,data
/* space_to_prot macro creates a prot id from a space id */ /* space_to_prot macro creates a prot id from a space id */
@ -420,8 +420,8 @@
SHLREG %r9,PxD_VALUE_SHIFT,\pmd SHLREG %r9,PxD_VALUE_SHIFT,\pmd
extru \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index extru \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */ dep %r0,31,PAGE_SHIFT,\pmd /* clear offset */
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd /* pmd is now pte */
LDREG %r0(\pmd),\pte /* pmd is now pte */ LDREG %r0(\pmd),\pte
bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault bb,>=,n \pte,_PAGE_PRESENT_BIT,\fault
.endm .endm
@ -453,57 +453,53 @@
L2_ptep \pgd,\pte,\index,\va,\fault L2_ptep \pgd,\pte,\index,\va,\fault
.endm .endm
/* Acquire pa_dbit_lock lock. */ /* Acquire pa_tlb_lock lock and recheck page is still present. */
.macro dbit_lock spc,tmp,tmp1 .macro tlb_lock spc,ptp,pte,tmp,tmp1,fault
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
cmpib,COND(=),n 0,\spc,2f cmpib,COND(=),n 0,\spc,2f
load32 PA(pa_dbit_lock),\tmp load32 PA(pa_tlb_lock),\tmp
1: LDCW 0(\tmp),\tmp1 1: LDCW 0(\tmp),\tmp1
cmpib,COND(=) 0,\tmp1,1b cmpib,COND(=) 0,\tmp1,1b
nop nop
LDREG 0(\ptp),\pte
bb,<,n \pte,_PAGE_PRESENT_BIT,2f
b \fault
stw \spc,0(\tmp)
2: 2:
#endif #endif
.endm .endm
/* Release pa_dbit_lock lock without reloading lock address. */ /* Release pa_tlb_lock lock without reloading lock address. */
.macro dbit_unlock0 spc,tmp .macro tlb_unlock0 spc,tmp
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
or,COND(=) %r0,\spc,%r0 or,COND(=) %r0,\spc,%r0
stw \spc,0(\tmp) stw \spc,0(\tmp)
#endif #endif
.endm .endm
/* Release pa_dbit_lock lock. */ /* Release pa_tlb_lock lock. */
.macro dbit_unlock1 spc,tmp .macro tlb_unlock1 spc,tmp
#ifdef CONFIG_SMP #ifdef CONFIG_SMP
load32 PA(pa_dbit_lock),\tmp load32 PA(pa_tlb_lock),\tmp
dbit_unlock0 \spc,\tmp tlb_unlock0 \spc,\tmp
#endif #endif
.endm .endm
/* Set the _PAGE_ACCESSED bit of the PTE. Be clever and /* Set the _PAGE_ACCESSED bit of the PTE. Be clever and
* don't needlessly dirty the cache line if it was already set */ * don't needlessly dirty the cache line if it was already set */
.macro update_ptep spc,ptep,pte,tmp,tmp1 .macro update_accessed ptp,pte,tmp,tmp1
#ifdef CONFIG_SMP
or,COND(=) %r0,\spc,%r0
LDREG 0(\ptep),\pte
#endif
ldi _PAGE_ACCESSED,\tmp1 ldi _PAGE_ACCESSED,\tmp1
or \tmp1,\pte,\tmp or \tmp1,\pte,\tmp
and,COND(<>) \tmp1,\pte,%r0 and,COND(<>) \tmp1,\pte,%r0
STREG \tmp,0(\ptep) STREG \tmp,0(\ptp)
.endm .endm
/* Set the dirty bit (and accessed bit). No need to be /* Set the dirty bit (and accessed bit). No need to be
* clever, this is only used from the dirty fault */ * clever, this is only used from the dirty fault */
.macro update_dirty spc,ptep,pte,tmp .macro update_dirty ptp,pte,tmp
#ifdef CONFIG_SMP
or,COND(=) %r0,\spc,%r0
LDREG 0(\ptep),\pte
#endif
ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp ldi _PAGE_ACCESSED|_PAGE_DIRTY,\tmp
or \tmp,\pte,\pte or \tmp,\pte,\pte
STREG \pte,0(\ptep) STREG \pte,0(\ptp)
.endm .endm
/* bitshift difference between a PFN (based on kernel's PAGE_SIZE) /* bitshift difference between a PFN (based on kernel's PAGE_SIZE)
@ -1148,14 +1144,14 @@ dtlb_miss_20w:
L3_ptep ptp,pte,t0,va,dtlb_check_alias_20w L3_ptep ptp,pte,t0,va,dtlb_check_alias_20w
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20w
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
idtlbt pte,prot idtlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1174,14 +1170,14 @@ nadtlb_miss_20w:
L3_ptep ptp,pte,t0,va,nadtlb_check_alias_20w L3_ptep ptp,pte,t0,va,nadtlb_check_alias_20w
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20w
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
idtlbt pte,prot idtlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1202,20 +1198,20 @@ dtlb_miss_11:
L2_ptep ptp,pte,t0,va,dtlb_check_alias_11 L2_ptep ptp,pte,t0,va,dtlb_check_alias_11
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_11
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb_11 spc,pte,prot make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1 mtsp spc,%sr1
idtlba pte,(%sr1,va) idtlba pte,(%sr1,va)
idtlbp prot,(%sr1,va) idtlbp prot,(%sr1,va)
mtsp t0, %sr1 /* Restore sr1 */ mtsp t1, %sr1 /* Restore sr1 */
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1235,21 +1231,20 @@ nadtlb_miss_11:
L2_ptep ptp,pte,t0,va,nadtlb_check_alias_11 L2_ptep ptp,pte,t0,va,nadtlb_check_alias_11
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_11
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb_11 spc,pte,prot make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1 mtsp spc,%sr1
idtlba pte,(%sr1,va) idtlba pte,(%sr1,va)
idtlbp prot,(%sr1,va) idtlbp prot,(%sr1,va)
mtsp t0, %sr1 /* Restore sr1 */ mtsp t1, %sr1 /* Restore sr1 */
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1269,16 +1264,16 @@ dtlb_miss_20:
L2_ptep ptp,pte,t0,va,dtlb_check_alias_20 L2_ptep ptp,pte,t0,va,dtlb_check_alias_20
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,dtlb_check_alias_20
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
f_extend pte,t0 f_extend pte,t1
idtlbt pte,prot idtlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1297,16 +1292,16 @@ nadtlb_miss_20:
L2_ptep ptp,pte,t0,va,nadtlb_check_alias_20 L2_ptep ptp,pte,t0,va,nadtlb_check_alias_20
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,nadtlb_check_alias_20
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
f_extend pte,t0 f_extend pte,t1
idtlbt pte,prot idtlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1406,14 +1401,14 @@ itlb_miss_20w:
L3_ptep ptp,pte,t0,va,itlb_fault L3_ptep ptp,pte,t0,va,itlb_fault
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,itlb_fault
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
iitlbt pte,prot iitlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1430,14 +1425,14 @@ naitlb_miss_20w:
L3_ptep ptp,pte,t0,va,naitlb_check_alias_20w L3_ptep ptp,pte,t0,va,naitlb_check_alias_20w
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20w
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
iitlbt pte,prot iitlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1458,20 +1453,20 @@ itlb_miss_11:
L2_ptep ptp,pte,t0,va,itlb_fault L2_ptep ptp,pte,t0,va,itlb_fault
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,itlb_fault
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb_11 spc,pte,prot make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1 mtsp spc,%sr1
iitlba pte,(%sr1,va) iitlba pte,(%sr1,va)
iitlbp prot,(%sr1,va) iitlbp prot,(%sr1,va)
mtsp t0, %sr1 /* Restore sr1 */ mtsp t1, %sr1 /* Restore sr1 */
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1482,20 +1477,20 @@ naitlb_miss_11:
L2_ptep ptp,pte,t0,va,naitlb_check_alias_11 L2_ptep ptp,pte,t0,va,naitlb_check_alias_11
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_11
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb_11 spc,pte,prot make_insert_tlb_11 spc,pte,prot
mfsp %sr1,t0 /* Save sr1 so we can use it in tlb inserts */ mfsp %sr1,t1 /* Save sr1 so we can use it in tlb inserts */
mtsp spc,%sr1 mtsp spc,%sr1
iitlba pte,(%sr1,va) iitlba pte,(%sr1,va)
iitlbp prot,(%sr1,va) iitlbp prot,(%sr1,va)
mtsp t0, %sr1 /* Restore sr1 */ mtsp t1, %sr1 /* Restore sr1 */
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1516,16 +1511,16 @@ itlb_miss_20:
L2_ptep ptp,pte,t0,va,itlb_fault L2_ptep ptp,pte,t0,va,itlb_fault
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,itlb_fault
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
f_extend pte,t0 f_extend pte,t1
iitlbt pte,prot iitlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1536,16 +1531,16 @@ naitlb_miss_20:
L2_ptep ptp,pte,t0,va,naitlb_check_alias_20 L2_ptep ptp,pte,t0,va,naitlb_check_alias_20
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,naitlb_check_alias_20
update_ptep spc,ptp,pte,t0,t1 update_accessed ptp,pte,t0,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
f_extend pte,t0 f_extend pte,t1
iitlbt pte,prot iitlbt pte,prot
dbit_unlock1 spc,t0
tlb_unlock1 spc,t0
rfir rfir
nop nop
@ -1568,14 +1563,14 @@ dbit_trap_20w:
L3_ptep ptp,pte,t0,va,dbit_fault L3_ptep ptp,pte,t0,va,dbit_fault
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,dbit_fault
update_dirty spc,ptp,pte,t1 update_dirty ptp,pte,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
idtlbt pte,prot idtlbt pte,prot
dbit_unlock0 spc,t0
tlb_unlock0 spc,t0
rfir rfir
nop nop
#else #else
@ -1588,8 +1583,8 @@ dbit_trap_11:
L2_ptep ptp,pte,t0,va,dbit_fault L2_ptep ptp,pte,t0,va,dbit_fault
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,dbit_fault
update_dirty spc,ptp,pte,t1 update_dirty ptp,pte,t1
make_insert_tlb_11 spc,pte,prot make_insert_tlb_11 spc,pte,prot
@ -1600,8 +1595,8 @@ dbit_trap_11:
idtlbp prot,(%sr1,va) idtlbp prot,(%sr1,va)
mtsp t1, %sr1 /* Restore sr1 */ mtsp t1, %sr1 /* Restore sr1 */
dbit_unlock0 spc,t0
tlb_unlock0 spc,t0
rfir rfir
nop nop
@ -1612,16 +1607,16 @@ dbit_trap_20:
L2_ptep ptp,pte,t0,va,dbit_fault L2_ptep ptp,pte,t0,va,dbit_fault
dbit_lock spc,t0,t1 tlb_lock spc,ptp,pte,t0,t1,dbit_fault
update_dirty spc,ptp,pte,t1 update_dirty ptp,pte,t1
make_insert_tlb spc,pte,prot make_insert_tlb spc,pte,prot
f_extend pte,t1 f_extend pte,t1
idtlbt pte,prot idtlbt pte,prot
dbit_unlock0 spc,t0
tlb_unlock0 spc,t0
rfir rfir
nop nop
#endif #endif

View File

@ -43,10 +43,6 @@
#include "../math-emu/math-emu.h" /* for handle_fpe() */ #include "../math-emu/math-emu.h" /* for handle_fpe() */
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
DEFINE_SPINLOCK(pa_dbit_lock);
#endif
static void parisc_show_stack(struct task_struct *task, unsigned long *sp, static void parisc_show_stack(struct task_struct *task, unsigned long *sp,
struct pt_regs *regs); struct pt_regs *regs);

View File

@ -51,6 +51,22 @@
.text .text
/*
* Used by threads when the lock bit of core_idle_state is set.
* Threads will spin in HMT_LOW until the lock bit is cleared.
* r14 - pointer to core_idle_state
* r15 - used to load contents of core_idle_state
*/
core_idle_lock_held:
HMT_LOW
3: lwz r15,0(r14)
andi. r15,r15,PNV_CORE_IDLE_LOCK_BIT
bne 3b
HMT_MEDIUM
lwarx r15,0,r14
blr
/* /*
* Pass requested state in r3: * Pass requested state in r3:
* r3 - PNV_THREAD_NAP/SLEEP/WINKLE * r3 - PNV_THREAD_NAP/SLEEP/WINKLE
@ -150,6 +166,10 @@ power7_enter_nap_mode:
ld r14,PACA_CORE_IDLE_STATE_PTR(r13) ld r14,PACA_CORE_IDLE_STATE_PTR(r13)
lwarx_loop1: lwarx_loop1:
lwarx r15,0,r14 lwarx r15,0,r14
andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
bnel core_idle_lock_held
andc r15,r15,r7 /* Clear thread bit */ andc r15,r15,r7 /* Clear thread bit */
andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS andi. r15,r15,PNV_CORE_IDLE_THREAD_BITS
@ -294,7 +314,7 @@ lwarx_loop2:
* workaround undo code or resyncing timebase or restoring context * workaround undo code or resyncing timebase or restoring context
* In either case loop until the lock bit is cleared. * In either case loop until the lock bit is cleared.
*/ */
bne core_idle_lock_held bnel core_idle_lock_held
cmpwi cr2,r15,0 cmpwi cr2,r15,0
lbz r4,PACA_SUBCORE_SIBLING_MASK(r13) lbz r4,PACA_SUBCORE_SIBLING_MASK(r13)
@ -319,15 +339,6 @@ lwarx_loop2:
isync isync
b common_exit b common_exit
core_idle_lock_held:
HMT_LOW
core_idle_lock_loop:
lwz r15,0(14)
andi. r9,r15,PNV_CORE_IDLE_LOCK_BIT
bne core_idle_lock_loop
HMT_MEDIUM
b lwarx_loop2
first_thread_in_subcore: first_thread_in_subcore:
/* First thread in subcore to wakeup */ /* First thread in subcore to wakeup */
ori r15,r15,PNV_CORE_IDLE_LOCK_BIT ori r15,r15,PNV_CORE_IDLE_LOCK_BIT

View File

@ -297,6 +297,8 @@ long machine_check_early(struct pt_regs *regs)
__this_cpu_inc(irq_stat.mce_exceptions); __this_cpu_inc(irq_stat.mce_exceptions);
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
if (cur_cpu_spec && cur_cpu_spec->machine_check_early) if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
handled = cur_cpu_spec->machine_check_early(regs); handled = cur_cpu_spec->machine_check_early(regs);
return handled; return handled;

View File

@ -529,6 +529,10 @@ void bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
printk(KERN_ALERT "Unable to handle kernel paging request for " printk(KERN_ALERT "Unable to handle kernel paging request for "
"instruction fetch\n"); "instruction fetch\n");
break; break;
case 0x600:
printk(KERN_ALERT "Unable to handle kernel paging request for "
"unaligned access at address 0x%08lx\n", regs->dar);
break;
default: default:
printk(KERN_ALERT "Unable to handle kernel paging request for " printk(KERN_ALERT "Unable to handle kernel paging request for "
"unknown fault\n"); "unknown fault\n");

View File

@ -320,6 +320,8 @@ static struct attribute *device_str_attr_create_(char *name, char *str)
if (!attr) if (!attr)
return NULL; return NULL;
sysfs_attr_init(&attr->attr.attr);
attr->var = str; attr->var = str;
attr->attr.attr.name = name; attr->attr.attr.name = name;
attr->attr.attr.mode = 0444; attr->attr.attr.mode = 0444;

View File

@ -237,7 +237,7 @@ static struct elog_obj *create_elog_obj(uint64_t id, size_t size, uint64_t type)
return elog; return elog;
} }
static void elog_work_fn(struct work_struct *work) static irqreturn_t elog_event(int irq, void *data)
{ {
__be64 size; __be64 size;
__be64 id; __be64 id;
@ -251,7 +251,7 @@ static void elog_work_fn(struct work_struct *work)
rc = opal_get_elog_size(&id, &size, &type); rc = opal_get_elog_size(&id, &size, &type);
if (rc != OPAL_SUCCESS) { if (rc != OPAL_SUCCESS) {
pr_err("ELOG: OPAL log info read failed\n"); pr_err("ELOG: OPAL log info read failed\n");
return; return IRQ_HANDLED;
} }
elog_size = be64_to_cpu(size); elog_size = be64_to_cpu(size);
@ -270,16 +270,10 @@ static void elog_work_fn(struct work_struct *work)
* entries. * entries.
*/ */
if (kset_find_obj(elog_kset, name)) if (kset_find_obj(elog_kset, name))
return; return IRQ_HANDLED;
create_elog_obj(log_id, elog_size, elog_type); create_elog_obj(log_id, elog_size, elog_type);
}
static DECLARE_WORK(elog_work, elog_work_fn);
static irqreturn_t elog_event(int irq, void *data)
{
schedule_work(&elog_work);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -304,8 +298,8 @@ int __init opal_elog_init(void)
return irq; return irq;
} }
rc = request_irq(irq, elog_event, rc = request_threaded_irq(irq, NULL, elog_event,
IRQ_TYPE_LEVEL_HIGH, "opal-elog", NULL); IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "opal-elog", NULL);
if (rc) { if (rc) {
pr_err("%s: Can't request OPAL event irq (%d)\n", pr_err("%s: Can't request OPAL event irq (%d)\n",
__func__, rc); __func__, rc);

View File

@ -112,6 +112,7 @@ static int opal_prd_open(struct inode *inode, struct file *file)
static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma) static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma)
{ {
size_t addr, size; size_t addr, size;
pgprot_t page_prot;
int rc; int rc;
pr_devel("opal_prd_mmap(0x%016lx, 0x%016lx, 0x%lx, 0x%lx)\n", pr_devel("opal_prd_mmap(0x%016lx, 0x%016lx, 0x%lx, 0x%lx)\n",
@ -125,13 +126,11 @@ static int opal_prd_mmap(struct file *file, struct vm_area_struct *vma)
if (!opal_prd_range_is_valid(addr, size)) if (!opal_prd_range_is_valid(addr, size))
return -EINVAL; return -EINVAL;
vma->vm_page_prot = __pgprot(pgprot_val(phys_mem_access_prot(file, page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
vma->vm_pgoff, size, vma->vm_page_prot);
size, vma->vm_page_prot))
| _PAGE_SPECIAL);
rc = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size, rc = remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, size,
vma->vm_page_prot); page_prot);
return rc; return rc;
} }

View File

@ -18,6 +18,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <asm/msi_bitmap.h> #include <asm/msi_bitmap.h>
#include <asm/ppc-pci.h>
struct ppc4xx_hsta_msi { struct ppc4xx_hsta_msi {
struct device *dev; struct device *dev;

View File

@ -28,7 +28,7 @@
#define _ST(p, inst, v) \ #define _ST(p, inst, v) \
({ \ ({ \
asm("1: " #inst " %0, %1;" \ asm("1: " #inst " %0, %1;" \
".pushsection .coldtext.memcpy,\"ax\";" \ ".pushsection .coldtext,\"ax\";" \
"2: { move r0, %2; jrp lr };" \ "2: { move r0, %2; jrp lr };" \
".section __ex_table,\"a\";" \ ".section __ex_table,\"a\";" \
".align 8;" \ ".align 8;" \
@ -41,7 +41,7 @@
({ \ ({ \
unsigned long __v; \ unsigned long __v; \
asm("1: " #inst " %0, %1;" \ asm("1: " #inst " %0, %1;" \
".pushsection .coldtext.memcpy,\"ax\";" \ ".pushsection .coldtext,\"ax\";" \
"2: { move r0, %2; jrp lr };" \ "2: { move r0, %2; jrp lr };" \
".section __ex_table,\"a\";" \ ".section __ex_table,\"a\";" \
".align 8;" \ ".align 8;" \

View File

@ -254,6 +254,11 @@ config ARCH_SUPPORTS_OPTIMIZED_INLINING
config ARCH_SUPPORTS_DEBUG_PAGEALLOC config ARCH_SUPPORTS_DEBUG_PAGEALLOC
def_bool y def_bool y
config KASAN_SHADOW_OFFSET
hex
depends on KASAN
default 0xdffffc0000000000
config HAVE_INTEL_TXT config HAVE_INTEL_TXT
def_bool y def_bool y
depends on INTEL_IOMMU && ACPI depends on INTEL_IOMMU && ACPI
@ -2015,7 +2020,7 @@ config CMDLINE_BOOL
To compile command line arguments into the kernel, To compile command line arguments into the kernel,
set this option to 'Y', then fill in the set this option to 'Y', then fill in the
the boot arguments in CONFIG_CMDLINE. boot arguments in CONFIG_CMDLINE.
Systems with fully functional boot loaders (i.e. non-embedded) Systems with fully functional boot loaders (i.e. non-embedded)
should leave this option set to 'N'. should leave this option set to 'N'.

View File

@ -9,7 +9,7 @@ DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_stack);
DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr); DECLARE_PER_CPU_READ_MOSTLY(unsigned long, espfix_waddr);
extern void init_espfix_bsp(void); extern void init_espfix_bsp(void);
extern void init_espfix_ap(void); extern void init_espfix_ap(int cpu);
#endif /* CONFIG_X86_64 */ #endif /* CONFIG_X86_64 */

View File

@ -14,15 +14,11 @@
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
extern pte_t kasan_zero_pte[];
extern pte_t kasan_zero_pmd[];
extern pte_t kasan_zero_pud[];
#ifdef CONFIG_KASAN #ifdef CONFIG_KASAN
void __init kasan_map_early_shadow(pgd_t *pgd); void __init kasan_early_init(void);
void __init kasan_init(void); void __init kasan_init(void);
#else #else
static inline void kasan_map_early_shadow(pgd_t *pgd) { } static inline void kasan_early_init(void) { }
static inline void kasan_init(void) { } static inline void kasan_init(void) { }
#endif #endif

View File

@ -409,12 +409,6 @@ static void __setup_vector_irq(int cpu)
int irq, vector; int irq, vector;
struct apic_chip_data *data; struct apic_chip_data *data;
/*
* vector_lock will make sure that we don't run into irq vector
* assignments that might be happening on another cpu in parallel,
* while we setup our initial vector to irq mappings.
*/
raw_spin_lock(&vector_lock);
/* Mark the inuse vectors */ /* Mark the inuse vectors */
for_each_active_irq(irq) { for_each_active_irq(irq) {
data = apic_chip_data(irq_get_irq_data(irq)); data = apic_chip_data(irq_get_irq_data(irq));
@ -436,16 +430,16 @@ static void __setup_vector_irq(int cpu)
if (!cpumask_test_cpu(cpu, data->domain)) if (!cpumask_test_cpu(cpu, data->domain))
per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED; per_cpu(vector_irq, cpu)[vector] = VECTOR_UNDEFINED;
} }
raw_spin_unlock(&vector_lock);
} }
/* /*
* Setup the vector to irq mappings. * Setup the vector to irq mappings. Must be called with vector_lock held.
*/ */
void setup_vector_irq(int cpu) void setup_vector_irq(int cpu)
{ {
int irq; int irq;
lockdep_assert_held(&vector_lock);
/* /*
* On most of the platforms, legacy PIC delivers the interrupts on the * On most of the platforms, legacy PIC delivers the interrupts on the
* boot cpu. But there are certain platforms where PIC interrupts are * boot cpu. But there are certain platforms where PIC interrupts are

View File

@ -175,7 +175,9 @@ static __init void early_serial_init(char *s)
} }
if (*s) { if (*s) {
if (kstrtoul(s, 0, &baud) < 0 || baud == 0) baud = simple_strtoull(s, &e, 0);
if (baud == 0 || s == e)
baud = DEFAULT_BAUD; baud = DEFAULT_BAUD;
} }

View File

@ -131,25 +131,24 @@ void __init init_espfix_bsp(void)
init_espfix_random(); init_espfix_random();
/* The rest is the same as for any other processor */ /* The rest is the same as for any other processor */
init_espfix_ap(); init_espfix_ap(0);
} }
void init_espfix_ap(void) void init_espfix_ap(int cpu)
{ {
unsigned int cpu, page; unsigned int page;
unsigned long addr; unsigned long addr;
pud_t pud, *pud_p; pud_t pud, *pud_p;
pmd_t pmd, *pmd_p; pmd_t pmd, *pmd_p;
pte_t pte, *pte_p; pte_t pte, *pte_p;
int n; int n, node;
void *stack_page; void *stack_page;
pteval_t ptemask; pteval_t ptemask;
/* We only have to do this once... */ /* We only have to do this once... */
if (likely(this_cpu_read(espfix_stack))) if (likely(per_cpu(espfix_stack, cpu)))
return; /* Already initialized */ return; /* Already initialized */
cpu = smp_processor_id();
addr = espfix_base_addr(cpu); addr = espfix_base_addr(cpu);
page = cpu/ESPFIX_STACKS_PER_PAGE; page = cpu/ESPFIX_STACKS_PER_PAGE;
@ -165,12 +164,15 @@ void init_espfix_ap(void)
if (stack_page) if (stack_page)
goto unlock_done; goto unlock_done;
node = cpu_to_node(cpu);
ptemask = __supported_pte_mask; ptemask = __supported_pte_mask;
pud_p = &espfix_pud_page[pud_index(addr)]; pud_p = &espfix_pud_page[pud_index(addr)];
pud = *pud_p; pud = *pud_p;
if (!pud_present(pud)) { if (!pud_present(pud)) {
pmd_p = (pmd_t *)__get_free_page(PGALLOC_GFP); struct page *page = alloc_pages_node(node, PGALLOC_GFP, 0);
pmd_p = (pmd_t *)page_address(page);
pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask)); pud = __pud(__pa(pmd_p) | (PGTABLE_PROT & ptemask));
paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT); paravirt_alloc_pmd(&init_mm, __pa(pmd_p) >> PAGE_SHIFT);
for (n = 0; n < ESPFIX_PUD_CLONES; n++) for (n = 0; n < ESPFIX_PUD_CLONES; n++)
@ -180,7 +182,9 @@ void init_espfix_ap(void)
pmd_p = pmd_offset(&pud, addr); pmd_p = pmd_offset(&pud, addr);
pmd = *pmd_p; pmd = *pmd_p;
if (!pmd_present(pmd)) { if (!pmd_present(pmd)) {
pte_p = (pte_t *)__get_free_page(PGALLOC_GFP); struct page *page = alloc_pages_node(node, PGALLOC_GFP, 0);
pte_p = (pte_t *)page_address(page);
pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask)); pmd = __pmd(__pa(pte_p) | (PGTABLE_PROT & ptemask));
paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT); paravirt_alloc_pte(&init_mm, __pa(pte_p) >> PAGE_SHIFT);
for (n = 0; n < ESPFIX_PMD_CLONES; n++) for (n = 0; n < ESPFIX_PMD_CLONES; n++)
@ -188,7 +192,7 @@ void init_espfix_ap(void)
} }
pte_p = pte_offset_kernel(&pmd, addr); pte_p = pte_offset_kernel(&pmd, addr);
stack_page = (void *)__get_free_page(GFP_KERNEL); stack_page = page_address(alloc_pages_node(node, GFP_KERNEL, 0));
pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask)); pte = __pte(__pa(stack_page) | (__PAGE_KERNEL_RO & ptemask));
for (n = 0; n < ESPFIX_PTE_CLONES; n++) for (n = 0; n < ESPFIX_PTE_CLONES; n++)
set_pte(&pte_p[n*PTE_STRIDE], pte); set_pte(&pte_p[n*PTE_STRIDE], pte);
@ -199,7 +203,7 @@ void init_espfix_ap(void)
unlock_done: unlock_done:
mutex_unlock(&espfix_init_mutex); mutex_unlock(&espfix_init_mutex);
done: done:
this_cpu_write(espfix_stack, addr); per_cpu(espfix_stack, cpu) = addr;
this_cpu_write(espfix_waddr, (unsigned long)stack_page per_cpu(espfix_waddr, cpu) = (unsigned long)stack_page
+ (addr & ~PAGE_MASK)); + (addr & ~PAGE_MASK);
} }

View File

@ -161,11 +161,12 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
/* Kill off the identity-map trampoline */ /* Kill off the identity-map trampoline */
reset_early_page_tables(); reset_early_page_tables();
kasan_map_early_shadow(early_level4_pgt);
/* clear bss before set_intr_gate with early_idt_handler */
clear_bss(); clear_bss();
clear_page(init_level4_pgt);
kasan_early_init();
for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
set_intr_gate(i, early_idt_handler_array[i]); set_intr_gate(i, early_idt_handler_array[i]);
load_idt((const struct desc_ptr *)&idt_descr); load_idt((const struct desc_ptr *)&idt_descr);
@ -177,12 +178,9 @@ asmlinkage __visible void __init x86_64_start_kernel(char * real_mode_data)
*/ */
load_ucode_bsp(); load_ucode_bsp();
clear_page(init_level4_pgt);
/* set init_level4_pgt kernel high mapping*/ /* set init_level4_pgt kernel high mapping*/
init_level4_pgt[511] = early_level4_pgt[511]; init_level4_pgt[511] = early_level4_pgt[511];
kasan_map_early_shadow(init_level4_pgt);
x86_64_start_reservations(real_mode_data); x86_64_start_reservations(real_mode_data);
} }

View File

@ -516,38 +516,9 @@ ENTRY(phys_base)
/* This must match the first entry in level2_kernel_pgt */ /* This must match the first entry in level2_kernel_pgt */
.quad 0x0000000000000000 .quad 0x0000000000000000
#ifdef CONFIG_KASAN
#define FILL(VAL, COUNT) \
.rept (COUNT) ; \
.quad (VAL) ; \
.endr
NEXT_PAGE(kasan_zero_pte)
FILL(kasan_zero_page - __START_KERNEL_map + _KERNPG_TABLE, 512)
NEXT_PAGE(kasan_zero_pmd)
FILL(kasan_zero_pte - __START_KERNEL_map + _KERNPG_TABLE, 512)
NEXT_PAGE(kasan_zero_pud)
FILL(kasan_zero_pmd - __START_KERNEL_map + _KERNPG_TABLE, 512)
#undef FILL
#endif
#include "../../x86/xen/xen-head.S" #include "../../x86/xen/xen-head.S"
__PAGE_ALIGNED_BSS __PAGE_ALIGNED_BSS
NEXT_PAGE(empty_zero_page) NEXT_PAGE(empty_zero_page)
.skip PAGE_SIZE .skip PAGE_SIZE
#ifdef CONFIG_KASAN
/*
* This page used as early shadow. We don't use empty_zero_page
* at early stages, stack instrumentation could write some garbage
* to this page.
* Latter we reuse it as zero shadow for large ranges of memory
* that allowed to access, but not instrumented by kasan
* (vmalloc/vmemmap ...).
*/
NEXT_PAGE(kasan_zero_page)
.skip PAGE_SIZE
#endif

View File

@ -347,14 +347,22 @@ int check_irq_vectors_for_cpu_disable(void)
if (!desc) if (!desc)
continue; continue;
/*
* Protect against concurrent action removal,
* affinity changes etc.
*/
raw_spin_lock(&desc->lock);
data = irq_desc_get_irq_data(desc); data = irq_desc_get_irq_data(desc);
cpumask_copy(&affinity_new, data->affinity); cpumask_copy(&affinity_new, data->affinity);
cpumask_clear_cpu(this_cpu, &affinity_new); cpumask_clear_cpu(this_cpu, &affinity_new);
/* Do not count inactive or per-cpu irqs. */ /* Do not count inactive or per-cpu irqs. */
if (!irq_has_action(irq) || irqd_is_per_cpu(data)) if (!irq_has_action(irq) || irqd_is_per_cpu(data)) {
raw_spin_unlock(&desc->lock);
continue; continue;
}
raw_spin_unlock(&desc->lock);
/* /*
* A single irq may be mapped to multiple * A single irq may be mapped to multiple
* cpu's vector_irq[] (for example IOAPIC cluster * cpu's vector_irq[] (for example IOAPIC cluster
@ -385,6 +393,9 @@ int check_irq_vectors_for_cpu_disable(void)
* vector. If the vector is marked in the used vectors * vector. If the vector is marked in the used vectors
* bitmap or an irq is assigned to it, we don't count * bitmap or an irq is assigned to it, we don't count
* it as available. * it as available.
*
* As this is an inaccurate snapshot anyway, we can do
* this w/o holding vector_lock.
*/ */
for (vector = FIRST_EXTERNAL_VECTOR; for (vector = FIRST_EXTERNAL_VECTOR;
vector < first_system_vector; vector++) { vector < first_system_vector; vector++) {
@ -486,6 +497,11 @@ void fixup_irqs(void)
*/ */
mdelay(1); mdelay(1);
/*
* We can walk the vector array of this cpu without holding
* vector_lock because the cpu is already marked !online, so
* nothing else will touch it.
*/
for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) { for (vector = FIRST_EXTERNAL_VECTOR; vector < NR_VECTORS; vector++) {
unsigned int irr; unsigned int irr;
@ -497,9 +513,9 @@ void fixup_irqs(void)
irq = __this_cpu_read(vector_irq[vector]); irq = __this_cpu_read(vector_irq[vector]);
desc = irq_to_desc(irq); desc = irq_to_desc(irq);
raw_spin_lock(&desc->lock);
data = irq_desc_get_irq_data(desc); data = irq_desc_get_irq_data(desc);
chip = irq_data_get_irq_chip(data); chip = irq_data_get_irq_chip(data);
raw_spin_lock(&desc->lock);
if (chip->irq_retrigger) { if (chip->irq_retrigger) {
chip->irq_retrigger(data); chip->irq_retrigger(data);
__this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED); __this_cpu_write(vector_irq[vector], VECTOR_RETRIGGERED);

View File

@ -170,11 +170,6 @@ static void smp_callin(void)
*/ */
apic_ap_setup(); apic_ap_setup();
/*
* Need to setup vector mappings before we enable interrupts.
*/
setup_vector_irq(smp_processor_id());
/* /*
* Save our processor parameters. Note: this information * Save our processor parameters. Note: this information
* is needed for clock calibration. * is needed for clock calibration.
@ -239,18 +234,13 @@ static void notrace start_secondary(void *unused)
check_tsc_sync_target(); check_tsc_sync_target();
/* /*
* Enable the espfix hack for this CPU * Lock vector_lock and initialize the vectors on this cpu
*/ * before setting the cpu online. We must set it online with
#ifdef CONFIG_X86_ESPFIX64 * vector_lock held to prevent a concurrent setup/teardown
init_espfix_ap(); * from seeing a half valid vector space.
#endif
/*
* We need to hold vector_lock so there the set of online cpus
* does not change while we are assigning vectors to cpus. Holding
* this lock ensures we don't half assign or remove an irq from a cpu.
*/ */
lock_vector_lock(); lock_vector_lock();
setup_vector_irq(smp_processor_id());
set_cpu_online(smp_processor_id(), true); set_cpu_online(smp_processor_id(), true);
unlock_vector_lock(); unlock_vector_lock();
cpu_set_state_online(smp_processor_id()); cpu_set_state_online(smp_processor_id());
@ -854,6 +844,13 @@ static int do_boot_cpu(int apicid, int cpu, struct task_struct *idle)
initial_code = (unsigned long)start_secondary; initial_code = (unsigned long)start_secondary;
stack_start = idle->thread.sp; stack_start = idle->thread.sp;
/*
* Enable the espfix hack for this CPU
*/
#ifdef CONFIG_X86_ESPFIX64
init_espfix_ap(cpu);
#endif
/* So we see what's up */ /* So we see what's up */
announce_cpu(cpu, apicid); announce_cpu(cpu, apicid);

View File

@ -598,10 +598,19 @@ static unsigned long quick_pit_calibrate(void)
if (!pit_expect_msb(0xff-i, &delta, &d2)) if (!pit_expect_msb(0xff-i, &delta, &d2))
break; break;
delta -= tsc;
/*
* Extrapolate the error and fail fast if the error will
* never be below 500 ppm.
*/
if (i == 1 &&
d1 + d2 >= (delta * MAX_QUICK_PIT_ITERATIONS) >> 11)
return 0;
/* /*
* Iterate until the error is less than 500 ppm * Iterate until the error is less than 500 ppm
*/ */
delta -= tsc;
if (d1+d2 >= delta >> 11) if (d1+d2 >= delta >> 11)
continue; continue;

View File

@ -20,7 +20,7 @@ copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
unsigned long ret; unsigned long ret;
if (__range_not_ok(from, n, TASK_SIZE)) if (__range_not_ok(from, n, TASK_SIZE))
return 0; return n;
/* /*
* Even though this function is typically called from NMI/IRQ context * Even though this function is typically called from NMI/IRQ context

View File

@ -1,3 +1,4 @@
#define pr_fmt(fmt) "kasan: " fmt
#include <linux/bootmem.h> #include <linux/bootmem.h>
#include <linux/kasan.h> #include <linux/kasan.h>
#include <linux/kdebug.h> #include <linux/kdebug.h>
@ -11,7 +12,19 @@
extern pgd_t early_level4_pgt[PTRS_PER_PGD]; extern pgd_t early_level4_pgt[PTRS_PER_PGD];
extern struct range pfn_mapped[E820_X_MAX]; extern struct range pfn_mapped[E820_X_MAX];
extern unsigned char kasan_zero_page[PAGE_SIZE]; static pud_t kasan_zero_pud[PTRS_PER_PUD] __page_aligned_bss;
static pmd_t kasan_zero_pmd[PTRS_PER_PMD] __page_aligned_bss;
static pte_t kasan_zero_pte[PTRS_PER_PTE] __page_aligned_bss;
/*
* This page used as early shadow. We don't use empty_zero_page
* at early stages, stack instrumentation could write some garbage
* to this page.
* Latter we reuse it as zero shadow for large ranges of memory
* that allowed to access, but not instrumented by kasan
* (vmalloc/vmemmap ...).
*/
static unsigned char kasan_zero_page[PAGE_SIZE] __page_aligned_bss;
static int __init map_range(struct range *range) static int __init map_range(struct range *range)
{ {
@ -36,7 +49,7 @@ static void __init clear_pgds(unsigned long start,
pgd_clear(pgd_offset_k(start)); pgd_clear(pgd_offset_k(start));
} }
void __init kasan_map_early_shadow(pgd_t *pgd) static void __init kasan_map_early_shadow(pgd_t *pgd)
{ {
int i; int i;
unsigned long start = KASAN_SHADOW_START; unsigned long start = KASAN_SHADOW_START;
@ -73,7 +86,7 @@ static int __init zero_pmd_populate(pud_t *pud, unsigned long addr,
while (IS_ALIGNED(addr, PMD_SIZE) && addr + PMD_SIZE <= end) { while (IS_ALIGNED(addr, PMD_SIZE) && addr + PMD_SIZE <= end) {
WARN_ON(!pmd_none(*pmd)); WARN_ON(!pmd_none(*pmd));
set_pmd(pmd, __pmd(__pa_nodebug(kasan_zero_pte) set_pmd(pmd, __pmd(__pa_nodebug(kasan_zero_pte)
| __PAGE_KERNEL_RO)); | _KERNPG_TABLE));
addr += PMD_SIZE; addr += PMD_SIZE;
pmd = pmd_offset(pud, addr); pmd = pmd_offset(pud, addr);
} }
@ -99,7 +112,7 @@ static int __init zero_pud_populate(pgd_t *pgd, unsigned long addr,
while (IS_ALIGNED(addr, PUD_SIZE) && addr + PUD_SIZE <= end) { while (IS_ALIGNED(addr, PUD_SIZE) && addr + PUD_SIZE <= end) {
WARN_ON(!pud_none(*pud)); WARN_ON(!pud_none(*pud));
set_pud(pud, __pud(__pa_nodebug(kasan_zero_pmd) set_pud(pud, __pud(__pa_nodebug(kasan_zero_pmd)
| __PAGE_KERNEL_RO)); | _KERNPG_TABLE));
addr += PUD_SIZE; addr += PUD_SIZE;
pud = pud_offset(pgd, addr); pud = pud_offset(pgd, addr);
} }
@ -124,7 +137,7 @@ static int __init zero_pgd_populate(unsigned long addr, unsigned long end)
while (IS_ALIGNED(addr, PGDIR_SIZE) && addr + PGDIR_SIZE <= end) { while (IS_ALIGNED(addr, PGDIR_SIZE) && addr + PGDIR_SIZE <= end) {
WARN_ON(!pgd_none(*pgd)); WARN_ON(!pgd_none(*pgd));
set_pgd(pgd, __pgd(__pa_nodebug(kasan_zero_pud) set_pgd(pgd, __pgd(__pa_nodebug(kasan_zero_pud)
| __PAGE_KERNEL_RO)); | _KERNPG_TABLE));
addr += PGDIR_SIZE; addr += PGDIR_SIZE;
pgd = pgd_offset_k(addr); pgd = pgd_offset_k(addr);
} }
@ -166,6 +179,26 @@ static struct notifier_block kasan_die_notifier = {
}; };
#endif #endif
void __init kasan_early_init(void)
{
int i;
pteval_t pte_val = __pa_nodebug(kasan_zero_page) | __PAGE_KERNEL;
pmdval_t pmd_val = __pa_nodebug(kasan_zero_pte) | _KERNPG_TABLE;
pudval_t pud_val = __pa_nodebug(kasan_zero_pmd) | _KERNPG_TABLE;
for (i = 0; i < PTRS_PER_PTE; i++)
kasan_zero_pte[i] = __pte(pte_val);
for (i = 0; i < PTRS_PER_PMD; i++)
kasan_zero_pmd[i] = __pmd(pmd_val);
for (i = 0; i < PTRS_PER_PUD; i++)
kasan_zero_pud[i] = __pud(pud_val);
kasan_map_early_shadow(early_level4_pgt);
kasan_map_early_shadow(init_level4_pgt);
}
void __init kasan_init(void) void __init kasan_init(void)
{ {
int i; int i;
@ -176,6 +209,7 @@ void __init kasan_init(void)
memcpy(early_level4_pgt, init_level4_pgt, sizeof(early_level4_pgt)); memcpy(early_level4_pgt, init_level4_pgt, sizeof(early_level4_pgt));
load_cr3(early_level4_pgt); load_cr3(early_level4_pgt);
__flush_tlb_all();
clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END); clear_pgds(KASAN_SHADOW_START, KASAN_SHADOW_END);
@ -202,5 +236,8 @@ void __init kasan_init(void)
memset(kasan_zero_page, 0, PAGE_SIZE); memset(kasan_zero_page, 0, PAGE_SIZE);
load_cr3(init_level4_pgt); load_cr3(init_level4_pgt);
__flush_tlb_all();
init_task.kasan_depth = 0; init_task.kasan_depth = 0;
pr_info("Kernel address sanitizer initialized\n");
} }

View File

@ -352,13 +352,16 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
pdata->mmio_size = resource_size(rentry->res); pdata->mmio_size = resource_size(rentry->res);
pdata->mmio_base = ioremap(rentry->res->start, pdata->mmio_base = ioremap(rentry->res->start,
pdata->mmio_size); pdata->mmio_size);
if (!pdata->mmio_base)
goto err_out;
break; break;
} }
acpi_dev_free_resource_list(&resource_list); acpi_dev_free_resource_list(&resource_list);
if (!pdata->mmio_base) {
ret = -ENOMEM;
goto err_out;
}
pdata->dev_desc = dev_desc; pdata->dev_desc = dev_desc;
if (dev_desc->setup) if (dev_desc->setup)

View File

@ -18,6 +18,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/sort.h> #include <linux/sort.h>
#include <linux/pmem.h>
#include <linux/io.h> #include <linux/io.h>
#include "nfit.h" #include "nfit.h"
@ -305,6 +306,23 @@ static bool add_idt(struct acpi_nfit_desc *acpi_desc,
return true; return true;
} }
static bool add_flush(struct acpi_nfit_desc *acpi_desc,
struct acpi_nfit_flush_address *flush)
{
struct device *dev = acpi_desc->dev;
struct nfit_flush *nfit_flush = devm_kzalloc(dev, sizeof(*nfit_flush),
GFP_KERNEL);
if (!nfit_flush)
return false;
INIT_LIST_HEAD(&nfit_flush->list);
nfit_flush->flush = flush;
list_add_tail(&nfit_flush->list, &acpi_desc->flushes);
dev_dbg(dev, "%s: nfit_flush handle: %d hint_count: %d\n", __func__,
flush->device_handle, flush->hint_count);
return true;
}
static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table, static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
const void *end) const void *end)
{ {
@ -338,7 +356,8 @@ static void *add_table(struct acpi_nfit_desc *acpi_desc, void *table,
return err; return err;
break; break;
case ACPI_NFIT_TYPE_FLUSH_ADDRESS: case ACPI_NFIT_TYPE_FLUSH_ADDRESS:
dev_dbg(dev, "%s: flush\n", __func__); if (!add_flush(acpi_desc, table))
return err;
break; break;
case ACPI_NFIT_TYPE_SMBIOS: case ACPI_NFIT_TYPE_SMBIOS:
dev_dbg(dev, "%s: smbios\n", __func__); dev_dbg(dev, "%s: smbios\n", __func__);
@ -389,6 +408,7 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
{ {
u16 dcr = __to_nfit_memdev(nfit_mem)->region_index; u16 dcr = __to_nfit_memdev(nfit_mem)->region_index;
struct nfit_memdev *nfit_memdev; struct nfit_memdev *nfit_memdev;
struct nfit_flush *nfit_flush;
struct nfit_dcr *nfit_dcr; struct nfit_dcr *nfit_dcr;
struct nfit_bdw *nfit_bdw; struct nfit_bdw *nfit_bdw;
struct nfit_idt *nfit_idt; struct nfit_idt *nfit_idt;
@ -442,6 +462,14 @@ static int nfit_mem_add(struct acpi_nfit_desc *acpi_desc,
nfit_mem->idt_bdw = nfit_idt->idt; nfit_mem->idt_bdw = nfit_idt->idt;
break; break;
} }
list_for_each_entry(nfit_flush, &acpi_desc->flushes, list) {
if (nfit_flush->flush->device_handle !=
nfit_memdev->memdev->device_handle)
continue;
nfit_mem->nfit_flush = nfit_flush;
break;
}
break; break;
} }
@ -978,6 +1006,24 @@ static u64 to_interleave_offset(u64 offset, struct nfit_blk_mmio *mmio)
return mmio->base_offset + line_offset + table_offset + sub_line_offset; return mmio->base_offset + line_offset + table_offset + sub_line_offset;
} }
static void wmb_blk(struct nfit_blk *nfit_blk)
{
if (nfit_blk->nvdimm_flush) {
/*
* The first wmb() is needed to 'sfence' all previous writes
* such that they are architecturally visible for the platform
* buffer flush. Note that we've already arranged for pmem
* writes to avoid the cache via arch_memcpy_to_pmem(). The
* final wmb() ensures ordering for the NVDIMM flush write.
*/
wmb();
writeq(1, nfit_blk->nvdimm_flush);
wmb();
} else
wmb_pmem();
}
static u64 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw) static u64 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw)
{ {
struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR]; struct nfit_blk_mmio *mmio = &nfit_blk->mmio[DCR];
@ -1012,7 +1058,10 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw,
offset = to_interleave_offset(offset, mmio); offset = to_interleave_offset(offset, mmio);
writeq(cmd, mmio->base + offset); writeq(cmd, mmio->base + offset);
/* FIXME: conditionally perform read-back if mandated by firmware */ wmb_blk(nfit_blk);
if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH)
readq(mmio->base + offset);
} }
static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
@ -1026,7 +1075,6 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES base_offset = nfit_blk->bdw_offset + dpa % L1_CACHE_BYTES
+ lane * mmio->size; + lane * mmio->size;
/* TODO: non-temporal access, flush hints, cache management etc... */
write_blk_ctl(nfit_blk, lane, dpa, len, rw); write_blk_ctl(nfit_blk, lane, dpa, len, rw);
while (len) { while (len) {
unsigned int c; unsigned int c;
@ -1045,13 +1093,19 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk,
} }
if (rw) if (rw)
memcpy(mmio->aperture + offset, iobuf + copied, c); memcpy_to_pmem(mmio->aperture + offset,
iobuf + copied, c);
else else
memcpy(iobuf + copied, mmio->aperture + offset, c); memcpy_from_pmem(iobuf + copied,
mmio->aperture + offset, c);
copied += c; copied += c;
len -= c; len -= c;
} }
if (rw)
wmb_blk(nfit_blk);
rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0; rc = read_blk_stat(nfit_blk, lane) ? -EIO : 0;
return rc; return rc;
} }
@ -1124,7 +1178,7 @@ static void nfit_spa_unmap(struct acpi_nfit_desc *acpi_desc,
} }
static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
struct acpi_nfit_system_address *spa) struct acpi_nfit_system_address *spa, enum spa_map_type type)
{ {
resource_size_t start = spa->address; resource_size_t start = spa->address;
resource_size_t n = spa->length; resource_size_t n = spa->length;
@ -1152,8 +1206,15 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
if (!res) if (!res)
goto err_mem; goto err_mem;
/* TODO: cacheability based on the spa type */ if (type == SPA_MAP_APERTURE) {
spa_map->iomem = ioremap_nocache(start, n); /*
* TODO: memremap_pmem() support, but that requires cache
* flushing when the aperture is moved.
*/
spa_map->iomem = ioremap_wc(start, n);
} else
spa_map->iomem = ioremap_nocache(start, n);
if (!spa_map->iomem) if (!spa_map->iomem)
goto err_map; goto err_map;
@ -1171,6 +1232,7 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
* nfit_spa_map - interleave-aware managed-mappings of acpi_nfit_system_address ranges * nfit_spa_map - interleave-aware managed-mappings of acpi_nfit_system_address ranges
* @nvdimm_bus: NFIT-bus that provided the spa table entry * @nvdimm_bus: NFIT-bus that provided the spa table entry
* @nfit_spa: spa table to map * @nfit_spa: spa table to map
* @type: aperture or control region
* *
* In the case where block-data-window apertures and * In the case where block-data-window apertures and
* dimm-control-regions are interleaved they will end up sharing a * dimm-control-regions are interleaved they will end up sharing a
@ -1180,12 +1242,12 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
* unbound. * unbound.
*/ */
static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc, static void __iomem *nfit_spa_map(struct acpi_nfit_desc *acpi_desc,
struct acpi_nfit_system_address *spa) struct acpi_nfit_system_address *spa, enum spa_map_type type)
{ {
void __iomem *iomem; void __iomem *iomem;
mutex_lock(&acpi_desc->spa_map_mutex); mutex_lock(&acpi_desc->spa_map_mutex);
iomem = __nfit_spa_map(acpi_desc, spa); iomem = __nfit_spa_map(acpi_desc, spa, type);
mutex_unlock(&acpi_desc->spa_map_mutex); mutex_unlock(&acpi_desc->spa_map_mutex);
return iomem; return iomem;
@ -1206,12 +1268,35 @@ static int nfit_blk_init_interleave(struct nfit_blk_mmio *mmio,
return 0; return 0;
} }
static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc,
struct nvdimm *nvdimm, struct nfit_blk *nfit_blk)
{
struct nd_cmd_dimm_flags flags;
int rc;
memset(&flags, 0, sizeof(flags));
rc = nd_desc->ndctl(nd_desc, nvdimm, ND_CMD_DIMM_FLAGS, &flags,
sizeof(flags));
if (rc >= 0 && flags.status == 0)
nfit_blk->dimm_flags = flags.flags;
else if (rc == -ENOTTY) {
/* fall back to a conservative default */
nfit_blk->dimm_flags = ND_BLK_DCR_LATCH;
rc = 0;
} else
rc = -ENXIO;
return rc;
}
static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
struct device *dev) struct device *dev)
{ {
struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus); struct nvdimm_bus_descriptor *nd_desc = to_nd_desc(nvdimm_bus);
struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc);
struct nd_blk_region *ndbr = to_nd_blk_region(dev); struct nd_blk_region *ndbr = to_nd_blk_region(dev);
struct nfit_flush *nfit_flush;
struct nfit_blk_mmio *mmio; struct nfit_blk_mmio *mmio;
struct nfit_blk *nfit_blk; struct nfit_blk *nfit_blk;
struct nfit_mem *nfit_mem; struct nfit_mem *nfit_mem;
@ -1223,8 +1308,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) { if (!nfit_mem || !nfit_mem->dcr || !nfit_mem->bdw) {
dev_dbg(dev, "%s: missing%s%s%s\n", __func__, dev_dbg(dev, "%s: missing%s%s%s\n", __func__,
nfit_mem ? "" : " nfit_mem", nfit_mem ? "" : " nfit_mem",
nfit_mem->dcr ? "" : " dcr", (nfit_mem && nfit_mem->dcr) ? "" : " dcr",
nfit_mem->bdw ? "" : " bdw"); (nfit_mem && nfit_mem->bdw) ? "" : " bdw");
return -ENXIO; return -ENXIO;
} }
@ -1237,7 +1322,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
/* map block aperture memory */ /* map block aperture memory */
nfit_blk->bdw_offset = nfit_mem->bdw->offset; nfit_blk->bdw_offset = nfit_mem->bdw->offset;
mmio = &nfit_blk->mmio[BDW]; mmio = &nfit_blk->mmio[BDW];
mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw); mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw,
SPA_MAP_APERTURE);
if (!mmio->base) { if (!mmio->base) {
dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, dev_dbg(dev, "%s: %s failed to map bdw\n", __func__,
nvdimm_name(nvdimm)); nvdimm_name(nvdimm));
@ -1259,7 +1345,8 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
nfit_blk->cmd_offset = nfit_mem->dcr->command_offset; nfit_blk->cmd_offset = nfit_mem->dcr->command_offset;
nfit_blk->stat_offset = nfit_mem->dcr->status_offset; nfit_blk->stat_offset = nfit_mem->dcr->status_offset;
mmio = &nfit_blk->mmio[DCR]; mmio = &nfit_blk->mmio[DCR];
mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr); mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr,
SPA_MAP_CONTROL);
if (!mmio->base) { if (!mmio->base) {
dev_dbg(dev, "%s: %s failed to map dcr\n", __func__, dev_dbg(dev, "%s: %s failed to map dcr\n", __func__,
nvdimm_name(nvdimm)); nvdimm_name(nvdimm));
@ -1277,6 +1364,24 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus,
return rc; return rc;
} }
rc = acpi_nfit_blk_get_flags(nd_desc, nvdimm, nfit_blk);
if (rc < 0) {
dev_dbg(dev, "%s: %s failed get DIMM flags\n",
__func__, nvdimm_name(nvdimm));
return rc;
}
nfit_flush = nfit_mem->nfit_flush;
if (nfit_flush && nfit_flush->flush->hint_count != 0) {
nfit_blk->nvdimm_flush = devm_ioremap_nocache(dev,
nfit_flush->flush->hint_address[0], 8);
if (!nfit_blk->nvdimm_flush)
return -ENOMEM;
}
if (!arch_has_pmem_api() && !nfit_blk->nvdimm_flush)
dev_warn(dev, "unable to guarantee persistence of writes\n");
if (mmio->line_size == 0) if (mmio->line_size == 0)
return 0; return 0;
@ -1459,6 +1564,7 @@ int acpi_nfit_init(struct acpi_nfit_desc *acpi_desc, acpi_size sz)
INIT_LIST_HEAD(&acpi_desc->dcrs); INIT_LIST_HEAD(&acpi_desc->dcrs);
INIT_LIST_HEAD(&acpi_desc->bdws); INIT_LIST_HEAD(&acpi_desc->bdws);
INIT_LIST_HEAD(&acpi_desc->idts); INIT_LIST_HEAD(&acpi_desc->idts);
INIT_LIST_HEAD(&acpi_desc->flushes);
INIT_LIST_HEAD(&acpi_desc->memdevs); INIT_LIST_HEAD(&acpi_desc->memdevs);
INIT_LIST_HEAD(&acpi_desc->dimms); INIT_LIST_HEAD(&acpi_desc->dimms);
mutex_init(&acpi_desc->spa_map_mutex); mutex_init(&acpi_desc->spa_map_mutex);

View File

@ -40,6 +40,10 @@ enum nfit_uuids {
NFIT_UUID_MAX, NFIT_UUID_MAX,
}; };
enum {
ND_BLK_DCR_LATCH = 2,
};
struct nfit_spa { struct nfit_spa {
struct acpi_nfit_system_address *spa; struct acpi_nfit_system_address *spa;
struct list_head list; struct list_head list;
@ -60,6 +64,11 @@ struct nfit_idt {
struct list_head list; struct list_head list;
}; };
struct nfit_flush {
struct acpi_nfit_flush_address *flush;
struct list_head list;
};
struct nfit_memdev { struct nfit_memdev {
struct acpi_nfit_memory_map *memdev; struct acpi_nfit_memory_map *memdev;
struct list_head list; struct list_head list;
@ -77,6 +86,7 @@ struct nfit_mem {
struct acpi_nfit_system_address *spa_bdw; struct acpi_nfit_system_address *spa_bdw;
struct acpi_nfit_interleave *idt_dcr; struct acpi_nfit_interleave *idt_dcr;
struct acpi_nfit_interleave *idt_bdw; struct acpi_nfit_interleave *idt_bdw;
struct nfit_flush *nfit_flush;
struct list_head list; struct list_head list;
struct acpi_device *adev; struct acpi_device *adev;
unsigned long dsm_mask; unsigned long dsm_mask;
@ -88,6 +98,7 @@ struct acpi_nfit_desc {
struct mutex spa_map_mutex; struct mutex spa_map_mutex;
struct list_head spa_maps; struct list_head spa_maps;
struct list_head memdevs; struct list_head memdevs;
struct list_head flushes;
struct list_head dimms; struct list_head dimms;
struct list_head spas; struct list_head spas;
struct list_head dcrs; struct list_head dcrs;
@ -109,7 +120,7 @@ struct nfit_blk {
struct nfit_blk_mmio { struct nfit_blk_mmio {
union { union {
void __iomem *base; void __iomem *base;
void *aperture; void __pmem *aperture;
}; };
u64 size; u64 size;
u64 base_offset; u64 base_offset;
@ -123,6 +134,13 @@ struct nfit_blk {
u64 bdw_offset; /* post interleave offset */ u64 bdw_offset; /* post interleave offset */
u64 stat_offset; u64 stat_offset;
u64 cmd_offset; u64 cmd_offset;
void __iomem *nvdimm_flush;
u32 dimm_flags;
};
enum spa_map_type {
SPA_MAP_CONTROL,
SPA_MAP_APERTURE,
}; };
struct nfit_spa_mapping { struct nfit_spa_mapping {

View File

@ -175,10 +175,14 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
if (!addr || !length) if (!addr || !length)
return; return;
acpi_reserve_region(addr, length, gas->space_id, 0, desc); /* Resources are never freed */
if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
request_region(addr, length, desc);
else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
request_mem_region(addr, length, desc);
} }
static void __init acpi_reserve_resources(void) static int __init acpi_reserve_resources(void)
{ {
acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
"ACPI PM1a_EVT_BLK"); "ACPI PM1a_EVT_BLK");
@ -207,7 +211,10 @@ static void __init acpi_reserve_resources(void)
if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
acpi_request_region(&acpi_gbl_FADT.xgpe1_block, acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
return 0;
} }
fs_initcall_sync(acpi_reserve_resources);
void acpi_os_printf(const char *fmt, ...) void acpi_os_printf(const char *fmt, ...)
{ {
@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(void)
acpi_status __init acpi_os_initialize1(void) acpi_status __init acpi_os_initialize1(void)
{ {
acpi_reserve_resources();
kacpid_wq = alloc_workqueue("kacpid", 0, 1); kacpid_wq = alloc_workqueue("kacpid", 0, 1);
kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);

View File

@ -26,7 +26,6 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/export.h> #include <linux/export.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/list.h>
#include <linux/slab.h> #include <linux/slab.h>
#ifdef CONFIG_X86 #ifdef CONFIG_X86
@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
return (type & types) ? 0 : 1; return (type & types) ? 0 : 1;
} }
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
struct reserved_region {
struct list_head node;
u64 start;
u64 end;
};
static LIST_HEAD(reserved_io_regions);
static LIST_HEAD(reserved_mem_regions);
static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
char *desc)
{
unsigned int length = end - start + 1;
struct resource *res;
res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
request_region(start, length, desc) :
request_mem_region(start, length, desc);
if (!res)
return -EIO;
res->flags &= ~flags;
return 0;
}
static int add_region_before(u64 start, u64 end, u8 space_id,
unsigned long flags, char *desc,
struct list_head *head)
{
struct reserved_region *reg;
int error;
reg = kmalloc(sizeof(*reg), GFP_KERNEL);
if (!reg)
return -ENOMEM;
error = request_range(start, end, space_id, flags, desc);
if (error) {
kfree(reg);
return error;
}
reg->start = start;
reg->end = end;
list_add_tail(&reg->node, head);
return 0;
}
/**
* acpi_reserve_region - Reserve an I/O or memory region as a system resource.
* @start: Starting address of the region.
* @length: Length of the region.
* @space_id: Identifier of address space to reserve the region from.
* @flags: Resource flags to clear for the region after requesting it.
* @desc: Region description (for messages).
*
* Reserve an I/O or memory region as a system resource to prevent others from
* using it. If the new region overlaps with one of the regions (in the given
* address space) already reserved by this routine, only the non-overlapping
* parts of it will be reserved.
*
* Returned is either 0 (success) or a negative error code indicating a resource
* reservation problem. It is the code of the first encountered error, but the
* routine doesn't abort until it has attempted to request all of the parts of
* the new region that don't overlap with other regions reserved previously.
*
* The resources requested by this routine are never released.
*/
int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
unsigned long flags, char *desc)
{
struct list_head *regions;
struct reserved_region *reg;
u64 end = start + length - 1;
int ret = 0, error = 0;
if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
regions = &reserved_io_regions;
else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
regions = &reserved_mem_regions;
else
return -EINVAL;
if (list_empty(regions))
return add_region_before(start, end, space_id, flags, desc, regions);
list_for_each_entry(reg, regions, node)
if (reg->start == end + 1) {
/* The new region can be prepended to this one. */
ret = request_range(start, end, space_id, flags, desc);
if (!ret)
reg->start = start;
return ret;
} else if (reg->start > end) {
/* No overlap. Add the new region here and get out. */
return add_region_before(start, end, space_id, flags,
desc, &reg->node);
} else if (reg->end == start - 1) {
goto combine;
} else if (reg->end >= start) {
goto overlap;
}
/* The new region goes after the last existing one. */
return add_region_before(start, end, space_id, flags, desc, regions);
overlap:
/*
* The new region overlaps an existing one.
*
* The head part of the new region immediately preceding the existing
* overlapping one can be combined with it right away.
*/
if (reg->start > start) {
error = request_range(start, reg->start - 1, space_id, flags, desc);
if (error)
ret = error;
else
reg->start = start;
}
combine:
/*
* The new region is adjacent to an existing one. If it extends beyond
* that region all the way to the next one, it is possible to combine
* all three of them.
*/
while (reg->end < end) {
struct reserved_region *next = NULL;
u64 a = reg->end + 1, b = end;
if (!list_is_last(&reg->node, regions)) {
next = list_next_entry(reg, node);
if (next->start <= end)
b = next->start - 1;
}
error = request_range(a, b, space_id, flags, desc);
if (!error) {
if (next && next->start == b + 1) {
reg->end = next->end;
list_del(&next->node);
kfree(next);
} else {
reg->end = end;
break;
}
} else if (next) {
if (!ret)
ret = error;
reg = next;
} else {
break;
}
}
return ret ? ret : error;
}
EXPORT_SYMBOL_GPL(acpi_reserve_region);

View File

@ -1019,6 +1019,29 @@ static bool acpi_of_match_device(struct acpi_device *adev,
return false; return false;
} }
static bool __acpi_match_device_cls(const struct acpi_device_id *id,
struct acpi_hardware_id *hwid)
{
int i, msk, byte_shift;
char buf[3];
if (!id->cls)
return false;
/* Apply class-code bitmask, before checking each class-code byte */
for (i = 1; i <= 3; i++) {
byte_shift = 8 * (3 - i);
msk = (id->cls_msk >> byte_shift) & 0xFF;
if (!msk)
continue;
sprintf(buf, "%02x", (id->cls >> byte_shift) & msk);
if (strncmp(buf, &hwid->id[(i - 1) * 2], 2))
return false;
}
return true;
}
static const struct acpi_device_id *__acpi_match_device( static const struct acpi_device_id *__acpi_match_device(
struct acpi_device *device, struct acpi_device *device,
const struct acpi_device_id *ids, const struct acpi_device_id *ids,
@ -1036,9 +1059,12 @@ static const struct acpi_device_id *__acpi_match_device(
list_for_each_entry(hwid, &device->pnp.ids, list) { list_for_each_entry(hwid, &device->pnp.ids, list) {
/* First, check the ACPI/PNP IDs provided by the caller. */ /* First, check the ACPI/PNP IDs provided by the caller. */
for (id = ids; id->id[0]; id++) for (id = ids; id->id[0] || id->cls; id++) {
if (!strcmp((char *) id->id, hwid->id)) if (id->id[0] && !strcmp((char *) id->id, hwid->id))
return id; return id;
else if (id->cls && __acpi_match_device_cls(id, hwid))
return id;
}
/* /*
* Next, check ACPI_DT_NAMESPACE_HID and try to match the * Next, check ACPI_DT_NAMESPACE_HID and try to match the
@ -2101,6 +2127,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
if (info->valid & ACPI_VALID_UID) if (info->valid & ACPI_VALID_UID)
pnp->unique_id = kstrdup(info->unique_id.string, pnp->unique_id = kstrdup(info->unique_id.string,
GFP_KERNEL); GFP_KERNEL);
if (info->valid & ACPI_VALID_CLS)
acpi_add_id(pnp, info->class_code.string);
kfree(info); kfree(info);

View File

@ -48,7 +48,7 @@ config ATA_VERBOSE_ERROR
config ATA_ACPI config ATA_ACPI
bool "ATA ACPI Support" bool "ATA ACPI Support"
depends on ACPI && PCI depends on ACPI
default y default y
help help
This option adds support for ATA-related ACPI objects. This option adds support for ATA-related ACPI objects.

View File

@ -20,6 +20,8 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/libata.h> #include <linux/libata.h>
#include <linux/ahci_platform.h> #include <linux/ahci_platform.h>
#include <linux/acpi.h>
#include <linux/pci_ids.h>
#include "ahci.h" #include "ahci.h"
#define DRV_NAME "ahci" #define DRV_NAME "ahci"
@ -79,12 +81,19 @@ static const struct of_device_id ahci_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, ahci_of_match); MODULE_DEVICE_TABLE(of, ahci_of_match);
static const struct acpi_device_id ahci_acpi_match[] = {
{ ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
{},
};
MODULE_DEVICE_TABLE(acpi, ahci_acpi_match);
static struct platform_driver ahci_driver = { static struct platform_driver ahci_driver = {
.probe = ahci_probe, .probe = ahci_probe,
.remove = ata_platform_remove_one, .remove = ata_platform_remove_one,
.driver = { .driver = {
.name = DRV_NAME, .name = DRV_NAME,
.of_match_table = ahci_of_match, .of_match_table = ahci_of_match,
.acpi_match_table = ahci_acpi_match,
.pm = &ahci_pm_ops, .pm = &ahci_pm_ops,
}, },
}; };

View File

@ -563,10 +563,8 @@ static void fw_dev_release(struct device *dev)
kfree(fw_priv); kfree(fw_priv);
} }
static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env) static int do_firmware_uevent(struct firmware_priv *fw_priv, struct kobj_uevent_env *env)
{ {
struct firmware_priv *fw_priv = to_firmware_priv(dev);
if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id)) if (add_uevent_var(env, "FIRMWARE=%s", fw_priv->buf->fw_id))
return -ENOMEM; return -ENOMEM;
if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout)) if (add_uevent_var(env, "TIMEOUT=%i", loading_timeout))
@ -577,6 +575,18 @@ static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0; return 0;
} }
static int firmware_uevent(struct device *dev, struct kobj_uevent_env *env)
{
struct firmware_priv *fw_priv = to_firmware_priv(dev);
int err = 0;
mutex_lock(&fw_lock);
if (fw_priv->buf)
err = do_firmware_uevent(fw_priv, env);
mutex_unlock(&fw_lock);
return err;
}
static struct class firmware_class = { static struct class firmware_class = {
.name = "firmware", .name = "firmware",
.class_attrs = firmware_class_attrs, .class_attrs = firmware_class_attrs,

View File

@ -6,6 +6,7 @@
* This file is released under the GPLv2. * This file is released under the GPLv2.
*/ */
#include <linux/delay.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
@ -19,6 +20,8 @@
#include <linux/suspend.h> #include <linux/suspend.h>
#include <linux/export.h> #include <linux/export.h>
#define GENPD_RETRY_MAX_MS 250 /* Approximate */
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \ #define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
({ \ ({ \
type (*__routine)(struct device *__d); \ type (*__routine)(struct device *__d); \
@ -2131,6 +2134,7 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
static void genpd_dev_pm_detach(struct device *dev, bool power_off) static void genpd_dev_pm_detach(struct device *dev, bool power_off)
{ {
struct generic_pm_domain *pd; struct generic_pm_domain *pd;
unsigned int i;
int ret = 0; int ret = 0;
pd = pm_genpd_lookup_dev(dev); pd = pm_genpd_lookup_dev(dev);
@ -2139,10 +2143,12 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
dev_dbg(dev, "removing from PM domain %s\n", pd->name); dev_dbg(dev, "removing from PM domain %s\n", pd->name);
while (1) { for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
ret = pm_genpd_remove_device(pd, dev); ret = pm_genpd_remove_device(pd, dev);
if (ret != -EAGAIN) if (ret != -EAGAIN)
break; break;
mdelay(i);
cond_resched(); cond_resched();
} }
@ -2183,6 +2189,7 @@ int genpd_dev_pm_attach(struct device *dev)
{ {
struct of_phandle_args pd_args; struct of_phandle_args pd_args;
struct generic_pm_domain *pd; struct generic_pm_domain *pd;
unsigned int i;
int ret; int ret;
if (!dev->of_node) if (!dev->of_node)
@ -2218,10 +2225,12 @@ int genpd_dev_pm_attach(struct device *dev)
dev_dbg(dev, "adding to PM domain %s\n", pd->name); dev_dbg(dev, "adding to PM domain %s\n", pd->name);
while (1) { for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
ret = pm_genpd_add_device(pd, dev); ret = pm_genpd_add_device(pd, dev);
if (ret != -EAGAIN) if (ret != -EAGAIN)
break; break;
mdelay(i);
cond_resched(); cond_resched();
} }

View File

@ -45,14 +45,12 @@ static int dev_pm_attach_wake_irq(struct device *dev, int irq,
return -EEXIST; return -EEXIST;
} }
dev->power.wakeirq = wirq;
spin_unlock_irqrestore(&dev->power.lock, flags);
err = device_wakeup_attach_irq(dev, wirq); err = device_wakeup_attach_irq(dev, wirq);
if (err) if (!err)
return err; dev->power.wakeirq = wirq;
return 0; spin_unlock_irqrestore(&dev->power.lock, flags);
return err;
} }
/** /**
@ -105,10 +103,10 @@ void dev_pm_clear_wake_irq(struct device *dev)
return; return;
spin_lock_irqsave(&dev->power.lock, flags); spin_lock_irqsave(&dev->power.lock, flags);
device_wakeup_detach_irq(dev);
dev->power.wakeirq = NULL; dev->power.wakeirq = NULL;
spin_unlock_irqrestore(&dev->power.lock, flags); spin_unlock_irqrestore(&dev->power.lock, flags);
device_wakeup_detach_irq(dev);
if (wirq->dedicated_irq) if (wirq->dedicated_irq)
free_irq(wirq->irq, wirq); free_irq(wirq->irq, wirq);
kfree(wirq); kfree(wirq);

View File

@ -281,32 +281,25 @@ EXPORT_SYMBOL_GPL(device_wakeup_enable);
* Attach a device wakeirq to the wakeup source so the device * Attach a device wakeirq to the wakeup source so the device
* wake IRQ can be configured automatically for suspend and * wake IRQ can be configured automatically for suspend and
* resume. * resume.
*
* Call under the device's power.lock lock.
*/ */
int device_wakeup_attach_irq(struct device *dev, int device_wakeup_attach_irq(struct device *dev,
struct wake_irq *wakeirq) struct wake_irq *wakeirq)
{ {
struct wakeup_source *ws; struct wakeup_source *ws;
int ret = 0;
spin_lock_irq(&dev->power.lock);
ws = dev->power.wakeup; ws = dev->power.wakeup;
if (!ws) { if (!ws) {
dev_err(dev, "forgot to call call device_init_wakeup?\n"); dev_err(dev, "forgot to call call device_init_wakeup?\n");
ret = -EINVAL; return -EINVAL;
goto unlock;
} }
if (ws->wakeirq) { if (ws->wakeirq)
ret = -EEXIST; return -EEXIST;
goto unlock;
}
ws->wakeirq = wakeirq; ws->wakeirq = wakeirq;
return 0;
unlock:
spin_unlock_irq(&dev->power.lock);
return ret;
} }
/** /**
@ -314,20 +307,16 @@ unlock:
* @dev: Device to handle * @dev: Device to handle
* *
* Removes a device wakeirq from the wakeup source. * Removes a device wakeirq from the wakeup source.
*
* Call under the device's power.lock lock.
*/ */
void device_wakeup_detach_irq(struct device *dev) void device_wakeup_detach_irq(struct device *dev)
{ {
struct wakeup_source *ws; struct wakeup_source *ws;
spin_lock_irq(&dev->power.lock);
ws = dev->power.wakeup; ws = dev->power.wakeup;
if (!ws) if (ws)
goto unlock; ws->wakeirq = NULL;
ws->wakeirq = NULL;
unlock:
spin_unlock_irq(&dev->power.lock);
} }
/** /**

View File

@ -116,8 +116,10 @@ void __init of_sama5d4_clk_h32mx_setup(struct device_node *np,
h32mxclk->pmc = pmc; h32mxclk->pmc = pmc;
clk = clk_register(NULL, &h32mxclk->hw); clk = clk_register(NULL, &h32mxclk->hw);
if (!clk) if (!clk) {
kfree(h32mxclk);
return; return;
}
of_clk_add_provider(np, of_clk_src_simple_get, clk); of_clk_add_provider(np, of_clk_src_simple_get, clk);
} }

View File

@ -171,8 +171,10 @@ at91_clk_register_main_osc(struct at91_pmc *pmc,
irq_set_status_flags(osc->irq, IRQ_NOAUTOEN); irq_set_status_flags(osc->irq, IRQ_NOAUTOEN);
ret = request_irq(osc->irq, clk_main_osc_irq_handler, ret = request_irq(osc->irq, clk_main_osc_irq_handler,
IRQF_TRIGGER_HIGH, name, osc); IRQF_TRIGGER_HIGH, name, osc);
if (ret) if (ret) {
kfree(osc);
return ERR_PTR(ret); return ERR_PTR(ret);
}
if (bypass) if (bypass)
pmc_write(pmc, AT91_CKGR_MOR, pmc_write(pmc, AT91_CKGR_MOR,

View File

@ -165,12 +165,16 @@ at91_clk_register_master(struct at91_pmc *pmc, unsigned int irq,
irq_set_status_flags(master->irq, IRQ_NOAUTOEN); irq_set_status_flags(master->irq, IRQ_NOAUTOEN);
ret = request_irq(master->irq, clk_master_irq_handler, ret = request_irq(master->irq, clk_master_irq_handler,
IRQF_TRIGGER_HIGH, "clk-master", master); IRQF_TRIGGER_HIGH, "clk-master", master);
if (ret) if (ret) {
kfree(master);
return ERR_PTR(ret); return ERR_PTR(ret);
}
clk = clk_register(NULL, &master->hw); clk = clk_register(NULL, &master->hw);
if (IS_ERR(clk)) if (IS_ERR(clk)) {
free_irq(master->irq, master);
kfree(master); kfree(master);
}
return clk; return clk;
} }

View File

@ -346,12 +346,16 @@ at91_clk_register_pll(struct at91_pmc *pmc, unsigned int irq, const char *name,
irq_set_status_flags(pll->irq, IRQ_NOAUTOEN); irq_set_status_flags(pll->irq, IRQ_NOAUTOEN);
ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH, ret = request_irq(pll->irq, clk_pll_irq_handler, IRQF_TRIGGER_HIGH,
id ? "clk-pllb" : "clk-plla", pll); id ? "clk-pllb" : "clk-plla", pll);
if (ret) if (ret) {
kfree(pll);
return ERR_PTR(ret); return ERR_PTR(ret);
}
clk = clk_register(NULL, &pll->hw); clk = clk_register(NULL, &pll->hw);
if (IS_ERR(clk)) if (IS_ERR(clk)) {
free_irq(pll->irq, pll);
kfree(pll); kfree(pll);
}
return clk; return clk;
} }

View File

@ -130,13 +130,17 @@ at91_clk_register_system(struct at91_pmc *pmc, const char *name,
irq_set_status_flags(sys->irq, IRQ_NOAUTOEN); irq_set_status_flags(sys->irq, IRQ_NOAUTOEN);
ret = request_irq(sys->irq, clk_system_irq_handler, ret = request_irq(sys->irq, clk_system_irq_handler,
IRQF_TRIGGER_HIGH, name, sys); IRQF_TRIGGER_HIGH, name, sys);
if (ret) if (ret) {
kfree(sys);
return ERR_PTR(ret); return ERR_PTR(ret);
}
} }
clk = clk_register(NULL, &sys->hw); clk = clk_register(NULL, &sys->hw);
if (IS_ERR(clk)) if (IS_ERR(clk)) {
free_irq(sys->irq, sys);
kfree(sys); kfree(sys);
}
return clk; return clk;
} }

View File

@ -118,12 +118,16 @@ at91_clk_register_utmi(struct at91_pmc *pmc, unsigned int irq,
irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN); irq_set_status_flags(utmi->irq, IRQ_NOAUTOEN);
ret = request_irq(utmi->irq, clk_utmi_irq_handler, ret = request_irq(utmi->irq, clk_utmi_irq_handler,
IRQF_TRIGGER_HIGH, "clk-utmi", utmi); IRQF_TRIGGER_HIGH, "clk-utmi", utmi);
if (ret) if (ret) {
kfree(utmi);
return ERR_PTR(ret); return ERR_PTR(ret);
}
clk = clk_register(NULL, &utmi->hw); clk = clk_register(NULL, &utmi->hw);
if (IS_ERR(clk)) if (IS_ERR(clk)) {
free_irq(utmi->irq, utmi);
kfree(utmi); kfree(utmi);
}
return clk; return clk;
} }

Some files were not shown because too many files have changed in this diff Show More