Skip to contentSkip to conversation

IDE Power Management, try 3

PATCH New Benjamin Herrenschmidt 1 participant 1 message Jun 6, 2003 Block layer

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 IDE Power Management, try 3

Ok, here's a new one, if it's ok, please submit to Linus for inclusion.

Will remain to do:

- Check if more is needed in ide-disk (what is there is ok for my
needs on pmac, but Alan suggested some BIOSes may want us to restore some PIO settings or whatever)

- Check if more is needed for ide-cd. (In 2.4, I had to hack around
check media change & revalidate for things to work properly when putting the machine to sleep while reading MP3s from a mouted CD-ROM, I haven't yet cheked such scenarios in 2.5).

- Eventually do something for ide-floppy, ide-tape

- ide-scsi should probably just wait for proper PM stuff to be done
in the SCSI layer. That is sd or sr will get the suspend/resume requests and do what they have to (if anything has to be done).

I also considered that a PM state of 4 is suspend-to-disk and skipped the STANDBY step in this case.

Ben.

===== drivers/ide/ide-cd.c 1.49 vs edited =====

drivers/ide/ide-cd.c +44 -0
@@ -3253,6 +3253,44 @@
 
 static int ide_cdrom_attach (ide_drive_t *drive);
 
+/* Power Management state machine. 
+ *
+ * We don't do much for CDs right now
+ */
+
+
+static void ide_cdrom_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
+{
+}
+
+static ide_startstop_t ide_cdrom_start_power_step (ide_drive_t *drive, struct request *rq)
+{
+	ide_task_t *args = rq->special;
+
+	memset(args, 0, sizeof(ide_task_t));
+
+	switch(rq->pm->pm_step) {
+	case ide_pm_state_start_suspend:
+		break;
+
+	case ide_pm_state_start_resume:	/* Resume step 1 (restore DMA) */
+		/* Right now, all we do is call ide_dma_check for the HWIF,
+		 * we could be smarter and check for current xfer_speed
+		 * in struct drive etc...
+		 * Also, this step could be implemented as a generic helper
+		 * as most subdrivers will use it
+		 */
+		if (!drive->id || !(drive->id->capability & 1))
+			break;
+		if (HWIF(drive)->ide_dma_check == NULL)
+			break;
+		HWIF(drive)->ide_dma_check(drive);
+		break;
+	}
+	rq->pm->pm_step = ide_pm_state_completed;
+	return ide_stopped;
+}
+
 static ide_driver_t ide_cdrom_driver = {
 	.owner			= THIS_MODULE,
 	.name			= "ide-cdrom",
@@ -3269,6 +3307,12 @@
 	.capacity		= ide_cdrom_capacity,
 	.attach			= ide_cdrom_attach,
 	.drives			= LIST_HEAD_INIT(ide_cdrom_driver.drives),
+	.start_power_step	= ide_cdrom_start_power_step,
+	.complete_power_step	= ide_cdrom_complete_power_step,
+	.gen_driver		= {
+		.suspend	= generic_ide_suspend,
+		.resume		= generic_ide_resume,
+	}
 };
 
 static int idecd_open(struct inode * inode, struct file * file)

===== drivers/ide/ide-disk.c 1.45 vs edited =====

drivers/ide/ide-disk.c +64 -45

148 lines not on this page · raw message

===== drivers/ide/ide-io.c 1.11 vs edited =====

drivers/ide/ide-io.c +109 -4

174 lines not on this page · raw message

===== drivers/ide/ide-iops.c 1.17 vs edited =====

drivers/ide/ide-iops.c +27 -0
@@ -1318,5 +1318,32 @@
 	return do_reset1(drive, 0);
 }
 
+/*
+ * This function waits for the hwif to report a non-busy status
+ * see comments in probe_hwif()
+ */
+int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
+{
+	u8 stat = 0;
+	
+	while(timeout--) {
+		/* Turn this into a schedule() sleep once I'm sure
+		 * about locking issues (2.5 work ?)
+		 */
+		mdelay(1);
+		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
+		if ((stat & BUSY_STAT) == 0)
+			break;
+		/* Assume a value of 0xff means nothing is connected to
+		 * the interface and it doesn't implement the pull-down
+		 * resistor on D7
+		 */
+		if (stat == 0xff)
+			break;
+	}
+	return ((stat & BUSY_STAT) == 0) ? 0 : -EBUSY;
+}
+
+
 EXPORT_SYMBOL(ide_do_reset);
 

===== drivers/ide/ide-probe.c 1.49 vs edited =====

drivers/ide/ide-probe.c +3 -33
@@ -723,35 +723,6 @@
 
 //EXPORT_SYMBOL(hwif_register);
 
-/* Enable code below on all archs later, for now, I want it on PPC
- */
-#ifdef CONFIG_PPC
-/*
- * This function waits for the hwif to report a non-busy status
- * see comments in probe_hwif()
- */
-static int wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
-{
-	u8 stat = 0;
-	
-	while(timeout--) {
-		/* Turn this into a schedule() sleep once I'm sure
-		 * about locking issues (2.5 work ?)
-		 */
-		mdelay(1);
-		stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);
-		if ((stat & BUSY_STAT) == 0)
-			break;
-		/* Assume a value of 0xff means nothing is connected to
-		 * the interface and it doesn't implement the pull-down
-		 * resistor on D7
-		 */
-		if (stat == 0xff)
-			break;
-	}
-	return ((stat & BUSY_STAT) == 0) ? 0 : -EBUSY;
-}
-
 static int wait_hwif_ready(ide_hwif_t *hwif)
 {
 	int rc;
@@ -766,7 +737,7 @@
 	 * I know of at least one disk who takes 31 seconds, I use 35
 	 * here to be safe
 	 */
-	rc = wait_not_busy(hwif, 35000);
+	rc = ide_wait_not_busy(hwif, 35000);
 	if (rc)
 		return rc;
 
@@ -774,20 +745,19 @@
 	SELECT_DRIVE(&hwif->drives[0]);
 	hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 	mdelay(2);
-	rc = wait_not_busy(hwif, 10000);
+	rc = ide_wait_not_busy(hwif, 10000);
 	if (rc)
 		return rc;
 	SELECT_DRIVE(&hwif->drives[1]);
 	hwif->OUTB(8, hwif->io_ports[IDE_CONTROL_OFFSET]);
 	mdelay(2);
-	rc = wait_not_busy(hwif, 10000);
+	rc = ide_wait_not_busy(hwif, 10000);
 
 	/* Exit function with master reselected (let's be sane) */
 	SELECT_DRIVE(&hwif->drives[0]);
 	
 	return rc;
 }
-#endif /* CONFIG_PPC */
 
 /*
  * This routine only knows how to look for drive units 0 and 1

===== drivers/ide/ide.c 1.70 vs edited =====

drivers/ide/ide.c +48 -0

54 lines not on this page · raw message

===== include/linux/blkdev.h 1.106 vs edited =====

include/linux/blkdev.h +27 -0
@@ -19,6 +19,7 @@
 typedef struct request_queue request_queue_t;
 struct elevator_s;
 typedef struct elevator_s elevator_t;
+struct request_pm_state;
 
 #define BLKDEV_MIN_RQ	4
 #define BLKDEV_MAX_RQ	128
@@ -102,6 +103,11 @@
 	void *sense;
 
 	unsigned int timeout;
+
+	/*
+	 * For Power Management requests
+	 */
+	struct request_pm_state *pm;
 };
 
 /*
@@ -130,6 +136,10 @@
 	__REQ_DRIVE_CMD,
 	__REQ_DRIVE_TASK,
 	__REQ_DRIVE_TASKFILE,
+	__REQ_PREEMPT,    /* Flag set for "ide_preempt" requests */
+	__REQ_PM_SUSPEND, /* Suspend request */
+	__REQ_PM_RESUME,  /* Resume request */
+	__REQ_PM_SHUTDOWN,/* Shutdown request */
 	__REQ_NR_BITS,	/* stops here */
 };
 
@@ -151,6 +161,23 @@
 #define REQ_DRIVE_CMD	(1 << __REQ_DRIVE_CMD)
 #define REQ_DRIVE_TASK	(1 << __REQ_DRIVE_TASK)
 #define REQ_DRIVE_TASKFILE	(1 << __REQ_DRIVE_TASKFILE)
+#define REQ_PREEMPT	(1 << __REQ_PREEMPT)
+#define REQ_PM_SUSPEND	(1 << __REQ_PM_SUSPEND)
+#define REQ_PM_RESUME	(1 << __REQ_PM_RESUME)
+#define REQ_PM_SHUTDOWN	(1 << __REQ_PM_SHUTDOWN)
+
+#define blk_request_is_pm(rq)	\
+	((rq->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME)) != 0)
+
+/* State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
+ * requests. Some step values could eventually be made generic.
+ */
+struct request_pm_state
+{
+	int	pm_step;	/* PM state machine step value, currently driver specific */
+	int	pm_state;	/* requested PM state value (S1,S2,S3,S4,...) */
+	void*	data;		/* for driver use */
+};
 
 #include <linux/elevator.h>
 

===== include/linux/ide.h 1.54 vs edited =====

include/linux/ide.h +42 -0

78 lines not on this page · raw message