Commit d9110d3a authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] ppc64: Allow PCI devices to use address that happens to fall in the ISA range

From: Jake Moilanen <moilanen@austin.ibm.com>

Allow PCI devices to use address that happens to fall in the ISA range,
but still protect against ISA device accesses when there is not an ISA
bus.
parent 28532196
...@@ -395,6 +395,12 @@ unsigned long eeh_check_failure(void *token, unsigned long val) ...@@ -395,6 +395,12 @@ unsigned long eeh_check_failure(void *token, unsigned long val)
return val; return val;
} }
/* Make sure we aren't ISA */
if (!strcmp(dn->type, "isa")) {
pci_dev_put(dev);
return val;
}
if (!dn->eeh_config_addr) { if (!dn->eeh_config_addr) {
pci_dev_put(dev); pci_dev_put(dev);
return val; return val;
......
...@@ -44,6 +44,12 @@ ...@@ -44,6 +44,12 @@
#include "open_pic.h" #include "open_pic.h"
#include "pci.h" #include "pci.h"
/* legal IO pages under MAX_ISA_PORT. This is to ensure we don't touch
devices we don't have access to. */
unsigned long io_page_mask;
EXPORT_SYMBOL(io_page_mask);
/* RTAS tokens */ /* RTAS tokens */
static int read_pci_config; static int read_pci_config;
static int write_pci_config; static int write_pci_config;
...@@ -280,6 +286,8 @@ static void __init pci_process_bridge_OF_ranges(struct pci_controller *hose, ...@@ -280,6 +286,8 @@ static void __init pci_process_bridge_OF_ranges(struct pci_controller *hose,
pci_process_ISA_OF_ranges(isa_dn, pci_process_ISA_OF_ranges(isa_dn,
hose->io_base_phys, hose->io_base_phys,
hose->io_base_virt); hose->io_base_virt);
/* Allow all IO */
io_page_mask = -1;
} }
} }
...@@ -523,8 +531,24 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, ...@@ -523,8 +531,24 @@ void __devinit pcibios_fixup_device_resources(struct pci_dev *dev,
for (i = 0; i < PCI_NUM_RESOURCES; i++) { for (i = 0; i < PCI_NUM_RESOURCES; i++) {
if (dev->resource[i].flags & IORESOURCE_IO) { if (dev->resource[i].flags & IORESOURCE_IO) {
unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base; unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
dev->resource[i].start += offset; unsigned long start, end, mask;
dev->resource[i].end += offset;
start = dev->resource[i].start += offset;
end = dev->resource[i].end += offset;
/* Need to allow IO access to pages that are in the
ISA range */
if (start < MAX_ISA_PORT) {
if (end > MAX_ISA_PORT)
end = MAX_ISA_PORT;
start >>= PAGE_SHIFT;
end >>= PAGE_SHIFT;
/* get the range of pages for the map */
mask = ((1 << (end+1))-1) ^ ((1 << start)-1);
io_page_mask |= mask;
}
} }
else if (dev->resource[i].flags & IORESOURCE_MEM) { else if (dev->resource[i].flags & IORESOURCE_MEM) {
dev->resource[i].start += hose->pci_mem_offset; dev->resource[i].start += hose->pci_mem_offset;
......
...@@ -199,74 +199,71 @@ static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) { ...@@ -199,74 +199,71 @@ static inline void eeh_memcpy_toio(void *dest, void *src, unsigned long n) {
memcpy(vdest, src, n); memcpy(vdest, src, n);
} }
/* The I/O macros must handle ISA ports as well as PCI I/O bars. #define MAX_ISA_PORT 0x10000
* ISA does not implement EEH and ISA may not exist in the system. extern unsigned long io_page_mask;
* For PCI we check for EEH failures. #define _IO_IS_VALID(port) ((port) >= MAX_ISA_PORT || (1 << (port>>PAGE_SHIFT)) & io_page_mask)
*/
#define _IO_IS_ISA(port) ((port) < 0x10000)
#define _IO_HAS_ISA_BUS (isa_io_base != 0)
static inline u8 eeh_inb(unsigned long port) { static inline u8 eeh_inb(unsigned long port) {
u8 val; u8 val;
if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS) if (!_IO_IS_VALID(port))
return ~0; return ~0;
val = in_8((u8 *)(port+pci_io_base)); val = in_8((u8 *)(port+pci_io_base));
if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u8)) if (EEH_POSSIBLE_IO_ERROR(val, u8))
return eeh_check_failure((void*)(port), val); return eeh_check_failure((void*)(port), val);
return val; return val;
} }
static inline void eeh_outb(u8 val, unsigned long port) { static inline void eeh_outb(u8 val, unsigned long port) {
if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS) if (_IO_IS_VALID(port))
return out_8((u8 *)(port+pci_io_base), val); return out_8((u8 *)(port+pci_io_base), val);
} }
static inline u16 eeh_inw(unsigned long port) { static inline u16 eeh_inw(unsigned long port) {
u16 val; u16 val;
if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS) if (!_IO_IS_VALID(port))
return ~0; return ~0;
val = in_le16((u16 *)(port+pci_io_base)); val = in_le16((u16 *)(port+pci_io_base));
if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u16)) if (EEH_POSSIBLE_IO_ERROR(val, u16))
return eeh_check_failure((void*)(port), val); return eeh_check_failure((void*)(port), val);
return val; return val;
} }
static inline void eeh_outw(u16 val, unsigned long port) { static inline void eeh_outw(u16 val, unsigned long port) {
if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS) if (_IO_IS_VALID(port))
return out_le16((u16 *)(port+pci_io_base), val); return out_le16((u16 *)(port+pci_io_base), val);
} }
static inline u32 eeh_inl(unsigned long port) { static inline u32 eeh_inl(unsigned long port) {
u32 val; u32 val;
if (_IO_IS_ISA(port) && !_IO_HAS_ISA_BUS) if (!_IO_IS_VALID(port))
return ~0; return ~0;
val = in_le32((u32 *)(port+pci_io_base)); val = in_le32((u32 *)(port+pci_io_base));
if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR(val, u32)) if (EEH_POSSIBLE_IO_ERROR(val, u32))
return eeh_check_failure((void*)(port), val); return eeh_check_failure((void*)(port), val);
return val; return val;
} }
static inline void eeh_outl(u32 val, unsigned long port) { static inline void eeh_outl(u32 val, unsigned long port) {
if (!_IO_IS_ISA(port) || _IO_HAS_ISA_BUS) if (_IO_IS_VALID(port))
return out_le32((u32 *)(port+pci_io_base), val); return out_le32((u32 *)(port+pci_io_base), val);
} }
/* in-string eeh macros */ /* in-string eeh macros */
static inline void eeh_insb(unsigned long port, void * buf, int ns) { static inline void eeh_insb(unsigned long port, void * buf, int ns) {
_insb((u8 *)(port+pci_io_base), buf, ns); _insb((u8 *)(port+pci_io_base), buf, ns);
if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR((*(((u8*)buf)+ns-1)), u8)) if (EEH_POSSIBLE_IO_ERROR((*(((u8*)buf)+ns-1)), u8))
eeh_check_failure((void*)(port), *(u8*)buf); eeh_check_failure((void*)(port), *(u8*)buf);
} }
static inline void eeh_insw_ns(unsigned long port, void * buf, int ns) { static inline void eeh_insw_ns(unsigned long port, void * buf, int ns) {
_insw_ns((u16 *)(port+pci_io_base), buf, ns); _insw_ns((u16 *)(port+pci_io_base), buf, ns);
if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR((*(((u16*)buf)+ns-1)), u16)) if (EEH_POSSIBLE_IO_ERROR((*(((u16*)buf)+ns-1)), u16))
eeh_check_failure((void*)(port), *(u16*)buf); eeh_check_failure((void*)(port), *(u16*)buf);
} }
static inline void eeh_insl_ns(unsigned long port, void * buf, int nl) { static inline void eeh_insl_ns(unsigned long port, void * buf, int nl) {
_insl_ns((u32 *)(port+pci_io_base), buf, nl); _insl_ns((u32 *)(port+pci_io_base), buf, nl);
if (!_IO_IS_ISA(port) && EEH_POSSIBLE_IO_ERROR((*(((u32*)buf)+nl-1)), u32)) if (EEH_POSSIBLE_IO_ERROR((*(((u32*)buf)+nl-1)), u32))
eeh_check_failure((void*)(port), *(u32*)buf); eeh_check_failure((void*)(port), *(u32*)buf);
} }
......
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