diff options
Diffstat (limited to 'arch/ia64')
-rw-r--r-- | arch/ia64/pci/pci.c | 106 |
1 files changed, 82 insertions, 24 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c index 017cfc3f4789..20d76fae24e8 100644 --- a/arch/ia64/pci/pci.c +++ b/arch/ia64/pci/pci.c | |||
@@ -95,7 +95,7 @@ pci_sal_write (unsigned int seg, unsigned int bus, unsigned int devfn, | |||
95 | } | 95 | } |
96 | 96 | ||
97 | static struct pci_raw_ops pci_sal_ops = { | 97 | static struct pci_raw_ops pci_sal_ops = { |
98 | .read = pci_sal_read, | 98 | .read = pci_sal_read, |
99 | .write = pci_sal_write | 99 | .write = pci_sal_write |
100 | }; | 100 | }; |
101 | 101 | ||
@@ -137,35 +137,98 @@ alloc_pci_controller (int seg) | |||
137 | return controller; | 137 | return controller; |
138 | } | 138 | } |
139 | 139 | ||
140 | static u64 __devinit | 140 | struct pci_root_info { |
141 | add_io_space (struct acpi_resource_address64 *addr) | 141 | struct pci_controller *controller; |
142 | char *name; | ||
143 | }; | ||
144 | |||
145 | static unsigned int | ||
146 | new_space (u64 phys_base, int sparse) | ||
142 | { | 147 | { |
143 | u64 offset; | 148 | u64 mmio_base; |
144 | int sparse = 0; | ||
145 | int i; | 149 | int i; |
146 | 150 | ||
147 | if (addr->address_translation_offset == 0) | 151 | if (phys_base == 0) |
148 | return IO_SPACE_BASE(0); /* part of legacy IO space */ | 152 | return 0; /* legacy I/O port space */ |
149 | |||
150 | if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION) | ||
151 | sparse = 1; | ||
152 | 153 | ||
153 | offset = (u64) ioremap(addr->address_translation_offset, 0); | 154 | mmio_base = (u64) ioremap(phys_base, 0); |
154 | for (i = 0; i < num_io_spaces; i++) | 155 | for (i = 0; i < num_io_spaces; i++) |
155 | if (io_space[i].mmio_base == offset && | 156 | if (io_space[i].mmio_base == mmio_base && |
156 | io_space[i].sparse == sparse) | 157 | io_space[i].sparse == sparse) |
157 | return IO_SPACE_BASE(i); | 158 | return i; |
158 | 159 | ||
159 | if (num_io_spaces == MAX_IO_SPACES) { | 160 | if (num_io_spaces == MAX_IO_SPACES) { |
160 | printk("Too many IO port spaces\n"); | 161 | printk(KERN_ERR "PCI: Too many IO port spaces " |
162 | "(MAX_IO_SPACES=%lu)\n", MAX_IO_SPACES); | ||
161 | return ~0; | 163 | return ~0; |
162 | } | 164 | } |
163 | 165 | ||
164 | i = num_io_spaces++; | 166 | i = num_io_spaces++; |
165 | io_space[i].mmio_base = offset; | 167 | io_space[i].mmio_base = mmio_base; |
166 | io_space[i].sparse = sparse; | 168 | io_space[i].sparse = sparse; |
167 | 169 | ||
168 | return IO_SPACE_BASE(i); | 170 | return i; |
171 | } | ||
172 | |||
173 | static u64 __devinit | ||
174 | add_io_space (struct pci_root_info *info, struct acpi_resource_address64 *addr) | ||
175 | { | ||
176 | struct resource *resource; | ||
177 | char *name; | ||
178 | u64 base, min, max, base_port; | ||
179 | unsigned int sparse = 0, space_nr, len; | ||
180 | |||
181 | resource = kzalloc(sizeof(*resource), GFP_KERNEL); | ||
182 | if (!resource) { | ||
183 | printk(KERN_ERR "PCI: No memory for %s I/O port space\n", | ||
184 | info->name); | ||
185 | goto out; | ||
186 | } | ||
187 | |||
188 | len = strlen(info->name) + 32; | ||
189 | name = kzalloc(len, GFP_KERNEL); | ||
190 | if (!name) { | ||
191 | printk(KERN_ERR "PCI: No memory for %s I/O port space name\n", | ||
192 | info->name); | ||
193 | goto free_resource; | ||
194 | } | ||
195 | |||
196 | min = addr->min_address_range; | ||
197 | max = min + addr->address_length - 1; | ||
198 | if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION) | ||
199 | sparse = 1; | ||
200 | |||
201 | space_nr = new_space(addr->address_translation_offset, sparse); | ||
202 | if (space_nr == ~0) | ||
203 | goto free_name; | ||
204 | |||
205 | base = __pa(io_space[space_nr].mmio_base); | ||
206 | base_port = IO_SPACE_BASE(space_nr); | ||
207 | snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name, | ||
208 | base_port + min, base_port + max); | ||
209 | |||
210 | /* | ||
211 | * The SDM guarantees the legacy 0-64K space is sparse, but if the | ||
212 | * mapping is done by the processor (not the bridge), ACPI may not | ||
213 | * mark it as sparse. | ||
214 | */ | ||
215 | if (space_nr == 0) | ||
216 | sparse = 1; | ||
217 | |||
218 | resource->name = name; | ||
219 | resource->flags = IORESOURCE_MEM; | ||
220 | resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); | ||
221 | resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); | ||
222 | insert_resource(&iomem_resource, resource); | ||
223 | |||
224 | return base_port; | ||
225 | |||
226 | free_name: | ||
227 | kfree(name); | ||
228 | free_resource: | ||
229 | kfree(resource); | ||
230 | out: | ||
231 | return ~0; | ||
169 | } | 232 | } |
170 | 233 | ||
171 | static acpi_status __devinit resource_to_window(struct acpi_resource *resource, | 234 | static acpi_status __devinit resource_to_window(struct acpi_resource *resource, |
@@ -205,11 +268,6 @@ count_window (struct acpi_resource *resource, void *data) | |||
205 | return AE_OK; | 268 | return AE_OK; |
206 | } | 269 | } |
207 | 270 | ||
208 | struct pci_root_info { | ||
209 | struct pci_controller *controller; | ||
210 | char *name; | ||
211 | }; | ||
212 | |||
213 | static __devinit acpi_status add_window(struct acpi_resource *res, void *data) | 271 | static __devinit acpi_status add_window(struct acpi_resource *res, void *data) |
214 | { | 272 | { |
215 | struct pci_root_info *info = data; | 273 | struct pci_root_info *info = data; |
@@ -231,7 +289,7 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data) | |||
231 | } else if (addr.resource_type == ACPI_IO_RANGE) { | 289 | } else if (addr.resource_type == ACPI_IO_RANGE) { |
232 | flags = IORESOURCE_IO; | 290 | flags = IORESOURCE_IO; |
233 | root = &ioport_resource; | 291 | root = &ioport_resource; |
234 | offset = add_io_space(&addr); | 292 | offset = add_io_space(info, &addr); |
235 | if (offset == ~0) | 293 | if (offset == ~0) |
236 | return AE_OK; | 294 | return AE_OK; |
237 | } else | 295 | } else |
@@ -241,7 +299,7 @@ static __devinit acpi_status add_window(struct acpi_resource *res, void *data) | |||
241 | window->resource.name = info->name; | 299 | window->resource.name = info->name; |
242 | window->resource.flags = flags; | 300 | window->resource.flags = flags; |
243 | window->resource.start = addr.min_address_range + offset; | 301 | window->resource.start = addr.min_address_range + offset; |
244 | window->resource.end = addr.max_address_range + offset; | 302 | window->resource.end = window->resource.start + addr.address_length - 1; |
245 | window->resource.child = NULL; | 303 | window->resource.child = NULL; |
246 | window->offset = offset; | 304 | window->offset = offset; |
247 | 305 | ||
@@ -739,7 +797,7 @@ int pci_vector_resources(int last, int nr_released) | |||
739 | { | 797 | { |
740 | int count = nr_released; | 798 | int count = nr_released; |
741 | 799 | ||
742 | count += (IA64_LAST_DEVICE_VECTOR - last); | 800 | count += (IA64_LAST_DEVICE_VECTOR - last); |
743 | 801 | ||
744 | return count; | 802 | return count; |
745 | } | 803 | } |