pcmcia: use ops_mutex for rsrc_{mgr,nonstatic} locking
Tested-by: Wolfram Sang <w.sang@pengutronix.de> Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
This commit is contained in:
parent
3f565232c5
commit
cfe5d80951
|
@ -36,7 +36,8 @@ be called with "ops_mutex" held:
|
||||||
socket_reset()
|
socket_reset()
|
||||||
socket_setup()
|
socket_setup()
|
||||||
|
|
||||||
struct pccard_operations *ops
|
struct pccard_operations *ops
|
||||||
|
struct pccard_resource_ops *resource_ops;
|
||||||
|
|
||||||
Note that send_event() and struct pcmcia_callback *callback must not be
|
Note that send_event() and struct pcmcia_callback *callback must not be
|
||||||
called with "ops_mutex" held.
|
called with "ops_mutex" held.
|
||||||
|
@ -54,7 +55,7 @@ protected by pcmcia_socket_list_rwsem;
|
||||||
|
|
||||||
2. Per-Socket Data:
|
2. Per-Socket Data:
|
||||||
-------------------
|
-------------------
|
||||||
The resource_ops are on their own to provide proper locking.
|
The resource_ops and their data are protected by ops_mutex.
|
||||||
|
|
||||||
The "main" struct pcmcia_socket is protected as follows (read-only fields
|
The "main" struct pcmcia_socket is protected as follows (read-only fields
|
||||||
or single-use fields not mentioned):
|
or single-use fields not mentioned):
|
||||||
|
|
|
@ -224,7 +224,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
|
||||||
spin_lock_init(&socket->thread_lock);
|
spin_lock_init(&socket->thread_lock);
|
||||||
|
|
||||||
if (socket->resource_ops->init) {
|
if (socket->resource_ops->init) {
|
||||||
|
mutex_lock(&socket->ops_mutex);
|
||||||
ret = socket->resource_ops->init(socket);
|
ret = socket->resource_ops->init(socket);
|
||||||
|
mutex_unlock(&socket->ops_mutex);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
@ -282,8 +284,11 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket)
|
||||||
up_write(&pcmcia_socket_list_rwsem);
|
up_write(&pcmcia_socket_list_rwsem);
|
||||||
|
|
||||||
/* wait for sysfs to drop all references */
|
/* wait for sysfs to drop all references */
|
||||||
if (socket->resource_ops->exit)
|
if (socket->resource_ops->exit) {
|
||||||
|
mutex_lock(&socket->ops_mutex);
|
||||||
socket->resource_ops->exit(socket);
|
socket->resource_ops->exit(socket);
|
||||||
|
mutex_unlock(&socket->ops_mutex);
|
||||||
|
}
|
||||||
wait_for_completion(&socket->socket_released);
|
wait_for_completion(&socket->socket_released);
|
||||||
} /* pcmcia_unregister_socket */
|
} /* pcmcia_unregister_socket */
|
||||||
EXPORT_SYMBOL(pcmcia_unregister_socket);
|
EXPORT_SYMBOL(pcmcia_unregister_socket);
|
||||||
|
|
|
@ -607,19 +607,23 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
|
||||||
{
|
{
|
||||||
cistpl_longlink_mfc_t mfc;
|
cistpl_longlink_mfc_t mfc;
|
||||||
unsigned int no_funcs, i, no_chains;
|
unsigned int no_funcs, i, no_chains;
|
||||||
int ret = 0;
|
int ret = -EAGAIN;
|
||||||
|
|
||||||
|
mutex_lock(&s->ops_mutex);
|
||||||
if (!(s->resource_setup_done)) {
|
if (!(s->resource_setup_done)) {
|
||||||
dev_dbg(&s->dev,
|
dev_dbg(&s->dev,
|
||||||
"no resources available, delaying card_add\n");
|
"no resources available, delaying card_add\n");
|
||||||
|
mutex_unlock(&s->ops_mutex);
|
||||||
return -EAGAIN; /* try again, but later... */
|
return -EAGAIN; /* try again, but later... */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pcmcia_validate_mem(s)) {
|
if (pcmcia_validate_mem(s)) {
|
||||||
dev_dbg(&s->dev, "validating mem resources failed, "
|
dev_dbg(&s->dev, "validating mem resources failed, "
|
||||||
"delaying card_add\n");
|
"delaying card_add\n");
|
||||||
|
mutex_unlock(&s->ops_mutex);
|
||||||
return -EAGAIN; /* try again, but later... */
|
return -EAGAIN; /* try again, but later... */
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&s->ops_mutex);
|
||||||
|
|
||||||
ret = pccard_validate_cis(s, &no_chains);
|
ret = pccard_validate_cis(s, &no_chains);
|
||||||
if (ret || !no_chains) {
|
if (ret || !no_chains) {
|
||||||
|
|
|
@ -187,7 +187,6 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
|
||||||
continue;
|
continue;
|
||||||
} else if (!(s->resource_setup_old))
|
} else if (!(s->resource_setup_old))
|
||||||
s->resource_setup_old = 1;
|
s->resource_setup_old = 1;
|
||||||
mutex_unlock(&s->ops_mutex);
|
|
||||||
|
|
||||||
switch (adj->Resource) {
|
switch (adj->Resource) {
|
||||||
case RES_MEMORY_RANGE:
|
case RES_MEMORY_RANGE:
|
||||||
|
@ -206,10 +205,9 @@ static int pcmcia_adjust_resource_info(adjust_t *adj)
|
||||||
* last call to adjust_resource_info, we
|
* last call to adjust_resource_info, we
|
||||||
* always need to assume this is the latest
|
* always need to assume this is the latest
|
||||||
* one... */
|
* one... */
|
||||||
mutex_lock(&s->ops_mutex);
|
|
||||||
s->resource_setup_done = 1;
|
s->resource_setup_done = 1;
|
||||||
mutex_unlock(&s->ops_mutex);
|
|
||||||
}
|
}
|
||||||
|
mutex_unlock(&s->ops_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
up_read(&pcmcia_socket_list_rwsem);
|
up_read(&pcmcia_socket_list_rwsem);
|
||||||
|
|
|
@ -26,9 +26,7 @@ static int static_init(struct pcmcia_socket *s)
|
||||||
/* the good thing about SS_CAP_STATIC_MAP sockets is
|
/* the good thing about SS_CAP_STATIC_MAP sockets is
|
||||||
* that they don't need a resource database */
|
* that they don't need a resource database */
|
||||||
|
|
||||||
mutex_lock(&s->ops_mutex);
|
|
||||||
s->resource_setup_done = 1;
|
s->resource_setup_done = 1;
|
||||||
mutex_unlock(&s->ops_mutex);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,7 +59,6 @@ struct socket_data {
|
||||||
unsigned int rsrc_mem_probe;
|
unsigned int rsrc_mem_probe;
|
||||||
};
|
};
|
||||||
|
|
||||||
static DEFINE_MUTEX(rsrc_mutex);
|
|
||||||
#define MEM_PROBE_LOW (1 << 0)
|
#define MEM_PROBE_LOW (1 << 0)
|
||||||
#define MEM_PROBE_HIGH (1 << 1)
|
#define MEM_PROBE_HIGH (1 << 1)
|
||||||
|
|
||||||
|
@ -274,7 +273,6 @@ static int readable(struct pcmcia_socket *s, struct resource *res,
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&s->ops_mutex);
|
|
||||||
s->cis_mem.res = res;
|
s->cis_mem.res = res;
|
||||||
s->cis_virt = ioremap(res->start, s->map_size);
|
s->cis_virt = ioremap(res->start, s->map_size);
|
||||||
if (s->cis_virt) {
|
if (s->cis_virt) {
|
||||||
|
@ -288,7 +286,6 @@ static int readable(struct pcmcia_socket *s, struct resource *res,
|
||||||
s->cis_virt = NULL;
|
s->cis_virt = NULL;
|
||||||
}
|
}
|
||||||
s->cis_mem.res = NULL;
|
s->cis_mem.res = NULL;
|
||||||
mutex_unlock(&s->ops_mutex);
|
|
||||||
if ((ret) || (*count == 0))
|
if ((ret) || (*count == 0))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -304,8 +301,6 @@ static int checksum(struct pcmcia_socket *s, struct resource *res,
|
||||||
int i, a = 0, b = -1, d;
|
int i, a = 0, b = -1, d;
|
||||||
void __iomem *virt;
|
void __iomem *virt;
|
||||||
|
|
||||||
mutex_lock(&s->ops_mutex);
|
|
||||||
|
|
||||||
virt = ioremap(res->start, s->map_size);
|
virt = ioremap(res->start, s->map_size);
|
||||||
if (virt) {
|
if (virt) {
|
||||||
map.map = 0;
|
map.map = 0;
|
||||||
|
@ -328,8 +323,6 @@ static int checksum(struct pcmcia_socket *s, struct resource *res,
|
||||||
iounmap(virt);
|
iounmap(virt);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&s->ops_mutex);
|
|
||||||
|
|
||||||
if (b == -1)
|
if (b == -1)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
@ -570,8 +563,6 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
|
||||||
if (!probe_mem)
|
if (!probe_mem)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
|
|
||||||
if (s->features & SS_CAP_PAGE_REGS)
|
if (s->features & SS_CAP_PAGE_REGS)
|
||||||
probe_mask = MEM_PROBE_HIGH;
|
probe_mask = MEM_PROBE_HIGH;
|
||||||
|
|
||||||
|
@ -583,8 +574,6 @@ static int pcmcia_nonstatic_validate_mem(struct pcmcia_socket *s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -661,7 +650,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
|
||||||
struct socket_data *s_data = s->resource_data;
|
struct socket_data *s_data = s->resource_data;
|
||||||
int ret = -ENOMEM;
|
int ret = -ENOMEM;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
|
for (m = s_data->io_db.next; m != &s_data->io_db; m = m->next) {
|
||||||
unsigned long start = m->base;
|
unsigned long start = m->base;
|
||||||
unsigned long end = m->base + m->num - 1;
|
unsigned long end = m->base + m->num - 1;
|
||||||
|
@ -672,7 +660,6 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
|
||||||
ret = adjust_resource(res, r_start, r_end - r_start + 1);
|
ret = adjust_resource(res, r_start, r_end - r_start + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -706,7 +693,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
|
||||||
data.offset = base & data.mask;
|
data.offset = base & data.mask;
|
||||||
data.map = &s_data->io_db;
|
data.map = &s_data->io_db;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
if (s->cb_dev) {
|
if (s->cb_dev) {
|
||||||
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
|
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
|
||||||
|
@ -715,7 +701,6 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
|
||||||
#endif
|
#endif
|
||||||
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
|
ret = allocate_resource(&ioport_resource, res, num, min, ~0UL,
|
||||||
1, pcmcia_align, &data);
|
1, pcmcia_align, &data);
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
kfree(res);
|
kfree(res);
|
||||||
|
@ -748,7 +733,6 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
|
||||||
min = 0x100000UL + base;
|
min = 0x100000UL + base;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
#ifdef CONFIG_PCI
|
#ifdef CONFIG_PCI
|
||||||
if (s->cb_dev) {
|
if (s->cb_dev) {
|
||||||
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
|
ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num,
|
||||||
|
@ -758,7 +742,6 @@ static struct resource *nonstatic_find_mem_region(u_long base, u_long num,
|
||||||
#endif
|
#endif
|
||||||
ret = allocate_resource(&iomem_resource, res, num, min,
|
ret = allocate_resource(&iomem_resource, res, num, min,
|
||||||
max, 1, pcmcia_align, &data);
|
max, 1, pcmcia_align, &data);
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
if (ret == 0 || low)
|
if (ret == 0 || low)
|
||||||
break;
|
break;
|
||||||
low = 1;
|
low = 1;
|
||||||
|
@ -781,7 +764,6 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
|
||||||
if (end < start)
|
if (end < start)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ADD_MANAGED_RESOURCE:
|
case ADD_MANAGED_RESOURCE:
|
||||||
ret = add_interval(&data->mem_db, start, size);
|
ret = add_interval(&data->mem_db, start, size);
|
||||||
|
@ -794,7 +776,6 @@ static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -812,7 +793,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
|
||||||
if (end > IO_SPACE_LIMIT)
|
if (end > IO_SPACE_LIMIT)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ADD_MANAGED_RESOURCE:
|
case ADD_MANAGED_RESOURCE:
|
||||||
if (add_interval(&data->io_db, start, size) != 0) {
|
if (add_interval(&data->io_db, start, size) != 0) {
|
||||||
|
@ -831,7 +811,6 @@ static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -929,7 +908,6 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
|
||||||
struct socket_data *data = s->resource_data;
|
struct socket_data *data = s->resource_data;
|
||||||
struct resource_map *p, *q;
|
struct resource_map *p, *q;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
|
||||||
for (p = data->mem_db.next; p != &data->mem_db; p = q) {
|
for (p = data->mem_db.next; p != &data->mem_db; p = q) {
|
||||||
q = p->next;
|
q = p->next;
|
||||||
kfree(p);
|
kfree(p);
|
||||||
|
@ -938,7 +916,6 @@ static void nonstatic_release_resource_db(struct pcmcia_socket *s)
|
||||||
q = p->next;
|
q = p->next;
|
||||||
kfree(p);
|
kfree(p);
|
||||||
}
|
}
|
||||||
mutex_unlock(&rsrc_mutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -965,7 +942,7 @@ static ssize_t show_io_db(struct device *dev,
|
||||||
struct resource_map *p;
|
struct resource_map *p;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
mutex_lock(&s->ops_mutex);
|
||||||
data = s->resource_data;
|
data = s->resource_data;
|
||||||
|
|
||||||
for (p = data->io_db.next; p != &data->io_db; p = p->next) {
|
for (p = data->io_db.next; p != &data->io_db; p = p->next) {
|
||||||
|
@ -977,7 +954,7 @@ static ssize_t show_io_db(struct device *dev,
|
||||||
((unsigned long) p->base + p->num - 1));
|
((unsigned long) p->base + p->num - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&rsrc_mutex);
|
mutex_unlock(&s->ops_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1005,9 +982,11 @@ static ssize_t store_io_db(struct device *dev,
|
||||||
if (end_addr < start_addr)
|
if (end_addr < start_addr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&s->ops_mutex);
|
||||||
ret = adjust_io(s, add, start_addr, end_addr);
|
ret = adjust_io(s, add, start_addr, end_addr);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
s->resource_setup_new = 1;
|
s->resource_setup_new = 1;
|
||||||
|
mutex_unlock(&s->ops_mutex);
|
||||||
|
|
||||||
return ret ? ret : count;
|
return ret ? ret : count;
|
||||||
}
|
}
|
||||||
|
@ -1021,7 +1000,7 @@ static ssize_t show_mem_db(struct device *dev,
|
||||||
struct resource_map *p;
|
struct resource_map *p;
|
||||||
ssize_t ret = 0;
|
ssize_t ret = 0;
|
||||||
|
|
||||||
mutex_lock(&rsrc_mutex);
|
mutex_lock(&s->ops_mutex);
|
||||||
data = s->resource_data;
|
data = s->resource_data;
|
||||||
|
|
||||||
for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
|
for (p = data->mem_db.next; p != &data->mem_db; p = p->next) {
|
||||||
|
@ -1033,7 +1012,7 @@ static ssize_t show_mem_db(struct device *dev,
|
||||||
((unsigned long) p->base + p->num - 1));
|
((unsigned long) p->base + p->num - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&rsrc_mutex);
|
mutex_unlock(&s->ops_mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1061,9 +1040,11 @@ static ssize_t store_mem_db(struct device *dev,
|
||||||
if (end_addr < start_addr)
|
if (end_addr < start_addr)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
|
mutex_lock(&s->ops_mutex);
|
||||||
ret = adjust_memory(s, add, start_addr, end_addr);
|
ret = adjust_memory(s, add, start_addr, end_addr);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
s->resource_setup_new = 1;
|
s->resource_setup_new = 1;
|
||||||
|
mutex_unlock(&s->ops_mutex);
|
||||||
|
|
||||||
return ret ? ret : count;
|
return ret ? ret : count;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue