Merge tag 'sh-for-4.17' of git://git.libc.org/linux-sh
Pull arch/sh updates from Rich Felker: "Fixes for bugs in futex, device tree, and userspace breakpoint traps, and for PCI issues on SH7786" * tag 'sh-for-4.17' of git://git.libc.org/linux-sh: arch/sh: pcie-sh7786: handle non-zero DMA offset arch/sh: pcie-sh7786: adjust the memory mapping arch/sh: pcie-sh7786: adjust PCI MEM and IO regions arch/sh: pcie-sh7786: exclude unusable PCI MEM areas arch/sh: pcie-sh7786: mark unavailable PCI resource as disabled arch/sh: pci: don't use disabled resources arch/sh: make the DMA mapping operations observe dev->dma_pfn_offset arch/sh: add sh7786_mm_sel() function sh: fix debug trap failure to process signals before return to user sh: fix memory corruption of unflattened device tree sh: fix futex FUTEX_OP_SET op on userspace addresses
This commit is contained in:
@@ -126,12 +126,6 @@ static void __init sh_of_setup(char **cmdline_p)
|
|||||||
{
|
{
|
||||||
struct device_node *root;
|
struct device_node *root;
|
||||||
|
|
||||||
#ifdef CONFIG_USE_BUILTIN_DTB
|
|
||||||
unflatten_and_copy_device_tree();
|
|
||||||
#else
|
|
||||||
unflatten_device_tree();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
board_time_init = sh_of_time_init;
|
board_time_init = sh_of_time_init;
|
||||||
|
|
||||||
sh_mv.mv_name = "Unknown SH model";
|
sh_mv.mv_name = "Unknown SH model";
|
||||||
|
@@ -49,6 +49,8 @@ static void pcibios_scanbus(struct pci_channel *hose)
|
|||||||
for (i = 0; i < hose->nr_resources; i++) {
|
for (i = 0; i < hose->nr_resources; i++) {
|
||||||
res = hose->resources + i;
|
res = hose->resources + i;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
if (res->flags & IORESOURCE_DISABLED)
|
||||||
|
continue;
|
||||||
if (res->flags & IORESOURCE_IO)
|
if (res->flags & IORESOURCE_IO)
|
||||||
offset = hose->io_offset;
|
offset = hose->io_offset;
|
||||||
else if (res->flags & IORESOURCE_MEM)
|
else if (res->flags & IORESOURCE_MEM)
|
||||||
@@ -102,6 +104,9 @@ int register_pci_controller(struct pci_channel *hose)
|
|||||||
for (i = 0; i < hose->nr_resources; i++) {
|
for (i = 0; i < hose->nr_resources; i++) {
|
||||||
struct resource *res = hose->resources + i;
|
struct resource *res = hose->resources + i;
|
||||||
|
|
||||||
|
if (res->flags & IORESOURCE_DISABLED)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (res->flags & IORESOURCE_IO) {
|
if (res->flags & IORESOURCE_IO) {
|
||||||
if (request_resource(&ioport_resource, res) < 0)
|
if (request_resource(&ioport_resource, res) < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
@@ -19,6 +19,7 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/sh_clk.h>
|
#include <linux/sh_clk.h>
|
||||||
#include <linux/sh_intc.h>
|
#include <linux/sh_intc.h>
|
||||||
|
#include <cpu/sh7786.h>
|
||||||
#include "pcie-sh7786.h"
|
#include "pcie-sh7786.h"
|
||||||
#include <asm/sizes.h>
|
#include <asm/sizes.h>
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ struct sh7786_pcie_port {
|
|||||||
|
|
||||||
static struct sh7786_pcie_port *sh7786_pcie_ports;
|
static struct sh7786_pcie_port *sh7786_pcie_ports;
|
||||||
static unsigned int nr_ports;
|
static unsigned int nr_ports;
|
||||||
|
static unsigned long dma_pfn_offset;
|
||||||
|
|
||||||
static struct sh7786_pcie_hwops {
|
static struct sh7786_pcie_hwops {
|
||||||
int (*core_init)(void);
|
int (*core_init)(void);
|
||||||
@@ -40,73 +42,73 @@ static struct sh7786_pcie_hwops {
|
|||||||
|
|
||||||
static struct resource sh7786_pci0_resources[] = {
|
static struct resource sh7786_pci0_resources[] = {
|
||||||
{
|
{
|
||||||
.name = "PCIe0 IO",
|
.name = "PCIe0 MEM 0",
|
||||||
.start = 0xfd000000,
|
.start = 0xfd000000,
|
||||||
.end = 0xfd000000 + SZ_8M - 1,
|
.end = 0xfd000000 + SZ_8M - 1,
|
||||||
.flags = IORESOURCE_IO,
|
.flags = IORESOURCE_MEM,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe0 MEM 0",
|
.name = "PCIe0 MEM 1",
|
||||||
.start = 0xc0000000,
|
.start = 0xc0000000,
|
||||||
.end = 0xc0000000 + SZ_512M - 1,
|
.end = 0xc0000000 + SZ_512M - 1,
|
||||||
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe0 MEM 1",
|
.name = "PCIe0 MEM 2",
|
||||||
.start = 0x10000000,
|
.start = 0x10000000,
|
||||||
.end = 0x10000000 + SZ_64M - 1,
|
.end = 0x10000000 + SZ_64M - 1,
|
||||||
.flags = IORESOURCE_MEM,
|
.flags = IORESOURCE_MEM,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe0 MEM 2",
|
.name = "PCIe0 IO",
|
||||||
.start = 0xfe100000,
|
.start = 0xfe100000,
|
||||||
.end = 0xfe100000 + SZ_1M - 1,
|
.end = 0xfe100000 + SZ_1M - 1,
|
||||||
.flags = IORESOURCE_MEM,
|
.flags = IORESOURCE_IO,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct resource sh7786_pci1_resources[] = {
|
static struct resource sh7786_pci1_resources[] = {
|
||||||
{
|
{
|
||||||
.name = "PCIe1 IO",
|
.name = "PCIe1 MEM 0",
|
||||||
.start = 0xfd800000,
|
.start = 0xfd800000,
|
||||||
.end = 0xfd800000 + SZ_8M - 1,
|
.end = 0xfd800000 + SZ_8M - 1,
|
||||||
.flags = IORESOURCE_IO,
|
.flags = IORESOURCE_MEM,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe1 MEM 0",
|
.name = "PCIe1 MEM 1",
|
||||||
.start = 0xa0000000,
|
.start = 0xa0000000,
|
||||||
.end = 0xa0000000 + SZ_512M - 1,
|
.end = 0xa0000000 + SZ_512M - 1,
|
||||||
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe1 MEM 1",
|
.name = "PCIe1 MEM 2",
|
||||||
.start = 0x30000000,
|
.start = 0x30000000,
|
||||||
.end = 0x30000000 + SZ_256M - 1,
|
.end = 0x30000000 + SZ_256M - 1,
|
||||||
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe1 MEM 2",
|
.name = "PCIe1 IO",
|
||||||
.start = 0xfe300000,
|
.start = 0xfe300000,
|
||||||
.end = 0xfe300000 + SZ_1M - 1,
|
.end = 0xfe300000 + SZ_1M - 1,
|
||||||
.flags = IORESOURCE_MEM,
|
.flags = IORESOURCE_IO,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct resource sh7786_pci2_resources[] = {
|
static struct resource sh7786_pci2_resources[] = {
|
||||||
{
|
{
|
||||||
.name = "PCIe2 IO",
|
.name = "PCIe2 MEM 0",
|
||||||
.start = 0xfc800000,
|
.start = 0xfc800000,
|
||||||
.end = 0xfc800000 + SZ_4M - 1,
|
.end = 0xfc800000 + SZ_4M - 1,
|
||||||
.flags = IORESOURCE_IO,
|
.flags = IORESOURCE_MEM,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe2 MEM 0",
|
.name = "PCIe2 MEM 1",
|
||||||
.start = 0x80000000,
|
.start = 0x80000000,
|
||||||
.end = 0x80000000 + SZ_512M - 1,
|
.end = 0x80000000 + SZ_512M - 1,
|
||||||
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe2 MEM 1",
|
.name = "PCIe2 MEM 2",
|
||||||
.start = 0x20000000,
|
.start = 0x20000000,
|
||||||
.end = 0x20000000 + SZ_256M - 1,
|
.end = 0x20000000 + SZ_256M - 1,
|
||||||
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
.flags = IORESOURCE_MEM | IORESOURCE_MEM_32BIT,
|
||||||
}, {
|
}, {
|
||||||
.name = "PCIe2 MEM 2",
|
.name = "PCIe2 IO",
|
||||||
.start = 0xfcd00000,
|
.start = 0xfcd00000,
|
||||||
.end = 0xfcd00000 + SZ_1M - 1,
|
.end = 0xfcd00000 + SZ_1M - 1,
|
||||||
.flags = IORESOURCE_MEM,
|
.flags = IORESOURCE_IO,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -301,7 +303,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
|
|||||||
{
|
{
|
||||||
struct pci_channel *chan = port->hose;
|
struct pci_channel *chan = port->hose;
|
||||||
unsigned int data;
|
unsigned int data;
|
||||||
phys_addr_t memphys;
|
phys_addr_t memstart, memend;
|
||||||
size_t memsize;
|
size_t memsize;
|
||||||
int ret, i, win;
|
int ret, i, win;
|
||||||
|
|
||||||
@@ -357,15 +359,26 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
|
|||||||
data |= (0xff << 16);
|
data |= (0xff << 16);
|
||||||
pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
|
pci_write_reg(chan, data, SH4A_PCIEMACCTLR);
|
||||||
|
|
||||||
memphys = __pa(memory_start);
|
memstart = __pa(memory_start);
|
||||||
memsize = roundup_pow_of_two(memory_end - memory_start);
|
memend = __pa(memory_end);
|
||||||
|
memsize = roundup_pow_of_two(memend - memstart);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The start address must be aligned on its size. So we round
|
||||||
|
* it down, and then recalculate the size so that it covers
|
||||||
|
* the entire memory.
|
||||||
|
*/
|
||||||
|
memstart = ALIGN_DOWN(memstart, memsize);
|
||||||
|
memsize = roundup_pow_of_two(memend - memstart);
|
||||||
|
|
||||||
|
dma_pfn_offset = memstart >> PAGE_SHIFT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's more than 512MB of memory, we need to roll over to
|
* If there's more than 512MB of memory, we need to roll over to
|
||||||
* LAR1/LAMR1.
|
* LAR1/LAMR1.
|
||||||
*/
|
*/
|
||||||
if (memsize > SZ_512M) {
|
if (memsize > SZ_512M) {
|
||||||
pci_write_reg(chan, memphys + SZ_512M, SH4A_PCIELAR1);
|
pci_write_reg(chan, memstart + SZ_512M, SH4A_PCIELAR1);
|
||||||
pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
|
pci_write_reg(chan, ((memsize - SZ_512M) - SZ_256) | 1,
|
||||||
SH4A_PCIELAMR1);
|
SH4A_PCIELAMR1);
|
||||||
memsize = SZ_512M;
|
memsize = SZ_512M;
|
||||||
@@ -381,7 +394,7 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
|
|||||||
* LAR0/LAMR0 covers up to the first 512MB, which is enough to
|
* LAR0/LAMR0 covers up to the first 512MB, which is enough to
|
||||||
* cover all of lowmem on most platforms.
|
* cover all of lowmem on most platforms.
|
||||||
*/
|
*/
|
||||||
pci_write_reg(chan, memphys, SH4A_PCIELAR0);
|
pci_write_reg(chan, memstart, SH4A_PCIELAR0);
|
||||||
pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
|
pci_write_reg(chan, (memsize - SZ_256) | 1, SH4A_PCIELAMR0);
|
||||||
|
|
||||||
/* Finish initialization */
|
/* Finish initialization */
|
||||||
@@ -438,6 +451,9 @@ static int __init pcie_init(struct sh7786_pcie_port *port)
|
|||||||
* mode, so just skip them entirely.
|
* mode, so just skip them entirely.
|
||||||
*/
|
*/
|
||||||
if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
|
if ((res->flags & IORESOURCE_MEM_32BIT) && __in_29bit_mode())
|
||||||
|
res->flags |= IORESOURCE_DISABLED;
|
||||||
|
|
||||||
|
if (res->flags & IORESOURCE_DISABLED)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
|
pci_write_reg(chan, 0x00000000, SH4A_PCIEPTCTLR(win));
|
||||||
@@ -472,6 +488,11 @@ int pcibios_map_platform_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
|||||||
return evt2irq(0xae0);
|
return evt2irq(0xae0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pcibios_bus_add_device(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
pdev->dev.dma_pfn_offset = dma_pfn_offset;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init sh7786_pcie_core_init(void)
|
static int __init sh7786_pcie_core_init(void)
|
||||||
{
|
{
|
||||||
/* Return the number of ports */
|
/* Return the number of ports */
|
||||||
@@ -527,6 +548,7 @@ static struct sh7786_pcie_hwops sh7786_65nm_pcie_hwops __initdata = {
|
|||||||
static int __init sh7786_pcie_init(void)
|
static int __init sh7786_pcie_init(void)
|
||||||
{
|
{
|
||||||
struct clk *platclk;
|
struct clk *platclk;
|
||||||
|
u32 mm_sel;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
printk(KERN_NOTICE "PCI: Starting initialization.\n");
|
printk(KERN_NOTICE "PCI: Starting initialization.\n");
|
||||||
@@ -560,6 +582,16 @@ static int __init sh7786_pcie_init(void)
|
|||||||
|
|
||||||
clk_enable(platclk);
|
clk_enable(platclk);
|
||||||
|
|
||||||
|
mm_sel = sh7786_mm_sel();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Depending on the MMSELR register value, the PCIe0 MEM 1
|
||||||
|
* area may not be available. See Table 13.11 of the SH7786
|
||||||
|
* datasheet.
|
||||||
|
*/
|
||||||
|
if (mm_sel != 1 && mm_sel != 2 && mm_sel != 5 && mm_sel != 6)
|
||||||
|
sh7786_pci0_resources[2].flags |= IORESOURCE_DISABLED;
|
||||||
|
|
||||||
printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
|
printk(KERN_NOTICE "PCI: probing %d ports.\n", nr_ports);
|
||||||
|
|
||||||
for (i = 0; i < nr_ports; i++) {
|
for (i = 0; i < nr_ports; i++) {
|
||||||
|
@@ -37,10 +37,7 @@ static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval,
|
|||||||
pagefault_disable();
|
pagefault_disable();
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (op == FUTEX_OP_SET)
|
ret = get_user(oldval, uaddr);
|
||||||
ret = oldval = 0;
|
|
||||||
else
|
|
||||||
ret = get_user(oldval, uaddr);
|
|
||||||
|
|
||||||
if (ret) break;
|
if (ret) break;
|
||||||
|
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
#ifndef __CPU_SH7786_H__
|
#ifndef __CPU_SH7786_H__
|
||||||
#define __CPU_SH7786_H__
|
#define __CPU_SH7786_H__
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
/* PA */
|
/* PA */
|
||||||
GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
|
GPIO_PA7, GPIO_PA6, GPIO_PA5, GPIO_PA4,
|
||||||
@@ -131,4 +133,9 @@ enum {
|
|||||||
GPIO_FN_IRL7, GPIO_FN_IRL6, GPIO_FN_IRL5, GPIO_FN_IRL4,
|
GPIO_FN_IRL7, GPIO_FN_IRL6, GPIO_FN_IRL5, GPIO_FN_IRL4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline u32 sh7786_mm_sel(void)
|
||||||
|
{
|
||||||
|
return __raw_readl(0xFC400020) & 0x7;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __CPU_SH7786_H__ */
|
#endif /* __CPU_SH7786_H__ */
|
||||||
|
@@ -16,7 +16,8 @@ static dma_addr_t nommu_map_page(struct device *dev, struct page *page,
|
|||||||
enum dma_data_direction dir,
|
enum dma_data_direction dir,
|
||||||
unsigned long attrs)
|
unsigned long attrs)
|
||||||
{
|
{
|
||||||
dma_addr_t addr = page_to_phys(page) + offset;
|
dma_addr_t addr = page_to_phys(page) + offset
|
||||||
|
- PFN_PHYS(dev->dma_pfn_offset);
|
||||||
|
|
||||||
WARN_ON(size == 0);
|
WARN_ON(size == 0);
|
||||||
|
|
||||||
@@ -36,12 +37,14 @@ static int nommu_map_sg(struct device *dev, struct scatterlist *sg,
|
|||||||
WARN_ON(nents == 0 || sg[0].length == 0);
|
WARN_ON(nents == 0 || sg[0].length == 0);
|
||||||
|
|
||||||
for_each_sg(sg, s, nents, i) {
|
for_each_sg(sg, s, nents, i) {
|
||||||
|
dma_addr_t offset = PFN_PHYS(dev->dma_pfn_offset);
|
||||||
|
|
||||||
BUG_ON(!sg_page(s));
|
BUG_ON(!sg_page(s));
|
||||||
|
|
||||||
if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
|
||||||
sh_sync_dma_for_device(sg_virt(s), s->length, dir);
|
sh_sync_dma_for_device(sg_virt(s), s->length, dir);
|
||||||
|
|
||||||
s->dma_address = sg_phys(s);
|
s->dma_address = sg_phys(s) - offset;
|
||||||
s->dma_length = s->length;
|
s->dma_length = s->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -255,7 +255,7 @@ debug_trap:
|
|||||||
mov.l @r8, r8
|
mov.l @r8, r8
|
||||||
jsr @r8
|
jsr @r8
|
||||||
nop
|
nop
|
||||||
bra __restore_all
|
bra ret_from_exception
|
||||||
nop
|
nop
|
||||||
CFI_ENDPROC
|
CFI_ENDPROC
|
||||||
|
|
||||||
|
@@ -330,6 +330,14 @@ void __init setup_arch(char **cmdline_p)
|
|||||||
/* Let earlyprintk output early console messages */
|
/* Let earlyprintk output early console messages */
|
||||||
early_platform_driver_probe("earlyprintk", 1, 1);
|
early_platform_driver_probe("earlyprintk", 1, 1);
|
||||||
|
|
||||||
|
#ifdef CONFIG_OF_FLATTREE
|
||||||
|
#ifdef CONFIG_USE_BUILTIN_DTB
|
||||||
|
unflatten_and_copy_device_tree();
|
||||||
|
#else
|
||||||
|
unflatten_device_tree();
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
paging_init();
|
paging_init();
|
||||||
|
|
||||||
#ifdef CONFIG_DUMMY_CONSOLE
|
#ifdef CONFIG_DUMMY_CONSOLE
|
||||||
|
@@ -59,7 +59,7 @@ void *dma_generic_alloc_coherent(struct device *dev, size_t size,
|
|||||||
|
|
||||||
split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order);
|
split_page(pfn_to_page(virt_to_phys(ret) >> PAGE_SHIFT), order);
|
||||||
|
|
||||||
*dma_handle = virt_to_phys(ret);
|
*dma_handle = virt_to_phys(ret) - PFN_PHYS(dev->dma_pfn_offset);
|
||||||
|
|
||||||
return ret_nocache;
|
return ret_nocache;
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ void dma_generic_free_coherent(struct device *dev, size_t size,
|
|||||||
unsigned long attrs)
|
unsigned long attrs)
|
||||||
{
|
{
|
||||||
int order = get_order(size);
|
int order = get_order(size);
|
||||||
unsigned long pfn = dma_handle >> PAGE_SHIFT;
|
unsigned long pfn = (dma_handle >> PAGE_SHIFT) + dev->dma_pfn_offset;
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
for (k = 0; k < (1 << order); k++)
|
for (k = 0; k < (1 << order); k++)
|
||||||
|
Reference in New Issue
Block a user