From: Martin Diehl <mdiehlcs@compuserve.de>
To: Linus Torvalds <torvalds@transmeta.com>
Cc: Martin Mares <mj@suse.cz>,
Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: [PATCH] yenta, pm - part 1
Date: Mon, 18 Dec 2000 14:08:25 +0100 (CET) [thread overview]
Message-ID: <Pine.LNX.4.21.0012181325370.579-100000@notebook.diehl.home> (raw)
In-Reply-To: <Pine.LNX.4.10.10012151042170.2255-100000@penguin.transmeta.com>
On Fri, 15 Dec 2000, Linus Torvalds wrote:
> I suspect that the suspend/resume will do something bad to the BAT
> registers, which control the BIOS area mapping behaviour, and it just
> kills the forwarding of the legacy region to the PCI bus, or something.
FYI: I've identified a single byte in the hostbridges config space which
is altered after resume. Blindly restoring it makes the 0xe6000 pci bus
address mapping accessible again. But I think that's not the Right way to
fix it.
> I wonder if the PCI cardbus init code should just notice this, and force
> all cardbus windows to be re-initialized. That legacy area address really
> doesn't look right.
That's what I've done now. So I'm sending the modification I made in case
you would still like them for 2.4.0. I've separated it in 2 (almost
independent) patches meant to be applied in series against 2.4.0-t12 (final)
This is part 1. It provides:
- pm_state, pm_lock for cardbus socket to prevent multiple suspend/resume,
especially the reentrant case due to some driver sleeping in resume.
- cardbus_change_pm_state() to handle pm state transition. Suspend is
handled synchronously but resume schedules an asynchronous completion
handler since pcmcia_resume_socket() may sleep.
- placing the pci_set_power_state() calls at the right place
Mainly touching pci_socket.* it fixes the suspend/resume multiple entrance
issues due to some driver (notably cardbus itself) sleeping in resume.
Regards
Martin
-----
diff -Nur v2.4.0-test12/drivers/pcmcia/pci_socket.c v2.4.0-t12-yenta1/driver/pcmcia/pci_socket.c
--- v2.4.0-test12/drivers/pcmcia/pci_socket.c Wed Nov 29 21:47:10 2000
+++ v2.4.0-t12-yenta1/driver/pcmcia/pci_socket.c Sun Dec 17 19:59:27 2000
@@ -178,6 +178,8 @@
socket->op = ops;
dev->driver_data = socket;
spin_lock_init(&socket->event_lock);
+ socket->pm_state = 0;
+ spin_lock_init(&socket->pm_lock);
return socket->op->open(socket);
}
@@ -212,16 +214,83 @@
dev->driver_data = 0;
}
+/* Delayed handler scheduled to complete the D3->D0 transition in the
+ * upper layers. We may sleep in pcmcia_resume_socket() with pm_lock
+ * hold - so we are save from resume re-entry due to other drivers
+ * sleeping in pci_pm resume handling.
+ */
+
+static void cardbus_resume_bh(void *data)
+{
+ pci_socket_t *socket = (pci_socket_t *)data;
+
+ pcmcia_resume_socket(socket->pcmcia_socket);
+ socket->pm_state = 0;
+ spin_unlock(&socket->pm_lock);
+ MOD_DEC_USE_COUNT;
+}
+
+/* We are forced to implement asynch resume semantics because the
+ * pcmcia_resume path sleeps and we might get screwed by a second
+ * pci_pm_resume_device() hitting us in the middle of the first one.
+ * Which might happen anyway, if other drivers do not cooperate!
+ * So it's good to know we are protected by our socket->pm_lock.
+ */
+
+static void cardbus_change_pm_state(pci_socket_t *socket, int newstate)
+{
+ switch (newstate) {
+ case 3:
+ pcmcia_suspend_socket(socket->pcmcia_socket);
+ break;
+
+ case 0:
+ socket->tq_resume.routine = cardbus_resume_bh;
+ socket->tq_resume.data = socket;
+ MOD_INC_USE_COUNT;
+ schedule_task(&socket->tq_resume);
+ break;
+ default:
+ printk("cardbus: undefined power state\n");
+ break;
+ }
+}
+
+
static void cardbus_suspend (struct pci_dev *dev)
{
pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
- pcmcia_suspend_socket (socket->pcmcia_socket);
+
+ spin_lock(&socket->pm_lock);
+ if (socket->pm_state != 0) {
+ spin_unlock(&socket->pm_lock);
+ printk("cardbus: suspend of already suspended socket blocked\n");
+ return;
+ }
+ cardbus_change_pm_state(socket,3);
+ pci_set_power_state(dev,3);
+ socket->pm_state = 3;
+ spin_unlock(&socket->pm_lock);
}
static void cardbus_resume (struct pci_dev *dev)
{
pci_socket_t *socket = (pci_socket_t *) dev->driver_data;
- pcmcia_resume_socket (socket->pcmcia_socket);
+
+ spin_lock(&socket->pm_lock);
+ if (socket->pm_state != 3) {
+ spin_unlock(&socket->pm_lock);
+ printk("cardbus: resume of non-suspended socket blocked\n");
+ return;
+ }
+ pci_set_power_state(dev,0);
+ cardbus_change_pm_state(socket, 0);
+
+ /* we intentionally leave with socket->pm_state not updated
+ * and socket->pm_lock still acquired!
+ * Will be released by the pending cardbus_resume_bh()
+ * Needed to protect against resume re-entry.
+ */
}
diff -Nur v2.4.0-test12/drivers/pcmcia/pci_socket.h v2.4.0-t12-yenta1/driver/pcmcia/pci_socket.h
--- v2.4.0-test12/drivers/pcmcia/pci_socket.h Wed Nov 29 21:47:10 2000
+++ v2.4.0-t12-yenta1/driver/pcmcia/pci_socket.h Sun Dec 17 20:04:32 2000
@@ -26,6 +26,14 @@
/* A few words of private data for the low-level driver.. */
unsigned int private[8];
+
+ /* used for delayed resume completion handler */
+ struct tq_struct tq_resume;
+
+ /* to protect our pm state management */
+ unsigned int pm_state;
+ spinlock_t pm_lock;
+
} pci_socket_t;
struct pci_socket_ops {
diff -Nur v2.4.0-test12/drivers/pcmcia/yenta.c v2.4.0-t12-yenta1/driver/pcmcia/yenta.c
--- v2.4.0-test12/drivers/pcmcia/yenta.c Wed Nov 29 21:47:10 2000
+++ v2.4.0-t12-yenta1/driver/pcmcia/yenta.c Sun Dec 17 20:00:17 2000
@@ -629,8 +629,6 @@
u16 bridge;
struct pci_dev *dev = socket->dev;
- pci_set_power_state(socket->dev, 0);
-
config_writel(socket, CB_LEGACY_MODE_BASE, 0);
config_writel(socket, PCI_BASE_ADDRESS_0, dev->resource[0].start);
config_writew(socket, PCI_COMMAND,
@@ -687,8 +685,6 @@
* the IO and MEM bridging region data.. That is
* something that pci_set_power_state() should
* probably know about bridges anyway.
- *
- pci_set_power_state(socket->dev, 3);
*/
return 0;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
Please read the FAQ at http://www.tux.org/lkml/
next prev parent reply other threads:[~2000-12-18 13:38 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <Pine.LNX.4.30.0012052110590.968-100000@localhost.localdomain>
2000-12-05 23:04 ` PCI irq routing Linus Torvalds
2000-12-05 23:25 ` Kai Germaschewski
2000-12-06 9:29 ` Martin Diehl
2000-12-06 17:49 ` Linus Torvalds
2000-12-07 18:30 ` Martin Diehl
2000-12-07 18:38 ` Linus Torvalds
2000-12-08 0:49 ` Martin Diehl
2000-12-11 1:46 ` [PATCH] VLSI irq router (was: PCI irq routing..) Martin Diehl
2000-12-15 18:39 ` yenta, pm, ioremap(!) problems " Martin Diehl
2000-12-15 18:55 ` Linus Torvalds
2000-12-16 0:21 ` Martin Diehl
2000-12-18 13:08 ` Martin Diehl [this message]
2000-12-18 13:10 ` [PATCH] yenta, pm - part 2 Martin Diehl
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.21.0012181325370.579-100000@notebook.diehl.home \
--to=mdiehlcs@compuserve.de \
--cc=linux-kernel@vger.kernel.org \
--cc=mj@suse.cz \
--cc=torvalds@transmeta.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).