Skip to content

Commit

Permalink
pci_iounmap'2: Electric Boogaloo: try to make sense of it all
Browse files Browse the repository at this point in the history
Nathan Chancellor reports that the recent change to pci_iounmap in
commit 9caea00 ("parisc: Declare pci_iounmap() parisc version only
when CONFIG_PCI enabled") causes build errors on arm64.

It took me about two hours to convince myself that I think I know what
the logic of that mess of #ifdef's in the <asm-generic/io.h> header file
really aim to do, and rewrite it to be easier to follow.

Famous last words.

Anyway, the code has now been lifted from that grotty header file into
lib/pci_iomap.c, and has fairly extensive comments about what the logic
is.  It also avoids indirecting through another confusing (and badly
named) helper function that has other preprocessor config conditionals.

Let's see what odd architecture did something else strange in this area
to break things.  But my arm64 cross build is clean.

Fixes: 9caea00 ("parisc: Declare pci_iounmap() parisc version only when CONFIG_PCI enabled")
Reported-by: Nathan Chancellor <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: Arnd Bergmann <[email protected]>
Cc: Guenter Roeck <[email protected]>
Cc: Ulrich Teichert <[email protected]>
Cc: James Bottomley <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
torvalds committed Sep 20, 2021
1 parent 20621d2 commit 316e8d7
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 23 deletions.
26 changes: 3 additions & 23 deletions include/asm-generic/io.h
Original file line number Diff line number Diff line change
Expand Up @@ -1023,16 +1023,7 @@ static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
port &= IO_SPACE_LIMIT;
return (port > MMIO_UPPER_LIMIT) ? NULL : PCI_IOBASE + port;
}
#define __pci_ioport_unmap __pci_ioport_unmap
static inline void __pci_ioport_unmap(void __iomem *p)
{
uintptr_t start = (uintptr_t) PCI_IOBASE;
uintptr_t addr = (uintptr_t) p;

if (addr >= start && addr < start + IO_SPACE_LIMIT)
return;
iounmap(p);
}
#define ARCH_HAS_GENERIC_IOPORT_MAP
#endif

#ifndef ioport_unmap
Expand All @@ -1048,21 +1039,10 @@ extern void ioport_unmap(void __iomem *p);
#endif /* CONFIG_HAS_IOPORT_MAP */

#ifndef CONFIG_GENERIC_IOMAP
struct pci_dev;
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);

#ifndef __pci_ioport_unmap
static inline void __pci_ioport_unmap(void __iomem *p) {}
#endif

#ifndef pci_iounmap
#define pci_iounmap pci_iounmap
static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
{
__pci_ioport_unmap(p);
}
#define ARCH_WANTS_GENERIC_PCI_IOUNMAP
#endif
#endif
#endif /* CONFIG_GENERIC_IOMAP */

#ifndef xlate_dev_mem_ptr
#define xlate_dev_mem_ptr xlate_dev_mem_ptr
Expand Down
43 changes: 43 additions & 0 deletions lib/pci_iomap.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,47 @@ void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long maxlen)
return pci_iomap_wc_range(dev, bar, 0, maxlen);
}
EXPORT_SYMBOL_GPL(pci_iomap_wc);

/*
* pci_iounmap() somewhat illogically comes from lib/iomap.c for the
* CONFIG_GENERIC_IOMAP case, because that's the code that knows about
* the different IOMAP ranges.
*
* But if the architecture does not use the generic iomap code, and if
* it has _not_ defined it's own private pci_iounmap function, we define
* it here.
*
* NOTE! This default implementation assumes that if the architecture
* support ioport mapping (HAS_IOPORT_MAP), the ioport mapping will
* be fixed to the range [ PCI_IOBASE, PCI_IOBASE+IO_SPACE_LIMIT [,
* and does not need unmapping with 'ioport_unmap()'.
*
* If you have different rules for your architecture, you need to
* implement your own pci_iounmap() that knows the rules for where
* and how IO vs MEM get mapped.
*
* This code is odd, and the ARCH_HAS/ARCH_WANTS #define logic comes
* from legacy <asm-generic/io.h> header file behavior. In particular,
* it would seem to make sense to do the iounmap(p) for the non-IO-space
* case here regardless, but that's not what the old header file code
* did. Probably incorrectly, but this is meant to be bug-for-bug
* compatible.
*/
#if defined(ARCH_WANTS_GENERIC_PCI_IOUNMAP)

void pci_iounmap(struct pci_dev *dev, void __iomem *p)
{
#ifdef ARCH_HAS_GENERIC_IOPORT_MAP
uintptr_t start = (uintptr_t) PCI_IOBASE;
uintptr_t addr = (uintptr_t) p;

if (addr >= start && addr < start + IO_SPACE_LIMIT)
return;
iounmap(p);
#endif
}
EXPORT_SYMBOL(pci_iounmap);

#endif /* ARCH_WANTS_GENERIC_PCI_IOUNMAP */

#endif /* CONFIG_PCI */

0 comments on commit 316e8d7

Please sign in to comment.