Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb-storage: implement autosuspend

This patch (as930) implements autosuspend for usb-storage. It is
adapted from a patch by Oliver Neukum. Autosuspend is allowed except
during LUN scanning, resets, and command execution.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Alan Stern and committed by
Greg Kroah-Hartman
8dfe4b14 b0e2a705

+29 -11
+9 -4
drivers/usb/storage/scsiglue.c
··· 285 285 286 286 US_DEBUGP("%s called\n", __FUNCTION__); 287 287 288 - /* lock the device pointers and do the reset */ 289 - mutex_lock(&(us->dev_mutex)); 290 - result = us->transport_reset(us); 291 - mutex_unlock(&us->dev_mutex); 288 + result = usb_autopm_get_interface(us->pusb_intf); 289 + if (result == 0) { 290 + 291 + /* lock the device pointers and do the reset */ 292 + mutex_lock(&(us->dev_mutex)); 293 + result = us->transport_reset(us); 294 + mutex_unlock(&us->dev_mutex); 295 + usb_autopm_put_interface(us->pusb_intf); 296 + } 292 297 293 298 return result < 0 ? FAILED : SUCCESS; 294 299 }
+20 -7
drivers/usb/storage/usb.c
··· 191 191 { 192 192 struct us_data *us = usb_get_intfdata(iface); 193 193 194 + US_DEBUGP("%s\n", __FUNCTION__); 195 + 194 196 /* Wait until no command is running */ 195 197 mutex_lock(&us->dev_mutex); 196 198 197 - US_DEBUGP("%s\n", __FUNCTION__); 198 199 if (us->suspend_resume_hook) 199 200 (us->suspend_resume_hook)(us, US_SUSPEND); 200 - 201 - /* When runtime PM is working, we'll set a flag to indicate 202 - * whether we should autoresume when a SCSI request arrives. */ 203 201 204 202 mutex_unlock(&us->dev_mutex); 205 203 return 0; ··· 207 209 { 208 210 struct us_data *us = usb_get_intfdata(iface); 209 211 210 - mutex_lock(&us->dev_mutex); 211 - 212 212 US_DEBUGP("%s\n", __FUNCTION__); 213 + 213 214 if (us->suspend_resume_hook) 214 215 (us->suspend_resume_hook)(us, US_RESUME); 215 216 216 - mutex_unlock(&us->dev_mutex); 217 217 return 0; 218 218 } 219 219 ··· 309 313 { 310 314 struct us_data *us = (struct us_data *)__us; 311 315 struct Scsi_Host *host = us_to_host(us); 316 + int autopm_rc; 312 317 313 318 current->flags |= PF_NOFREEZE; 314 319 ··· 319 322 break; 320 323 321 324 US_DEBUGP("*** thread awakened.\n"); 325 + 326 + /* Autoresume the device */ 327 + autopm_rc = usb_autopm_get_interface(us->pusb_intf); 322 328 323 329 /* lock the device pointers */ 324 330 mutex_lock(&(us->dev_mutex)); ··· 381 381 us->srb->result = SAM_STAT_GOOD; 382 382 } 383 383 384 + /* Did the autoresume fail? */ 385 + else if (autopm_rc < 0) { 386 + US_DEBUGP("Could not wake device\n"); 387 + us->srb->result = DID_ERROR << 16; 388 + } 389 + 384 390 /* we've got a command, let's do it! */ 385 391 else { 386 392 US_DEBUG(usb_stor_show_command(us->srb)); ··· 429 423 430 424 /* unlock the device pointers */ 431 425 mutex_unlock(&us->dev_mutex); 426 + 427 + /* Start an autosuspend */ 428 + if (autopm_rc == 0) 429 + usb_autopm_put_interface(us->pusb_intf); 432 430 } /* for (;;) */ 433 431 434 432 /* Wait until we are told to stop */ ··· 949 939 } 950 940 951 941 scsi_host_put(us_to_host(us)); 942 + usb_autopm_put_interface(us->pusb_intf); 952 943 complete_and_exit(&threads_gone, 0); 953 944 } 954 945 ··· 1039 1028 * start it up. */ 1040 1029 scsi_host_get(us_to_host(us)); 1041 1030 atomic_inc(&total_threads); 1031 + usb_autopm_get_interface(intf); /* dropped in the scanning thread */ 1042 1032 wake_up_process(th); 1043 1033 1044 1034 return 0; ··· 1077 1065 .pre_reset = storage_pre_reset, 1078 1066 .post_reset = storage_post_reset, 1079 1067 .id_table = storage_usb_ids, 1068 + .supports_autosuspend = 1, 1080 1069 }; 1081 1070 1082 1071 static int __init usb_stor_init(void)