^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * rsrc_nonstatic.c -- Resource management routines for !SS_CAP_STATIC_MAP sockets
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * The initial developer of the original code is David A. Hinds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * (C) 1999 David A. Hinds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/moduleparam.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/interrupt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <linux/ioport.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <linux/timer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include <asm/irq.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include <pcmcia/ss.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <pcmcia/cistpl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include "cs_internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) /* moved to rsrc_mgr.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) MODULE_AUTHOR("David A. Hinds, Dominik Brodowski");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) MODULE_LICENSE("GPL");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) /* Parameters that can be set with 'insmod' */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) #define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) INT_MODULE_PARM(probe_mem, 1); /* memory probe? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #ifdef CONFIG_PCMCIA_PROBE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) INT_MODULE_PARM(probe_io, 1); /* IO port probe? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) INT_MODULE_PARM(mem_limit, 0x10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) /* for io_db and mem_db */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) struct resource_map {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) u_long base, num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) struct resource_map *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) struct socket_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) struct resource_map mem_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) struct resource_map mem_db_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) struct resource_map io_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define MEM_PROBE_LOW (1 << 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define MEM_PROBE_HIGH (1 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Action field */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define REMOVE_MANAGED_RESOURCE 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define ADD_MANAGED_RESOURCE 2
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) Linux resource management extensions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static struct resource *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) claim_region(struct pcmcia_socket *s, resource_size_t base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) resource_size_t size, int type, char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct resource *res, *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) parent = type & IORESOURCE_MEM ? &iomem_resource : &ioport_resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) res = pcmcia_make_resource(base, size, type | IORESOURCE_BUSY, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) if (s && s->cb_dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) parent = pci_find_parent_resource(s->cb_dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) if (!parent || request_resource(parent, res)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) kfree(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) res = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static void free_region(struct resource *res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) if (res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) release_resource(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) kfree(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) These manage the internal databases of available resources.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int add_interval(struct resource_map *map, u_long base, u_long num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct resource_map *p, *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) for (p = map; ; p = p->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) if ((p != map) && (p->base+p->num >= base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) p->num = max(num + base - p->base, p->num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if ((p->next == map) || (p->next->base > base+num-1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) q = kmalloc(sizeof(struct resource_map), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (!q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) printk(KERN_WARNING "out of memory to update resources\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) q->base = base; q->num = num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) q->next = p->next; p->next = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) /*====================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int sub_interval(struct resource_map *map, u_long base, u_long num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct resource_map *p, *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) for (p = map; ; p = q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) q = p->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (q == map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) if ((q->base+q->num > base) && (base+num > q->base)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) if (q->base >= base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (q->base+q->num <= base+num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* Delete whole block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) p->next = q->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) kfree(q);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* don't advance the pointer yet */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) q = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) /* Cut off bit from the front */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) q->num = q->base + q->num - base - num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) q->base = base + num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) } else if (q->base+q->num <= base+num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) /* Cut off bit from the end */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) q->num = base - q->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /* Split the block into two pieces */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) p = kmalloc(sizeof(struct resource_map),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (!p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) printk(KERN_WARNING "out of memory to update resources\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) p->base = base+num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) p->num = q->base+q->num - p->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) q->num = base - q->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) p->next = q->next ; q->next = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) These routines examine a region of IO or memory addresses to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) determine what ranges might be genuinely available.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) #ifdef CONFIG_PCMCIA_PROBE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) static void do_io_probe(struct pcmcia_socket *s, unsigned int base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) unsigned int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) unsigned int i, j, bad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) int any;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) u_char *b, hole, most;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) dev_info(&s->dev, "cs: IO port probe %#x-%#x:", base, base+num-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) /* First, what does a floating port look like? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) b = kzalloc(256, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!b) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) pr_cont("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) dev_err(&s->dev, "do_io_probe: unable to kmalloc 256 bytes\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) for (i = base, most = 0; i < base+num; i += 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) hole = inb(i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) for (j = 1; j < 8; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) if (inb(i+j) != hole)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) free_region(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) if ((j == 8) && (++b[hole] > b[most]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) most = hole;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (b[most] == 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) kfree(b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) bad = any = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) for (i = base; i < base+num; i += 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) res = claim_region(s, i, 8, IORESOURCE_IO, "PCMCIA ioprobe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) if (!any)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) pr_cont(" excluding");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (!bad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) bad = any = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) for (j = 0; j < 8; j++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (inb(i+j) != most)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) free_region(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) if (j < 8) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) if (!any)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) pr_cont(" excluding");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) if (!bad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) bad = any = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (bad) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) sub_interval(&s_data->io_db, bad, i-bad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) pr_cont(" %#x-%#x", bad, i-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) bad = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) if (bad) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if ((num > 16) && (bad == base) && (i == base+num)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) sub_interval(&s_data->io_db, bad, i-bad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) pr_cont(" nothing: probe failed.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) sub_interval(&s_data->io_db, bad, i-bad);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) pr_cont(" %#x-%#x", bad, i-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) pr_cont("%s\n", !any ? " clean" : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /*======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) * readable() - iomem validation function for cards with a valid CIS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) static int readable(struct pcmcia_socket *s, struct resource *res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) unsigned int *count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (s->fake_cis) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) dev_dbg(&s->dev, "fake CIS is being used: can't validate mem\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) s->cis_mem.res = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) s->cis_virt = ioremap(res->start, s->map_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (s->cis_virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) mutex_unlock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* as we're only called from pcmcia.c, we're safe */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (s->callback->validate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) ret = s->callback->validate(s, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) /* invalidate mapping */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) mutex_lock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) iounmap(s->cis_virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) s->cis_virt = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) s->cis_mem.res = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if ((ret) || (*count == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) * checksum() - iomem validation function for simple memory cards
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) static int checksum(struct pcmcia_socket *s, struct resource *res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) unsigned int *value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) pccard_mem_map map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) int i, a = 0, b = -1, d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) void __iomem *virt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) virt = ioremap(res->start, s->map_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) if (virt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) map.map = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) map.flags = MAP_ACTIVE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) map.speed = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) map.res = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) map.card_start = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) s->ops->set_mem_map(s, &map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /* Don't bother checking every word... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) for (i = 0; i < s->map_size; i += 44) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) d = readl(virt+i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) a += d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) b &= d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) map.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) s->ops->set_mem_map(s, &map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) iounmap(virt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (b == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) *value = a;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) * do_validate_mem() - low level validate a memory region for PCMCIA use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) * @s: PCMCIA socket to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) * @base: start address of resource to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) * @size: size of resource to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) * @validate: validation function to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) * do_validate_mem() splits up the memory region which is to be checked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) * into two parts. Both are passed to the @validate() function. If
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) * @validate() returns non-zero, or the value parameter to @validate()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) * is zero, or the value parameter is different between both calls,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) * the check fails, and -EINVAL is returned. Else, 0 is returned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) static int do_validate_mem(struct pcmcia_socket *s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) unsigned long base, unsigned long size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) int validate (struct pcmcia_socket *s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) struct resource *res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) unsigned int *value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) struct resource *res1, *res2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) unsigned int info1 = 1, info2 = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) res1 = claim_region(s, base, size/2, IORESOURCE_MEM, "PCMCIA memprobe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) res2 = claim_region(s, base + size/2, size/2, IORESOURCE_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) "PCMCIA memprobe");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (res1 && res2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (validate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) ret = validate(s, res1, &info1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) ret += validate(s, res2, &info2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) dev_dbg(&s->dev, "cs: memory probe 0x%06lx-0x%06lx: %pr %pr %u %u %u",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) base, base+size-1, res1, res2, ret, info1, info2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) free_region(res2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) free_region(res1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if ((ret) || (info1 != info2) || (info1 == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (validate && !s->fake_cis) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) /* move it to the validated data set */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) add_interval(&s_data->mem_db_valid, base, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) sub_interval(&s_data->mem_db, base, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) * do_mem_probe() - validate a memory region for PCMCIA use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) * @s: PCMCIA socket to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) * @base: start address of resource to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) * @num: size of resource to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) * @validate: validation function to use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) * @fallback: validation function to use if validate fails
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) * do_mem_probe() checks a memory region for use by the PCMCIA subsystem.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) * To do so, the area is split up into sensible parts, and then passed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) * into the @validate() function. Only if @validate() and @fallback() fail,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) * the area is marked as unavaibale for use by the PCMCIA subsystem. The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) * function returns the size of the usable memory area.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) static int do_mem_probe(struct pcmcia_socket *s, u_long base, u_long num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) int validate (struct pcmcia_socket *s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) struct resource *res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) unsigned int *value),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) int fallback (struct pcmcia_socket *s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) struct resource *res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) unsigned int *value))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) u_long i, j, bad, fail, step;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) dev_info(&s->dev, "cs: memory probe 0x%06lx-0x%06lx:",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) base, base+num-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) bad = fail = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) /* don't allow too large steps */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) if (step > 0x800000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) step = 0x800000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) /* cis_readable wants to map 2x map_size */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (step < 2 * s->map_size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) step = 2 * s->map_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) for (i = j = base; i < base+num; i = j + step) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) if (!fail) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) for (j = i; j < base+num; j += step) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) if (!do_validate_mem(s, j, step, validate))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) fail = ((i == base) && (j == base+num));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) if ((fail) && (fallback)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) for (j = i; j < base+num; j += step)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (!do_validate_mem(s, j, step, fallback))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) if (i != j) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) if (!bad)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) pr_cont(" excluding");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) pr_cont(" %#05lx-%#05lx", i, j-1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) sub_interval(&s_data->mem_db, i, j-i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) bad += j-i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) pr_cont("%s\n", !bad ? " clean" : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) return num - bad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) #ifdef CONFIG_PCMCIA_PROBE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) * inv_probe() - top-to-bottom search for one usuable high memory area
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) * @s: PCMCIA socket to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) * @m: resource_map to check
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static u_long inv_probe(struct resource_map *m, struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) u_long ok;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) if (m == &s_data->mem_db)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) ok = inv_probe(m->next, s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) if (ok) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) if (m->base >= 0x100000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) sub_interval(&s_data->mem_db, m->base, m->num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) return ok;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) if (m->base < 0x100000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) return do_mem_probe(s, m->base, m->num, readable, checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) * validate_mem() - memory probe function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) * @s: PCMCIA socket to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) * @probe_mask: MEM_PROBE_LOW | MEM_PROBE_HIGH
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) * The memory probe. If the memory list includes a 64K-aligned block
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) * below 1MB, we probe in 64K chunks, and as soon as we accumulate at
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) * least mem_limit free space, we quit. Returns 0 on usuable ports.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) struct resource_map *m, mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static unsigned char order[] = { 0xd0, 0xe0, 0xc0, 0xf0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) unsigned long b, i, ok = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) /* We do up to four passes through the list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) if (probe_mask & MEM_PROBE_HIGH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (inv_probe(s_data->mem_db.next, s) > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) dev_notice(&s->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) "cs: warning: no high memory space available!\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) mm = *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) /* Only probe < 1 MB */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) if (mm.base >= 0x100000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) if ((mm.base | mm.num) & 0xffff) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) ok += do_mem_probe(s, mm.base, mm.num, readable,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) /* Special probe for 64K-aligned block */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) for (i = 0; i < 4; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) b = order[i] << 12;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) if ((b >= mm.base) && (b+0x10000 <= mm.base+mm.num)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) if (ok >= mem_limit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) sub_interval(&s_data->mem_db, b, 0x10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) ok += do_mem_probe(s, b, 0x10000,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) readable, checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) if (ok > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) #else /* CONFIG_PCMCIA_PROBE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) * validate_mem() - memory probe function
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) * @s: PCMCIA socket to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) * @probe_mask: ignored
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) * Returns 0 on usuable ports.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) static int validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) struct resource_map *m, mm;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) unsigned long ok = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) mm = *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) ok += do_mem_probe(s, mm.base, mm.num, readable, checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) if (ok > 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) #endif /* CONFIG_PCMCIA_PROBE */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) * pcmcia_nonstatic_validate_mem() - try to validate iomem for PCMCIA use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) * @s: PCMCIA socket to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) * This is tricky... when we set up CIS memory, we try to validate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) * the memory window space allocations.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) * Locking note: Must be called with skt_mutex held!
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) unsigned int probe_mask = MEM_PROBE_LOW;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) if (!probe_mem || !(s->state & SOCKET_PRESENT))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) if (s->features & SS_CAP_PAGE_REGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) probe_mask = MEM_PROBE_HIGH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) ret = validate_mem(s, probe_mask);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (s_data->mem_db_valid.next != &s_data->mem_db_valid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) struct pcmcia_align_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) unsigned long mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) unsigned long offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) struct resource_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) static resource_size_t pcmcia_common_align(struct pcmcia_align_data *align_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) resource_size_t start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) resource_size_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) * Ensure that we have the correct start address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) ret = (start & ~align_data->mask) + align_data->offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) if (ret < start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) ret += align_data->mask + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) static resource_size_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) pcmcia_align(void *align_data, const struct resource *res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) resource_size_t size, resource_size_t align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) struct pcmcia_align_data *data = align_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) struct resource_map *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) resource_size_t start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) start = pcmcia_common_align(data, res->start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) for (m = data->map->next; m != data->map; m = m->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) unsigned long map_start = m->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) unsigned long map_end = m->base + m->num - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) * If the lower resources are not available, try aligning
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) * to this entry of the resource database to see if it'll
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) * fit here.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) if (start < map_start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) start = pcmcia_common_align(data, map_start);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) * If we're above the area which was passed in, there's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) * no point proceeding.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (start >= res->end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631) if ((start + size - 1) <= map_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) * If we failed to find something suitable, ensure we fail.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (m == data->map)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) start = res->end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) * Adjust an existing IO region allocation, but making sure that we don't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) * encroach outside the resources which the user supplied.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) static int __nonstatic_adjust_io_region(struct pcmcia_socket *s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) unsigned long r_start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) unsigned long r_end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) struct resource_map *m;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) int ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) unsigned long start = m->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) unsigned long end = m->base + m->num - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) if (start > r_start || r_end > end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) /*======================================================================
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) These find ranges of I/O ports or memory addresses that are not
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) currently allocated by other devices.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) The 'align' field should reflect the number of bits of address
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) that need to be preserved from the initial value of *base. It
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) should be a power of two, greater than or equal to 'num'. A value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) of 0 means that all bits of *base are significant. *base should
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) also be strictly less than 'align'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) ======================================================================*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) static struct resource *__nonstatic_find_io_region(struct pcmcia_socket *s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) unsigned long base, int num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) unsigned long align)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) dev_name(&s->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) struct pcmcia_align_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) unsigned long min = base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) data.mask = align - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) data.offset = base & data.mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) data.map = &s_data->io_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) if (s->cb_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702) ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) min, 0, pcmcia_align, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) 1, pcmcia_align, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) kfree(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) res = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) static int nonstatic_find_io(struct pcmcia_socket *s, unsigned int attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) unsigned int *base, unsigned int num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) unsigned int align, struct resource **parent)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) int i, ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) /* Check for an already-allocated window that must conflict with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) * what was asked for. It is a hack because it does not catch all
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) * potential conflicts, just the most obvious ones.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) for (i = 0; i < MAX_IO_WIN; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) if (!s->io[i].res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) if (!*base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if ((s->io[i].res->start & (align-1)) == *base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) for (i = 0; i < MAX_IO_WIN; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) struct resource *res = s->io[i].res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) unsigned int try;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) if (res && (res->flags & IORESOURCE_BITS) !=
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) (attr & IORESOURCE_BITS))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) if (!res) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (align == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) align = 0x10000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) res = s->io[i].res = __nonstatic_find_io_region(s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) *base, num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) align);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) *base = res->start;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) s->io[i].res->flags =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) ((res->flags & ~IORESOURCE_BITS) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) (attr & IORESOURCE_BITS));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) s->io[i].InUse = num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) *parent = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) /* Try to extend top of window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) try = res->end + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) if ((*base == 0) || (*base == try)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) ret = __nonstatic_adjust_io_region(s, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) res->end + num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) ret = adjust_resource(s->io[i].res, res->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) resource_size(res) + num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) *base = try;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) s->io[i].InUse += num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) *parent = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) /* Try to extend bottom of window */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) try = res->start - num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) if ((*base == 0) || (*base == try)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) ret = __nonstatic_adjust_io_region(s,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) res->start - num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) res->end);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (!ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) ret = adjust_resource(s->io[i].res,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) res->start - num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) resource_size(res) + num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) *base = try;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) s->io[i].InUse += num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) *parent = res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) u_long align, int low, struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) dev_name(&s->dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) struct socket_data *s_data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) struct pcmcia_align_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) unsigned long min, max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) int ret, i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) low = low || !(s->features & SS_CAP_PAGE_REGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) data.mask = align - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) data.offset = base & data.mask;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) for (i = 0; i < 2; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) data.map = &s_data->mem_db_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) if (low) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) max = 0x100000UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) min = base < max ? base : 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) max = ~0UL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) min = 0x100000UL + base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) for (j = 0; j < 2; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835) if (s->cb_dev) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) ret = pci_bus_alloc_resource(s->cb_dev->bus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) res, num, 1, min, 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) pcmcia_align, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) ret = allocate_resource(&iomem_resource,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) res, num, min, max, 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) pcmcia_align, &data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) if (ret == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) data.map = &s_data->mem_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) if (ret == 0 || low)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) low = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) if (ret != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) kfree(res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857) res = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865) struct socket_data *data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) unsigned long size = end - start + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) if (end < start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) switch (action) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) case ADD_MANAGED_RESOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874) ret = add_interval(&data->mem_db, start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) if (!ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) do_mem_probe(s, start, size, NULL, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) case REMOVE_MANAGED_RESOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) ret = sub_interval(&data->mem_db, start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889) static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) struct socket_data *data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892) unsigned long size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) #if defined(CONFIG_X86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) /* on x86, avoid anything < 0x100 for it is often used for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) * legacy platform devices */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898) if (start < 0x100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) start = 0x100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) size = end - start + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) if (end < start)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907) if (end > IO_SPACE_LIMIT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910) switch (action) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) case ADD_MANAGED_RESOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) if (add_interval(&data->io_db, start, size) != 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) ret = -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) #ifdef CONFIG_PCMCIA_PROBE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) if (probe_io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918) do_io_probe(s, start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) case REMOVE_MANAGED_RESOURCE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) sub_interval(&data->io_db, start, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) #ifdef CONFIG_PCI
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934) static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) int i, done = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) if (!s->cb_dev || !s->cb_dev->bus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942) #if defined(CONFIG_X86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) /* If this is the root bus, the risk of hitting some strange
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) * system devices is too high: If a driver isn't loaded, the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) * resources are not claimed; even if a driver is loaded, it
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) * may not request all resources or even the wrong one. We
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947) * can neither trust the rest of the kernel nor ACPI/PNP and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) * CRS parsing to get it right. Therefore, use several
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) * safeguards:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) * - Do not auto-add resources if the CardBus bridge is on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) * the PCI root bus
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) * - Avoid any I/O ports < 0x100.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) * - On PCI-PCI bridges, only use resources which are set up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957) * exclusively for the secondary PCI bus: the risk of hitting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) * system devices is quite low, as they usually aren't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) * connected to the secondary PCI bus.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) if (s->cb_dev->bus->number == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964) for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) res = s->cb_dev->bus->resource[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) pci_bus_for_each_resource(s->cb_dev->bus, res, i) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969) if (!res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972) if (res->flags & IORESOURCE_IO) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) /* safeguard against the root resource, where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) * risk of hitting any other device would be too
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) * high */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) if (res == &ioport_resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) dev_info(&s->cb_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) "pcmcia: parent PCI bridge window: %pR\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983) done |= IORESOURCE_IO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) if (res->flags & IORESOURCE_MEM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988) /* safeguard against the root resource, where the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) * risk of hitting any other device would be too
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) * high */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) if (res == &iomem_resource)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) dev_info(&s->cb_dev->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995) "pcmcia: parent PCI bridge window: %pR\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997) if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) done |= IORESOURCE_MEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) /* if we got at least one of IO, and one of MEM, we can be glad and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) * activate the PCMCIA subsystem */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) if (done == (IORESOURCE_MEM | IORESOURCE_IO))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) s->resource_setup_done = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) #else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) static int nonstatic_init(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) struct socket_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) data = kzalloc(sizeof(struct socket_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) data->mem_db.next = &data->mem_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) data->mem_db_valid.next = &data->mem_db_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) data->io_db.next = &data->io_db;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032) s->resource_data = (void *) data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) nonstatic_autoadd_resources(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) static void nonstatic_release_resource_db(struct pcmcia_socket *s)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) struct socket_data *data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042) struct resource_map *p, *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) for (p = data->mem_db_valid.next; p != &data->mem_db_valid; p = q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) q = p->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) for (p = data->mem_db.next; p != &data->mem_db; p = q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049) q = p->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) for (p = data->io_db.next; p != &data->io_db; p = q) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) q = p->next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) kfree(p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) struct pccard_resource_ops pccard_nonstatic_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060) .validate_mem = pcmcia_nonstatic_validate_mem,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) .find_io = nonstatic_find_io,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) .find_mem = nonstatic_find_mem_region,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) .init = nonstatic_init,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064) .exit = nonstatic_release_resource_db,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) EXPORT_SYMBOL(pccard_nonstatic_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) /* sysfs interface to the resource database */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) static ssize_t show_io_db(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074) struct pcmcia_socket *s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) struct socket_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) struct resource_map *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) mutex_lock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) for (p = data->io_db.next; p != &data->io_db; p = p->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) if (ret > (PAGE_SIZE - 10))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) "0x%08lx - 0x%08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) ((unsigned long) p->base),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088) ((unsigned long) p->base + p->num - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) mutex_unlock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) static ssize_t store_io_db(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) struct pcmcia_socket *s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) unsigned long start_addr, end_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) unsigned int add = ADD_MANAGED_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104) ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) if (ret != 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) add = REMOVE_MANAGED_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) if (ret != 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) &end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) add = ADD_MANAGED_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112) if (ret != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) if (end_addr < start_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119) mutex_lock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) ret = adjust_io(s, add, start_addr, end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) mutex_unlock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) return ret ? ret : count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127) static ssize_t show_mem_db(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) struct pcmcia_socket *s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131) struct socket_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) struct resource_map *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) mutex_lock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) data = s->resource_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138) for (p = data->mem_db_valid.next; p != &data->mem_db_valid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) p = p->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) if (ret > (PAGE_SIZE - 10))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143) "0x%08lx - 0x%08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) ((unsigned long) p->base),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) ((unsigned long) p->base + p->num - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148) for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) if (ret > (PAGE_SIZE - 10))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151) ret += scnprintf(&buf[ret], (PAGE_SIZE - ret - 1),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) "0x%08lx - 0x%08lx\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) ((unsigned long) p->base),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) ((unsigned long) p->base + p->num - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157) mutex_unlock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) static ssize_t store_mem_db(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) struct device_attribute *attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) struct pcmcia_socket *s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) unsigned long start_addr, end_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) unsigned int add = ADD_MANAGED_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) ssize_t ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) ret = sscanf(buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171) if (ret != 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) ret = sscanf(buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) add = REMOVE_MANAGED_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) if (ret != 2) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) ret = sscanf(buf, "0x%lx - 0x%lx", &start_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176) &end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) add = ADD_MANAGED_RESOURCE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) if (ret != 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182) if (end_addr < start_addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) mutex_lock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186) ret = adjust_memory(s, add, start_addr, end_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) mutex_unlock(&s->ops_mutex);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189) return ret ? ret : count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) static struct attribute *pccard_rsrc_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) &dev_attr_available_resources_io.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) &dev_attr_available_resources_mem.attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) static const struct attribute_group rsrc_attributes = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) .attrs = pccard_rsrc_attributes,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203) static int pccard_sysfs_add_rsrc(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) struct class_interface *class_intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) struct pcmcia_socket *s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) if (s->resource_ops != &pccard_nonstatic_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210) return sysfs_create_group(&dev->kobj, &rsrc_attributes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) static void pccard_sysfs_remove_rsrc(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) struct class_interface *class_intf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216) struct pcmcia_socket *s = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218) if (s->resource_ops != &pccard_nonstatic_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) sysfs_remove_group(&dev->kobj, &rsrc_attributes);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) static struct class_interface pccard_rsrc_interface __refdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) .class = &pcmcia_socket_class,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) .add_dev = &pccard_sysfs_add_rsrc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) .remove_dev = &pccard_sysfs_remove_rsrc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) static int __init nonstatic_sysfs_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231) return class_interface_register(&pccard_rsrc_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) static void __exit nonstatic_sysfs_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236) class_interface_unregister(&pccard_rsrc_interface);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) module_init(nonstatic_sysfs_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) module_exit(nonstatic_sysfs_exit);