Blame view

lib/devres.c 12.3 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
f4a18312f   Thierry Reding   lib: devres: Fix ...
2
  #include <linux/err.h>
5ea817699   Al Viro   [PATCH] sort the ...
3
4
  #include <linux/pci.h>
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
5
  #include <linux/gfp.h>
8bc3bcc93   Paul Gortmaker   lib: reduce the u...
6
  #include <linux/export.h>
d5e838275   Benjamin Herrenschmidt   devres: Add devm_...
7
  #include <linux/of_address.h>
5ea817699   Al Viro   [PATCH] sort the ...
8

1b723413a   Yisheng Xie   devres: combine f...
9
10
  enum devm_ioremap_type {
  	DEVM_IOREMAP = 0,
e537654b7   Tuowen Zhao   lib: devres: add ...
11
  	DEVM_IOREMAP_UC,
1b723413a   Yisheng Xie   devres: combine f...
12
13
  	DEVM_IOREMAP_WC,
  };
b41e5fffe   Emil Medve   [POWERPC] devres:...
14
  void devm_ioremap_release(struct device *dev, void *res)
5ea817699   Al Viro   [PATCH] sort the ...
15
16
17
18
19
20
21
22
  {
  	iounmap(*(void __iomem **)res);
  }
  
  static int devm_ioremap_match(struct device *dev, void *res, void *match_data)
  {
  	return *(void **)res == match_data;
  }
1b723413a   Yisheng Xie   devres: combine f...
23
24
25
  static void __iomem *__devm_ioremap(struct device *dev, resource_size_t offset,
  				    resource_size_t size,
  				    enum devm_ioremap_type type)
5ea817699   Al Viro   [PATCH] sort the ...
26
  {
1b723413a   Yisheng Xie   devres: combine f...
27
  	void __iomem **ptr, *addr = NULL;
5ea817699   Al Viro   [PATCH] sort the ...
28
29
30
31
  
  	ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL);
  	if (!ptr)
  		return NULL;
1b723413a   Yisheng Xie   devres: combine f...
32
33
34
35
  	switch (type) {
  	case DEVM_IOREMAP:
  		addr = ioremap(offset, size);
  		break;
e537654b7   Tuowen Zhao   lib: devres: add ...
36
37
38
  	case DEVM_IOREMAP_UC:
  		addr = ioremap_uc(offset, size);
  		break;
1b723413a   Yisheng Xie   devres: combine f...
39
40
41
42
  	case DEVM_IOREMAP_WC:
  		addr = ioremap_wc(offset, size);
  		break;
  	}
5ea817699   Al Viro   [PATCH] sort the ...
43
44
45
46
47
48
49
50
  	if (addr) {
  		*ptr = addr;
  		devres_add(dev, ptr);
  	} else
  		devres_free(ptr);
  
  	return addr;
  }
1b723413a   Yisheng Xie   devres: combine f...
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  
  /**
   * devm_ioremap - Managed ioremap()
   * @dev: Generic device to remap IO address for
   * @offset: Resource address to map
   * @size: Size of map
   *
   * Managed ioremap().  Map is automatically unmapped on driver detach.
   */
  void __iomem *devm_ioremap(struct device *dev, resource_size_t offset,
  			   resource_size_t size)
  {
  	return __devm_ioremap(dev, offset, size, DEVM_IOREMAP);
  }
5ea817699   Al Viro   [PATCH] sort the ...
65
66
67
  EXPORT_SYMBOL(devm_ioremap);
  
  /**
e537654b7   Tuowen Zhao   lib: devres: add ...
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
   * devm_ioremap_uc - Managed ioremap_uc()
   * @dev: Generic device to remap IO address for
   * @offset: Resource address to map
   * @size: Size of map
   *
   * Managed ioremap_uc().  Map is automatically unmapped on driver detach.
   */
  void __iomem *devm_ioremap_uc(struct device *dev, resource_size_t offset,
  			      resource_size_t size)
  {
  	return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_UC);
  }
  EXPORT_SYMBOL_GPL(devm_ioremap_uc);
  
  /**
34644524b   Abhilash Kesavan   lib: devres: add ...
83
84
   * devm_ioremap_wc - Managed ioremap_wc()
   * @dev: Generic device to remap IO address for
6524754ef   Lorenzo Pieralisi   devres: fix devm_...
85
   * @offset: Resource address to map
34644524b   Abhilash Kesavan   lib: devres: add ...
86
87
88
89
90
91
92
   * @size: Size of map
   *
   * Managed ioremap_wc().  Map is automatically unmapped on driver detach.
   */
  void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset,
  			      resource_size_t size)
  {
1b723413a   Yisheng Xie   devres: combine f...
93
  	return __devm_ioremap(dev, offset, size, DEVM_IOREMAP_WC);
34644524b   Abhilash Kesavan   lib: devres: add ...
94
95
96
97
  }
  EXPORT_SYMBOL(devm_ioremap_wc);
  
  /**
5ea817699   Al Viro   [PATCH] sort the ...
98
99
100
101
102
103
104
105
   * devm_iounmap - Managed iounmap()
   * @dev: Generic device to unmap for
   * @addr: Address to unmap
   *
   * Managed iounmap().  @addr must have been mapped using devm_ioremap*().
   */
  void devm_iounmap(struct device *dev, void __iomem *addr)
  {
5ea817699   Al Viro   [PATCH] sort the ...
106
  	WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match,
b104d6a5a   Steven Rostedt   lib/devres.c: fix...
107
  			       (__force void *)addr));
ae891a1b9   Maxin B John   devres: fix possi...
108
  	iounmap(addr);
5ea817699   Al Viro   [PATCH] sort the ...
109
110
  }
  EXPORT_SYMBOL(devm_iounmap);
6e9248227   Bartosz Golaszewski   lib: devres: prep...
111
112
113
  static void __iomem *
  __devm_ioremap_resource(struct device *dev, const struct resource *res,
  			enum devm_ioremap_type type)
72f8c0bfa   Wolfram Sang   lib: devres: add ...
114
115
  {
  	resource_size_t size;
72f8c0bfa   Wolfram Sang   lib: devres: add ...
116
  	void __iomem *dest_ptr;
35bd8c07d   Vladimir Oltean   devres: keep both...
117
  	char *pretty_name;
72f8c0bfa   Wolfram Sang   lib: devres: add ...
118
119
120
121
122
123
  
  	BUG_ON(!dev);
  
  	if (!res || resource_type(res) != IORESOURCE_MEM) {
  		dev_err(dev, "invalid resource
  ");
b104d6a5a   Steven Rostedt   lib/devres.c: fix...
124
  		return IOMEM_ERR_PTR(-EINVAL);
72f8c0bfa   Wolfram Sang   lib: devres: add ...
125
126
127
  	}
  
  	size = resource_size(res);
72f8c0bfa   Wolfram Sang   lib: devres: add ...
128

35bd8c07d   Vladimir Oltean   devres: keep both...
129
130
131
132
133
134
135
136
137
  	if (res->name)
  		pretty_name = devm_kasprintf(dev, GFP_KERNEL, "%s %s",
  					     dev_name(dev), res->name);
  	else
  		pretty_name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL);
  	if (!pretty_name)
  		return IOMEM_ERR_PTR(-ENOMEM);
  
  	if (!devm_request_mem_region(dev, res->start, size, pretty_name)) {
72f8c0bfa   Wolfram Sang   lib: devres: add ...
138
139
  		dev_err(dev, "can't request region for resource %pR
  ", res);
b104d6a5a   Steven Rostedt   lib/devres.c: fix...
140
  		return IOMEM_ERR_PTR(-EBUSY);
72f8c0bfa   Wolfram Sang   lib: devres: add ...
141
  	}
6e9248227   Bartosz Golaszewski   lib: devres: prep...
142
  	dest_ptr = __devm_ioremap(dev, res->start, size, type);
72f8c0bfa   Wolfram Sang   lib: devres: add ...
143
144
145
146
  	if (!dest_ptr) {
  		dev_err(dev, "ioremap failed for resource %pR
  ", res);
  		devm_release_mem_region(dev, res->start, size);
b104d6a5a   Steven Rostedt   lib/devres.c: fix...
147
  		dest_ptr = IOMEM_ERR_PTR(-ENOMEM);
72f8c0bfa   Wolfram Sang   lib: devres: add ...
148
149
150
151
  	}
  
  	return dest_ptr;
  }
6e9248227   Bartosz Golaszewski   lib: devres: prep...
152
153
154
155
156
157
158
159
160
161
  
  /**
   * devm_ioremap_resource() - check, request region, and ioremap resource
   * @dev: generic device to handle the resource for
   * @res: resource to be handled
   *
   * Checks that a resource is a valid memory region, requests the memory
   * region and ioremaps it. All operations are managed and will be undone
   * on driver detach.
   *
0c7a6b91d   Stephen Boyd   driver core: plat...
162
   * Usage example:
6e9248227   Bartosz Golaszewski   lib: devres: prep...
163
164
165
166
167
   *
   *	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
   *	base = devm_ioremap_resource(&pdev->dev, res);
   *	if (IS_ERR(base))
   *		return PTR_ERR(base);
0c7a6b91d   Stephen Boyd   driver core: plat...
168
169
170
   *
   * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
   * on failure.
6e9248227   Bartosz Golaszewski   lib: devres: prep...
171
172
173
174
175
176
   */
  void __iomem *devm_ioremap_resource(struct device *dev,
  				    const struct resource *res)
  {
  	return __devm_ioremap_resource(dev, res, DEVM_IOREMAP);
  }
75096579c   Thierry Reding   lib: devres: Intr...
177
  EXPORT_SYMBOL(devm_ioremap_resource);
b873af620   Bartosz Golaszewski   lib: devres: prov...
178
179
180
181
182
183
  /**
   * devm_ioremap_resource_wc() - write-combined variant of
   *				devm_ioremap_resource()
   * @dev: generic device to handle the resource for
   * @res: resource to be handled
   *
0c7a6b91d   Stephen Boyd   driver core: plat...
184
185
   * Return: a pointer to the remapped memory or an ERR_PTR() encoded error code
   * on failure.
b873af620   Bartosz Golaszewski   lib: devres: prov...
186
187
188
189
190
191
   */
  void __iomem *devm_ioremap_resource_wc(struct device *dev,
  				       const struct resource *res)
  {
  	return __devm_ioremap_resource(dev, res, DEVM_IOREMAP_WC);
  }
d5e838275   Benjamin Herrenschmidt   devres: Add devm_...
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  /*
   * devm_of_iomap - Requests a resource and maps the memory mapped IO
   *		   for a given device_node managed by a given device
   *
   * Checks that a resource is a valid memory region, requests the memory
   * region and ioremaps it. All operations are managed and will be undone
   * on driver detach of the device.
   *
   * This is to be used when a device requests/maps resources described
   * by other device tree nodes (children or otherwise).
   *
   * @dev:	The device "managing" the resource
   * @node:       The device-tree node where the resource resides
   * @index:	index of the MMIO range in the "reg" property
   * @size:	Returns the size of the resource (pass NULL if not needed)
0c7a6b91d   Stephen Boyd   driver core: plat...
207
208
   *
   * Usage example:
d5e838275   Benjamin Herrenschmidt   devres: Add devm_...
209
210
211
212
   *
   *	base = devm_of_iomap(&pdev->dev, node, 0, NULL);
   *	if (IS_ERR(base))
   *		return PTR_ERR(base);
7ae731a84   Dan Carpenter   lib: devres: add ...
213
214
215
216
   *
   * Please Note: This is not a one-to-one replacement for of_iomap() because the
   * of_iomap() function does not track whether the region is already mapped.  If
   * two drivers try to map the same memory, the of_iomap() function will succeed
28d9fdf04   Randy Dunlap   lib: devres: dele...
217
   * but the devm_of_iomap() function will return -EBUSY.
7ae731a84   Dan Carpenter   lib: devres: add ...
218
   *
0c7a6b91d   Stephen Boyd   driver core: plat...
219
220
   * Return: a pointer to the requested and mapped memory or an ERR_PTR() encoded
   * error code on failure.
d5e838275   Benjamin Herrenschmidt   devres: Add devm_...
221
222
223
224
225
226
227
228
229
230
231
232
233
   */
  void __iomem *devm_of_iomap(struct device *dev, struct device_node *node, int index,
  			    resource_size_t *size)
  {
  	struct resource res;
  
  	if (of_address_to_resource(node, index, &res))
  		return IOMEM_ERR_PTR(-EINVAL);
  	if (size)
  		*size = resource_size(&res);
  	return devm_ioremap_resource(dev, &res);
  }
  EXPORT_SYMBOL(devm_of_iomap);
ce816fa88   Uwe Kleine-König   Kconfig: rename H...
234
  #ifdef CONFIG_HAS_IOPORT_MAP
5ea817699   Al Viro   [PATCH] sort the ...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  /*
   * Generic iomap devres
   */
  static void devm_ioport_map_release(struct device *dev, void *res)
  {
  	ioport_unmap(*(void __iomem **)res);
  }
  
  static int devm_ioport_map_match(struct device *dev, void *res,
  				 void *match_data)
  {
  	return *(void **)res == match_data;
  }
  
  /**
   * devm_ioport_map - Managed ioport_map()
   * @dev: Generic device to map ioport for
   * @port: Port to map
   * @nr: Number of ports to map
   *
   * Managed ioport_map().  Map is automatically unmapped on driver
   * detach.
0c7a6b91d   Stephen Boyd   driver core: plat...
257
258
   *
   * Return: a pointer to the remapped memory or NULL on failure.
5ea817699   Al Viro   [PATCH] sort the ...
259
   */
5cbb00cc4   Fabian Frederick   lib/devres.c: fix...
260
  void __iomem *devm_ioport_map(struct device *dev, unsigned long port,
5ea817699   Al Viro   [PATCH] sort the ...
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  			       unsigned int nr)
  {
  	void __iomem **ptr, *addr;
  
  	ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL);
  	if (!ptr)
  		return NULL;
  
  	addr = ioport_map(port, nr);
  	if (addr) {
  		*ptr = addr;
  		devres_add(dev, ptr);
  	} else
  		devres_free(ptr);
  
  	return addr;
  }
  EXPORT_SYMBOL(devm_ioport_map);
  
  /**
   * devm_ioport_unmap - Managed ioport_unmap()
   * @dev: Generic device to unmap for
   * @addr: Address to unmap
   *
   * Managed ioport_unmap().  @addr must have been mapped using
   * devm_ioport_map().
   */
  void devm_ioport_unmap(struct device *dev, void __iomem *addr)
  {
  	ioport_unmap(addr);
  	WARN_ON(devres_destroy(dev, devm_ioport_map_release,
b104d6a5a   Steven Rostedt   lib/devres.c: fix...
292
  			       devm_ioport_map_match, (__force void *)addr));
5ea817699   Al Viro   [PATCH] sort the ...
293
294
  }
  EXPORT_SYMBOL(devm_ioport_unmap);
ce816fa88   Uwe Kleine-König   Kconfig: rename H...
295
  #endif /* CONFIG_HAS_IOPORT_MAP */
5ea817699   Al Viro   [PATCH] sort the ...
296
297
298
299
300
  
  #ifdef CONFIG_PCI
  /*
   * PCI iomap devres
   */
c9c13ba42   Denis Efremov   PCI: Add PCI_STD_...
301
  #define PCIM_IOMAP_MAX	PCI_STD_NUM_BARS
5ea817699   Al Viro   [PATCH] sort the ...
302
303
304
305
306
307
308
  
  struct pcim_iomap_devres {
  	void __iomem *table[PCIM_IOMAP_MAX];
  };
  
  static void pcim_iomap_release(struct device *gendev, void *res)
  {
20af74ef1   Geliang Tang   devres: use to_pc...
309
  	struct pci_dev *dev = to_pci_dev(gendev);
5ea817699   Al Viro   [PATCH] sort the ...
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
  	struct pcim_iomap_devres *this = res;
  	int i;
  
  	for (i = 0; i < PCIM_IOMAP_MAX; i++)
  		if (this->table[i])
  			pci_iounmap(dev, this->table[i]);
  }
  
  /**
   * pcim_iomap_table - access iomap allocation table
   * @pdev: PCI device to access iomap table for
   *
   * Access iomap allocation table for @dev.  If iomap table doesn't
   * exist and @pdev is managed, it will be allocated.  All iomaps
   * recorded in the iomap table are automatically unmapped on driver
   * detach.
   *
   * This function might sleep when the table is first allocated but can
   * be safely called without context and guaranteed to succed once
   * allocated.
   */
5cbb00cc4   Fabian Frederick   lib/devres.c: fix...
331
  void __iomem * const *pcim_iomap_table(struct pci_dev *pdev)
5ea817699   Al Viro   [PATCH] sort the ...
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  {
  	struct pcim_iomap_devres *dr, *new_dr;
  
  	dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL);
  	if (dr)
  		return dr->table;
  
  	new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL);
  	if (!new_dr)
  		return NULL;
  	dr = devres_get(&pdev->dev, new_dr, NULL, NULL);
  	return dr->table;
  }
  EXPORT_SYMBOL(pcim_iomap_table);
  
  /**
   * pcim_iomap - Managed pcim_iomap()
   * @pdev: PCI device to iomap for
   * @bar: BAR to iomap
   * @maxlen: Maximum length of iomap
   *
   * Managed pci_iomap().  Map is automatically unmapped on driver
   * detach.
   */
5cbb00cc4   Fabian Frederick   lib/devres.c: fix...
356
  void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen)
5ea817699   Al Viro   [PATCH] sort the ...
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
  {
  	void __iomem **tbl;
  
  	BUG_ON(bar >= PCIM_IOMAP_MAX);
  
  	tbl = (void __iomem **)pcim_iomap_table(pdev);
  	if (!tbl || tbl[bar])	/* duplicate mappings not allowed */
  		return NULL;
  
  	tbl[bar] = pci_iomap(pdev, bar, maxlen);
  	return tbl[bar];
  }
  EXPORT_SYMBOL(pcim_iomap);
  
  /**
   * pcim_iounmap - Managed pci_iounmap()
   * @pdev: PCI device to iounmap for
   * @addr: Address to unmap
   *
   * Managed pci_iounmap().  @addr must have been mapped using pcim_iomap().
   */
  void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr)
  {
  	void __iomem **tbl;
  	int i;
  
  	pci_iounmap(pdev, addr);
  
  	tbl = (void __iomem **)pcim_iomap_table(pdev);
  	BUG_ON(!tbl);
  
  	for (i = 0; i < PCIM_IOMAP_MAX; i++)
  		if (tbl[i] == addr) {
  			tbl[i] = NULL;
  			return;
  		}
  	WARN_ON(1);
  }
  EXPORT_SYMBOL(pcim_iounmap);
  
  /**
   * pcim_iomap_regions - Request and iomap PCI BARs
   * @pdev: PCI device to map IO resources for
   * @mask: Mask of BARs to request and iomap
   * @name: Name used when requesting regions
   *
   * Request and iomap regions specified by @mask.
   */
fb7ebfe41   Yinghai Lu   PCI: Increase res...
405
  int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name)
5ea817699   Al Viro   [PATCH] sort the ...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
  {
  	void __iomem * const *iomap;
  	int i, rc;
  
  	iomap = pcim_iomap_table(pdev);
  	if (!iomap)
  		return -ENOMEM;
  
  	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
  		unsigned long len;
  
  		if (!(mask & (1 << i)))
  			continue;
  
  		rc = -EINVAL;
  		len = pci_resource_len(pdev, i);
  		if (!len)
  			goto err_inval;
  
  		rc = pci_request_region(pdev, i, name);
  		if (rc)
fb4d64e78   Frederik Deweerdt   [PATCH] pci_iomap...
427
  			goto err_inval;
5ea817699   Al Viro   [PATCH] sort the ...
428
429
430
  
  		rc = -ENOMEM;
  		if (!pcim_iomap(pdev, i, 0))
fb4d64e78   Frederik Deweerdt   [PATCH] pci_iomap...
431
  			goto err_region;
5ea817699   Al Viro   [PATCH] sort the ...
432
433
434
  	}
  
  	return 0;
5ea817699   Al Viro   [PATCH] sort the ...
435
436
437
438
   err_region:
  	pci_release_region(pdev, i);
   err_inval:
  	while (--i >= 0) {
fb4d64e78   Frederik Deweerdt   [PATCH] pci_iomap...
439
440
  		if (!(mask & (1 << i)))
  			continue;
5ea817699   Al Viro   [PATCH] sort the ...
441
442
443
444
445
446
447
  		pcim_iounmap(pdev, iomap[i]);
  		pci_release_region(pdev, i);
  	}
  
  	return rc;
  }
  EXPORT_SYMBOL(pcim_iomap_regions);
ec04b0758   Tejun Heo   iomap: implement ...
448
449
  
  /**
916fbfb7a   Tejun Heo   devres: implement...
450
451
452
453
454
455
456
   * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones
   * @pdev: PCI device to map IO resources for
   * @mask: Mask of BARs to iomap
   * @name: Name used when requesting regions
   *
   * Request all PCI BARs and iomap regions specified by @mask.
   */
fb7ebfe41   Yinghai Lu   PCI: Increase res...
457
  int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask,
916fbfb7a   Tejun Heo   devres: implement...
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
  				   const char *name)
  {
  	int request_mask = ((1 << 6) - 1) & ~mask;
  	int rc;
  
  	rc = pci_request_selected_regions(pdev, request_mask, name);
  	if (rc)
  		return rc;
  
  	rc = pcim_iomap_regions(pdev, mask, name);
  	if (rc)
  		pci_release_selected_regions(pdev, request_mask);
  	return rc;
  }
  EXPORT_SYMBOL(pcim_iomap_regions_request_all);
  
  /**
ec04b0758   Tejun Heo   iomap: implement ...
475
476
477
478
   * pcim_iounmap_regions - Unmap and release PCI BARs
   * @pdev: PCI device to map IO resources for
   * @mask: Mask of BARs to unmap and release
   *
4d45ada36   Kulikov Vasiliy   lib/devres.c: fix...
479
   * Unmap and release regions specified by @mask.
ec04b0758   Tejun Heo   iomap: implement ...
480
   */
fb7ebfe41   Yinghai Lu   PCI: Increase res...
481
  void pcim_iounmap_regions(struct pci_dev *pdev, int mask)
ec04b0758   Tejun Heo   iomap: implement ...
482
483
484
485
486
487
488
  {
  	void __iomem * const *iomap;
  	int i;
  
  	iomap = pcim_iomap_table(pdev);
  	if (!iomap)
  		return;
1f35d04a0   Dan Carpenter   devres: fix a for...
489
  	for (i = 0; i < PCIM_IOMAP_MAX; i++) {
ec04b0758   Tejun Heo   iomap: implement ...
490
491
492
493
494
495
496
497
  		if (!(mask & (1 << i)))
  			continue;
  
  		pcim_iounmap(pdev, iomap[i]);
  		pci_release_region(pdev, i);
  	}
  }
  EXPORT_SYMBOL(pcim_iounmap_regions);
571806a9f   Wolfram Sang   lib: devres: add ...
498
  #endif /* CONFIG_PCI */