diff options
author | Tomasz Nowicki <tn@semihalf.com> | 2016-05-11 18:34:51 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2016-05-12 08:07:42 -0400 |
commit | c5076cfe768998e9d395bc8486b29b18b0f99fd9 (patch) | |
tree | 94eaff672e0871147c33abf16edcbf0843078e25 /drivers/pci/pci.c | |
parent | 1958e7173df14ff50d75ed2fbd24b349d25caf80 (diff) |
PCI, of: Move PCI I/O space management to PCI core code
No functional changes in this patch.
PCI I/O space mapping code does not depend on OF; therefore it can be moved
to PCI core code. This way we will be able to use it, e.g., in ACPI PCI
code.
Suggested-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Tomasz Nowicki <tn@semihalf.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Liviu Dudau <Liviu.Dudau@arm.com>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r-- | drivers/pci/pci.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 25e0327d4429..bc0c914b8afc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -3021,6 +3021,121 @@ int pci_request_regions_exclusive(struct pci_dev *pdev, const char *res_name) | |||
3021 | } | 3021 | } |
3022 | EXPORT_SYMBOL(pci_request_regions_exclusive); | 3022 | EXPORT_SYMBOL(pci_request_regions_exclusive); |
3023 | 3023 | ||
3024 | #ifdef PCI_IOBASE | ||
3025 | struct io_range { | ||
3026 | struct list_head list; | ||
3027 | phys_addr_t start; | ||
3028 | resource_size_t size; | ||
3029 | }; | ||
3030 | |||
3031 | static LIST_HEAD(io_range_list); | ||
3032 | static DEFINE_SPINLOCK(io_range_lock); | ||
3033 | #endif | ||
3034 | |||
3035 | /* | ||
3036 | * Record the PCI IO range (expressed as CPU physical address + size). | ||
3037 | * Return a negative value if an error has occured, zero otherwise | ||
3038 | */ | ||
3039 | int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size) | ||
3040 | { | ||
3041 | int err = 0; | ||
3042 | |||
3043 | #ifdef PCI_IOBASE | ||
3044 | struct io_range *range; | ||
3045 | resource_size_t allocated_size = 0; | ||
3046 | |||
3047 | /* check if the range hasn't been previously recorded */ | ||
3048 | spin_lock(&io_range_lock); | ||
3049 | list_for_each_entry(range, &io_range_list, list) { | ||
3050 | if (addr >= range->start && addr + size <= range->start + size) { | ||
3051 | /* range already registered, bail out */ | ||
3052 | goto end_register; | ||
3053 | } | ||
3054 | allocated_size += range->size; | ||
3055 | } | ||
3056 | |||
3057 | /* range not registed yet, check for available space */ | ||
3058 | if (allocated_size + size - 1 > IO_SPACE_LIMIT) { | ||
3059 | /* if it's too big check if 64K space can be reserved */ | ||
3060 | if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) { | ||
3061 | err = -E2BIG; | ||
3062 | goto end_register; | ||
3063 | } | ||
3064 | |||
3065 | size = SZ_64K; | ||
3066 | pr_warn("Requested IO range too big, new size set to 64K\n"); | ||
3067 | } | ||
3068 | |||
3069 | /* add the range to the list */ | ||
3070 | range = kzalloc(sizeof(*range), GFP_ATOMIC); | ||
3071 | if (!range) { | ||
3072 | err = -ENOMEM; | ||
3073 | goto end_register; | ||
3074 | } | ||
3075 | |||
3076 | range->start = addr; | ||
3077 | range->size = size; | ||
3078 | |||
3079 | list_add_tail(&range->list, &io_range_list); | ||
3080 | |||
3081 | end_register: | ||
3082 | spin_unlock(&io_range_lock); | ||
3083 | #endif | ||
3084 | |||
3085 | return err; | ||
3086 | } | ||
3087 | |||
3088 | phys_addr_t pci_pio_to_address(unsigned long pio) | ||
3089 | { | ||
3090 | phys_addr_t address = (phys_addr_t)OF_BAD_ADDR; | ||
3091 | |||
3092 | #ifdef PCI_IOBASE | ||
3093 | struct io_range *range; | ||
3094 | resource_size_t allocated_size = 0; | ||
3095 | |||
3096 | if (pio > IO_SPACE_LIMIT) | ||
3097 | return address; | ||
3098 | |||
3099 | spin_lock(&io_range_lock); | ||
3100 | list_for_each_entry(range, &io_range_list, list) { | ||
3101 | if (pio >= allocated_size && pio < allocated_size + range->size) { | ||
3102 | address = range->start + pio - allocated_size; | ||
3103 | break; | ||
3104 | } | ||
3105 | allocated_size += range->size; | ||
3106 | } | ||
3107 | spin_unlock(&io_range_lock); | ||
3108 | #endif | ||
3109 | |||
3110 | return address; | ||
3111 | } | ||
3112 | |||
3113 | unsigned long __weak pci_address_to_pio(phys_addr_t address) | ||
3114 | { | ||
3115 | #ifdef PCI_IOBASE | ||
3116 | struct io_range *res; | ||
3117 | resource_size_t offset = 0; | ||
3118 | unsigned long addr = -1; | ||
3119 | |||
3120 | spin_lock(&io_range_lock); | ||
3121 | list_for_each_entry(res, &io_range_list, list) { | ||
3122 | if (address >= res->start && address < res->start + res->size) { | ||
3123 | addr = address - res->start + offset; | ||
3124 | break; | ||
3125 | } | ||
3126 | offset += res->size; | ||
3127 | } | ||
3128 | spin_unlock(&io_range_lock); | ||
3129 | |||
3130 | return addr; | ||
3131 | #else | ||
3132 | if (address > IO_SPACE_LIMIT) | ||
3133 | return (unsigned long)-1; | ||
3134 | |||
3135 | return (unsigned long) address; | ||
3136 | #endif | ||
3137 | } | ||
3138 | |||
3024 | /** | 3139 | /** |
3025 | * pci_remap_iospace - Remap the memory mapped I/O space | 3140 | * pci_remap_iospace - Remap the memory mapped I/O space |
3026 | * @res: Resource describing the I/O space | 3141 | * @res: Resource describing the I/O space |