Commit 43c6494f authored by Michael Ellerman's avatar Michael Ellerman

powerpc/io: Fix the IO workarounds code to work with Radix

Back in 2006 Ben added some workarounds for a misbehaviour in the
Spider IO bridge used on early Cell machines, see commit
014da7ff ("[POWERPC] Cell "Spider" MMIO workarounds"). Later these
were made to be generic, ie. not tied specifically to Spider.

The code stashes a token in the high bits (59-48) of virtual addresses
used for IO (eg. returned from ioremap()). This works fine when using
the Hash MMU, but when we're using the Radix MMU the bits used for the
token overlap with some of the bits of the virtual address.

This is because the maximum virtual address is larger with Radix, up
to c00fffffffffffff, and in fact we use that high part of the address
range for ioremap(), see RADIX_KERN_IO_START.

As it happens the bits that are used overlap with the bits that
differentiate an IO address vs a linear map address. If the resulting
address lies outside the linear mapping we will crash (see below), if
not we just corrupt memory.

  virtio-pci 0000:00:00.0: Using 64-bit direct DMA at offset 800000000000000
  Unable to handle kernel paging request for data at address 0xc000000080000014
  ...
  CFAR: c000000000626b98 DAR: c000000080000014 DSISR: 42000000 IRQMASK: 0
  GPR00: c0000000006c54fc c00000003e523378 c0000000016de600 0000000000000000
  GPR04: c00c000080000014 0000000000000007 0fffffff000affff 0000000000000030
         ^^^^
  ...
  NIP [c000000000626c5c] .iowrite8+0xec/0x100
  LR [c0000000006c992c] .vp_reset+0x2c/0x90
  Call Trace:
    .pci_bus_read_config_dword+0xc4/0x120 (unreliable)
    .register_virtio_device+0x13c/0x1c0
    .virtio_pci_probe+0x148/0x1f0
    .local_pci_probe+0x68/0x140
    .pci_device_probe+0x164/0x220
    .really_probe+0x274/0x3b0
    .driver_probe_device+0x80/0x170
    .__driver_attach+0x14c/0x150
    .bus_for_each_dev+0xb8/0x130
    .driver_attach+0x34/0x50
    .bus_add_driver+0x178/0x2f0
    .driver_register+0x90/0x1a0
    .__pci_register_driver+0x6c/0x90
    .virtio_pci_driver_init+0x2c/0x40
    .do_one_initcall+0x64/0x280
    .kernel_init_freeable+0x36c/0x474
    .kernel_init+0x24/0x160
    .ret_from_kernel_thread+0x58/0x7c

This hasn't been a problem because CONFIG_PPC_IO_WORKAROUNDS which
enables this code is usually not enabled. It is only enabled when it's
selected by PPC_CELL_NATIVE which is only selected by
PPC_IBM_CELL_BLADE and that in turn depends on BIG_ENDIAN. So in order
to hit the bug you need to build a big endian kernel, with IBM Cell
Blade support enabled, as well as Radix MMU support, and then boot
that on Power9 using Radix MMU.

Still we can fix the bug, so let's do that. We simply use fewer bits
for the token, taking the union of the restrictions on the address
from both Hash and Radix, we end up with 8 bits we can use for the
token. The only user of the token is iowa_mem_find_bus() which only
supports 8 token values, so 8 bits is plenty for that.

Fixes: 566ca99a ("powerpc/mm/radix: Add dummy radix_enabled()")
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent c8b00bb7
...@@ -268,19 +268,13 @@ extern void _memcpy_toio(volatile void __iomem *dest, const void *src, ...@@ -268,19 +268,13 @@ extern void _memcpy_toio(volatile void __iomem *dest, const void *src,
* their hooks, a bitfield is reserved for use by the platform near the * their hooks, a bitfield is reserved for use by the platform near the
* top of MMIO addresses (not PIO, those have to cope the hard way). * top of MMIO addresses (not PIO, those have to cope the hard way).
* *
* This bit field is 12 bits and is at the top of the IO virtual * The highest address in the kernel virtual space are:
* addresses PCI_IO_INDIRECT_TOKEN_MASK.
* *
* The kernel virtual space is thus: * d0003fffffffffff # with Hash MMU
* c00fffffffffffff # with Radix MMU
* *
* 0xD000000000000000 : vmalloc * The top 4 bits are reserved as the region ID on hash, leaving us 8 bits
* 0xD000080000000000 : PCI PHB IO space * that can be used for the field.
* 0xD000080080000000 : ioremap
* 0xD0000fffffffffff : end of ioremap region
*
* Since the top 4 bits are reserved as the region ID, we use thus
* the next 12 bits and keep 4 bits available for the future if the
* virtual address space is ever to be extended.
* *
* The direct IO mapping operations will then mask off those bits * The direct IO mapping operations will then mask off those bits
* before doing the actual access, though that only happen when * before doing the actual access, though that only happen when
...@@ -292,8 +286,8 @@ extern void _memcpy_toio(volatile void __iomem *dest, const void *src, ...@@ -292,8 +286,8 @@ extern void _memcpy_toio(volatile void __iomem *dest, const void *src,
*/ */
#ifdef CONFIG_PPC_INDIRECT_MMIO #ifdef CONFIG_PPC_INDIRECT_MMIO
#define PCI_IO_IND_TOKEN_MASK 0x0fff000000000000ul #define PCI_IO_IND_TOKEN_SHIFT 52
#define PCI_IO_IND_TOKEN_SHIFT 48 #define PCI_IO_IND_TOKEN_MASK (0xfful << PCI_IO_IND_TOKEN_SHIFT)
#define PCI_FIX_ADDR(addr) \ #define PCI_FIX_ADDR(addr) \
((PCI_IO_ADDR)(((unsigned long)(addr)) & ~PCI_IO_IND_TOKEN_MASK)) ((PCI_IO_ADDR)(((unsigned long)(addr)) & ~PCI_IO_IND_TOKEN_MASK))
#define PCI_GET_ADDR_TOKEN(addr) \ #define PCI_GET_ADDR_TOKEN(addr) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment