From d250a4810402ec68f64802b66340a0e70c61cbd3 Mon Sep 17 00:00:00 2001 From: Daniel Ritz Date: Mon, 6 Mar 2006 17:37:04 +0100 Subject: [PATCH] yenta: do power-up only after socket is configured Power-up the card only after the socket is configured. power-down in the old place. The point is not to power-up the card before the interrupt routing is set up correctly. Signed-off-by: Daniel Ritz Signed-off-by: Dominik Brodowski --- drivers/pcmcia/yenta_socket.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 4145eb83b9b..006749dc8d7 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -287,7 +287,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) struct yenta_socket *socket = container_of(sock, struct yenta_socket, socket); u16 bridge; - yenta_set_power(socket, state); + /* if powering down: do it immediately */ + if (state->Vcc == 0) + yenta_set_power(socket, state); + socket->io_irq = state->io_irq; bridge = config_readw(socket, CB_BRIDGE_CONTROL) & ~(CB_BRIDGE_CRST | CB_BRIDGE_INTR); if (cb_readl(socket, CB_SOCKET_STATE) & CB_CBCARD) { @@ -339,6 +342,10 @@ static int yenta_set_socket(struct pcmcia_socket *sock, socket_state_t *state) /* Socket event mask: get card insert/remove events.. */ cb_writel(socket, CB_SOCKET_EVENT, -1); cb_writel(socket, CB_SOCKET_MASK, CB_CDMASK); + + /* if powering up: do it as the last step when the socket is configured */ + if (state->Vcc != 0) + yenta_set_power(socket, state); return 0; } -- cgit v1.2.3 From b435261b1e09bb2bb6acc4abbc7f6e3d885f9e62 Mon Sep 17 00:00:00 2001 From: Bernhard Kaindl Date: Tue, 30 May 2006 18:00:34 +0200 Subject: [PATCH] yenta: fix hidden PCI bus numbers Fixup the subordinate number parent bridge of yenta Cardbus Bridges before the PCI bus scan starts to make the cardbus cards which are otherwise hidden for PCI scans work. Signed-off-by: Bernhard Kaindl Signed-off-by: Dominik Brodowski --- drivers/pcmcia/yenta_socket.c | 73 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 006749dc8d7..d9d005ec920 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1005,6 +1005,77 @@ static void yenta_config_init(struct yenta_socket *socket) config_writew(socket, CB_BRIDGE_CONTROL, bridge); } +/** + * yenta_fixup_parent_subordinate - Fix subordinate bus# of the parent bridge + * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to + * + * Checks if devices on the bus which the CardBus bridge bridges to would be + * invisible during PCI scans because of a misconfigured subordinate number + * of the parent brige - some BIOSes seem to be too lazy to set it right. + * Does the fixup carefully by checking how far it can go without conflicts. + * See http://bugzilla.kernel.org/show_bug.cgi?id=2944 for more information. + */ +static void yenta_fixup_parent_bridge(struct pci_bus *cardbus_bridge) +{ + struct list_head *tmp; + unsigned char upper_limit; + /* + * We only check and fix the parent bridge: All systems which need + * this fixup that have been reviewed are laptops and the only bridge + * which needed fixing was the parent bridge of the CardBus bridge: + */ + struct pci_bus *bridge_to_fix = cardbus_bridge->parent; + + /* Check bus numbers are already set up correctly: */ + if (bridge_to_fix->subordinate >= cardbus_bridge->subordinate) + return; /* The subordinate number is ok, nothing to do */ + + if (!bridge_to_fix->parent) + return; /* Root bridges are ok */ + + /* stay within the limits of the bus range of the parent: */ + upper_limit = bridge_to_fix->parent->subordinate; + + /* check the bus ranges of all silbling bridges to prevent overlap */ + list_for_each(tmp, &bridge_to_fix->parent->children) { + struct pci_bus * silbling = pci_bus_b(tmp); + /* + * If the silbling has a higher secondary bus number + * and it's secondary is equal or smaller than our + * current upper limit, set the new upper limit to + * the bus number below the silbling's range: + */ + if (silbling->secondary > bridge_to_fix->subordinate + && silbling->secondary <= upper_limit) + upper_limit = silbling->secondary - 1; + } + + /* Show that the wanted subordinate number is not possible: */ + if (cardbus_bridge->subordinate > upper_limit) + printk(KERN_WARNING "Yenta: Upper limit for fixing this " + "bridge's parent bridge: #%02x\n", upper_limit); + + /* If we have room to increase the bridge's subordinate number, */ + if (bridge_to_fix->subordinate < upper_limit) { + + /* use the highest number of the hidden bus, within limits */ + unsigned char subordinate_to_assign = + min(cardbus_bridge->subordinate, upper_limit); + + printk(KERN_INFO "Yenta: Raising subordinate bus# of parent " + "bus (#%02x) from #%02x to #%02x\n", + bridge_to_fix->number, + bridge_to_fix->subordinate, subordinate_to_assign); + + /* Save the new subordinate in the bus struct of the bridge */ + bridge_to_fix->subordinate = subordinate_to_assign; + + /* and update the PCI config space with the new subordinate */ + pci_write_config_byte(bridge_to_fix->self, + PCI_SUBORDINATE_BUS, bridge_to_fix->subordinate); + } +} + /* * Initialize a cardbus controller. Make sure we have a usable * interrupt, and that we can map the cardbus area. Fill in the @@ -1120,6 +1191,8 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i yenta_get_socket_capabilities(socket, isa_interrupts); printk(KERN_INFO "Socket status: %08x\n", cb_readl(socket, CB_SOCKET_STATE)); + yenta_fixup_parent_bridge(dev->subordinate); + /* Register it with the pcmcia layer.. */ ret = pcmcia_register_socket(&socket->socket); if (ret == 0) { -- cgit v1.2.3 From c533120b8da215dc02310c535fa87c5c480d0f14 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Tue, 16 May 2006 16:16:44 +0100 Subject: [PATCH] pcmcia: warn if driver requests exclusive, but gets a shared IRQ The patch below cleans up the pcmcia code a bit on the IRQ side (I did this while debugging the problem just so I could read wtf it was doing), and also adds a warning and passes back the correct information when a device asks for exclusive but gets given shared. This at least means the dmesg dump of a problem triggered by this will have a signature to find. Signed-off-by: Alan Cox Signed-off-by: Dominik Brodowski --- drivers/pcmcia/pcmcia_resource.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c index 3131bb0a009..3281e519e71 100644 --- a/drivers/pcmcia/pcmcia_resource.c +++ b/drivers/pcmcia/pcmcia_resource.c @@ -788,6 +788,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) struct pcmcia_socket *s = p_dev->socket; config_t *c; int ret = CS_IN_USE, irq = 0; + int type; if (!(s->state & SOCKET_PRESENT)) return CS_NO_CARD; @@ -797,6 +798,13 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (c->state & CONFIG_IRQ_REQ) return CS_IN_USE; + /* Decide what type of interrupt we are registering */ + type = 0; + if (s->functions > 1) /* All of this ought to be handled higher up */ + type = SA_SHIRQ; + if (req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) + type = SA_SHIRQ; + #ifdef CONFIG_PCMCIA_PROBE if (s->irq.AssignedIRQ != 0) { /* If the interrupt is already assigned, it must be the same */ @@ -822,9 +830,7 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) * marked as used by the kernel resource management core */ ret = request_irq(irq, (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action, - ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || - (s->functions > 1) || - (irq == s->pci_irq)) ? SA_SHIRQ : 0, + type, p_dev->devname, (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data); if (!ret) { @@ -839,18 +845,21 @@ int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req) if (ret && !s->irq.AssignedIRQ) { if (!s->pci_irq) return ret; + type = SA_SHIRQ; irq = s->pci_irq; } - if (ret && req->Attributes & IRQ_HANDLE_PRESENT) { - if (request_irq(irq, req->Handler, - ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) || - (s->functions > 1) || - (irq == s->pci_irq)) ? SA_SHIRQ : 0, - p_dev->devname, req->Instance)) + if (ret && (req->Attributes & IRQ_HANDLE_PRESENT)) { + if (request_irq(irq, req->Handler, type, p_dev->devname, req->Instance)) return CS_IN_USE; } + /* Make sure the fact the request type was overridden is passed back */ + if (type == SA_SHIRQ && !(req->Attributes & IRQ_TYPE_DYNAMIC_SHARING)) { + req->Attributes |= IRQ_TYPE_DYNAMIC_SHARING; + printk(KERN_WARNING "pcmcia: request for exclusive IRQ could not be fulfilled.\n"); + printk(KERN_WARNING "pcmcia: the driver needs updating to supported shared IRQ lines.\n"); + } c->irq.Attributes = req->Attributes; s->irq.AssignedIRQ = req->AssignedIRQ = irq; s->irq.Config++; -- cgit v1.2.3 From 59e35ba1257903eaff5203f62f77554da02f5b63 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Mon, 8 May 2006 23:22:07 -0600 Subject: [PATCH] pcmcia: TI PCIxx12 CardBus controller support The patch below adds support for the TI PCIxx12 CardBus controllers. This seems to be sufficient to detect the cardbus bridge on an HP nc6320 and works with an orinoco wifi card. Signed-off-by: Alex Williamson Signed-off-by: Dominik Brodowski --- drivers/pcmcia/ti113x.h | 1 + drivers/pcmcia/yenta_socket.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h index 7a3d1b8e16b..62e9ebf967f 100644 --- a/drivers/pcmcia/ti113x.h +++ b/drivers/pcmcia/ti113x.h @@ -647,6 +647,7 @@ static int ti12xx_2nd_slot_empty(struct yenta_socket *socket) */ break; + case PCI_DEVICE_ID_TI_XX12: case PCI_DEVICE_ID_TI_X515: case PCI_DEVICE_ID_TI_X420: case PCI_DEVICE_ID_TI_X620: diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index d9d005ec920..9fcd6612aeb 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1312,6 +1312,7 @@ static struct pci_device_id yenta_table [] = { CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X515, TI12XX), + CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X420, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_X620, TI12XX), CB_ID(PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_7410, TI12XX), -- cgit v1.2.3 From 0db6095d4ff8918350797dfe299d572980e82fa0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Wed, 19 Apr 2006 06:37:48 -0700 Subject: [PATCH] pcmcia: at91_cf suspend/resume/wakeup AT91 CF updates, mostly for power management: - Add suspend/resume methods to the AT91 CF driver, disabling non-wakeup IRQs during system suspend. The card detect IRQ serves as a wakeup event source. - Convert the driver to the more-current "platform_driver" style. So inserting or removing a CF card will wake the system, unless that has been disabled by updating the sysfs file; and there will be no more warnings about spurious IRQs during suspend/resume cycles. Signed-off-by: David Brownell Signed-off-by: Dominik Brodowski --- drivers/pcmcia/at91_cf.c | 75 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 16 deletions(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c index a4d50940ebe..5256342e853 100644 --- a/drivers/pcmcia/at91_cf.c +++ b/drivers/pcmcia/at91_cf.c @@ -214,11 +214,10 @@ static struct pccard_operations at91_cf_ops = { /*--------------------------------------------------------------------------*/ -static int __init at91_cf_probe(struct device *dev) +static int __init at91_cf_probe(struct platform_device *pdev) { struct at91_cf_socket *cf; - struct at91_cf_data *board = dev->platform_data; - struct platform_device *pdev = to_platform_device(dev); + struct at91_cf_data *board = pdev->dev.platform_data; struct resource *io; unsigned int csa; int status; @@ -236,7 +235,7 @@ static int __init at91_cf_probe(struct device *dev) cf->board = board; cf->pdev = pdev; - dev_set_drvdata(dev, cf); + platform_set_drvdata(pdev, cf); /* CF takes over CS4, CS5, CS6 */ csa = at91_sys_read(AT91_EBI_CSA); @@ -271,6 +270,7 @@ static int __init at91_cf_probe(struct device *dev) SA_SAMPLE_RANDOM, driver_name, cf); if (status < 0) goto fail0; + device_init_wakeup(&pdev->dev, 1); /* * The card driver will request this irq later as needed. @@ -301,7 +301,7 @@ static int __init at91_cf_probe(struct device *dev) board->det_pin, board->irq_pin); cf->socket.owner = THIS_MODULE; - cf->socket.dev.dev = dev; + cf->socket.dev.dev = &pdev->dev; cf->socket.ops = &at91_cf_ops; cf->socket.resource_ops = &pccard_static_ops; cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP @@ -323,21 +323,25 @@ fail1: free_irq(board->irq_pin, cf); fail0a: free_irq(board->det_pin, cf); + device_init_wakeup(&pdev->dev, 0); fail0: at91_sys_write(AT91_EBI_CSA, csa); kfree(cf); return status; } -static int __exit at91_cf_remove(struct device *dev) +static int __exit at91_cf_remove(struct platform_device *pdev) { - struct at91_cf_socket *cf = dev_get_drvdata(dev); + struct at91_cf_socket *cf = platform_get_drvdata(pdev); + struct at91_cf_data *board = cf->board; struct resource *io = cf->socket.io[0].res; unsigned int csa; pcmcia_unregister_socket(&cf->socket); - free_irq(cf->board->irq_pin, cf); - free_irq(cf->board->det_pin, cf); + if (board->irq_pin) + free_irq(board->irq_pin, cf); + free_irq(board->det_pin, cf); + device_init_wakeup(&pdev->dev, 0); iounmap((void __iomem *) cf->socket.io_offset); release_mem_region(io->start, io->end + 1 - io->start); @@ -348,26 +352,65 @@ static int __exit at91_cf_remove(struct device *dev) return 0; } -static struct device_driver at91_cf_driver = { - .name = (char *) driver_name, - .bus = &platform_bus_type, +#ifdef CONFIG_PM + +static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + struct at91_cf_socket *cf = platform_get_drvdata(pdev); + struct at91_cf_data *board = cf->board; + + pcmcia_socket_dev_suspend(&pdev->dev, mesg); + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(board->det_pin); + else { + disable_irq_wake(board->det_pin); + disable_irq(board->det_pin); + } + if (board->irq_pin) + disable_irq(board->irq_pin); + return 0; +} + +static int at91_cf_resume(struct platform_device *pdev) +{ + struct at91_cf_socket *cf = platform_get_drvdata(pdev); + struct at91_cf_data *board = cf->board; + + if (board->irq_pin) + enable_irq(board->irq_pin); + if (!device_may_wakeup(&pdev->dev)) + enable_irq(board->det_pin); + pcmcia_socket_dev_resume(&pdev->dev); + return 0; +} + +#else +#define at91_cf_suspend NULL +#define at91_cf_resume NULL +#endif + +static struct platform_driver at91_cf_driver = { + .driver = { + .name = (char *) driver_name, + .owner = THIS_MODULE, + }, .probe = at91_cf_probe, .remove = __exit_p(at91_cf_remove), - .suspend = pcmcia_socket_dev_suspend, - .resume = pcmcia_socket_dev_resume, + .suspend = at91_cf_suspend, + .resume = at91_cf_resume, }; /*--------------------------------------------------------------------------*/ static int __init at91_cf_init(void) { - return driver_register(&at91_cf_driver); + return platform_driver_register(&at91_cf_driver); } module_init(at91_cf_init); static void __exit at91_cf_exit(void) { - driver_unregister(&at91_cf_driver); + platform_driver_unregister(&at91_cf_driver); } module_exit(at91_cf_exit); -- cgit v1.2.3 From 66005216074337e3925514456175b202f17e23ef Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 6 Jun 2006 12:06:41 -0700 Subject: [PATCH] pcmcia: fix kernel-doc function name Fix kernel-doc function name spello. Signed-off-by: Randy Dunlap Signed-off-by: Dominik Brodowski --- drivers/pcmcia/yenta_socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c index 9fcd6612aeb..47e57602d5e 100644 --- a/drivers/pcmcia/yenta_socket.c +++ b/drivers/pcmcia/yenta_socket.c @@ -1006,7 +1006,7 @@ static void yenta_config_init(struct yenta_socket *socket) } /** - * yenta_fixup_parent_subordinate - Fix subordinate bus# of the parent bridge + * yenta_fixup_parent_bridge - Fix subordinate bus# of the parent bridge * @cardbus_bridge: The PCI bus which the CardBus bridge bridges to * * Checks if devices on the bus which the CardBus bridge bridges to would be -- cgit v1.2.3 From 1da9ab7389b8a0789a1b3ad43d3efe80b4c57c03 Mon Sep 17 00:00:00 2001 From: "Serge E. Hallyn" Date: Wed, 14 Jun 2006 08:01:26 -0500 Subject: [PATCH] pcmcia: convert pcmcia_cs to kthread Convert pcmcia_cs to use kthread instead of the deprecated kernel_thread. Signed-off-by: Serge E. Hallyn Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 3162998579c..06e2cda4e07 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -176,6 +177,7 @@ static int pccardd(void *__skt); */ int pcmcia_register_socket(struct pcmcia_socket *socket) { + struct task_struct *tsk; int ret; if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops) @@ -239,15 +241,18 @@ int pcmcia_register_socket(struct pcmcia_socket *socket) mutex_init(&socket->skt_mutex); spin_lock_init(&socket->thread_lock); - ret = kernel_thread(pccardd, socket, CLONE_KERNEL); - if (ret < 0) + tsk = kthread_run(pccardd, socket, "pccardd"); + if (IS_ERR(tsk)) { + ret = PTR_ERR(tsk); goto err; + } wait_for_completion(&socket->thread_done); - if(!socket->thread) { + if (!socket->thread) { printk(KERN_WARNING "PCMCIA: warning: socket thread for socket %p did not start\n", socket); return -EIO; } + pcmcia_parse_events(socket, SS_DETECT); return 0; @@ -272,10 +277,8 @@ void pcmcia_unregister_socket(struct pcmcia_socket *socket) cs_dbg(socket, 0, "pcmcia_unregister_socket(0x%p)\n", socket->ops); if (socket->thread) { - init_completion(&socket->thread_done); - socket->thread = NULL; wake_up(&socket->thread_wait); - wait_for_completion(&socket->thread_done); + kthread_stop(socket->thread); } release_cis_mem(socket); @@ -630,8 +633,6 @@ static int pccardd(void *__skt) DECLARE_WAITQUEUE(wait, current); int ret; - daemonize("pccardd"); - skt->thread = current; skt->socket = dead_socket; skt->ops->init(skt); @@ -643,7 +644,8 @@ static int pccardd(void *__skt) printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n", skt); skt->thread = NULL; - complete_and_exit(&skt->thread_done, 0); + complete(&skt->thread_done); + return 0; } add_wait_queue(&skt->thread_wait, &wait); @@ -674,7 +676,7 @@ static int pccardd(void *__skt) continue; } - if (!skt->thread) + if (kthread_should_stop()) break; schedule(); @@ -688,7 +690,7 @@ static int pccardd(void *__skt) /* remove from the device core */ class_device_unregister(&skt->dev); - complete_and_exit(&skt->thread_done, 0); + return 0; } /* -- cgit v1.2.3 From 0973ddddca72bc8aee8a273c232060b9608d1793 Mon Sep 17 00:00:00 2001 From: Domen Puncer Date: Fri, 23 Jun 2006 12:06:56 +0100 Subject: [PATCH] au1xxx: pcmcia: fix __init called from non-init This must not be marked __init, as it is called from au1x00_drv_pcmcia_probe. Signed-off-by: Domen Puncer Signed-off-by: Dominik Brodowski --- drivers/pcmcia/au1000_db1x00.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/au1000_db1x00.c b/drivers/pcmcia/au1000_db1x00.c index abc13f28ba3..fef99f4e30c 100644 --- a/drivers/pcmcia/au1000_db1x00.c +++ b/drivers/pcmcia/au1000_db1x00.c @@ -296,7 +296,7 @@ struct pcmcia_low_level db1x00_pcmcia_ops = { .socket_suspend = db1x00_socket_suspend }; -int __init au1x_board_init(struct device *dev) +int au1x_board_init(struct device *dev) { int ret = -ENODEV; bcsr->pcmcia = 0; /* turn off power, if it's not already off */ -- cgit v1.2.3 From 4b7a89a3c1cf545b03470416aa821fc2ff826b91 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Fri, 30 Jun 2006 10:31:13 +0200 Subject: [PATCH] pcmcia: fix deadlock in pcmcia_parse_events The PCMCIA layer calls pcmcia_parse_events both from user context and IRQ context; the lock thus needs to be irqsave to avoid deadlocks Signed-off-by: Arjan van de Ven Signed-off-by: Dominik Brodowski --- drivers/pcmcia/cs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/pcmcia') diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c index 06e2cda4e07..f9cd831a3f3 100644 --- a/drivers/pcmcia/cs.c +++ b/drivers/pcmcia/cs.c @@ -699,11 +699,12 @@ static int pccardd(void *__skt) */ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events) { + unsigned long flags; cs_dbg(s, 4, "parse_events: events %08x\n", events); if (s->thread) { - spin_lock(&s->thread_lock); + spin_lock_irqsave(&s->thread_lock, flags); s->thread_events |= events; - spin_unlock(&s->thread_lock); + spin_unlock_irqrestore(&s->thread_lock, flags); wake_up(&s->thread_wait); } -- cgit v1.2.3