diff options
Diffstat (limited to 'drivers')
130 files changed, 5155 insertions, 1517 deletions
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h index 07e20135f01b..0bba148a2c61 100644 --- a/drivers/acpi/acpica/acevents.h +++ b/drivers/acpi/acpica/acevents.h | |||
@@ -139,7 +139,7 @@ acpi_status acpi_ev_initialize_op_regions(void); | |||
139 | acpi_status | 139 | acpi_status |
140 | acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, | 140 | acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, |
141 | u32 function, | 141 | u32 function, |
142 | acpi_physical_address address, | 142 | u32 region_offset, |
143 | u32 bit_width, acpi_integer * value); | 143 | u32 bit_width, acpi_integer * value); |
144 | 144 | ||
145 | acpi_status | 145 | acpi_status |
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 16e5210ae936..3d87362d17ed 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h | |||
@@ -362,9 +362,6 @@ extern u8 acpi_gbl_method_executing; | |||
362 | extern u8 acpi_gbl_abort_method; | 362 | extern u8 acpi_gbl_abort_method; |
363 | extern u8 acpi_gbl_db_terminate_threads; | 363 | extern u8 acpi_gbl_db_terminate_threads; |
364 | 364 | ||
365 | ACPI_EXTERN int optind; | ||
366 | ACPI_EXTERN char *optarg; | ||
367 | |||
368 | ACPI_EXTERN u8 acpi_gbl_db_opt_tables; | 365 | ACPI_EXTERN u8 acpi_gbl_db_opt_tables; |
369 | ACPI_EXTERN u8 acpi_gbl_db_opt_stats; | 366 | ACPI_EXTERN u8 acpi_gbl_db_opt_stats; |
370 | ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; | 367 | ACPI_EXTERN u8 acpi_gbl_db_opt_ini_methods; |
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 2ec394a328e9..ee986edfa0da 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h | |||
@@ -205,6 +205,7 @@ struct acpi_namespace_node { | |||
205 | #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ | 205 | #define ANOBJ_METHOD_LOCAL 0x08 /* Node is a method local */ |
206 | #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ | 206 | #define ANOBJ_SUBTREE_HAS_INI 0x10 /* Used to optimize device initialization */ |
207 | #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ | 207 | #define ANOBJ_EVALUATED 0x20 /* Set on first evaluation of node */ |
208 | #define ANOBJ_ALLOCATED_BUFFER 0x40 /* Method AML buffer is dynamic (install_method) */ | ||
208 | 209 | ||
209 | #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ | 210 | #define ANOBJ_IS_EXTERNAL 0x08 /* i_aSL only: This object created via External() */ |
210 | #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ | 211 | #define ANOBJ_METHOD_NO_RETVAL 0x10 /* i_aSL only: Method has no return value */ |
@@ -788,11 +789,14 @@ struct acpi_bit_register_info { | |||
788 | /* For control registers, both ignored and reserved bits must be preserved */ | 789 | /* For control registers, both ignored and reserved bits must be preserved */ |
789 | 790 | ||
790 | /* | 791 | /* |
791 | * The ACPI spec says to ignore PM1_CTL.SCI_EN (bit 0) | 792 | * For PM1 control, the SCI enable bit (bit 0, SCI_EN) is defined by the |
792 | * but we need to be able to write ACPI_BITREG_SCI_ENABLE directly | 793 | * ACPI specification to be a "preserved" bit - "OSPM always preserves this |
793 | * as a BIOS workaround on some machines. | 794 | * bit position", section 4.7.3.2.1. However, on some machines the OS must |
795 | * write a one to this bit after resume for the machine to work properly. | ||
796 | * To enable this, we no longer attempt to preserve this bit. No machines | ||
797 | * are known to fail if the bit is not preserved. (May 2009) | ||
794 | */ | 798 | */ |
795 | #define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bits 9 */ | 799 | #define ACPI_PM1_CONTROL_IGNORED_BITS 0x0200 /* Bit 9 */ |
796 | #define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ | 800 | #define ACPI_PM1_CONTROL_RESERVED_BITS 0xC1F8 /* Bits 14-15, 3-8 */ |
797 | #define ACPI_PM1_CONTROL_PRESERVED_BITS \ | 801 | #define ACPI_PM1_CONTROL_PRESERVED_BITS \ |
798 | (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) | 802 | (ACPI_PM1_CONTROL_IGNORED_BITS | ACPI_PM1_CONTROL_RESERVED_BITS) |
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 46cb5b46d280..94cdc2b8cb93 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h | |||
@@ -99,10 +99,19 @@ acpi_ns_walk_namespace(acpi_object_type type, | |||
99 | acpi_walk_callback user_function, | 99 | acpi_walk_callback user_function, |
100 | void *context, void **return_value); | 100 | void *context, void **return_value); |
101 | 101 | ||
102 | struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node | 102 | struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node |
103 | *parent, struct acpi_namespace_node | 103 | *parent, |
104 | struct acpi_namespace_node | ||
104 | *child); | 105 | *child); |
105 | 106 | ||
107 | struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, | ||
108 | struct | ||
109 | acpi_namespace_node | ||
110 | *parent, | ||
111 | struct | ||
112 | acpi_namespace_node | ||
113 | *child); | ||
114 | |||
106 | /* | 115 | /* |
107 | * nsparse - table parsing | 116 | * nsparse - table parsing |
108 | */ | 117 | */ |
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h index ff851c5df698..067f967eb389 100644 --- a/drivers/acpi/acpica/amlcode.h +++ b/drivers/acpi/acpica/amlcode.h | |||
@@ -483,7 +483,7 @@ typedef enum { | |||
483 | 483 | ||
484 | #define AML_METHOD_ARG_COUNT 0x07 | 484 | #define AML_METHOD_ARG_COUNT 0x07 |
485 | #define AML_METHOD_SERIALIZED 0x08 | 485 | #define AML_METHOD_SERIALIZED 0x08 |
486 | #define AML_METHOD_SYNCH_LEVEL 0xF0 | 486 | #define AML_METHOD_SYNC_LEVEL 0xF0 |
487 | 487 | ||
488 | /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ | 488 | /* METHOD_FLAGS_ARG_COUNT is not used internally, define additional flags */ |
489 | 489 | ||
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c index dab3f48f0b42..02e6caad4a76 100644 --- a/drivers/acpi/acpica/dsobject.c +++ b/drivers/acpi/acpica/dsobject.c | |||
@@ -734,7 +734,8 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, | |||
734 | 734 | ||
735 | /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ | 735 | /* Local ID (0-7) is (AML opcode - base AML_LOCAL_OP) */ |
736 | 736 | ||
737 | obj_desc->reference.value = opcode - AML_LOCAL_OP; | 737 | obj_desc->reference.value = |
738 | ((u32)opcode) - AML_LOCAL_OP; | ||
738 | obj_desc->reference.class = ACPI_REFCLASS_LOCAL; | 739 | obj_desc->reference.class = ACPI_REFCLASS_LOCAL; |
739 | 740 | ||
740 | #ifndef ACPI_NO_METHOD_EXECUTION | 741 | #ifndef ACPI_NO_METHOD_EXECUTION |
@@ -754,7 +755,7 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, | |||
754 | 755 | ||
755 | /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ | 756 | /* Arg ID (0-6) is (AML opcode - base AML_ARG_OP) */ |
756 | 757 | ||
757 | obj_desc->reference.value = opcode - AML_ARG_OP; | 758 | obj_desc->reference.value = ((u32)opcode) - AML_ARG_OP; |
758 | obj_desc->reference.class = ACPI_REFCLASS_ARG; | 759 | obj_desc->reference.class = ACPI_REFCLASS_ARG; |
759 | 760 | ||
760 | #ifndef ACPI_NO_METHOD_EXECUTION | 761 | #ifndef ACPI_NO_METHOD_EXECUTION |
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index b4c87b5053e6..584d766e6f12 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c | |||
@@ -1386,14 +1386,19 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, | |||
1386 | 1386 | ||
1387 | case AML_BREAK_POINT_OP: | 1387 | case AML_BREAK_POINT_OP: |
1388 | 1388 | ||
1389 | /* Call up to the OS service layer to handle this */ | 1389 | /* |
1390 | 1390 | * Set the single-step flag. This will cause the debugger (if present) | |
1391 | status = | 1391 | * to break to the console within the AML debugger at the start of the |
1392 | acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, | 1392 | * next AML instruction. |
1393 | "Executed AML Breakpoint opcode"); | 1393 | */ |
1394 | ACPI_DEBUGGER_EXEC(acpi_gbl_cm_single_step = TRUE); | ||
1395 | ACPI_DEBUGGER_EXEC(acpi_os_printf | ||
1396 | ("**break** Executed AML BreakPoint opcode\n")); | ||
1394 | 1397 | ||
1395 | /* If and when it returns, all done. */ | 1398 | /* Call to the OSL in case OS wants a piece of the action */ |
1396 | 1399 | ||
1400 | status = acpi_os_signal(ACPI_SIGNAL_BREAKPOINT, | ||
1401 | "Executed AML Breakpoint opcode"); | ||
1397 | break; | 1402 | break; |
1398 | 1403 | ||
1399 | case AML_BREAK_OP: | 1404 | case AML_BREAK_OP: |
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c index 40f92bf7dce5..e46c821cf572 100644 --- a/drivers/acpi/acpica/dswstate.c +++ b/drivers/acpi/acpica/dswstate.c | |||
@@ -102,7 +102,7 @@ acpi_ds_result_pop(union acpi_operand_object **object, | |||
102 | /* Return object of the top element and clean that top element result stack */ | 102 | /* Return object of the top element and clean that top element result stack */ |
103 | 103 | ||
104 | walk_state->result_count--; | 104 | walk_state->result_count--; |
105 | index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; | 105 | index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; |
106 | 106 | ||
107 | *object = state->results.obj_desc[index]; | 107 | *object = state->results.obj_desc[index]; |
108 | if (!*object) { | 108 | if (!*object) { |
@@ -186,7 +186,7 @@ acpi_ds_result_push(union acpi_operand_object * object, | |||
186 | 186 | ||
187 | /* Assign the address of object to the top free element of result stack */ | 187 | /* Assign the address of object to the top free element of result stack */ |
188 | 188 | ||
189 | index = walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; | 189 | index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; |
190 | state->results.obj_desc[index] = object; | 190 | state->results.obj_desc[index] = object; |
191 | walk_state->result_count++; | 191 | walk_state->result_count++; |
192 | 192 | ||
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 538d63264555..98c7f9c62653 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c | |||
@@ -275,7 +275,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) | |||
275 | * | 275 | * |
276 | * PARAMETERS: region_obj - Internal region object | 276 | * PARAMETERS: region_obj - Internal region object |
277 | * Function - Read or Write operation | 277 | * Function - Read or Write operation |
278 | * Address - Where in the space to read or write | 278 | * region_offset - Where in the region to read or write |
279 | * bit_width - Field width in bits (8, 16, 32, or 64) | 279 | * bit_width - Field width in bits (8, 16, 32, or 64) |
280 | * Value - Pointer to in or out value, must be | 280 | * Value - Pointer to in or out value, must be |
281 | * full 64-bit acpi_integer | 281 | * full 64-bit acpi_integer |
@@ -290,7 +290,7 @@ acpi_ev_execute_reg_method(union acpi_operand_object *region_obj, u32 function) | |||
290 | acpi_status | 290 | acpi_status |
291 | acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, | 291 | acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, |
292 | u32 function, | 292 | u32 function, |
293 | acpi_physical_address address, | 293 | u32 region_offset, |
294 | u32 bit_width, acpi_integer * value) | 294 | u32 bit_width, acpi_integer * value) |
295 | { | 295 | { |
296 | acpi_status status; | 296 | acpi_status status; |
@@ -396,7 +396,8 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, | |||
396 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, | 396 | ACPI_DEBUG_PRINT((ACPI_DB_OPREGION, |
397 | "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", | 397 | "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", |
398 | ®ion_obj->region.handler->address_space, handler, | 398 | ®ion_obj->region.handler->address_space, handler, |
399 | ACPI_FORMAT_NATIVE_UINT(address), | 399 | ACPI_FORMAT_NATIVE_UINT(region_obj->region.address + |
400 | region_offset), | ||
400 | acpi_ut_get_region_name(region_obj->region. | 401 | acpi_ut_get_region_name(region_obj->region. |
401 | space_id))); | 402 | space_id))); |
402 | 403 | ||
@@ -412,8 +413,9 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj, | |||
412 | 413 | ||
413 | /* Call the handler */ | 414 | /* Call the handler */ |
414 | 415 | ||
415 | status = handler(function, address, bit_width, value, | 416 | status = handler(function, |
416 | handler_desc->address_space.context, | 417 | (region_obj->region.address + region_offset), |
418 | bit_width, value, handler_desc->address_space.context, | ||
417 | region_obj2->extra.region_context); | 419 | region_obj2->extra.region_context); |
418 | 420 | ||
419 | if (ACPI_FAILURE(status)) { | 421 | if (ACPI_FAILURE(status)) { |
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index d0a080747ec3..4721f58fe42c 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c | |||
@@ -51,7 +51,7 @@ | |||
51 | ACPI_MODULE_NAME("evxfevnt") | 51 | ACPI_MODULE_NAME("evxfevnt") |
52 | 52 | ||
53 | /* Local prototypes */ | 53 | /* Local prototypes */ |
54 | acpi_status | 54 | static acpi_status |
55 | acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | 55 | acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
56 | struct acpi_gpe_block_info *gpe_block, void *context); | 56 | struct acpi_gpe_block_info *gpe_block, void *context); |
57 | 57 | ||
@@ -785,7 +785,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_gpe_device) | |||
785 | * block device. NULL if the GPE is one of the FADT-defined GPEs. | 785 | * block device. NULL if the GPE is one of the FADT-defined GPEs. |
786 | * | 786 | * |
787 | ******************************************************************************/ | 787 | ******************************************************************************/ |
788 | acpi_status | 788 | static acpi_status |
789 | acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, | 789 | acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info, |
790 | struct acpi_gpe_block_info *gpe_block, void *context) | 790 | struct acpi_gpe_block_info *gpe_block, void *context) |
791 | { | 791 | { |
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 3deb20a126b2..277fd609611a 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #include "acnamesp.h" | 47 | #include "acnamesp.h" |
48 | #include "actables.h" | 48 | #include "actables.h" |
49 | #include "acdispat.h" | 49 | #include "acdispat.h" |
50 | #include "acevents.h" | ||
50 | 51 | ||
51 | #define _COMPONENT ACPI_EXECUTER | 52 | #define _COMPONENT ACPI_EXECUTER |
52 | ACPI_MODULE_NAME("exconfig") | 53 | ACPI_MODULE_NAME("exconfig") |
@@ -57,6 +58,10 @@ acpi_ex_add_table(u32 table_index, | |||
57 | struct acpi_namespace_node *parent_node, | 58 | struct acpi_namespace_node *parent_node, |
58 | union acpi_operand_object **ddb_handle); | 59 | union acpi_operand_object **ddb_handle); |
59 | 60 | ||
61 | static acpi_status | ||
62 | acpi_ex_region_read(union acpi_operand_object *obj_desc, | ||
63 | u32 length, u8 *buffer); | ||
64 | |||
60 | /******************************************************************************* | 65 | /******************************************************************************* |
61 | * | 66 | * |
62 | * FUNCTION: acpi_ex_add_table | 67 | * FUNCTION: acpi_ex_add_table |
@@ -91,6 +96,7 @@ acpi_ex_add_table(u32 table_index, | |||
91 | 96 | ||
92 | /* Init the table handle */ | 97 | /* Init the table handle */ |
93 | 98 | ||
99 | obj_desc->common.flags |= AOPOBJ_DATA_VALID; | ||
94 | obj_desc->reference.class = ACPI_REFCLASS_TABLE; | 100 | obj_desc->reference.class = ACPI_REFCLASS_TABLE; |
95 | *ddb_handle = obj_desc; | 101 | *ddb_handle = obj_desc; |
96 | 102 | ||
@@ -229,6 +235,8 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, | |||
229 | walk_state); | 235 | walk_state); |
230 | if (ACPI_FAILURE(status)) { | 236 | if (ACPI_FAILURE(status)) { |
231 | (void)acpi_ex_unload_table(ddb_handle); | 237 | (void)acpi_ex_unload_table(ddb_handle); |
238 | |||
239 | acpi_ut_remove_reference(ddb_handle); | ||
232 | return_ACPI_STATUS(status); | 240 | return_ACPI_STATUS(status); |
233 | } | 241 | } |
234 | } | 242 | } |
@@ -254,6 +262,47 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, | |||
254 | 262 | ||
255 | /******************************************************************************* | 263 | /******************************************************************************* |
256 | * | 264 | * |
265 | * FUNCTION: acpi_ex_region_read | ||
266 | * | ||
267 | * PARAMETERS: obj_desc - Region descriptor | ||
268 | * Length - Number of bytes to read | ||
269 | * Buffer - Pointer to where to put the data | ||
270 | * | ||
271 | * RETURN: Status | ||
272 | * | ||
273 | * DESCRIPTION: Read data from an operation region. The read starts from the | ||
274 | * beginning of the region. | ||
275 | * | ||
276 | ******************************************************************************/ | ||
277 | |||
278 | static acpi_status | ||
279 | acpi_ex_region_read(union acpi_operand_object *obj_desc, u32 length, u8 *buffer) | ||
280 | { | ||
281 | acpi_status status; | ||
282 | acpi_integer value; | ||
283 | u32 region_offset = 0; | ||
284 | u32 i; | ||
285 | |||
286 | /* Bytewise reads */ | ||
287 | |||
288 | for (i = 0; i < length; i++) { | ||
289 | status = acpi_ev_address_space_dispatch(obj_desc, ACPI_READ, | ||
290 | region_offset, 8, | ||
291 | &value); | ||
292 | if (ACPI_FAILURE(status)) { | ||
293 | return status; | ||
294 | } | ||
295 | |||
296 | *buffer = (u8)value; | ||
297 | buffer++; | ||
298 | region_offset++; | ||
299 | } | ||
300 | |||
301 | return AE_OK; | ||
302 | } | ||
303 | |||
304 | /******************************************************************************* | ||
305 | * | ||
257 | * FUNCTION: acpi_ex_load_op | 306 | * FUNCTION: acpi_ex_load_op |
258 | * | 307 | * |
259 | * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be | 308 | * PARAMETERS: obj_desc - Region or Buffer/Field where the table will be |
@@ -314,18 +363,23 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
314 | } | 363 | } |
315 | } | 364 | } |
316 | 365 | ||
317 | /* | 366 | /* Get the table header first so we can get the table length */ |
318 | * Map the table header and get the actual table length. The region | 367 | |
319 | * length is not guaranteed to be the same as the table length. | 368 | table = ACPI_ALLOCATE(sizeof(struct acpi_table_header)); |
320 | */ | ||
321 | table = acpi_os_map_memory(obj_desc->region.address, | ||
322 | sizeof(struct acpi_table_header)); | ||
323 | if (!table) { | 369 | if (!table) { |
324 | return_ACPI_STATUS(AE_NO_MEMORY); | 370 | return_ACPI_STATUS(AE_NO_MEMORY); |
325 | } | 371 | } |
326 | 372 | ||
373 | status = | ||
374 | acpi_ex_region_read(obj_desc, | ||
375 | sizeof(struct acpi_table_header), | ||
376 | ACPI_CAST_PTR(u8, table)); | ||
327 | length = table->length; | 377 | length = table->length; |
328 | acpi_os_unmap_memory(table, sizeof(struct acpi_table_header)); | 378 | ACPI_FREE(table); |
379 | |||
380 | if (ACPI_FAILURE(status)) { | ||
381 | return_ACPI_STATUS(status); | ||
382 | } | ||
329 | 383 | ||
330 | /* Must have at least an ACPI table header */ | 384 | /* Must have at least an ACPI table header */ |
331 | 385 | ||
@@ -334,10 +388,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
334 | } | 388 | } |
335 | 389 | ||
336 | /* | 390 | /* |
337 | * The memory region is not guaranteed to remain stable and we must | 391 | * The original implementation simply mapped the table, with no copy. |
338 | * copy the table to a local buffer. For example, the memory region | 392 | * However, the memory region is not guaranteed to remain stable and |
339 | * is corrupted after suspend on some machines. Dynamically loaded | 393 | * we must copy the table to a local buffer. For example, the memory |
340 | * tables are usually small, so this overhead is minimal. | 394 | * region is corrupted after suspend on some machines. Dynamically |
395 | * loaded tables are usually small, so this overhead is minimal. | ||
396 | * | ||
397 | * The latest implementation (5/2009) does not use a mapping at all. | ||
398 | * We use the low-level operation region interface to read the table | ||
399 | * instead of the obvious optimization of using a direct mapping. | ||
400 | * This maintains a consistent use of operation regions across the | ||
401 | * entire subsystem. This is important if additional processing must | ||
402 | * be performed in the (possibly user-installed) operation region | ||
403 | * handler. For example, acpi_exec and ASLTS depend on this. | ||
341 | */ | 404 | */ |
342 | 405 | ||
343 | /* Allocate a buffer for the table */ | 406 | /* Allocate a buffer for the table */ |
@@ -347,17 +410,16 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
347 | return_ACPI_STATUS(AE_NO_MEMORY); | 410 | return_ACPI_STATUS(AE_NO_MEMORY); |
348 | } | 411 | } |
349 | 412 | ||
350 | /* Map the entire table and copy it */ | 413 | /* Read the entire table */ |
351 | 414 | ||
352 | table = acpi_os_map_memory(obj_desc->region.address, length); | 415 | status = acpi_ex_region_read(obj_desc, length, |
353 | if (!table) { | 416 | ACPI_CAST_PTR(u8, |
417 | table_desc.pointer)); | ||
418 | if (ACPI_FAILURE(status)) { | ||
354 | ACPI_FREE(table_desc.pointer); | 419 | ACPI_FREE(table_desc.pointer); |
355 | return_ACPI_STATUS(AE_NO_MEMORY); | 420 | return_ACPI_STATUS(status); |
356 | } | 421 | } |
357 | 422 | ||
358 | ACPI_MEMCPY(table_desc.pointer, table, length); | ||
359 | acpi_os_unmap_memory(table, length); | ||
360 | |||
361 | table_desc.address = obj_desc->region.address; | 423 | table_desc.address = obj_desc->region.address; |
362 | break; | 424 | break; |
363 | 425 | ||
@@ -454,6 +516,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc, | |||
454 | return_ACPI_STATUS(status); | 516 | return_ACPI_STATUS(status); |
455 | } | 517 | } |
456 | 518 | ||
519 | /* Remove the reference by added by acpi_ex_store above */ | ||
520 | |||
521 | acpi_ut_remove_reference(ddb_handle); | ||
522 | |||
457 | /* Invoke table handler if present */ | 523 | /* Invoke table handler if present */ |
458 | 524 | ||
459 | if (acpi_gbl_table_handler) { | 525 | if (acpi_gbl_table_handler) { |
@@ -495,13 +561,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
495 | 561 | ||
496 | /* | 562 | /* |
497 | * Validate the handle | 563 | * Validate the handle |
498 | * Although the handle is partially validated in acpi_ex_reconfiguration(), | 564 | * Although the handle is partially validated in acpi_ex_reconfiguration() |
499 | * when it calls acpi_ex_resolve_operands(), the handle is more completely | 565 | * when it calls acpi_ex_resolve_operands(), the handle is more completely |
500 | * validated here. | 566 | * validated here. |
567 | * | ||
568 | * Handle must be a valid operand object of type reference. Also, the | ||
569 | * ddb_handle must still be marked valid (table has not been previously | ||
570 | * unloaded) | ||
501 | */ | 571 | */ |
502 | if ((!ddb_handle) || | 572 | if ((!ddb_handle) || |
503 | (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || | 573 | (ACPI_GET_DESCRIPTOR_TYPE(ddb_handle) != ACPI_DESC_TYPE_OPERAND) || |
504 | (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE)) { | 574 | (ddb_handle->common.type != ACPI_TYPE_LOCAL_REFERENCE) || |
575 | (!(ddb_handle->common.flags & AOPOBJ_DATA_VALID))) { | ||
505 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 576 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
506 | } | 577 | } |
507 | 578 | ||
@@ -509,6 +580,12 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
509 | 580 | ||
510 | table_index = table_desc->reference.value; | 581 | table_index = table_desc->reference.value; |
511 | 582 | ||
583 | /* Ensure the table is still loaded */ | ||
584 | |||
585 | if (!acpi_tb_is_table_loaded(table_index)) { | ||
586 | return_ACPI_STATUS(AE_NOT_EXIST); | ||
587 | } | ||
588 | |||
512 | /* Invoke table handler if present */ | 589 | /* Invoke table handler if present */ |
513 | 590 | ||
514 | if (acpi_gbl_table_handler) { | 591 | if (acpi_gbl_table_handler) { |
@@ -530,8 +607,10 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle) | |||
530 | (void)acpi_tb_release_owner_id(table_index); | 607 | (void)acpi_tb_release_owner_id(table_index); |
531 | acpi_tb_set_table_loaded_flag(table_index, FALSE); | 608 | acpi_tb_set_table_loaded_flag(table_index, FALSE); |
532 | 609 | ||
533 | /* Table unloaded, remove a reference to the ddb_handle object */ | 610 | /* |
534 | 611 | * Invalidate the handle. We do this because the handle may be stored | |
535 | acpi_ut_remove_reference(ddb_handle); | 612 | * in a named object and may not be actually deleted until much later. |
613 | */ | ||
614 | ddb_handle->common.flags &= ~AOPOBJ_DATA_VALID; | ||
536 | return_ACPI_STATUS(AE_OK); | 615 | return_ACPI_STATUS(AE_OK); |
537 | } | 616 | } |
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index a57ad2564ab0..02b25d233d99 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c | |||
@@ -502,7 +502,7 @@ acpi_ex_create_method(u8 * aml_start, | |||
502 | * ACPI 2.0: sync_level = sync_level in method declaration | 502 | * ACPI 2.0: sync_level = sync_level in method declaration |
503 | */ | 503 | */ |
504 | obj_desc->method.sync_level = (u8) | 504 | obj_desc->method.sync_level = (u8) |
505 | ((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4); | 505 | ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); |
506 | } | 506 | } |
507 | 507 | ||
508 | /* Attach the new object to the method Node */ | 508 | /* Attach the new object to the method Node */ |
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 89d141fdae0b..ec524614e708 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c | |||
@@ -120,9 +120,11 @@ static struct acpi_exdump_info acpi_ex_dump_event[2] = { | |||
120 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} | 120 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(event.os_semaphore), "OsSemaphore"} |
121 | }; | 121 | }; |
122 | 122 | ||
123 | static struct acpi_exdump_info acpi_ex_dump_method[8] = { | 123 | static struct acpi_exdump_info acpi_ex_dump_method[9] = { |
124 | {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, | 124 | {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_method), NULL}, |
125 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), "ParamCount"}, | 125 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.method_flags), "Method Flags"}, |
126 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.param_count), | ||
127 | "Parameter Count"}, | ||
126 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, | 128 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.sync_level), "Sync Level"}, |
127 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, | 129 | {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.mutex), "Mutex"}, |
128 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, | 130 | {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(method.owner_id), "Owner Id"}, |
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c index 99cee61e655d..d4075b821021 100644 --- a/drivers/acpi/acpica/exfldio.c +++ b/drivers/acpi/acpica/exfldio.c | |||
@@ -222,7 +222,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, | |||
222 | { | 222 | { |
223 | acpi_status status; | 223 | acpi_status status; |
224 | union acpi_operand_object *rgn_desc; | 224 | union acpi_operand_object *rgn_desc; |
225 | acpi_physical_address address; | 225 | u32 region_offset; |
226 | 226 | ||
227 | ACPI_FUNCTION_TRACE(ex_access_region); | 227 | ACPI_FUNCTION_TRACE(ex_access_region); |
228 | 228 | ||
@@ -243,7 +243,7 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, | |||
243 | * 3) The current offset into the field | 243 | * 3) The current offset into the field |
244 | */ | 244 | */ |
245 | rgn_desc = obj_desc->common_field.region_obj; | 245 | rgn_desc = obj_desc->common_field.region_obj; |
246 | address = rgn_desc->region.address + | 246 | region_offset = |
247 | obj_desc->common_field.base_byte_offset + field_datum_byte_offset; | 247 | obj_desc->common_field.base_byte_offset + field_datum_byte_offset; |
248 | 248 | ||
249 | if ((function & ACPI_IO_MASK) == ACPI_READ) { | 249 | if ((function & ACPI_IO_MASK) == ACPI_READ) { |
@@ -260,16 +260,18 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc, | |||
260 | obj_desc->common_field.access_byte_width, | 260 | obj_desc->common_field.access_byte_width, |
261 | obj_desc->common_field.base_byte_offset, | 261 | obj_desc->common_field.base_byte_offset, |
262 | field_datum_byte_offset, ACPI_CAST_PTR(void, | 262 | field_datum_byte_offset, ACPI_CAST_PTR(void, |
263 | address))); | 263 | (rgn_desc-> |
264 | region. | ||
265 | address + | ||
266 | region_offset)))); | ||
264 | 267 | ||
265 | /* Invoke the appropriate address_space/op_region handler */ | 268 | /* Invoke the appropriate address_space/op_region handler */ |
266 | 269 | ||
267 | status = acpi_ev_address_space_dispatch(rgn_desc, function, | 270 | status = |
268 | address, | 271 | acpi_ev_address_space_dispatch(rgn_desc, function, region_offset, |
269 | ACPI_MUL_8(obj_desc-> | 272 | ACPI_MUL_8(obj_desc->common_field. |
270 | common_field. | 273 | access_byte_width), |
271 | access_byte_width), | 274 | value); |
272 | value); | ||
273 | 275 | ||
274 | if (ACPI_FAILURE(status)) { | 276 | if (ACPI_FAILURE(status)) { |
275 | if (status == AE_NOT_IMPLEMENTED) { | 277 | if (status == AE_NOT_IMPLEMENTED) { |
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index d301c1f363ef..2f0114202b05 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c | |||
@@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc) | |||
83 | 83 | ||
84 | if (obj_desc->mutex.prev) { | 84 | if (obj_desc->mutex.prev) { |
85 | (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; | 85 | (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; |
86 | |||
87 | /* | ||
88 | * Migrate the previous sync level associated with this mutex to the | ||
89 | * previous mutex on the list so that it may be preserved. This handles | ||
90 | * the case where several mutexes have been acquired at the same level, | ||
91 | * but are not released in opposite order. | ||
92 | */ | ||
93 | (obj_desc->mutex.prev)->mutex.original_sync_level = | ||
94 | obj_desc->mutex.original_sync_level; | ||
86 | } else { | 95 | } else { |
87 | thread->acquired_mutex_list = obj_desc->mutex.next; | 96 | thread->acquired_mutex_list = obj_desc->mutex.next; |
88 | } | 97 | } |
@@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
349 | struct acpi_walk_state *walk_state) | 358 | struct acpi_walk_state *walk_state) |
350 | { | 359 | { |
351 | acpi_status status = AE_OK; | 360 | acpi_status status = AE_OK; |
361 | u8 previous_sync_level; | ||
352 | 362 | ||
353 | ACPI_FUNCTION_TRACE(ex_release_mutex); | 363 | ACPI_FUNCTION_TRACE(ex_release_mutex); |
354 | 364 | ||
@@ -373,11 +383,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
373 | walk_state->thread->thread_id) | 383 | walk_state->thread->thread_id) |
374 | && (obj_desc != acpi_gbl_global_lock_mutex)) { | 384 | && (obj_desc != acpi_gbl_global_lock_mutex)) { |
375 | ACPI_ERROR((AE_INFO, | 385 | ACPI_ERROR((AE_INFO, |
376 | "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", | 386 | "Thread %p cannot release Mutex [%4.4s] acquired by thread %p", |
377 | (unsigned long)walk_state->thread->thread_id, | 387 | ACPI_CAST_PTR(void, walk_state->thread->thread_id), |
378 | acpi_ut_get_node_name(obj_desc->mutex.node), | 388 | acpi_ut_get_node_name(obj_desc->mutex.node), |
379 | (unsigned long)obj_desc->mutex.owner_thread-> | 389 | ACPI_CAST_PTR(void, |
380 | thread_id)); | 390 | obj_desc->mutex.owner_thread-> |
391 | thread_id))); | ||
381 | return_ACPI_STATUS(AE_AML_NOT_OWNER); | 392 | return_ACPI_STATUS(AE_AML_NOT_OWNER); |
382 | } | 393 | } |
383 | 394 | ||
@@ -391,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
391 | } | 402 | } |
392 | 403 | ||
393 | /* | 404 | /* |
394 | * The sync level of the mutex must be less than or equal to the current | 405 | * The sync level of the mutex must be equal to the current sync level. In |
395 | * sync level | 406 | * other words, the current level means that at least one mutex at that |
407 | * level is currently being held. Attempting to release a mutex of a | ||
408 | * different level can only mean that the mutex ordering rule is being | ||
409 | * violated. This behavior is clarified in ACPI 4.0 specification. | ||
396 | */ | 410 | */ |
397 | if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { | 411 | if (obj_desc->mutex.sync_level != |
412 | walk_state->thread->current_sync_level) { | ||
398 | ACPI_ERROR((AE_INFO, | 413 | ACPI_ERROR((AE_INFO, |
399 | "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", | 414 | "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", |
400 | acpi_ut_get_node_name(obj_desc->mutex.node), | 415 | acpi_ut_get_node_name(obj_desc->mutex.node), |
@@ -403,14 +418,24 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
403 | return_ACPI_STATUS(AE_AML_MUTEX_ORDER); | 418 | return_ACPI_STATUS(AE_AML_MUTEX_ORDER); |
404 | } | 419 | } |
405 | 420 | ||
421 | /* | ||
422 | * Get the previous sync_level from the head of the acquired mutex list. | ||
423 | * This handles the case where several mutexes at the same level have been | ||
424 | * acquired, but are not released in reverse order. | ||
425 | */ | ||
426 | previous_sync_level = | ||
427 | walk_state->thread->acquired_mutex_list->mutex.original_sync_level; | ||
428 | |||
406 | status = acpi_ex_release_mutex_object(obj_desc); | 429 | status = acpi_ex_release_mutex_object(obj_desc); |
430 | if (ACPI_FAILURE(status)) { | ||
431 | return_ACPI_STATUS(status); | ||
432 | } | ||
407 | 433 | ||
408 | if (obj_desc->mutex.acquisition_depth == 0) { | 434 | if (obj_desc->mutex.acquisition_depth == 0) { |
409 | 435 | ||
410 | /* Restore the original sync_level */ | 436 | /* Restore the previous sync_level */ |
411 | 437 | ||
412 | walk_state->thread->current_sync_level = | 438 | walk_state->thread->current_sync_level = previous_sync_level; |
413 | obj_desc->mutex.original_sync_level; | ||
414 | } | 439 | } |
415 | return_ACPI_STATUS(status); | 440 | return_ACPI_STATUS(status); |
416 | } | 441 | } |
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c index 90d606196c99..6efd07a4f779 100644 --- a/drivers/acpi/acpica/exstore.c +++ b/drivers/acpi/acpica/exstore.c | |||
@@ -193,10 +193,12 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, | |||
193 | 193 | ||
194 | case ACPI_REFCLASS_TABLE: | 194 | case ACPI_REFCLASS_TABLE: |
195 | 195 | ||
196 | /* Case for ddb_handle */ | ||
197 | |||
196 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, | 198 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_DEBUG_OBJECT, |
197 | "Table Index 0x%X\n", | 199 | "Table Index 0x%X\n", |
198 | source_desc->reference.value)); | 200 | source_desc->reference.value)); |
199 | break; | 201 | return; |
200 | 202 | ||
201 | default: | 203 | default: |
202 | break; | 204 | break; |
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c index 7b2fb602b5cb..23d5505cb1f7 100644 --- a/drivers/acpi/acpica/hwregs.c +++ b/drivers/acpi/acpica/hwregs.c | |||
@@ -81,9 +81,9 @@ acpi_status acpi_hw_clear_acpi_status(void) | |||
81 | 81 | ||
82 | ACPI_FUNCTION_TRACE(hw_clear_acpi_status); | 82 | ACPI_FUNCTION_TRACE(hw_clear_acpi_status); |
83 | 83 | ||
84 | ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %0llX\n", | 84 | ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %8.8X%8.8X\n", |
85 | ACPI_BITMASK_ALL_FIXED_STATUS, | 85 | ACPI_BITMASK_ALL_FIXED_STATUS, |
86 | acpi_gbl_xpm1a_status.address)); | 86 | ACPI_FORMAT_UINT64(acpi_gbl_xpm1a_status.address))); |
87 | 87 | ||
88 | lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); | 88 | lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock); |
89 | 89 | ||
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c index aceb93111967..efc971ab7d65 100644 --- a/drivers/acpi/acpica/nsalloc.c +++ b/drivers/acpi/acpica/nsalloc.c | |||
@@ -334,9 +334,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) | |||
334 | 334 | ||
335 | /* Get the next node in this scope (NULL if none) */ | 335 | /* Get the next node in this scope (NULL if none) */ |
336 | 336 | ||
337 | child_node = | 337 | child_node = acpi_ns_get_next_node(parent_node, child_node); |
338 | acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, | ||
339 | child_node); | ||
340 | if (child_node) { | 338 | if (child_node) { |
341 | 339 | ||
342 | /* Found a child node - detach any attached object */ | 340 | /* Found a child node - detach any attached object */ |
@@ -345,8 +343,7 @@ void acpi_ns_delete_namespace_subtree(struct acpi_namespace_node *parent_node) | |||
345 | 343 | ||
346 | /* Check if this node has any children */ | 344 | /* Check if this node has any children */ |
347 | 345 | ||
348 | if (acpi_ns_get_next_node | 346 | if (child_node->child) { |
349 | (ACPI_TYPE_ANY, child_node, NULL)) { | ||
350 | /* | 347 | /* |
351 | * There is at least one child of this node, | 348 | * There is at least one child of this node, |
352 | * visit the node | 349 | * visit the node |
@@ -432,9 +429,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) | |||
432 | * Get the next child of this parent node. When child_node is NULL, | 429 | * Get the next child of this parent node. When child_node is NULL, |
433 | * the first child of the parent is returned | 430 | * the first child of the parent is returned |
434 | */ | 431 | */ |
435 | child_node = | 432 | child_node = acpi_ns_get_next_node(parent_node, child_node); |
436 | acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, | ||
437 | child_node); | ||
438 | 433 | ||
439 | if (deletion_node) { | 434 | if (deletion_node) { |
440 | acpi_ns_delete_children(deletion_node); | 435 | acpi_ns_delete_children(deletion_node); |
@@ -452,8 +447,7 @@ void acpi_ns_delete_namespace_by_owner(acpi_owner_id owner_id) | |||
452 | 447 | ||
453 | /* Check if this node has any children */ | 448 | /* Check if this node has any children */ |
454 | 449 | ||
455 | if (acpi_ns_get_next_node | 450 | if (child_node->child) { |
456 | (ACPI_TYPE_ANY, child_node, NULL)) { | ||
457 | /* | 451 | /* |
458 | * There is at least one child of this node, | 452 | * There is at least one child of this node, |
459 | * visit the node | 453 | * visit the node |
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index ae3dc10a7e81..af8e6bcee07e 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c | |||
@@ -149,7 +149,7 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) | |||
149 | 149 | ||
150 | name_buffer = ACPI_ALLOCATE_ZEROED(size); | 150 | name_buffer = ACPI_ALLOCATE_ZEROED(size); |
151 | if (!name_buffer) { | 151 | if (!name_buffer) { |
152 | ACPI_ERROR((AE_INFO, "Allocation failure")); | 152 | ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); |
153 | return_PTR(NULL); | 153 | return_PTR(NULL); |
154 | } | 154 | } |
155 | 155 | ||
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c index 3eb20bfda9d8..60f3af08d28c 100644 --- a/drivers/acpi/acpica/nsobject.c +++ b/drivers/acpi/acpica/nsobject.c | |||
@@ -213,6 +213,15 @@ void acpi_ns_detach_object(struct acpi_namespace_node *node) | |||
213 | return_VOID; | 213 | return_VOID; |
214 | } | 214 | } |
215 | 215 | ||
216 | if (node->flags & ANOBJ_ALLOCATED_BUFFER) { | ||
217 | |||
218 | /* Free the dynamic aml buffer */ | ||
219 | |||
220 | if (obj_desc->common.type == ACPI_TYPE_METHOD) { | ||
221 | ACPI_FREE(obj_desc->method.aml_start); | ||
222 | } | ||
223 | } | ||
224 | |||
216 | /* Clear the entry in all cases */ | 225 | /* Clear the entry in all cases */ |
217 | 226 | ||
218 | node->object = NULL; | 227 | node->object = NULL; |
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index d9e8cbc6e679..7f8e066b12a3 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c | |||
@@ -144,7 +144,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, | |||
144 | 144 | ||
145 | pathname = acpi_ns_get_external_pathname(node); | 145 | pathname = acpi_ns_get_external_pathname(node); |
146 | if (!pathname) { | 146 | if (!pathname) { |
147 | pathname = ACPI_CAST_PTR(char, predefined->info.name); | 147 | return AE_OK; /* Could not get pathname, ignore */ |
148 | } | 148 | } |
149 | 149 | ||
150 | /* | 150 | /* |
@@ -230,10 +230,7 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, | |||
230 | } | 230 | } |
231 | 231 | ||
232 | exit: | 232 | exit: |
233 | if (pathname != predefined->info.name) { | 233 | ACPI_FREE(pathname); |
234 | ACPI_FREE(pathname); | ||
235 | } | ||
236 | |||
237 | return (status); | 234 | return (status); |
238 | } | 235 | } |
239 | 236 | ||
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c index f9b4f51bf8f2..7e865639a928 100644 --- a/drivers/acpi/acpica/nssearch.c +++ b/drivers/acpi/acpica/nssearch.c | |||
@@ -45,6 +45,10 @@ | |||
45 | #include "accommon.h" | 45 | #include "accommon.h" |
46 | #include "acnamesp.h" | 46 | #include "acnamesp.h" |
47 | 47 | ||
48 | #ifdef ACPI_ASL_COMPILER | ||
49 | #include "amlcode.h" | ||
50 | #endif | ||
51 | |||
48 | #define _COMPONENT ACPI_NAMESPACE | 52 | #define _COMPONENT ACPI_NAMESPACE |
49 | ACPI_MODULE_NAME("nssearch") | 53 | ACPI_MODULE_NAME("nssearch") |
50 | 54 | ||
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c index 83e3aa6d4b9b..35539df5c75d 100644 --- a/drivers/acpi/acpica/nswalk.c +++ b/drivers/acpi/acpica/nswalk.c | |||
@@ -52,8 +52,7 @@ ACPI_MODULE_NAME("nswalk") | |||
52 | * | 52 | * |
53 | * FUNCTION: acpi_ns_get_next_node | 53 | * FUNCTION: acpi_ns_get_next_node |
54 | * | 54 | * |
55 | * PARAMETERS: Type - Type of node to be searched for | 55 | * PARAMETERS: parent_node - Parent node whose children we are |
56 | * parent_node - Parent node whose children we are | ||
57 | * getting | 56 | * getting |
58 | * child_node - Previous child that was found. | 57 | * child_node - Previous child that was found. |
59 | * The NEXT child will be returned | 58 | * The NEXT child will be returned |
@@ -66,27 +65,68 @@ ACPI_MODULE_NAME("nswalk") | |||
66 | * within Scope is returned. | 65 | * within Scope is returned. |
67 | * | 66 | * |
68 | ******************************************************************************/ | 67 | ******************************************************************************/ |
69 | struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type, struct acpi_namespace_node | 68 | struct acpi_namespace_node *acpi_ns_get_next_node(struct acpi_namespace_node |
70 | *parent_node, struct acpi_namespace_node | 69 | *parent_node, |
70 | struct acpi_namespace_node | ||
71 | *child_node) | 71 | *child_node) |
72 | { | 72 | { |
73 | struct acpi_namespace_node *next_node = NULL; | ||
74 | |||
75 | ACPI_FUNCTION_ENTRY(); | 73 | ACPI_FUNCTION_ENTRY(); |
76 | 74 | ||
77 | if (!child_node) { | 75 | if (!child_node) { |
78 | 76 | ||
79 | /* It's really the parent's _scope_ that we want */ | 77 | /* It's really the parent's _scope_ that we want */ |
80 | 78 | ||
81 | next_node = parent_node->child; | 79 | return parent_node->child; |
82 | } | 80 | } |
83 | 81 | ||
84 | else { | 82 | /* |
85 | /* Start search at the NEXT node */ | 83 | * Get the next node. |
86 | 84 | * | |
87 | next_node = acpi_ns_get_next_valid_node(child_node); | 85 | * If we are at the end of this peer list, return NULL |
86 | */ | ||
87 | if (child_node->flags & ANOBJ_END_OF_PEER_LIST) { | ||
88 | return NULL; | ||
88 | } | 89 | } |
89 | 90 | ||
91 | /* Otherwise just return the next peer */ | ||
92 | |||
93 | return child_node->peer; | ||
94 | } | ||
95 | |||
96 | /******************************************************************************* | ||
97 | * | ||
98 | * FUNCTION: acpi_ns_get_next_node_typed | ||
99 | * | ||
100 | * PARAMETERS: Type - Type of node to be searched for | ||
101 | * parent_node - Parent node whose children we are | ||
102 | * getting | ||
103 | * child_node - Previous child that was found. | ||
104 | * The NEXT child will be returned | ||
105 | * | ||
106 | * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if | ||
107 | * none is found. | ||
108 | * | ||
109 | * DESCRIPTION: Return the next peer node within the namespace. If Handle | ||
110 | * is valid, Scope is ignored. Otherwise, the first node | ||
111 | * within Scope is returned. | ||
112 | * | ||
113 | ******************************************************************************/ | ||
114 | |||
115 | struct acpi_namespace_node *acpi_ns_get_next_node_typed(acpi_object_type type, | ||
116 | struct | ||
117 | acpi_namespace_node | ||
118 | *parent_node, | ||
119 | struct | ||
120 | acpi_namespace_node | ||
121 | *child_node) | ||
122 | { | ||
123 | struct acpi_namespace_node *next_node = NULL; | ||
124 | |||
125 | ACPI_FUNCTION_ENTRY(); | ||
126 | |||
127 | next_node = acpi_ns_get_next_node(parent_node, child_node); | ||
128 | |||
129 | |||
90 | /* If any type is OK, we are done */ | 130 | /* If any type is OK, we are done */ |
91 | 131 | ||
92 | if (type == ACPI_TYPE_ANY) { | 132 | if (type == ACPI_TYPE_ANY) { |
@@ -186,9 +226,7 @@ acpi_ns_walk_namespace(acpi_object_type type, | |||
186 | /* Get the next node in this scope. Null if not found */ | 226 | /* Get the next node in this scope. Null if not found */ |
187 | 227 | ||
188 | status = AE_OK; | 228 | status = AE_OK; |
189 | child_node = | 229 | child_node = acpi_ns_get_next_node(parent_node, child_node); |
190 | acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node, | ||
191 | child_node); | ||
192 | if (child_node) { | 230 | if (child_node) { |
193 | 231 | ||
194 | /* Found next child, get the type if we are not searching for ANY */ | 232 | /* Found next child, get the type if we are not searching for ANY */ |
@@ -269,8 +307,7 @@ acpi_ns_walk_namespace(acpi_object_type type, | |||
269 | * function has specified that the maximum depth has been reached. | 307 | * function has specified that the maximum depth has been reached. |
270 | */ | 308 | */ |
271 | if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { | 309 | if ((level < max_depth) && (status != AE_CTRL_DEPTH)) { |
272 | if (acpi_ns_get_next_node | 310 | if (child_node->child) { |
273 | (ACPI_TYPE_ANY, child_node, NULL)) { | ||
274 | 311 | ||
275 | /* There is at least one child of this node, visit it */ | 312 | /* There is at least one child of this node, visit it */ |
276 | 313 | ||
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9589fea24997..f23593d6add4 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c | |||
@@ -45,6 +45,8 @@ | |||
45 | #include <acpi/acpi.h> | 45 | #include <acpi/acpi.h> |
46 | #include "accommon.h" | 46 | #include "accommon.h" |
47 | #include "acnamesp.h" | 47 | #include "acnamesp.h" |
48 | #include "acparser.h" | ||
49 | #include "amlcode.h" | ||
48 | 50 | ||
49 | #define _COMPONENT ACPI_NAMESPACE | 51 | #define _COMPONENT ACPI_NAMESPACE |
50 | ACPI_MODULE_NAME("nsxfname") | 52 | ACPI_MODULE_NAME("nsxfname") |
@@ -358,3 +360,151 @@ acpi_get_object_info(acpi_handle handle, struct acpi_buffer * buffer) | |||
358 | } | 360 | } |
359 | 361 | ||
360 | ACPI_EXPORT_SYMBOL(acpi_get_object_info) | 362 | ACPI_EXPORT_SYMBOL(acpi_get_object_info) |
363 | |||
364 | /****************************************************************************** | ||
365 | * | ||
366 | * FUNCTION: acpi_install_method | ||
367 | * | ||
368 | * PARAMETERS: Buffer - An ACPI table containing one control method | ||
369 | * | ||
370 | * RETURN: Status | ||
371 | * | ||
372 | * DESCRIPTION: Install a control method into the namespace. If the method | ||
373 | * name already exists in the namespace, it is overwritten. The | ||
374 | * input buffer must contain a valid DSDT or SSDT containing a | ||
375 | * single control method. | ||
376 | * | ||
377 | ******************************************************************************/ | ||
378 | acpi_status acpi_install_method(u8 *buffer) | ||
379 | { | ||
380 | struct acpi_table_header *table = | ||
381 | ACPI_CAST_PTR(struct acpi_table_header, buffer); | ||
382 | u8 *aml_buffer; | ||
383 | u8 *aml_start; | ||
384 | char *path; | ||
385 | struct acpi_namespace_node *node; | ||
386 | union acpi_operand_object *method_obj; | ||
387 | struct acpi_parse_state parser_state; | ||
388 | u32 aml_length; | ||
389 | u16 opcode; | ||
390 | u8 method_flags; | ||
391 | acpi_status status; | ||
392 | |||
393 | /* Parameter validation */ | ||
394 | |||
395 | if (!buffer) { | ||
396 | return AE_BAD_PARAMETER; | ||
397 | } | ||
398 | |||
399 | /* Table must be a DSDT or SSDT */ | ||
400 | |||
401 | if (!ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) && | ||
402 | !ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) { | ||
403 | return AE_BAD_HEADER; | ||
404 | } | ||
405 | |||
406 | /* First AML opcode in the table must be a control method */ | ||
407 | |||
408 | parser_state.aml = buffer + sizeof(struct acpi_table_header); | ||
409 | opcode = acpi_ps_peek_opcode(&parser_state); | ||
410 | if (opcode != AML_METHOD_OP) { | ||
411 | return AE_BAD_PARAMETER; | ||
412 | } | ||
413 | |||
414 | /* Extract method information from the raw AML */ | ||
415 | |||
416 | parser_state.aml += acpi_ps_get_opcode_size(opcode); | ||
417 | parser_state.pkg_end = acpi_ps_get_next_package_end(&parser_state); | ||
418 | path = acpi_ps_get_next_namestring(&parser_state); | ||
419 | method_flags = *parser_state.aml++; | ||
420 | aml_start = parser_state.aml; | ||
421 | aml_length = ACPI_PTR_DIFF(parser_state.pkg_end, aml_start); | ||
422 | |||
423 | /* | ||
424 | * Allocate resources up-front. We don't want to have to delete a new | ||
425 | * node from the namespace if we cannot allocate memory. | ||
426 | */ | ||
427 | aml_buffer = ACPI_ALLOCATE(aml_length); | ||
428 | if (!aml_buffer) { | ||
429 | return AE_NO_MEMORY; | ||
430 | } | ||
431 | |||
432 | method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); | ||
433 | if (!method_obj) { | ||
434 | ACPI_FREE(aml_buffer); | ||
435 | return AE_NO_MEMORY; | ||
436 | } | ||
437 | |||
438 | /* Lock namespace for acpi_ns_lookup, we may be creating a new node */ | ||
439 | |||
440 | status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); | ||
441 | if (ACPI_FAILURE(status)) { | ||
442 | goto error_exit; | ||
443 | } | ||
444 | |||
445 | /* The lookup either returns an existing node or creates a new one */ | ||
446 | |||
447 | status = | ||
448 | acpi_ns_lookup(NULL, path, ACPI_TYPE_METHOD, ACPI_IMODE_LOAD_PASS1, | ||
449 | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND, | ||
450 | NULL, &node); | ||
451 | |||
452 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | ||
453 | |||
454 | if (ACPI_FAILURE(status)) { /* ns_lookup */ | ||
455 | if (status != AE_ALREADY_EXISTS) { | ||
456 | goto error_exit; | ||
457 | } | ||
458 | |||
459 | /* Node existed previously, make sure it is a method node */ | ||
460 | |||
461 | if (node->type != ACPI_TYPE_METHOD) { | ||
462 | status = AE_TYPE; | ||
463 | goto error_exit; | ||
464 | } | ||
465 | } | ||
466 | |||
467 | /* Copy the method AML to the local buffer */ | ||
468 | |||
469 | ACPI_MEMCPY(aml_buffer, aml_start, aml_length); | ||
470 | |||
471 | /* Initialize the method object with the new method's information */ | ||
472 | |||
473 | method_obj->method.aml_start = aml_buffer; | ||
474 | method_obj->method.aml_length = aml_length; | ||
475 | |||
476 | method_obj->method.param_count = (u8) | ||
477 | (method_flags & AML_METHOD_ARG_COUNT); | ||
478 | |||
479 | method_obj->method.method_flags = (u8) | ||
480 | (method_flags & ~AML_METHOD_ARG_COUNT); | ||
481 | |||
482 | if (method_flags & AML_METHOD_SERIALIZED) { | ||
483 | method_obj->method.sync_level = (u8) | ||
484 | ((method_flags & AML_METHOD_SYNC_LEVEL) >> 4); | ||
485 | } | ||
486 | |||
487 | /* | ||
488 | * Now that it is complete, we can attach the new method object to | ||
489 | * the method Node (detaches/deletes any existing object) | ||
490 | */ | ||
491 | status = acpi_ns_attach_object(node, method_obj, ACPI_TYPE_METHOD); | ||
492 | |||
493 | /* | ||
494 | * Flag indicates AML buffer is dynamic, must be deleted later. | ||
495 | * Must be set only after attach above. | ||
496 | */ | ||
497 | node->flags |= ANOBJ_ALLOCATED_BUFFER; | ||
498 | |||
499 | /* Remove local reference to the method object */ | ||
500 | |||
501 | acpi_ut_remove_reference(method_obj); | ||
502 | return status; | ||
503 | |||
504 | error_exit: | ||
505 | |||
506 | ACPI_FREE(aml_buffer); | ||
507 | ACPI_FREE(method_obj); | ||
508 | return status; | ||
509 | } | ||
510 | ACPI_EXPORT_SYMBOL(acpi_install_method) | ||
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 1c7efc15225f..4071bad4458e 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c | |||
@@ -162,6 +162,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_type) | |||
162 | acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) | 162 | acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) |
163 | { | 163 | { |
164 | struct acpi_namespace_node *node; | 164 | struct acpi_namespace_node *node; |
165 | struct acpi_namespace_node *parent_node; | ||
165 | acpi_status status; | 166 | acpi_status status; |
166 | 167 | ||
167 | if (!ret_handle) { | 168 | if (!ret_handle) { |
@@ -189,12 +190,12 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) | |||
189 | 190 | ||
190 | /* Get the parent entry */ | 191 | /* Get the parent entry */ |
191 | 192 | ||
192 | *ret_handle = | 193 | parent_node = acpi_ns_get_parent_node(node); |
193 | acpi_ns_convert_entry_to_handle(acpi_ns_get_parent_node(node)); | 194 | *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); |
194 | 195 | ||
195 | /* Return exception if parent is null */ | 196 | /* Return exception if parent is null */ |
196 | 197 | ||
197 | if (!acpi_ns_get_parent_node(node)) { | 198 | if (!parent_node) { |
198 | status = AE_NULL_ENTRY; | 199 | status = AE_NULL_ENTRY; |
199 | } | 200 | } |
200 | 201 | ||
@@ -268,7 +269,7 @@ acpi_get_next_object(acpi_object_type type, | |||
268 | 269 | ||
269 | /* Internal function does the real work */ | 270 | /* Internal function does the real work */ |
270 | 271 | ||
271 | node = acpi_ns_get_next_node(type, parent_node, child_node); | 272 | node = acpi_ns_get_next_node_typed(type, parent_node, child_node); |
272 | if (!node) { | 273 | if (!node) { |
273 | status = AE_NOT_FOUND; | 274 | status = AE_NOT_FOUND; |
274 | goto unlock_and_exit; | 275 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c index 88b5a2c4814d..3c4dcc3d1069 100644 --- a/drivers/acpi/acpica/rscalc.c +++ b/drivers/acpi/acpica/rscalc.c | |||
@@ -547,7 +547,7 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, | |||
547 | 547 | ||
548 | if (!package_element || | 548 | if (!package_element || |
549 | (package_element->common.type != ACPI_TYPE_PACKAGE)) { | 549 | (package_element->common.type != ACPI_TYPE_PACKAGE)) { |
550 | return_ACPI_STATUS (AE_AML_OPERAND_TYPE); | 550 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
551 | } | 551 | } |
552 | 552 | ||
553 | /* | 553 | /* |
@@ -593,9 +593,6 @@ acpi_rs_get_pci_routing_table_length(union acpi_operand_object *package_object, | |||
593 | } else { | 593 | } else { |
594 | temp_size_needed += | 594 | temp_size_needed += |
595 | acpi_ns_get_pathname_length((*sub_object_list)->reference.node); | 595 | acpi_ns_get_pathname_length((*sub_object_list)->reference.node); |
596 | if (!temp_size_needed) { | ||
597 | return_ACPI_STATUS(AE_BAD_PARAMETER); | ||
598 | } | ||
599 | } | 596 | } |
600 | } else { | 597 | } else { |
601 | /* | 598 | /* |
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 69a2aa5b5d83..395212bcd19b 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c | |||
@@ -338,13 +338,17 @@ acpi_resource_to_address64(struct acpi_resource *resource, | |||
338 | switch (resource->type) { | 338 | switch (resource->type) { |
339 | case ACPI_RESOURCE_TYPE_ADDRESS16: | 339 | case ACPI_RESOURCE_TYPE_ADDRESS16: |
340 | 340 | ||
341 | address16 = (struct acpi_resource_address16 *)&resource->data; | 341 | address16 = |
342 | ACPI_CAST_PTR(struct acpi_resource_address16, | ||
343 | &resource->data); | ||
342 | ACPI_COPY_ADDRESS(out, address16); | 344 | ACPI_COPY_ADDRESS(out, address16); |
343 | break; | 345 | break; |
344 | 346 | ||
345 | case ACPI_RESOURCE_TYPE_ADDRESS32: | 347 | case ACPI_RESOURCE_TYPE_ADDRESS32: |
346 | 348 | ||
347 | address32 = (struct acpi_resource_address32 *)&resource->data; | 349 | address32 = |
350 | ACPI_CAST_PTR(struct acpi_resource_address32, | ||
351 | &resource->data); | ||
348 | ACPI_COPY_ADDRESS(out, address32); | 352 | ACPI_COPY_ADDRESS(out, address32); |
349 | break; | 353 | break; |
350 | 354 | ||
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 71e655d14cb0..82b02dcb942e 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c | |||
@@ -284,9 +284,9 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length) | |||
284 | if (length > sizeof(struct acpi_table_fadt)) { | 284 | if (length > sizeof(struct acpi_table_fadt)) { |
285 | ACPI_WARNING((AE_INFO, | 285 | ACPI_WARNING((AE_INFO, |
286 | "FADT (revision %u) is longer than ACPI 2.0 version, " | 286 | "FADT (revision %u) is longer than ACPI 2.0 version, " |
287 | "truncating length 0x%X to 0x%zX", | 287 | "truncating length 0x%X to 0x%X", |
288 | table->revision, (unsigned)length, | 288 | table->revision, length, |
289 | sizeof(struct acpi_table_fadt))); | 289 | (u32)sizeof(struct acpi_table_fadt))); |
290 | } | 290 | } |
291 | 291 | ||
292 | /* Clear the entire local FADT */ | 292 | /* Clear the entire local FADT */ |
@@ -441,7 +441,7 @@ static void acpi_tb_convert_fadt(void) | |||
441 | &acpi_gbl_FADT, | 441 | &acpi_gbl_FADT, |
442 | fadt_info_table | 442 | fadt_info_table |
443 | [i].length), | 443 | [i].length), |
444 | address32); | 444 | (u64) address32); |
445 | } | 445 | } |
446 | } | 446 | } |
447 | } | 447 | } |
@@ -469,7 +469,6 @@ static void acpi_tb_convert_fadt(void) | |||
469 | static void acpi_tb_validate_fadt(void) | 469 | static void acpi_tb_validate_fadt(void) |
470 | { | 470 | { |
471 | char *name; | 471 | char *name; |
472 | u32 *address32; | ||
473 | struct acpi_generic_address *address64; | 472 | struct acpi_generic_address *address64; |
474 | u8 length; | 473 | u8 length; |
475 | u32 i; | 474 | u32 i; |
@@ -505,15 +504,12 @@ static void acpi_tb_validate_fadt(void) | |||
505 | 504 | ||
506 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { | 505 | for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) { |
507 | /* | 506 | /* |
508 | * Generate pointers to the 32-bit and 64-bit addresses, get the | 507 | * Generate pointer to the 64-bit address, get the register |
509 | * register length (width), and the register name | 508 | * length (width) and the register name |
510 | */ | 509 | */ |
511 | address64 = ACPI_ADD_PTR(struct acpi_generic_address, | 510 | address64 = ACPI_ADD_PTR(struct acpi_generic_address, |
512 | &acpi_gbl_FADT, | 511 | &acpi_gbl_FADT, |
513 | fadt_info_table[i].address64); | 512 | fadt_info_table[i].address64); |
514 | address32 = | ||
515 | ACPI_ADD_PTR(u32, &acpi_gbl_FADT, | ||
516 | fadt_info_table[i].address32); | ||
517 | length = | 513 | length = |
518 | *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, | 514 | *ACPI_ADD_PTR(u8, &acpi_gbl_FADT, |
519 | fadt_info_table[i].length); | 515 | fadt_info_table[i].length); |
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index f865d5a096de..63e82329a9e8 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c | |||
@@ -472,7 +472,7 @@ acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index) | |||
472 | * lock may block, and also since the execution of a namespace walk | 472 | * lock may block, and also since the execution of a namespace walk |
473 | * must be allowed to use the interpreter. | 473 | * must be allowed to use the interpreter. |
474 | */ | 474 | */ |
475 | acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); | 475 | (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER); |
476 | status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); | 476 | status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock); |
477 | 477 | ||
478 | acpi_ns_delete_namespace_by_owner(owner_id); | 478 | acpi_ns_delete_namespace_by_owner(owner_id); |
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 919624f123d5..0f0c64bf8ac9 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c | |||
@@ -676,6 +676,7 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, | |||
676 | { | 676 | { |
677 | u16 reference_count; | 677 | u16 reference_count; |
678 | union acpi_operand_object *next_object; | 678 | union acpi_operand_object *next_object; |
679 | acpi_status status; | ||
679 | 680 | ||
680 | /* Save fields from destination that we don't want to overwrite */ | 681 | /* Save fields from destination that we don't want to overwrite */ |
681 | 682 | ||
@@ -768,6 +769,28 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc, | |||
768 | } | 769 | } |
769 | break; | 770 | break; |
770 | 771 | ||
772 | /* | ||
773 | * For Mutex and Event objects, we cannot simply copy the underlying | ||
774 | * OS object. We must create a new one. | ||
775 | */ | ||
776 | case ACPI_TYPE_MUTEX: | ||
777 | |||
778 | status = acpi_os_create_mutex(&dest_desc->mutex.os_mutex); | ||
779 | if (ACPI_FAILURE(status)) { | ||
780 | return status; | ||
781 | } | ||
782 | break; | ||
783 | |||
784 | case ACPI_TYPE_EVENT: | ||
785 | |||
786 | status = acpi_os_create_semaphore(ACPI_NO_UNIT_LIMIT, 0, | ||
787 | &dest_desc->event. | ||
788 | os_semaphore); | ||
789 | if (ACPI_FAILURE(status)) { | ||
790 | return status; | ||
791 | } | ||
792 | break; | ||
793 | |||
771 | default: | 794 | default: |
772 | /* Nothing to do for other simple objects */ | 795 | /* Nothing to do for other simple objects */ |
773 | break; | 796 | break; |
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index 38821f53042c..527d729f6815 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c | |||
@@ -179,9 +179,9 @@ acpi_debug_print(u32 requested_debug_level, | |||
179 | if (thread_id != acpi_gbl_prev_thread_id) { | 179 | if (thread_id != acpi_gbl_prev_thread_id) { |
180 | if (ACPI_LV_THREADS & acpi_dbg_level) { | 180 | if (ACPI_LV_THREADS & acpi_dbg_level) { |
181 | acpi_os_printf | 181 | acpi_os_printf |
182 | ("\n**** Context Switch from TID %lX to TID %lX ****\n\n", | 182 | ("\n**** Context Switch from TID %p to TID %p ****\n\n", |
183 | (unsigned long)acpi_gbl_prev_thread_id, | 183 | ACPI_CAST_PTR(void, acpi_gbl_prev_thread_id), |
184 | (unsigned long)thread_id); | 184 | ACPI_CAST_PTR(void, thread_id)); |
185 | } | 185 | } |
186 | 186 | ||
187 | acpi_gbl_prev_thread_id = thread_id; | 187 | acpi_gbl_prev_thread_id = thread_id; |
@@ -194,7 +194,7 @@ acpi_debug_print(u32 requested_debug_level, | |||
194 | acpi_os_printf("%8s-%04ld ", module_name, line_number); | 194 | acpi_os_printf("%8s-%04ld ", module_name, line_number); |
195 | 195 | ||
196 | if (ACPI_LV_THREADS & acpi_dbg_level) { | 196 | if (ACPI_LV_THREADS & acpi_dbg_level) { |
197 | acpi_os_printf("[%04lX] ", (unsigned long)thread_id); | 197 | acpi_os_printf("[%p] ", ACPI_CAST_PTR(void, thread_id)); |
198 | } | 198 | } |
199 | 199 | ||
200 | acpi_os_printf("[%02ld] %-22.22s: ", | 200 | acpi_os_printf("[%02ld] %-22.22s: ", |
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index a5ee23bc4f55..bc1710315088 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c | |||
@@ -75,6 +75,7 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) | |||
75 | union acpi_operand_object *handler_desc; | 75 | union acpi_operand_object *handler_desc; |
76 | union acpi_operand_object *second_desc; | 76 | union acpi_operand_object *second_desc; |
77 | union acpi_operand_object *next_desc; | 77 | union acpi_operand_object *next_desc; |
78 | union acpi_operand_object **last_obj_ptr; | ||
78 | 79 | ||
79 | ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); | 80 | ACPI_FUNCTION_TRACE_PTR(ut_delete_internal_obj, object); |
80 | 81 | ||
@@ -223,6 +224,26 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) | |||
223 | */ | 224 | */ |
224 | handler_desc = object->region.handler; | 225 | handler_desc = object->region.handler; |
225 | if (handler_desc) { | 226 | if (handler_desc) { |
227 | next_desc = | ||
228 | handler_desc->address_space.region_list; | ||
229 | last_obj_ptr = | ||
230 | &handler_desc->address_space.region_list; | ||
231 | |||
232 | /* Remove the region object from the handler's list */ | ||
233 | |||
234 | while (next_desc) { | ||
235 | if (next_desc == object) { | ||
236 | *last_obj_ptr = | ||
237 | next_desc->region.next; | ||
238 | break; | ||
239 | } | ||
240 | |||
241 | /* Walk the linked list of handler */ | ||
242 | |||
243 | last_obj_ptr = &next_desc->region.next; | ||
244 | next_desc = next_desc->region.next; | ||
245 | } | ||
246 | |||
226 | if (handler_desc->address_space.handler_flags & | 247 | if (handler_desc->address_space.handler_flags & |
227 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { | 248 | ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) { |
228 | 249 | ||
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 1c9e250caefb..fbe782348b0b 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c | |||
@@ -1033,11 +1033,12 @@ acpi_error(const char *module_name, u32 line_number, const char *format, ...) | |||
1033 | { | 1033 | { |
1034 | va_list args; | 1034 | va_list args; |
1035 | 1035 | ||
1036 | acpi_os_printf("ACPI Error (%s-%04d): ", module_name, line_number); | 1036 | acpi_os_printf("ACPI Error: "); |
1037 | 1037 | ||
1038 | va_start(args, format); | 1038 | va_start(args, format); |
1039 | acpi_os_vprintf(format, args); | 1039 | acpi_os_vprintf(format, args); |
1040 | acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); | 1040 | acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, |
1041 | line_number); | ||
1041 | va_end(args); | 1042 | va_end(args); |
1042 | } | 1043 | } |
1043 | 1044 | ||
@@ -1047,12 +1048,12 @@ acpi_exception(const char *module_name, | |||
1047 | { | 1048 | { |
1048 | va_list args; | 1049 | va_list args; |
1049 | 1050 | ||
1050 | acpi_os_printf("ACPI Exception (%s-%04d): %s, ", module_name, | 1051 | acpi_os_printf("ACPI Exception: %s, ", acpi_format_exception(status)); |
1051 | line_number, acpi_format_exception(status)); | ||
1052 | 1052 | ||
1053 | va_start(args, format); | 1053 | va_start(args, format); |
1054 | acpi_os_vprintf(format, args); | 1054 | acpi_os_vprintf(format, args); |
1055 | acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); | 1055 | acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, |
1056 | line_number); | ||
1056 | va_end(args); | 1057 | va_end(args); |
1057 | } | 1058 | } |
1058 | 1059 | ||
@@ -1061,11 +1062,12 @@ acpi_warning(const char *module_name, u32 line_number, const char *format, ...) | |||
1061 | { | 1062 | { |
1062 | va_list args; | 1063 | va_list args; |
1063 | 1064 | ||
1064 | acpi_os_printf("ACPI Warning (%s-%04d): ", module_name, line_number); | 1065 | acpi_os_printf("ACPI Warning: "); |
1065 | 1066 | ||
1066 | va_start(args, format); | 1067 | va_start(args, format); |
1067 | acpi_os_vprintf(format, args); | 1068 | acpi_os_vprintf(format, args); |
1068 | acpi_os_printf(" [%X]\n", ACPI_CA_VERSION); | 1069 | acpi_os_printf(" %8.8X %s-%u\n", ACPI_CA_VERSION, module_name, |
1070 | line_number); | ||
1069 | va_end(args); | 1071 | va_end(args); |
1070 | } | 1072 | } |
1071 | 1073 | ||
@@ -1074,10 +1076,6 @@ acpi_info(const char *module_name, u32 line_number, const char *format, ...) | |||
1074 | { | 1076 | { |
1075 | va_list args; | 1077 | va_list args; |
1076 | 1078 | ||
1077 | /* | ||
1078 | * Removed module_name, line_number, and acpica version, not needed | ||
1079 | * for info output | ||
1080 | */ | ||
1081 | acpi_os_printf("ACPI: "); | 1079 | acpi_os_printf("ACPI: "); |
1082 | 1080 | ||
1083 | va_start(args, format); | 1081 | va_start(args, format); |
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c index 26c93a748e64..80bb65154117 100644 --- a/drivers/acpi/acpica/utmutex.c +++ b/drivers/acpi/acpica/utmutex.c | |||
@@ -230,17 +230,18 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) | |||
230 | if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { | 230 | if (acpi_gbl_mutex_info[i].thread_id == this_thread_id) { |
231 | if (i == mutex_id) { | 231 | if (i == mutex_id) { |
232 | ACPI_ERROR((AE_INFO, | 232 | ACPI_ERROR((AE_INFO, |
233 | "Mutex [%s] already acquired by this thread [%X]", | 233 | "Mutex [%s] already acquired by this thread [%p]", |
234 | acpi_ut_get_mutex_name | 234 | acpi_ut_get_mutex_name |
235 | (mutex_id), | 235 | (mutex_id), |
236 | this_thread_id)); | 236 | ACPI_CAST_PTR(void, |
237 | this_thread_id))); | ||
237 | 238 | ||
238 | return (AE_ALREADY_ACQUIRED); | 239 | return (AE_ALREADY_ACQUIRED); |
239 | } | 240 | } |
240 | 241 | ||
241 | ACPI_ERROR((AE_INFO, | 242 | ACPI_ERROR((AE_INFO, |
242 | "Invalid acquire order: Thread %X owns [%s], wants [%s]", | 243 | "Invalid acquire order: Thread %p owns [%s], wants [%s]", |
243 | this_thread_id, | 244 | ACPI_CAST_PTR(void, this_thread_id), |
244 | acpi_ut_get_mutex_name(i), | 245 | acpi_ut_get_mutex_name(i), |
245 | acpi_ut_get_mutex_name(mutex_id))); | 246 | acpi_ut_get_mutex_name(mutex_id))); |
246 | 247 | ||
@@ -251,24 +252,24 @@ acpi_status acpi_ut_acquire_mutex(acpi_mutex_handle mutex_id) | |||
251 | #endif | 252 | #endif |
252 | 253 | ||
253 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | 254 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, |
254 | "Thread %lX attempting to acquire Mutex [%s]\n", | 255 | "Thread %p attempting to acquire Mutex [%s]\n", |
255 | (unsigned long)this_thread_id, | 256 | ACPI_CAST_PTR(void, this_thread_id), |
256 | acpi_ut_get_mutex_name(mutex_id))); | 257 | acpi_ut_get_mutex_name(mutex_id))); |
257 | 258 | ||
258 | status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, | 259 | status = acpi_os_acquire_mutex(acpi_gbl_mutex_info[mutex_id].mutex, |
259 | ACPI_WAIT_FOREVER); | 260 | ACPI_WAIT_FOREVER); |
260 | if (ACPI_SUCCESS(status)) { | 261 | if (ACPI_SUCCESS(status)) { |
261 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | 262 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, |
262 | "Thread %lX acquired Mutex [%s]\n", | 263 | "Thread %p acquired Mutex [%s]\n", |
263 | (unsigned long)this_thread_id, | 264 | ACPI_CAST_PTR(void, this_thread_id), |
264 | acpi_ut_get_mutex_name(mutex_id))); | 265 | acpi_ut_get_mutex_name(mutex_id))); |
265 | 266 | ||
266 | acpi_gbl_mutex_info[mutex_id].use_count++; | 267 | acpi_gbl_mutex_info[mutex_id].use_count++; |
267 | acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; | 268 | acpi_gbl_mutex_info[mutex_id].thread_id = this_thread_id; |
268 | } else { | 269 | } else { |
269 | ACPI_EXCEPTION((AE_INFO, status, | 270 | ACPI_EXCEPTION((AE_INFO, status, |
270 | "Thread %lX could not acquire Mutex [%X]", | 271 | "Thread %p could not acquire Mutex [%X]", |
271 | (unsigned long)this_thread_id, mutex_id)); | 272 | ACPI_CAST_PTR(void, this_thread_id), mutex_id)); |
272 | } | 273 | } |
273 | 274 | ||
274 | return (status); | 275 | return (status); |
@@ -293,9 +294,8 @@ acpi_status acpi_ut_release_mutex(acpi_mutex_handle mutex_id) | |||
293 | ACPI_FUNCTION_NAME(ut_release_mutex); | 294 | ACPI_FUNCTION_NAME(ut_release_mutex); |
294 | 295 | ||
295 | this_thread_id = acpi_os_get_thread_id(); | 296 | this_thread_id = acpi_os_get_thread_id(); |
296 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | 297 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Thread %p releasing Mutex [%s]\n", |
297 | "Thread %lX releasing Mutex [%s]\n", | 298 | ACPI_CAST_PTR(void, this_thread_id), |
298 | (unsigned long)this_thread_id, | ||
299 | acpi_ut_get_mutex_name(mutex_id))); | 299 | acpi_ut_get_mutex_name(mutex_id))); |
300 | 300 | ||
301 | if (mutex_id > ACPI_MAX_MUTEX) { | 301 | if (mutex_id > ACPI_MAX_MUTEX) { |
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index b22cec97ea19..c7a527c08a09 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -38,7 +38,6 @@ | |||
38 | #include <linux/hdreg.h> | 38 | #include <linux/hdreg.h> |
39 | #include <linux/spinlock.h> | 39 | #include <linux/spinlock.h> |
40 | #include <linux/compat.h> | 40 | #include <linux/compat.h> |
41 | #include <linux/blktrace_api.h> | ||
42 | #include <asm/uaccess.h> | 41 | #include <asm/uaccess.h> |
43 | #include <asm/io.h> | 42 | #include <asm/io.h> |
44 | 43 | ||
diff --git a/drivers/block/mg_disk.c b/drivers/block/mg_disk.c index 60de5a01e71e..f703f5478246 100644 --- a/drivers/block/mg_disk.c +++ b/drivers/block/mg_disk.c | |||
@@ -22,13 +22,12 @@ | |||
22 | #include <linux/delay.h> | 22 | #include <linux/delay.h> |
23 | #include <linux/platform_device.h> | 23 | #include <linux/platform_device.h> |
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | #include <linux/mg_disk.h> | ||
25 | 26 | ||
26 | #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1) | 27 | #define MG_RES_SEC (CONFIG_MG_DISK_RES << 1) |
27 | 28 | ||
28 | /* name for block device */ | 29 | /* name for block device */ |
29 | #define MG_DISK_NAME "mgd" | 30 | #define MG_DISK_NAME "mgd" |
30 | /* name for platform device */ | ||
31 | #define MG_DEV_NAME "mg_disk" | ||
32 | 31 | ||
33 | #define MG_DISK_MAJ 0 | 32 | #define MG_DISK_MAJ 0 |
34 | #define MG_DISK_MAX_PART 16 | 33 | #define MG_DISK_MAX_PART 16 |
@@ -103,33 +102,8 @@ | |||
103 | #define MG_TMAX_SWRST_TO_RDY 500 | 102 | #define MG_TMAX_SWRST_TO_RDY 500 |
104 | #define MG_TMAX_RSTOUT 3000 | 103 | #define MG_TMAX_RSTOUT 3000 |
105 | 104 | ||
106 | /* device attribution */ | ||
107 | /* use mflash as boot device */ | ||
108 | #define MG_BOOT_DEV (1 << 0) | ||
109 | /* use mflash as storage device */ | ||
110 | #define MG_STORAGE_DEV (1 << 1) | ||
111 | /* same as MG_STORAGE_DEV, but bootloader already done reset sequence */ | ||
112 | #define MG_STORAGE_DEV_SKIP_RST (1 << 2) | ||
113 | |||
114 | #define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) | 105 | #define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST) |
115 | 106 | ||
116 | /* names of GPIO resource */ | ||
117 | #define MG_RST_PIN "mg_rst" | ||
118 | /* except MG_BOOT_DEV, reset-out pin should be assigned */ | ||
119 | #define MG_RSTOUT_PIN "mg_rstout" | ||
120 | |||
121 | /* private driver data */ | ||
122 | struct mg_drv_data { | ||
123 | /* disk resource */ | ||
124 | u32 use_polling; | ||
125 | |||
126 | /* device attribution */ | ||
127 | u32 dev_attr; | ||
128 | |||
129 | /* internally used */ | ||
130 | struct mg_host *host; | ||
131 | }; | ||
132 | |||
133 | /* main structure for mflash driver */ | 107 | /* main structure for mflash driver */ |
134 | struct mg_host { | 108 | struct mg_host { |
135 | struct device *dev; | 109 | struct device *dev; |
diff --git a/drivers/block/ps3disk.c b/drivers/block/ps3disk.c index aaeeb544228a..34cbb7f3efa8 100644 --- a/drivers/block/ps3disk.c +++ b/drivers/block/ps3disk.c | |||
@@ -120,7 +120,7 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev, | |||
120 | static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, | 120 | static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, |
121 | struct request *req) | 121 | struct request *req) |
122 | { | 122 | { |
123 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | 123 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
124 | int write = rq_data_dir(req), res; | 124 | int write = rq_data_dir(req), res; |
125 | const char *op = write ? "write" : "read"; | 125 | const char *op = write ? "write" : "read"; |
126 | u64 start_sector, sectors; | 126 | u64 start_sector, sectors; |
@@ -168,7 +168,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev, | |||
168 | static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, | 168 | static int ps3disk_submit_flush_request(struct ps3_storage_device *dev, |
169 | struct request *req) | 169 | struct request *req) |
170 | { | 170 | { |
171 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | 171 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
172 | u64 res; | 172 | u64 res; |
173 | 173 | ||
174 | dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); | 174 | dev_dbg(&dev->sbd.core, "%s:%u: flush request\n", __func__, __LINE__); |
@@ -213,7 +213,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev, | |||
213 | static void ps3disk_request(struct request_queue *q) | 213 | static void ps3disk_request(struct request_queue *q) |
214 | { | 214 | { |
215 | struct ps3_storage_device *dev = q->queuedata; | 215 | struct ps3_storage_device *dev = q->queuedata; |
216 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | 216 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
217 | 217 | ||
218 | if (priv->req) { | 218 | if (priv->req) { |
219 | dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); | 219 | dev_dbg(&dev->sbd.core, "%s:%u busy\n", __func__, __LINE__); |
@@ -245,7 +245,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data) | |||
245 | return IRQ_HANDLED; | 245 | return IRQ_HANDLED; |
246 | } | 246 | } |
247 | 247 | ||
248 | priv = dev->sbd.core.driver_data; | 248 | priv = ps3_system_bus_get_drvdata(&dev->sbd); |
249 | req = priv->req; | 249 | req = priv->req; |
250 | if (!req) { | 250 | if (!req) { |
251 | dev_dbg(&dev->sbd.core, | 251 | dev_dbg(&dev->sbd.core, |
@@ -364,7 +364,7 @@ static void ata_id_c_string(const u16 *id, unsigned char *s, unsigned int ofs, | |||
364 | 364 | ||
365 | static int ps3disk_identify(struct ps3_storage_device *dev) | 365 | static int ps3disk_identify(struct ps3_storage_device *dev) |
366 | { | 366 | { |
367 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | 367 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
368 | struct lv1_ata_cmnd_block ata_cmnd; | 368 | struct lv1_ata_cmnd_block ata_cmnd; |
369 | u16 *id = dev->bounce_buf; | 369 | u16 *id = dev->bounce_buf; |
370 | u64 res; | 370 | u64 res; |
@@ -445,7 +445,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev) | |||
445 | goto fail; | 445 | goto fail; |
446 | } | 446 | } |
447 | 447 | ||
448 | dev->sbd.core.driver_data = priv; | 448 | ps3_system_bus_set_drvdata(_dev, priv); |
449 | spin_lock_init(&priv->lock); | 449 | spin_lock_init(&priv->lock); |
450 | 450 | ||
451 | dev->bounce_size = BOUNCE_SIZE; | 451 | dev->bounce_size = BOUNCE_SIZE; |
@@ -523,7 +523,7 @@ fail_free_bounce: | |||
523 | kfree(dev->bounce_buf); | 523 | kfree(dev->bounce_buf); |
524 | fail_free_priv: | 524 | fail_free_priv: |
525 | kfree(priv); | 525 | kfree(priv); |
526 | dev->sbd.core.driver_data = NULL; | 526 | ps3_system_bus_set_drvdata(_dev, NULL); |
527 | fail: | 527 | fail: |
528 | mutex_lock(&ps3disk_mask_mutex); | 528 | mutex_lock(&ps3disk_mask_mutex); |
529 | __clear_bit(devidx, &ps3disk_mask); | 529 | __clear_bit(devidx, &ps3disk_mask); |
@@ -534,7 +534,7 @@ fail: | |||
534 | static int ps3disk_remove(struct ps3_system_bus_device *_dev) | 534 | static int ps3disk_remove(struct ps3_system_bus_device *_dev) |
535 | { | 535 | { |
536 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | 536 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); |
537 | struct ps3disk_private *priv = dev->sbd.core.driver_data; | 537 | struct ps3disk_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
538 | 538 | ||
539 | mutex_lock(&ps3disk_mask_mutex); | 539 | mutex_lock(&ps3disk_mask_mutex); |
540 | __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, | 540 | __clear_bit(MINOR(disk_devt(priv->gendisk)) / PS3DISK_MINORS, |
@@ -548,7 +548,7 @@ static int ps3disk_remove(struct ps3_system_bus_device *_dev) | |||
548 | ps3stor_teardown(dev); | 548 | ps3stor_teardown(dev); |
549 | kfree(dev->bounce_buf); | 549 | kfree(dev->bounce_buf); |
550 | kfree(priv); | 550 | kfree(priv); |
551 | dev->sbd.core.driver_data = NULL; | 551 | ps3_system_bus_set_drvdata(_dev, NULL); |
552 | return 0; | 552 | return 0; |
553 | } | 553 | } |
554 | 554 | ||
diff --git a/drivers/block/ps3vram.c b/drivers/block/ps3vram.c index 8eddef373a91..095f97e60665 100644 --- a/drivers/block/ps3vram.c +++ b/drivers/block/ps3vram.c | |||
@@ -14,8 +14,10 @@ | |||
14 | #include <linux/seq_file.h> | 14 | #include <linux/seq_file.h> |
15 | 15 | ||
16 | #include <asm/firmware.h> | 16 | #include <asm/firmware.h> |
17 | #include <asm/iommu.h> | ||
17 | #include <asm/lv1call.h> | 18 | #include <asm/lv1call.h> |
18 | #include <asm/ps3.h> | 19 | #include <asm/ps3.h> |
20 | #include <asm/ps3gpu.h> | ||
19 | 21 | ||
20 | 22 | ||
21 | #define DEVICE_NAME "ps3vram" | 23 | #define DEVICE_NAME "ps3vram" |
@@ -45,8 +47,6 @@ | |||
45 | #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c | 47 | #define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c |
46 | #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 | 48 | #define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104 |
47 | 49 | ||
48 | #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 | ||
49 | |||
50 | #define CACHE_PAGE_PRESENT 1 | 50 | #define CACHE_PAGE_PRESENT 1 |
51 | #define CACHE_PAGE_DIRTY 2 | 51 | #define CACHE_PAGE_DIRTY 2 |
52 | 52 | ||
@@ -72,8 +72,7 @@ struct ps3vram_priv { | |||
72 | u64 memory_handle; | 72 | u64 memory_handle; |
73 | u64 context_handle; | 73 | u64 context_handle; |
74 | u32 *ctrl; | 74 | u32 *ctrl; |
75 | u32 *reports; | 75 | void *reports; |
76 | u8 __iomem *ddr_base; | ||
77 | u8 *xdr_buf; | 76 | u8 *xdr_buf; |
78 | 77 | ||
79 | u32 *fifo_base; | 78 | u32 *fifo_base; |
@@ -81,8 +80,8 @@ struct ps3vram_priv { | |||
81 | 80 | ||
82 | struct ps3vram_cache cache; | 81 | struct ps3vram_cache cache; |
83 | 82 | ||
84 | /* Used to serialize cache/DMA operations */ | 83 | spinlock_t lock; /* protecting list of bios */ |
85 | struct mutex lock; | 84 | struct bio_list list; |
86 | }; | 85 | }; |
87 | 86 | ||
88 | 87 | ||
@@ -103,15 +102,15 @@ static char *size = "256M"; | |||
103 | module_param(size, charp, 0); | 102 | module_param(size, charp, 0); |
104 | MODULE_PARM_DESC(size, "memory size"); | 103 | MODULE_PARM_DESC(size, "memory size"); |
105 | 104 | ||
106 | static u32 *ps3vram_get_notifier(u32 *reports, int notifier) | 105 | static u32 *ps3vram_get_notifier(void *reports, int notifier) |
107 | { | 106 | { |
108 | return (void *)reports + DMA_NOTIFIER_OFFSET_BASE + | 107 | return reports + DMA_NOTIFIER_OFFSET_BASE + |
109 | DMA_NOTIFIER_SIZE * notifier; | 108 | DMA_NOTIFIER_SIZE * notifier; |
110 | } | 109 | } |
111 | 110 | ||
112 | static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) | 111 | static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) |
113 | { | 112 | { |
114 | struct ps3vram_priv *priv = dev->core.driver_data; | 113 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
115 | u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); | 114 | u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); |
116 | int i; | 115 | int i; |
117 | 116 | ||
@@ -122,7 +121,7 @@ static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev) | |||
122 | static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, | 121 | static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, |
123 | unsigned int timeout_ms) | 122 | unsigned int timeout_ms) |
124 | { | 123 | { |
125 | struct ps3vram_priv *priv = dev->core.driver_data; | 124 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
126 | u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); | 125 | u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER); |
127 | unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); | 126 | unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); |
128 | 127 | ||
@@ -137,7 +136,7 @@ static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev, | |||
137 | 136 | ||
138 | static void ps3vram_init_ring(struct ps3_system_bus_device *dev) | 137 | static void ps3vram_init_ring(struct ps3_system_bus_device *dev) |
139 | { | 138 | { |
140 | struct ps3vram_priv *priv = dev->core.driver_data; | 139 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
141 | 140 | ||
142 | priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; | 141 | priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; |
143 | priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; | 142 | priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET; |
@@ -146,7 +145,7 @@ static void ps3vram_init_ring(struct ps3_system_bus_device *dev) | |||
146 | static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, | 145 | static int ps3vram_wait_ring(struct ps3_system_bus_device *dev, |
147 | unsigned int timeout_ms) | 146 | unsigned int timeout_ms) |
148 | { | 147 | { |
149 | struct ps3vram_priv *priv = dev->core.driver_data; | 148 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
150 | unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); | 149 | unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms); |
151 | 150 | ||
152 | do { | 151 | do { |
@@ -175,7 +174,7 @@ static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag, | |||
175 | 174 | ||
176 | static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) | 175 | static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) |
177 | { | 176 | { |
178 | struct ps3vram_priv *priv = dev->core.driver_data; | 177 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
179 | int status; | 178 | int status; |
180 | 179 | ||
181 | ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); | 180 | ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET)); |
@@ -183,20 +182,17 @@ static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev) | |||
183 | priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; | 182 | priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET; |
184 | 183 | ||
185 | /* asking the HV for a blit will kick the FIFO */ | 184 | /* asking the HV for a blit will kick the FIFO */ |
186 | status = lv1_gpu_context_attribute(priv->context_handle, | 185 | status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); |
187 | L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, | ||
188 | 0, 0, 0); | ||
189 | if (status) | 186 | if (status) |
190 | dev_err(&dev->core, | 187 | dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", |
191 | "%s: lv1_gpu_context_attribute failed %d\n", __func__, | 188 | __func__, status); |
192 | status); | ||
193 | 189 | ||
194 | priv->fifo_ptr = priv->fifo_base; | 190 | priv->fifo_ptr = priv->fifo_base; |
195 | } | 191 | } |
196 | 192 | ||
197 | static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) | 193 | static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) |
198 | { | 194 | { |
199 | struct ps3vram_priv *priv = dev->core.driver_data; | 195 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
200 | int status; | 196 | int status; |
201 | 197 | ||
202 | mutex_lock(&ps3_gpu_mutex); | 198 | mutex_lock(&ps3_gpu_mutex); |
@@ -205,13 +201,10 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) | |||
205 | (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); | 201 | (priv->fifo_ptr - priv->fifo_base) * sizeof(u32); |
206 | 202 | ||
207 | /* asking the HV for a blit will kick the FIFO */ | 203 | /* asking the HV for a blit will kick the FIFO */ |
208 | status = lv1_gpu_context_attribute(priv->context_handle, | 204 | status = lv1_gpu_fb_blit(priv->context_handle, 0, 0, 0, 0); |
209 | L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0, | ||
210 | 0, 0, 0); | ||
211 | if (status) | 205 | if (status) |
212 | dev_err(&dev->core, | 206 | dev_err(&dev->core, "%s: lv1_gpu_fb_blit failed %d\n", |
213 | "%s: lv1_gpu_context_attribute failed %d\n", __func__, | 207 | __func__, status); |
214 | status); | ||
215 | 208 | ||
216 | if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > | 209 | if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) > |
217 | FIFO_SIZE - 1024) { | 210 | FIFO_SIZE - 1024) { |
@@ -225,7 +218,7 @@ static void ps3vram_fire_ring(struct ps3_system_bus_device *dev) | |||
225 | 218 | ||
226 | static void ps3vram_bind(struct ps3_system_bus_device *dev) | 219 | static void ps3vram_bind(struct ps3_system_bus_device *dev) |
227 | { | 220 | { |
228 | struct ps3vram_priv *priv = dev->core.driver_data; | 221 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
229 | 222 | ||
230 | ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); | 223 | ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1); |
231 | ps3vram_out_ring(priv, 0x31337303); | 224 | ps3vram_out_ring(priv, 0x31337303); |
@@ -248,7 +241,7 @@ static int ps3vram_upload(struct ps3_system_bus_device *dev, | |||
248 | unsigned int src_offset, unsigned int dst_offset, | 241 | unsigned int src_offset, unsigned int dst_offset, |
249 | int len, int count) | 242 | int len, int count) |
250 | { | 243 | { |
251 | struct ps3vram_priv *priv = dev->core.driver_data; | 244 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
252 | 245 | ||
253 | ps3vram_begin_ring(priv, UPLOAD_SUBCH, | 246 | ps3vram_begin_ring(priv, UPLOAD_SUBCH, |
254 | NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); | 247 | NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); |
@@ -280,7 +273,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, | |||
280 | unsigned int src_offset, unsigned int dst_offset, | 273 | unsigned int src_offset, unsigned int dst_offset, |
281 | int len, int count) | 274 | int len, int count) |
282 | { | 275 | { |
283 | struct ps3vram_priv *priv = dev->core.driver_data; | 276 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
284 | 277 | ||
285 | ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, | 278 | ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, |
286 | NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); | 279 | NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8); |
@@ -310,7 +303,7 @@ static int ps3vram_download(struct ps3_system_bus_device *dev, | |||
310 | 303 | ||
311 | static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) | 304 | static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) |
312 | { | 305 | { |
313 | struct ps3vram_priv *priv = dev->core.driver_data; | 306 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
314 | struct ps3vram_cache *cache = &priv->cache; | 307 | struct ps3vram_cache *cache = &priv->cache; |
315 | 308 | ||
316 | if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) | 309 | if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY)) |
@@ -332,7 +325,7 @@ static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry) | |||
332 | static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, | 325 | static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, |
333 | unsigned int address) | 326 | unsigned int address) |
334 | { | 327 | { |
335 | struct ps3vram_priv *priv = dev->core.driver_data; | 328 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
336 | struct ps3vram_cache *cache = &priv->cache; | 329 | struct ps3vram_cache *cache = &priv->cache; |
337 | 330 | ||
338 | dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); | 331 | dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address); |
@@ -352,7 +345,7 @@ static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry, | |||
352 | 345 | ||
353 | static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) | 346 | static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) |
354 | { | 347 | { |
355 | struct ps3vram_priv *priv = dev->core.driver_data; | 348 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
356 | struct ps3vram_cache *cache = &priv->cache; | 349 | struct ps3vram_cache *cache = &priv->cache; |
357 | int i; | 350 | int i; |
358 | 351 | ||
@@ -366,7 +359,7 @@ static void ps3vram_cache_flush(struct ps3_system_bus_device *dev) | |||
366 | static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, | 359 | static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, |
367 | loff_t address) | 360 | loff_t address) |
368 | { | 361 | { |
369 | struct ps3vram_priv *priv = dev->core.driver_data; | 362 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
370 | struct ps3vram_cache *cache = &priv->cache; | 363 | struct ps3vram_cache *cache = &priv->cache; |
371 | unsigned int base; | 364 | unsigned int base; |
372 | unsigned int offset; | 365 | unsigned int offset; |
@@ -400,7 +393,7 @@ static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev, | |||
400 | 393 | ||
401 | static int ps3vram_cache_init(struct ps3_system_bus_device *dev) | 394 | static int ps3vram_cache_init(struct ps3_system_bus_device *dev) |
402 | { | 395 | { |
403 | struct ps3vram_priv *priv = dev->core.driver_data; | 396 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
404 | 397 | ||
405 | priv->cache.page_count = CACHE_PAGE_COUNT; | 398 | priv->cache.page_count = CACHE_PAGE_COUNT; |
406 | priv->cache.page_size = CACHE_PAGE_SIZE; | 399 | priv->cache.page_size = CACHE_PAGE_SIZE; |
@@ -419,7 +412,7 @@ static int ps3vram_cache_init(struct ps3_system_bus_device *dev) | |||
419 | 412 | ||
420 | static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) | 413 | static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) |
421 | { | 414 | { |
422 | struct ps3vram_priv *priv = dev->core.driver_data; | 415 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
423 | 416 | ||
424 | ps3vram_cache_flush(dev); | 417 | ps3vram_cache_flush(dev); |
425 | kfree(priv->cache.tags); | 418 | kfree(priv->cache.tags); |
@@ -428,7 +421,7 @@ static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev) | |||
428 | static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, | 421 | static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, |
429 | size_t len, size_t *retlen, u_char *buf) | 422 | size_t len, size_t *retlen, u_char *buf) |
430 | { | 423 | { |
431 | struct ps3vram_priv *priv = dev->core.driver_data; | 424 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
432 | unsigned int cached, count; | 425 | unsigned int cached, count; |
433 | 426 | ||
434 | dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, | 427 | dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__, |
@@ -449,8 +442,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, | |||
449 | offset = (unsigned int) (from & (priv->cache.page_size - 1)); | 442 | offset = (unsigned int) (from & (priv->cache.page_size - 1)); |
450 | avail = priv->cache.page_size - offset; | 443 | avail = priv->cache.page_size - offset; |
451 | 444 | ||
452 | mutex_lock(&priv->lock); | ||
453 | |||
454 | entry = ps3vram_cache_match(dev, from); | 445 | entry = ps3vram_cache_match(dev, from); |
455 | cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; | 446 | cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; |
456 | 447 | ||
@@ -462,8 +453,6 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, | |||
462 | avail = count; | 453 | avail = count; |
463 | memcpy(buf, priv->xdr_buf + cached, avail); | 454 | memcpy(buf, priv->xdr_buf + cached, avail); |
464 | 455 | ||
465 | mutex_unlock(&priv->lock); | ||
466 | |||
467 | buf += avail; | 456 | buf += avail; |
468 | count -= avail; | 457 | count -= avail; |
469 | from += avail; | 458 | from += avail; |
@@ -476,7 +465,7 @@ static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from, | |||
476 | static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, | 465 | static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, |
477 | size_t len, size_t *retlen, const u_char *buf) | 466 | size_t len, size_t *retlen, const u_char *buf) |
478 | { | 467 | { |
479 | struct ps3vram_priv *priv = dev->core.driver_data; | 468 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
480 | unsigned int cached, count; | 469 | unsigned int cached, count; |
481 | 470 | ||
482 | if (to >= priv->size) | 471 | if (to >= priv->size) |
@@ -494,8 +483,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, | |||
494 | offset = (unsigned int) (to & (priv->cache.page_size - 1)); | 483 | offset = (unsigned int) (to & (priv->cache.page_size - 1)); |
495 | avail = priv->cache.page_size - offset; | 484 | avail = priv->cache.page_size - offset; |
496 | 485 | ||
497 | mutex_lock(&priv->lock); | ||
498 | |||
499 | entry = ps3vram_cache_match(dev, to); | 486 | entry = ps3vram_cache_match(dev, to); |
500 | cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; | 487 | cached = CACHE_OFFSET + entry * priv->cache.page_size + offset; |
501 | 488 | ||
@@ -509,8 +496,6 @@ static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to, | |||
509 | 496 | ||
510 | priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; | 497 | priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY; |
511 | 498 | ||
512 | mutex_unlock(&priv->lock); | ||
513 | |||
514 | buf += avail; | 499 | buf += avail; |
515 | count -= avail; | 500 | count -= avail; |
516 | to += avail; | 501 | to += avail; |
@@ -543,28 +528,26 @@ static const struct file_operations ps3vram_proc_fops = { | |||
543 | 528 | ||
544 | static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) | 529 | static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev) |
545 | { | 530 | { |
546 | struct ps3vram_priv *priv = dev->core.driver_data; | 531 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
547 | struct proc_dir_entry *pde; | 532 | struct proc_dir_entry *pde; |
548 | 533 | ||
549 | pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops); | 534 | pde = proc_create_data(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops, |
550 | if (!pde) { | 535 | priv); |
536 | if (!pde) | ||
551 | dev_warn(&dev->core, "failed to create /proc entry\n"); | 537 | dev_warn(&dev->core, "failed to create /proc entry\n"); |
552 | return; | ||
553 | } | ||
554 | pde->data = priv; | ||
555 | } | 538 | } |
556 | 539 | ||
557 | static int ps3vram_make_request(struct request_queue *q, struct bio *bio) | 540 | static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev, |
541 | struct bio *bio) | ||
558 | { | 542 | { |
559 | struct ps3_system_bus_device *dev = q->queuedata; | 543 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
560 | int write = bio_data_dir(bio) == WRITE; | 544 | int write = bio_data_dir(bio) == WRITE; |
561 | const char *op = write ? "write" : "read"; | 545 | const char *op = write ? "write" : "read"; |
562 | loff_t offset = bio->bi_sector << 9; | 546 | loff_t offset = bio->bi_sector << 9; |
563 | int error = 0; | 547 | int error = 0; |
564 | struct bio_vec *bvec; | 548 | struct bio_vec *bvec; |
565 | unsigned int i; | 549 | unsigned int i; |
566 | 550 | struct bio *next; | |
567 | dev_dbg(&dev->core, "%s\n", __func__); | ||
568 | 551 | ||
569 | bio_for_each_segment(bvec, bio, i) { | 552 | bio_for_each_segment(bvec, bio, i) { |
570 | /* PS3 is ppc64, so we don't handle highmem */ | 553 | /* PS3 is ppc64, so we don't handle highmem */ |
@@ -585,6 +568,7 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) | |||
585 | 568 | ||
586 | if (retlen != len) { | 569 | if (retlen != len) { |
587 | dev_err(&dev->core, "Short %s\n", op); | 570 | dev_err(&dev->core, "Short %s\n", op); |
571 | error = -EIO; | ||
588 | goto out; | 572 | goto out; |
589 | } | 573 | } |
590 | 574 | ||
@@ -594,7 +578,35 @@ static int ps3vram_make_request(struct request_queue *q, struct bio *bio) | |||
594 | dev_dbg(&dev->core, "%s completed\n", op); | 578 | dev_dbg(&dev->core, "%s completed\n", op); |
595 | 579 | ||
596 | out: | 580 | out: |
581 | spin_lock_irq(&priv->lock); | ||
582 | bio_list_pop(&priv->list); | ||
583 | next = bio_list_peek(&priv->list); | ||
584 | spin_unlock_irq(&priv->lock); | ||
585 | |||
597 | bio_endio(bio, error); | 586 | bio_endio(bio, error); |
587 | return next; | ||
588 | } | ||
589 | |||
590 | static int ps3vram_make_request(struct request_queue *q, struct bio *bio) | ||
591 | { | ||
592 | struct ps3_system_bus_device *dev = q->queuedata; | ||
593 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); | ||
594 | int busy; | ||
595 | |||
596 | dev_dbg(&dev->core, "%s\n", __func__); | ||
597 | |||
598 | spin_lock_irq(&priv->lock); | ||
599 | busy = !bio_list_empty(&priv->list); | ||
600 | bio_list_add(&priv->list, bio); | ||
601 | spin_unlock_irq(&priv->lock); | ||
602 | |||
603 | if (busy) | ||
604 | return 0; | ||
605 | |||
606 | do { | ||
607 | bio = ps3vram_do_bio(dev, bio); | ||
608 | } while (bio); | ||
609 | |||
598 | return 0; | 610 | return 0; |
599 | } | 611 | } |
600 | 612 | ||
@@ -604,8 +616,8 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) | |||
604 | int error, status; | 616 | int error, status; |
605 | struct request_queue *queue; | 617 | struct request_queue *queue; |
606 | struct gendisk *gendisk; | 618 | struct gendisk *gendisk; |
607 | u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size, | 619 | u64 ddr_size, ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, |
608 | reports_size; | 620 | reports_size, xdr_lpar; |
609 | char *rest; | 621 | char *rest; |
610 | 622 | ||
611 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 623 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
@@ -614,10 +626,9 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) | |||
614 | goto fail; | 626 | goto fail; |
615 | } | 627 | } |
616 | 628 | ||
617 | mutex_init(&priv->lock); | 629 | spin_lock_init(&priv->lock); |
618 | dev->core.driver_data = priv; | 630 | bio_list_init(&priv->list); |
619 | 631 | ps3_system_bus_set_drvdata(dev, priv); | |
620 | priv = dev->core.driver_data; | ||
621 | 632 | ||
622 | /* Allocate XDR buffer (1MiB aligned) */ | 633 | /* Allocate XDR buffer (1MiB aligned) */ |
623 | priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, | 634 | priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL, |
@@ -636,7 +647,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) | |||
636 | if (ps3_open_hv_device(dev)) { | 647 | if (ps3_open_hv_device(dev)) { |
637 | dev_err(&dev->core, "ps3_open_hv_device failed\n"); | 648 | dev_err(&dev->core, "ps3_open_hv_device failed\n"); |
638 | error = -EAGAIN; | 649 | error = -EAGAIN; |
639 | goto out_close_gpu; | 650 | goto out_free_xdr_buf; |
640 | } | 651 | } |
641 | 652 | ||
642 | /* Request memory */ | 653 | /* Request memory */ |
@@ -660,7 +671,7 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) | |||
660 | dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n", | 671 | dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n", |
661 | status); | 672 | status); |
662 | error = -ENOMEM; | 673 | error = -ENOMEM; |
663 | goto out_free_xdr_buf; | 674 | goto out_close_gpu; |
664 | } | 675 | } |
665 | 676 | ||
666 | /* Request context */ | 677 | /* Request context */ |
@@ -676,9 +687,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) | |||
676 | } | 687 | } |
677 | 688 | ||
678 | /* Map XDR buffer to RSX */ | 689 | /* Map XDR buffer to RSX */ |
690 | xdr_lpar = ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)); | ||
679 | status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, | 691 | status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, |
680 | ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), | 692 | xdr_lpar, XDR_BUF_SIZE, |
681 | XDR_BUF_SIZE, 0); | 693 | CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | |
694 | CBE_IOPTE_M); | ||
682 | if (status) { | 695 | if (status) { |
683 | dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n", | 696 | dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n", |
684 | status); | 697 | status); |
@@ -686,19 +699,11 @@ static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev) | |||
686 | goto out_free_context; | 699 | goto out_free_context; |
687 | } | 700 | } |
688 | 701 | ||
689 | priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE); | ||
690 | |||
691 | if (!priv->ddr_base) { | ||
692 | dev_err(&dev->core, "ioremap DDR failed\n"); | ||
693 | error = -ENOMEM; | ||
694 | goto out_free_context; | ||
695 | } | ||
696 | |||
697 | priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); | 702 | priv->ctrl = ioremap(ctrl_lpar, 64 * 1024); |
698 | if (!priv->ctrl) { | 703 | if (!priv->ctrl) { |
699 | dev_err(&dev->core, "ioremap CTRL failed\n"); | 704 | dev_err(&dev->core, "ioremap CTRL failed\n"); |
700 | error = -ENOMEM; | 705 | error = -ENOMEM; |
701 | goto out_unmap_vram; | 706 | goto out_unmap_context; |
702 | } | 707 | } |
703 | 708 | ||
704 | priv->reports = ioremap(reports_lpar, reports_size); | 709 | priv->reports = ioremap(reports_lpar, reports_size); |
@@ -775,8 +780,9 @@ out_unmap_reports: | |||
775 | iounmap(priv->reports); | 780 | iounmap(priv->reports); |
776 | out_unmap_ctrl: | 781 | out_unmap_ctrl: |
777 | iounmap(priv->ctrl); | 782 | iounmap(priv->ctrl); |
778 | out_unmap_vram: | 783 | out_unmap_context: |
779 | iounmap(priv->ddr_base); | 784 | lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, xdr_lpar, |
785 | XDR_BUF_SIZE, CBE_IOPTE_M); | ||
780 | out_free_context: | 786 | out_free_context: |
781 | lv1_gpu_context_free(priv->context_handle); | 787 | lv1_gpu_context_free(priv->context_handle); |
782 | out_free_memory: | 788 | out_free_memory: |
@@ -787,14 +793,14 @@ out_free_xdr_buf: | |||
787 | free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); | 793 | free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); |
788 | fail_free_priv: | 794 | fail_free_priv: |
789 | kfree(priv); | 795 | kfree(priv); |
790 | dev->core.driver_data = NULL; | 796 | ps3_system_bus_set_drvdata(dev, NULL); |
791 | fail: | 797 | fail: |
792 | return error; | 798 | return error; |
793 | } | 799 | } |
794 | 800 | ||
795 | static int ps3vram_remove(struct ps3_system_bus_device *dev) | 801 | static int ps3vram_remove(struct ps3_system_bus_device *dev) |
796 | { | 802 | { |
797 | struct ps3vram_priv *priv = dev->core.driver_data; | 803 | struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev); |
798 | 804 | ||
799 | del_gendisk(priv->gendisk); | 805 | del_gendisk(priv->gendisk); |
800 | put_disk(priv->gendisk); | 806 | put_disk(priv->gendisk); |
@@ -803,13 +809,15 @@ static int ps3vram_remove(struct ps3_system_bus_device *dev) | |||
803 | ps3vram_cache_cleanup(dev); | 809 | ps3vram_cache_cleanup(dev); |
804 | iounmap(priv->reports); | 810 | iounmap(priv->reports); |
805 | iounmap(priv->ctrl); | 811 | iounmap(priv->ctrl); |
806 | iounmap(priv->ddr_base); | 812 | lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF, |
813 | ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)), | ||
814 | XDR_BUF_SIZE, CBE_IOPTE_M); | ||
807 | lv1_gpu_context_free(priv->context_handle); | 815 | lv1_gpu_context_free(priv->context_handle); |
808 | lv1_gpu_memory_free(priv->memory_handle); | 816 | lv1_gpu_memory_free(priv->memory_handle); |
809 | ps3_close_hv_device(dev); | 817 | ps3_close_hv_device(dev); |
810 | free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); | 818 | free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE)); |
811 | kfree(priv); | 819 | kfree(priv); |
812 | dev->core.driver_data = NULL; | 820 | ps3_system_bus_set_drvdata(dev, NULL); |
813 | return 0; | 821 | return 0; |
814 | } | 822 | } |
815 | 823 | ||
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c index 54481a887769..86105efb4eb6 100644 --- a/drivers/char/hvc_iucv.c +++ b/drivers/char/hvc_iucv.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This HVC device driver provides terminal access using | 4 | * This HVC device driver provides terminal access using |
5 | * z/VM IUCV communication paths. | 5 | * z/VM IUCV communication paths. |
6 | * | 6 | * |
7 | * Copyright IBM Corp. 2008 | 7 | * Copyright IBM Corp. 2008, 2009 |
8 | * | 8 | * |
9 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | 9 | * Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com> |
10 | */ | 10 | */ |
@@ -15,6 +15,7 @@ | |||
15 | #include <asm/ebcdic.h> | 15 | #include <asm/ebcdic.h> |
16 | #include <linux/ctype.h> | 16 | #include <linux/ctype.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/device.h> | ||
18 | #include <linux/init.h> | 19 | #include <linux/init.h> |
19 | #include <linux/mempool.h> | 20 | #include <linux/mempool.h> |
20 | #include <linux/moduleparam.h> | 21 | #include <linux/moduleparam.h> |
@@ -74,6 +75,7 @@ struct hvc_iucv_private { | |||
74 | wait_queue_head_t sndbuf_waitq; /* wait for send completion */ | 75 | wait_queue_head_t sndbuf_waitq; /* wait for send completion */ |
75 | struct list_head tty_outqueue; /* outgoing IUCV messages */ | 76 | struct list_head tty_outqueue; /* outgoing IUCV messages */ |
76 | struct list_head tty_inqueue; /* incoming IUCV messages */ | 77 | struct list_head tty_inqueue; /* incoming IUCV messages */ |
78 | struct device *dev; /* device structure */ | ||
77 | }; | 79 | }; |
78 | 80 | ||
79 | struct iucv_tty_buffer { | 81 | struct iucv_tty_buffer { |
@@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv) | |||
542 | 544 | ||
543 | if (sync_wait) | 545 | if (sync_wait) |
544 | wait_event_timeout(priv->sndbuf_waitq, | 546 | wait_event_timeout(priv->sndbuf_waitq, |
545 | tty_outqueue_empty(priv), HZ); | 547 | tty_outqueue_empty(priv), HZ/10); |
548 | } | ||
549 | |||
550 | /** | ||
551 | * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up | ||
552 | * @priv: Pointer to hvc_iucv_private structure | ||
553 | * | ||
554 | * This routine severs an existing IUCV communication path and hangs | ||
555 | * up the underlying HVC terminal device. | ||
556 | * The hang-up occurs only if an IUCV communication path is established; | ||
557 | * otherwise there is no need to hang up the terminal device. | ||
558 | * | ||
559 | * The IUCV HVC hang-up is separated into two steps: | ||
560 | * 1. After the IUCV path has been severed, the iucv_state is set to | ||
561 | * IUCV_SEVERED. | ||
562 | * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the | ||
563 | * IUCV_SEVERED state causes the tty hang-up in the HVC layer. | ||
564 | * | ||
565 | * If the tty has not yet been opened, clean up the hvc_iucv_private | ||
566 | * structure to allow re-connects. | ||
567 | * If the tty has been opened, let get_chars() return -EPIPE to signal | ||
568 | * the HVC layer to hang up the tty and, if so, wake up the HVC thread | ||
569 | * to call get_chars()... | ||
570 | * | ||
571 | * Special notes on hanging up a HVC terminal instantiated as console: | ||
572 | * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops) | ||
573 | * 2. do_tty_hangup() calls tty->ops->close() for console_filp | ||
574 | * => no hangup notifier is called by HVC (default) | ||
575 | * 2. hvc_close() returns because of tty_hung_up_p(filp) | ||
576 | * => no delete notifier is called! | ||
577 | * Finally, the back-end is not being notified, thus, the tty session is | ||
578 | * kept active (TTY_OPEN) to be ready for re-connects. | ||
579 | * | ||
580 | * Locking: spin_lock(&priv->lock) w/o disabling bh | ||
581 | */ | ||
582 | static void hvc_iucv_hangup(struct hvc_iucv_private *priv) | ||
583 | { | ||
584 | struct iucv_path *path; | ||
585 | |||
586 | path = NULL; | ||
587 | spin_lock(&priv->lock); | ||
588 | if (priv->iucv_state == IUCV_CONNECTED) { | ||
589 | path = priv->path; | ||
590 | priv->path = NULL; | ||
591 | priv->iucv_state = IUCV_SEVERED; | ||
592 | if (priv->tty_state == TTY_CLOSED) | ||
593 | hvc_iucv_cleanup(priv); | ||
594 | else | ||
595 | /* console is special (see above) */ | ||
596 | if (priv->is_console) { | ||
597 | hvc_iucv_cleanup(priv); | ||
598 | priv->tty_state = TTY_OPENED; | ||
599 | } else | ||
600 | hvc_kick(); | ||
601 | } | ||
602 | spin_unlock(&priv->lock); | ||
603 | |||
604 | /* finally sever path (outside of priv->lock due to lock ordering) */ | ||
605 | if (path) { | ||
606 | iucv_path_sever(path, NULL); | ||
607 | iucv_path_free(path); | ||
608 | } | ||
546 | } | 609 | } |
547 | 610 | ||
548 | /** | 611 | /** |
@@ -735,11 +798,8 @@ out_path_handled: | |||
735 | * @ipuser: User specified data for this path | 798 | * @ipuser: User specified data for this path |
736 | * (AF_IUCV: port/service name and originator port) | 799 | * (AF_IUCV: port/service name and originator port) |
737 | * | 800 | * |
738 | * The function also severs the path (as required by the IUCV protocol) and | 801 | * This function calls the hvc_iucv_hangup() function for the |
739 | * sets the iucv state to IUCV_SEVERED for the associated struct | 802 | * respective IUCV HVC terminal. |
740 | * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty | ||
741 | * hangup (hvc_iucv_get_chars() / hvc_iucv_write()). | ||
742 | * If tty portion of the HVC is closed, clean up the outqueue. | ||
743 | * | 803 | * |
744 | * Locking: struct hvc_iucv_private->lock | 804 | * Locking: struct hvc_iucv_private->lock |
745 | */ | 805 | */ |
@@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16]) | |||
747 | { | 807 | { |
748 | struct hvc_iucv_private *priv = path->private; | 808 | struct hvc_iucv_private *priv = path->private; |
749 | 809 | ||
750 | spin_lock(&priv->lock); | 810 | hvc_iucv_hangup(priv); |
751 | priv->iucv_state = IUCV_SEVERED; | ||
752 | |||
753 | /* If the tty has not yet been opened, clean up the hvc_iucv_private | ||
754 | * structure to allow re-connects. | ||
755 | * This is also done for our console device because console hangups | ||
756 | * are handled specially and no notifier is called by HVC. | ||
757 | * The tty session is active (TTY_OPEN) and ready for re-connects... | ||
758 | * | ||
759 | * If it has been opened, let get_chars() return -EPIPE to signal the | ||
760 | * HVC layer to hang up the tty. | ||
761 | * If so, we need to wake up the HVC thread to call get_chars()... | ||
762 | */ | ||
763 | priv->path = NULL; | ||
764 | if (priv->tty_state == TTY_CLOSED) | ||
765 | hvc_iucv_cleanup(priv); | ||
766 | else | ||
767 | if (priv->is_console) { | ||
768 | hvc_iucv_cleanup(priv); | ||
769 | priv->tty_state = TTY_OPENED; | ||
770 | } else | ||
771 | hvc_kick(); | ||
772 | spin_unlock(&priv->lock); | ||
773 | |||
774 | /* finally sever path (outside of priv->lock due to lock ordering) */ | ||
775 | iucv_path_sever(path, ipuser); | ||
776 | iucv_path_free(path); | ||
777 | } | 811 | } |
778 | 812 | ||
779 | /** | 813 | /** |
@@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path, | |||
853 | destroy_tty_buffer_list(&list_remove); | 887 | destroy_tty_buffer_list(&list_remove); |
854 | } | 888 | } |
855 | 889 | ||
890 | /** | ||
891 | * hvc_iucv_pm_freeze() - Freeze PM callback | ||
892 | * @dev: IUVC HVC terminal device | ||
893 | * | ||
894 | * Sever an established IUCV communication path and | ||
895 | * trigger a hang-up of the underlying HVC terminal. | ||
896 | */ | ||
897 | static int hvc_iucv_pm_freeze(struct device *dev) | ||
898 | { | ||
899 | struct hvc_iucv_private *priv = dev_get_drvdata(dev); | ||
900 | |||
901 | local_bh_disable(); | ||
902 | hvc_iucv_hangup(priv); | ||
903 | local_bh_enable(); | ||
904 | |||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | /** | ||
909 | * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback | ||
910 | * @dev: IUVC HVC terminal device | ||
911 | * | ||
912 | * Wake up the HVC thread to trigger hang-up and respective | ||
913 | * HVC back-end notifier invocations. | ||
914 | */ | ||
915 | static int hvc_iucv_pm_restore_thaw(struct device *dev) | ||
916 | { | ||
917 | hvc_kick(); | ||
918 | return 0; | ||
919 | } | ||
920 | |||
856 | 921 | ||
857 | /* HVC operations */ | 922 | /* HVC operations */ |
858 | static struct hv_ops hvc_iucv_ops = { | 923 | static struct hv_ops hvc_iucv_ops = { |
@@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = { | |||
863 | .notifier_hangup = hvc_iucv_notifier_hangup, | 928 | .notifier_hangup = hvc_iucv_notifier_hangup, |
864 | }; | 929 | }; |
865 | 930 | ||
931 | /* Suspend / resume device operations */ | ||
932 | static struct dev_pm_ops hvc_iucv_pm_ops = { | ||
933 | .freeze = hvc_iucv_pm_freeze, | ||
934 | .thaw = hvc_iucv_pm_restore_thaw, | ||
935 | .restore = hvc_iucv_pm_restore_thaw, | ||
936 | }; | ||
937 | |||
938 | /* IUCV HVC device driver */ | ||
939 | static struct device_driver hvc_iucv_driver = { | ||
940 | .name = KMSG_COMPONENT, | ||
941 | .bus = &iucv_bus, | ||
942 | .pm = &hvc_iucv_pm_ops, | ||
943 | }; | ||
944 | |||
866 | /** | 945 | /** |
867 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance | 946 | * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance |
868 | * @id: hvc_iucv_table index | 947 | * @id: hvc_iucv_table index |
@@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) | |||
897 | /* set console flag */ | 976 | /* set console flag */ |
898 | priv->is_console = is_console; | 977 | priv->is_console = is_console; |
899 | 978 | ||
900 | /* finally allocate hvc */ | 979 | /* allocate hvc device */ |
901 | priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ | 980 | priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */ |
902 | HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); | 981 | HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256); |
903 | if (IS_ERR(priv->hvc)) { | 982 | if (IS_ERR(priv->hvc)) { |
904 | rc = PTR_ERR(priv->hvc); | 983 | rc = PTR_ERR(priv->hvc); |
905 | free_page((unsigned long) priv->sndbuf); | 984 | goto out_error_hvc; |
906 | kfree(priv); | ||
907 | return rc; | ||
908 | } | 985 | } |
909 | 986 | ||
910 | /* notify HVC thread instead of using polling */ | 987 | /* notify HVC thread instead of using polling */ |
@@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console) | |||
915 | memcpy(priv->srv_name, name, 8); | 992 | memcpy(priv->srv_name, name, 8); |
916 | ASCEBC(priv->srv_name, 8); | 993 | ASCEBC(priv->srv_name, 8); |
917 | 994 | ||
995 | /* create and setup device */ | ||
996 | priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL); | ||
997 | if (!priv->dev) { | ||
998 | rc = -ENOMEM; | ||
999 | goto out_error_dev; | ||
1000 | } | ||
1001 | dev_set_name(priv->dev, "hvc_iucv%d", id); | ||
1002 | dev_set_drvdata(priv->dev, priv); | ||
1003 | priv->dev->bus = &iucv_bus; | ||
1004 | priv->dev->parent = iucv_root; | ||
1005 | priv->dev->driver = &hvc_iucv_driver; | ||
1006 | priv->dev->release = (void (*)(struct device *)) kfree; | ||
1007 | rc = device_register(priv->dev); | ||
1008 | if (rc) { | ||
1009 | kfree(priv->dev); | ||
1010 | goto out_error_dev; | ||
1011 | } | ||
1012 | |||
918 | hvc_iucv_table[id] = priv; | 1013 | hvc_iucv_table[id] = priv; |
919 | return 0; | 1014 | return 0; |
1015 | |||
1016 | out_error_dev: | ||
1017 | hvc_remove(priv->hvc); | ||
1018 | out_error_hvc: | ||
1019 | free_page((unsigned long) priv->sndbuf); | ||
1020 | kfree(priv); | ||
1021 | |||
1022 | return rc; | ||
1023 | } | ||
1024 | |||
1025 | /** | ||
1026 | * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances | ||
1027 | */ | ||
1028 | static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv) | ||
1029 | { | ||
1030 | hvc_remove(priv->hvc); | ||
1031 | device_unregister(priv->dev); | ||
1032 | free_page((unsigned long) priv->sndbuf); | ||
1033 | kfree(priv); | ||
920 | } | 1034 | } |
921 | 1035 | ||
922 | /** | 1036 | /** |
@@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void) | |||
1109 | goto out_error; | 1223 | goto out_error; |
1110 | } | 1224 | } |
1111 | 1225 | ||
1226 | /* register IUCV HVC device driver */ | ||
1227 | rc = driver_register(&hvc_iucv_driver); | ||
1228 | if (rc) | ||
1229 | goto out_error; | ||
1230 | |||
1112 | /* parse hvc_iucv_allow string and create z/VM user ID filter list */ | 1231 | /* parse hvc_iucv_allow string and create z/VM user ID filter list */ |
1113 | if (hvc_iucv_filter_string) { | 1232 | if (hvc_iucv_filter_string) { |
1114 | rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); | 1233 | rc = hvc_iucv_setup_filter(hvc_iucv_filter_string); |
@@ -1183,15 +1302,14 @@ out_error_iucv: | |||
1183 | iucv_unregister(&hvc_iucv_handler, 0); | 1302 | iucv_unregister(&hvc_iucv_handler, 0); |
1184 | out_error_hvc: | 1303 | out_error_hvc: |
1185 | for (i = 0; i < hvc_iucv_devices; i++) | 1304 | for (i = 0; i < hvc_iucv_devices; i++) |
1186 | if (hvc_iucv_table[i]) { | 1305 | if (hvc_iucv_table[i]) |
1187 | if (hvc_iucv_table[i]->hvc) | 1306 | hvc_iucv_destroy(hvc_iucv_table[i]); |
1188 | hvc_remove(hvc_iucv_table[i]->hvc); | ||
1189 | kfree(hvc_iucv_table[i]); | ||
1190 | } | ||
1191 | out_error_memory: | 1307 | out_error_memory: |
1192 | mempool_destroy(hvc_iucv_mempool); | 1308 | mempool_destroy(hvc_iucv_mempool); |
1193 | kmem_cache_destroy(hvc_iucv_buffer_cache); | 1309 | kmem_cache_destroy(hvc_iucv_buffer_cache); |
1194 | out_error: | 1310 | out_error: |
1311 | if (hvc_iucv_filter) | ||
1312 | kfree(hvc_iucv_filter); | ||
1195 | hvc_iucv_devices = 0; /* ensure that we do not provide any device */ | 1313 | hvc_iucv_devices = 0; /* ensure that we do not provide any device */ |
1196 | return rc; | 1314 | return rc; |
1197 | } | 1315 | } |
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c index afbe45676d71..f424d394a286 100644 --- a/drivers/char/ps3flash.c +++ b/drivers/char/ps3flash.c | |||
@@ -33,48 +33,64 @@ | |||
33 | 33 | ||
34 | struct ps3flash_private { | 34 | struct ps3flash_private { |
35 | struct mutex mutex; /* Bounce buffer mutex */ | 35 | struct mutex mutex; /* Bounce buffer mutex */ |
36 | u64 chunk_sectors; | ||
37 | int tag; /* Start sector of buffer, -1 if invalid */ | ||
38 | bool dirty; | ||
36 | }; | 39 | }; |
37 | 40 | ||
38 | static struct ps3_storage_device *ps3flash_dev; | 41 | static struct ps3_storage_device *ps3flash_dev; |
39 | 42 | ||
40 | static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev, | 43 | static int ps3flash_read_write_sectors(struct ps3_storage_device *dev, |
41 | u64 lpar, u64 start_sector, | 44 | u64 start_sector, int write) |
42 | u64 sectors, int write) | ||
43 | { | 45 | { |
44 | u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors, | 46 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
47 | u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar, | ||
48 | start_sector, priv->chunk_sectors, | ||
45 | write); | 49 | write); |
46 | if (res) { | 50 | if (res) { |
47 | dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, | 51 | dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__, |
48 | __LINE__, write ? "write" : "read", res); | 52 | __LINE__, write ? "write" : "read", res); |
49 | return -EIO; | 53 | return -EIO; |
50 | } | 54 | } |
51 | return sectors; | 55 | return 0; |
52 | } | 56 | } |
53 | 57 | ||
54 | static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev, | 58 | static int ps3flash_writeback(struct ps3_storage_device *dev) |
55 | u64 start_sector, u64 sectors, | ||
56 | unsigned int sector_offset) | ||
57 | { | 59 | { |
58 | u64 max_sectors, lpar; | 60 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
61 | int res; | ||
59 | 62 | ||
60 | max_sectors = dev->bounce_size / dev->blk_size; | 63 | if (!priv->dirty || priv->tag < 0) |
61 | if (sectors > max_sectors) { | 64 | return 0; |
62 | dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n", | ||
63 | __func__, __LINE__, max_sectors); | ||
64 | sectors = max_sectors; | ||
65 | } | ||
66 | 65 | ||
67 | lpar = dev->bounce_lpar + sector_offset * dev->blk_size; | 66 | res = ps3flash_read_write_sectors(dev, priv->tag, 1); |
68 | return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors, | 67 | if (res) |
69 | 0); | 68 | return res; |
69 | |||
70 | priv->dirty = false; | ||
71 | return 0; | ||
70 | } | 72 | } |
71 | 73 | ||
72 | static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev, | 74 | static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector) |
73 | u64 start_sector) | ||
74 | { | 75 | { |
75 | u64 sectors = dev->bounce_size / dev->blk_size; | 76 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
76 | return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector, | 77 | int res; |
77 | sectors, 1); | 78 | |
79 | if (start_sector == priv->tag) | ||
80 | return 0; | ||
81 | |||
82 | res = ps3flash_writeback(dev); | ||
83 | if (res) | ||
84 | return res; | ||
85 | |||
86 | priv->tag = -1; | ||
87 | |||
88 | res = ps3flash_read_write_sectors(dev, start_sector, 0); | ||
89 | if (res) | ||
90 | return res; | ||
91 | |||
92 | priv->tag = start_sector; | ||
93 | return 0; | ||
78 | } | 94 | } |
79 | 95 | ||
80 | static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) | 96 | static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin) |
@@ -104,18 +120,19 @@ out: | |||
104 | return res; | 120 | return res; |
105 | } | 121 | } |
106 | 122 | ||
107 | static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, | 123 | static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf, |
108 | loff_t *pos) | 124 | size_t count, loff_t *pos) |
109 | { | 125 | { |
110 | struct ps3_storage_device *dev = ps3flash_dev; | 126 | struct ps3_storage_device *dev = ps3flash_dev; |
111 | struct ps3flash_private *priv = dev->sbd.core.driver_data; | 127 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
112 | u64 size, start_sector, end_sector, offset; | 128 | u64 size, sector, offset; |
113 | ssize_t sectors_read; | 129 | int res; |
114 | size_t remaining, n; | 130 | size_t remaining, n; |
131 | const void *src; | ||
115 | 132 | ||
116 | dev_dbg(&dev->sbd.core, | 133 | dev_dbg(&dev->sbd.core, |
117 | "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n", | 134 | "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n", |
118 | __func__, __LINE__, count, *pos, buf); | 135 | __func__, __LINE__, count, *pos, userbuf, kernelbuf); |
119 | 136 | ||
120 | size = dev->regions[dev->region_idx].size*dev->blk_size; | 137 | size = dev->regions[dev->region_idx].size*dev->blk_size; |
121 | if (*pos >= size || !count) | 138 | if (*pos >= size || !count) |
@@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count, | |||
128 | count = size - *pos; | 145 | count = size - *pos; |
129 | } | 146 | } |
130 | 147 | ||
131 | start_sector = *pos / dev->blk_size; | 148 | sector = *pos / dev->bounce_size * priv->chunk_sectors; |
132 | offset = *pos % dev->blk_size; | 149 | offset = *pos % dev->bounce_size; |
133 | end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size); | ||
134 | 150 | ||
135 | remaining = count; | 151 | remaining = count; |
136 | do { | 152 | do { |
153 | n = min_t(u64, remaining, dev->bounce_size - offset); | ||
154 | src = dev->bounce_buf + offset; | ||
155 | |||
137 | mutex_lock(&priv->mutex); | 156 | mutex_lock(&priv->mutex); |
138 | 157 | ||
139 | sectors_read = ps3flash_read_sectors(dev, start_sector, | 158 | res = ps3flash_fetch(dev, sector); |
140 | end_sector-start_sector, | 159 | if (res) |
141 | 0); | ||
142 | if (sectors_read < 0) { | ||
143 | mutex_unlock(&priv->mutex); | ||
144 | goto fail; | 160 | goto fail; |
145 | } | ||
146 | 161 | ||
147 | n = min_t(u64, remaining, sectors_read*dev->blk_size-offset); | ||
148 | dev_dbg(&dev->sbd.core, | 162 | dev_dbg(&dev->sbd.core, |
149 | "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n", | 163 | "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n", |
150 | __func__, __LINE__, n, dev->bounce_buf+offset, buf); | 164 | __func__, __LINE__, n, src, userbuf, kernelbuf); |
151 | if (copy_to_user(buf, dev->bounce_buf+offset, n)) { | 165 | if (userbuf) { |
152 | mutex_unlock(&priv->mutex); | 166 | if (copy_to_user(userbuf, src, n)) { |
153 | sectors_read = -EFAULT; | 167 | res = -EFAULT; |
154 | goto fail; | 168 | goto fail; |
169 | } | ||
170 | userbuf += n; | ||
171 | } | ||
172 | if (kernelbuf) { | ||
173 | memcpy(kernelbuf, src, n); | ||
174 | kernelbuf += n; | ||
155 | } | 175 | } |
156 | 176 | ||
157 | mutex_unlock(&priv->mutex); | 177 | mutex_unlock(&priv->mutex); |
158 | 178 | ||
159 | *pos += n; | 179 | *pos += n; |
160 | buf += n; | ||
161 | remaining -= n; | 180 | remaining -= n; |
162 | start_sector += sectors_read; | 181 | sector += priv->chunk_sectors; |
163 | offset = 0; | 182 | offset = 0; |
164 | } while (remaining > 0); | 183 | } while (remaining > 0); |
165 | 184 | ||
166 | return count; | 185 | return count; |
167 | 186 | ||
168 | fail: | 187 | fail: |
169 | return sectors_read; | 188 | mutex_unlock(&priv->mutex); |
189 | return res; | ||
170 | } | 190 | } |
171 | 191 | ||
172 | static ssize_t ps3flash_write(struct file *file, const char __user *buf, | 192 | static ssize_t ps3flash_write(const char __user *userbuf, |
173 | size_t count, loff_t *pos) | 193 | const void *kernelbuf, size_t count, loff_t *pos) |
174 | { | 194 | { |
175 | struct ps3_storage_device *dev = ps3flash_dev; | 195 | struct ps3_storage_device *dev = ps3flash_dev; |
176 | struct ps3flash_private *priv = dev->sbd.core.driver_data; | 196 | struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd); |
177 | u64 size, chunk_sectors, start_write_sector, end_write_sector, | 197 | u64 size, sector, offset; |
178 | end_read_sector, start_read_sector, head, tail, offset; | 198 | int res = 0; |
179 | ssize_t res; | ||
180 | size_t remaining, n; | 199 | size_t remaining, n; |
181 | unsigned int sec_off; | 200 | void *dst; |
182 | 201 | ||
183 | dev_dbg(&dev->sbd.core, | 202 | dev_dbg(&dev->sbd.core, |
184 | "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n", | 203 | "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n", |
185 | __func__, __LINE__, count, *pos, buf); | 204 | __func__, __LINE__, count, *pos, userbuf, kernelbuf); |
186 | 205 | ||
187 | size = dev->regions[dev->region_idx].size*dev->blk_size; | 206 | size = dev->regions[dev->region_idx].size*dev->blk_size; |
188 | if (*pos >= size || !count) | 207 | if (*pos >= size || !count) |
@@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf, | |||
195 | count = size - *pos; | 214 | count = size - *pos; |
196 | } | 215 | } |
197 | 216 | ||
198 | chunk_sectors = dev->bounce_size / dev->blk_size; | 217 | sector = *pos / dev->bounce_size * priv->chunk_sectors; |
199 | |||
200 | start_write_sector = *pos / dev->bounce_size * chunk_sectors; | ||
201 | offset = *pos % dev->bounce_size; | 218 | offset = *pos % dev->bounce_size; |
202 | end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) * | ||
203 | chunk_sectors; | ||
204 | |||
205 | end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size); | ||
206 | start_read_sector = (*pos + count) / dev->blk_size; | ||
207 | |||
208 | /* | ||
209 | * As we have to write in 256 KiB chunks, while we can read in blk_size | ||
210 | * (usually 512 bytes) chunks, we perform the following steps: | ||
211 | * 1. Read from start_write_sector to end_read_sector ("head") | ||
212 | * 2. Read from start_read_sector to end_write_sector ("tail") | ||
213 | * 3. Copy data to buffer | ||
214 | * 4. Write from start_write_sector to end_write_sector | ||
215 | * All of this is complicated by using only one 256 KiB bounce buffer. | ||
216 | */ | ||
217 | |||
218 | head = end_read_sector - start_write_sector; | ||
219 | tail = end_write_sector - start_read_sector; | ||
220 | 219 | ||
221 | remaining = count; | 220 | remaining = count; |
222 | do { | 221 | do { |
222 | n = min_t(u64, remaining, dev->bounce_size - offset); | ||
223 | dst = dev->bounce_buf + offset; | ||
224 | |||
223 | mutex_lock(&priv->mutex); | 225 | mutex_lock(&priv->mutex); |
224 | 226 | ||
225 | if (end_read_sector >= start_read_sector) { | 227 | if (n != dev->bounce_size) |
226 | /* Merge head and tail */ | 228 | res = ps3flash_fetch(dev, sector); |
227 | dev_dbg(&dev->sbd.core, | 229 | else if (sector != priv->tag) |
228 | "Merged head and tail: %llu sectors at %llu\n", | 230 | res = ps3flash_writeback(dev); |
229 | chunk_sectors, start_write_sector); | 231 | if (res) |
230 | res = ps3flash_read_sectors(dev, start_write_sector, | 232 | goto fail; |
231 | chunk_sectors, 0); | 233 | |
232 | if (res < 0) | 234 | dev_dbg(&dev->sbd.core, |
235 | "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n", | ||
236 | __func__, __LINE__, n, userbuf, kernelbuf, dst); | ||
237 | if (userbuf) { | ||
238 | if (copy_from_user(dst, userbuf, n)) { | ||
239 | res = -EFAULT; | ||
233 | goto fail; | 240 | goto fail; |
234 | } else { | ||
235 | if (head) { | ||
236 | /* Read head */ | ||
237 | dev_dbg(&dev->sbd.core, | ||
238 | "head: %llu sectors at %llu\n", head, | ||
239 | start_write_sector); | ||
240 | res = ps3flash_read_sectors(dev, | ||
241 | start_write_sector, | ||
242 | head, 0); | ||
243 | if (res < 0) | ||
244 | goto fail; | ||
245 | } | ||
246 | if (start_read_sector < | ||
247 | start_write_sector+chunk_sectors) { | ||
248 | /* Read tail */ | ||
249 | dev_dbg(&dev->sbd.core, | ||
250 | "tail: %llu sectors at %llu\n", tail, | ||
251 | start_read_sector); | ||
252 | sec_off = start_read_sector-start_write_sector; | ||
253 | res = ps3flash_read_sectors(dev, | ||
254 | start_read_sector, | ||
255 | tail, sec_off); | ||
256 | if (res < 0) | ||
257 | goto fail; | ||
258 | } | 241 | } |
242 | userbuf += n; | ||
259 | } | 243 | } |
260 | 244 | if (kernelbuf) { | |
261 | n = min_t(u64, remaining, dev->bounce_size-offset); | 245 | memcpy(dst, kernelbuf, n); |
262 | dev_dbg(&dev->sbd.core, | 246 | kernelbuf += n; |
263 | "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n", | ||
264 | __func__, __LINE__, n, buf, dev->bounce_buf+offset); | ||
265 | if (copy_from_user(dev->bounce_buf+offset, buf, n)) { | ||
266 | res = -EFAULT; | ||
267 | goto fail; | ||
268 | } | 247 | } |
269 | 248 | ||
270 | res = ps3flash_write_chunk(dev, start_write_sector); | 249 | priv->tag = sector; |
271 | if (res < 0) | 250 | priv->dirty = true; |
272 | goto fail; | ||
273 | 251 | ||
274 | mutex_unlock(&priv->mutex); | 252 | mutex_unlock(&priv->mutex); |
275 | 253 | ||
276 | *pos += n; | 254 | *pos += n; |
277 | buf += n; | ||
278 | remaining -= n; | 255 | remaining -= n; |
279 | start_write_sector += chunk_sectors; | 256 | sector += priv->chunk_sectors; |
280 | head = 0; | ||
281 | offset = 0; | 257 | offset = 0; |
282 | } while (remaining > 0); | 258 | } while (remaining > 0); |
283 | 259 | ||
@@ -288,6 +264,51 @@ fail: | |||
288 | return res; | 264 | return res; |
289 | } | 265 | } |
290 | 266 | ||
267 | static ssize_t ps3flash_user_read(struct file *file, char __user *buf, | ||
268 | size_t count, loff_t *pos) | ||
269 | { | ||
270 | return ps3flash_read(buf, NULL, count, pos); | ||
271 | } | ||
272 | |||
273 | static ssize_t ps3flash_user_write(struct file *file, const char __user *buf, | ||
274 | size_t count, loff_t *pos) | ||
275 | { | ||
276 | return ps3flash_write(buf, NULL, count, pos); | ||
277 | } | ||
278 | |||
279 | static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos) | ||
280 | { | ||
281 | return ps3flash_read(NULL, buf, count, &pos); | ||
282 | } | ||
283 | |||
284 | static ssize_t ps3flash_kernel_write(const void *buf, size_t count, | ||
285 | loff_t pos) | ||
286 | { | ||
287 | ssize_t res; | ||
288 | int wb; | ||
289 | |||
290 | res = ps3flash_write(NULL, buf, count, &pos); | ||
291 | if (res < 0) | ||
292 | return res; | ||
293 | |||
294 | /* Make kernel writes synchronous */ | ||
295 | wb = ps3flash_writeback(ps3flash_dev); | ||
296 | if (wb) | ||
297 | return wb; | ||
298 | |||
299 | return res; | ||
300 | } | ||
301 | |||
302 | static int ps3flash_flush(struct file *file, fl_owner_t id) | ||
303 | { | ||
304 | return ps3flash_writeback(ps3flash_dev); | ||
305 | } | ||
306 | |||
307 | static int ps3flash_fsync(struct file *file, struct dentry *dentry, | ||
308 | int datasync) | ||
309 | { | ||
310 | return ps3flash_writeback(ps3flash_dev); | ||
311 | } | ||
291 | 312 | ||
292 | static irqreturn_t ps3flash_interrupt(int irq, void *data) | 313 | static irqreturn_t ps3flash_interrupt(int irq, void *data) |
293 | { | 314 | { |
@@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data) | |||
312 | return IRQ_HANDLED; | 333 | return IRQ_HANDLED; |
313 | } | 334 | } |
314 | 335 | ||
315 | |||
316 | static const struct file_operations ps3flash_fops = { | 336 | static const struct file_operations ps3flash_fops = { |
317 | .owner = THIS_MODULE, | 337 | .owner = THIS_MODULE, |
318 | .llseek = ps3flash_llseek, | 338 | .llseek = ps3flash_llseek, |
319 | .read = ps3flash_read, | 339 | .read = ps3flash_user_read, |
320 | .write = ps3flash_write, | 340 | .write = ps3flash_user_write, |
341 | .flush = ps3flash_flush, | ||
342 | .fsync = ps3flash_fsync, | ||
343 | }; | ||
344 | |||
345 | static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = { | ||
346 | .read = ps3flash_kernel_read, | ||
347 | .write = ps3flash_kernel_write, | ||
321 | }; | 348 | }; |
322 | 349 | ||
323 | static struct miscdevice ps3flash_misc = { | 350 | static struct miscdevice ps3flash_misc = { |
@@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) | |||
366 | goto fail; | 393 | goto fail; |
367 | } | 394 | } |
368 | 395 | ||
369 | dev->sbd.core.driver_data = priv; | 396 | ps3_system_bus_set_drvdata(&dev->sbd, priv); |
370 | mutex_init(&priv->mutex); | 397 | mutex_init(&priv->mutex); |
398 | priv->tag = -1; | ||
371 | 399 | ||
372 | dev->bounce_size = ps3flash_bounce_buffer.size; | 400 | dev->bounce_size = ps3flash_bounce_buffer.size; |
373 | dev->bounce_buf = ps3flash_bounce_buffer.address; | 401 | dev->bounce_buf = ps3flash_bounce_buffer.address; |
402 | priv->chunk_sectors = dev->bounce_size / dev->blk_size; | ||
374 | 403 | ||
375 | error = ps3stor_setup(dev, ps3flash_interrupt); | 404 | error = ps3stor_setup(dev, ps3flash_interrupt); |
376 | if (error) | 405 | if (error) |
@@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev) | |||
386 | 415 | ||
387 | dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", | 416 | dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n", |
388 | __func__, __LINE__, ps3flash_misc.minor); | 417 | __func__, __LINE__, ps3flash_misc.minor); |
418 | |||
419 | ps3_os_area_flash_register(&ps3flash_kernel_ops); | ||
389 | return 0; | 420 | return 0; |
390 | 421 | ||
391 | fail_teardown: | 422 | fail_teardown: |
392 | ps3stor_teardown(dev); | 423 | ps3stor_teardown(dev); |
393 | fail_free_priv: | 424 | fail_free_priv: |
394 | kfree(priv); | 425 | kfree(priv); |
395 | dev->sbd.core.driver_data = NULL; | 426 | ps3_system_bus_set_drvdata(&dev->sbd, NULL); |
396 | fail: | 427 | fail: |
397 | ps3flash_dev = NULL; | 428 | ps3flash_dev = NULL; |
398 | return error; | 429 | return error; |
@@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev) | |||
402 | { | 433 | { |
403 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); | 434 | struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core); |
404 | 435 | ||
436 | ps3_os_area_flash_register(NULL); | ||
405 | misc_deregister(&ps3flash_misc); | 437 | misc_deregister(&ps3flash_misc); |
406 | ps3stor_teardown(dev); | 438 | ps3stor_teardown(dev); |
407 | kfree(dev->sbd.core.driver_data); | 439 | kfree(ps3_system_bus_get_drvdata(&dev->sbd)); |
408 | dev->sbd.core.driver_data = NULL; | 440 | ps3_system_bus_set_drvdata(&dev->sbd, NULL); |
409 | ps3flash_dev = NULL; | 441 | ps3flash_dev = NULL; |
410 | return 0; | 442 | return 0; |
411 | } | 443 | } |
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d73f5f473e38..f8090e137fef 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -306,11 +306,11 @@ config SENSORS_F71805F | |||
306 | will be called f71805f. | 306 | will be called f71805f. |
307 | 307 | ||
308 | config SENSORS_F71882FG | 308 | config SENSORS_F71882FG |
309 | tristate "Fintek F71862FG, F71882FG and F8000" | 309 | tristate "Fintek F71858FG, F71862FG, F71882FG and F8000" |
310 | depends on EXPERIMENTAL | 310 | depends on EXPERIMENTAL |
311 | help | 311 | help |
312 | If you say yes here you get support for hardware monitoring | 312 | If you say yes here you get support for hardware monitoring |
313 | features of the Fintek F71882FG/F71883FG, F71862FG/71863FG | 313 | features of the Fintek F71858FG, F71862FG/71863FG, F71882FG/F71883FG |
314 | and F8000 Super-I/O chips. | 314 | and F8000 Super-I/O chips. |
315 | 315 | ||
316 | This driver can also be built as a module. If so, the module | 316 | This driver can also be built as a module. If so, the module |
@@ -418,7 +418,7 @@ config SENSORS_IBMAEM | |||
418 | power sensors and capping hardware in various IBM System X | 418 | power sensors and capping hardware in various IBM System X |
419 | servers that support Active Energy Manager. This includes | 419 | servers that support Active Energy Manager. This includes |
420 | the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, | 420 | the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, |
421 | and certain HS2x/LS2x/QS2x blades. | 421 | and certain HC10/HS2x/LS2x/QS2x blades. |
422 | 422 | ||
423 | This driver can also be built as a module. If so, the module | 423 | This driver can also be built as a module. If so, the module |
424 | will be called ibmaem. | 424 | will be called ibmaem. |
@@ -787,6 +787,16 @@ config SENSORS_THMC50 | |||
787 | This driver can also be built as a module. If so, the module | 787 | This driver can also be built as a module. If so, the module |
788 | will be called thmc50. | 788 | will be called thmc50. |
789 | 789 | ||
790 | config SENSORS_TMP401 | ||
791 | tristate "Texas Instruments TMP401 and compatibles" | ||
792 | depends on I2C && EXPERIMENTAL | ||
793 | help | ||
794 | If you say yes here you get support for Texas Instruments TMP401 and | ||
795 | TMP411 temperature sensor chips. | ||
796 | |||
797 | This driver can also be built as a module. If so, the module | ||
798 | will be called tmp401. | ||
799 | |||
790 | config SENSORS_VIA686A | 800 | config SENSORS_VIA686A |
791 | tristate "VIA686A" | 801 | tristate "VIA686A" |
792 | depends on PCI | 802 | depends on PCI |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 0ae26984ba45..b793dce6bed5 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -82,6 +82,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o | |||
82 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o | 82 | obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o |
83 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o | 83 | obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o |
84 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o | 84 | obj-$(CONFIG_SENSORS_THMC50) += thmc50.o |
85 | obj-$(CONFIG_SENSORS_TMP401) += tmp401.o | ||
85 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o | 86 | obj-$(CONFIG_SENSORS_VIA686A) += via686a.o |
86 | obj-$(CONFIG_SENSORS_VT1211) += vt1211.o | 87 | obj-$(CONFIG_SENSORS_VT1211) += vt1211.o |
87 | obj-$(CONFIG_SENSORS_VT8231) += vt8231.o | 88 | obj-$(CONFIG_SENSORS_VT8231) += vt8231.o |
diff --git a/drivers/hwmon/f71882fg.c b/drivers/hwmon/f71882fg.c index 5f81ddf71508..4146105f1a57 100644 --- a/drivers/hwmon/f71882fg.c +++ b/drivers/hwmon/f71882fg.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /*************************************************************************** | 1 | /*************************************************************************** |
2 | * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * | 2 | * Copyright (C) 2006 by Hans Edgington <hans@edgington.nl> * |
3 | * Copyright (C) 2007,2008 by Hans de Goede <hdegoede@redhat.com> * | 3 | * Copyright (C) 2007-2009 Hans de Goede <hdegoede@redhat.com> * |
4 | * * | 4 | * * |
5 | * This program is free software; you can redistribute it and/or modify * | 5 | * This program is free software; you can redistribute it and/or modify * |
6 | * it under the terms of the GNU General Public License as published by * | 6 | * it under the terms of the GNU General Public License as published by * |
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | #define DRVNAME "f71882fg" | 33 | #define DRVNAME "f71882fg" |
34 | 34 | ||
35 | #define SIO_F71858FG_LD_HWM 0x02 /* Hardware monitor logical device */ | ||
35 | #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */ | 36 | #define SIO_F71882FG_LD_HWM 0x04 /* Hardware monitor logical device */ |
36 | #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ | 37 | #define SIO_UNLOCK_KEY 0x87 /* Key to enable Super-I/O */ |
37 | #define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ | 38 | #define SIO_LOCK_KEY 0xAA /* Key to diasble Super-I/O */ |
@@ -44,6 +45,7 @@ | |||
44 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ | 45 | #define SIO_REG_ADDR 0x60 /* Logical device address (2 bytes) */ |
45 | 46 | ||
46 | #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ | 47 | #define SIO_FINTEK_ID 0x1934 /* Manufacturers ID */ |
48 | #define SIO_F71858_ID 0x0507 /* Chipset ID */ | ||
47 | #define SIO_F71862_ID 0x0601 /* Chipset ID */ | 49 | #define SIO_F71862_ID 0x0601 /* Chipset ID */ |
48 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ | 50 | #define SIO_F71882_ID 0x0541 /* Chipset ID */ |
49 | #define SIO_F8000_ID 0x0581 /* Chipset ID */ | 51 | #define SIO_F8000_ID 0x0581 /* Chipset ID */ |
@@ -70,6 +72,7 @@ | |||
70 | #define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr)) | 72 | #define F71882FG_REG_TEMP_HIGH(nr) (0x81 + 2 * (nr)) |
71 | #define F71882FG_REG_TEMP_STATUS 0x62 | 73 | #define F71882FG_REG_TEMP_STATUS 0x62 |
72 | #define F71882FG_REG_TEMP_BEEP 0x63 | 74 | #define F71882FG_REG_TEMP_BEEP 0x63 |
75 | #define F71882FG_REG_TEMP_CONFIG 0x69 | ||
73 | #define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr)) | 76 | #define F71882FG_REG_TEMP_HYST(nr) (0x6C + (nr)) |
74 | #define F71882FG_REG_TEMP_TYPE 0x6B | 77 | #define F71882FG_REG_TEMP_TYPE 0x6B |
75 | #define F71882FG_REG_TEMP_DIODE_OPEN 0x6F | 78 | #define F71882FG_REG_TEMP_DIODE_OPEN 0x6F |
@@ -92,9 +95,10 @@ static unsigned short force_id; | |||
92 | module_param(force_id, ushort, 0); | 95 | module_param(force_id, ushort, 0); |
93 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); | 96 | MODULE_PARM_DESC(force_id, "Override the detected device ID"); |
94 | 97 | ||
95 | enum chips { f71862fg, f71882fg, f8000 }; | 98 | enum chips { f71858fg, f71862fg, f71882fg, f8000 }; |
96 | 99 | ||
97 | static const char *f71882fg_names[] = { | 100 | static const char *f71882fg_names[] = { |
101 | "f71858fg", | ||
98 | "f71862fg", | 102 | "f71862fg", |
99 | "f71882fg", | 103 | "f71882fg", |
100 | "f8000", | 104 | "f8000", |
@@ -119,6 +123,7 @@ struct f71882fg_data { | |||
119 | struct device *hwmon_dev; | 123 | struct device *hwmon_dev; |
120 | 124 | ||
121 | struct mutex update_lock; | 125 | struct mutex update_lock; |
126 | int temp_start; /* temp numbering start (0 or 1) */ | ||
122 | char valid; /* !=0 if following fields are valid */ | 127 | char valid; /* !=0 if following fields are valid */ |
123 | unsigned long last_updated; /* In jiffies */ | 128 | unsigned long last_updated; /* In jiffies */ |
124 | unsigned long last_limits; /* In jiffies */ | 129 | unsigned long last_limits; /* In jiffies */ |
@@ -136,7 +141,7 @@ struct f71882fg_data { | |||
136 | /* Note: all models have only 3 temperature channels, but on some | 141 | /* Note: all models have only 3 temperature channels, but on some |
137 | they are addressed as 0-2 and on others as 1-3, so for coding | 142 | they are addressed as 0-2 and on others as 1-3, so for coding |
138 | convenience we reserve space for 4 channels */ | 143 | convenience we reserve space for 4 channels */ |
139 | u8 temp[4]; | 144 | u16 temp[4]; |
140 | u8 temp_ovt[4]; | 145 | u8 temp_ovt[4]; |
141 | u8 temp_high[4]; | 146 | u8 temp_high[4]; |
142 | u8 temp_hyst[2]; /* 2 hysts stored per reg */ | 147 | u8 temp_hyst[2]; /* 2 hysts stored per reg */ |
@@ -144,6 +149,7 @@ struct f71882fg_data { | |||
144 | u8 temp_status; | 149 | u8 temp_status; |
145 | u8 temp_beep; | 150 | u8 temp_beep; |
146 | u8 temp_diode_open; | 151 | u8 temp_diode_open; |
152 | u8 temp_config; | ||
147 | u8 pwm[4]; | 153 | u8 pwm[4]; |
148 | u8 pwm_enable; | 154 | u8 pwm_enable; |
149 | u8 pwm_auto_point_hyst[2]; | 155 | u8 pwm_auto_point_hyst[2]; |
@@ -247,11 +253,55 @@ static struct platform_driver f71882fg_driver = { | |||
247 | .name = DRVNAME, | 253 | .name = DRVNAME, |
248 | }, | 254 | }, |
249 | .probe = f71882fg_probe, | 255 | .probe = f71882fg_probe, |
250 | .remove = __devexit_p(f71882fg_remove), | 256 | .remove = f71882fg_remove, |
251 | }; | 257 | }; |
252 | 258 | ||
253 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 259 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
254 | 260 | ||
261 | /* Temp and in attr for the f71858fg */ | ||
262 | static struct sensor_device_attribute_2 f71858fg_in_temp_attr[] = { | ||
263 | SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), | ||
264 | SENSOR_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 0, 1), | ||
265 | SENSOR_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 0, 2), | ||
266 | SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0), | ||
267 | SENSOR_ATTR_2(temp1_max, S_IRUGO|S_IWUSR, show_temp_max, | ||
268 | store_temp_max, 0, 0), | ||
269 | SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, | ||
270 | store_temp_max_hyst, 0, 0), | ||
271 | SENSOR_ATTR_2(temp1_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 0), | ||
272 | SENSOR_ATTR_2(temp1_crit, S_IRUGO|S_IWUSR, show_temp_crit, | ||
273 | store_temp_crit, 0, 0), | ||
274 | SENSOR_ATTR_2(temp1_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, | ||
275 | 0, 0), | ||
276 | SENSOR_ATTR_2(temp1_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), | ||
277 | SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), | ||
278 | SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), | ||
279 | SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_max, | ||
280 | store_temp_max, 0, 1), | ||
281 | SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, | ||
282 | store_temp_max_hyst, 0, 1), | ||
283 | SENSOR_ATTR_2(temp2_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 1), | ||
284 | SENSOR_ATTR_2(temp2_crit, S_IRUGO|S_IWUSR, show_temp_crit, | ||
285 | store_temp_crit, 0, 1), | ||
286 | SENSOR_ATTR_2(temp2_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, | ||
287 | 0, 1), | ||
288 | SENSOR_ATTR_2(temp2_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), | ||
289 | SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), | ||
290 | SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), | ||
291 | SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), | ||
292 | SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_max, | ||
293 | store_temp_max, 0, 2), | ||
294 | SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max_hyst, | ||
295 | store_temp_max_hyst, 0, 2), | ||
296 | SENSOR_ATTR_2(temp3_max_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 2), | ||
297 | SENSOR_ATTR_2(temp3_crit, S_IRUGO|S_IWUSR, show_temp_crit, | ||
298 | store_temp_crit, 0, 2), | ||
299 | SENSOR_ATTR_2(temp3_crit_hyst, S_IRUGO, show_temp_crit_hyst, NULL, | ||
300 | 0, 2), | ||
301 | SENSOR_ATTR_2(temp3_crit_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), | ||
302 | SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), | ||
303 | }; | ||
304 | |||
255 | /* Temp and in attr common to both the f71862fg and f71882fg */ | 305 | /* Temp and in attr common to both the f71862fg and f71882fg */ |
256 | static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { | 306 | static struct sensor_device_attribute_2 f718x2fg_in_temp_attr[] = { |
257 | SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), | 307 | SENSOR_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0), |
@@ -344,6 +394,7 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { | |||
344 | SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, | 394 | SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, |
345 | store_temp_max, 0, 0), | 395 | store_temp_max, 0, 0), |
346 | SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), | 396 | SENSOR_ATTR_2(temp1_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 4), |
397 | SENSOR_ATTR_2(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0, 0), | ||
347 | SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), | 398 | SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1), |
348 | SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit, | 399 | SENSOR_ATTR_2(temp2_max, S_IRUGO|S_IWUSR, show_temp_crit, |
349 | store_temp_crit, 0, 1), | 400 | store_temp_crit, 0, 1), |
@@ -351,12 +402,14 @@ static struct sensor_device_attribute_2 f8000_in_temp_attr[] = { | |||
351 | store_temp_max, 0, 1), | 402 | store_temp_max, 0, 1), |
352 | SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), | 403 | SENSOR_ATTR_2(temp2_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 5), |
353 | SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), | 404 | SENSOR_ATTR_2(temp2_type, S_IRUGO, show_temp_type, NULL, 0, 1), |
405 | SENSOR_ATTR_2(temp2_fault, S_IRUGO, show_temp_fault, NULL, 0, 1), | ||
354 | SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), | 406 | SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0, 2), |
355 | SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit, | 407 | SENSOR_ATTR_2(temp3_max, S_IRUGO|S_IWUSR, show_temp_crit, |
356 | store_temp_crit, 0, 2), | 408 | store_temp_crit, 0, 2), |
357 | SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, | 409 | SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO|S_IWUSR, show_temp_max, |
358 | store_temp_max, 0, 2), | 410 | store_temp_max, 0, 2), |
359 | SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), | 411 | SENSOR_ATTR_2(temp3_alarm, S_IRUGO, show_temp_alarm, NULL, 0, 6), |
412 | SENSOR_ATTR_2(temp3_fault, S_IRUGO, show_temp_fault, NULL, 0, 2), | ||
360 | }; | 413 | }; |
361 | 414 | ||
362 | /* Fan / PWM attr common to all models */ | 415 | /* Fan / PWM attr common to all models */ |
@@ -395,6 +448,9 @@ static struct sensor_device_attribute_2 fxxxx_fan_attr[] = { | |||
395 | show_pwm_auto_point_channel, | 448 | show_pwm_auto_point_channel, |
396 | store_pwm_auto_point_channel, 0, 1), | 449 | store_pwm_auto_point_channel, 0, 1), |
397 | 450 | ||
451 | SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), | ||
452 | SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | ||
453 | store_pwm_enable, 0, 2), | ||
398 | SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR, | 454 | SENSOR_ATTR_2(pwm3_interpolate, S_IRUGO|S_IWUSR, |
399 | show_pwm_interpolate, store_pwm_interpolate, 0, 2), | 455 | show_pwm_interpolate, store_pwm_interpolate, 0, 2), |
400 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, | 456 | SENSOR_ATTR_2(pwm3_auto_channels_temp, S_IRUGO|S_IWUSR, |
@@ -450,9 +506,6 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { | |||
450 | SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, | 506 | SENSOR_ATTR_2(pwm2_auto_point2_temp_hyst, S_IRUGO, |
451 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), | 507 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), |
452 | 508 | ||
453 | SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), | ||
454 | SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | ||
455 | store_pwm_enable, 0, 2), | ||
456 | SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, | 509 | SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, |
457 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, | 510 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, |
458 | 1, 2), | 511 | 1, 2), |
@@ -473,22 +526,8 @@ static struct sensor_device_attribute_2 f71862fg_fan_attr[] = { | |||
473 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), | 526 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), |
474 | }; | 527 | }; |
475 | 528 | ||
476 | /* Fan / PWM attr for the f71882fg */ | 529 | /* Fan / PWM attr common to both the f71882fg and f71858fg */ |
477 | static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { | 530 | static struct sensor_device_attribute_2 f71882fg_f71858fg_fan_attr[] = { |
478 | SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
479 | store_fan_beep, 0, 0), | ||
480 | SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
481 | store_fan_beep, 0, 1), | ||
482 | SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
483 | store_fan_beep, 0, 2), | ||
484 | SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), | ||
485 | SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, | ||
486 | show_fan_full_speed, | ||
487 | store_fan_full_speed, 0, 3), | ||
488 | SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
489 | store_fan_beep, 0, 3), | ||
490 | SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), | ||
491 | |||
492 | SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, | 531 | SENSOR_ATTR_2(pwm1_auto_point1_pwm, S_IRUGO|S_IWUSR, |
493 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, | 532 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, |
494 | 0, 0), | 533 | 0, 0), |
@@ -565,9 +604,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { | |||
565 | SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO, | 604 | SENSOR_ATTR_2(pwm2_auto_point4_temp_hyst, S_IRUGO, |
566 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), | 605 | show_pwm_auto_point_temp_hyst, NULL, 3, 1), |
567 | 606 | ||
568 | SENSOR_ATTR_2(pwm3, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 2), | ||
569 | SENSOR_ATTR_2(pwm3_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | ||
570 | store_pwm_enable, 0, 2), | ||
571 | SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, | 607 | SENSOR_ATTR_2(pwm3_auto_point1_pwm, S_IRUGO|S_IWUSR, |
572 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, | 608 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, |
573 | 0, 2), | 609 | 0, 2), |
@@ -605,6 +641,24 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { | |||
605 | show_pwm_auto_point_temp_hyst, NULL, 2, 2), | 641 | show_pwm_auto_point_temp_hyst, NULL, 2, 2), |
606 | SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO, | 642 | SENSOR_ATTR_2(pwm3_auto_point4_temp_hyst, S_IRUGO, |
607 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), | 643 | show_pwm_auto_point_temp_hyst, NULL, 3, 2), |
644 | }; | ||
645 | |||
646 | /* Fan / PWM attr found on the f71882fg but not on the f71858fg */ | ||
647 | static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { | ||
648 | SENSOR_ATTR_2(fan1_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
649 | store_fan_beep, 0, 0), | ||
650 | SENSOR_ATTR_2(fan2_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
651 | store_fan_beep, 0, 1), | ||
652 | SENSOR_ATTR_2(fan3_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
653 | store_fan_beep, 0, 2), | ||
654 | |||
655 | SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), | ||
656 | SENSOR_ATTR_2(fan4_full_speed, S_IRUGO|S_IWUSR, | ||
657 | show_fan_full_speed, | ||
658 | store_fan_full_speed, 0, 3), | ||
659 | SENSOR_ATTR_2(fan4_beep, S_IRUGO|S_IWUSR, show_fan_beep, | ||
660 | store_fan_beep, 0, 3), | ||
661 | SENSOR_ATTR_2(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 0, 3), | ||
608 | 662 | ||
609 | SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3), | 663 | SENSOR_ATTR_2(pwm4, S_IRUGO|S_IWUSR, show_pwm, store_pwm, 0, 3), |
610 | SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable, | 664 | SENSOR_ATTR_2(pwm4_enable, S_IRUGO|S_IWUSR, show_pwm_enable, |
@@ -659,8 +713,6 @@ static struct sensor_device_attribute_2 f71882fg_fan_attr[] = { | |||
659 | static struct sensor_device_attribute_2 f8000_fan_attr[] = { | 713 | static struct sensor_device_attribute_2 f8000_fan_attr[] = { |
660 | SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), | 714 | SENSOR_ATTR_2(fan4_input, S_IRUGO, show_fan, NULL, 0, 3), |
661 | 715 | ||
662 | SENSOR_ATTR_2(pwm3, S_IRUGO, show_pwm, NULL, 0, 2), | ||
663 | |||
664 | SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR, | 716 | SENSOR_ATTR_2(temp1_auto_point1_pwm, S_IRUGO|S_IWUSR, |
665 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, | 717 | show_pwm_auto_point_pwm, store_pwm_auto_point_pwm, |
666 | 0, 2), | 718 | 0, 2), |
@@ -857,13 +909,20 @@ static void f71882fg_write16(struct f71882fg_data *data, u8 reg, u16 val) | |||
857 | outb(val & 255, data->addr + DATA_REG_OFFSET); | 909 | outb(val & 255, data->addr + DATA_REG_OFFSET); |
858 | } | 910 | } |
859 | 911 | ||
912 | static u16 f71882fg_read_temp(struct f71882fg_data *data, int nr) | ||
913 | { | ||
914 | if (data->type == f71858fg) | ||
915 | return f71882fg_read16(data, F71882FG_REG_TEMP(nr)); | ||
916 | else | ||
917 | return f71882fg_read8(data, F71882FG_REG_TEMP(nr)); | ||
918 | } | ||
919 | |||
860 | static struct f71882fg_data *f71882fg_update_device(struct device *dev) | 920 | static struct f71882fg_data *f71882fg_update_device(struct device *dev) |
861 | { | 921 | { |
862 | struct f71882fg_data *data = dev_get_drvdata(dev); | 922 | struct f71882fg_data *data = dev_get_drvdata(dev); |
863 | int nr, reg = 0, reg2; | 923 | int nr, reg = 0, reg2; |
864 | int nr_fans = (data->type == f71882fg) ? 4 : 3; | 924 | int nr_fans = (data->type == f71882fg) ? 4 : 3; |
865 | int nr_ins = (data->type == f8000) ? 3 : 9; | 925 | int nr_ins = (data->type == f71858fg || data->type == f8000) ? 3 : 9; |
866 | int temp_start = (data->type == f8000) ? 0 : 1; | ||
867 | 926 | ||
868 | mutex_lock(&data->update_lock); | 927 | mutex_lock(&data->update_lock); |
869 | 928 | ||
@@ -878,7 +937,7 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) | |||
878 | } | 937 | } |
879 | 938 | ||
880 | /* Get High & boundary temps*/ | 939 | /* Get High & boundary temps*/ |
881 | for (nr = temp_start; nr < 3 + temp_start; nr++) { | 940 | for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) { |
882 | data->temp_ovt[nr] = f71882fg_read8(data, | 941 | data->temp_ovt[nr] = f71882fg_read8(data, |
883 | F71882FG_REG_TEMP_OVT(nr)); | 942 | F71882FG_REG_TEMP_OVT(nr)); |
884 | data->temp_high[nr] = f71882fg_read8(data, | 943 | data->temp_high[nr] = f71882fg_read8(data, |
@@ -886,14 +945,17 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) | |||
886 | } | 945 | } |
887 | 946 | ||
888 | if (data->type != f8000) { | 947 | if (data->type != f8000) { |
889 | data->fan_beep = f71882fg_read8(data, | ||
890 | F71882FG_REG_FAN_BEEP); | ||
891 | data->temp_beep = f71882fg_read8(data, | ||
892 | F71882FG_REG_TEMP_BEEP); | ||
893 | data->temp_hyst[0] = f71882fg_read8(data, | 948 | data->temp_hyst[0] = f71882fg_read8(data, |
894 | F71882FG_REG_TEMP_HYST(0)); | 949 | F71882FG_REG_TEMP_HYST(0)); |
895 | data->temp_hyst[1] = f71882fg_read8(data, | 950 | data->temp_hyst[1] = f71882fg_read8(data, |
896 | F71882FG_REG_TEMP_HYST(1)); | 951 | F71882FG_REG_TEMP_HYST(1)); |
952 | } | ||
953 | |||
954 | if (data->type == f71862fg || data->type == f71882fg) { | ||
955 | data->fan_beep = f71882fg_read8(data, | ||
956 | F71882FG_REG_FAN_BEEP); | ||
957 | data->temp_beep = f71882fg_read8(data, | ||
958 | F71882FG_REG_TEMP_BEEP); | ||
897 | /* Have to hardcode type, because temp1 is special */ | 959 | /* Have to hardcode type, because temp1 is special */ |
898 | reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); | 960 | reg = f71882fg_read8(data, F71882FG_REG_TEMP_TYPE); |
899 | data->temp_type[2] = (reg & 0x04) ? 2 : 4; | 961 | data->temp_type[2] = (reg & 0x04) ? 2 : 4; |
@@ -904,10 +966,10 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) | |||
904 | data->temp_type[1] = 6 /* PECI */; | 966 | data->temp_type[1] = 6 /* PECI */; |
905 | else if ((reg2 & 0x03) == 0x02) | 967 | else if ((reg2 & 0x03) == 0x02) |
906 | data->temp_type[1] = 5 /* AMDSI */; | 968 | data->temp_type[1] = 5 /* AMDSI */; |
907 | else if (data->type != f8000) | 969 | else if (data->type == f71862fg || data->type == f71882fg) |
908 | data->temp_type[1] = (reg & 0x02) ? 2 : 4; | 970 | data->temp_type[1] = (reg & 0x02) ? 2 : 4; |
909 | else | 971 | else |
910 | data->temp_type[1] = 2; /* F8000 only supports BJT */ | 972 | data->temp_type[1] = 2; /* Only supports BJT */ |
911 | 973 | ||
912 | data->pwm_enable = f71882fg_read8(data, | 974 | data->pwm_enable = f71882fg_read8(data, |
913 | F71882FG_REG_PWM_ENABLE); | 975 | F71882FG_REG_PWM_ENABLE); |
@@ -963,9 +1025,8 @@ static struct f71882fg_data *f71882fg_update_device(struct device *dev) | |||
963 | F71882FG_REG_TEMP_STATUS); | 1025 | F71882FG_REG_TEMP_STATUS); |
964 | data->temp_diode_open = f71882fg_read8(data, | 1026 | data->temp_diode_open = f71882fg_read8(data, |
965 | F71882FG_REG_TEMP_DIODE_OPEN); | 1027 | F71882FG_REG_TEMP_DIODE_OPEN); |
966 | for (nr = temp_start; nr < 3 + temp_start; nr++) | 1028 | for (nr = data->temp_start; nr < 3 + data->temp_start; nr++) |
967 | data->temp[nr] = f71882fg_read8(data, | 1029 | data->temp[nr] = f71882fg_read_temp(data, nr); |
968 | F71882FG_REG_TEMP(nr)); | ||
969 | 1030 | ||
970 | data->fan_status = f71882fg_read8(data, | 1031 | data->fan_status = f71882fg_read8(data, |
971 | F71882FG_REG_FAN_STATUS); | 1032 | F71882FG_REG_FAN_STATUS); |
@@ -1168,8 +1229,24 @@ static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, | |||
1168 | { | 1229 | { |
1169 | struct f71882fg_data *data = f71882fg_update_device(dev); | 1230 | struct f71882fg_data *data = f71882fg_update_device(dev); |
1170 | int nr = to_sensor_dev_attr_2(devattr)->index; | 1231 | int nr = to_sensor_dev_attr_2(devattr)->index; |
1232 | int sign, temp; | ||
1233 | |||
1234 | if (data->type == f71858fg) { | ||
1235 | /* TEMP_TABLE_SEL 1 or 3 ? */ | ||
1236 | if (data->temp_config & 1) { | ||
1237 | sign = data->temp[nr] & 0x0001; | ||
1238 | temp = (data->temp[nr] >> 5) & 0x7ff; | ||
1239 | } else { | ||
1240 | sign = data->temp[nr] & 0x8000; | ||
1241 | temp = (data->temp[nr] >> 5) & 0x3ff; | ||
1242 | } | ||
1243 | temp *= 125; | ||
1244 | if (sign) | ||
1245 | temp -= 128000; | ||
1246 | } else | ||
1247 | temp = data->temp[nr] * 1000; | ||
1171 | 1248 | ||
1172 | return sprintf(buf, "%d\n", data->temp[nr] * 1000); | 1249 | return sprintf(buf, "%d\n", temp); |
1173 | } | 1250 | } |
1174 | 1251 | ||
1175 | static ssize_t show_temp_max(struct device *dev, struct device_attribute | 1252 | static ssize_t show_temp_max(struct device *dev, struct device_attribute |
@@ -1440,6 +1517,10 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute | |||
1440 | int nr = to_sensor_dev_attr_2(devattr)->index; | 1517 | int nr = to_sensor_dev_attr_2(devattr)->index; |
1441 | long val = simple_strtol(buf, NULL, 10); | 1518 | long val = simple_strtol(buf, NULL, 10); |
1442 | 1519 | ||
1520 | /* Special case for F8000 pwm channel 3 which only does auto mode */ | ||
1521 | if (data->type == f8000 && nr == 2 && val != 2) | ||
1522 | return -EINVAL; | ||
1523 | |||
1443 | mutex_lock(&data->update_lock); | 1524 | mutex_lock(&data->update_lock); |
1444 | data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); | 1525 | data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); |
1445 | /* Special case for F8000 auto PWM mode / Thermostat mode */ | 1526 | /* Special case for F8000 auto PWM mode / Thermostat mode */ |
@@ -1458,6 +1539,12 @@ static ssize_t store_pwm_enable(struct device *dev, struct device_attribute | |||
1458 | } else { | 1539 | } else { |
1459 | switch (val) { | 1540 | switch (val) { |
1460 | case 1: | 1541 | case 1: |
1542 | /* The f71858fg does not support manual RPM mode */ | ||
1543 | if (data->type == f71858fg && | ||
1544 | ((data->pwm_enable >> (2 * nr)) & 1)) { | ||
1545 | count = -EINVAL; | ||
1546 | goto leave; | ||
1547 | } | ||
1461 | data->pwm_enable |= 2 << (2 * nr); | 1548 | data->pwm_enable |= 2 << (2 * nr); |
1462 | break; /* Manual */ | 1549 | break; /* Manual */ |
1463 | case 2: | 1550 | case 2: |
@@ -1616,9 +1703,9 @@ static ssize_t show_pwm_auto_point_channel(struct device *dev, | |||
1616 | int result; | 1703 | int result; |
1617 | struct f71882fg_data *data = f71882fg_update_device(dev); | 1704 | struct f71882fg_data *data = f71882fg_update_device(dev); |
1618 | int nr = to_sensor_dev_attr_2(devattr)->index; | 1705 | int nr = to_sensor_dev_attr_2(devattr)->index; |
1619 | int temp_start = (data->type == f8000) ? 0 : 1; | ||
1620 | 1706 | ||
1621 | result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - temp_start); | 1707 | result = 1 << ((data->pwm_auto_point_mapping[nr] & 3) - |
1708 | data->temp_start); | ||
1622 | 1709 | ||
1623 | return sprintf(buf, "%d\n", result); | 1710 | return sprintf(buf, "%d\n", result); |
1624 | } | 1711 | } |
@@ -1629,7 +1716,6 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, | |||
1629 | { | 1716 | { |
1630 | struct f71882fg_data *data = dev_get_drvdata(dev); | 1717 | struct f71882fg_data *data = dev_get_drvdata(dev); |
1631 | int nr = to_sensor_dev_attr_2(devattr)->index; | 1718 | int nr = to_sensor_dev_attr_2(devattr)->index; |
1632 | int temp_start = (data->type == f8000) ? 0 : 1; | ||
1633 | long val = simple_strtol(buf, NULL, 10); | 1719 | long val = simple_strtol(buf, NULL, 10); |
1634 | 1720 | ||
1635 | switch (val) { | 1721 | switch (val) { |
@@ -1645,7 +1731,7 @@ static ssize_t store_pwm_auto_point_channel(struct device *dev, | |||
1645 | default: | 1731 | default: |
1646 | return -EINVAL; | 1732 | return -EINVAL; |
1647 | } | 1733 | } |
1648 | val += temp_start; | 1734 | val += data->temp_start; |
1649 | mutex_lock(&data->update_lock); | 1735 | mutex_lock(&data->update_lock); |
1650 | data->pwm_auto_point_mapping[nr] = | 1736 | data->pwm_auto_point_mapping[nr] = |
1651 | f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); | 1737 | f71882fg_read8(data, F71882FG_REG_POINT_MAPPING(nr)); |
@@ -1721,6 +1807,8 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
1721 | 1807 | ||
1722 | data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; | 1808 | data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; |
1723 | data->type = sio_data->type; | 1809 | data->type = sio_data->type; |
1810 | data->temp_start = | ||
1811 | (data->type == f71858fg || data->type == f8000) ? 0 : 1; | ||
1724 | mutex_init(&data->update_lock); | 1812 | mutex_init(&data->update_lock); |
1725 | platform_set_drvdata(pdev, data); | 1813 | platform_set_drvdata(pdev, data); |
1726 | 1814 | ||
@@ -1736,19 +1824,6 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
1736 | goto exit_free; | 1824 | goto exit_free; |
1737 | } | 1825 | } |
1738 | 1826 | ||
1739 | data->pwm_enable = f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); | ||
1740 | /* If it is a 71862 and the fan / pwm part is enabled sanity check | ||
1741 | the pwm settings */ | ||
1742 | if (data->type == f71862fg && (start_reg & 0x02)) { | ||
1743 | if ((data->pwm_enable & 0x15) != 0x15) { | ||
1744 | dev_err(&pdev->dev, | ||
1745 | "Invalid (reserved) pwm settings: 0x%02x\n", | ||
1746 | (unsigned int)data->pwm_enable); | ||
1747 | err = -ENODEV; | ||
1748 | goto exit_free; | ||
1749 | } | ||
1750 | } | ||
1751 | |||
1752 | /* Register sysfs interface files */ | 1827 | /* Register sysfs interface files */ |
1753 | err = device_create_file(&pdev->dev, &dev_attr_name); | 1828 | err = device_create_file(&pdev->dev, &dev_attr_name); |
1754 | if (err) | 1829 | if (err) |
@@ -1756,6 +1831,20 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
1756 | 1831 | ||
1757 | if (start_reg & 0x01) { | 1832 | if (start_reg & 0x01) { |
1758 | switch (data->type) { | 1833 | switch (data->type) { |
1834 | case f71858fg: | ||
1835 | data->temp_config = | ||
1836 | f71882fg_read8(data, F71882FG_REG_TEMP_CONFIG); | ||
1837 | if (data->temp_config & 0x10) | ||
1838 | /* The f71858fg temperature alarms behave as | ||
1839 | the f8000 alarms in this mode */ | ||
1840 | err = f71882fg_create_sysfs_files(pdev, | ||
1841 | f8000_in_temp_attr, | ||
1842 | ARRAY_SIZE(f8000_in_temp_attr)); | ||
1843 | else | ||
1844 | err = f71882fg_create_sysfs_files(pdev, | ||
1845 | f71858fg_in_temp_attr, | ||
1846 | ARRAY_SIZE(f71858fg_in_temp_attr)); | ||
1847 | break; | ||
1759 | case f71882fg: | 1848 | case f71882fg: |
1760 | err = f71882fg_create_sysfs_files(pdev, | 1849 | err = f71882fg_create_sysfs_files(pdev, |
1761 | f71882fg_in_temp_attr, | 1850 | f71882fg_in_temp_attr, |
@@ -1779,6 +1868,35 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
1779 | } | 1868 | } |
1780 | 1869 | ||
1781 | if (start_reg & 0x02) { | 1870 | if (start_reg & 0x02) { |
1871 | data->pwm_enable = | ||
1872 | f71882fg_read8(data, F71882FG_REG_PWM_ENABLE); | ||
1873 | |||
1874 | /* Sanity check the pwm settings */ | ||
1875 | switch (data->type) { | ||
1876 | case f71858fg: | ||
1877 | err = 0; | ||
1878 | for (i = 0; i < nr_fans; i++) | ||
1879 | if (((data->pwm_enable >> (i * 2)) & 3) == 3) | ||
1880 | err = 1; | ||
1881 | break; | ||
1882 | case f71862fg: | ||
1883 | err = (data->pwm_enable & 0x15) != 0x15; | ||
1884 | break; | ||
1885 | case f71882fg: | ||
1886 | err = 0; | ||
1887 | break; | ||
1888 | case f8000: | ||
1889 | err = data->pwm_enable & 0x20; | ||
1890 | break; | ||
1891 | } | ||
1892 | if (err) { | ||
1893 | dev_err(&pdev->dev, | ||
1894 | "Invalid (reserved) pwm settings: 0x%02x\n", | ||
1895 | (unsigned int)data->pwm_enable); | ||
1896 | err = -ENODEV; | ||
1897 | goto exit_unregister_sysfs; | ||
1898 | } | ||
1899 | |||
1782 | err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr, | 1900 | err = f71882fg_create_sysfs_files(pdev, fxxxx_fan_attr, |
1783 | ARRAY_SIZE(fxxxx_fan_attr)); | 1901 | ARRAY_SIZE(fxxxx_fan_attr)); |
1784 | if (err) | 1902 | if (err) |
@@ -1794,6 +1912,13 @@ static int __devinit f71882fg_probe(struct platform_device *pdev) | |||
1794 | err = f71882fg_create_sysfs_files(pdev, | 1912 | err = f71882fg_create_sysfs_files(pdev, |
1795 | f71882fg_fan_attr, | 1913 | f71882fg_fan_attr, |
1796 | ARRAY_SIZE(f71882fg_fan_attr)); | 1914 | ARRAY_SIZE(f71882fg_fan_attr)); |
1915 | if (err) | ||
1916 | goto exit_unregister_sysfs; | ||
1917 | /* fall through! */ | ||
1918 | case f71858fg: | ||
1919 | err = f71882fg_create_sysfs_files(pdev, | ||
1920 | f71882fg_f71858fg_fan_attr, | ||
1921 | ARRAY_SIZE(f71882fg_f71858fg_fan_attr)); | ||
1797 | break; | 1922 | break; |
1798 | case f8000: | 1923 | case f8000: |
1799 | err = f71882fg_create_sysfs_files(pdev, | 1924 | err = f71882fg_create_sysfs_files(pdev, |
@@ -1878,6 +2003,9 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, | |||
1878 | 2003 | ||
1879 | devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); | 2004 | devid = force_id ? force_id : superio_inw(sioaddr, SIO_REG_DEVID); |
1880 | switch (devid) { | 2005 | switch (devid) { |
2006 | case SIO_F71858_ID: | ||
2007 | sio_data->type = f71858fg; | ||
2008 | break; | ||
1881 | case SIO_F71862_ID: | 2009 | case SIO_F71862_ID: |
1882 | sio_data->type = f71862fg; | 2010 | sio_data->type = f71862fg; |
1883 | break; | 2011 | break; |
@@ -1892,7 +2020,11 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address, | |||
1892 | goto exit; | 2020 | goto exit; |
1893 | } | 2021 | } |
1894 | 2022 | ||
1895 | superio_select(sioaddr, SIO_F71882FG_LD_HWM); | 2023 | if (sio_data->type == f71858fg) |
2024 | superio_select(sioaddr, SIO_F71858FG_LD_HWM); | ||
2025 | else | ||
2026 | superio_select(sioaddr, SIO_F71882FG_LD_HWM); | ||
2027 | |||
1896 | if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { | 2028 | if (!(superio_inb(sioaddr, SIO_REG_ENABLE) & 0x01)) { |
1897 | printk(KERN_WARNING DRVNAME ": Device not activated\n"); | 2029 | printk(KERN_WARNING DRVNAME ": Device not activated\n"); |
1898 | goto exit; | 2030 | goto exit; |
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c index e15c3e7b07e9..29ea6753f3bb 100644 --- a/drivers/hwmon/hwmon.c +++ b/drivers/hwmon/hwmon.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/hwmon.h> | 18 | #include <linux/hwmon.h> |
19 | #include <linux/gfp.h> | 19 | #include <linux/gfp.h> |
20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
21 | #include <linux/pci.h> | ||
21 | 22 | ||
22 | #define HWMON_ID_PREFIX "hwmon" | 23 | #define HWMON_ID_PREFIX "hwmon" |
23 | #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" | 24 | #define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" |
@@ -86,8 +87,36 @@ void hwmon_device_unregister(struct device *dev) | |||
86 | "hwmon_device_unregister() failed: bad class ID!\n"); | 87 | "hwmon_device_unregister() failed: bad class ID!\n"); |
87 | } | 88 | } |
88 | 89 | ||
90 | static void __init hwmon_pci_quirks(void) | ||
91 | { | ||
92 | #if defined CONFIG_X86 && defined CONFIG_PCI | ||
93 | struct pci_dev *sb; | ||
94 | u16 base; | ||
95 | u8 enable; | ||
96 | |||
97 | /* Open access to 0x295-0x296 on MSI MS-7031 */ | ||
98 | sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); | ||
99 | if (sb && | ||
100 | (sb->subsystem_vendor == 0x1462 && /* MSI */ | ||
101 | sb->subsystem_device == 0x0031)) { /* MS-7031 */ | ||
102 | |||
103 | pci_read_config_byte(sb, 0x48, &enable); | ||
104 | pci_read_config_word(sb, 0x64, &base); | ||
105 | |||
106 | if (base == 0 && !(enable & BIT(2))) { | ||
107 | dev_info(&sb->dev, | ||
108 | "Opening wide generic port at 0x295\n"); | ||
109 | pci_write_config_word(sb, 0x64, 0x295); | ||
110 | pci_write_config_byte(sb, 0x48, enable | BIT(2)); | ||
111 | } | ||
112 | } | ||
113 | #endif | ||
114 | } | ||
115 | |||
89 | static int __init hwmon_init(void) | 116 | static int __init hwmon_init(void) |
90 | { | 117 | { |
118 | hwmon_pci_quirks(); | ||
119 | |||
91 | hwmon_class = class_create(THIS_MODULE, "hwmon"); | 120 | hwmon_class = class_create(THIS_MODULE, "hwmon"); |
92 | if (IS_ERR(hwmon_class)) { | 121 | if (IS_ERR(hwmon_class)) { |
93 | printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); | 122 | printk(KERN_ERR "hwmon.c: couldn't create sysfs class\n"); |
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index fe74609a7feb..405d3fb5d76f 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c | |||
@@ -1127,3 +1127,4 @@ MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3650-*"); | |||
1127 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*"); | 1127 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3655-*"); |
1128 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*"); | 1128 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBMSystemx3755-*"); |
1129 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*"); | 1129 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBM3850M2/x3950M2-*"); |
1130 | MODULE_ALIAS("dmi:bvnIBM:*:pnIBMBladeHC10-*"); | ||
diff --git a/drivers/hwmon/max6650.c b/drivers/hwmon/max6650.c index f27af6a9da41..86142a858238 100644 --- a/drivers/hwmon/max6650.c +++ b/drivers/hwmon/max6650.c | |||
@@ -12,7 +12,7 @@ | |||
12 | * also work with the MAX6651. It does not distinguish max6650 and max6651 | 12 | * also work with the MAX6651. It does not distinguish max6650 and max6651 |
13 | * chips. | 13 | * chips. |
14 | * | 14 | * |
15 | * Tha datasheet was last seen at: | 15 | * The datasheet was last seen at: |
16 | * | 16 | * |
17 | * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf | 17 | * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf |
18 | * | 18 | * |
@@ -98,6 +98,16 @@ I2C_CLIENT_INSMOD_1(max6650); | |||
98 | #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 | 98 | #define MAX6650_CFG_MODE_OPEN_LOOP 0x30 |
99 | #define MAX6650_COUNT_MASK 0x03 | 99 | #define MAX6650_COUNT_MASK 0x03 |
100 | 100 | ||
101 | /* | ||
102 | * Alarm status register bits | ||
103 | */ | ||
104 | |||
105 | #define MAX6650_ALRM_MAX 0x01 | ||
106 | #define MAX6650_ALRM_MIN 0x02 | ||
107 | #define MAX6650_ALRM_TACH 0x04 | ||
108 | #define MAX6650_ALRM_GPIO1 0x08 | ||
109 | #define MAX6650_ALRM_GPIO2 0x10 | ||
110 | |||
101 | /* Minimum and maximum values of the FAN-RPM */ | 111 | /* Minimum and maximum values of the FAN-RPM */ |
102 | #define FAN_RPM_MIN 240 | 112 | #define FAN_RPM_MIN 240 |
103 | #define FAN_RPM_MAX 30000 | 113 | #define FAN_RPM_MAX 30000 |
@@ -151,6 +161,7 @@ struct max6650_data | |||
151 | u8 tach[4]; | 161 | u8 tach[4]; |
152 | u8 count; | 162 | u8 count; |
153 | u8 dac; | 163 | u8 dac; |
164 | u8 alarm; | ||
154 | }; | 165 | }; |
155 | 166 | ||
156 | static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, | 167 | static ssize_t get_fan(struct device *dev, struct device_attribute *devattr, |
@@ -418,6 +429,33 @@ static ssize_t set_div(struct device *dev, struct device_attribute *devattr, | |||
418 | return count; | 429 | return count; |
419 | } | 430 | } |
420 | 431 | ||
432 | /* | ||
433 | * Get alarm stati: | ||
434 | * Possible values: | ||
435 | * 0 = no alarm | ||
436 | * 1 = alarm | ||
437 | */ | ||
438 | |||
439 | static ssize_t get_alarm(struct device *dev, struct device_attribute *devattr, | ||
440 | char *buf) | ||
441 | { | ||
442 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
443 | struct max6650_data *data = max6650_update_device(dev); | ||
444 | struct i2c_client *client = to_i2c_client(dev); | ||
445 | int alarm = 0; | ||
446 | |||
447 | if (data->alarm & attr->index) { | ||
448 | mutex_lock(&data->update_lock); | ||
449 | alarm = 1; | ||
450 | data->alarm &= ~attr->index; | ||
451 | data->alarm |= i2c_smbus_read_byte_data(client, | ||
452 | MAX6650_REG_ALARM); | ||
453 | mutex_unlock(&data->update_lock); | ||
454 | } | ||
455 | |||
456 | return sprintf(buf, "%d\n", alarm); | ||
457 | } | ||
458 | |||
421 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); | 459 | static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, 0); |
422 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); | 460 | static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, get_fan, NULL, 1); |
423 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); | 461 | static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, get_fan, NULL, 2); |
@@ -426,7 +464,41 @@ static DEVICE_ATTR(fan1_target, S_IWUSR | S_IRUGO, get_target, set_target); | |||
426 | static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); | 464 | static DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO, get_div, set_div); |
427 | static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); | 465 | static DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, get_enable, set_enable); |
428 | static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); | 466 | static DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm, set_pwm); |
467 | static SENSOR_DEVICE_ATTR(fan1_max_alarm, S_IRUGO, get_alarm, NULL, | ||
468 | MAX6650_ALRM_MAX); | ||
469 | static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, get_alarm, NULL, | ||
470 | MAX6650_ALRM_MIN); | ||
471 | static SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_alarm, NULL, | ||
472 | MAX6650_ALRM_TACH); | ||
473 | static SENSOR_DEVICE_ATTR(gpio1_alarm, S_IRUGO, get_alarm, NULL, | ||
474 | MAX6650_ALRM_GPIO1); | ||
475 | static SENSOR_DEVICE_ATTR(gpio2_alarm, S_IRUGO, get_alarm, NULL, | ||
476 | MAX6650_ALRM_GPIO2); | ||
477 | |||
478 | static mode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a, | ||
479 | int n) | ||
480 | { | ||
481 | struct device *dev = container_of(kobj, struct device, kobj); | ||
482 | struct i2c_client *client = to_i2c_client(dev); | ||
483 | u8 alarm_en = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN); | ||
484 | struct device_attribute *devattr; | ||
429 | 485 | ||
486 | /* | ||
487 | * Hide the alarms that have not been enabled by the firmware | ||
488 | */ | ||
489 | |||
490 | devattr = container_of(a, struct device_attribute, attr); | ||
491 | if (devattr == &sensor_dev_attr_fan1_max_alarm.dev_attr | ||
492 | || devattr == &sensor_dev_attr_fan1_min_alarm.dev_attr | ||
493 | || devattr == &sensor_dev_attr_fan1_fault.dev_attr | ||
494 | || devattr == &sensor_dev_attr_gpio1_alarm.dev_attr | ||
495 | || devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) { | ||
496 | if (!(alarm_en & to_sensor_dev_attr(devattr)->index)) | ||
497 | return 0; | ||
498 | } | ||
499 | |||
500 | return a->mode; | ||
501 | } | ||
430 | 502 | ||
431 | static struct attribute *max6650_attrs[] = { | 503 | static struct attribute *max6650_attrs[] = { |
432 | &sensor_dev_attr_fan1_input.dev_attr.attr, | 504 | &sensor_dev_attr_fan1_input.dev_attr.attr, |
@@ -437,11 +509,17 @@ static struct attribute *max6650_attrs[] = { | |||
437 | &dev_attr_fan1_div.attr, | 509 | &dev_attr_fan1_div.attr, |
438 | &dev_attr_pwm1_enable.attr, | 510 | &dev_attr_pwm1_enable.attr, |
439 | &dev_attr_pwm1.attr, | 511 | &dev_attr_pwm1.attr, |
512 | &sensor_dev_attr_fan1_max_alarm.dev_attr.attr, | ||
513 | &sensor_dev_attr_fan1_min_alarm.dev_attr.attr, | ||
514 | &sensor_dev_attr_fan1_fault.dev_attr.attr, | ||
515 | &sensor_dev_attr_gpio1_alarm.dev_attr.attr, | ||
516 | &sensor_dev_attr_gpio2_alarm.dev_attr.attr, | ||
440 | NULL | 517 | NULL |
441 | }; | 518 | }; |
442 | 519 | ||
443 | static struct attribute_group max6650_attr_grp = { | 520 | static struct attribute_group max6650_attr_grp = { |
444 | .attrs = max6650_attrs, | 521 | .attrs = max6650_attrs, |
522 | .is_visible = max6650_attrs_visible, | ||
445 | }; | 523 | }; |
446 | 524 | ||
447 | /* | 525 | /* |
@@ -659,6 +737,12 @@ static struct max6650_data *max6650_update_device(struct device *dev) | |||
659 | MAX6650_REG_COUNT); | 737 | MAX6650_REG_COUNT); |
660 | data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); | 738 | data->dac = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC); |
661 | 739 | ||
740 | /* Alarms are cleared on read in case the condition that | ||
741 | * caused the alarm is removed. Keep the value latched here | ||
742 | * for providing the register through different alarm files. */ | ||
743 | data->alarm |= i2c_smbus_read_byte_data(client, | ||
744 | MAX6650_REG_ALARM); | ||
745 | |||
662 | data->last_updated = jiffies; | 746 | data->last_updated = jiffies; |
663 | data->valid = 1; | 747 | data->valid = 1; |
664 | } | 748 | } |
diff --git a/drivers/hwmon/sht15.c b/drivers/hwmon/sht15.c index 6cbdc2fea734..56cd6004da36 100644 --- a/drivers/hwmon/sht15.c +++ b/drivers/hwmon/sht15.c | |||
@@ -627,35 +627,35 @@ static struct platform_driver sht_drivers[] = { | |||
627 | .owner = THIS_MODULE, | 627 | .owner = THIS_MODULE, |
628 | }, | 628 | }, |
629 | .probe = sht15_probe, | 629 | .probe = sht15_probe, |
630 | .remove = sht15_remove, | 630 | .remove = __devexit_p(sht15_remove), |
631 | }, { | 631 | }, { |
632 | .driver = { | 632 | .driver = { |
633 | .name = "sht11", | 633 | .name = "sht11", |
634 | .owner = THIS_MODULE, | 634 | .owner = THIS_MODULE, |
635 | }, | 635 | }, |
636 | .probe = sht15_probe, | 636 | .probe = sht15_probe, |
637 | .remove = sht15_remove, | 637 | .remove = __devexit_p(sht15_remove), |
638 | }, { | 638 | }, { |
639 | .driver = { | 639 | .driver = { |
640 | .name = "sht15", | 640 | .name = "sht15", |
641 | .owner = THIS_MODULE, | 641 | .owner = THIS_MODULE, |
642 | }, | 642 | }, |
643 | .probe = sht15_probe, | 643 | .probe = sht15_probe, |
644 | .remove = sht15_remove, | 644 | .remove = __devexit_p(sht15_remove), |
645 | }, { | 645 | }, { |
646 | .driver = { | 646 | .driver = { |
647 | .name = "sht71", | 647 | .name = "sht71", |
648 | .owner = THIS_MODULE, | 648 | .owner = THIS_MODULE, |
649 | }, | 649 | }, |
650 | .probe = sht15_probe, | 650 | .probe = sht15_probe, |
651 | .remove = sht15_remove, | 651 | .remove = __devexit_p(sht15_remove), |
652 | }, { | 652 | }, { |
653 | .driver = { | 653 | .driver = { |
654 | .name = "sht75", | 654 | .name = "sht75", |
655 | .owner = THIS_MODULE, | 655 | .owner = THIS_MODULE, |
656 | }, | 656 | }, |
657 | .probe = sht15_probe, | 657 | .probe = sht15_probe, |
658 | .remove = sht15_remove, | 658 | .remove = __devexit_p(sht15_remove), |
659 | }, | 659 | }, |
660 | }; | 660 | }; |
661 | 661 | ||
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c new file mode 100644 index 000000000000..7b34f2cd08bb --- /dev/null +++ b/drivers/hwmon/tmp401.c | |||
@@ -0,0 +1,690 @@ | |||
1 | /* tmp401.c | ||
2 | * | ||
3 | * Copyright (C) 2007,2008 Hans de Goede <hdegoede@redhat.com> | ||
4 | * Preliminary tmp411 support by: | ||
5 | * Gabriel Konat, Sander Leget, Wouter Willems | ||
6 | * Copyright (C) 2009 Andre Prendel <andre.prendel@gmx.de> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | /* | ||
24 | * Driver for the Texas Instruments TMP401 SMBUS temperature sensor IC. | ||
25 | * | ||
26 | * Note this IC is in some aspect similar to the LM90, but it has quite a | ||
27 | * few differences too, for example the local temp has a higher resolution | ||
28 | * and thus has 16 bits registers for its value and limit instead of 8 bits. | ||
29 | */ | ||
30 | |||
31 | #include <linux/module.h> | ||
32 | #include <linux/init.h> | ||
33 | #include <linux/slab.h> | ||
34 | #include <linux/jiffies.h> | ||
35 | #include <linux/i2c.h> | ||
36 | #include <linux/hwmon.h> | ||
37 | #include <linux/hwmon-sysfs.h> | ||
38 | #include <linux/err.h> | ||
39 | #include <linux/mutex.h> | ||
40 | #include <linux/sysfs.h> | ||
41 | |||
42 | /* Addresses to scan */ | ||
43 | static const unsigned short normal_i2c[] = { 0x4c, I2C_CLIENT_END }; | ||
44 | |||
45 | /* Insmod parameters */ | ||
46 | I2C_CLIENT_INSMOD_2(tmp401, tmp411); | ||
47 | |||
48 | /* | ||
49 | * The TMP401 registers, note some registers have different addresses for | ||
50 | * reading and writing | ||
51 | */ | ||
52 | #define TMP401_STATUS 0x02 | ||
53 | #define TMP401_CONFIG_READ 0x03 | ||
54 | #define TMP401_CONFIG_WRITE 0x09 | ||
55 | #define TMP401_CONVERSION_RATE_READ 0x04 | ||
56 | #define TMP401_CONVERSION_RATE_WRITE 0x0A | ||
57 | #define TMP401_TEMP_CRIT_HYST 0x21 | ||
58 | #define TMP401_CONSECUTIVE_ALERT 0x22 | ||
59 | #define TMP401_MANUFACTURER_ID_REG 0xFE | ||
60 | #define TMP401_DEVICE_ID_REG 0xFF | ||
61 | #define TMP411_N_FACTOR_REG 0x18 | ||
62 | |||
63 | static const u8 TMP401_TEMP_MSB[2] = { 0x00, 0x01 }; | ||
64 | static const u8 TMP401_TEMP_LSB[2] = { 0x15, 0x10 }; | ||
65 | static const u8 TMP401_TEMP_LOW_LIMIT_MSB_READ[2] = { 0x06, 0x08 }; | ||
66 | static const u8 TMP401_TEMP_LOW_LIMIT_MSB_WRITE[2] = { 0x0C, 0x0E }; | ||
67 | static const u8 TMP401_TEMP_LOW_LIMIT_LSB[2] = { 0x17, 0x14 }; | ||
68 | static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_READ[2] = { 0x05, 0x07 }; | ||
69 | static const u8 TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[2] = { 0x0B, 0x0D }; | ||
70 | static const u8 TMP401_TEMP_HIGH_LIMIT_LSB[2] = { 0x16, 0x13 }; | ||
71 | /* These are called the THERM limit / hysteresis / mask in the datasheet */ | ||
72 | static const u8 TMP401_TEMP_CRIT_LIMIT[2] = { 0x20, 0x19 }; | ||
73 | |||
74 | static const u8 TMP411_TEMP_LOWEST_MSB[2] = { 0x30, 0x34 }; | ||
75 | static const u8 TMP411_TEMP_LOWEST_LSB[2] = { 0x31, 0x35 }; | ||
76 | static const u8 TMP411_TEMP_HIGHEST_MSB[2] = { 0x32, 0x36 }; | ||
77 | static const u8 TMP411_TEMP_HIGHEST_LSB[2] = { 0x33, 0x37 }; | ||
78 | |||
79 | /* Flags */ | ||
80 | #define TMP401_CONFIG_RANGE 0x04 | ||
81 | #define TMP401_CONFIG_SHUTDOWN 0x40 | ||
82 | #define TMP401_STATUS_LOCAL_CRIT 0x01 | ||
83 | #define TMP401_STATUS_REMOTE_CRIT 0x02 | ||
84 | #define TMP401_STATUS_REMOTE_OPEN 0x04 | ||
85 | #define TMP401_STATUS_REMOTE_LOW 0x08 | ||
86 | #define TMP401_STATUS_REMOTE_HIGH 0x10 | ||
87 | #define TMP401_STATUS_LOCAL_LOW 0x20 | ||
88 | #define TMP401_STATUS_LOCAL_HIGH 0x40 | ||
89 | |||
90 | /* Manufacturer / Device ID's */ | ||
91 | #define TMP401_MANUFACTURER_ID 0x55 | ||
92 | #define TMP401_DEVICE_ID 0x11 | ||
93 | #define TMP411_DEVICE_ID 0x12 | ||
94 | |||
95 | /* | ||
96 | * Functions declarations | ||
97 | */ | ||
98 | |||
99 | static int tmp401_probe(struct i2c_client *client, | ||
100 | const struct i2c_device_id *id); | ||
101 | static int tmp401_detect(struct i2c_client *client, int kind, | ||
102 | struct i2c_board_info *info); | ||
103 | static int tmp401_remove(struct i2c_client *client); | ||
104 | static struct tmp401_data *tmp401_update_device(struct device *dev); | ||
105 | |||
106 | /* | ||
107 | * Driver data (common to all clients) | ||
108 | */ | ||
109 | |||
110 | static const struct i2c_device_id tmp401_id[] = { | ||
111 | { "tmp401", tmp401 }, | ||
112 | { "tmp411", tmp411 }, | ||
113 | { } | ||
114 | }; | ||
115 | MODULE_DEVICE_TABLE(i2c, tmp401_id); | ||
116 | |||
117 | static struct i2c_driver tmp401_driver = { | ||
118 | .class = I2C_CLASS_HWMON, | ||
119 | .driver = { | ||
120 | .name = "tmp401", | ||
121 | }, | ||
122 | .probe = tmp401_probe, | ||
123 | .remove = tmp401_remove, | ||
124 | .id_table = tmp401_id, | ||
125 | .detect = tmp401_detect, | ||
126 | .address_data = &addr_data, | ||
127 | }; | ||
128 | |||
129 | /* | ||
130 | * Client data (each client gets its own) | ||
131 | */ | ||
132 | |||
133 | struct tmp401_data { | ||
134 | struct device *hwmon_dev; | ||
135 | struct mutex update_lock; | ||
136 | char valid; /* zero until following fields are valid */ | ||
137 | unsigned long last_updated; /* in jiffies */ | ||
138 | int kind; | ||
139 | |||
140 | /* register values */ | ||
141 | u8 status; | ||
142 | u8 config; | ||
143 | u16 temp[2]; | ||
144 | u16 temp_low[2]; | ||
145 | u16 temp_high[2]; | ||
146 | u8 temp_crit[2]; | ||
147 | u8 temp_crit_hyst; | ||
148 | u16 temp_lowest[2]; | ||
149 | u16 temp_highest[2]; | ||
150 | }; | ||
151 | |||
152 | /* | ||
153 | * Sysfs attr show / store functions | ||
154 | */ | ||
155 | |||
156 | static int tmp401_register_to_temp(u16 reg, u8 config) | ||
157 | { | ||
158 | int temp = reg; | ||
159 | |||
160 | if (config & TMP401_CONFIG_RANGE) | ||
161 | temp -= 64 * 256; | ||
162 | |||
163 | return (temp * 625 + 80) / 160; | ||
164 | } | ||
165 | |||
166 | static u16 tmp401_temp_to_register(long temp, u8 config) | ||
167 | { | ||
168 | if (config & TMP401_CONFIG_RANGE) { | ||
169 | temp = SENSORS_LIMIT(temp, -64000, 191000); | ||
170 | temp += 64000; | ||
171 | } else | ||
172 | temp = SENSORS_LIMIT(temp, 0, 127000); | ||
173 | |||
174 | return (temp * 160 + 312) / 625; | ||
175 | } | ||
176 | |||
177 | static int tmp401_crit_register_to_temp(u8 reg, u8 config) | ||
178 | { | ||
179 | int temp = reg; | ||
180 | |||
181 | if (config & TMP401_CONFIG_RANGE) | ||
182 | temp -= 64; | ||
183 | |||
184 | return temp * 1000; | ||
185 | } | ||
186 | |||
187 | static u8 tmp401_crit_temp_to_register(long temp, u8 config) | ||
188 | { | ||
189 | if (config & TMP401_CONFIG_RANGE) { | ||
190 | temp = SENSORS_LIMIT(temp, -64000, 191000); | ||
191 | temp += 64000; | ||
192 | } else | ||
193 | temp = SENSORS_LIMIT(temp, 0, 127000); | ||
194 | |||
195 | return (temp + 500) / 1000; | ||
196 | } | ||
197 | |||
198 | static ssize_t show_temp_value(struct device *dev, | ||
199 | struct device_attribute *devattr, char *buf) | ||
200 | { | ||
201 | int index = to_sensor_dev_attr(devattr)->index; | ||
202 | struct tmp401_data *data = tmp401_update_device(dev); | ||
203 | |||
204 | return sprintf(buf, "%d\n", | ||
205 | tmp401_register_to_temp(data->temp[index], data->config)); | ||
206 | } | ||
207 | |||
208 | static ssize_t show_temp_min(struct device *dev, | ||
209 | struct device_attribute *devattr, char *buf) | ||
210 | { | ||
211 | int index = to_sensor_dev_attr(devattr)->index; | ||
212 | struct tmp401_data *data = tmp401_update_device(dev); | ||
213 | |||
214 | return sprintf(buf, "%d\n", | ||
215 | tmp401_register_to_temp(data->temp_low[index], data->config)); | ||
216 | } | ||
217 | |||
218 | static ssize_t show_temp_max(struct device *dev, | ||
219 | struct device_attribute *devattr, char *buf) | ||
220 | { | ||
221 | int index = to_sensor_dev_attr(devattr)->index; | ||
222 | struct tmp401_data *data = tmp401_update_device(dev); | ||
223 | |||
224 | return sprintf(buf, "%d\n", | ||
225 | tmp401_register_to_temp(data->temp_high[index], data->config)); | ||
226 | } | ||
227 | |||
228 | static ssize_t show_temp_crit(struct device *dev, | ||
229 | struct device_attribute *devattr, char *buf) | ||
230 | { | ||
231 | int index = to_sensor_dev_attr(devattr)->index; | ||
232 | struct tmp401_data *data = tmp401_update_device(dev); | ||
233 | |||
234 | return sprintf(buf, "%d\n", | ||
235 | tmp401_crit_register_to_temp(data->temp_crit[index], | ||
236 | data->config)); | ||
237 | } | ||
238 | |||
239 | static ssize_t show_temp_crit_hyst(struct device *dev, | ||
240 | struct device_attribute *devattr, char *buf) | ||
241 | { | ||
242 | int temp, index = to_sensor_dev_attr(devattr)->index; | ||
243 | struct tmp401_data *data = tmp401_update_device(dev); | ||
244 | |||
245 | mutex_lock(&data->update_lock); | ||
246 | temp = tmp401_crit_register_to_temp(data->temp_crit[index], | ||
247 | data->config); | ||
248 | temp -= data->temp_crit_hyst * 1000; | ||
249 | mutex_unlock(&data->update_lock); | ||
250 | |||
251 | return sprintf(buf, "%d\n", temp); | ||
252 | } | ||
253 | |||
254 | static ssize_t show_temp_lowest(struct device *dev, | ||
255 | struct device_attribute *devattr, char *buf) | ||
256 | { | ||
257 | int index = to_sensor_dev_attr(devattr)->index; | ||
258 | struct tmp401_data *data = tmp401_update_device(dev); | ||
259 | |||
260 | return sprintf(buf, "%d\n", | ||
261 | tmp401_register_to_temp(data->temp_lowest[index], | ||
262 | data->config)); | ||
263 | } | ||
264 | |||
265 | static ssize_t show_temp_highest(struct device *dev, | ||
266 | struct device_attribute *devattr, char *buf) | ||
267 | { | ||
268 | int index = to_sensor_dev_attr(devattr)->index; | ||
269 | struct tmp401_data *data = tmp401_update_device(dev); | ||
270 | |||
271 | return sprintf(buf, "%d\n", | ||
272 | tmp401_register_to_temp(data->temp_highest[index], | ||
273 | data->config)); | ||
274 | } | ||
275 | |||
276 | static ssize_t show_status(struct device *dev, | ||
277 | struct device_attribute *devattr, char *buf) | ||
278 | { | ||
279 | int mask = to_sensor_dev_attr(devattr)->index; | ||
280 | struct tmp401_data *data = tmp401_update_device(dev); | ||
281 | |||
282 | if (data->status & mask) | ||
283 | return sprintf(buf, "1\n"); | ||
284 | else | ||
285 | return sprintf(buf, "0\n"); | ||
286 | } | ||
287 | |||
288 | static ssize_t store_temp_min(struct device *dev, struct device_attribute | ||
289 | *devattr, const char *buf, size_t count) | ||
290 | { | ||
291 | int index = to_sensor_dev_attr(devattr)->index; | ||
292 | struct tmp401_data *data = tmp401_update_device(dev); | ||
293 | long val; | ||
294 | u16 reg; | ||
295 | |||
296 | if (strict_strtol(buf, 10, &val)) | ||
297 | return -EINVAL; | ||
298 | |||
299 | reg = tmp401_temp_to_register(val, data->config); | ||
300 | |||
301 | mutex_lock(&data->update_lock); | ||
302 | |||
303 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
304 | TMP401_TEMP_LOW_LIMIT_MSB_WRITE[index], reg >> 8); | ||
305 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
306 | TMP401_TEMP_LOW_LIMIT_LSB[index], reg & 0xFF); | ||
307 | |||
308 | data->temp_low[index] = reg; | ||
309 | |||
310 | mutex_unlock(&data->update_lock); | ||
311 | |||
312 | return count; | ||
313 | } | ||
314 | |||
315 | static ssize_t store_temp_max(struct device *dev, struct device_attribute | ||
316 | *devattr, const char *buf, size_t count) | ||
317 | { | ||
318 | int index = to_sensor_dev_attr(devattr)->index; | ||
319 | struct tmp401_data *data = tmp401_update_device(dev); | ||
320 | long val; | ||
321 | u16 reg; | ||
322 | |||
323 | if (strict_strtol(buf, 10, &val)) | ||
324 | return -EINVAL; | ||
325 | |||
326 | reg = tmp401_temp_to_register(val, data->config); | ||
327 | |||
328 | mutex_lock(&data->update_lock); | ||
329 | |||
330 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
331 | TMP401_TEMP_HIGH_LIMIT_MSB_WRITE[index], reg >> 8); | ||
332 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
333 | TMP401_TEMP_HIGH_LIMIT_LSB[index], reg & 0xFF); | ||
334 | |||
335 | data->temp_high[index] = reg; | ||
336 | |||
337 | mutex_unlock(&data->update_lock); | ||
338 | |||
339 | return count; | ||
340 | } | ||
341 | |||
342 | static ssize_t store_temp_crit(struct device *dev, struct device_attribute | ||
343 | *devattr, const char *buf, size_t count) | ||
344 | { | ||
345 | int index = to_sensor_dev_attr(devattr)->index; | ||
346 | struct tmp401_data *data = tmp401_update_device(dev); | ||
347 | long val; | ||
348 | u8 reg; | ||
349 | |||
350 | if (strict_strtol(buf, 10, &val)) | ||
351 | return -EINVAL; | ||
352 | |||
353 | reg = tmp401_crit_temp_to_register(val, data->config); | ||
354 | |||
355 | mutex_lock(&data->update_lock); | ||
356 | |||
357 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
358 | TMP401_TEMP_CRIT_LIMIT[index], reg); | ||
359 | |||
360 | data->temp_crit[index] = reg; | ||
361 | |||
362 | mutex_unlock(&data->update_lock); | ||
363 | |||
364 | return count; | ||
365 | } | ||
366 | |||
367 | static ssize_t store_temp_crit_hyst(struct device *dev, struct device_attribute | ||
368 | *devattr, const char *buf, size_t count) | ||
369 | { | ||
370 | int temp, index = to_sensor_dev_attr(devattr)->index; | ||
371 | struct tmp401_data *data = tmp401_update_device(dev); | ||
372 | long val; | ||
373 | u8 reg; | ||
374 | |||
375 | if (strict_strtol(buf, 10, &val)) | ||
376 | return -EINVAL; | ||
377 | |||
378 | if (data->config & TMP401_CONFIG_RANGE) | ||
379 | val = SENSORS_LIMIT(val, -64000, 191000); | ||
380 | else | ||
381 | val = SENSORS_LIMIT(val, 0, 127000); | ||
382 | |||
383 | mutex_lock(&data->update_lock); | ||
384 | temp = tmp401_crit_register_to_temp(data->temp_crit[index], | ||
385 | data->config); | ||
386 | val = SENSORS_LIMIT(val, temp - 255000, temp); | ||
387 | reg = ((temp - val) + 500) / 1000; | ||
388 | |||
389 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
390 | TMP401_TEMP_CRIT_HYST, reg); | ||
391 | |||
392 | data->temp_crit_hyst = reg; | ||
393 | |||
394 | mutex_unlock(&data->update_lock); | ||
395 | |||
396 | return count; | ||
397 | } | ||
398 | |||
399 | /* | ||
400 | * Resets the historical measurements of minimum and maximum temperatures. | ||
401 | * This is done by writing any value to any of the minimum/maximum registers | ||
402 | * (0x30-0x37). | ||
403 | */ | ||
404 | static ssize_t reset_temp_history(struct device *dev, | ||
405 | struct device_attribute *devattr, const char *buf, size_t count) | ||
406 | { | ||
407 | long val; | ||
408 | |||
409 | if (strict_strtol(buf, 10, &val)) | ||
410 | return -EINVAL; | ||
411 | |||
412 | if (val != 1) { | ||
413 | dev_err(dev, "temp_reset_history value %ld not" | ||
414 | " supported. Use 1 to reset the history!\n", val); | ||
415 | return -EINVAL; | ||
416 | } | ||
417 | i2c_smbus_write_byte_data(to_i2c_client(dev), | ||
418 | TMP411_TEMP_LOWEST_MSB[0], val); | ||
419 | |||
420 | return count; | ||
421 | } | ||
422 | |||
423 | static struct sensor_device_attribute tmp401_attr[] = { | ||
424 | SENSOR_ATTR(temp1_input, 0444, show_temp_value, NULL, 0), | ||
425 | SENSOR_ATTR(temp1_min, 0644, show_temp_min, store_temp_min, 0), | ||
426 | SENSOR_ATTR(temp1_max, 0644, show_temp_max, store_temp_max, 0), | ||
427 | SENSOR_ATTR(temp1_crit, 0644, show_temp_crit, store_temp_crit, 0), | ||
428 | SENSOR_ATTR(temp1_crit_hyst, 0644, show_temp_crit_hyst, | ||
429 | store_temp_crit_hyst, 0), | ||
430 | SENSOR_ATTR(temp1_min_alarm, 0444, show_status, NULL, | ||
431 | TMP401_STATUS_LOCAL_LOW), | ||
432 | SENSOR_ATTR(temp1_max_alarm, 0444, show_status, NULL, | ||
433 | TMP401_STATUS_LOCAL_HIGH), | ||
434 | SENSOR_ATTR(temp1_crit_alarm, 0444, show_status, NULL, | ||
435 | TMP401_STATUS_LOCAL_CRIT), | ||
436 | SENSOR_ATTR(temp2_input, 0444, show_temp_value, NULL, 1), | ||
437 | SENSOR_ATTR(temp2_min, 0644, show_temp_min, store_temp_min, 1), | ||
438 | SENSOR_ATTR(temp2_max, 0644, show_temp_max, store_temp_max, 1), | ||
439 | SENSOR_ATTR(temp2_crit, 0644, show_temp_crit, store_temp_crit, 1), | ||
440 | SENSOR_ATTR(temp2_crit_hyst, 0444, show_temp_crit_hyst, NULL, 1), | ||
441 | SENSOR_ATTR(temp2_fault, 0444, show_status, NULL, | ||
442 | TMP401_STATUS_REMOTE_OPEN), | ||
443 | SENSOR_ATTR(temp2_min_alarm, 0444, show_status, NULL, | ||
444 | TMP401_STATUS_REMOTE_LOW), | ||
445 | SENSOR_ATTR(temp2_max_alarm, 0444, show_status, NULL, | ||
446 | TMP401_STATUS_REMOTE_HIGH), | ||
447 | SENSOR_ATTR(temp2_crit_alarm, 0444, show_status, NULL, | ||
448 | TMP401_STATUS_REMOTE_CRIT), | ||
449 | }; | ||
450 | |||
451 | /* | ||
452 | * Additional features of the TMP411 chip. | ||
453 | * The TMP411 stores the minimum and maximum | ||
454 | * temperature measured since power-on, chip-reset, or | ||
455 | * minimum and maximum register reset for both the local | ||
456 | * and remote channels. | ||
457 | */ | ||
458 | static struct sensor_device_attribute tmp411_attr[] = { | ||
459 | SENSOR_ATTR(temp1_highest, 0444, show_temp_highest, NULL, 0), | ||
460 | SENSOR_ATTR(temp1_lowest, 0444, show_temp_lowest, NULL, 0), | ||
461 | SENSOR_ATTR(temp2_highest, 0444, show_temp_highest, NULL, 1), | ||
462 | SENSOR_ATTR(temp2_lowest, 0444, show_temp_lowest, NULL, 1), | ||
463 | SENSOR_ATTR(temp_reset_history, 0200, NULL, reset_temp_history, 0), | ||
464 | }; | ||
465 | |||
466 | /* | ||
467 | * Begin non sysfs callback code (aka Real code) | ||
468 | */ | ||
469 | |||
470 | static void tmp401_init_client(struct i2c_client *client) | ||
471 | { | ||
472 | int config, config_orig; | ||
473 | |||
474 | /* Set the conversion rate to 2 Hz */ | ||
475 | i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5); | ||
476 | |||
477 | /* Start conversions (disable shutdown if necessary) */ | ||
478 | config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); | ||
479 | if (config < 0) { | ||
480 | dev_warn(&client->dev, "Initialization failed!\n"); | ||
481 | return; | ||
482 | } | ||
483 | |||
484 | config_orig = config; | ||
485 | config &= ~TMP401_CONFIG_SHUTDOWN; | ||
486 | |||
487 | if (config != config_orig) | ||
488 | i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config); | ||
489 | } | ||
490 | |||
491 | static int tmp401_detect(struct i2c_client *client, int kind, | ||
492 | struct i2c_board_info *info) | ||
493 | { | ||
494 | struct i2c_adapter *adapter = client->adapter; | ||
495 | |||
496 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
497 | return -ENODEV; | ||
498 | |||
499 | /* Detect and identify the chip */ | ||
500 | if (kind <= 0) { | ||
501 | u8 reg; | ||
502 | |||
503 | reg = i2c_smbus_read_byte_data(client, | ||
504 | TMP401_MANUFACTURER_ID_REG); | ||
505 | if (reg != TMP401_MANUFACTURER_ID) | ||
506 | return -ENODEV; | ||
507 | |||
508 | reg = i2c_smbus_read_byte_data(client, TMP401_DEVICE_ID_REG); | ||
509 | |||
510 | switch (reg) { | ||
511 | case TMP401_DEVICE_ID: | ||
512 | kind = tmp401; | ||
513 | break; | ||
514 | case TMP411_DEVICE_ID: | ||
515 | kind = tmp411; | ||
516 | break; | ||
517 | default: | ||
518 | return -ENODEV; | ||
519 | } | ||
520 | |||
521 | reg = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ); | ||
522 | if (reg & 0x1b) | ||
523 | return -ENODEV; | ||
524 | |||
525 | reg = i2c_smbus_read_byte_data(client, | ||
526 | TMP401_CONVERSION_RATE_READ); | ||
527 | /* Datasheet says: 0x1-0x6 */ | ||
528 | if (reg > 15) | ||
529 | return -ENODEV; | ||
530 | } | ||
531 | strlcpy(info->type, tmp401_id[kind - 1].name, I2C_NAME_SIZE); | ||
532 | |||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int tmp401_probe(struct i2c_client *client, | ||
537 | const struct i2c_device_id *id) | ||
538 | { | ||
539 | int i, err = 0; | ||
540 | struct tmp401_data *data; | ||
541 | const char *names[] = { "TMP401", "TMP411" }; | ||
542 | |||
543 | data = kzalloc(sizeof(struct tmp401_data), GFP_KERNEL); | ||
544 | if (!data) | ||
545 | return -ENOMEM; | ||
546 | |||
547 | i2c_set_clientdata(client, data); | ||
548 | mutex_init(&data->update_lock); | ||
549 | data->kind = id->driver_data; | ||
550 | |||
551 | /* Initialize the TMP401 chip */ | ||
552 | tmp401_init_client(client); | ||
553 | |||
554 | /* Register sysfs hooks */ | ||
555 | for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) { | ||
556 | err = device_create_file(&client->dev, | ||
557 | &tmp401_attr[i].dev_attr); | ||
558 | if (err) | ||
559 | goto exit_remove; | ||
560 | } | ||
561 | |||
562 | /* Register aditional tmp411 sysfs hooks */ | ||
563 | if (data->kind == tmp411) { | ||
564 | for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) { | ||
565 | err = device_create_file(&client->dev, | ||
566 | &tmp411_attr[i].dev_attr); | ||
567 | if (err) | ||
568 | goto exit_remove; | ||
569 | } | ||
570 | } | ||
571 | |||
572 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
573 | if (IS_ERR(data->hwmon_dev)) { | ||
574 | err = PTR_ERR(data->hwmon_dev); | ||
575 | data->hwmon_dev = NULL; | ||
576 | goto exit_remove; | ||
577 | } | ||
578 | |||
579 | dev_info(&client->dev, "Detected TI %s chip\n", | ||
580 | names[data->kind - 1]); | ||
581 | |||
582 | return 0; | ||
583 | |||
584 | exit_remove: | ||
585 | tmp401_remove(client); /* will also free data for us */ | ||
586 | return err; | ||
587 | } | ||
588 | |||
589 | static int tmp401_remove(struct i2c_client *client) | ||
590 | { | ||
591 | struct tmp401_data *data = i2c_get_clientdata(client); | ||
592 | int i; | ||
593 | |||
594 | if (data->hwmon_dev) | ||
595 | hwmon_device_unregister(data->hwmon_dev); | ||
596 | |||
597 | for (i = 0; i < ARRAY_SIZE(tmp401_attr); i++) | ||
598 | device_remove_file(&client->dev, &tmp401_attr[i].dev_attr); | ||
599 | |||
600 | if (data->kind == tmp411) { | ||
601 | for (i = 0; i < ARRAY_SIZE(tmp411_attr); i++) | ||
602 | device_remove_file(&client->dev, | ||
603 | &tmp411_attr[i].dev_attr); | ||
604 | } | ||
605 | |||
606 | kfree(data); | ||
607 | return 0; | ||
608 | } | ||
609 | |||
610 | static struct tmp401_data *tmp401_update_device_reg16( | ||
611 | struct i2c_client *client, struct tmp401_data *data) | ||
612 | { | ||
613 | int i; | ||
614 | |||
615 | for (i = 0; i < 2; i++) { | ||
616 | /* | ||
617 | * High byte must be read first immediately followed | ||
618 | * by the low byte | ||
619 | */ | ||
620 | data->temp[i] = i2c_smbus_read_byte_data(client, | ||
621 | TMP401_TEMP_MSB[i]) << 8; | ||
622 | data->temp[i] |= i2c_smbus_read_byte_data(client, | ||
623 | TMP401_TEMP_LSB[i]); | ||
624 | data->temp_low[i] = i2c_smbus_read_byte_data(client, | ||
625 | TMP401_TEMP_LOW_LIMIT_MSB_READ[i]) << 8; | ||
626 | data->temp_low[i] |= i2c_smbus_read_byte_data(client, | ||
627 | TMP401_TEMP_LOW_LIMIT_LSB[i]); | ||
628 | data->temp_high[i] = i2c_smbus_read_byte_data(client, | ||
629 | TMP401_TEMP_HIGH_LIMIT_MSB_READ[i]) << 8; | ||
630 | data->temp_high[i] |= i2c_smbus_read_byte_data(client, | ||
631 | TMP401_TEMP_HIGH_LIMIT_LSB[i]); | ||
632 | data->temp_crit[i] = i2c_smbus_read_byte_data(client, | ||
633 | TMP401_TEMP_CRIT_LIMIT[i]); | ||
634 | |||
635 | if (data->kind == tmp411) { | ||
636 | data->temp_lowest[i] = i2c_smbus_read_byte_data(client, | ||
637 | TMP411_TEMP_LOWEST_MSB[i]) << 8; | ||
638 | data->temp_lowest[i] |= i2c_smbus_read_byte_data( | ||
639 | client, TMP411_TEMP_LOWEST_LSB[i]); | ||
640 | |||
641 | data->temp_highest[i] = i2c_smbus_read_byte_data( | ||
642 | client, TMP411_TEMP_HIGHEST_MSB[i]) << 8; | ||
643 | data->temp_highest[i] |= i2c_smbus_read_byte_data( | ||
644 | client, TMP411_TEMP_HIGHEST_LSB[i]); | ||
645 | } | ||
646 | } | ||
647 | return data; | ||
648 | } | ||
649 | |||
650 | static struct tmp401_data *tmp401_update_device(struct device *dev) | ||
651 | { | ||
652 | struct i2c_client *client = to_i2c_client(dev); | ||
653 | struct tmp401_data *data = i2c_get_clientdata(client); | ||
654 | |||
655 | mutex_lock(&data->update_lock); | ||
656 | |||
657 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | ||
658 | data->status = i2c_smbus_read_byte_data(client, TMP401_STATUS); | ||
659 | data->config = i2c_smbus_read_byte_data(client, | ||
660 | TMP401_CONFIG_READ); | ||
661 | tmp401_update_device_reg16(client, data); | ||
662 | |||
663 | data->temp_crit_hyst = i2c_smbus_read_byte_data(client, | ||
664 | TMP401_TEMP_CRIT_HYST); | ||
665 | |||
666 | data->last_updated = jiffies; | ||
667 | data->valid = 1; | ||
668 | } | ||
669 | |||
670 | mutex_unlock(&data->update_lock); | ||
671 | |||
672 | return data; | ||
673 | } | ||
674 | |||
675 | static int __init tmp401_init(void) | ||
676 | { | ||
677 | return i2c_add_driver(&tmp401_driver); | ||
678 | } | ||
679 | |||
680 | static void __exit tmp401_exit(void) | ||
681 | { | ||
682 | i2c_del_driver(&tmp401_driver); | ||
683 | } | ||
684 | |||
685 | MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); | ||
686 | MODULE_DESCRIPTION("Texas Instruments TMP401 temperature sensor driver"); | ||
687 | MODULE_LICENSE("GPL"); | ||
688 | |||
689 | module_init(tmp401_init); | ||
690 | module_exit(tmp401_exit); | ||
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c index e64b42058b21..0e9746913d2b 100644 --- a/drivers/hwmon/w83627ehf.c +++ b/drivers/hwmon/w83627ehf.c | |||
@@ -36,6 +36,7 @@ | |||
36 | w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 | 36 | w83627ehf 10 5 4 3 0x8850 0x88 0x5ca3 |
37 | 0x8860 0xa1 | 37 | 0x8860 0xa1 |
38 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 | 38 | w83627dhg 9 5 4 3 0xa020 0xc1 0x5ca3 |
39 | w83627dhg-p 9 5 4 3 0xb070 0xc1 0x5ca3 | ||
39 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 | 40 | w83667hg 9 5 3 3 0xa510 0xc1 0x5ca3 |
40 | */ | 41 | */ |
41 | 42 | ||
@@ -53,12 +54,13 @@ | |||
53 | #include <asm/io.h> | 54 | #include <asm/io.h> |
54 | #include "lm75.h" | 55 | #include "lm75.h" |
55 | 56 | ||
56 | enum kinds { w83627ehf, w83627dhg, w83667hg }; | 57 | enum kinds { w83627ehf, w83627dhg, w83627dhg_p, w83667hg }; |
57 | 58 | ||
58 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ | 59 | /* used to set data->name = w83627ehf_device_names[data->sio_kind] */ |
59 | static const char * w83627ehf_device_names[] = { | 60 | static const char * w83627ehf_device_names[] = { |
60 | "w83627ehf", | 61 | "w83627ehf", |
61 | "w83627dhg", | 62 | "w83627dhg", |
63 | "w83627dhg", | ||
62 | "w83667hg", | 64 | "w83667hg", |
63 | }; | 65 | }; |
64 | 66 | ||
@@ -86,6 +88,7 @@ MODULE_PARM_DESC(force_id, "Override the detected device ID"); | |||
86 | #define SIO_W83627EHF_ID 0x8850 | 88 | #define SIO_W83627EHF_ID 0x8850 |
87 | #define SIO_W83627EHG_ID 0x8860 | 89 | #define SIO_W83627EHG_ID 0x8860 |
88 | #define SIO_W83627DHG_ID 0xa020 | 90 | #define SIO_W83627DHG_ID 0xa020 |
91 | #define SIO_W83627DHG_P_ID 0xb070 | ||
89 | #define SIO_W83667HG_ID 0xa510 | 92 | #define SIO_W83667HG_ID 0xa510 |
90 | #define SIO_ID_MASK 0xFFF0 | 93 | #define SIO_ID_MASK 0xFFF0 |
91 | 94 | ||
@@ -1517,6 +1520,7 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1517 | static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; | 1520 | static const char __initdata sio_name_W83627EHF[] = "W83627EHF"; |
1518 | static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; | 1521 | static const char __initdata sio_name_W83627EHG[] = "W83627EHG"; |
1519 | static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; | 1522 | static const char __initdata sio_name_W83627DHG[] = "W83627DHG"; |
1523 | static const char __initdata sio_name_W83627DHG_P[] = "W83627DHG-P"; | ||
1520 | static const char __initdata sio_name_W83667HG[] = "W83667HG"; | 1524 | static const char __initdata sio_name_W83667HG[] = "W83667HG"; |
1521 | 1525 | ||
1522 | u16 val; | 1526 | u16 val; |
@@ -1542,6 +1546,10 @@ static int __init w83627ehf_find(int sioaddr, unsigned short *addr, | |||
1542 | sio_data->kind = w83627dhg; | 1546 | sio_data->kind = w83627dhg; |
1543 | sio_name = sio_name_W83627DHG; | 1547 | sio_name = sio_name_W83627DHG; |
1544 | break; | 1548 | break; |
1549 | case SIO_W83627DHG_P_ID: | ||
1550 | sio_data->kind = w83627dhg_p; | ||
1551 | sio_name = sio_name_W83627DHG_P; | ||
1552 | break; | ||
1545 | case SIO_W83667HG_ID: | 1553 | case SIO_W83667HG_ID: |
1546 | sio_data->kind = w83667hg; | 1554 | sio_data->kind = w83667hg; |
1547 | sio_name = sio_name_W83667HG; | 1555 | sio_name = sio_name_W83667HG; |
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c8460fa9cfac..0d04d3ebfc2d 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig | |||
@@ -211,7 +211,7 @@ config I2C_VIA | |||
211 | will be called i2c-via. | 211 | will be called i2c-via. |
212 | 212 | ||
213 | config I2C_VIAPRO | 213 | config I2C_VIAPRO |
214 | tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820" | 214 | tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx" |
215 | depends on PCI | 215 | depends on PCI |
216 | help | 216 | help |
217 | If you say yes to this option, support will be included for the VIA | 217 | If you say yes to this option, support will be included for the VIA |
@@ -225,8 +225,8 @@ config I2C_VIAPRO | |||
225 | VT8237R/A/S | 225 | VT8237R/A/S |
226 | VT8251 | 226 | VT8251 |
227 | CX700 | 227 | CX700 |
228 | VX800 | 228 | VX800/VX820 |
229 | VX820 | 229 | VX855/VX875 |
230 | 230 | ||
231 | This driver can also be built as a module. If so, the module | 231 | This driver can also be built as a module. If so, the module |
232 | will be called i2c-viapro. | 232 | will be called i2c-viapro. |
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 02e6f724b05f..54d810a4d00f 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c | |||
@@ -37,6 +37,7 @@ | |||
37 | VT8251 0x3287 yes | 37 | VT8251 0x3287 yes |
38 | CX700 0x8324 yes | 38 | CX700 0x8324 yes |
39 | VX800/VX820 0x8353 yes | 39 | VX800/VX820 0x8353 yes |
40 | VX855/VX875 0x8409 yes | ||
40 | 41 | ||
41 | Note: we assume there can only be one device, with one SMBus interface. | 42 | Note: we assume there can only be one device, with one SMBus interface. |
42 | */ | 43 | */ |
@@ -404,6 +405,7 @@ found: | |||
404 | switch (pdev->device) { | 405 | switch (pdev->device) { |
405 | case PCI_DEVICE_ID_VIA_CX700: | 406 | case PCI_DEVICE_ID_VIA_CX700: |
406 | case PCI_DEVICE_ID_VIA_VX800: | 407 | case PCI_DEVICE_ID_VIA_VX800: |
408 | case PCI_DEVICE_ID_VIA_VX855: | ||
407 | case PCI_DEVICE_ID_VIA_8251: | 409 | case PCI_DEVICE_ID_VIA_8251: |
408 | case PCI_DEVICE_ID_VIA_8237: | 410 | case PCI_DEVICE_ID_VIA_8237: |
409 | case PCI_DEVICE_ID_VIA_8237A: | 411 | case PCI_DEVICE_ID_VIA_8237A: |
@@ -469,6 +471,8 @@ static struct pci_device_id vt596_ids[] = { | |||
469 | .driver_data = SMBBA3 }, | 471 | .driver_data = SMBBA3 }, |
470 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), | 472 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800), |
471 | .driver_data = SMBBA3 }, | 473 | .driver_data = SMBBA3 }, |
474 | { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855), | ||
475 | .driver_data = SMBBA3 }, | ||
472 | { 0, } | 476 | { 0, } |
473 | }; | 477 | }; |
474 | 478 | ||
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c index 1a474acc0ddd..7663d57833a0 100644 --- a/drivers/i2c/busses/i2c-voodoo3.c +++ b/drivers/i2c/busses/i2c-voodoo3.c | |||
@@ -163,7 +163,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = { | |||
163 | 163 | ||
164 | static struct i2c_adapter voodoo3_i2c_adapter = { | 164 | static struct i2c_adapter voodoo3_i2c_adapter = { |
165 | .owner = THIS_MODULE, | 165 | .owner = THIS_MODULE, |
166 | .class = I2C_CLASS_TV_ANALOG, | ||
167 | .name = "I2C Voodoo3/Banshee adapter", | 166 | .name = "I2C Voodoo3/Banshee adapter", |
168 | .algo_data = &voo_i2c_bit_data, | 167 | .algo_data = &voo_i2c_bit_data, |
169 | }; | 168 | }; |
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig index 8f8c81eb0aee..02d746c9c474 100644 --- a/drivers/i2c/chips/Kconfig +++ b/drivers/i2c/chips/Kconfig | |||
@@ -64,21 +64,6 @@ config SENSORS_PCA9539 | |||
64 | This driver is deprecated and will be dropped soon. Use | 64 | This driver is deprecated and will be dropped soon. Use |
65 | drivers/gpio/pca953x.c instead. | 65 | drivers/gpio/pca953x.c instead. |
66 | 66 | ||
67 | config SENSORS_MAX6875 | ||
68 | tristate "Maxim MAX6875 Power supply supervisor" | ||
69 | depends on EXPERIMENTAL | ||
70 | help | ||
71 | If you say yes here you get support for the Maxim MAX6875 | ||
72 | EEPROM-programmable, quad power-supply sequencer/supervisor. | ||
73 | |||
74 | This provides an interface to program the EEPROM and reset the chip. | ||
75 | |||
76 | This driver also supports the Maxim MAX6874 hex power-supply | ||
77 | sequencer/supervisor if found at a compatible address. | ||
78 | |||
79 | This driver can also be built as a module. If so, the module | ||
80 | will be called max6875. | ||
81 | |||
82 | config SENSORS_TSL2550 | 67 | config SENSORS_TSL2550 |
83 | tristate "Taos TSL2550 ambient light sensor" | 68 | tristate "Taos TSL2550 ambient light sensor" |
84 | depends on EXPERIMENTAL | 69 | depends on EXPERIMENTAL |
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile index 55a376037183..f4680d16ee34 100644 --- a/drivers/i2c/chips/Makefile +++ b/drivers/i2c/chips/Makefile | |||
@@ -11,7 +11,6 @@ | |||
11 | # | 11 | # |
12 | 12 | ||
13 | obj-$(CONFIG_DS1682) += ds1682.o | 13 | obj-$(CONFIG_DS1682) += ds1682.o |
14 | obj-$(CONFIG_SENSORS_MAX6875) += max6875.o | ||
15 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o | 14 | obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o |
16 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o | 15 | obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o |
17 | obj-$(CONFIG_PCF8575) += pcf8575.o | 16 | obj-$(CONFIG_PCF8575) += pcf8575.o |
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 85e2e919d1cd..5ed622ee65c3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/i2c.h> | 29 | #include <linux/i2c.h> |
30 | #include <linux/init.h> | 30 | #include <linux/init.h> |
31 | #include <linux/idr.h> | 31 | #include <linux/idr.h> |
32 | #include <linux/platform_device.h> | ||
33 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
34 | #include <linux/completion.h> | 33 | #include <linux/completion.h> |
35 | #include <linux/hardirq.h> | 34 | #include <linux/hardirq.h> |
@@ -451,16 +450,6 @@ static int i2c_register_adapter(struct i2c_adapter *adap) | |||
451 | 450 | ||
452 | mutex_lock(&core_lock); | 451 | mutex_lock(&core_lock); |
453 | 452 | ||
454 | /* Add the adapter to the driver core. | ||
455 | * If the parent pointer is not set up, | ||
456 | * we add this adapter to the host bus. | ||
457 | */ | ||
458 | if (adap->dev.parent == NULL) { | ||
459 | adap->dev.parent = &platform_bus; | ||
460 | pr_debug("I2C adapter driver [%s] forgot to specify " | ||
461 | "physical device\n", adap->name); | ||
462 | } | ||
463 | |||
464 | /* Set default timeout to 1 second if not already set */ | 453 | /* Set default timeout to 1 second if not already set */ |
465 | if (adap->timeout == 0) | 454 | if (adap->timeout == 0) |
466 | adap->timeout = HZ; | 455 | adap->timeout = HZ; |
@@ -1022,7 +1011,8 @@ module_exit(i2c_exit); | |||
1022 | */ | 1011 | */ |
1023 | int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | 1012 | int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) |
1024 | { | 1013 | { |
1025 | int ret; | 1014 | unsigned long orig_jiffies; |
1015 | int ret, try; | ||
1026 | 1016 | ||
1027 | /* REVISIT the fault reporting model here is weak: | 1017 | /* REVISIT the fault reporting model here is weak: |
1028 | * | 1018 | * |
@@ -1060,7 +1050,15 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) | |||
1060 | mutex_lock_nested(&adap->bus_lock, adap->level); | 1050 | mutex_lock_nested(&adap->bus_lock, adap->level); |
1061 | } | 1051 | } |
1062 | 1052 | ||
1063 | ret = adap->algo->master_xfer(adap,msgs,num); | 1053 | /* Retry automatically on arbitration loss */ |
1054 | orig_jiffies = jiffies; | ||
1055 | for (ret = 0, try = 0; try <= adap->retries; try++) { | ||
1056 | ret = adap->algo->master_xfer(adap, msgs, num); | ||
1057 | if (ret != -EAGAIN) | ||
1058 | break; | ||
1059 | if (time_after(jiffies, orig_jiffies + adap->timeout)) | ||
1060 | break; | ||
1061 | } | ||
1064 | mutex_unlock(&adap->bus_lock); | 1062 | mutex_unlock(&adap->bus_lock); |
1065 | 1063 | ||
1066 | return ret; | 1064 | return ret; |
@@ -1509,7 +1507,7 @@ struct i2c_adapter* i2c_get_adapter(int id) | |||
1509 | struct i2c_adapter *adapter; | 1507 | struct i2c_adapter *adapter; |
1510 | 1508 | ||
1511 | mutex_lock(&core_lock); | 1509 | mutex_lock(&core_lock); |
1512 | adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id); | 1510 | adapter = idr_find(&i2c_adapter_idr, id); |
1513 | if (adapter && !try_module_get(adapter->owner)) | 1511 | if (adapter && !try_module_get(adapter->owner)) |
1514 | adapter = NULL; | 1512 | adapter = NULL; |
1515 | 1513 | ||
@@ -1995,14 +1993,27 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, | |||
1995 | char read_write, u8 command, int protocol, | 1993 | char read_write, u8 command, int protocol, |
1996 | union i2c_smbus_data *data) | 1994 | union i2c_smbus_data *data) |
1997 | { | 1995 | { |
1996 | unsigned long orig_jiffies; | ||
1997 | int try; | ||
1998 | s32 res; | 1998 | s32 res; |
1999 | 1999 | ||
2000 | flags &= I2C_M_TEN | I2C_CLIENT_PEC; | 2000 | flags &= I2C_M_TEN | I2C_CLIENT_PEC; |
2001 | 2001 | ||
2002 | if (adapter->algo->smbus_xfer) { | 2002 | if (adapter->algo->smbus_xfer) { |
2003 | mutex_lock(&adapter->bus_lock); | 2003 | mutex_lock(&adapter->bus_lock); |
2004 | res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write, | 2004 | |
2005 | command, protocol, data); | 2005 | /* Retry automatically on arbitration loss */ |
2006 | orig_jiffies = jiffies; | ||
2007 | for (res = 0, try = 0; try <= adapter->retries; try++) { | ||
2008 | res = adapter->algo->smbus_xfer(adapter, addr, flags, | ||
2009 | read_write, command, | ||
2010 | protocol, data); | ||
2011 | if (res != -EAGAIN) | ||
2012 | break; | ||
2013 | if (time_after(jiffies, | ||
2014 | orig_jiffies + adapter->timeout)) | ||
2015 | break; | ||
2016 | } | ||
2006 | mutex_unlock(&adapter->bus_lock); | 2017 | mutex_unlock(&adapter->bus_lock); |
2007 | } else | 2018 | } else |
2008 | res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, | 2019 | res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write, |
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c index 0ddf9044948a..fde377c60cca 100644 --- a/drivers/macintosh/therm_adt746x.c +++ b/drivers/macintosh/therm_adt746x.c | |||
@@ -72,7 +72,7 @@ MODULE_PARM_DESC(verbose,"Verbose log operations " | |||
72 | "(default 0)"); | 72 | "(default 0)"); |
73 | 73 | ||
74 | struct thermostat { | 74 | struct thermostat { |
75 | struct i2c_client clt; | 75 | struct i2c_client *clt; |
76 | u8 temps[3]; | 76 | u8 temps[3]; |
77 | u8 cached_temp[3]; | 77 | u8 cached_temp[3]; |
78 | u8 initial_limits[3]; | 78 | u8 initial_limits[3]; |
@@ -87,9 +87,6 @@ static struct of_device * of_dev; | |||
87 | static struct thermostat* thermostat; | 87 | static struct thermostat* thermostat; |
88 | static struct task_struct *thread_therm = NULL; | 88 | static struct task_struct *thread_therm = NULL; |
89 | 89 | ||
90 | static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, | ||
91 | int busno); | ||
92 | |||
93 | static void write_both_fan_speed(struct thermostat *th, int speed); | 90 | static void write_both_fan_speed(struct thermostat *th, int speed); |
94 | static void write_fan_speed(struct thermostat *th, int speed, int fan); | 91 | static void write_fan_speed(struct thermostat *th, int speed, int fan); |
95 | 92 | ||
@@ -101,7 +98,7 @@ write_reg(struct thermostat* th, int reg, u8 data) | |||
101 | 98 | ||
102 | tmp[0] = reg; | 99 | tmp[0] = reg; |
103 | tmp[1] = data; | 100 | tmp[1] = data; |
104 | rc = i2c_master_send(&th->clt, (const char *)tmp, 2); | 101 | rc = i2c_master_send(th->clt, (const char *)tmp, 2); |
105 | if (rc < 0) | 102 | if (rc < 0) |
106 | return rc; | 103 | return rc; |
107 | if (rc != 2) | 104 | if (rc != 2) |
@@ -116,12 +113,12 @@ read_reg(struct thermostat* th, int reg) | |||
116 | int rc; | 113 | int rc; |
117 | 114 | ||
118 | reg_addr = (u8)reg; | 115 | reg_addr = (u8)reg; |
119 | rc = i2c_master_send(&th->clt, ®_addr, 1); | 116 | rc = i2c_master_send(th->clt, ®_addr, 1); |
120 | if (rc < 0) | 117 | if (rc < 0) |
121 | return rc; | 118 | return rc; |
122 | if (rc != 1) | 119 | if (rc != 1) |
123 | return -ENODEV; | 120 | return -ENODEV; |
124 | rc = i2c_master_recv(&th->clt, (char *)&data, 1); | 121 | rc = i2c_master_recv(th->clt, (char *)&data, 1); |
125 | if (rc < 0) | 122 | if (rc < 0) |
126 | return rc; | 123 | return rc; |
127 | return data; | 124 | return data; |
@@ -131,26 +128,36 @@ static int | |||
131 | attach_thermostat(struct i2c_adapter *adapter) | 128 | attach_thermostat(struct i2c_adapter *adapter) |
132 | { | 129 | { |
133 | unsigned long bus_no; | 130 | unsigned long bus_no; |
131 | struct i2c_board_info info; | ||
132 | struct i2c_client *client; | ||
134 | 133 | ||
135 | if (strncmp(adapter->name, "uni-n", 5)) | 134 | if (strncmp(adapter->name, "uni-n", 5)) |
136 | return -ENODEV; | 135 | return -ENODEV; |
137 | bus_no = simple_strtoul(adapter->name + 6, NULL, 10); | 136 | bus_no = simple_strtoul(adapter->name + 6, NULL, 10); |
138 | if (bus_no != therm_bus) | 137 | if (bus_no != therm_bus) |
139 | return -ENODEV; | 138 | return -ENODEV; |
140 | return attach_one_thermostat(adapter, therm_address, bus_no); | 139 | |
140 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
141 | strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE); | ||
142 | info.addr = therm_address; | ||
143 | client = i2c_new_device(adapter, &info); | ||
144 | if (!client) | ||
145 | return -ENODEV; | ||
146 | |||
147 | /* | ||
148 | * Let i2c-core delete that device on driver removal. | ||
149 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
150 | */ | ||
151 | list_add_tail(&client->detected, &client->driver->clients); | ||
152 | return 0; | ||
141 | } | 153 | } |
142 | 154 | ||
143 | static int | 155 | static int |
144 | detach_thermostat(struct i2c_adapter *adapter) | 156 | remove_thermostat(struct i2c_client *client) |
145 | { | 157 | { |
146 | struct thermostat* th; | 158 | struct thermostat *th = i2c_get_clientdata(client); |
147 | int i; | 159 | int i; |
148 | 160 | ||
149 | if (thermostat == NULL) | ||
150 | return 0; | ||
151 | |||
152 | th = thermostat; | ||
153 | |||
154 | if (thread_therm != NULL) { | 161 | if (thread_therm != NULL) { |
155 | kthread_stop(thread_therm); | 162 | kthread_stop(thread_therm); |
156 | } | 163 | } |
@@ -166,8 +173,6 @@ detach_thermostat(struct i2c_adapter *adapter) | |||
166 | 173 | ||
167 | write_both_fan_speed(th, -1); | 174 | write_both_fan_speed(th, -1); |
168 | 175 | ||
169 | i2c_detach_client(&th->clt); | ||
170 | |||
171 | thermostat = NULL; | 176 | thermostat = NULL; |
172 | 177 | ||
173 | kfree(th); | 178 | kfree(th); |
@@ -175,14 +180,6 @@ detach_thermostat(struct i2c_adapter *adapter) | |||
175 | return 0; | 180 | return 0; |
176 | } | 181 | } |
177 | 182 | ||
178 | static struct i2c_driver thermostat_driver = { | ||
179 | .driver = { | ||
180 | .name = "therm_adt746x", | ||
181 | }, | ||
182 | .attach_adapter = attach_thermostat, | ||
183 | .detach_adapter = detach_thermostat, | ||
184 | }; | ||
185 | |||
186 | static int read_fan_speed(struct thermostat *th, u8 addr) | 183 | static int read_fan_speed(struct thermostat *th, u8 addr) |
187 | { | 184 | { |
188 | u8 tmp[2]; | 185 | u8 tmp[2]; |
@@ -371,8 +368,8 @@ static void set_limit(struct thermostat *th, int i) | |||
371 | th->limits[i] = default_limits_local[i] + limit_adjust; | 368 | th->limits[i] = default_limits_local[i] + limit_adjust; |
372 | } | 369 | } |
373 | 370 | ||
374 | static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, | 371 | static int probe_thermostat(struct i2c_client *client, |
375 | int busno) | 372 | const struct i2c_device_id *id) |
376 | { | 373 | { |
377 | struct thermostat* th; | 374 | struct thermostat* th; |
378 | int rc; | 375 | int rc; |
@@ -385,16 +382,12 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, | |||
385 | if (!th) | 382 | if (!th) |
386 | return -ENOMEM; | 383 | return -ENOMEM; |
387 | 384 | ||
388 | th->clt.addr = addr; | 385 | i2c_set_clientdata(client, th); |
389 | th->clt.adapter = adapter; | 386 | th->clt = client; |
390 | th->clt.driver = &thermostat_driver; | ||
391 | strcpy(th->clt.name, "thermostat"); | ||
392 | 387 | ||
393 | rc = read_reg(th, 0); | 388 | rc = read_reg(th, 0); |
394 | if (rc < 0) { | 389 | if (rc < 0) { |
395 | printk(KERN_ERR "adt746x: Thermostat failed to read config " | 390 | dev_err(&client->dev, "Thermostat failed to read config!\n"); |
396 | "from bus %d !\n", | ||
397 | busno); | ||
398 | kfree(th); | 391 | kfree(th); |
399 | return -ENODEV; | 392 | return -ENODEV; |
400 | } | 393 | } |
@@ -423,14 +416,6 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, | |||
423 | 416 | ||
424 | thermostat = th; | 417 | thermostat = th; |
425 | 418 | ||
426 | if (i2c_attach_client(&th->clt)) { | ||
427 | printk(KERN_INFO "adt746x: Thermostat failed to attach " | ||
428 | "client !\n"); | ||
429 | thermostat = NULL; | ||
430 | kfree(th); | ||
431 | return -ENODEV; | ||
432 | } | ||
433 | |||
434 | /* be sure to really write fan speed the first time */ | 419 | /* be sure to really write fan speed the first time */ |
435 | th->last_speed[0] = -2; | 420 | th->last_speed[0] = -2; |
436 | th->last_speed[1] = -2; | 421 | th->last_speed[1] = -2; |
@@ -456,6 +441,21 @@ static int attach_one_thermostat(struct i2c_adapter *adapter, int addr, | |||
456 | return 0; | 441 | return 0; |
457 | } | 442 | } |
458 | 443 | ||
444 | static const struct i2c_device_id therm_adt746x_id[] = { | ||
445 | { "therm_adt746x", 0 }, | ||
446 | { } | ||
447 | }; | ||
448 | |||
449 | static struct i2c_driver thermostat_driver = { | ||
450 | .driver = { | ||
451 | .name = "therm_adt746x", | ||
452 | }, | ||
453 | .attach_adapter = attach_thermostat, | ||
454 | .probe = probe_thermostat, | ||
455 | .remove = remove_thermostat, | ||
456 | .id_table = therm_adt746x_id, | ||
457 | }; | ||
458 | |||
459 | /* | 459 | /* |
460 | * Now, unfortunately, sysfs doesn't give us a nice void * we could | 460 | * Now, unfortunately, sysfs doesn't give us a nice void * we could |
461 | * pass around to the attribute functions, so we don't really have | 461 | * pass around to the attribute functions, so we don't really have |
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c index 817607e2af6a..a028598af2d3 100644 --- a/drivers/macintosh/therm_pm72.c +++ b/drivers/macintosh/therm_pm72.c | |||
@@ -287,22 +287,6 @@ struct fcu_fan_table fcu_fans[] = { | |||
287 | }; | 287 | }; |
288 | 288 | ||
289 | /* | 289 | /* |
290 | * i2c_driver structure to attach to the host i2c controller | ||
291 | */ | ||
292 | |||
293 | static int therm_pm72_attach(struct i2c_adapter *adapter); | ||
294 | static int therm_pm72_detach(struct i2c_adapter *adapter); | ||
295 | |||
296 | static struct i2c_driver therm_pm72_driver = | ||
297 | { | ||
298 | .driver = { | ||
299 | .name = "therm_pm72", | ||
300 | }, | ||
301 | .attach_adapter = therm_pm72_attach, | ||
302 | .detach_adapter = therm_pm72_detach, | ||
303 | }; | ||
304 | |||
305 | /* | ||
306 | * Utility function to create an i2c_client structure and | 290 | * Utility function to create an i2c_client structure and |
307 | * attach it to one of u3 adapters | 291 | * attach it to one of u3 adapters |
308 | */ | 292 | */ |
@@ -310,6 +294,7 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) | |||
310 | { | 294 | { |
311 | struct i2c_client *clt; | 295 | struct i2c_client *clt; |
312 | struct i2c_adapter *adap; | 296 | struct i2c_adapter *adap; |
297 | struct i2c_board_info info; | ||
313 | 298 | ||
314 | if (id & 0x200) | 299 | if (id & 0x200) |
315 | adap = k2; | 300 | adap = k2; |
@@ -320,31 +305,21 @@ static struct i2c_client *attach_i2c_chip(int id, const char *name) | |||
320 | if (adap == NULL) | 305 | if (adap == NULL) |
321 | return NULL; | 306 | return NULL; |
322 | 307 | ||
323 | clt = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); | 308 | memset(&info, 0, sizeof(struct i2c_board_info)); |
324 | if (clt == NULL) | 309 | info.addr = (id >> 1) & 0x7f; |
325 | return NULL; | 310 | strlcpy(info.type, "therm_pm72", I2C_NAME_SIZE); |
326 | 311 | clt = i2c_new_device(adap, &info); | |
327 | clt->addr = (id >> 1) & 0x7f; | 312 | if (!clt) { |
328 | clt->adapter = adap; | ||
329 | clt->driver = &therm_pm72_driver; | ||
330 | strncpy(clt->name, name, I2C_NAME_SIZE-1); | ||
331 | |||
332 | if (i2c_attach_client(clt)) { | ||
333 | printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id); | 313 | printk(KERN_ERR "therm_pm72: Failed to attach to i2c ID 0x%x\n", id); |
334 | kfree(clt); | ||
335 | return NULL; | 314 | return NULL; |
336 | } | 315 | } |
337 | return clt; | ||
338 | } | ||
339 | 316 | ||
340 | /* | 317 | /* |
341 | * Utility function to get rid of the i2c_client structure | 318 | * Let i2c-core delete that device on driver removal. |
342 | * (will also detach from the adapter hopepfully) | 319 | * This is safe because i2c-core holds the core_lock mutex for us. |
343 | */ | 320 | */ |
344 | static void detach_i2c_chip(struct i2c_client *clt) | 321 | list_add_tail(&clt->detected, &clt->driver->clients); |
345 | { | 322 | return clt; |
346 | i2c_detach_client(clt); | ||
347 | kfree(clt); | ||
348 | } | 323 | } |
349 | 324 | ||
350 | /* | 325 | /* |
@@ -1203,8 +1178,6 @@ static int init_cpu_state(struct cpu_pid_state *state, int index) | |||
1203 | 1178 | ||
1204 | return 0; | 1179 | return 0; |
1205 | fail: | 1180 | fail: |
1206 | if (state->monitor) | ||
1207 | detach_i2c_chip(state->monitor); | ||
1208 | state->monitor = NULL; | 1181 | state->monitor = NULL; |
1209 | 1182 | ||
1210 | return -ENODEV; | 1183 | return -ENODEV; |
@@ -1232,7 +1205,6 @@ static void dispose_cpu_state(struct cpu_pid_state *state) | |||
1232 | device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm); | 1205 | device_remove_file(&of_dev->dev, &dev_attr_cpu1_intake_fan_rpm); |
1233 | } | 1206 | } |
1234 | 1207 | ||
1235 | detach_i2c_chip(state->monitor); | ||
1236 | state->monitor = NULL; | 1208 | state->monitor = NULL; |
1237 | } | 1209 | } |
1238 | 1210 | ||
@@ -1407,7 +1379,6 @@ static void dispose_backside_state(struct backside_pid_state *state) | |||
1407 | device_remove_file(&of_dev->dev, &dev_attr_backside_temperature); | 1379 | device_remove_file(&of_dev->dev, &dev_attr_backside_temperature); |
1408 | device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm); | 1380 | device_remove_file(&of_dev->dev, &dev_attr_backside_fan_pwm); |
1409 | 1381 | ||
1410 | detach_i2c_chip(state->monitor); | ||
1411 | state->monitor = NULL; | 1382 | state->monitor = NULL; |
1412 | } | 1383 | } |
1413 | 1384 | ||
@@ -1532,7 +1503,6 @@ static void dispose_drives_state(struct drives_pid_state *state) | |||
1532 | device_remove_file(&of_dev->dev, &dev_attr_drives_temperature); | 1503 | device_remove_file(&of_dev->dev, &dev_attr_drives_temperature); |
1533 | device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm); | 1504 | device_remove_file(&of_dev->dev, &dev_attr_drives_fan_rpm); |
1534 | 1505 | ||
1535 | detach_i2c_chip(state->monitor); | ||
1536 | state->monitor = NULL; | 1506 | state->monitor = NULL; |
1537 | } | 1507 | } |
1538 | 1508 | ||
@@ -1654,7 +1624,6 @@ static void dispose_dimms_state(struct dimm_pid_state *state) | |||
1654 | 1624 | ||
1655 | device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature); | 1625 | device_remove_file(&of_dev->dev, &dev_attr_dimms_temperature); |
1656 | 1626 | ||
1657 | detach_i2c_chip(state->monitor); | ||
1658 | state->monitor = NULL; | 1627 | state->monitor = NULL; |
1659 | } | 1628 | } |
1660 | 1629 | ||
@@ -1779,7 +1748,6 @@ static void dispose_slots_state(struct slots_pid_state *state) | |||
1779 | device_remove_file(&of_dev->dev, &dev_attr_slots_temperature); | 1748 | device_remove_file(&of_dev->dev, &dev_attr_slots_temperature); |
1780 | device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm); | 1749 | device_remove_file(&of_dev->dev, &dev_attr_slots_fan_pwm); |
1781 | 1750 | ||
1782 | detach_i2c_chip(state->monitor); | ||
1783 | state->monitor = NULL; | 1751 | state->monitor = NULL; |
1784 | } | 1752 | } |
1785 | 1753 | ||
@@ -2008,8 +1976,6 @@ static int attach_fcu(void) | |||
2008 | */ | 1976 | */ |
2009 | static void detach_fcu(void) | 1977 | static void detach_fcu(void) |
2010 | { | 1978 | { |
2011 | if (fcu) | ||
2012 | detach_i2c_chip(fcu); | ||
2013 | fcu = NULL; | 1979 | fcu = NULL; |
2014 | } | 1980 | } |
2015 | 1981 | ||
@@ -2060,12 +2026,21 @@ static int therm_pm72_attach(struct i2c_adapter *adapter) | |||
2060 | return 0; | 2026 | return 0; |
2061 | } | 2027 | } |
2062 | 2028 | ||
2029 | static int therm_pm72_probe(struct i2c_client *client, | ||
2030 | const struct i2c_device_id *id) | ||
2031 | { | ||
2032 | /* Always succeed, the real work was done in therm_pm72_attach() */ | ||
2033 | return 0; | ||
2034 | } | ||
2035 | |||
2063 | /* | 2036 | /* |
2064 | * Called on every adapter when the driver or the i2c controller | 2037 | * Called when any of the devices which participates into thermal management |
2065 | * is going away. | 2038 | * is going away. |
2066 | */ | 2039 | */ |
2067 | static int therm_pm72_detach(struct i2c_adapter *adapter) | 2040 | static int therm_pm72_remove(struct i2c_client *client) |
2068 | { | 2041 | { |
2042 | struct i2c_adapter *adapter = client->adapter; | ||
2043 | |||
2069 | mutex_lock(&driver_lock); | 2044 | mutex_lock(&driver_lock); |
2070 | 2045 | ||
2071 | if (state != state_detached) | 2046 | if (state != state_detached) |
@@ -2096,6 +2071,30 @@ static int therm_pm72_detach(struct i2c_adapter *adapter) | |||
2096 | return 0; | 2071 | return 0; |
2097 | } | 2072 | } |
2098 | 2073 | ||
2074 | /* | ||
2075 | * i2c_driver structure to attach to the host i2c controller | ||
2076 | */ | ||
2077 | |||
2078 | static const struct i2c_device_id therm_pm72_id[] = { | ||
2079 | /* | ||
2080 | * Fake device name, thermal management is done by several | ||
2081 | * chips but we don't need to differentiate between them at | ||
2082 | * this point. | ||
2083 | */ | ||
2084 | { "therm_pm72", 0 }, | ||
2085 | { } | ||
2086 | }; | ||
2087 | |||
2088 | static struct i2c_driver therm_pm72_driver = { | ||
2089 | .driver = { | ||
2090 | .name = "therm_pm72", | ||
2091 | }, | ||
2092 | .attach_adapter = therm_pm72_attach, | ||
2093 | .probe = therm_pm72_probe, | ||
2094 | .remove = therm_pm72_remove, | ||
2095 | .id_table = therm_pm72_id, | ||
2096 | }; | ||
2097 | |||
2099 | static int fan_check_loc_match(const char *loc, int fan) | 2098 | static int fan_check_loc_match(const char *loc, int fan) |
2100 | { | 2099 | { |
2101 | char tmp[64]; | 2100 | char tmp[64]; |
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c index 3da0a02efd76..40023313a760 100644 --- a/drivers/macintosh/therm_windtunnel.c +++ b/drivers/macintosh/therm_windtunnel.c | |||
@@ -48,16 +48,6 @@ | |||
48 | 48 | ||
49 | #define LOG_TEMP 0 /* continously log temperature */ | 49 | #define LOG_TEMP 0 /* continously log temperature */ |
50 | 50 | ||
51 | static int do_probe( struct i2c_adapter *adapter, int addr, int kind); | ||
52 | |||
53 | /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ | ||
54 | static const unsigned short normal_i2c[] = { 0x48, 0x49, 0x4a, 0x4b, | ||
55 | 0x4c, 0x4d, 0x4e, 0x4f, | ||
56 | 0x2c, 0x2d, 0x2e, 0x2f, | ||
57 | I2C_CLIENT_END }; | ||
58 | |||
59 | I2C_CLIENT_INSMOD; | ||
60 | |||
61 | static struct { | 51 | static struct { |
62 | volatile int running; | 52 | volatile int running; |
63 | struct task_struct *poll_task; | 53 | struct task_struct *poll_task; |
@@ -315,53 +305,54 @@ static int control_loop(void *dummy) | |||
315 | static int | 305 | static int |
316 | do_attach( struct i2c_adapter *adapter ) | 306 | do_attach( struct i2c_adapter *adapter ) |
317 | { | 307 | { |
318 | int ret = 0; | 308 | /* scan 0x48-0x4f (DS1775) and 0x2c-2x2f (ADM1030) */ |
309 | static const unsigned short scan_ds1775[] = { | ||
310 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, | ||
311 | I2C_CLIENT_END | ||
312 | }; | ||
313 | static const unsigned short scan_adm1030[] = { | ||
314 | 0x2c, 0x2d, 0x2e, 0x2f, | ||
315 | I2C_CLIENT_END | ||
316 | }; | ||
319 | 317 | ||
320 | if( strncmp(adapter->name, "uni-n", 5) ) | 318 | if( strncmp(adapter->name, "uni-n", 5) ) |
321 | return 0; | 319 | return 0; |
322 | 320 | ||
323 | if( !x.running ) { | 321 | if( !x.running ) { |
324 | ret = i2c_probe( adapter, &addr_data, &do_probe ); | 322 | struct i2c_board_info info; |
323 | |||
324 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
325 | strlcpy(info.type, "therm_ds1775", I2C_NAME_SIZE); | ||
326 | i2c_new_probed_device(adapter, &info, scan_ds1775); | ||
327 | |||
328 | strlcpy(info.type, "therm_adm1030", I2C_NAME_SIZE); | ||
329 | i2c_new_probed_device(adapter, &info, scan_adm1030); | ||
330 | |||
325 | if( x.thermostat && x.fan ) { | 331 | if( x.thermostat && x.fan ) { |
326 | x.running = 1; | 332 | x.running = 1; |
327 | x.poll_task = kthread_run(control_loop, NULL, "g4fand"); | 333 | x.poll_task = kthread_run(control_loop, NULL, "g4fand"); |
328 | } | 334 | } |
329 | } | 335 | } |
330 | return ret; | 336 | return 0; |
331 | } | 337 | } |
332 | 338 | ||
333 | static int | 339 | static int |
334 | do_detach( struct i2c_client *client ) | 340 | do_remove(struct i2c_client *client) |
335 | { | 341 | { |
336 | int err; | 342 | if (x.running) { |
337 | 343 | x.running = 0; | |
338 | if( (err=i2c_detach_client(client)) ) | 344 | kthread_stop(x.poll_task); |
339 | printk(KERN_ERR "failed to detach thermostat client\n"); | 345 | x.poll_task = NULL; |
340 | else { | ||
341 | if( x.running ) { | ||
342 | x.running = 0; | ||
343 | kthread_stop(x.poll_task); | ||
344 | x.poll_task = NULL; | ||
345 | } | ||
346 | if( client == x.thermostat ) | ||
347 | x.thermostat = NULL; | ||
348 | else if( client == x.fan ) | ||
349 | x.fan = NULL; | ||
350 | else { | ||
351 | printk(KERN_ERR "g4fan: bad client\n"); | ||
352 | } | ||
353 | kfree( client ); | ||
354 | } | 346 | } |
355 | return err; | 347 | if (client == x.thermostat) |
356 | } | 348 | x.thermostat = NULL; |
349 | else if (client == x.fan) | ||
350 | x.fan = NULL; | ||
351 | else | ||
352 | printk(KERN_ERR "g4fan: bad client\n"); | ||
357 | 353 | ||
358 | static struct i2c_driver g4fan_driver = { | 354 | return 0; |
359 | .driver = { | 355 | } |
360 | .name = "therm_windtunnel", | ||
361 | }, | ||
362 | .attach_adapter = do_attach, | ||
363 | .detach_client = do_detach, | ||
364 | }; | ||
365 | 356 | ||
366 | static int | 357 | static int |
367 | attach_fan( struct i2c_client *cl ) | 358 | attach_fan( struct i2c_client *cl ) |
@@ -374,13 +365,8 @@ attach_fan( struct i2c_client *cl ) | |||
374 | goto out; | 365 | goto out; |
375 | printk("ADM1030 fan controller [@%02x]\n", cl->addr ); | 366 | printk("ADM1030 fan controller [@%02x]\n", cl->addr ); |
376 | 367 | ||
377 | strlcpy( cl->name, "ADM1030 fan controller", sizeof(cl->name) ); | 368 | x.fan = cl; |
378 | |||
379 | if( !i2c_attach_client(cl) ) | ||
380 | x.fan = cl; | ||
381 | out: | 369 | out: |
382 | if( cl != x.fan ) | ||
383 | kfree( cl ); | ||
384 | return 0; | 370 | return 0; |
385 | } | 371 | } |
386 | 372 | ||
@@ -412,39 +398,47 @@ attach_thermostat( struct i2c_client *cl ) | |||
412 | x.temp = temp; | 398 | x.temp = temp; |
413 | x.overheat_temp = os_temp; | 399 | x.overheat_temp = os_temp; |
414 | x.overheat_hyst = hyst_temp; | 400 | x.overheat_hyst = hyst_temp; |
415 | 401 | x.thermostat = cl; | |
416 | strlcpy( cl->name, "DS1775 thermostat", sizeof(cl->name) ); | ||
417 | |||
418 | if( !i2c_attach_client(cl) ) | ||
419 | x.thermostat = cl; | ||
420 | out: | 402 | out: |
421 | if( cl != x.thermostat ) | ||
422 | kfree( cl ); | ||
423 | return 0; | 403 | return 0; |
424 | } | 404 | } |
425 | 405 | ||
406 | enum chip { ds1775, adm1030 }; | ||
407 | |||
408 | static const struct i2c_device_id therm_windtunnel_id[] = { | ||
409 | { "therm_ds1775", ds1775 }, | ||
410 | { "therm_adm1030", adm1030 }, | ||
411 | { } | ||
412 | }; | ||
413 | |||
426 | static int | 414 | static int |
427 | do_probe( struct i2c_adapter *adapter, int addr, int kind ) | 415 | do_probe(struct i2c_client *cl, const struct i2c_device_id *id) |
428 | { | 416 | { |
429 | struct i2c_client *cl; | 417 | struct i2c_adapter *adapter = cl->adapter; |
430 | 418 | ||
431 | if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA | 419 | if( !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
432 | | I2C_FUNC_SMBUS_WRITE_BYTE) ) | 420 | | I2C_FUNC_SMBUS_WRITE_BYTE) ) |
433 | return 0; | 421 | return 0; |
434 | 422 | ||
435 | if( !(cl=kzalloc(sizeof(*cl), GFP_KERNEL)) ) | 423 | switch (id->driver_data) { |
436 | return -ENOMEM; | 424 | case adm1030: |
437 | |||
438 | cl->addr = addr; | ||
439 | cl->adapter = adapter; | ||
440 | cl->driver = &g4fan_driver; | ||
441 | cl->flags = 0; | ||
442 | |||
443 | if( addr < 0x48 ) | ||
444 | return attach_fan( cl ); | 425 | return attach_fan( cl ); |
445 | return attach_thermostat( cl ); | 426 | case ds1775: |
427 | return attach_thermostat(cl); | ||
428 | } | ||
429 | return 0; | ||
446 | } | 430 | } |
447 | 431 | ||
432 | static struct i2c_driver g4fan_driver = { | ||
433 | .driver = { | ||
434 | .name = "therm_windtunnel", | ||
435 | }, | ||
436 | .attach_adapter = do_attach, | ||
437 | .probe = do_probe, | ||
438 | .remove = do_remove, | ||
439 | .id_table = therm_windtunnel_id, | ||
440 | }; | ||
441 | |||
448 | 442 | ||
449 | /************************************************************************/ | 443 | /************************************************************************/ |
450 | /* initialization / cleanup */ | 444 | /* initialization / cleanup */ |
diff --git a/drivers/macintosh/windfarm_lm75_sensor.c b/drivers/macintosh/windfarm_lm75_sensor.c index b92b959fe16e..529886c7a826 100644 --- a/drivers/macintosh/windfarm_lm75_sensor.c +++ b/drivers/macintosh/windfarm_lm75_sensor.c | |||
@@ -37,34 +37,22 @@ | |||
37 | struct wf_lm75_sensor { | 37 | struct wf_lm75_sensor { |
38 | int ds1775 : 1; | 38 | int ds1775 : 1; |
39 | int inited : 1; | 39 | int inited : 1; |
40 | struct i2c_client i2c; | 40 | struct i2c_client *i2c; |
41 | struct wf_sensor sens; | 41 | struct wf_sensor sens; |
42 | }; | 42 | }; |
43 | #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) | 43 | #define wf_to_lm75(c) container_of(c, struct wf_lm75_sensor, sens) |
44 | #define i2c_to_lm75(c) container_of(c, struct wf_lm75_sensor, i2c) | ||
45 | |||
46 | static int wf_lm75_attach(struct i2c_adapter *adapter); | ||
47 | static int wf_lm75_detach(struct i2c_client *client); | ||
48 | |||
49 | static struct i2c_driver wf_lm75_driver = { | ||
50 | .driver = { | ||
51 | .name = "wf_lm75", | ||
52 | }, | ||
53 | .attach_adapter = wf_lm75_attach, | ||
54 | .detach_client = wf_lm75_detach, | ||
55 | }; | ||
56 | 44 | ||
57 | static int wf_lm75_get(struct wf_sensor *sr, s32 *value) | 45 | static int wf_lm75_get(struct wf_sensor *sr, s32 *value) |
58 | { | 46 | { |
59 | struct wf_lm75_sensor *lm = wf_to_lm75(sr); | 47 | struct wf_lm75_sensor *lm = wf_to_lm75(sr); |
60 | s32 data; | 48 | s32 data; |
61 | 49 | ||
62 | if (lm->i2c.adapter == NULL) | 50 | if (lm->i2c == NULL) |
63 | return -ENODEV; | 51 | return -ENODEV; |
64 | 52 | ||
65 | /* Init chip if necessary */ | 53 | /* Init chip if necessary */ |
66 | if (!lm->inited) { | 54 | if (!lm->inited) { |
67 | u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(&lm->i2c, 1); | 55 | u8 cfg_new, cfg = (u8)i2c_smbus_read_byte_data(lm->i2c, 1); |
68 | 56 | ||
69 | DBG("wf_lm75: Initializing %s, cfg was: %02x\n", | 57 | DBG("wf_lm75: Initializing %s, cfg was: %02x\n", |
70 | sr->name, cfg); | 58 | sr->name, cfg); |
@@ -73,7 +61,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) | |||
73 | * the firmware for now | 61 | * the firmware for now |
74 | */ | 62 | */ |
75 | cfg_new = cfg & ~0x01; | 63 | cfg_new = cfg & ~0x01; |
76 | i2c_smbus_write_byte_data(&lm->i2c, 1, cfg_new); | 64 | i2c_smbus_write_byte_data(lm->i2c, 1, cfg_new); |
77 | lm->inited = 1; | 65 | lm->inited = 1; |
78 | 66 | ||
79 | /* If we just powered it up, let's wait 200 ms */ | 67 | /* If we just powered it up, let's wait 200 ms */ |
@@ -81,7 +69,7 @@ static int wf_lm75_get(struct wf_sensor *sr, s32 *value) | |||
81 | } | 69 | } |
82 | 70 | ||
83 | /* Read temperature register */ | 71 | /* Read temperature register */ |
84 | data = (s32)le16_to_cpu(i2c_smbus_read_word_data(&lm->i2c, 0)); | 72 | data = (s32)le16_to_cpu(i2c_smbus_read_word_data(lm->i2c, 0)); |
85 | data <<= 8; | 73 | data <<= 8; |
86 | *value = data; | 74 | *value = data; |
87 | 75 | ||
@@ -92,12 +80,6 @@ static void wf_lm75_release(struct wf_sensor *sr) | |||
92 | { | 80 | { |
93 | struct wf_lm75_sensor *lm = wf_to_lm75(sr); | 81 | struct wf_lm75_sensor *lm = wf_to_lm75(sr); |
94 | 82 | ||
95 | /* check if client is registered and detach from i2c */ | ||
96 | if (lm->i2c.adapter) { | ||
97 | i2c_detach_client(&lm->i2c); | ||
98 | lm->i2c.adapter = NULL; | ||
99 | } | ||
100 | |||
101 | kfree(lm); | 83 | kfree(lm); |
102 | } | 84 | } |
103 | 85 | ||
@@ -107,59 +89,77 @@ static struct wf_sensor_ops wf_lm75_ops = { | |||
107 | .owner = THIS_MODULE, | 89 | .owner = THIS_MODULE, |
108 | }; | 90 | }; |
109 | 91 | ||
110 | static struct wf_lm75_sensor *wf_lm75_create(struct i2c_adapter *adapter, | 92 | static int wf_lm75_probe(struct i2c_client *client, |
111 | u8 addr, int ds1775, | 93 | const struct i2c_device_id *id) |
112 | const char *loc) | ||
113 | { | 94 | { |
114 | struct wf_lm75_sensor *lm; | 95 | struct wf_lm75_sensor *lm; |
115 | int rc; | 96 | int rc; |
116 | 97 | ||
117 | DBG("wf_lm75: creating %s device at address 0x%02x\n", | ||
118 | ds1775 ? "ds1775" : "lm75", addr); | ||
119 | |||
120 | lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); | 98 | lm = kzalloc(sizeof(struct wf_lm75_sensor), GFP_KERNEL); |
121 | if (lm == NULL) | 99 | if (lm == NULL) |
122 | return NULL; | 100 | return -ENODEV; |
101 | |||
102 | lm->inited = 0; | ||
103 | lm->ds1775 = id->driver_data; | ||
104 | lm->i2c = client; | ||
105 | lm->sens.name = client->dev.platform_data; | ||
106 | lm->sens.ops = &wf_lm75_ops; | ||
107 | i2c_set_clientdata(client, lm); | ||
108 | |||
109 | rc = wf_register_sensor(&lm->sens); | ||
110 | if (rc) { | ||
111 | i2c_set_clientdata(client, NULL); | ||
112 | kfree(lm); | ||
113 | } | ||
114 | |||
115 | return rc; | ||
116 | } | ||
117 | |||
118 | static struct i2c_client *wf_lm75_create(struct i2c_adapter *adapter, | ||
119 | u8 addr, int ds1775, | ||
120 | const char *loc) | ||
121 | { | ||
122 | struct i2c_board_info info; | ||
123 | struct i2c_client *client; | ||
124 | char *name; | ||
125 | |||
126 | DBG("wf_lm75: creating %s device at address 0x%02x\n", | ||
127 | ds1775 ? "ds1775" : "lm75", addr); | ||
123 | 128 | ||
124 | /* Usual rant about sensor names not beeing very consistent in | 129 | /* Usual rant about sensor names not beeing very consistent in |
125 | * the device-tree, oh well ... | 130 | * the device-tree, oh well ... |
126 | * Add more entries below as you deal with more setups | 131 | * Add more entries below as you deal with more setups |
127 | */ | 132 | */ |
128 | if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) | 133 | if (!strcmp(loc, "Hard drive") || !strcmp(loc, "DRIVE BAY")) |
129 | lm->sens.name = "hd-temp"; | 134 | name = "hd-temp"; |
130 | else if (!strcmp(loc, "Incoming Air Temp")) | 135 | else if (!strcmp(loc, "Incoming Air Temp")) |
131 | lm->sens.name = "incoming-air-temp"; | 136 | name = "incoming-air-temp"; |
132 | else if (!strcmp(loc, "ODD Temp")) | 137 | else if (!strcmp(loc, "ODD Temp")) |
133 | lm->sens.name = "optical-drive-temp"; | 138 | name = "optical-drive-temp"; |
134 | else if (!strcmp(loc, "HD Temp")) | 139 | else if (!strcmp(loc, "HD Temp")) |
135 | lm->sens.name = "hard-drive-temp"; | 140 | name = "hard-drive-temp"; |
136 | else | 141 | else |
137 | goto fail; | 142 | goto fail; |
138 | 143 | ||
139 | lm->inited = 0; | 144 | memset(&info, 0, sizeof(struct i2c_board_info)); |
140 | lm->sens.ops = &wf_lm75_ops; | 145 | info.addr = (addr >> 1) & 0x7f; |
141 | lm->ds1775 = ds1775; | 146 | info.platform_data = name; |
142 | lm->i2c.addr = (addr >> 1) & 0x7f; | 147 | strlcpy(info.type, ds1775 ? "wf_ds1775" : "wf_lm75", I2C_NAME_SIZE); |
143 | lm->i2c.adapter = adapter; | ||
144 | lm->i2c.driver = &wf_lm75_driver; | ||
145 | strncpy(lm->i2c.name, lm->sens.name, I2C_NAME_SIZE-1); | ||
146 | |||
147 | rc = i2c_attach_client(&lm->i2c); | ||
148 | if (rc) { | ||
149 | printk(KERN_ERR "windfarm: failed to attach %s %s to i2c," | ||
150 | " err %d\n", ds1775 ? "ds1775" : "lm75", | ||
151 | lm->i2c.name, rc); | ||
152 | goto fail; | ||
153 | } | ||
154 | 148 | ||
155 | if (wf_register_sensor(&lm->sens)) { | 149 | client = i2c_new_device(adapter, &info); |
156 | i2c_detach_client(&lm->i2c); | 150 | if (client == NULL) { |
151 | printk(KERN_ERR "windfarm: failed to attach %s %s to i2c\n", | ||
152 | ds1775 ? "ds1775" : "lm75", name); | ||
157 | goto fail; | 153 | goto fail; |
158 | } | 154 | } |
159 | 155 | ||
160 | return lm; | 156 | /* |
157 | * Let i2c-core delete that device on driver removal. | ||
158 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
159 | */ | ||
160 | list_add_tail(&client->detected, &client->driver->clients); | ||
161 | return client; | ||
161 | fail: | 162 | fail: |
162 | kfree(lm); | ||
163 | return NULL; | 163 | return NULL; |
164 | } | 164 | } |
165 | 165 | ||
@@ -202,21 +202,38 @@ static int wf_lm75_attach(struct i2c_adapter *adapter) | |||
202 | return 0; | 202 | return 0; |
203 | } | 203 | } |
204 | 204 | ||
205 | static int wf_lm75_detach(struct i2c_client *client) | 205 | static int wf_lm75_remove(struct i2c_client *client) |
206 | { | 206 | { |
207 | struct wf_lm75_sensor *lm = i2c_to_lm75(client); | 207 | struct wf_lm75_sensor *lm = i2c_get_clientdata(client); |
208 | 208 | ||
209 | DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); | 209 | DBG("wf_lm75: i2c detatch called for %s\n", lm->sens.name); |
210 | 210 | ||
211 | /* Mark client detached */ | 211 | /* Mark client detached */ |
212 | lm->i2c.adapter = NULL; | 212 | lm->i2c = NULL; |
213 | 213 | ||
214 | /* release sensor */ | 214 | /* release sensor */ |
215 | wf_unregister_sensor(&lm->sens); | 215 | wf_unregister_sensor(&lm->sens); |
216 | 216 | ||
217 | i2c_set_clientdata(client, NULL); | ||
217 | return 0; | 218 | return 0; |
218 | } | 219 | } |
219 | 220 | ||
221 | static const struct i2c_device_id wf_lm75_id[] = { | ||
222 | { "wf_lm75", 0 }, | ||
223 | { "wf_ds1775", 1 }, | ||
224 | { } | ||
225 | }; | ||
226 | |||
227 | static struct i2c_driver wf_lm75_driver = { | ||
228 | .driver = { | ||
229 | .name = "wf_lm75", | ||
230 | }, | ||
231 | .attach_adapter = wf_lm75_attach, | ||
232 | .probe = wf_lm75_probe, | ||
233 | .remove = wf_lm75_remove, | ||
234 | .id_table = wf_lm75_id, | ||
235 | }; | ||
236 | |||
220 | static int __init wf_lm75_sensor_init(void) | 237 | static int __init wf_lm75_sensor_init(void) |
221 | { | 238 | { |
222 | /* Don't register on old machines that use therm_pm72 for now */ | 239 | /* Don't register on old machines that use therm_pm72 for now */ |
diff --git a/drivers/macintosh/windfarm_max6690_sensor.c b/drivers/macintosh/windfarm_max6690_sensor.c index e207a90d6b27..e2a55ecda2b2 100644 --- a/drivers/macintosh/windfarm_max6690_sensor.c +++ b/drivers/macintosh/windfarm_max6690_sensor.c | |||
@@ -26,34 +26,22 @@ | |||
26 | #define MAX6690_EXTERNAL_TEMP 1 | 26 | #define MAX6690_EXTERNAL_TEMP 1 |
27 | 27 | ||
28 | struct wf_6690_sensor { | 28 | struct wf_6690_sensor { |
29 | struct i2c_client i2c; | 29 | struct i2c_client *i2c; |
30 | struct wf_sensor sens; | 30 | struct wf_sensor sens; |
31 | }; | 31 | }; |
32 | 32 | ||
33 | #define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) | 33 | #define wf_to_6690(x) container_of((x), struct wf_6690_sensor, sens) |
34 | #define i2c_to_6690(x) container_of((x), struct wf_6690_sensor, i2c) | ||
35 | |||
36 | static int wf_max6690_attach(struct i2c_adapter *adapter); | ||
37 | static int wf_max6690_detach(struct i2c_client *client); | ||
38 | |||
39 | static struct i2c_driver wf_max6690_driver = { | ||
40 | .driver = { | ||
41 | .name = "wf_max6690", | ||
42 | }, | ||
43 | .attach_adapter = wf_max6690_attach, | ||
44 | .detach_client = wf_max6690_detach, | ||
45 | }; | ||
46 | 34 | ||
47 | static int wf_max6690_get(struct wf_sensor *sr, s32 *value) | 35 | static int wf_max6690_get(struct wf_sensor *sr, s32 *value) |
48 | { | 36 | { |
49 | struct wf_6690_sensor *max = wf_to_6690(sr); | 37 | struct wf_6690_sensor *max = wf_to_6690(sr); |
50 | s32 data; | 38 | s32 data; |
51 | 39 | ||
52 | if (max->i2c.adapter == NULL) | 40 | if (max->i2c == NULL) |
53 | return -ENODEV; | 41 | return -ENODEV; |
54 | 42 | ||
55 | /* chip gets initialized by firmware */ | 43 | /* chip gets initialized by firmware */ |
56 | data = i2c_smbus_read_byte_data(&max->i2c, MAX6690_EXTERNAL_TEMP); | 44 | data = i2c_smbus_read_byte_data(max->i2c, MAX6690_EXTERNAL_TEMP); |
57 | if (data < 0) | 45 | if (data < 0) |
58 | return data; | 46 | return data; |
59 | *value = data << 16; | 47 | *value = data << 16; |
@@ -64,10 +52,6 @@ static void wf_max6690_release(struct wf_sensor *sr) | |||
64 | { | 52 | { |
65 | struct wf_6690_sensor *max = wf_to_6690(sr); | 53 | struct wf_6690_sensor *max = wf_to_6690(sr); |
66 | 54 | ||
67 | if (max->i2c.adapter) { | ||
68 | i2c_detach_client(&max->i2c); | ||
69 | max->i2c.adapter = NULL; | ||
70 | } | ||
71 | kfree(max); | 55 | kfree(max); |
72 | } | 56 | } |
73 | 57 | ||
@@ -77,19 +61,40 @@ static struct wf_sensor_ops wf_max6690_ops = { | |||
77 | .owner = THIS_MODULE, | 61 | .owner = THIS_MODULE, |
78 | }; | 62 | }; |
79 | 63 | ||
80 | static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, | 64 | static int wf_max6690_probe(struct i2c_client *client, |
81 | const char *loc) | 65 | const struct i2c_device_id *id) |
82 | { | 66 | { |
83 | struct wf_6690_sensor *max; | 67 | struct wf_6690_sensor *max; |
84 | char *name; | 68 | int rc; |
85 | 69 | ||
86 | max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); | 70 | max = kzalloc(sizeof(struct wf_6690_sensor), GFP_KERNEL); |
87 | if (max == NULL) { | 71 | if (max == NULL) { |
88 | printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor %s: " | 72 | printk(KERN_ERR "windfarm: Couldn't create MAX6690 sensor: " |
89 | "no memory\n", loc); | 73 | "no memory\n"); |
90 | return; | 74 | return -ENOMEM; |
75 | } | ||
76 | |||
77 | max->i2c = client; | ||
78 | max->sens.name = client->dev.platform_data; | ||
79 | max->sens.ops = &wf_max6690_ops; | ||
80 | i2c_set_clientdata(client, max); | ||
81 | |||
82 | rc = wf_register_sensor(&max->sens); | ||
83 | if (rc) { | ||
84 | i2c_set_clientdata(client, NULL); | ||
85 | kfree(max); | ||
91 | } | 86 | } |
92 | 87 | ||
88 | return rc; | ||
89 | } | ||
90 | |||
91 | static struct i2c_client *wf_max6690_create(struct i2c_adapter *adapter, | ||
92 | u8 addr, const char *loc) | ||
93 | { | ||
94 | struct i2c_board_info info; | ||
95 | struct i2c_client *client; | ||
96 | char *name; | ||
97 | |||
93 | if (!strcmp(loc, "BACKSIDE")) | 98 | if (!strcmp(loc, "BACKSIDE")) |
94 | name = "backside-temp"; | 99 | name = "backside-temp"; |
95 | else if (!strcmp(loc, "NB Ambient")) | 100 | else if (!strcmp(loc, "NB Ambient")) |
@@ -99,27 +104,26 @@ static void wf_max6690_create(struct i2c_adapter *adapter, u8 addr, | |||
99 | else | 104 | else |
100 | goto fail; | 105 | goto fail; |
101 | 106 | ||
102 | max->sens.ops = &wf_max6690_ops; | 107 | memset(&info, 0, sizeof(struct i2c_board_info)); |
103 | max->sens.name = name; | 108 | info.addr = addr >> 1; |
104 | max->i2c.addr = addr >> 1; | 109 | info.platform_data = name; |
105 | max->i2c.adapter = adapter; | 110 | strlcpy(info.type, "wf_max6690", I2C_NAME_SIZE); |
106 | max->i2c.driver = &wf_max6690_driver; | ||
107 | strncpy(max->i2c.name, name, I2C_NAME_SIZE-1); | ||
108 | 111 | ||
109 | if (i2c_attach_client(&max->i2c)) { | 112 | client = i2c_new_device(adapter, &info); |
113 | if (client == NULL) { | ||
110 | printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); | 114 | printk(KERN_ERR "windfarm: failed to attach MAX6690 sensor\n"); |
111 | goto fail; | 115 | goto fail; |
112 | } | 116 | } |
113 | 117 | ||
114 | if (wf_register_sensor(&max->sens)) { | 118 | /* |
115 | i2c_detach_client(&max->i2c); | 119 | * Let i2c-core delete that device on driver removal. |
116 | goto fail; | 120 | * This is safe because i2c-core holds the core_lock mutex for us. |
117 | } | 121 | */ |
118 | 122 | list_add_tail(&client->detected, &client->driver->clients); | |
119 | return; | 123 | return client; |
120 | 124 | ||
121 | fail: | 125 | fail: |
122 | kfree(max); | 126 | return NULL; |
123 | } | 127 | } |
124 | 128 | ||
125 | static int wf_max6690_attach(struct i2c_adapter *adapter) | 129 | static int wf_max6690_attach(struct i2c_adapter *adapter) |
@@ -154,16 +158,31 @@ static int wf_max6690_attach(struct i2c_adapter *adapter) | |||
154 | return 0; | 158 | return 0; |
155 | } | 159 | } |
156 | 160 | ||
157 | static int wf_max6690_detach(struct i2c_client *client) | 161 | static int wf_max6690_remove(struct i2c_client *client) |
158 | { | 162 | { |
159 | struct wf_6690_sensor *max = i2c_to_6690(client); | 163 | struct wf_6690_sensor *max = i2c_get_clientdata(client); |
160 | 164 | ||
161 | max->i2c.adapter = NULL; | 165 | max->i2c = NULL; |
162 | wf_unregister_sensor(&max->sens); | 166 | wf_unregister_sensor(&max->sens); |
163 | 167 | ||
164 | return 0; | 168 | return 0; |
165 | } | 169 | } |
166 | 170 | ||
171 | static const struct i2c_device_id wf_max6690_id[] = { | ||
172 | { "wf_max6690", 0 }, | ||
173 | { } | ||
174 | }; | ||
175 | |||
176 | static struct i2c_driver wf_max6690_driver = { | ||
177 | .driver = { | ||
178 | .name = "wf_max6690", | ||
179 | }, | ||
180 | .attach_adapter = wf_max6690_attach, | ||
181 | .probe = wf_max6690_probe, | ||
182 | .remove = wf_max6690_remove, | ||
183 | .id_table = wf_max6690_id, | ||
184 | }; | ||
185 | |||
167 | static int __init wf_max6690_sensor_init(void) | 186 | static int __init wf_max6690_sensor_init(void) |
168 | { | 187 | { |
169 | /* Don't register on old machines that use therm_pm72 for now */ | 188 | /* Don't register on old machines that use therm_pm72 for now */ |
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c index 7847e981ac33..5da729e58f99 100644 --- a/drivers/macintosh/windfarm_smu_sat.c +++ b/drivers/macintosh/windfarm_smu_sat.c | |||
@@ -39,7 +39,7 @@ struct wf_sat { | |||
39 | struct mutex mutex; | 39 | struct mutex mutex; |
40 | unsigned long last_read; /* jiffies when cache last updated */ | 40 | unsigned long last_read; /* jiffies when cache last updated */ |
41 | u8 cache[16]; | 41 | u8 cache[16]; |
42 | struct i2c_client i2c; | 42 | struct i2c_client *i2c; |
43 | struct device_node *node; | 43 | struct device_node *node; |
44 | }; | 44 | }; |
45 | 45 | ||
@@ -54,18 +54,6 @@ struct wf_sat_sensor { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) | 56 | #define wf_to_sat(c) container_of(c, struct wf_sat_sensor, sens) |
57 | #define i2c_to_sat(c) container_of(c, struct wf_sat, i2c) | ||
58 | |||
59 | static int wf_sat_attach(struct i2c_adapter *adapter); | ||
60 | static int wf_sat_detach(struct i2c_client *client); | ||
61 | |||
62 | static struct i2c_driver wf_sat_driver = { | ||
63 | .driver = { | ||
64 | .name = "wf_smu_sat", | ||
65 | }, | ||
66 | .attach_adapter = wf_sat_attach, | ||
67 | .detach_client = wf_sat_detach, | ||
68 | }; | ||
69 | 57 | ||
70 | struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, | 58 | struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, |
71 | unsigned int *size) | 59 | unsigned int *size) |
@@ -81,13 +69,13 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, | |||
81 | if (sat_id > 1 || (sat = sats[sat_id]) == NULL) | 69 | if (sat_id > 1 || (sat = sats[sat_id]) == NULL) |
82 | return NULL; | 70 | return NULL; |
83 | 71 | ||
84 | err = i2c_smbus_write_word_data(&sat->i2c, 8, id << 8); | 72 | err = i2c_smbus_write_word_data(sat->i2c, 8, id << 8); |
85 | if (err) { | 73 | if (err) { |
86 | printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err); | 74 | printk(KERN_ERR "smu_sat_get_sdb_part wr error %d\n", err); |
87 | return NULL; | 75 | return NULL; |
88 | } | 76 | } |
89 | 77 | ||
90 | err = i2c_smbus_read_word_data(&sat->i2c, 9); | 78 | err = i2c_smbus_read_word_data(sat->i2c, 9); |
91 | if (err < 0) { | 79 | if (err < 0) { |
92 | printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); | 80 | printk(KERN_ERR "smu_sat_get_sdb_part rd len error\n"); |
93 | return NULL; | 81 | return NULL; |
@@ -105,7 +93,7 @@ struct smu_sdbp_header *smu_sat_get_sdb_partition(unsigned int sat_id, int id, | |||
105 | return NULL; | 93 | return NULL; |
106 | 94 | ||
107 | for (i = 0; i < len; i += 4) { | 95 | for (i = 0; i < len; i += 4) { |
108 | err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0xa, 4, data); | 96 | err = i2c_smbus_read_i2c_block_data(sat->i2c, 0xa, 4, data); |
109 | if (err < 0) { | 97 | if (err < 0) { |
110 | printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", | 98 | printk(KERN_ERR "smu_sat_get_sdb_part rd err %d\n", |
111 | err); | 99 | err); |
@@ -138,7 +126,7 @@ static int wf_sat_read_cache(struct wf_sat *sat) | |||
138 | { | 126 | { |
139 | int err; | 127 | int err; |
140 | 128 | ||
141 | err = i2c_smbus_read_i2c_block_data(&sat->i2c, 0x3f, 16, sat->cache); | 129 | err = i2c_smbus_read_i2c_block_data(sat->i2c, 0x3f, 16, sat->cache); |
142 | if (err < 0) | 130 | if (err < 0) |
143 | return err; | 131 | return err; |
144 | sat->last_read = jiffies; | 132 | sat->last_read = jiffies; |
@@ -161,7 +149,7 @@ static int wf_sat_get(struct wf_sensor *sr, s32 *value) | |||
161 | int i, err; | 149 | int i, err; |
162 | s32 val; | 150 | s32 val; |
163 | 151 | ||
164 | if (sat->i2c.adapter == NULL) | 152 | if (sat->i2c == NULL) |
165 | return -ENODEV; | 153 | return -ENODEV; |
166 | 154 | ||
167 | mutex_lock(&sat->mutex); | 155 | mutex_lock(&sat->mutex); |
@@ -193,10 +181,6 @@ static void wf_sat_release(struct wf_sensor *sr) | |||
193 | struct wf_sat *sat = sens->sat; | 181 | struct wf_sat *sat = sens->sat; |
194 | 182 | ||
195 | if (atomic_dec_and_test(&sat->refcnt)) { | 183 | if (atomic_dec_and_test(&sat->refcnt)) { |
196 | if (sat->i2c.adapter) { | ||
197 | i2c_detach_client(&sat->i2c); | ||
198 | sat->i2c.adapter = NULL; | ||
199 | } | ||
200 | if (sat->nr >= 0) | 184 | if (sat->nr >= 0) |
201 | sats[sat->nr] = NULL; | 185 | sats[sat->nr] = NULL; |
202 | kfree(sat); | 186 | kfree(sat); |
@@ -212,38 +196,58 @@ static struct wf_sensor_ops wf_sat_ops = { | |||
212 | 196 | ||
213 | static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) | 197 | static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) |
214 | { | 198 | { |
199 | struct i2c_board_info info; | ||
200 | struct i2c_client *client; | ||
201 | const u32 *reg; | ||
202 | u8 addr; | ||
203 | |||
204 | reg = of_get_property(dev, "reg", NULL); | ||
205 | if (reg == NULL) | ||
206 | return; | ||
207 | addr = *reg; | ||
208 | DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); | ||
209 | |||
210 | memset(&info, 0, sizeof(struct i2c_board_info)); | ||
211 | info.addr = (addr >> 1) & 0x7f; | ||
212 | info.platform_data = dev; | ||
213 | strlcpy(info.type, "wf_sat", I2C_NAME_SIZE); | ||
214 | |||
215 | client = i2c_new_device(adapter, &info); | ||
216 | if (client == NULL) { | ||
217 | printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | /* | ||
222 | * Let i2c-core delete that device on driver removal. | ||
223 | * This is safe because i2c-core holds the core_lock mutex for us. | ||
224 | */ | ||
225 | list_add_tail(&client->detected, &client->driver->clients); | ||
226 | } | ||
227 | |||
228 | static int wf_sat_probe(struct i2c_client *client, | ||
229 | const struct i2c_device_id *id) | ||
230 | { | ||
231 | struct device_node *dev = client->dev.platform_data; | ||
215 | struct wf_sat *sat; | 232 | struct wf_sat *sat; |
216 | struct wf_sat_sensor *sens; | 233 | struct wf_sat_sensor *sens; |
217 | const u32 *reg; | 234 | const u32 *reg; |
218 | const char *loc, *type; | 235 | const char *loc, *type; |
219 | u8 addr, chip, core; | 236 | u8 chip, core; |
220 | struct device_node *child; | 237 | struct device_node *child; |
221 | int shift, cpu, index; | 238 | int shift, cpu, index; |
222 | char *name; | 239 | char *name; |
223 | int vsens[2], isens[2]; | 240 | int vsens[2], isens[2]; |
224 | 241 | ||
225 | reg = of_get_property(dev, "reg", NULL); | ||
226 | if (reg == NULL) | ||
227 | return; | ||
228 | addr = *reg; | ||
229 | DBG(KERN_DEBUG "wf_sat: creating sat at address %x\n", addr); | ||
230 | |||
231 | sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL); | 242 | sat = kzalloc(sizeof(struct wf_sat), GFP_KERNEL); |
232 | if (sat == NULL) | 243 | if (sat == NULL) |
233 | return; | 244 | return -ENOMEM; |
234 | sat->nr = -1; | 245 | sat->nr = -1; |
235 | sat->node = of_node_get(dev); | 246 | sat->node = of_node_get(dev); |
236 | atomic_set(&sat->refcnt, 0); | 247 | atomic_set(&sat->refcnt, 0); |
237 | mutex_init(&sat->mutex); | 248 | mutex_init(&sat->mutex); |
238 | sat->i2c.addr = (addr >> 1) & 0x7f; | 249 | sat->i2c = client; |
239 | sat->i2c.adapter = adapter; | 250 | i2c_set_clientdata(client, sat); |
240 | sat->i2c.driver = &wf_sat_driver; | ||
241 | strncpy(sat->i2c.name, "smu-sat", I2C_NAME_SIZE-1); | ||
242 | |||
243 | if (i2c_attach_client(&sat->i2c)) { | ||
244 | printk(KERN_ERR "windfarm: failed to attach smu-sat to i2c\n"); | ||
245 | goto fail; | ||
246 | } | ||
247 | 251 | ||
248 | vsens[0] = vsens[1] = -1; | 252 | vsens[0] = vsens[1] = -1; |
249 | isens[0] = isens[1] = -1; | 253 | isens[0] = isens[1] = -1; |
@@ -344,10 +348,7 @@ static void wf_sat_create(struct i2c_adapter *adapter, struct device_node *dev) | |||
344 | if (sat->nr >= 0) | 348 | if (sat->nr >= 0) |
345 | sats[sat->nr] = sat; | 349 | sats[sat->nr] = sat; |
346 | 350 | ||
347 | return; | 351 | return 0; |
348 | |||
349 | fail: | ||
350 | kfree(sat); | ||
351 | } | 352 | } |
352 | 353 | ||
353 | static int wf_sat_attach(struct i2c_adapter *adapter) | 354 | static int wf_sat_attach(struct i2c_adapter *adapter) |
@@ -366,16 +367,32 @@ static int wf_sat_attach(struct i2c_adapter *adapter) | |||
366 | return 0; | 367 | return 0; |
367 | } | 368 | } |
368 | 369 | ||
369 | static int wf_sat_detach(struct i2c_client *client) | 370 | static int wf_sat_remove(struct i2c_client *client) |
370 | { | 371 | { |
371 | struct wf_sat *sat = i2c_to_sat(client); | 372 | struct wf_sat *sat = i2c_get_clientdata(client); |
372 | 373 | ||
373 | /* XXX TODO */ | 374 | /* XXX TODO */ |
374 | 375 | ||
375 | sat->i2c.adapter = NULL; | 376 | sat->i2c = NULL; |
377 | i2c_set_clientdata(client, NULL); | ||
376 | return 0; | 378 | return 0; |
377 | } | 379 | } |
378 | 380 | ||
381 | static const struct i2c_device_id wf_sat_id[] = { | ||
382 | { "wf_sat", 0 }, | ||
383 | { } | ||
384 | }; | ||
385 | |||
386 | static struct i2c_driver wf_sat_driver = { | ||
387 | .driver = { | ||
388 | .name = "wf_smu_sat", | ||
389 | }, | ||
390 | .attach_adapter = wf_sat_attach, | ||
391 | .probe = wf_sat_probe, | ||
392 | .remove = wf_sat_remove, | ||
393 | .id_table = wf_sat_id, | ||
394 | }; | ||
395 | |||
379 | static int __init sat_sensors_init(void) | 396 | static int __init sat_sensors_init(void) |
380 | { | 397 | { |
381 | return i2c_add_driver(&wf_sat_driver); | 398 | return i2c_add_driver(&wf_sat_driver); |
diff --git a/drivers/md/dm.c b/drivers/md/dm.c index 3fd8b1e65483..48db308fae67 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c | |||
@@ -19,7 +19,6 @@ | |||
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/idr.h> | 20 | #include <linux/idr.h> |
21 | #include <linux/hdreg.h> | 21 | #include <linux/hdreg.h> |
22 | #include <linux/blktrace_api.h> | ||
23 | 22 | ||
24 | #include <trace/events/block.h> | 23 | #include <trace/events/block.h> |
25 | 24 | ||
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig index 89fec052f3b4..9118613af321 100644 --- a/drivers/misc/eeprom/Kconfig +++ b/drivers/misc/eeprom/Kconfig | |||
@@ -48,6 +48,20 @@ config EEPROM_LEGACY | |||
48 | This driver can also be built as a module. If so, the module | 48 | This driver can also be built as a module. If so, the module |
49 | will be called eeprom. | 49 | will be called eeprom. |
50 | 50 | ||
51 | config EEPROM_MAX6875 | ||
52 | tristate "Maxim MAX6874/5 power supply supervisor" | ||
53 | depends on I2C && EXPERIMENTAL | ||
54 | help | ||
55 | If you say yes here you get read-only support for the user EEPROM of | ||
56 | the Maxim MAX6874/5 EEPROM-programmable, quad power-supply | ||
57 | sequencer/supervisor. | ||
58 | |||
59 | All other features of this chip should be accessed via i2c-dev. | ||
60 | |||
61 | This driver can also be built as a module. If so, the module | ||
62 | will be called max6875. | ||
63 | |||
64 | |||
51 | config EEPROM_93CX6 | 65 | config EEPROM_93CX6 |
52 | tristate "EEPROM 93CX6 support" | 66 | tristate "EEPROM 93CX6 support" |
53 | help | 67 | help |
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile index 539dd8f88128..df3d68ffa9d1 100644 --- a/drivers/misc/eeprom/Makefile +++ b/drivers/misc/eeprom/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_EEPROM_AT24) += at24.o | 1 | obj-$(CONFIG_EEPROM_AT24) += at24.o |
2 | obj-$(CONFIG_EEPROM_AT25) += at25.o | 2 | obj-$(CONFIG_EEPROM_AT25) += at25.o |
3 | obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o | 3 | obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o |
4 | obj-$(CONFIG_EEPROM_MAX6875) += max6875.o | ||
4 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o | 5 | obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o |
diff --git a/drivers/i2c/chips/max6875.c b/drivers/misc/eeprom/max6875.c index 033d9d81ec8a..3c0c58eed347 100644 --- a/drivers/i2c/chips/max6875.c +++ b/drivers/misc/eeprom/max6875.c | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> | 4 | Copyright (C) 2005 Ben Gardner <bgardner@wabtec.com> |
5 | 5 | ||
6 | Based on i2c/chips/eeprom.c | 6 | Based on eeprom.c |
7 | 7 | ||
8 | The MAX6875 has a bank of registers and two banks of EEPROM. | 8 | The MAX6875 has a bank of registers and two banks of EEPROM. |
9 | Address ranges are defined as follows: | 9 | Address ranges are defined as follows: |
diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 30900b30d532..2b38f39924a6 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c | |||
@@ -1648,7 +1648,7 @@ static int ps3_gelic_driver_probe(struct ps3_system_bus_device *dev) | |||
1648 | result = -ENOMEM; | 1648 | result = -ENOMEM; |
1649 | goto fail_alloc_card; | 1649 | goto fail_alloc_card; |
1650 | } | 1650 | } |
1651 | ps3_system_bus_set_driver_data(dev, card); | 1651 | ps3_system_bus_set_drvdata(dev, card); |
1652 | card->dev = dev; | 1652 | card->dev = dev; |
1653 | 1653 | ||
1654 | /* get internal vlan info */ | 1654 | /* get internal vlan info */ |
@@ -1749,7 +1749,7 @@ fail_alloc_irq: | |||
1749 | bus_id(card), | 1749 | bus_id(card), |
1750 | 0, 0); | 1750 | 0, 0); |
1751 | fail_status_indicator: | 1751 | fail_status_indicator: |
1752 | ps3_system_bus_set_driver_data(dev, NULL); | 1752 | ps3_system_bus_set_drvdata(dev, NULL); |
1753 | kfree(netdev_card(netdev)->unalign); | 1753 | kfree(netdev_card(netdev)->unalign); |
1754 | free_netdev(netdev); | 1754 | free_netdev(netdev); |
1755 | fail_alloc_card: | 1755 | fail_alloc_card: |
@@ -1766,7 +1766,7 @@ fail_open: | |||
1766 | 1766 | ||
1767 | static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) | 1767 | static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) |
1768 | { | 1768 | { |
1769 | struct gelic_card *card = ps3_system_bus_get_driver_data(dev); | 1769 | struct gelic_card *card = ps3_system_bus_get_drvdata(dev); |
1770 | struct net_device *netdev0; | 1770 | struct net_device *netdev0; |
1771 | pr_debug("%s: called\n", __func__); | 1771 | pr_debug("%s: called\n", __func__); |
1772 | 1772 | ||
@@ -1803,7 +1803,7 @@ static int ps3_gelic_driver_remove(struct ps3_system_bus_device *dev) | |||
1803 | kfree(netdev_card(netdev0)->unalign); | 1803 | kfree(netdev_card(netdev0)->unalign); |
1804 | free_netdev(netdev0); | 1804 | free_netdev(netdev0); |
1805 | 1805 | ||
1806 | ps3_system_bus_set_driver_data(dev, NULL); | 1806 | ps3_system_bus_set_drvdata(dev, NULL); |
1807 | 1807 | ||
1808 | ps3_dma_region_free(dev->d_region); | 1808 | ps3_dma_region_free(dev->d_region); |
1809 | 1809 | ||
diff --git a/drivers/ps3/ps3-sys-manager.c b/drivers/ps3/ps3-sys-manager.c index f17513dd9d4b..88cb74088611 100644 --- a/drivers/ps3/ps3-sys-manager.c +++ b/drivers/ps3/ps3-sys-manager.c | |||
@@ -706,7 +706,7 @@ static void ps3_sys_manager_work(struct ps3_system_bus_device *dev) | |||
706 | ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); | 706 | ps3_vuart_read_async(dev, PS3_SM_RX_MSG_LEN_MIN); |
707 | } | 707 | } |
708 | 708 | ||
709 | static int ps3_sys_manager_probe(struct ps3_system_bus_device *dev) | 709 | static int __devinit ps3_sys_manager_probe(struct ps3_system_bus_device *dev) |
710 | { | 710 | { |
711 | int result; | 711 | int result; |
712 | struct ps3_sys_manager_ops ops; | 712 | struct ps3_sys_manager_ops ops; |
diff --git a/drivers/ps3/ps3av.c b/drivers/ps3/ps3av.c index 235e87fcb49f..e82d8c9c6cda 100644 --- a/drivers/ps3/ps3av.c +++ b/drivers/ps3/ps3av.c | |||
@@ -80,12 +80,12 @@ static const struct avset_video_mode { | |||
80 | { 0, }, /* auto */ | 80 | { 0, }, /* auto */ |
81 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, | 81 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480I, A_N, 720, 480}, |
82 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, | 82 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_480P, A_N, 720, 480}, |
83 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_N, 1280, 720}, | 83 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_60HZ, A_W, 1280, 720}, |
84 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, | 84 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_60HZ, A_W, 1920, 1080}, |
85 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, | 85 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_60HZ, A_W, 1920, 1080}, |
86 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, | 86 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576I, A_N, 720, 576}, |
87 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, | 87 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_576P, A_N, 720, 576}, |
88 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_N, 1280, 720}, | 88 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_720P_50HZ, A_W, 1280, 720}, |
89 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, | 89 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080I_50HZ, A_W, 1920, 1080}, |
90 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, | 90 | {YUV444, XRGB, PS3AV_CMD_VIDEO_VID_1080P_50HZ, A_W, 1920, 1080}, |
91 | { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, | 91 | { RGB8, XRGB, PS3AV_CMD_VIDEO_VID_WXGA, A_W, 1280, 768}, |
@@ -937,7 +937,7 @@ int ps3av_audio_mute(int mute) | |||
937 | 937 | ||
938 | EXPORT_SYMBOL_GPL(ps3av_audio_mute); | 938 | EXPORT_SYMBOL_GPL(ps3av_audio_mute); |
939 | 939 | ||
940 | static int ps3av_probe(struct ps3_system_bus_device *dev) | 940 | static int __devinit ps3av_probe(struct ps3_system_bus_device *dev) |
941 | { | 941 | { |
942 | int res; | 942 | int res; |
943 | int id; | 943 | int id; |
@@ -1048,7 +1048,7 @@ static struct ps3_vuart_port_driver ps3av_driver = { | |||
1048 | .shutdown = ps3av_shutdown, | 1048 | .shutdown = ps3av_shutdown, |
1049 | }; | 1049 | }; |
1050 | 1050 | ||
1051 | static int ps3av_module_init(void) | 1051 | static int __init ps3av_module_init(void) |
1052 | { | 1052 | { |
1053 | int error; | 1053 | int error; |
1054 | 1054 | ||
diff --git a/drivers/ps3/ps3av_cmd.c b/drivers/ps3/ps3av_cmd.c index 716596e8e5b0..f555fedd5073 100644 --- a/drivers/ps3/ps3av_cmd.c +++ b/drivers/ps3/ps3av_cmd.c | |||
@@ -21,9 +21,10 @@ | |||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | |||
24 | #include <asm/ps3av.h> | 25 | #include <asm/ps3av.h> |
25 | #include <asm/ps3fb.h> | ||
26 | #include <asm/ps3.h> | 26 | #include <asm/ps3.h> |
27 | #include <asm/ps3gpu.h> | ||
27 | 28 | ||
28 | #include "vuart.h" | 29 | #include "vuart.h" |
29 | 30 | ||
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c index 442bb98a2821..e5b84db0aa03 100644 --- a/drivers/s390/block/dasd.c +++ b/drivers/s390/block/dasd.c | |||
@@ -5,8 +5,7 @@ | |||
5 | * Carsten Otte <Cotte@de.ibm.com> | 5 | * Carsten Otte <Cotte@de.ibm.com> |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Bugreports.to..: <Linux390@de.ibm.com> | 7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 | 8 | * Copyright IBM Corp. 1999, 2009 |
9 | * | ||
10 | */ | 9 | */ |
11 | 10 | ||
12 | #define KMSG_COMPONENT "dasd" | 11 | #define KMSG_COMPONENT "dasd" |
@@ -61,6 +60,7 @@ static int dasd_flush_block_queue(struct dasd_block *); | |||
61 | static void dasd_device_tasklet(struct dasd_device *); | 60 | static void dasd_device_tasklet(struct dasd_device *); |
62 | static void dasd_block_tasklet(struct dasd_block *); | 61 | static void dasd_block_tasklet(struct dasd_block *); |
63 | static void do_kick_device(struct work_struct *); | 62 | static void do_kick_device(struct work_struct *); |
63 | static void do_restore_device(struct work_struct *); | ||
64 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); | 64 | static void dasd_return_cqr_cb(struct dasd_ccw_req *, void *); |
65 | static void dasd_device_timeout(unsigned long); | 65 | static void dasd_device_timeout(unsigned long); |
66 | static void dasd_block_timeout(unsigned long); | 66 | static void dasd_block_timeout(unsigned long); |
@@ -109,6 +109,7 @@ struct dasd_device *dasd_alloc_device(void) | |||
109 | device->timer.function = dasd_device_timeout; | 109 | device->timer.function = dasd_device_timeout; |
110 | device->timer.data = (unsigned long) device; | 110 | device->timer.data = (unsigned long) device; |
111 | INIT_WORK(&device->kick_work, do_kick_device); | 111 | INIT_WORK(&device->kick_work, do_kick_device); |
112 | INIT_WORK(&device->restore_device, do_restore_device); | ||
112 | device->state = DASD_STATE_NEW; | 113 | device->state = DASD_STATE_NEW; |
113 | device->target = DASD_STATE_NEW; | 114 | device->target = DASD_STATE_NEW; |
114 | 115 | ||
@@ -512,6 +513,25 @@ void dasd_kick_device(struct dasd_device *device) | |||
512 | } | 513 | } |
513 | 514 | ||
514 | /* | 515 | /* |
516 | * dasd_restore_device will schedule a call do do_restore_device to the kernel | ||
517 | * event daemon. | ||
518 | */ | ||
519 | static void do_restore_device(struct work_struct *work) | ||
520 | { | ||
521 | struct dasd_device *device = container_of(work, struct dasd_device, | ||
522 | restore_device); | ||
523 | device->cdev->drv->restore(device->cdev); | ||
524 | dasd_put_device(device); | ||
525 | } | ||
526 | |||
527 | void dasd_restore_device(struct dasd_device *device) | ||
528 | { | ||
529 | dasd_get_device(device); | ||
530 | /* queue call to dasd_restore_device to the kernel event daemon. */ | ||
531 | schedule_work(&device->restore_device); | ||
532 | } | ||
533 | |||
534 | /* | ||
515 | * Set the target state for a device and starts the state change. | 535 | * Set the target state for a device and starts the state change. |
516 | */ | 536 | */ |
517 | void dasd_set_target_state(struct dasd_device *device, int target) | 537 | void dasd_set_target_state(struct dasd_device *device, int target) |
@@ -908,6 +928,12 @@ int dasd_start_IO(struct dasd_ccw_req *cqr) | |||
908 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | 928 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", |
909 | "start_IO: -EIO device gone, retry"); | 929 | "start_IO: -EIO device gone, retry"); |
910 | break; | 930 | break; |
931 | case -EINVAL: | ||
932 | /* most likely caused in power management context */ | ||
933 | DBF_DEV_EVENT(DBF_DEBUG, device, "%s", | ||
934 | "start_IO: -EINVAL device currently " | ||
935 | "not accessible"); | ||
936 | break; | ||
911 | default: | 937 | default: |
912 | /* internal error 11 - unknown rc */ | 938 | /* internal error 11 - unknown rc */ |
913 | snprintf(errorstring, ERRORLENGTH, "11 %d", rc); | 939 | snprintf(errorstring, ERRORLENGTH, "11 %d", rc); |
@@ -2400,6 +2426,12 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2400 | case CIO_OPER: | 2426 | case CIO_OPER: |
2401 | /* FIXME: add a sanity check. */ | 2427 | /* FIXME: add a sanity check. */ |
2402 | device->stopped &= ~DASD_STOPPED_DC_WAIT; | 2428 | device->stopped &= ~DASD_STOPPED_DC_WAIT; |
2429 | if (device->stopped & DASD_UNRESUMED_PM) { | ||
2430 | device->stopped &= ~DASD_UNRESUMED_PM; | ||
2431 | dasd_restore_device(device); | ||
2432 | ret = 1; | ||
2433 | break; | ||
2434 | } | ||
2403 | dasd_schedule_device_bh(device); | 2435 | dasd_schedule_device_bh(device); |
2404 | if (device->block) | 2436 | if (device->block) |
2405 | dasd_schedule_block_bh(device->block); | 2437 | dasd_schedule_block_bh(device->block); |
@@ -2410,6 +2442,79 @@ int dasd_generic_notify(struct ccw_device *cdev, int event) | |||
2410 | return ret; | 2442 | return ret; |
2411 | } | 2443 | } |
2412 | 2444 | ||
2445 | int dasd_generic_pm_freeze(struct ccw_device *cdev) | ||
2446 | { | ||
2447 | struct dasd_ccw_req *cqr, *n; | ||
2448 | int rc; | ||
2449 | struct list_head freeze_queue; | ||
2450 | struct dasd_device *device = dasd_device_from_cdev(cdev); | ||
2451 | |||
2452 | if (IS_ERR(device)) | ||
2453 | return PTR_ERR(device); | ||
2454 | /* disallow new I/O */ | ||
2455 | device->stopped |= DASD_STOPPED_PM; | ||
2456 | /* clear active requests */ | ||
2457 | INIT_LIST_HEAD(&freeze_queue); | ||
2458 | spin_lock_irq(get_ccwdev_lock(cdev)); | ||
2459 | rc = 0; | ||
2460 | list_for_each_entry_safe(cqr, n, &device->ccw_queue, devlist) { | ||
2461 | /* Check status and move request to flush_queue */ | ||
2462 | if (cqr->status == DASD_CQR_IN_IO) { | ||
2463 | rc = device->discipline->term_IO(cqr); | ||
2464 | if (rc) { | ||
2465 | /* unable to terminate requeust */ | ||
2466 | dev_err(&device->cdev->dev, | ||
2467 | "Unable to terminate request %p " | ||
2468 | "on suspend\n", cqr); | ||
2469 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
2470 | dasd_put_device(device); | ||
2471 | return rc; | ||
2472 | } | ||
2473 | } | ||
2474 | list_move_tail(&cqr->devlist, &freeze_queue); | ||
2475 | } | ||
2476 | |||
2477 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
2478 | |||
2479 | list_for_each_entry_safe(cqr, n, &freeze_queue, devlist) { | ||
2480 | wait_event(dasd_flush_wq, | ||
2481 | (cqr->status != DASD_CQR_CLEAR_PENDING)); | ||
2482 | if (cqr->status == DASD_CQR_CLEARED) | ||
2483 | cqr->status = DASD_CQR_QUEUED; | ||
2484 | } | ||
2485 | /* move freeze_queue to start of the ccw_queue */ | ||
2486 | spin_lock_irq(get_ccwdev_lock(cdev)); | ||
2487 | list_splice_tail(&freeze_queue, &device->ccw_queue); | ||
2488 | spin_unlock_irq(get_ccwdev_lock(cdev)); | ||
2489 | |||
2490 | if (device->discipline->freeze) | ||
2491 | rc = device->discipline->freeze(device); | ||
2492 | |||
2493 | dasd_put_device(device); | ||
2494 | return rc; | ||
2495 | } | ||
2496 | EXPORT_SYMBOL_GPL(dasd_generic_pm_freeze); | ||
2497 | |||
2498 | int dasd_generic_restore_device(struct ccw_device *cdev) | ||
2499 | { | ||
2500 | struct dasd_device *device = dasd_device_from_cdev(cdev); | ||
2501 | int rc = 0; | ||
2502 | |||
2503 | if (IS_ERR(device)) | ||
2504 | return PTR_ERR(device); | ||
2505 | |||
2506 | dasd_schedule_device_bh(device); | ||
2507 | if (device->block) | ||
2508 | dasd_schedule_block_bh(device->block); | ||
2509 | |||
2510 | if (device->discipline->restore) | ||
2511 | rc = device->discipline->restore(device); | ||
2512 | |||
2513 | dasd_put_device(device); | ||
2514 | return rc; | ||
2515 | } | ||
2516 | EXPORT_SYMBOL_GPL(dasd_generic_restore_device); | ||
2517 | |||
2413 | static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, | 2518 | static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, |
2414 | void *rdc_buffer, | 2519 | void *rdc_buffer, |
2415 | int rdc_buffer_size, | 2520 | int rdc_buffer_size, |
diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index e77666c8e6c0..4cac5b54f26a 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c | |||
@@ -1098,6 +1098,7 @@ dasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid) | |||
1098 | spin_unlock(&dasd_devmap_lock); | 1098 | spin_unlock(&dasd_devmap_lock); |
1099 | return 0; | 1099 | return 0; |
1100 | } | 1100 | } |
1101 | EXPORT_SYMBOL_GPL(dasd_get_uid); | ||
1101 | 1102 | ||
1102 | /* | 1103 | /* |
1103 | * Register the given device unique identifier into devmap struct. | 1104 | * Register the given device unique identifier into devmap struct. |
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index cf0cfdba1244..1c28ec3e4ccb 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c | |||
@@ -5,10 +5,9 @@ | |||
5 | * Carsten Otte <Cotte@de.ibm.com> | 5 | * Carsten Otte <Cotte@de.ibm.com> |
6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Bugreports.to..: <Linux390@de.ibm.com> | 7 | * Bugreports.to..: <Linux390@de.ibm.com> |
8 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 8 | * Copyright IBM Corp. 1999, 2009 |
9 | * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 | 9 | * EMC Symmetrix ioctl Copyright EMC Corporation, 2008 |
10 | * Author.........: Nigel Hislop <hislop_nigel@emc.com> | 10 | * Author.........: Nigel Hislop <hislop_nigel@emc.com> |
11 | * | ||
12 | */ | 11 | */ |
13 | 12 | ||
14 | #define KMSG_COMPONENT "dasd" | 13 | #define KMSG_COMPONENT "dasd" |
@@ -104,17 +103,6 @@ dasd_eckd_set_online(struct ccw_device *cdev) | |||
104 | return dasd_generic_set_online(cdev, &dasd_eckd_discipline); | 103 | return dasd_generic_set_online(cdev, &dasd_eckd_discipline); |
105 | } | 104 | } |
106 | 105 | ||
107 | static struct ccw_driver dasd_eckd_driver = { | ||
108 | .name = "dasd-eckd", | ||
109 | .owner = THIS_MODULE, | ||
110 | .ids = dasd_eckd_ids, | ||
111 | .probe = dasd_eckd_probe, | ||
112 | .remove = dasd_generic_remove, | ||
113 | .set_offline = dasd_generic_set_offline, | ||
114 | .set_online = dasd_eckd_set_online, | ||
115 | .notify = dasd_generic_notify, | ||
116 | }; | ||
117 | |||
118 | static const int sizes_trk0[] = { 28, 148, 84 }; | 106 | static const int sizes_trk0[] = { 28, 148, 84 }; |
119 | #define LABEL_SIZE 140 | 107 | #define LABEL_SIZE 140 |
120 | 108 | ||
@@ -3236,6 +3224,98 @@ static void dasd_eckd_dump_sense(struct dasd_device *device, | |||
3236 | dasd_eckd_dump_sense_ccw(device, req, irb); | 3224 | dasd_eckd_dump_sense_ccw(device, req, irb); |
3237 | } | 3225 | } |
3238 | 3226 | ||
3227 | int dasd_eckd_pm_freeze(struct dasd_device *device) | ||
3228 | { | ||
3229 | /* | ||
3230 | * the device should be disconnected from our LCU structure | ||
3231 | * on restore we will reconnect it and reread LCU specific | ||
3232 | * information like PAV support that might have changed | ||
3233 | */ | ||
3234 | dasd_alias_remove_device(device); | ||
3235 | dasd_alias_disconnect_device_from_lcu(device); | ||
3236 | |||
3237 | return 0; | ||
3238 | } | ||
3239 | |||
3240 | int dasd_eckd_restore_device(struct dasd_device *device) | ||
3241 | { | ||
3242 | struct dasd_eckd_private *private; | ||
3243 | int is_known, rc; | ||
3244 | struct dasd_uid temp_uid; | ||
3245 | |||
3246 | /* allow new IO again */ | ||
3247 | device->stopped &= ~DASD_STOPPED_PM; | ||
3248 | |||
3249 | private = (struct dasd_eckd_private *) device->private; | ||
3250 | |||
3251 | /* Read Configuration Data */ | ||
3252 | rc = dasd_eckd_read_conf(device); | ||
3253 | if (rc) | ||
3254 | goto out_err; | ||
3255 | |||
3256 | /* Generate device unique id and register in devmap */ | ||
3257 | rc = dasd_eckd_generate_uid(device, &private->uid); | ||
3258 | dasd_get_uid(device->cdev, &temp_uid); | ||
3259 | if (memcmp(&private->uid, &temp_uid, sizeof(struct dasd_uid)) != 0) | ||
3260 | dev_err(&device->cdev->dev, "The UID of the DASD has changed\n"); | ||
3261 | if (rc) | ||
3262 | goto out_err; | ||
3263 | dasd_set_uid(device->cdev, &private->uid); | ||
3264 | |||
3265 | /* register lcu with alias handling, enable PAV if this is a new lcu */ | ||
3266 | is_known = dasd_alias_make_device_known_to_lcu(device); | ||
3267 | if (is_known < 0) | ||
3268 | return is_known; | ||
3269 | if (!is_known) { | ||
3270 | /* new lcu found */ | ||
3271 | rc = dasd_eckd_validate_server(device); /* will switch pav on */ | ||
3272 | if (rc) | ||
3273 | goto out_err; | ||
3274 | } | ||
3275 | |||
3276 | /* Read Feature Codes */ | ||
3277 | rc = dasd_eckd_read_features(device); | ||
3278 | if (rc) | ||
3279 | goto out_err; | ||
3280 | |||
3281 | /* Read Device Characteristics */ | ||
3282 | memset(&private->rdc_data, 0, sizeof(private->rdc_data)); | ||
3283 | rc = dasd_generic_read_dev_chars(device, "ECKD", | ||
3284 | &private->rdc_data, 64); | ||
3285 | if (rc) { | ||
3286 | DBF_EVENT(DBF_WARNING, | ||
3287 | "Read device characteristics failed, rc=%d for " | ||
3288 | "device: %s", rc, dev_name(&device->cdev->dev)); | ||
3289 | goto out_err; | ||
3290 | } | ||
3291 | |||
3292 | /* add device to alias management */ | ||
3293 | dasd_alias_add_device(device); | ||
3294 | |||
3295 | return 0; | ||
3296 | |||
3297 | out_err: | ||
3298 | /* | ||
3299 | * if the resume failed for the DASD we put it in | ||
3300 | * an UNRESUMED stop state | ||
3301 | */ | ||
3302 | device->stopped |= DASD_UNRESUMED_PM; | ||
3303 | return 0; | ||
3304 | } | ||
3305 | |||
3306 | static struct ccw_driver dasd_eckd_driver = { | ||
3307 | .name = "dasd-eckd", | ||
3308 | .owner = THIS_MODULE, | ||
3309 | .ids = dasd_eckd_ids, | ||
3310 | .probe = dasd_eckd_probe, | ||
3311 | .remove = dasd_generic_remove, | ||
3312 | .set_offline = dasd_generic_set_offline, | ||
3313 | .set_online = dasd_eckd_set_online, | ||
3314 | .notify = dasd_generic_notify, | ||
3315 | .freeze = dasd_generic_pm_freeze, | ||
3316 | .thaw = dasd_generic_restore_device, | ||
3317 | .restore = dasd_generic_restore_device, | ||
3318 | }; | ||
3239 | 3319 | ||
3240 | /* | 3320 | /* |
3241 | * max_blocks is dependent on the amount of storage that is available | 3321 | * max_blocks is dependent on the amount of storage that is available |
@@ -3274,6 +3354,8 @@ static struct dasd_discipline dasd_eckd_discipline = { | |||
3274 | .dump_sense_dbf = dasd_eckd_dump_sense_dbf, | 3354 | .dump_sense_dbf = dasd_eckd_dump_sense_dbf, |
3275 | .fill_info = dasd_eckd_fill_info, | 3355 | .fill_info = dasd_eckd_fill_info, |
3276 | .ioctl = dasd_eckd_ioctl, | 3356 | .ioctl = dasd_eckd_ioctl, |
3357 | .freeze = dasd_eckd_pm_freeze, | ||
3358 | .restore = dasd_eckd_restore_device, | ||
3277 | }; | 3359 | }; |
3278 | 3360 | ||
3279 | static int __init | 3361 | static int __init |
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c index 597c6ffdb9f2..e21ee735f926 100644 --- a/drivers/s390/block/dasd_fba.c +++ b/drivers/s390/block/dasd_fba.c | |||
@@ -2,8 +2,7 @@ | |||
2 | * File...........: linux/drivers/s390/block/dasd_fba.c | 2 | * File...........: linux/drivers/s390/block/dasd_fba.c |
3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> | 3 | * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> |
4 | * Bugreports.to..: <Linux390@de.ibm.com> | 4 | * Bugreports.to..: <Linux390@de.ibm.com> |
5 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 5 | * Copyright IBM Corp. 1999, 2009 |
6 | * | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #define KMSG_COMPONENT "dasd" | 8 | #define KMSG_COMPONENT "dasd" |
@@ -75,6 +74,9 @@ static struct ccw_driver dasd_fba_driver = { | |||
75 | .set_offline = dasd_generic_set_offline, | 74 | .set_offline = dasd_generic_set_offline, |
76 | .set_online = dasd_fba_set_online, | 75 | .set_online = dasd_fba_set_online, |
77 | .notify = dasd_generic_notify, | 76 | .notify = dasd_generic_notify, |
77 | .freeze = dasd_generic_pm_freeze, | ||
78 | .thaw = dasd_generic_restore_device, | ||
79 | .restore = dasd_generic_restore_device, | ||
78 | }; | 80 | }; |
79 | 81 | ||
80 | static void | 82 | static void |
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h index f97ceb795078..fd63b2f2bda9 100644 --- a/drivers/s390/block/dasd_int.h +++ b/drivers/s390/block/dasd_int.h | |||
@@ -4,8 +4,7 @@ | |||
4 | * Horst Hummel <Horst.Hummel@de.ibm.com> | 4 | * Horst Hummel <Horst.Hummel@de.ibm.com> |
5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
6 | * Bugreports.to..: <Linux390@de.ibm.com> | 6 | * Bugreports.to..: <Linux390@de.ibm.com> |
7 | * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 | 7 | * Copyright IBM Corp. 1999, 2009 |
8 | * | ||
9 | */ | 8 | */ |
10 | 9 | ||
11 | #ifndef DASD_INT_H | 10 | #ifndef DASD_INT_H |
@@ -295,6 +294,10 @@ struct dasd_discipline { | |||
295 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); | 294 | int (*fill_geometry) (struct dasd_block *, struct hd_geometry *); |
296 | int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); | 295 | int (*fill_info) (struct dasd_device *, struct dasd_information2_t *); |
297 | int (*ioctl) (struct dasd_block *, unsigned int, void __user *); | 296 | int (*ioctl) (struct dasd_block *, unsigned int, void __user *); |
297 | |||
298 | /* suspend/resume functions */ | ||
299 | int (*freeze) (struct dasd_device *); | ||
300 | int (*restore) (struct dasd_device *); | ||
298 | }; | 301 | }; |
299 | 302 | ||
300 | extern struct dasd_discipline *dasd_diag_discipline_pointer; | 303 | extern struct dasd_discipline *dasd_diag_discipline_pointer; |
@@ -367,6 +370,7 @@ struct dasd_device { | |||
367 | atomic_t tasklet_scheduled; | 370 | atomic_t tasklet_scheduled; |
368 | struct tasklet_struct tasklet; | 371 | struct tasklet_struct tasklet; |
369 | struct work_struct kick_work; | 372 | struct work_struct kick_work; |
373 | struct work_struct restore_device; | ||
370 | struct timer_list timer; | 374 | struct timer_list timer; |
371 | 375 | ||
372 | debug_info_t *debug_area; | 376 | debug_info_t *debug_area; |
@@ -410,6 +414,8 @@ struct dasd_block { | |||
410 | #define DASD_STOPPED_PENDING 4 /* long busy */ | 414 | #define DASD_STOPPED_PENDING 4 /* long busy */ |
411 | #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ | 415 | #define DASD_STOPPED_DC_WAIT 8 /* disconnected, wait */ |
412 | #define DASD_STOPPED_SU 16 /* summary unit check handling */ | 416 | #define DASD_STOPPED_SU 16 /* summary unit check handling */ |
417 | #define DASD_STOPPED_PM 32 /* pm state transition */ | ||
418 | #define DASD_UNRESUMED_PM 64 /* pm resume failed state */ | ||
413 | 419 | ||
414 | /* per device flags */ | 420 | /* per device flags */ |
415 | #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ | 421 | #define DASD_FLAG_OFFLINE 3 /* device is in offline processing */ |
@@ -556,6 +562,7 @@ void dasd_free_block(struct dasd_block *); | |||
556 | void dasd_enable_device(struct dasd_device *); | 562 | void dasd_enable_device(struct dasd_device *); |
557 | void dasd_set_target_state(struct dasd_device *, int); | 563 | void dasd_set_target_state(struct dasd_device *, int); |
558 | void dasd_kick_device(struct dasd_device *); | 564 | void dasd_kick_device(struct dasd_device *); |
565 | void dasd_restore_device(struct dasd_device *); | ||
559 | 566 | ||
560 | void dasd_add_request_head(struct dasd_ccw_req *); | 567 | void dasd_add_request_head(struct dasd_ccw_req *); |
561 | void dasd_add_request_tail(struct dasd_ccw_req *); | 568 | void dasd_add_request_tail(struct dasd_ccw_req *); |
@@ -578,6 +585,8 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *); | |||
578 | int dasd_generic_set_offline (struct ccw_device *cdev); | 585 | int dasd_generic_set_offline (struct ccw_device *cdev); |
579 | int dasd_generic_notify(struct ccw_device *, int); | 586 | int dasd_generic_notify(struct ccw_device *, int); |
580 | void dasd_generic_handle_state_change(struct dasd_device *); | 587 | void dasd_generic_handle_state_change(struct dasd_device *); |
588 | int dasd_generic_pm_freeze(struct ccw_device *); | ||
589 | int dasd_generic_restore_device(struct ccw_device *); | ||
581 | 590 | ||
582 | int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); | 591 | int dasd_generic_read_dev_chars(struct dasd_device *, char *, void *, int); |
583 | char *dasd_get_sense(struct irb *); | 592 | char *dasd_get_sense(struct irb *); |
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index b21caf177e37..016f9e9d2591 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c | |||
@@ -14,10 +14,11 @@ | |||
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/blkdev.h> | 16 | #include <linux/blkdev.h> |
17 | #include <asm/extmem.h> | ||
18 | #include <asm/io.h> | ||
19 | #include <linux/completion.h> | 17 | #include <linux/completion.h> |
20 | #include <linux/interrupt.h> | 18 | #include <linux/interrupt.h> |
19 | #include <linux/platform_device.h> | ||
20 | #include <asm/extmem.h> | ||
21 | #include <asm/io.h> | ||
21 | 22 | ||
22 | #define DCSSBLK_NAME "dcssblk" | 23 | #define DCSSBLK_NAME "dcssblk" |
23 | #define DCSSBLK_MINORS_PER_DISK 1 | 24 | #define DCSSBLK_MINORS_PER_DISK 1 |
@@ -940,11 +941,94 @@ dcssblk_check_params(void) | |||
940 | } | 941 | } |
941 | 942 | ||
942 | /* | 943 | /* |
944 | * Suspend / Resume | ||
945 | */ | ||
946 | static int dcssblk_freeze(struct device *dev) | ||
947 | { | ||
948 | struct dcssblk_dev_info *dev_info; | ||
949 | int rc = 0; | ||
950 | |||
951 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
952 | switch (dev_info->segment_type) { | ||
953 | case SEG_TYPE_SR: | ||
954 | case SEG_TYPE_ER: | ||
955 | case SEG_TYPE_SC: | ||
956 | if (!dev_info->is_shared) | ||
957 | rc = -EINVAL; | ||
958 | break; | ||
959 | default: | ||
960 | rc = -EINVAL; | ||
961 | break; | ||
962 | } | ||
963 | if (rc) | ||
964 | break; | ||
965 | } | ||
966 | if (rc) | ||
967 | pr_err("Suspend failed because device %s is writeable.\n", | ||
968 | dev_info->segment_name); | ||
969 | return rc; | ||
970 | } | ||
971 | |||
972 | static int dcssblk_restore(struct device *dev) | ||
973 | { | ||
974 | struct dcssblk_dev_info *dev_info; | ||
975 | struct segment_info *entry; | ||
976 | unsigned long start, end; | ||
977 | int rc = 0; | ||
978 | |||
979 | list_for_each_entry(dev_info, &dcssblk_devices, lh) { | ||
980 | list_for_each_entry(entry, &dev_info->seg_list, lh) { | ||
981 | segment_unload(entry->segment_name); | ||
982 | rc = segment_load(entry->segment_name, SEGMENT_SHARED, | ||
983 | &start, &end); | ||
984 | if (rc < 0) { | ||
985 | // TODO in_use check ? | ||
986 | segment_warning(rc, entry->segment_name); | ||
987 | goto out_panic; | ||
988 | } | ||
989 | if (start != entry->start || end != entry->end) { | ||
990 | pr_err("Mismatch of start / end address after " | ||
991 | "resuming device %s\n", | ||
992 | entry->segment_name); | ||
993 | goto out_panic; | ||
994 | } | ||
995 | } | ||
996 | } | ||
997 | return 0; | ||
998 | out_panic: | ||
999 | panic("fatal dcssblk resume error\n"); | ||
1000 | } | ||
1001 | |||
1002 | static int dcssblk_thaw(struct device *dev) | ||
1003 | { | ||
1004 | return 0; | ||
1005 | } | ||
1006 | |||
1007 | static struct dev_pm_ops dcssblk_pm_ops = { | ||
1008 | .freeze = dcssblk_freeze, | ||
1009 | .thaw = dcssblk_thaw, | ||
1010 | .restore = dcssblk_restore, | ||
1011 | }; | ||
1012 | |||
1013 | static struct platform_driver dcssblk_pdrv = { | ||
1014 | .driver = { | ||
1015 | .name = "dcssblk", | ||
1016 | .owner = THIS_MODULE, | ||
1017 | .pm = &dcssblk_pm_ops, | ||
1018 | }, | ||
1019 | }; | ||
1020 | |||
1021 | static struct platform_device *dcssblk_pdev; | ||
1022 | |||
1023 | |||
1024 | /* | ||
943 | * The init/exit functions. | 1025 | * The init/exit functions. |
944 | */ | 1026 | */ |
945 | static void __exit | 1027 | static void __exit |
946 | dcssblk_exit(void) | 1028 | dcssblk_exit(void) |
947 | { | 1029 | { |
1030 | platform_device_unregister(dcssblk_pdev); | ||
1031 | platform_driver_unregister(&dcssblk_pdrv); | ||
948 | root_device_unregister(dcssblk_root_dev); | 1032 | root_device_unregister(dcssblk_root_dev); |
949 | unregister_blkdev(dcssblk_major, DCSSBLK_NAME); | 1033 | unregister_blkdev(dcssblk_major, DCSSBLK_NAME); |
950 | } | 1034 | } |
@@ -954,30 +1038,44 @@ dcssblk_init(void) | |||
954 | { | 1038 | { |
955 | int rc; | 1039 | int rc; |
956 | 1040 | ||
957 | dcssblk_root_dev = root_device_register("dcssblk"); | 1041 | rc = platform_driver_register(&dcssblk_pdrv); |
958 | if (IS_ERR(dcssblk_root_dev)) | 1042 | if (rc) |
959 | return PTR_ERR(dcssblk_root_dev); | ||
960 | rc = device_create_file(dcssblk_root_dev, &dev_attr_add); | ||
961 | if (rc) { | ||
962 | root_device_unregister(dcssblk_root_dev); | ||
963 | return rc; | 1043 | return rc; |
1044 | |||
1045 | dcssblk_pdev = platform_device_register_simple("dcssblk", -1, NULL, | ||
1046 | 0); | ||
1047 | if (IS_ERR(dcssblk_pdev)) { | ||
1048 | rc = PTR_ERR(dcssblk_pdev); | ||
1049 | goto out_pdrv; | ||
964 | } | 1050 | } |
965 | rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); | 1051 | |
966 | if (rc) { | 1052 | dcssblk_root_dev = root_device_register("dcssblk"); |
967 | root_device_unregister(dcssblk_root_dev); | 1053 | if (IS_ERR(dcssblk_root_dev)) { |
968 | return rc; | 1054 | rc = PTR_ERR(dcssblk_root_dev); |
1055 | goto out_pdev; | ||
969 | } | 1056 | } |
1057 | rc = device_create_file(dcssblk_root_dev, &dev_attr_add); | ||
1058 | if (rc) | ||
1059 | goto out_root; | ||
1060 | rc = device_create_file(dcssblk_root_dev, &dev_attr_remove); | ||
1061 | if (rc) | ||
1062 | goto out_root; | ||
970 | rc = register_blkdev(0, DCSSBLK_NAME); | 1063 | rc = register_blkdev(0, DCSSBLK_NAME); |
971 | if (rc < 0) { | 1064 | if (rc < 0) |
972 | root_device_unregister(dcssblk_root_dev); | 1065 | goto out_root; |
973 | return rc; | ||
974 | } | ||
975 | dcssblk_major = rc; | 1066 | dcssblk_major = rc; |
976 | init_rwsem(&dcssblk_devices_sem); | 1067 | init_rwsem(&dcssblk_devices_sem); |
977 | 1068 | ||
978 | dcssblk_check_params(); | 1069 | dcssblk_check_params(); |
979 | |||
980 | return 0; | 1070 | return 0; |
1071 | |||
1072 | out_root: | ||
1073 | root_device_unregister(dcssblk_root_dev); | ||
1074 | out_pdev: | ||
1075 | platform_device_unregister(dcssblk_pdev); | ||
1076 | out_pdrv: | ||
1077 | platform_driver_unregister(&dcssblk_pdrv); | ||
1078 | return rc; | ||
981 | } | 1079 | } |
982 | 1080 | ||
983 | module_init(dcssblk_init); | 1081 | module_init(dcssblk_init); |
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 0ae0c83ef879..2e9e1ecd6d82 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c | |||
@@ -39,7 +39,10 @@ | |||
39 | #include <linux/hdreg.h> /* HDIO_GETGEO */ | 39 | #include <linux/hdreg.h> /* HDIO_GETGEO */ |
40 | #include <linux/sysdev.h> | 40 | #include <linux/sysdev.h> |
41 | #include <linux/bio.h> | 41 | #include <linux/bio.h> |
42 | #include <linux/suspend.h> | ||
43 | #include <linux/platform_device.h> | ||
42 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
45 | #include <asm/checksum.h> | ||
43 | 46 | ||
44 | #define XPRAM_NAME "xpram" | 47 | #define XPRAM_NAME "xpram" |
45 | #define XPRAM_DEVS 1 /* one partition */ | 48 | #define XPRAM_DEVS 1 /* one partition */ |
@@ -48,6 +51,7 @@ | |||
48 | typedef struct { | 51 | typedef struct { |
49 | unsigned int size; /* size of xpram segment in pages */ | 52 | unsigned int size; /* size of xpram segment in pages */ |
50 | unsigned int offset; /* start page of xpram segment */ | 53 | unsigned int offset; /* start page of xpram segment */ |
54 | unsigned int csum; /* partition checksum for suspend */ | ||
51 | } xpram_device_t; | 55 | } xpram_device_t; |
52 | 56 | ||
53 | static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; | 57 | static xpram_device_t xpram_devices[XPRAM_MAX_DEVS]; |
@@ -138,7 +142,7 @@ static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index) | |||
138 | /* | 142 | /* |
139 | * Check if xpram is available. | 143 | * Check if xpram is available. |
140 | */ | 144 | */ |
141 | static int __init xpram_present(void) | 145 | static int xpram_present(void) |
142 | { | 146 | { |
143 | unsigned long mem_page; | 147 | unsigned long mem_page; |
144 | int rc; | 148 | int rc; |
@@ -154,7 +158,7 @@ static int __init xpram_present(void) | |||
154 | /* | 158 | /* |
155 | * Return index of the last available xpram page. | 159 | * Return index of the last available xpram page. |
156 | */ | 160 | */ |
157 | static unsigned long __init xpram_highest_page_index(void) | 161 | static unsigned long xpram_highest_page_index(void) |
158 | { | 162 | { |
159 | unsigned int page_index, add_bit; | 163 | unsigned int page_index, add_bit; |
160 | unsigned long mem_page; | 164 | unsigned long mem_page; |
@@ -383,6 +387,106 @@ out: | |||
383 | } | 387 | } |
384 | 388 | ||
385 | /* | 389 | /* |
390 | * Save checksums for all partitions. | ||
391 | */ | ||
392 | static int xpram_save_checksums(void) | ||
393 | { | ||
394 | unsigned long mem_page; | ||
395 | int rc, i; | ||
396 | |||
397 | rc = 0; | ||
398 | mem_page = (unsigned long) __get_free_page(GFP_KERNEL); | ||
399 | if (!mem_page) | ||
400 | return -ENOMEM; | ||
401 | for (i = 0; i < xpram_devs; i++) { | ||
402 | rc = xpram_page_in(mem_page, xpram_devices[i].offset); | ||
403 | if (rc) | ||
404 | goto fail; | ||
405 | xpram_devices[i].csum = csum_partial((const void *) mem_page, | ||
406 | PAGE_SIZE, 0); | ||
407 | } | ||
408 | fail: | ||
409 | free_page(mem_page); | ||
410 | return rc ? -ENXIO : 0; | ||
411 | } | ||
412 | |||
413 | /* | ||
414 | * Verify checksums for all partitions. | ||
415 | */ | ||
416 | static int xpram_validate_checksums(void) | ||
417 | { | ||
418 | unsigned long mem_page; | ||
419 | unsigned int csum; | ||
420 | int rc, i; | ||
421 | |||
422 | rc = 0; | ||
423 | mem_page = (unsigned long) __get_free_page(GFP_KERNEL); | ||
424 | if (!mem_page) | ||
425 | return -ENOMEM; | ||
426 | for (i = 0; i < xpram_devs; i++) { | ||
427 | rc = xpram_page_in(mem_page, xpram_devices[i].offset); | ||
428 | if (rc) | ||
429 | goto fail; | ||
430 | csum = csum_partial((const void *) mem_page, PAGE_SIZE, 0); | ||
431 | if (xpram_devices[i].csum != csum) { | ||
432 | rc = -EINVAL; | ||
433 | goto fail; | ||
434 | } | ||
435 | } | ||
436 | fail: | ||
437 | free_page(mem_page); | ||
438 | return rc ? -ENXIO : 0; | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Resume failed: Print error message and call panic. | ||
443 | */ | ||
444 | static void xpram_resume_error(const char *message) | ||
445 | { | ||
446 | pr_err("Resume error: %s\n", message); | ||
447 | panic("xpram resume error\n"); | ||
448 | } | ||
449 | |||
450 | /* | ||
451 | * Check if xpram setup changed between suspend and resume. | ||
452 | */ | ||
453 | static int xpram_restore(struct device *dev) | ||
454 | { | ||
455 | if (!xpram_pages) | ||
456 | return 0; | ||
457 | if (xpram_present() != 0) | ||
458 | xpram_resume_error("xpram disappeared"); | ||
459 | if (xpram_pages != xpram_highest_page_index() + 1) | ||
460 | xpram_resume_error("Size of xpram changed"); | ||
461 | if (xpram_validate_checksums()) | ||
462 | xpram_resume_error("Data of xpram changed"); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | /* | ||
467 | * Save necessary state in suspend. | ||
468 | */ | ||
469 | static int xpram_freeze(struct device *dev) | ||
470 | { | ||
471 | return xpram_save_checksums(); | ||
472 | } | ||
473 | |||
474 | static struct dev_pm_ops xpram_pm_ops = { | ||
475 | .freeze = xpram_freeze, | ||
476 | .restore = xpram_restore, | ||
477 | }; | ||
478 | |||
479 | static struct platform_driver xpram_pdrv = { | ||
480 | .driver = { | ||
481 | .name = XPRAM_NAME, | ||
482 | .owner = THIS_MODULE, | ||
483 | .pm = &xpram_pm_ops, | ||
484 | }, | ||
485 | }; | ||
486 | |||
487 | static struct platform_device *xpram_pdev; | ||
488 | |||
489 | /* | ||
386 | * Finally, the init/exit functions. | 490 | * Finally, the init/exit functions. |
387 | */ | 491 | */ |
388 | static void __exit xpram_exit(void) | 492 | static void __exit xpram_exit(void) |
@@ -394,6 +498,8 @@ static void __exit xpram_exit(void) | |||
394 | put_disk(xpram_disks[i]); | 498 | put_disk(xpram_disks[i]); |
395 | } | 499 | } |
396 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); | 500 | unregister_blkdev(XPRAM_MAJOR, XPRAM_NAME); |
501 | platform_device_unregister(xpram_pdev); | ||
502 | platform_driver_unregister(&xpram_pdrv); | ||
397 | } | 503 | } |
398 | 504 | ||
399 | static int __init xpram_init(void) | 505 | static int __init xpram_init(void) |
@@ -411,7 +517,24 @@ static int __init xpram_init(void) | |||
411 | rc = xpram_setup_sizes(xpram_pages); | 517 | rc = xpram_setup_sizes(xpram_pages); |
412 | if (rc) | 518 | if (rc) |
413 | return rc; | 519 | return rc; |
414 | return xpram_setup_blkdev(); | 520 | rc = platform_driver_register(&xpram_pdrv); |
521 | if (rc) | ||
522 | return rc; | ||
523 | xpram_pdev = platform_device_register_simple(XPRAM_NAME, -1, NULL, 0); | ||
524 | if (IS_ERR(xpram_pdev)) { | ||
525 | rc = PTR_ERR(xpram_pdev); | ||
526 | goto fail_platform_driver_unregister; | ||
527 | } | ||
528 | rc = xpram_setup_blkdev(); | ||
529 | if (rc) | ||
530 | goto fail_platform_device_unregister; | ||
531 | return 0; | ||
532 | |||
533 | fail_platform_device_unregister: | ||
534 | platform_device_unregister(xpram_pdev); | ||
535 | fail_platform_driver_unregister: | ||
536 | platform_driver_unregister(&xpram_pdrv); | ||
537 | return rc; | ||
415 | } | 538 | } |
416 | 539 | ||
417 | module_init(xpram_init); | 540 | module_init(xpram_init); |
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 9ab06e0dad40..b79f31add39c 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c | |||
@@ -1,14 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/con3215.c | 2 | * 3215 line mode terminal driver. |
3 | * 3215 line mode terminal driver. | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> |
7 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com), | ||
8 | * | 6 | * |
9 | * Updated: | 7 | * Updated: |
10 | * Aug-2000: Added tab support | 8 | * Aug-2000: Added tab support |
11 | * Dan Morrison, IBM Corporation (dmorriso@cse.buffalo.edu) | 9 | * Dan Morrison, IBM Corporation <dmorriso@cse.buffalo.edu> |
12 | */ | 10 | */ |
13 | 11 | ||
14 | #include <linux/module.h> | 12 | #include <linux/module.h> |
@@ -56,6 +54,7 @@ | |||
56 | #define RAW3215_CLOSING 32 /* set while in close process */ | 54 | #define RAW3215_CLOSING 32 /* set while in close process */ |
57 | #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ | 55 | #define RAW3215_TIMER_RUNS 64 /* set if the output delay timer is on */ |
58 | #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ | 56 | #define RAW3215_FLUSHING 128 /* set to flush buffer (no delay) */ |
57 | #define RAW3215_FROZEN 256 /* set if 3215 is frozen for suspend */ | ||
59 | 58 | ||
60 | #define TAB_STOP_SIZE 8 /* tab stop size */ | 59 | #define TAB_STOP_SIZE 8 /* tab stop size */ |
61 | 60 | ||
@@ -111,8 +110,8 @@ static struct tty_driver *tty3215_driver; | |||
111 | /* | 110 | /* |
112 | * Get a request structure from the free list | 111 | * Get a request structure from the free list |
113 | */ | 112 | */ |
114 | static inline struct raw3215_req * | 113 | static inline struct raw3215_req *raw3215_alloc_req(void) |
115 | raw3215_alloc_req(void) { | 114 | { |
116 | struct raw3215_req *req; | 115 | struct raw3215_req *req; |
117 | unsigned long flags; | 116 | unsigned long flags; |
118 | 117 | ||
@@ -126,8 +125,8 @@ raw3215_alloc_req(void) { | |||
126 | /* | 125 | /* |
127 | * Put a request structure back to the free list | 126 | * Put a request structure back to the free list |
128 | */ | 127 | */ |
129 | static inline void | 128 | static inline void raw3215_free_req(struct raw3215_req *req) |
130 | raw3215_free_req(struct raw3215_req *req) { | 129 | { |
131 | unsigned long flags; | 130 | unsigned long flags; |
132 | 131 | ||
133 | if (req->type == RAW3215_FREE) | 132 | if (req->type == RAW3215_FREE) |
@@ -145,8 +144,7 @@ raw3215_free_req(struct raw3215_req *req) { | |||
145 | * because a 3215 terminal won't accept a new read before the old one is | 144 | * because a 3215 terminal won't accept a new read before the old one is |
146 | * completed. | 145 | * completed. |
147 | */ | 146 | */ |
148 | static void | 147 | static void raw3215_mk_read_req(struct raw3215_info *raw) |
149 | raw3215_mk_read_req(struct raw3215_info *raw) | ||
150 | { | 148 | { |
151 | struct raw3215_req *req; | 149 | struct raw3215_req *req; |
152 | struct ccw1 *ccw; | 150 | struct ccw1 *ccw; |
@@ -174,8 +172,7 @@ raw3215_mk_read_req(struct raw3215_info *raw) | |||
174 | * buffer to the 3215 device. If a queued write exists it is replaced by | 172 | * buffer to the 3215 device. If a queued write exists it is replaced by |
175 | * the new, probably lengthened request. | 173 | * the new, probably lengthened request. |
176 | */ | 174 | */ |
177 | static void | 175 | static void raw3215_mk_write_req(struct raw3215_info *raw) |
178 | raw3215_mk_write_req(struct raw3215_info *raw) | ||
179 | { | 176 | { |
180 | struct raw3215_req *req; | 177 | struct raw3215_req *req; |
181 | struct ccw1 *ccw; | 178 | struct ccw1 *ccw; |
@@ -251,8 +248,7 @@ raw3215_mk_write_req(struct raw3215_info *raw) | |||
251 | /* | 248 | /* |
252 | * Start a read or a write request | 249 | * Start a read or a write request |
253 | */ | 250 | */ |
254 | static void | 251 | static void raw3215_start_io(struct raw3215_info *raw) |
255 | raw3215_start_io(struct raw3215_info *raw) | ||
256 | { | 252 | { |
257 | struct raw3215_req *req; | 253 | struct raw3215_req *req; |
258 | int res; | 254 | int res; |
@@ -290,8 +286,7 @@ raw3215_start_io(struct raw3215_info *raw) | |||
290 | /* | 286 | /* |
291 | * Function to start a delayed output after RAW3215_TIMEOUT seconds | 287 | * Function to start a delayed output after RAW3215_TIMEOUT seconds |
292 | */ | 288 | */ |
293 | static void | 289 | static void raw3215_timeout(unsigned long __data) |
294 | raw3215_timeout(unsigned long __data) | ||
295 | { | 290 | { |
296 | struct raw3215_info *raw = (struct raw3215_info *) __data; | 291 | struct raw3215_info *raw = (struct raw3215_info *) __data; |
297 | unsigned long flags; | 292 | unsigned long flags; |
@@ -300,8 +295,10 @@ raw3215_timeout(unsigned long __data) | |||
300 | if (raw->flags & RAW3215_TIMER_RUNS) { | 295 | if (raw->flags & RAW3215_TIMER_RUNS) { |
301 | del_timer(&raw->timer); | 296 | del_timer(&raw->timer); |
302 | raw->flags &= ~RAW3215_TIMER_RUNS; | 297 | raw->flags &= ~RAW3215_TIMER_RUNS; |
303 | raw3215_mk_write_req(raw); | 298 | if (!(raw->flags & RAW3215_FROZEN)) { |
304 | raw3215_start_io(raw); | 299 | raw3215_mk_write_req(raw); |
300 | raw3215_start_io(raw); | ||
301 | } | ||
305 | } | 302 | } |
306 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 303 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
307 | } | 304 | } |
@@ -312,10 +309,9 @@ raw3215_timeout(unsigned long __data) | |||
312 | * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not | 309 | * amount of data is bigger than RAW3215_MIN_WRITE. If a write is not |
313 | * done immediately a timer is started with a delay of RAW3215_TIMEOUT. | 310 | * done immediately a timer is started with a delay of RAW3215_TIMEOUT. |
314 | */ | 311 | */ |
315 | static inline void | 312 | static inline void raw3215_try_io(struct raw3215_info *raw) |
316 | raw3215_try_io(struct raw3215_info *raw) | ||
317 | { | 313 | { |
318 | if (!(raw->flags & RAW3215_ACTIVE)) | 314 | if (!(raw->flags & RAW3215_ACTIVE) || (raw->flags & RAW3215_FROZEN)) |
319 | return; | 315 | return; |
320 | if (raw->queued_read != NULL) | 316 | if (raw->queued_read != NULL) |
321 | raw3215_start_io(raw); | 317 | raw3215_start_io(raw); |
@@ -359,8 +355,8 @@ static void raw3215_next_io(struct raw3215_info *raw) | |||
359 | /* | 355 | /* |
360 | * Interrupt routine, called from common io layer | 356 | * Interrupt routine, called from common io layer |
361 | */ | 357 | */ |
362 | static void | 358 | static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm, |
363 | raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | 359 | struct irb *irb) |
364 | { | 360 | { |
365 | struct raw3215_info *raw; | 361 | struct raw3215_info *raw; |
366 | struct raw3215_req *req; | 362 | struct raw3215_req *req; |
@@ -459,14 +455,40 @@ raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb) | |||
459 | } | 455 | } |
460 | 456 | ||
461 | /* | 457 | /* |
458 | * Drop the oldest line from the output buffer. | ||
459 | */ | ||
460 | static void raw3215_drop_line(struct raw3215_info *raw) | ||
461 | { | ||
462 | int ix; | ||
463 | char ch; | ||
464 | |||
465 | BUG_ON(raw->written != 0); | ||
466 | ix = (raw->head - raw->count) & (RAW3215_BUFFER_SIZE - 1); | ||
467 | while (raw->count > 0) { | ||
468 | ch = raw->buffer[ix]; | ||
469 | ix = (ix + 1) & (RAW3215_BUFFER_SIZE - 1); | ||
470 | raw->count--; | ||
471 | if (ch == 0x15) | ||
472 | break; | ||
473 | } | ||
474 | raw->head = ix; | ||
475 | } | ||
476 | |||
477 | /* | ||
462 | * Wait until length bytes are available int the output buffer. | 478 | * Wait until length bytes are available int the output buffer. |
463 | * Has to be called with the s390irq lock held. Can be called | 479 | * Has to be called with the s390irq lock held. Can be called |
464 | * disabled. | 480 | * disabled. |
465 | */ | 481 | */ |
466 | static void | 482 | static void raw3215_make_room(struct raw3215_info *raw, unsigned int length) |
467 | raw3215_make_room(struct raw3215_info *raw, unsigned int length) | ||
468 | { | 483 | { |
469 | while (RAW3215_BUFFER_SIZE - raw->count < length) { | 484 | while (RAW3215_BUFFER_SIZE - raw->count < length) { |
485 | /* While console is frozen for suspend we have no other | ||
486 | * choice but to drop message from the buffer to make | ||
487 | * room for even more messages. */ | ||
488 | if (raw->flags & RAW3215_FROZEN) { | ||
489 | raw3215_drop_line(raw); | ||
490 | continue; | ||
491 | } | ||
470 | /* there might be a request pending */ | 492 | /* there might be a request pending */ |
471 | raw->flags |= RAW3215_FLUSHING; | 493 | raw->flags |= RAW3215_FLUSHING; |
472 | raw3215_mk_write_req(raw); | 494 | raw3215_mk_write_req(raw); |
@@ -488,8 +510,8 @@ raw3215_make_room(struct raw3215_info *raw, unsigned int length) | |||
488 | /* | 510 | /* |
489 | * String write routine for 3215 devices | 511 | * String write routine for 3215 devices |
490 | */ | 512 | */ |
491 | static void | 513 | static void raw3215_write(struct raw3215_info *raw, const char *str, |
492 | raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) | 514 | unsigned int length) |
493 | { | 515 | { |
494 | unsigned long flags; | 516 | unsigned long flags; |
495 | int c, count; | 517 | int c, count; |
@@ -529,8 +551,7 @@ raw3215_write(struct raw3215_info *raw, const char *str, unsigned int length) | |||
529 | /* | 551 | /* |
530 | * Put character routine for 3215 devices | 552 | * Put character routine for 3215 devices |
531 | */ | 553 | */ |
532 | static void | 554 | static void raw3215_putchar(struct raw3215_info *raw, unsigned char ch) |
533 | raw3215_putchar(struct raw3215_info *raw, unsigned char ch) | ||
534 | { | 555 | { |
535 | unsigned long flags; | 556 | unsigned long flags; |
536 | unsigned int length, i; | 557 | unsigned int length, i; |
@@ -566,8 +587,7 @@ raw3215_putchar(struct raw3215_info *raw, unsigned char ch) | |||
566 | * Flush routine, it simply sets the flush flag and tries to start | 587 | * Flush routine, it simply sets the flush flag and tries to start |
567 | * pending IO. | 588 | * pending IO. |
568 | */ | 589 | */ |
569 | static void | 590 | static void raw3215_flush_buffer(struct raw3215_info *raw) |
570 | raw3215_flush_buffer(struct raw3215_info *raw) | ||
571 | { | 591 | { |
572 | unsigned long flags; | 592 | unsigned long flags; |
573 | 593 | ||
@@ -583,8 +603,7 @@ raw3215_flush_buffer(struct raw3215_info *raw) | |||
583 | /* | 603 | /* |
584 | * Fire up a 3215 device. | 604 | * Fire up a 3215 device. |
585 | */ | 605 | */ |
586 | static int | 606 | static int raw3215_startup(struct raw3215_info *raw) |
587 | raw3215_startup(struct raw3215_info *raw) | ||
588 | { | 607 | { |
589 | unsigned long flags; | 608 | unsigned long flags; |
590 | 609 | ||
@@ -602,8 +621,7 @@ raw3215_startup(struct raw3215_info *raw) | |||
602 | /* | 621 | /* |
603 | * Shutdown a 3215 device. | 622 | * Shutdown a 3215 device. |
604 | */ | 623 | */ |
605 | static void | 624 | static void raw3215_shutdown(struct raw3215_info *raw) |
606 | raw3215_shutdown(struct raw3215_info *raw) | ||
607 | { | 625 | { |
608 | DECLARE_WAITQUEUE(wait, current); | 626 | DECLARE_WAITQUEUE(wait, current); |
609 | unsigned long flags; | 627 | unsigned long flags; |
@@ -628,8 +646,7 @@ raw3215_shutdown(struct raw3215_info *raw) | |||
628 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 646 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
629 | } | 647 | } |
630 | 648 | ||
631 | static int | 649 | static int raw3215_probe (struct ccw_device *cdev) |
632 | raw3215_probe (struct ccw_device *cdev) | ||
633 | { | 650 | { |
634 | struct raw3215_info *raw; | 651 | struct raw3215_info *raw; |
635 | int line; | 652 | int line; |
@@ -675,8 +692,7 @@ raw3215_probe (struct ccw_device *cdev) | |||
675 | return 0; | 692 | return 0; |
676 | } | 693 | } |
677 | 694 | ||
678 | static void | 695 | static void raw3215_remove (struct ccw_device *cdev) |
679 | raw3215_remove (struct ccw_device *cdev) | ||
680 | { | 696 | { |
681 | struct raw3215_info *raw; | 697 | struct raw3215_info *raw; |
682 | 698 | ||
@@ -689,8 +705,7 @@ raw3215_remove (struct ccw_device *cdev) | |||
689 | } | 705 | } |
690 | } | 706 | } |
691 | 707 | ||
692 | static int | 708 | static int raw3215_set_online (struct ccw_device *cdev) |
693 | raw3215_set_online (struct ccw_device *cdev) | ||
694 | { | 709 | { |
695 | struct raw3215_info *raw; | 710 | struct raw3215_info *raw; |
696 | 711 | ||
@@ -701,8 +716,7 @@ raw3215_set_online (struct ccw_device *cdev) | |||
701 | return raw3215_startup(raw); | 716 | return raw3215_startup(raw); |
702 | } | 717 | } |
703 | 718 | ||
704 | static int | 719 | static int raw3215_set_offline (struct ccw_device *cdev) |
705 | raw3215_set_offline (struct ccw_device *cdev) | ||
706 | { | 720 | { |
707 | struct raw3215_info *raw; | 721 | struct raw3215_info *raw; |
708 | 722 | ||
@@ -715,6 +729,36 @@ raw3215_set_offline (struct ccw_device *cdev) | |||
715 | return 0; | 729 | return 0; |
716 | } | 730 | } |
717 | 731 | ||
732 | static int raw3215_pm_stop(struct ccw_device *cdev) | ||
733 | { | ||
734 | struct raw3215_info *raw; | ||
735 | unsigned long flags; | ||
736 | |||
737 | /* Empty the output buffer, then prevent new I/O. */ | ||
738 | raw = cdev->dev.driver_data; | ||
739 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | ||
740 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); | ||
741 | raw->flags |= RAW3215_FROZEN; | ||
742 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | ||
743 | return 0; | ||
744 | } | ||
745 | |||
746 | static int raw3215_pm_start(struct ccw_device *cdev) | ||
747 | { | ||
748 | struct raw3215_info *raw; | ||
749 | unsigned long flags; | ||
750 | |||
751 | /* Allow I/O again and flush output buffer. */ | ||
752 | raw = cdev->dev.driver_data; | ||
753 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | ||
754 | raw->flags &= ~RAW3215_FROZEN; | ||
755 | raw->flags |= RAW3215_FLUSHING; | ||
756 | raw3215_try_io(raw); | ||
757 | raw->flags &= ~RAW3215_FLUSHING; | ||
758 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | ||
759 | return 0; | ||
760 | } | ||
761 | |||
718 | static struct ccw_device_id raw3215_id[] = { | 762 | static struct ccw_device_id raw3215_id[] = { |
719 | { CCW_DEVICE(0x3215, 0) }, | 763 | { CCW_DEVICE(0x3215, 0) }, |
720 | { /* end of list */ }, | 764 | { /* end of list */ }, |
@@ -728,14 +772,17 @@ static struct ccw_driver raw3215_ccw_driver = { | |||
728 | .remove = &raw3215_remove, | 772 | .remove = &raw3215_remove, |
729 | .set_online = &raw3215_set_online, | 773 | .set_online = &raw3215_set_online, |
730 | .set_offline = &raw3215_set_offline, | 774 | .set_offline = &raw3215_set_offline, |
775 | .freeze = &raw3215_pm_stop, | ||
776 | .thaw = &raw3215_pm_start, | ||
777 | .restore = &raw3215_pm_start, | ||
731 | }; | 778 | }; |
732 | 779 | ||
733 | #ifdef CONFIG_TN3215_CONSOLE | 780 | #ifdef CONFIG_TN3215_CONSOLE |
734 | /* | 781 | /* |
735 | * Write a string to the 3215 console | 782 | * Write a string to the 3215 console |
736 | */ | 783 | */ |
737 | static void | 784 | static void con3215_write(struct console *co, const char *str, |
738 | con3215_write(struct console *co, const char *str, unsigned int count) | 785 | unsigned int count) |
739 | { | 786 | { |
740 | struct raw3215_info *raw; | 787 | struct raw3215_info *raw; |
741 | int i; | 788 | int i; |
@@ -768,13 +815,17 @@ static struct tty_driver *con3215_device(struct console *c, int *index) | |||
768 | * panic() calls con3215_flush through a panic_notifier | 815 | * panic() calls con3215_flush through a panic_notifier |
769 | * before the system enters a disabled, endless loop. | 816 | * before the system enters a disabled, endless loop. |
770 | */ | 817 | */ |
771 | static void | 818 | static void con3215_flush(void) |
772 | con3215_flush(void) | ||
773 | { | 819 | { |
774 | struct raw3215_info *raw; | 820 | struct raw3215_info *raw; |
775 | unsigned long flags; | 821 | unsigned long flags; |
776 | 822 | ||
777 | raw = raw3215[0]; /* console 3215 is the first one */ | 823 | raw = raw3215[0]; /* console 3215 is the first one */ |
824 | if (raw->flags & RAW3215_FROZEN) | ||
825 | /* The console is still frozen for suspend. */ | ||
826 | if (ccw_device_force_console()) | ||
827 | /* Forcing didn't work, no panic message .. */ | ||
828 | return; | ||
778 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); | 829 | spin_lock_irqsave(get_ccwdev_lock(raw->cdev), flags); |
779 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); | 830 | raw3215_make_room(raw, RAW3215_BUFFER_SIZE); |
780 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); | 831 | spin_unlock_irqrestore(get_ccwdev_lock(raw->cdev), flags); |
@@ -811,8 +862,7 @@ static struct console con3215 = { | |||
811 | * 3215 console initialization code called from console_init(). | 862 | * 3215 console initialization code called from console_init(). |
812 | * NOTE: This is called before kmalloc is available. | 863 | * NOTE: This is called before kmalloc is available. |
813 | */ | 864 | */ |
814 | static int __init | 865 | static int __init con3215_init(void) |
815 | con3215_init(void) | ||
816 | { | 866 | { |
817 | struct ccw_device *cdev; | 867 | struct ccw_device *cdev; |
818 | struct raw3215_info *raw; | 868 | struct raw3215_info *raw; |
@@ -875,8 +925,7 @@ console_initcall(con3215_init); | |||
875 | * | 925 | * |
876 | * This routine is called whenever a 3215 tty is opened. | 926 | * This routine is called whenever a 3215 tty is opened. |
877 | */ | 927 | */ |
878 | static int | 928 | static int tty3215_open(struct tty_struct *tty, struct file * filp) |
879 | tty3215_open(struct tty_struct *tty, struct file * filp) | ||
880 | { | 929 | { |
881 | struct raw3215_info *raw; | 930 | struct raw3215_info *raw; |
882 | int retval, line; | 931 | int retval, line; |
@@ -909,8 +958,7 @@ tty3215_open(struct tty_struct *tty, struct file * filp) | |||
909 | * This routine is called when the 3215 tty is closed. We wait | 958 | * This routine is called when the 3215 tty is closed. We wait |
910 | * for the remaining request to be completed. Then we clean up. | 959 | * for the remaining request to be completed. Then we clean up. |
911 | */ | 960 | */ |
912 | static void | 961 | static void tty3215_close(struct tty_struct *tty, struct file * filp) |
913 | tty3215_close(struct tty_struct *tty, struct file * filp) | ||
914 | { | 962 | { |
915 | struct raw3215_info *raw; | 963 | struct raw3215_info *raw; |
916 | 964 | ||
@@ -927,8 +975,7 @@ tty3215_close(struct tty_struct *tty, struct file * filp) | |||
927 | /* | 975 | /* |
928 | * Returns the amount of free space in the output buffer. | 976 | * Returns the amount of free space in the output buffer. |
929 | */ | 977 | */ |
930 | static int | 978 | static int tty3215_write_room(struct tty_struct *tty) |
931 | tty3215_write_room(struct tty_struct *tty) | ||
932 | { | 979 | { |
933 | struct raw3215_info *raw; | 980 | struct raw3215_info *raw; |
934 | 981 | ||
@@ -944,9 +991,8 @@ tty3215_write_room(struct tty_struct *tty) | |||
944 | /* | 991 | /* |
945 | * String write routine for 3215 ttys | 992 | * String write routine for 3215 ttys |
946 | */ | 993 | */ |
947 | static int | 994 | static int tty3215_write(struct tty_struct * tty, |
948 | tty3215_write(struct tty_struct * tty, | 995 | const unsigned char *buf, int count) |
949 | const unsigned char *buf, int count) | ||
950 | { | 996 | { |
951 | struct raw3215_info *raw; | 997 | struct raw3215_info *raw; |
952 | 998 | ||
@@ -960,8 +1006,7 @@ tty3215_write(struct tty_struct * tty, | |||
960 | /* | 1006 | /* |
961 | * Put character routine for 3215 ttys | 1007 | * Put character routine for 3215 ttys |
962 | */ | 1008 | */ |
963 | static int | 1009 | static int tty3215_put_char(struct tty_struct *tty, unsigned char ch) |
964 | tty3215_put_char(struct tty_struct *tty, unsigned char ch) | ||
965 | { | 1010 | { |
966 | struct raw3215_info *raw; | 1011 | struct raw3215_info *raw; |
967 | 1012 | ||
@@ -972,16 +1017,14 @@ tty3215_put_char(struct tty_struct *tty, unsigned char ch) | |||
972 | return 1; | 1017 | return 1; |
973 | } | 1018 | } |
974 | 1019 | ||
975 | static void | 1020 | static void tty3215_flush_chars(struct tty_struct *tty) |
976 | tty3215_flush_chars(struct tty_struct *tty) | ||
977 | { | 1021 | { |
978 | } | 1022 | } |
979 | 1023 | ||
980 | /* | 1024 | /* |
981 | * Returns the number of characters in the output buffer | 1025 | * Returns the number of characters in the output buffer |
982 | */ | 1026 | */ |
983 | static int | 1027 | static int tty3215_chars_in_buffer(struct tty_struct *tty) |
984 | tty3215_chars_in_buffer(struct tty_struct *tty) | ||
985 | { | 1028 | { |
986 | struct raw3215_info *raw; | 1029 | struct raw3215_info *raw; |
987 | 1030 | ||
@@ -989,8 +1032,7 @@ tty3215_chars_in_buffer(struct tty_struct *tty) | |||
989 | return raw->count; | 1032 | return raw->count; |
990 | } | 1033 | } |
991 | 1034 | ||
992 | static void | 1035 | static void tty3215_flush_buffer(struct tty_struct *tty) |
993 | tty3215_flush_buffer(struct tty_struct *tty) | ||
994 | { | 1036 | { |
995 | struct raw3215_info *raw; | 1037 | struct raw3215_info *raw; |
996 | 1038 | ||
@@ -1002,9 +1044,8 @@ tty3215_flush_buffer(struct tty_struct *tty) | |||
1002 | /* | 1044 | /* |
1003 | * Currently we don't have any io controls for 3215 ttys | 1045 | * Currently we don't have any io controls for 3215 ttys |
1004 | */ | 1046 | */ |
1005 | static int | 1047 | static int tty3215_ioctl(struct tty_struct *tty, struct file * file, |
1006 | tty3215_ioctl(struct tty_struct *tty, struct file * file, | 1048 | unsigned int cmd, unsigned long arg) |
1007 | unsigned int cmd, unsigned long arg) | ||
1008 | { | 1049 | { |
1009 | if (tty->flags & (1 << TTY_IO_ERROR)) | 1050 | if (tty->flags & (1 << TTY_IO_ERROR)) |
1010 | return -EIO; | 1051 | return -EIO; |
@@ -1019,8 +1060,7 @@ tty3215_ioctl(struct tty_struct *tty, struct file * file, | |||
1019 | /* | 1060 | /* |
1020 | * Disable reading from a 3215 tty | 1061 | * Disable reading from a 3215 tty |
1021 | */ | 1062 | */ |
1022 | static void | 1063 | static void tty3215_throttle(struct tty_struct * tty) |
1023 | tty3215_throttle(struct tty_struct * tty) | ||
1024 | { | 1064 | { |
1025 | struct raw3215_info *raw; | 1065 | struct raw3215_info *raw; |
1026 | 1066 | ||
@@ -1031,8 +1071,7 @@ tty3215_throttle(struct tty_struct * tty) | |||
1031 | /* | 1071 | /* |
1032 | * Enable reading from a 3215 tty | 1072 | * Enable reading from a 3215 tty |
1033 | */ | 1073 | */ |
1034 | static void | 1074 | static void tty3215_unthrottle(struct tty_struct * tty) |
1035 | tty3215_unthrottle(struct tty_struct * tty) | ||
1036 | { | 1075 | { |
1037 | struct raw3215_info *raw; | 1076 | struct raw3215_info *raw; |
1038 | unsigned long flags; | 1077 | unsigned long flags; |
@@ -1049,8 +1088,7 @@ tty3215_unthrottle(struct tty_struct * tty) | |||
1049 | /* | 1088 | /* |
1050 | * Disable writing to a 3215 tty | 1089 | * Disable writing to a 3215 tty |
1051 | */ | 1090 | */ |
1052 | static void | 1091 | static void tty3215_stop(struct tty_struct *tty) |
1053 | tty3215_stop(struct tty_struct *tty) | ||
1054 | { | 1092 | { |
1055 | struct raw3215_info *raw; | 1093 | struct raw3215_info *raw; |
1056 | 1094 | ||
@@ -1061,8 +1099,7 @@ tty3215_stop(struct tty_struct *tty) | |||
1061 | /* | 1099 | /* |
1062 | * Enable writing to a 3215 tty | 1100 | * Enable writing to a 3215 tty |
1063 | */ | 1101 | */ |
1064 | static void | 1102 | static void tty3215_start(struct tty_struct *tty) |
1065 | tty3215_start(struct tty_struct *tty) | ||
1066 | { | 1103 | { |
1067 | struct raw3215_info *raw; | 1104 | struct raw3215_info *raw; |
1068 | unsigned long flags; | 1105 | unsigned long flags; |
@@ -1096,8 +1133,7 @@ static const struct tty_operations tty3215_ops = { | |||
1096 | * 3215 tty registration code called from tty_init(). | 1133 | * 3215 tty registration code called from tty_init(). |
1097 | * Most kernel services (incl. kmalloc) are available at this poimt. | 1134 | * Most kernel services (incl. kmalloc) are available at this poimt. |
1098 | */ | 1135 | */ |
1099 | static int __init | 1136 | static int __init tty3215_init(void) |
1100 | tty3215_init(void) | ||
1101 | { | 1137 | { |
1102 | struct tty_driver *driver; | 1138 | struct tty_driver *driver; |
1103 | int ret; | 1139 | int ret; |
@@ -1142,8 +1178,7 @@ tty3215_init(void) | |||
1142 | return 0; | 1178 | return 0; |
1143 | } | 1179 | } |
1144 | 1180 | ||
1145 | static void __exit | 1181 | static void __exit tty3215_exit(void) |
1146 | tty3215_exit(void) | ||
1147 | { | 1182 | { |
1148 | tty_unregister_driver(tty3215_driver); | 1183 | tty_unregister_driver(tty3215_driver); |
1149 | put_tty_driver(tty3215_driver); | 1184 | put_tty_driver(tty3215_driver); |
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c index ed5396dae58e..44d02e371c04 100644 --- a/drivers/s390/char/con3270.c +++ b/drivers/s390/char/con3270.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/con3270.c | 2 | * IBM/3270 Driver - console view. |
3 | * IBM/3270 Driver - console view. | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
@@ -530,6 +529,7 @@ con3270_flush(void) | |||
530 | cp = condev; | 529 | cp = condev; |
531 | if (!cp->view.dev) | 530 | if (!cp->view.dev) |
532 | return; | 531 | return; |
532 | raw3270_pm_unfreeze(&cp->view); | ||
533 | spin_lock_irqsave(&cp->view.lock, flags); | 533 | spin_lock_irqsave(&cp->view.lock, flags); |
534 | con3270_wait_write(cp); | 534 | con3270_wait_write(cp); |
535 | cp->nr_up = 0; | 535 | cp->nr_up = 0; |
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c index 40759c33477d..097d3846a828 100644 --- a/drivers/s390/char/fs3270.c +++ b/drivers/s390/char/fs3270.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/fs3270.c | 2 | * IBM/3270 Driver - fullscreen driver. |
3 | * IBM/3270 Driver - fullscreen driver. | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
@@ -399,6 +398,11 @@ fs3270_free_view(struct raw3270_view *view) | |||
399 | static void | 398 | static void |
400 | fs3270_release(struct raw3270_view *view) | 399 | fs3270_release(struct raw3270_view *view) |
401 | { | 400 | { |
401 | struct fs3270 *fp; | ||
402 | |||
403 | fp = (struct fs3270 *) view; | ||
404 | if (fp->fs_pid) | ||
405 | kill_pid(fp->fs_pid, SIGHUP, 1); | ||
402 | } | 406 | } |
403 | 407 | ||
404 | /* View to a 3270 device. Can be console, tty or fullscreen. */ | 408 | /* View to a 3270 device. Can be console, tty or fullscreen. */ |
diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index 97e63cf46944..75a8831eebbc 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c | |||
@@ -1,10 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/monreader.c | ||
3 | * | ||
4 | * Character device driver for reading z/VM *MONITOR service records. | 2 | * Character device driver for reading z/VM *MONITOR service records. |
5 | * | 3 | * |
6 | * Copyright IBM Corp. 2004, 2008 | 4 | * Copyright IBM Corp. 2004, 2009 |
7 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> | 5 | * |
6 | * Author: Gerald Schaefer <gerald.schaefer@de.ibm.com> | ||
8 | */ | 7 | */ |
9 | 8 | ||
10 | #define KMSG_COMPONENT "monreader" | 9 | #define KMSG_COMPONENT "monreader" |
@@ -22,6 +21,7 @@ | |||
22 | #include <linux/spinlock.h> | 21 | #include <linux/spinlock.h> |
23 | #include <linux/interrupt.h> | 22 | #include <linux/interrupt.h> |
24 | #include <linux/poll.h> | 23 | #include <linux/poll.h> |
24 | #include <linux/device.h> | ||
25 | #include <net/iucv/iucv.h> | 25 | #include <net/iucv/iucv.h> |
26 | #include <asm/uaccess.h> | 26 | #include <asm/uaccess.h> |
27 | #include <asm/ebcdic.h> | 27 | #include <asm/ebcdic.h> |
@@ -78,6 +78,7 @@ static u8 user_data_sever[16] = { | |||
78 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | 78 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static struct device *monreader_device; | ||
81 | 82 | ||
82 | /****************************************************************************** | 83 | /****************************************************************************** |
83 | * helper functions * | 84 | * helper functions * |
@@ -319,11 +320,12 @@ static int mon_open(struct inode *inode, struct file *filp) | |||
319 | goto out_path; | 320 | goto out_path; |
320 | } | 321 | } |
321 | filp->private_data = monpriv; | 322 | filp->private_data = monpriv; |
323 | monreader_device->driver_data = monpriv; | ||
322 | unlock_kernel(); | 324 | unlock_kernel(); |
323 | return nonseekable_open(inode, filp); | 325 | return nonseekable_open(inode, filp); |
324 | 326 | ||
325 | out_path: | 327 | out_path: |
326 | kfree(monpriv->path); | 328 | iucv_path_free(monpriv->path); |
327 | out_priv: | 329 | out_priv: |
328 | mon_free_mem(monpriv); | 330 | mon_free_mem(monpriv); |
329 | out_use: | 331 | out_use: |
@@ -341,10 +343,13 @@ static int mon_close(struct inode *inode, struct file *filp) | |||
341 | /* | 343 | /* |
342 | * Close IUCV connection and unregister | 344 | * Close IUCV connection and unregister |
343 | */ | 345 | */ |
344 | rc = iucv_path_sever(monpriv->path, user_data_sever); | 346 | if (monpriv->path) { |
345 | if (rc) | 347 | rc = iucv_path_sever(monpriv->path, user_data_sever); |
346 | pr_warning("Disconnecting the z/VM *MONITOR system service " | 348 | if (rc) |
347 | "failed with rc=%i\n", rc); | 349 | pr_warning("Disconnecting the z/VM *MONITOR system " |
350 | "service failed with rc=%i\n", rc); | ||
351 | iucv_path_free(monpriv->path); | ||
352 | } | ||
348 | 353 | ||
349 | atomic_set(&monpriv->iucv_severed, 0); | 354 | atomic_set(&monpriv->iucv_severed, 0); |
350 | atomic_set(&monpriv->iucv_connected, 0); | 355 | atomic_set(&monpriv->iucv_connected, 0); |
@@ -452,6 +457,94 @@ static struct miscdevice mon_dev = { | |||
452 | .minor = MISC_DYNAMIC_MINOR, | 457 | .minor = MISC_DYNAMIC_MINOR, |
453 | }; | 458 | }; |
454 | 459 | ||
460 | |||
461 | /****************************************************************************** | ||
462 | * suspend / resume * | ||
463 | *****************************************************************************/ | ||
464 | static int monreader_freeze(struct device *dev) | ||
465 | { | ||
466 | struct mon_private *monpriv = dev->driver_data; | ||
467 | int rc; | ||
468 | |||
469 | if (!monpriv) | ||
470 | return 0; | ||
471 | if (monpriv->path) { | ||
472 | rc = iucv_path_sever(monpriv->path, user_data_sever); | ||
473 | if (rc) | ||
474 | pr_warning("Disconnecting the z/VM *MONITOR system " | ||
475 | "service failed with rc=%i\n", rc); | ||
476 | iucv_path_free(monpriv->path); | ||
477 | } | ||
478 | atomic_set(&monpriv->iucv_severed, 0); | ||
479 | atomic_set(&monpriv->iucv_connected, 0); | ||
480 | atomic_set(&monpriv->read_ready, 0); | ||
481 | atomic_set(&monpriv->msglim_count, 0); | ||
482 | monpriv->write_index = 0; | ||
483 | monpriv->read_index = 0; | ||
484 | monpriv->path = NULL; | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int monreader_thaw(struct device *dev) | ||
489 | { | ||
490 | struct mon_private *monpriv = dev->driver_data; | ||
491 | int rc; | ||
492 | |||
493 | if (!monpriv) | ||
494 | return 0; | ||
495 | rc = -ENOMEM; | ||
496 | monpriv->path = iucv_path_alloc(MON_MSGLIM, IUCV_IPRMDATA, GFP_KERNEL); | ||
497 | if (!monpriv->path) | ||
498 | goto out; | ||
499 | rc = iucv_path_connect(monpriv->path, &monreader_iucv_handler, | ||
500 | MON_SERVICE, NULL, user_data_connect, monpriv); | ||
501 | if (rc) { | ||
502 | pr_err("Connecting to the z/VM *MONITOR system service " | ||
503 | "failed with rc=%i\n", rc); | ||
504 | goto out_path; | ||
505 | } | ||
506 | wait_event(mon_conn_wait_queue, | ||
507 | atomic_read(&monpriv->iucv_connected) || | ||
508 | atomic_read(&monpriv->iucv_severed)); | ||
509 | if (atomic_read(&monpriv->iucv_severed)) | ||
510 | goto out_path; | ||
511 | return 0; | ||
512 | out_path: | ||
513 | rc = -EIO; | ||
514 | iucv_path_free(monpriv->path); | ||
515 | monpriv->path = NULL; | ||
516 | out: | ||
517 | atomic_set(&monpriv->iucv_severed, 1); | ||
518 | return rc; | ||
519 | } | ||
520 | |||
521 | static int monreader_restore(struct device *dev) | ||
522 | { | ||
523 | int rc; | ||
524 | |||
525 | segment_unload(mon_dcss_name); | ||
526 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, | ||
527 | &mon_dcss_start, &mon_dcss_end); | ||
528 | if (rc < 0) { | ||
529 | segment_warning(rc, mon_dcss_name); | ||
530 | panic("fatal monreader resume error: no monitor dcss\n"); | ||
531 | } | ||
532 | return monreader_thaw(dev); | ||
533 | } | ||
534 | |||
535 | static struct dev_pm_ops monreader_pm_ops = { | ||
536 | .freeze = monreader_freeze, | ||
537 | .thaw = monreader_thaw, | ||
538 | .restore = monreader_restore, | ||
539 | }; | ||
540 | |||
541 | static struct device_driver monreader_driver = { | ||
542 | .name = "monreader", | ||
543 | .bus = &iucv_bus, | ||
544 | .pm = &monreader_pm_ops, | ||
545 | }; | ||
546 | |||
547 | |||
455 | /****************************************************************************** | 548 | /****************************************************************************** |
456 | * module init/exit * | 549 | * module init/exit * |
457 | *****************************************************************************/ | 550 | *****************************************************************************/ |
@@ -475,16 +568,33 @@ static int __init mon_init(void) | |||
475 | return rc; | 568 | return rc; |
476 | } | 569 | } |
477 | 570 | ||
571 | rc = driver_register(&monreader_driver); | ||
572 | if (rc) | ||
573 | goto out_iucv; | ||
574 | monreader_device = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
575 | if (!monreader_device) | ||
576 | goto out_driver; | ||
577 | dev_set_name(monreader_device, "monreader-dev"); | ||
578 | monreader_device->bus = &iucv_bus; | ||
579 | monreader_device->parent = iucv_root; | ||
580 | monreader_device->driver = &monreader_driver; | ||
581 | monreader_device->release = (void (*)(struct device *))kfree; | ||
582 | rc = device_register(monreader_device); | ||
583 | if (rc) { | ||
584 | kfree(monreader_device); | ||
585 | goto out_driver; | ||
586 | } | ||
587 | |||
478 | rc = segment_type(mon_dcss_name); | 588 | rc = segment_type(mon_dcss_name); |
479 | if (rc < 0) { | 589 | if (rc < 0) { |
480 | segment_warning(rc, mon_dcss_name); | 590 | segment_warning(rc, mon_dcss_name); |
481 | goto out_iucv; | 591 | goto out_device; |
482 | } | 592 | } |
483 | if (rc != SEG_TYPE_SC) { | 593 | if (rc != SEG_TYPE_SC) { |
484 | pr_err("The specified *MONITOR DCSS %s does not have the " | 594 | pr_err("The specified *MONITOR DCSS %s does not have the " |
485 | "required type SC\n", mon_dcss_name); | 595 | "required type SC\n", mon_dcss_name); |
486 | rc = -EINVAL; | 596 | rc = -EINVAL; |
487 | goto out_iucv; | 597 | goto out_device; |
488 | } | 598 | } |
489 | 599 | ||
490 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, | 600 | rc = segment_load(mon_dcss_name, SEGMENT_SHARED, |
@@ -492,7 +602,7 @@ static int __init mon_init(void) | |||
492 | if (rc < 0) { | 602 | if (rc < 0) { |
493 | segment_warning(rc, mon_dcss_name); | 603 | segment_warning(rc, mon_dcss_name); |
494 | rc = -EINVAL; | 604 | rc = -EINVAL; |
495 | goto out_iucv; | 605 | goto out_device; |
496 | } | 606 | } |
497 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); | 607 | dcss_mkname(mon_dcss_name, &user_data_connect[8]); |
498 | 608 | ||
@@ -503,6 +613,10 @@ static int __init mon_init(void) | |||
503 | 613 | ||
504 | out: | 614 | out: |
505 | segment_unload(mon_dcss_name); | 615 | segment_unload(mon_dcss_name); |
616 | out_device: | ||
617 | device_unregister(monreader_device); | ||
618 | out_driver: | ||
619 | driver_unregister(&monreader_driver); | ||
506 | out_iucv: | 620 | out_iucv: |
507 | iucv_unregister(&monreader_iucv_handler, 1); | 621 | iucv_unregister(&monreader_iucv_handler, 1); |
508 | return rc; | 622 | return rc; |
@@ -512,6 +626,8 @@ static void __exit mon_exit(void) | |||
512 | { | 626 | { |
513 | segment_unload(mon_dcss_name); | 627 | segment_unload(mon_dcss_name); |
514 | WARN_ON(misc_deregister(&mon_dev) != 0); | 628 | WARN_ON(misc_deregister(&mon_dev) != 0); |
629 | device_unregister(monreader_device); | ||
630 | driver_unregister(&monreader_driver); | ||
515 | iucv_unregister(&monreader_iucv_handler, 1); | 631 | iucv_unregister(&monreader_iucv_handler, 1); |
516 | return; | 632 | return; |
517 | } | 633 | } |
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index c7d7483bab9a..66fb8eba93f4 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/monwriter.c | ||
3 | * | ||
4 | * Character device driver for writing z/VM *MONITOR service records. | 2 | * Character device driver for writing z/VM *MONITOR service records. |
5 | * | 3 | * |
6 | * Copyright (C) IBM Corp. 2006 | 4 | * Copyright IBM Corp. 2006, 2009 |
7 | * | 5 | * |
8 | * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> | 6 | * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> |
9 | */ | 7 | */ |
@@ -22,6 +20,7 @@ | |||
22 | #include <linux/ctype.h> | 20 | #include <linux/ctype.h> |
23 | #include <linux/poll.h> | 21 | #include <linux/poll.h> |
24 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/platform_device.h> | ||
25 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
26 | #include <asm/ebcdic.h> | 25 | #include <asm/ebcdic.h> |
27 | #include <asm/io.h> | 26 | #include <asm/io.h> |
@@ -40,7 +39,10 @@ struct mon_buf { | |||
40 | char *data; | 39 | char *data; |
41 | }; | 40 | }; |
42 | 41 | ||
42 | static LIST_HEAD(mon_priv_list); | ||
43 | |||
43 | struct mon_private { | 44 | struct mon_private { |
45 | struct list_head priv_list; | ||
44 | struct list_head list; | 46 | struct list_head list; |
45 | struct monwrite_hdr hdr; | 47 | struct monwrite_hdr hdr; |
46 | size_t hdr_to_read; | 48 | size_t hdr_to_read; |
@@ -188,6 +190,7 @@ static int monwrite_open(struct inode *inode, struct file *filp) | |||
188 | monpriv->hdr_to_read = sizeof(monpriv->hdr); | 190 | monpriv->hdr_to_read = sizeof(monpriv->hdr); |
189 | mutex_init(&monpriv->thread_mutex); | 191 | mutex_init(&monpriv->thread_mutex); |
190 | filp->private_data = monpriv; | 192 | filp->private_data = monpriv; |
193 | list_add_tail(&monpriv->priv_list, &mon_priv_list); | ||
191 | unlock_kernel(); | 194 | unlock_kernel(); |
192 | return nonseekable_open(inode, filp); | 195 | return nonseekable_open(inode, filp); |
193 | } | 196 | } |
@@ -206,6 +209,7 @@ static int monwrite_close(struct inode *inode, struct file *filp) | |||
206 | kfree(entry->data); | 209 | kfree(entry->data); |
207 | kfree(entry); | 210 | kfree(entry); |
208 | } | 211 | } |
212 | list_del(&monpriv->priv_list); | ||
209 | kfree(monpriv); | 213 | kfree(monpriv); |
210 | return 0; | 214 | return 0; |
211 | } | 215 | } |
@@ -281,20 +285,102 @@ static struct miscdevice mon_dev = { | |||
281 | }; | 285 | }; |
282 | 286 | ||
283 | /* | 287 | /* |
288 | * suspend/resume | ||
289 | */ | ||
290 | |||
291 | static int monwriter_freeze(struct device *dev) | ||
292 | { | ||
293 | struct mon_private *monpriv; | ||
294 | struct mon_buf *monbuf; | ||
295 | |||
296 | list_for_each_entry(monpriv, &mon_priv_list, priv_list) { | ||
297 | list_for_each_entry(monbuf, &monpriv->list, list) { | ||
298 | if (monbuf->hdr.mon_function != MONWRITE_GEN_EVENT) | ||
299 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
300 | APPLDATA_STOP_REC); | ||
301 | } | ||
302 | } | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int monwriter_restore(struct device *dev) | ||
307 | { | ||
308 | struct mon_private *monpriv; | ||
309 | struct mon_buf *monbuf; | ||
310 | |||
311 | list_for_each_entry(monpriv, &mon_priv_list, priv_list) { | ||
312 | list_for_each_entry(monbuf, &monpriv->list, list) { | ||
313 | if (monbuf->hdr.mon_function == MONWRITE_START_INTERVAL) | ||
314 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
315 | APPLDATA_START_INTERVAL_REC); | ||
316 | if (monbuf->hdr.mon_function == MONWRITE_START_CONFIG) | ||
317 | monwrite_diag(&monbuf->hdr, monbuf->data, | ||
318 | APPLDATA_START_CONFIG_REC); | ||
319 | } | ||
320 | } | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int monwriter_thaw(struct device *dev) | ||
325 | { | ||
326 | return monwriter_restore(dev); | ||
327 | } | ||
328 | |||
329 | static struct dev_pm_ops monwriter_pm_ops = { | ||
330 | .freeze = monwriter_freeze, | ||
331 | .thaw = monwriter_thaw, | ||
332 | .restore = monwriter_restore, | ||
333 | }; | ||
334 | |||
335 | static struct platform_driver monwriter_pdrv = { | ||
336 | .driver = { | ||
337 | .name = "monwriter", | ||
338 | .owner = THIS_MODULE, | ||
339 | .pm = &monwriter_pm_ops, | ||
340 | }, | ||
341 | }; | ||
342 | |||
343 | static struct platform_device *monwriter_pdev; | ||
344 | |||
345 | /* | ||
284 | * module init/exit | 346 | * module init/exit |
285 | */ | 347 | */ |
286 | 348 | ||
287 | static int __init mon_init(void) | 349 | static int __init mon_init(void) |
288 | { | 350 | { |
289 | if (MACHINE_IS_VM) | 351 | int rc; |
290 | return misc_register(&mon_dev); | 352 | |
291 | else | 353 | if (!MACHINE_IS_VM) |
292 | return -ENODEV; | 354 | return -ENODEV; |
355 | |||
356 | rc = platform_driver_register(&monwriter_pdrv); | ||
357 | if (rc) | ||
358 | return rc; | ||
359 | |||
360 | monwriter_pdev = platform_device_register_simple("monwriter", -1, NULL, | ||
361 | 0); | ||
362 | if (IS_ERR(monwriter_pdev)) { | ||
363 | rc = PTR_ERR(monwriter_pdev); | ||
364 | goto out_driver; | ||
365 | } | ||
366 | |||
367 | rc = misc_register(&mon_dev); | ||
368 | if (rc) | ||
369 | goto out_device; | ||
370 | return 0; | ||
371 | |||
372 | out_device: | ||
373 | platform_device_unregister(monwriter_pdev); | ||
374 | out_driver: | ||
375 | platform_driver_unregister(&monwriter_pdrv); | ||
376 | return rc; | ||
293 | } | 377 | } |
294 | 378 | ||
295 | static void __exit mon_exit(void) | 379 | static void __exit mon_exit(void) |
296 | { | 380 | { |
297 | WARN_ON(misc_deregister(&mon_dev) != 0); | 381 | WARN_ON(misc_deregister(&mon_dev) != 0); |
382 | platform_device_unregister(monwriter_pdev); | ||
383 | platform_driver_unregister(&monwriter_pdrv); | ||
298 | } | 384 | } |
299 | 385 | ||
300 | module_init(mon_init); | 386 | module_init(mon_init); |
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c index 0b15cf107ec9..81c151b5f0ac 100644 --- a/drivers/s390/char/raw3270.c +++ b/drivers/s390/char/raw3270.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/raw3270.c | 2 | * IBM/3270 Driver - core functions. |
3 | * IBM/3270 Driver - core functions. | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/bootmem.h> | 10 | #include <linux/bootmem.h> |
@@ -61,6 +60,7 @@ struct raw3270 { | |||
61 | #define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ | 60 | #define RAW3270_FLAGS_ATTN 2 /* Device sent an ATTN interrupt */ |
62 | #define RAW3270_FLAGS_READY 4 /* Device is useable by views */ | 61 | #define RAW3270_FLAGS_READY 4 /* Device is useable by views */ |
63 | #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ | 62 | #define RAW3270_FLAGS_CONSOLE 8 /* Device is the console. */ |
63 | #define RAW3270_FLAGS_FROZEN 16 /* set if 3270 is frozen for suspend */ | ||
64 | 64 | ||
65 | /* Semaphore to protect global data of raw3270 (devices, views, etc). */ | 65 | /* Semaphore to protect global data of raw3270 (devices, views, etc). */ |
66 | static DEFINE_MUTEX(raw3270_mutex); | 66 | static DEFINE_MUTEX(raw3270_mutex); |
@@ -306,7 +306,8 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq) | |||
306 | 306 | ||
307 | spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); | 307 | spin_lock_irqsave(get_ccwdev_lock(view->dev->cdev), flags); |
308 | rp = view->dev; | 308 | rp = view->dev; |
309 | if (!rp || rp->view != view) | 309 | if (!rp || rp->view != view || |
310 | test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
310 | rc = -EACCES; | 311 | rc = -EACCES; |
311 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 312 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
312 | rc = -ENODEV; | 313 | rc = -ENODEV; |
@@ -323,7 +324,8 @@ raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq) | |||
323 | int rc; | 324 | int rc; |
324 | 325 | ||
325 | rp = view->dev; | 326 | rp = view->dev; |
326 | if (!rp || rp->view != view) | 327 | if (!rp || rp->view != view || |
328 | test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
327 | rc = -EACCES; | 329 | rc = -EACCES; |
328 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 330 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
329 | rc = -ENODEV; | 331 | rc = -ENODEV; |
@@ -764,7 +766,8 @@ raw3270_reset(struct raw3270_view *view) | |||
764 | int rc; | 766 | int rc; |
765 | 767 | ||
766 | rp = view->dev; | 768 | rp = view->dev; |
767 | if (!rp || rp->view != view) | 769 | if (!rp || rp->view != view || |
770 | test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
768 | rc = -EACCES; | 771 | rc = -EACCES; |
769 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 772 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
770 | rc = -ENODEV; | 773 | rc = -ENODEV; |
@@ -922,6 +925,8 @@ raw3270_activate_view(struct raw3270_view *view) | |||
922 | rc = 0; | 925 | rc = 0; |
923 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) | 926 | else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags)) |
924 | rc = -ENODEV; | 927 | rc = -ENODEV; |
928 | else if (test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
929 | rc = -EACCES; | ||
925 | else { | 930 | else { |
926 | oldview = NULL; | 931 | oldview = NULL; |
927 | if (rp->view) { | 932 | if (rp->view) { |
@@ -969,7 +974,8 @@ raw3270_deactivate_view(struct raw3270_view *view) | |||
969 | list_del_init(&view->list); | 974 | list_del_init(&view->list); |
970 | list_add_tail(&view->list, &rp->view_list); | 975 | list_add_tail(&view->list, &rp->view_list); |
971 | /* Try to activate another view. */ | 976 | /* Try to activate another view. */ |
972 | if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { | 977 | if (test_bit(RAW3270_FLAGS_READY, &rp->flags) && |
978 | !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { | ||
973 | list_for_each_entry(view, &rp->view_list, list) { | 979 | list_for_each_entry(view, &rp->view_list, list) { |
974 | rp->view = view; | 980 | rp->view = view; |
975 | if (view->fn->activate(view) == 0) | 981 | if (view->fn->activate(view) == 0) |
@@ -1068,7 +1074,8 @@ raw3270_del_view(struct raw3270_view *view) | |||
1068 | rp->view = NULL; | 1074 | rp->view = NULL; |
1069 | } | 1075 | } |
1070 | list_del_init(&view->list); | 1076 | list_del_init(&view->list); |
1071 | if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { | 1077 | if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags) && |
1078 | !test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) { | ||
1072 | /* Try to activate another view. */ | 1079 | /* Try to activate another view. */ |
1073 | list_for_each_entry(nv, &rp->view_list, list) { | 1080 | list_for_each_entry(nv, &rp->view_list, list) { |
1074 | if (nv->fn->activate(nv) == 0) { | 1081 | if (nv->fn->activate(nv) == 0) { |
@@ -1337,6 +1344,58 @@ raw3270_set_offline (struct ccw_device *cdev) | |||
1337 | return 0; | 1344 | return 0; |
1338 | } | 1345 | } |
1339 | 1346 | ||
1347 | static int raw3270_pm_stop(struct ccw_device *cdev) | ||
1348 | { | ||
1349 | struct raw3270 *rp; | ||
1350 | struct raw3270_view *view; | ||
1351 | unsigned long flags; | ||
1352 | |||
1353 | rp = cdev->dev.driver_data; | ||
1354 | if (!rp) | ||
1355 | return 0; | ||
1356 | spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); | ||
1357 | if (rp->view) | ||
1358 | rp->view->fn->deactivate(rp->view); | ||
1359 | if (!test_bit(RAW3270_FLAGS_CONSOLE, &rp->flags)) { | ||
1360 | /* | ||
1361 | * Release tty and fullscreen for all non-console | ||
1362 | * devices. | ||
1363 | */ | ||
1364 | list_for_each_entry(view, &rp->view_list, list) { | ||
1365 | if (view->fn->release) | ||
1366 | view->fn->release(view); | ||
1367 | } | ||
1368 | } | ||
1369 | set_bit(RAW3270_FLAGS_FROZEN, &rp->flags); | ||
1370 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | static int raw3270_pm_start(struct ccw_device *cdev) | ||
1375 | { | ||
1376 | struct raw3270 *rp; | ||
1377 | unsigned long flags; | ||
1378 | |||
1379 | rp = cdev->dev.driver_data; | ||
1380 | if (!rp) | ||
1381 | return 0; | ||
1382 | spin_lock_irqsave(get_ccwdev_lock(rp->cdev), flags); | ||
1383 | clear_bit(RAW3270_FLAGS_FROZEN, &rp->flags); | ||
1384 | if (rp->view) | ||
1385 | rp->view->fn->activate(rp->view); | ||
1386 | spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); | ||
1387 | return 0; | ||
1388 | } | ||
1389 | |||
1390 | void raw3270_pm_unfreeze(struct raw3270_view *view) | ||
1391 | { | ||
1392 | struct raw3270 *rp; | ||
1393 | |||
1394 | rp = view->dev; | ||
1395 | if (rp && test_bit(RAW3270_FLAGS_FROZEN, &rp->flags)) | ||
1396 | ccw_device_force_console(); | ||
1397 | } | ||
1398 | |||
1340 | static struct ccw_device_id raw3270_id[] = { | 1399 | static struct ccw_device_id raw3270_id[] = { |
1341 | { CCW_DEVICE(0x3270, 0) }, | 1400 | { CCW_DEVICE(0x3270, 0) }, |
1342 | { CCW_DEVICE(0x3271, 0) }, | 1401 | { CCW_DEVICE(0x3271, 0) }, |
@@ -1360,6 +1419,9 @@ static struct ccw_driver raw3270_ccw_driver = { | |||
1360 | .remove = &raw3270_remove, | 1419 | .remove = &raw3270_remove, |
1361 | .set_online = &raw3270_set_online, | 1420 | .set_online = &raw3270_set_online, |
1362 | .set_offline = &raw3270_set_offline, | 1421 | .set_offline = &raw3270_set_offline, |
1422 | .freeze = &raw3270_pm_stop, | ||
1423 | .thaw = &raw3270_pm_start, | ||
1424 | .restore = &raw3270_pm_start, | ||
1363 | }; | 1425 | }; |
1364 | 1426 | ||
1365 | static int | 1427 | static int |
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h index 90beaa80a782..ed34eb2199cc 100644 --- a/drivers/s390/char/raw3270.h +++ b/drivers/s390/char/raw3270.h | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/raw3270.h | 2 | * IBM/3270 Driver |
3 | * IBM/3270 Driver | ||
4 | * | 3 | * |
5 | * Author(s): | 4 | * Author(s): |
6 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) | 5 | * Original 3270 Code for 2.4 written by Richard Hitt (UTS Global) |
7 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> | 6 | * Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 7 | * Copyright IBM Corp. 2003, 2009 |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <asm/idals.h> | 10 | #include <asm/idals.h> |
@@ -195,6 +194,7 @@ void raw3270_wait_cons_dev(struct raw3270 *); | |||
195 | /* Notifier for device addition/removal */ | 194 | /* Notifier for device addition/removal */ |
196 | int raw3270_register_notifier(void (*notifier)(int, int)); | 195 | int raw3270_register_notifier(void (*notifier)(int, int)); |
197 | void raw3270_unregister_notifier(void (*notifier)(int, int)); | 196 | void raw3270_unregister_notifier(void (*notifier)(int, int)); |
197 | void raw3270_pm_unfreeze(struct raw3270_view *); | ||
198 | 198 | ||
199 | /* | 199 | /* |
200 | * Little memory allocator for string objects. | 200 | * Little memory allocator for string objects. |
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 4377e93a43d7..a983f5086788 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp.c | 2 | * core function to access sclp interface |
3 | * core function to access sclp interface | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/module.h> | 10 | #include <linux/module.h> |
@@ -16,6 +15,9 @@ | |||
16 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
17 | #include <linux/jiffies.h> | 16 | #include <linux/jiffies.h> |
18 | #include <linux/init.h> | 17 | #include <linux/init.h> |
18 | #include <linux/suspend.h> | ||
19 | #include <linux/completion.h> | ||
20 | #include <linux/platform_device.h> | ||
19 | #include <asm/types.h> | 21 | #include <asm/types.h> |
20 | #include <asm/s390_ext.h> | 22 | #include <asm/s390_ext.h> |
21 | 23 | ||
@@ -47,6 +49,16 @@ static struct sclp_req sclp_init_req; | |||
47 | static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | 49 | static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |
48 | static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); | 50 | static char sclp_init_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); |
49 | 51 | ||
52 | /* Suspend request */ | ||
53 | static DECLARE_COMPLETION(sclp_request_queue_flushed); | ||
54 | |||
55 | static void sclp_suspend_req_cb(struct sclp_req *req, void *data) | ||
56 | { | ||
57 | complete(&sclp_request_queue_flushed); | ||
58 | } | ||
59 | |||
60 | static struct sclp_req sclp_suspend_req; | ||
61 | |||
50 | /* Timer for request retries. */ | 62 | /* Timer for request retries. */ |
51 | static struct timer_list sclp_request_timer; | 63 | static struct timer_list sclp_request_timer; |
52 | 64 | ||
@@ -84,6 +96,12 @@ static volatile enum sclp_mask_state_t { | |||
84 | sclp_mask_state_initializing | 96 | sclp_mask_state_initializing |
85 | } sclp_mask_state = sclp_mask_state_idle; | 97 | } sclp_mask_state = sclp_mask_state_idle; |
86 | 98 | ||
99 | /* Internal state: is the driver suspended? */ | ||
100 | static enum sclp_suspend_state_t { | ||
101 | sclp_suspend_state_running, | ||
102 | sclp_suspend_state_suspended, | ||
103 | } sclp_suspend_state = sclp_suspend_state_running; | ||
104 | |||
87 | /* Maximum retry counts */ | 105 | /* Maximum retry counts */ |
88 | #define SCLP_INIT_RETRY 3 | 106 | #define SCLP_INIT_RETRY 3 |
89 | #define SCLP_MASK_RETRY 3 | 107 | #define SCLP_MASK_RETRY 3 |
@@ -211,6 +229,8 @@ sclp_process_queue(void) | |||
211 | del_timer(&sclp_request_timer); | 229 | del_timer(&sclp_request_timer); |
212 | while (!list_empty(&sclp_req_queue)) { | 230 | while (!list_empty(&sclp_req_queue)) { |
213 | req = list_entry(sclp_req_queue.next, struct sclp_req, list); | 231 | req = list_entry(sclp_req_queue.next, struct sclp_req, list); |
232 | if (!req->sccb) | ||
233 | goto do_post; | ||
214 | rc = __sclp_start_request(req); | 234 | rc = __sclp_start_request(req); |
215 | if (rc == 0) | 235 | if (rc == 0) |
216 | break; | 236 | break; |
@@ -222,6 +242,7 @@ sclp_process_queue(void) | |||
222 | sclp_request_timeout, 0); | 242 | sclp_request_timeout, 0); |
223 | break; | 243 | break; |
224 | } | 244 | } |
245 | do_post: | ||
225 | /* Post-processing for aborted request */ | 246 | /* Post-processing for aborted request */ |
226 | list_del(&req->list); | 247 | list_del(&req->list); |
227 | if (req->callback) { | 248 | if (req->callback) { |
@@ -233,6 +254,19 @@ sclp_process_queue(void) | |||
233 | spin_unlock_irqrestore(&sclp_lock, flags); | 254 | spin_unlock_irqrestore(&sclp_lock, flags); |
234 | } | 255 | } |
235 | 256 | ||
257 | static int __sclp_can_add_request(struct sclp_req *req) | ||
258 | { | ||
259 | if (req == &sclp_suspend_req || req == &sclp_init_req) | ||
260 | return 1; | ||
261 | if (sclp_suspend_state != sclp_suspend_state_running) | ||
262 | return 0; | ||
263 | if (sclp_init_state != sclp_init_state_initialized) | ||
264 | return 0; | ||
265 | if (sclp_activation_state != sclp_activation_state_active) | ||
266 | return 0; | ||
267 | return 1; | ||
268 | } | ||
269 | |||
236 | /* Queue a new request. Return zero on success, non-zero otherwise. */ | 270 | /* Queue a new request. Return zero on success, non-zero otherwise. */ |
237 | int | 271 | int |
238 | sclp_add_request(struct sclp_req *req) | 272 | sclp_add_request(struct sclp_req *req) |
@@ -241,9 +275,7 @@ sclp_add_request(struct sclp_req *req) | |||
241 | int rc; | 275 | int rc; |
242 | 276 | ||
243 | spin_lock_irqsave(&sclp_lock, flags); | 277 | spin_lock_irqsave(&sclp_lock, flags); |
244 | if ((sclp_init_state != sclp_init_state_initialized || | 278 | if (!__sclp_can_add_request(req)) { |
245 | sclp_activation_state != sclp_activation_state_active) && | ||
246 | req != &sclp_init_req) { | ||
247 | spin_unlock_irqrestore(&sclp_lock, flags); | 279 | spin_unlock_irqrestore(&sclp_lock, flags); |
248 | return -EIO; | 280 | return -EIO; |
249 | } | 281 | } |
@@ -254,10 +286,16 @@ sclp_add_request(struct sclp_req *req) | |||
254 | /* Start if request is first in list */ | 286 | /* Start if request is first in list */ |
255 | if (sclp_running_state == sclp_running_state_idle && | 287 | if (sclp_running_state == sclp_running_state_idle && |
256 | req->list.prev == &sclp_req_queue) { | 288 | req->list.prev == &sclp_req_queue) { |
289 | if (!req->sccb) { | ||
290 | list_del(&req->list); | ||
291 | rc = -ENODATA; | ||
292 | goto out; | ||
293 | } | ||
257 | rc = __sclp_start_request(req); | 294 | rc = __sclp_start_request(req); |
258 | if (rc) | 295 | if (rc) |
259 | list_del(&req->list); | 296 | list_del(&req->list); |
260 | } | 297 | } |
298 | out: | ||
261 | spin_unlock_irqrestore(&sclp_lock, flags); | 299 | spin_unlock_irqrestore(&sclp_lock, flags); |
262 | return rc; | 300 | return rc; |
263 | } | 301 | } |
@@ -560,6 +598,7 @@ sclp_register(struct sclp_register *reg) | |||
560 | /* Trigger initial state change callback */ | 598 | /* Trigger initial state change callback */ |
561 | reg->sclp_receive_mask = 0; | 599 | reg->sclp_receive_mask = 0; |
562 | reg->sclp_send_mask = 0; | 600 | reg->sclp_send_mask = 0; |
601 | reg->pm_event_posted = 0; | ||
563 | list_add(®->list, &sclp_reg_list); | 602 | list_add(®->list, &sclp_reg_list); |
564 | spin_unlock_irqrestore(&sclp_lock, flags); | 603 | spin_unlock_irqrestore(&sclp_lock, flags); |
565 | rc = sclp_init_mask(1); | 604 | rc = sclp_init_mask(1); |
@@ -880,20 +919,134 @@ static struct notifier_block sclp_reboot_notifier = { | |||
880 | .notifier_call = sclp_reboot_event | 919 | .notifier_call = sclp_reboot_event |
881 | }; | 920 | }; |
882 | 921 | ||
922 | /* | ||
923 | * Suspend/resume SCLP notifier implementation | ||
924 | */ | ||
925 | |||
926 | static void sclp_pm_event(enum sclp_pm_event sclp_pm_event, int rollback) | ||
927 | { | ||
928 | struct sclp_register *reg; | ||
929 | unsigned long flags; | ||
930 | |||
931 | if (!rollback) { | ||
932 | spin_lock_irqsave(&sclp_lock, flags); | ||
933 | list_for_each_entry(reg, &sclp_reg_list, list) | ||
934 | reg->pm_event_posted = 0; | ||
935 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
936 | } | ||
937 | do { | ||
938 | spin_lock_irqsave(&sclp_lock, flags); | ||
939 | list_for_each_entry(reg, &sclp_reg_list, list) { | ||
940 | if (rollback && reg->pm_event_posted) | ||
941 | goto found; | ||
942 | if (!rollback && !reg->pm_event_posted) | ||
943 | goto found; | ||
944 | } | ||
945 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
946 | return; | ||
947 | found: | ||
948 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
949 | if (reg->pm_event_fn) | ||
950 | reg->pm_event_fn(reg, sclp_pm_event); | ||
951 | reg->pm_event_posted = rollback ? 0 : 1; | ||
952 | } while (1); | ||
953 | } | ||
954 | |||
955 | /* | ||
956 | * Susend/resume callbacks for platform device | ||
957 | */ | ||
958 | |||
959 | static int sclp_freeze(struct device *dev) | ||
960 | { | ||
961 | unsigned long flags; | ||
962 | int rc; | ||
963 | |||
964 | sclp_pm_event(SCLP_PM_EVENT_FREEZE, 0); | ||
965 | |||
966 | spin_lock_irqsave(&sclp_lock, flags); | ||
967 | sclp_suspend_state = sclp_suspend_state_suspended; | ||
968 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
969 | |||
970 | /* Init supend data */ | ||
971 | memset(&sclp_suspend_req, 0, sizeof(sclp_suspend_req)); | ||
972 | sclp_suspend_req.callback = sclp_suspend_req_cb; | ||
973 | sclp_suspend_req.status = SCLP_REQ_FILLED; | ||
974 | init_completion(&sclp_request_queue_flushed); | ||
975 | |||
976 | rc = sclp_add_request(&sclp_suspend_req); | ||
977 | if (rc == 0) | ||
978 | wait_for_completion(&sclp_request_queue_flushed); | ||
979 | else if (rc != -ENODATA) | ||
980 | goto fail_thaw; | ||
981 | |||
982 | rc = sclp_deactivate(); | ||
983 | if (rc) | ||
984 | goto fail_thaw; | ||
985 | return 0; | ||
986 | |||
987 | fail_thaw: | ||
988 | spin_lock_irqsave(&sclp_lock, flags); | ||
989 | sclp_suspend_state = sclp_suspend_state_running; | ||
990 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
991 | sclp_pm_event(SCLP_PM_EVENT_THAW, 1); | ||
992 | return rc; | ||
993 | } | ||
994 | |||
995 | static int sclp_undo_suspend(enum sclp_pm_event event) | ||
996 | { | ||
997 | unsigned long flags; | ||
998 | int rc; | ||
999 | |||
1000 | rc = sclp_reactivate(); | ||
1001 | if (rc) | ||
1002 | return rc; | ||
1003 | |||
1004 | spin_lock_irqsave(&sclp_lock, flags); | ||
1005 | sclp_suspend_state = sclp_suspend_state_running; | ||
1006 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
1007 | |||
1008 | sclp_pm_event(event, 0); | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static int sclp_thaw(struct device *dev) | ||
1013 | { | ||
1014 | return sclp_undo_suspend(SCLP_PM_EVENT_THAW); | ||
1015 | } | ||
1016 | |||
1017 | static int sclp_restore(struct device *dev) | ||
1018 | { | ||
1019 | return sclp_undo_suspend(SCLP_PM_EVENT_RESTORE); | ||
1020 | } | ||
1021 | |||
1022 | static struct dev_pm_ops sclp_pm_ops = { | ||
1023 | .freeze = sclp_freeze, | ||
1024 | .thaw = sclp_thaw, | ||
1025 | .restore = sclp_restore, | ||
1026 | }; | ||
1027 | |||
1028 | static struct platform_driver sclp_pdrv = { | ||
1029 | .driver = { | ||
1030 | .name = "sclp", | ||
1031 | .owner = THIS_MODULE, | ||
1032 | .pm = &sclp_pm_ops, | ||
1033 | }, | ||
1034 | }; | ||
1035 | |||
1036 | static struct platform_device *sclp_pdev; | ||
1037 | |||
883 | /* Initialize SCLP driver. Return zero if driver is operational, non-zero | 1038 | /* Initialize SCLP driver. Return zero if driver is operational, non-zero |
884 | * otherwise. */ | 1039 | * otherwise. */ |
885 | static int | 1040 | static int |
886 | sclp_init(void) | 1041 | sclp_init(void) |
887 | { | 1042 | { |
888 | unsigned long flags; | 1043 | unsigned long flags; |
889 | int rc; | 1044 | int rc = 0; |
890 | 1045 | ||
891 | spin_lock_irqsave(&sclp_lock, flags); | 1046 | spin_lock_irqsave(&sclp_lock, flags); |
892 | /* Check for previous or running initialization */ | 1047 | /* Check for previous or running initialization */ |
893 | if (sclp_init_state != sclp_init_state_uninitialized) { | 1048 | if (sclp_init_state != sclp_init_state_uninitialized) |
894 | spin_unlock_irqrestore(&sclp_lock, flags); | 1049 | goto fail_unlock; |
895 | return 0; | ||
896 | } | ||
897 | sclp_init_state = sclp_init_state_initializing; | 1050 | sclp_init_state = sclp_init_state_initializing; |
898 | /* Set up variables */ | 1051 | /* Set up variables */ |
899 | INIT_LIST_HEAD(&sclp_req_queue); | 1052 | INIT_LIST_HEAD(&sclp_req_queue); |
@@ -904,27 +1057,17 @@ sclp_init(void) | |||
904 | spin_unlock_irqrestore(&sclp_lock, flags); | 1057 | spin_unlock_irqrestore(&sclp_lock, flags); |
905 | rc = sclp_check_interface(); | 1058 | rc = sclp_check_interface(); |
906 | spin_lock_irqsave(&sclp_lock, flags); | 1059 | spin_lock_irqsave(&sclp_lock, flags); |
907 | if (rc) { | 1060 | if (rc) |
908 | sclp_init_state = sclp_init_state_uninitialized; | 1061 | goto fail_init_state_uninitialized; |
909 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
910 | return rc; | ||
911 | } | ||
912 | /* Register reboot handler */ | 1062 | /* Register reboot handler */ |
913 | rc = register_reboot_notifier(&sclp_reboot_notifier); | 1063 | rc = register_reboot_notifier(&sclp_reboot_notifier); |
914 | if (rc) { | 1064 | if (rc) |
915 | sclp_init_state = sclp_init_state_uninitialized; | 1065 | goto fail_init_state_uninitialized; |
916 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
917 | return rc; | ||
918 | } | ||
919 | /* Register interrupt handler */ | 1066 | /* Register interrupt handler */ |
920 | rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, | 1067 | rc = register_early_external_interrupt(0x2401, sclp_interrupt_handler, |
921 | &ext_int_info_hwc); | 1068 | &ext_int_info_hwc); |
922 | if (rc) { | 1069 | if (rc) |
923 | unregister_reboot_notifier(&sclp_reboot_notifier); | 1070 | goto fail_unregister_reboot_notifier; |
924 | sclp_init_state = sclp_init_state_uninitialized; | ||
925 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
926 | return rc; | ||
927 | } | ||
928 | sclp_init_state = sclp_init_state_initialized; | 1071 | sclp_init_state = sclp_init_state_initialized; |
929 | spin_unlock_irqrestore(&sclp_lock, flags); | 1072 | spin_unlock_irqrestore(&sclp_lock, flags); |
930 | /* Enable service-signal external interruption - needs to happen with | 1073 | /* Enable service-signal external interruption - needs to happen with |
@@ -932,11 +1075,56 @@ sclp_init(void) | |||
932 | ctl_set_bit(0, 9); | 1075 | ctl_set_bit(0, 9); |
933 | sclp_init_mask(1); | 1076 | sclp_init_mask(1); |
934 | return 0; | 1077 | return 0; |
1078 | |||
1079 | fail_unregister_reboot_notifier: | ||
1080 | unregister_reboot_notifier(&sclp_reboot_notifier); | ||
1081 | fail_init_state_uninitialized: | ||
1082 | sclp_init_state = sclp_init_state_uninitialized; | ||
1083 | fail_unlock: | ||
1084 | spin_unlock_irqrestore(&sclp_lock, flags); | ||
1085 | return rc; | ||
935 | } | 1086 | } |
936 | 1087 | ||
1088 | /* | ||
1089 | * SCLP panic notifier: If we are suspended, we thaw SCLP in order to be able | ||
1090 | * to print the panic message. | ||
1091 | */ | ||
1092 | static int sclp_panic_notify(struct notifier_block *self, | ||
1093 | unsigned long event, void *data) | ||
1094 | { | ||
1095 | if (sclp_suspend_state == sclp_suspend_state_suspended) | ||
1096 | sclp_undo_suspend(SCLP_PM_EVENT_THAW); | ||
1097 | return NOTIFY_OK; | ||
1098 | } | ||
1099 | |||
1100 | static struct notifier_block sclp_on_panic_nb = { | ||
1101 | .notifier_call = sclp_panic_notify, | ||
1102 | .priority = SCLP_PANIC_PRIO, | ||
1103 | }; | ||
1104 | |||
937 | static __init int sclp_initcall(void) | 1105 | static __init int sclp_initcall(void) |
938 | { | 1106 | { |
1107 | int rc; | ||
1108 | |||
1109 | rc = platform_driver_register(&sclp_pdrv); | ||
1110 | if (rc) | ||
1111 | return rc; | ||
1112 | sclp_pdev = platform_device_register_simple("sclp", -1, NULL, 0); | ||
1113 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | ||
1114 | if (rc) | ||
1115 | goto fail_platform_driver_unregister; | ||
1116 | rc = atomic_notifier_chain_register(&panic_notifier_list, | ||
1117 | &sclp_on_panic_nb); | ||
1118 | if (rc) | ||
1119 | goto fail_platform_device_unregister; | ||
1120 | |||
939 | return sclp_init(); | 1121 | return sclp_init(); |
1122 | |||
1123 | fail_platform_device_unregister: | ||
1124 | platform_device_unregister(sclp_pdev); | ||
1125 | fail_platform_driver_unregister: | ||
1126 | platform_driver_unregister(&sclp_pdrv); | ||
1127 | return rc; | ||
940 | } | 1128 | } |
941 | 1129 | ||
942 | arch_initcall(sclp_initcall); | 1130 | arch_initcall(sclp_initcall); |
diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index bac80e856f97..60e7cb07095b 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h | |||
@@ -1,10 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp.h | 2 | * Copyright IBM Corp. 1999, 2009 |
3 | * | 3 | * |
4 | * S390 version | 4 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
5 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | ||
7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
8 | */ | 6 | */ |
9 | 7 | ||
10 | #ifndef __SCLP_H__ | 8 | #ifndef __SCLP_H__ |
@@ -17,7 +15,7 @@ | |||
17 | 15 | ||
18 | /* maximum number of pages concerning our own memory management */ | 16 | /* maximum number of pages concerning our own memory management */ |
19 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) | 17 | #define MAX_KMEM_PAGES (sizeof(unsigned long) << 3) |
20 | #define MAX_CONSOLE_PAGES 4 | 18 | #define MAX_CONSOLE_PAGES 6 |
21 | 19 | ||
22 | #define EVTYP_OPCMD 0x01 | 20 | #define EVTYP_OPCMD 0x01 |
23 | #define EVTYP_MSG 0x02 | 21 | #define EVTYP_MSG 0x02 |
@@ -68,6 +66,15 @@ typedef unsigned int sclp_cmdw_t; | |||
68 | 66 | ||
69 | #define GDS_KEY_SELFDEFTEXTMSG 0x31 | 67 | #define GDS_KEY_SELFDEFTEXTMSG 0x31 |
70 | 68 | ||
69 | enum sclp_pm_event { | ||
70 | SCLP_PM_EVENT_FREEZE, | ||
71 | SCLP_PM_EVENT_THAW, | ||
72 | SCLP_PM_EVENT_RESTORE, | ||
73 | }; | ||
74 | |||
75 | #define SCLP_PANIC_PRIO 1 | ||
76 | #define SCLP_PANIC_PRIO_CLIENT 0 | ||
77 | |||
71 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ | 78 | typedef u32 sccb_mask_t; /* ATTENTION: assumes 32bit mask !!! */ |
72 | 79 | ||
73 | struct sccb_header { | 80 | struct sccb_header { |
@@ -134,6 +141,10 @@ struct sclp_register { | |||
134 | void (*state_change_fn)(struct sclp_register *); | 141 | void (*state_change_fn)(struct sclp_register *); |
135 | /* called for events in cp_receive_mask/sclp_receive_mask */ | 142 | /* called for events in cp_receive_mask/sclp_receive_mask */ |
136 | void (*receiver_fn)(struct evbuf_header *); | 143 | void (*receiver_fn)(struct evbuf_header *); |
144 | /* called for power management events */ | ||
145 | void (*pm_event_fn)(struct sclp_register *, enum sclp_pm_event); | ||
146 | /* pm event posted flag */ | ||
147 | int pm_event_posted; | ||
137 | }; | 148 | }; |
138 | 149 | ||
139 | /* externals from sclp.c */ | 150 | /* externals from sclp.c */ |
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c index 77ab6e34a100..5cc11c636d38 100644 --- a/drivers/s390/char/sclp_cmd.c +++ b/drivers/s390/char/sclp_cmd.c | |||
@@ -1,9 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_cmd.c | 2 | * Copyright IBM Corp. 2007, 2009 |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, |
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>, | 5 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> |
6 | * Peter Oberparleiter <peter.oberparleiter@de.ibm.com> | ||
7 | */ | 6 | */ |
8 | 7 | ||
9 | #define KMSG_COMPONENT "sclp_cmd" | 8 | #define KMSG_COMPONENT "sclp_cmd" |
@@ -12,11 +11,13 @@ | |||
12 | #include <linux/completion.h> | 11 | #include <linux/completion.h> |
13 | #include <linux/init.h> | 12 | #include <linux/init.h> |
14 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
14 | #include <linux/err.h> | ||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/mmzone.h> | 18 | #include <linux/mmzone.h> |
19 | #include <linux/memory.h> | 19 | #include <linux/memory.h> |
20 | #include <linux/platform_device.h> | ||
20 | #include <asm/chpid.h> | 21 | #include <asm/chpid.h> |
21 | #include <asm/sclp.h> | 22 | #include <asm/sclp.h> |
22 | #include <asm/setup.h> | 23 | #include <asm/setup.h> |
@@ -292,6 +293,7 @@ static DEFINE_MUTEX(sclp_mem_mutex); | |||
292 | static LIST_HEAD(sclp_mem_list); | 293 | static LIST_HEAD(sclp_mem_list); |
293 | static u8 sclp_max_storage_id; | 294 | static u8 sclp_max_storage_id; |
294 | static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; | 295 | static unsigned long sclp_storage_ids[256 / BITS_PER_LONG]; |
296 | static int sclp_mem_state_changed; | ||
295 | 297 | ||
296 | struct memory_increment { | 298 | struct memory_increment { |
297 | struct list_head list; | 299 | struct list_head list; |
@@ -450,6 +452,8 @@ static int sclp_mem_notifier(struct notifier_block *nb, | |||
450 | rc = -EINVAL; | 452 | rc = -EINVAL; |
451 | break; | 453 | break; |
452 | } | 454 | } |
455 | if (!rc) | ||
456 | sclp_mem_state_changed = 1; | ||
453 | mutex_unlock(&sclp_mem_mutex); | 457 | mutex_unlock(&sclp_mem_mutex); |
454 | return rc ? NOTIFY_BAD : NOTIFY_OK; | 458 | return rc ? NOTIFY_BAD : NOTIFY_OK; |
455 | } | 459 | } |
@@ -525,6 +529,14 @@ static void __init insert_increment(u16 rn, int standby, int assigned) | |||
525 | list_add(&new_incr->list, prev); | 529 | list_add(&new_incr->list, prev); |
526 | } | 530 | } |
527 | 531 | ||
532 | static int sclp_mem_freeze(struct device *dev) | ||
533 | { | ||
534 | if (!sclp_mem_state_changed) | ||
535 | return 0; | ||
536 | pr_err("Memory hotplug state changed, suspend refused.\n"); | ||
537 | return -EPERM; | ||
538 | } | ||
539 | |||
528 | struct read_storage_sccb { | 540 | struct read_storage_sccb { |
529 | struct sccb_header header; | 541 | struct sccb_header header; |
530 | u16 max_id; | 542 | u16 max_id; |
@@ -534,8 +546,20 @@ struct read_storage_sccb { | |||
534 | u32 entries[0]; | 546 | u32 entries[0]; |
535 | } __packed; | 547 | } __packed; |
536 | 548 | ||
549 | static struct dev_pm_ops sclp_mem_pm_ops = { | ||
550 | .freeze = sclp_mem_freeze, | ||
551 | }; | ||
552 | |||
553 | static struct platform_driver sclp_mem_pdrv = { | ||
554 | .driver = { | ||
555 | .name = "sclp_mem", | ||
556 | .pm = &sclp_mem_pm_ops, | ||
557 | }, | ||
558 | }; | ||
559 | |||
537 | static int __init sclp_detect_standby_memory(void) | 560 | static int __init sclp_detect_standby_memory(void) |
538 | { | 561 | { |
562 | struct platform_device *sclp_pdev; | ||
539 | struct read_storage_sccb *sccb; | 563 | struct read_storage_sccb *sccb; |
540 | int i, id, assigned, rc; | 564 | int i, id, assigned, rc; |
541 | 565 | ||
@@ -588,7 +612,17 @@ static int __init sclp_detect_standby_memory(void) | |||
588 | rc = register_memory_notifier(&sclp_mem_nb); | 612 | rc = register_memory_notifier(&sclp_mem_nb); |
589 | if (rc) | 613 | if (rc) |
590 | goto out; | 614 | goto out; |
615 | rc = platform_driver_register(&sclp_mem_pdrv); | ||
616 | if (rc) | ||
617 | goto out; | ||
618 | sclp_pdev = platform_device_register_simple("sclp_mem", -1, NULL, 0); | ||
619 | rc = IS_ERR(sclp_pdev) ? PTR_ERR(sclp_pdev) : 0; | ||
620 | if (rc) | ||
621 | goto out_driver; | ||
591 | sclp_add_standby_memory(); | 622 | sclp_add_standby_memory(); |
623 | goto out; | ||
624 | out_driver: | ||
625 | platform_driver_unregister(&sclp_mem_pdrv); | ||
592 | out: | 626 | out: |
593 | free_page((unsigned long) sccb); | 627 | free_page((unsigned long) sccb); |
594 | return rc; | 628 | return rc; |
diff --git a/drivers/s390/char/sclp_con.c b/drivers/s390/char/sclp_con.c index 9a25c4bd1421..336811a77672 100644 --- a/drivers/s390/char/sclp_con.c +++ b/drivers/s390/char/sclp_con.c | |||
@@ -1,11 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_con.c | 2 | * SCLP line mode console driver |
3 | * SCLP line mode console driver | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
9 | */ | 7 | */ |
10 | 8 | ||
11 | #include <linux/kmod.h> | 9 | #include <linux/kmod.h> |
@@ -32,13 +30,14 @@ static spinlock_t sclp_con_lock; | |||
32 | static struct list_head sclp_con_pages; | 30 | static struct list_head sclp_con_pages; |
33 | /* List of full struct sclp_buffer structures ready for output */ | 31 | /* List of full struct sclp_buffer structures ready for output */ |
34 | static struct list_head sclp_con_outqueue; | 32 | static struct list_head sclp_con_outqueue; |
35 | /* Counter how many buffers are emitted (max 1) and how many */ | ||
36 | /* are on the output queue. */ | ||
37 | static int sclp_con_buffer_count; | ||
38 | /* Pointer to current console buffer */ | 33 | /* Pointer to current console buffer */ |
39 | static struct sclp_buffer *sclp_conbuf; | 34 | static struct sclp_buffer *sclp_conbuf; |
40 | /* Timer for delayed output of console messages */ | 35 | /* Timer for delayed output of console messages */ |
41 | static struct timer_list sclp_con_timer; | 36 | static struct timer_list sclp_con_timer; |
37 | /* Suspend mode flag */ | ||
38 | static int sclp_con_suspended; | ||
39 | /* Flag that output queue is currently running */ | ||
40 | static int sclp_con_queue_running; | ||
42 | 41 | ||
43 | /* Output format for console messages */ | 42 | /* Output format for console messages */ |
44 | static unsigned short sclp_con_columns; | 43 | static unsigned short sclp_con_columns; |
@@ -53,42 +52,71 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc) | |||
53 | do { | 52 | do { |
54 | page = sclp_unmake_buffer(buffer); | 53 | page = sclp_unmake_buffer(buffer); |
55 | spin_lock_irqsave(&sclp_con_lock, flags); | 54 | spin_lock_irqsave(&sclp_con_lock, flags); |
55 | |||
56 | /* Remove buffer from outqueue */ | 56 | /* Remove buffer from outqueue */ |
57 | list_del(&buffer->list); | 57 | list_del(&buffer->list); |
58 | sclp_con_buffer_count--; | ||
59 | list_add_tail((struct list_head *) page, &sclp_con_pages); | 58 | list_add_tail((struct list_head *) page, &sclp_con_pages); |
59 | |||
60 | /* Check if there is a pending buffer on the out queue. */ | 60 | /* Check if there is a pending buffer on the out queue. */ |
61 | buffer = NULL; | 61 | buffer = NULL; |
62 | if (!list_empty(&sclp_con_outqueue)) | 62 | if (!list_empty(&sclp_con_outqueue)) |
63 | buffer = list_entry(sclp_con_outqueue.next, | 63 | buffer = list_first_entry(&sclp_con_outqueue, |
64 | struct sclp_buffer, list); | 64 | struct sclp_buffer, list); |
65 | if (!buffer || sclp_con_suspended) { | ||
66 | sclp_con_queue_running = 0; | ||
67 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
68 | break; | ||
69 | } | ||
65 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 70 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
66 | } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback)); | 71 | } while (sclp_emit_buffer(buffer, sclp_conbuf_callback)); |
67 | } | 72 | } |
68 | 73 | ||
69 | static void | 74 | /* |
70 | sclp_conbuf_emit(void) | 75 | * Finalize and emit first pending buffer. |
76 | */ | ||
77 | static void sclp_conbuf_emit(void) | ||
71 | { | 78 | { |
72 | struct sclp_buffer* buffer; | 79 | struct sclp_buffer* buffer; |
73 | unsigned long flags; | 80 | unsigned long flags; |
74 | int count; | ||
75 | int rc; | 81 | int rc; |
76 | 82 | ||
77 | spin_lock_irqsave(&sclp_con_lock, flags); | 83 | spin_lock_irqsave(&sclp_con_lock, flags); |
78 | buffer = sclp_conbuf; | 84 | if (sclp_conbuf) |
85 | list_add_tail(&sclp_conbuf->list, &sclp_con_outqueue); | ||
79 | sclp_conbuf = NULL; | 86 | sclp_conbuf = NULL; |
80 | if (buffer == NULL) { | 87 | if (sclp_con_queue_running || sclp_con_suspended) |
81 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 88 | goto out_unlock; |
82 | return; | 89 | if (list_empty(&sclp_con_outqueue)) |
83 | } | 90 | goto out_unlock; |
84 | list_add_tail(&buffer->list, &sclp_con_outqueue); | 91 | buffer = list_first_entry(&sclp_con_outqueue, struct sclp_buffer, |
85 | count = sclp_con_buffer_count++; | 92 | list); |
93 | sclp_con_queue_running = 1; | ||
86 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 94 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
87 | if (count) | 95 | |
88 | return; | ||
89 | rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); | 96 | rc = sclp_emit_buffer(buffer, sclp_conbuf_callback); |
90 | if (rc) | 97 | if (rc) |
91 | sclp_conbuf_callback(buffer, rc); | 98 | sclp_conbuf_callback(buffer, rc); |
99 | return; | ||
100 | out_unlock: | ||
101 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * Wait until out queue is empty | ||
106 | */ | ||
107 | static void sclp_console_sync_queue(void) | ||
108 | { | ||
109 | unsigned long flags; | ||
110 | |||
111 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
112 | if (timer_pending(&sclp_con_timer)) | ||
113 | del_timer_sync(&sclp_con_timer); | ||
114 | while (sclp_con_queue_running) { | ||
115 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
116 | sclp_sync_wait(); | ||
117 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
118 | } | ||
119 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
92 | } | 120 | } |
93 | 121 | ||
94 | /* | 122 | /* |
@@ -123,6 +151,8 @@ sclp_console_write(struct console *console, const char *message, | |||
123 | /* make sure we have a console output buffer */ | 151 | /* make sure we have a console output buffer */ |
124 | if (sclp_conbuf == NULL) { | 152 | if (sclp_conbuf == NULL) { |
125 | while (list_empty(&sclp_con_pages)) { | 153 | while (list_empty(&sclp_con_pages)) { |
154 | if (sclp_con_suspended) | ||
155 | goto out; | ||
126 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 156 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
127 | sclp_sync_wait(); | 157 | sclp_sync_wait(); |
128 | spin_lock_irqsave(&sclp_con_lock, flags); | 158 | spin_lock_irqsave(&sclp_con_lock, flags); |
@@ -157,6 +187,7 @@ sclp_console_write(struct console *console, const char *message, | |||
157 | sclp_con_timer.expires = jiffies + HZ/10; | 187 | sclp_con_timer.expires = jiffies + HZ/10; |
158 | add_timer(&sclp_con_timer); | 188 | add_timer(&sclp_con_timer); |
159 | } | 189 | } |
190 | out: | ||
160 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 191 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
161 | } | 192 | } |
162 | 193 | ||
@@ -168,30 +199,43 @@ sclp_console_device(struct console *c, int *index) | |||
168 | } | 199 | } |
169 | 200 | ||
170 | /* | 201 | /* |
171 | * This routine is called from panic when the kernel | 202 | * Make sure that all buffers will be flushed to the SCLP. |
172 | * is going to give up. We have to make sure that all buffers | ||
173 | * will be flushed to the SCLP. | ||
174 | */ | 203 | */ |
175 | static void | 204 | static void |
176 | sclp_console_flush(void) | 205 | sclp_console_flush(void) |
177 | { | 206 | { |
207 | sclp_conbuf_emit(); | ||
208 | sclp_console_sync_queue(); | ||
209 | } | ||
210 | |||
211 | /* | ||
212 | * Resume console: If there are cached messages, emit them. | ||
213 | */ | ||
214 | static void sclp_console_resume(void) | ||
215 | { | ||
178 | unsigned long flags; | 216 | unsigned long flags; |
179 | 217 | ||
218 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
219 | sclp_con_suspended = 0; | ||
220 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
180 | sclp_conbuf_emit(); | 221 | sclp_conbuf_emit(); |
222 | } | ||
223 | |||
224 | /* | ||
225 | * Suspend console: Set suspend flag and flush console | ||
226 | */ | ||
227 | static void sclp_console_suspend(void) | ||
228 | { | ||
229 | unsigned long flags; | ||
230 | |||
181 | spin_lock_irqsave(&sclp_con_lock, flags); | 231 | spin_lock_irqsave(&sclp_con_lock, flags); |
182 | if (timer_pending(&sclp_con_timer)) | 232 | sclp_con_suspended = 1; |
183 | del_timer(&sclp_con_timer); | ||
184 | while (sclp_con_buffer_count > 0) { | ||
185 | spin_unlock_irqrestore(&sclp_con_lock, flags); | ||
186 | sclp_sync_wait(); | ||
187 | spin_lock_irqsave(&sclp_con_lock, flags); | ||
188 | } | ||
189 | spin_unlock_irqrestore(&sclp_con_lock, flags); | 233 | spin_unlock_irqrestore(&sclp_con_lock, flags); |
234 | sclp_console_flush(); | ||
190 | } | 235 | } |
191 | 236 | ||
192 | static int | 237 | static int sclp_console_notify(struct notifier_block *self, |
193 | sclp_console_notify(struct notifier_block *self, | 238 | unsigned long event, void *data) |
194 | unsigned long event, void *data) | ||
195 | { | 239 | { |
196 | sclp_console_flush(); | 240 | sclp_console_flush(); |
197 | return NOTIFY_OK; | 241 | return NOTIFY_OK; |
@@ -199,7 +243,7 @@ sclp_console_notify(struct notifier_block *self, | |||
199 | 243 | ||
200 | static struct notifier_block on_panic_nb = { | 244 | static struct notifier_block on_panic_nb = { |
201 | .notifier_call = sclp_console_notify, | 245 | .notifier_call = sclp_console_notify, |
202 | .priority = 1, | 246 | .priority = SCLP_PANIC_PRIO_CLIENT, |
203 | }; | 247 | }; |
204 | 248 | ||
205 | static struct notifier_block on_reboot_nb = { | 249 | static struct notifier_block on_reboot_nb = { |
@@ -221,6 +265,22 @@ static struct console sclp_console = | |||
221 | }; | 265 | }; |
222 | 266 | ||
223 | /* | 267 | /* |
268 | * This function is called for SCLP suspend and resume events. | ||
269 | */ | ||
270 | void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event) | ||
271 | { | ||
272 | switch (sclp_pm_event) { | ||
273 | case SCLP_PM_EVENT_FREEZE: | ||
274 | sclp_console_suspend(); | ||
275 | break; | ||
276 | case SCLP_PM_EVENT_RESTORE: | ||
277 | case SCLP_PM_EVENT_THAW: | ||
278 | sclp_console_resume(); | ||
279 | break; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | /* | ||
224 | * called by console_init() in drivers/char/tty_io.c at boot-time. | 284 | * called by console_init() in drivers/char/tty_io.c at boot-time. |
225 | */ | 285 | */ |
226 | static int __init | 286 | static int __init |
@@ -243,7 +303,6 @@ sclp_console_init(void) | |||
243 | } | 303 | } |
244 | INIT_LIST_HEAD(&sclp_con_outqueue); | 304 | INIT_LIST_HEAD(&sclp_con_outqueue); |
245 | spin_lock_init(&sclp_con_lock); | 305 | spin_lock_init(&sclp_con_lock); |
246 | sclp_con_buffer_count = 0; | ||
247 | sclp_conbuf = NULL; | 306 | sclp_conbuf = NULL; |
248 | init_timer(&sclp_con_timer); | 307 | init_timer(&sclp_con_timer); |
249 | 308 | ||
diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 710af42603f8..4be63be73445 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_rw.c | 2 | * driver: reading from and writing to system console on S/390 via SCLP |
3 | * driver: reading from and writing to system console on S/390 via SCLP | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #include <linux/kmod.h> | 10 | #include <linux/kmod.h> |
@@ -26,9 +25,16 @@ | |||
26 | */ | 25 | */ |
27 | #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) | 26 | #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer)) |
28 | 27 | ||
28 | static void sclp_rw_pm_event(struct sclp_register *reg, | ||
29 | enum sclp_pm_event sclp_pm_event) | ||
30 | { | ||
31 | sclp_console_pm_event(sclp_pm_event); | ||
32 | } | ||
33 | |||
29 | /* Event type structure for write message and write priority message */ | 34 | /* Event type structure for write message and write priority message */ |
30 | static struct sclp_register sclp_rw_event = { | 35 | static struct sclp_register sclp_rw_event = { |
31 | .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK | 36 | .send_mask = EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK, |
37 | .pm_event_fn = sclp_rw_pm_event, | ||
32 | }; | 38 | }; |
33 | 39 | ||
34 | /* | 40 | /* |
diff --git a/drivers/s390/char/sclp_rw.h b/drivers/s390/char/sclp_rw.h index 6aa7a6948bc9..85f491ea929c 100644 --- a/drivers/s390/char/sclp_rw.h +++ b/drivers/s390/char/sclp_rw.h | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_rw.h | 2 | * interface to the SCLP-read/write driver |
3 | * interface to the SCLP-read/write driver | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corporation 1999, 2009 |
6 | * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation | 5 | * |
7 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> | 6 | * Author(s): Martin Peschke <mpeschke@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 7 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
9 | */ | 8 | */ |
10 | 9 | ||
11 | #ifndef __SCLP_RW_H__ | 10 | #ifndef __SCLP_RW_H__ |
@@ -93,4 +92,5 @@ void sclp_set_columns(struct sclp_buffer *, unsigned short); | |||
93 | void sclp_set_htab(struct sclp_buffer *, unsigned short); | 92 | void sclp_set_htab(struct sclp_buffer *, unsigned short); |
94 | int sclp_chars_in_buffer(struct sclp_buffer *); | 93 | int sclp_chars_in_buffer(struct sclp_buffer *); |
95 | 94 | ||
95 | void sclp_console_pm_event(enum sclp_pm_event sclp_pm_event); | ||
96 | #endif /* __SCLP_RW_H__ */ | 96 | #endif /* __SCLP_RW_H__ */ |
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index a839aa531d7c..5518e24946aa 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c | |||
@@ -1,10 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/char/sclp_vt220.c | 2 | * SCLP VT220 terminal driver. |
3 | * SCLP VT220 terminal driver. | ||
4 | * | 3 | * |
5 | * S390 version | 4 | * Copyright IBM Corp. 2003, 2009 |
6 | * Copyright IBM Corp. 2003,2008 | 5 | * |
7 | * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> | 6 | * Author(s): Peter Oberparleiter <Peter.Oberparleiter@de.ibm.com> |
8 | */ | 7 | */ |
9 | 8 | ||
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
@@ -69,8 +68,11 @@ static struct list_head sclp_vt220_empty; | |||
69 | /* List of pending requests */ | 68 | /* List of pending requests */ |
70 | static struct list_head sclp_vt220_outqueue; | 69 | static struct list_head sclp_vt220_outqueue; |
71 | 70 | ||
72 | /* Number of requests in outqueue */ | 71 | /* Suspend mode flag */ |
73 | static int sclp_vt220_outqueue_count; | 72 | static int sclp_vt220_suspended; |
73 | |||
74 | /* Flag that output queue is currently running */ | ||
75 | static int sclp_vt220_queue_running; | ||
74 | 76 | ||
75 | /* Timer used for delaying write requests to merge subsequent messages into | 77 | /* Timer used for delaying write requests to merge subsequent messages into |
76 | * a single buffer */ | 78 | * a single buffer */ |
@@ -92,6 +94,8 @@ static int __initdata sclp_vt220_init_count; | |||
92 | static int sclp_vt220_flush_later; | 94 | static int sclp_vt220_flush_later; |
93 | 95 | ||
94 | static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); | 96 | static void sclp_vt220_receiver_fn(struct evbuf_header *evbuf); |
97 | static void sclp_vt220_pm_event_fn(struct sclp_register *reg, | ||
98 | enum sclp_pm_event sclp_pm_event); | ||
95 | static int __sclp_vt220_emit(struct sclp_vt220_request *request); | 99 | static int __sclp_vt220_emit(struct sclp_vt220_request *request); |
96 | static void sclp_vt220_emit_current(void); | 100 | static void sclp_vt220_emit_current(void); |
97 | 101 | ||
@@ -100,7 +104,8 @@ static struct sclp_register sclp_vt220_register = { | |||
100 | .send_mask = EVTYP_VT220MSG_MASK, | 104 | .send_mask = EVTYP_VT220MSG_MASK, |
101 | .receive_mask = EVTYP_VT220MSG_MASK, | 105 | .receive_mask = EVTYP_VT220MSG_MASK, |
102 | .state_change_fn = NULL, | 106 | .state_change_fn = NULL, |
103 | .receiver_fn = sclp_vt220_receiver_fn | 107 | .receiver_fn = sclp_vt220_receiver_fn, |
108 | .pm_event_fn = sclp_vt220_pm_event_fn, | ||
104 | }; | 109 | }; |
105 | 110 | ||
106 | 111 | ||
@@ -120,15 +125,19 @@ sclp_vt220_process_queue(struct sclp_vt220_request *request) | |||
120 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 125 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
121 | /* Move request from outqueue to empty queue */ | 126 | /* Move request from outqueue to empty queue */ |
122 | list_del(&request->list); | 127 | list_del(&request->list); |
123 | sclp_vt220_outqueue_count--; | ||
124 | list_add_tail((struct list_head *) page, &sclp_vt220_empty); | 128 | list_add_tail((struct list_head *) page, &sclp_vt220_empty); |
125 | /* Check if there is a pending buffer on the out queue. */ | 129 | /* Check if there is a pending buffer on the out queue. */ |
126 | request = NULL; | 130 | request = NULL; |
127 | if (!list_empty(&sclp_vt220_outqueue)) | 131 | if (!list_empty(&sclp_vt220_outqueue)) |
128 | request = list_entry(sclp_vt220_outqueue.next, | 132 | request = list_entry(sclp_vt220_outqueue.next, |
129 | struct sclp_vt220_request, list); | 133 | struct sclp_vt220_request, list); |
134 | if (!request || sclp_vt220_suspended) { | ||
135 | sclp_vt220_queue_running = 0; | ||
136 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
137 | break; | ||
138 | } | ||
130 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 139 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
131 | } while (request && __sclp_vt220_emit(request)); | 140 | } while (__sclp_vt220_emit(request)); |
132 | if (request == NULL && sclp_vt220_flush_later) | 141 | if (request == NULL && sclp_vt220_flush_later) |
133 | sclp_vt220_emit_current(); | 142 | sclp_vt220_emit_current(); |
134 | /* Check if the tty needs a wake up call */ | 143 | /* Check if the tty needs a wake up call */ |
@@ -212,26 +221,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request) | |||
212 | } | 221 | } |
213 | 222 | ||
214 | /* | 223 | /* |
215 | * Queue and emit given request. | 224 | * Queue and emit current request. |
216 | */ | ||
217 | static void | ||
218 | sclp_vt220_emit(struct sclp_vt220_request *request) | ||
219 | { | ||
220 | unsigned long flags; | ||
221 | int count; | ||
222 | |||
223 | spin_lock_irqsave(&sclp_vt220_lock, flags); | ||
224 | list_add_tail(&request->list, &sclp_vt220_outqueue); | ||
225 | count = sclp_vt220_outqueue_count++; | ||
226 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
227 | /* Emit only the first buffer immediately - callback takes care of | ||
228 | * the rest */ | ||
229 | if (count == 0 && __sclp_vt220_emit(request)) | ||
230 | sclp_vt220_process_queue(request); | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * Queue and emit current request. Return zero on success, non-zero otherwise. | ||
235 | */ | 225 | */ |
236 | static void | 226 | static void |
237 | sclp_vt220_emit_current(void) | 227 | sclp_vt220_emit_current(void) |
@@ -241,22 +231,33 @@ sclp_vt220_emit_current(void) | |||
241 | struct sclp_vt220_sccb *sccb; | 231 | struct sclp_vt220_sccb *sccb; |
242 | 232 | ||
243 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 233 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
244 | request = NULL; | 234 | if (sclp_vt220_current_request) { |
245 | if (sclp_vt220_current_request != NULL) { | ||
246 | sccb = (struct sclp_vt220_sccb *) | 235 | sccb = (struct sclp_vt220_sccb *) |
247 | sclp_vt220_current_request->sclp_req.sccb; | 236 | sclp_vt220_current_request->sclp_req.sccb; |
248 | /* Only emit buffers with content */ | 237 | /* Only emit buffers with content */ |
249 | if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { | 238 | if (sccb->header.length != sizeof(struct sclp_vt220_sccb)) { |
250 | request = sclp_vt220_current_request; | 239 | list_add_tail(&sclp_vt220_current_request->list, |
240 | &sclp_vt220_outqueue); | ||
251 | sclp_vt220_current_request = NULL; | 241 | sclp_vt220_current_request = NULL; |
252 | if (timer_pending(&sclp_vt220_timer)) | 242 | if (timer_pending(&sclp_vt220_timer)) |
253 | del_timer(&sclp_vt220_timer); | 243 | del_timer(&sclp_vt220_timer); |
254 | } | 244 | } |
255 | sclp_vt220_flush_later = 0; | 245 | sclp_vt220_flush_later = 0; |
256 | } | 246 | } |
247 | if (sclp_vt220_queue_running || sclp_vt220_suspended) | ||
248 | goto out_unlock; | ||
249 | if (list_empty(&sclp_vt220_outqueue)) | ||
250 | goto out_unlock; | ||
251 | request = list_first_entry(&sclp_vt220_outqueue, | ||
252 | struct sclp_vt220_request, list); | ||
253 | sclp_vt220_queue_running = 1; | ||
254 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
255 | |||
256 | if (__sclp_vt220_emit(request)) | ||
257 | sclp_vt220_process_queue(request); | ||
258 | return; | ||
259 | out_unlock: | ||
257 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 260 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
258 | if (request != NULL) | ||
259 | sclp_vt220_emit(request); | ||
260 | } | 261 | } |
261 | 262 | ||
262 | #define SCLP_NORMAL_WRITE 0x00 | 263 | #define SCLP_NORMAL_WRITE 0x00 |
@@ -396,7 +397,7 @@ __sclp_vt220_write(const unsigned char *buf, int count, int do_schedule, | |||
396 | if (sclp_vt220_current_request == NULL) { | 397 | if (sclp_vt220_current_request == NULL) { |
397 | while (list_empty(&sclp_vt220_empty)) { | 398 | while (list_empty(&sclp_vt220_empty)) { |
398 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 399 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
399 | if (may_fail) | 400 | if (may_fail || sclp_vt220_suspended) |
400 | goto out; | 401 | goto out; |
401 | else | 402 | else |
402 | sclp_sync_wait(); | 403 | sclp_sync_wait(); |
@@ -531,7 +532,7 @@ sclp_vt220_put_char(struct tty_struct *tty, unsigned char ch) | |||
531 | static void | 532 | static void |
532 | sclp_vt220_flush_chars(struct tty_struct *tty) | 533 | sclp_vt220_flush_chars(struct tty_struct *tty) |
533 | { | 534 | { |
534 | if (sclp_vt220_outqueue_count == 0) | 535 | if (!sclp_vt220_queue_running) |
535 | sclp_vt220_emit_current(); | 536 | sclp_vt220_emit_current(); |
536 | else | 537 | else |
537 | sclp_vt220_flush_later = 1; | 538 | sclp_vt220_flush_later = 1; |
@@ -635,7 +636,6 @@ static int __init __sclp_vt220_init(int num_pages) | |||
635 | init_timer(&sclp_vt220_timer); | 636 | init_timer(&sclp_vt220_timer); |
636 | sclp_vt220_current_request = NULL; | 637 | sclp_vt220_current_request = NULL; |
637 | sclp_vt220_buffered_chars = 0; | 638 | sclp_vt220_buffered_chars = 0; |
638 | sclp_vt220_outqueue_count = 0; | ||
639 | sclp_vt220_tty = NULL; | 639 | sclp_vt220_tty = NULL; |
640 | sclp_vt220_flush_later = 0; | 640 | sclp_vt220_flush_later = 0; |
641 | 641 | ||
@@ -736,7 +736,7 @@ static void __sclp_vt220_flush_buffer(void) | |||
736 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 736 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
737 | if (timer_pending(&sclp_vt220_timer)) | 737 | if (timer_pending(&sclp_vt220_timer)) |
738 | del_timer(&sclp_vt220_timer); | 738 | del_timer(&sclp_vt220_timer); |
739 | while (sclp_vt220_outqueue_count > 0) { | 739 | while (sclp_vt220_queue_running) { |
740 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 740 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
741 | sclp_sync_wait(); | 741 | sclp_sync_wait(); |
742 | spin_lock_irqsave(&sclp_vt220_lock, flags); | 742 | spin_lock_irqsave(&sclp_vt220_lock, flags); |
@@ -744,6 +744,46 @@ static void __sclp_vt220_flush_buffer(void) | |||
744 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | 744 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); |
745 | } | 745 | } |
746 | 746 | ||
747 | /* | ||
748 | * Resume console: If there are cached messages, emit them. | ||
749 | */ | ||
750 | static void sclp_vt220_resume(void) | ||
751 | { | ||
752 | unsigned long flags; | ||
753 | |||
754 | spin_lock_irqsave(&sclp_vt220_lock, flags); | ||
755 | sclp_vt220_suspended = 0; | ||
756 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
757 | sclp_vt220_emit_current(); | ||
758 | } | ||
759 | |||
760 | /* | ||
761 | * Suspend console: Set suspend flag and flush console | ||
762 | */ | ||
763 | static void sclp_vt220_suspend(void) | ||
764 | { | ||
765 | unsigned long flags; | ||
766 | |||
767 | spin_lock_irqsave(&sclp_vt220_lock, flags); | ||
768 | sclp_vt220_suspended = 1; | ||
769 | spin_unlock_irqrestore(&sclp_vt220_lock, flags); | ||
770 | __sclp_vt220_flush_buffer(); | ||
771 | } | ||
772 | |||
773 | static void sclp_vt220_pm_event_fn(struct sclp_register *reg, | ||
774 | enum sclp_pm_event sclp_pm_event) | ||
775 | { | ||
776 | switch (sclp_pm_event) { | ||
777 | case SCLP_PM_EVENT_FREEZE: | ||
778 | sclp_vt220_suspend(); | ||
779 | break; | ||
780 | case SCLP_PM_EVENT_RESTORE: | ||
781 | case SCLP_PM_EVENT_THAW: | ||
782 | sclp_vt220_resume(); | ||
783 | break; | ||
784 | } | ||
785 | } | ||
786 | |||
747 | static int | 787 | static int |
748 | sclp_vt220_notify(struct notifier_block *self, | 788 | sclp_vt220_notify(struct notifier_block *self, |
749 | unsigned long event, void *data) | 789 | unsigned long event, void *data) |
diff --git a/drivers/s390/char/tape.h b/drivers/s390/char/tape.h index 5469e099597e..a26333774701 100644 --- a/drivers/s390/char/tape.h +++ b/drivers/s390/char/tape.h | |||
@@ -3,7 +3,7 @@ | |||
3 | * tape device driver for 3480/3490E/3590 tapes. | 3 | * tape device driver for 3480/3490E/3590 tapes. |
4 | * | 4 | * |
5 | * S390 and zSeries version | 5 | * S390 and zSeries version |
6 | * Copyright IBM Corp. 2001,2006 | 6 | * Copyright IBM Corp. 2001, 2009 |
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 7 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | 8 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -286,6 +286,7 @@ extern void tape_state_set(struct tape_device *, enum tape_state); | |||
286 | 286 | ||
287 | extern int tape_generic_online(struct tape_device *, struct tape_discipline *); | 287 | extern int tape_generic_online(struct tape_device *, struct tape_discipline *); |
288 | extern int tape_generic_offline(struct ccw_device *); | 288 | extern int tape_generic_offline(struct ccw_device *); |
289 | extern int tape_generic_pm_suspend(struct ccw_device *); | ||
289 | 290 | ||
290 | /* Externals from tape_devmap.c */ | 291 | /* Externals from tape_devmap.c */ |
291 | extern int tape_generic_probe(struct ccw_device *); | 292 | extern int tape_generic_probe(struct ccw_device *); |
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c index 2d00a383a475..144d2a5e1a92 100644 --- a/drivers/s390/char/tape_34xx.c +++ b/drivers/s390/char/tape_34xx.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * drivers/s390/char/tape_34xx.c | 2 | * drivers/s390/char/tape_34xx.c |
3 | * tape device discipline for 3480/3490 tapes. | 3 | * tape device discipline for 3480/3490 tapes. |
4 | * | 4 | * |
5 | * Copyright (C) IBM Corp. 2001,2006 | 5 | * Copyright IBM Corp. 2001, 2009 |
6 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 6 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
7 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | 7 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -1302,6 +1302,7 @@ static struct ccw_driver tape_34xx_driver = { | |||
1302 | .remove = tape_generic_remove, | 1302 | .remove = tape_generic_remove, |
1303 | .set_online = tape_34xx_online, | 1303 | .set_online = tape_34xx_online, |
1304 | .set_offline = tape_generic_offline, | 1304 | .set_offline = tape_generic_offline, |
1305 | .freeze = tape_generic_pm_suspend, | ||
1305 | }; | 1306 | }; |
1306 | 1307 | ||
1307 | static int | 1308 | static int |
diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index c453b2f3e9f4..23e6598bc4b5 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * drivers/s390/char/tape_3590.c | 2 | * drivers/s390/char/tape_3590.c |
3 | * tape device discipline for 3590 tapes. | 3 | * tape device discipline for 3590 tapes. |
4 | * | 4 | * |
5 | * Copyright IBM Corp. 2001,2006 | 5 | * Copyright IBM Corp. 2001, 2009 |
6 | * Author(s): Stefan Bader <shbader@de.ibm.com> | 6 | * Author(s): Stefan Bader <shbader@de.ibm.com> |
7 | * Michael Holzheu <holzheu@de.ibm.com> | 7 | * Michael Holzheu <holzheu@de.ibm.com> |
8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | 8 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
@@ -1715,6 +1715,7 @@ static struct ccw_driver tape_3590_driver = { | |||
1715 | .remove = tape_generic_remove, | 1715 | .remove = tape_generic_remove, |
1716 | .set_offline = tape_generic_offline, | 1716 | .set_offline = tape_generic_offline, |
1717 | .set_online = tape_3590_online, | 1717 | .set_online = tape_3590_online, |
1718 | .freeze = tape_generic_pm_suspend, | ||
1718 | }; | 1719 | }; |
1719 | 1720 | ||
1720 | /* | 1721 | /* |
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c index 8a109f3b69c6..3ebaa8eb5c86 100644 --- a/drivers/s390/char/tape_core.c +++ b/drivers/s390/char/tape_core.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * basic function of the tape device driver | 3 | * basic function of the tape device driver |
4 | * | 4 | * |
5 | * S390 and zSeries version | 5 | * S390 and zSeries version |
6 | * Copyright IBM Corp. 2001,2006 | 6 | * Copyright IBM Corp. 2001, 2009 |
7 | * Author(s): Carsten Otte <cotte@de.ibm.com> | 7 | * Author(s): Carsten Otte <cotte@de.ibm.com> |
8 | * Michael Holzheu <holzheu@de.ibm.com> | 8 | * Michael Holzheu <holzheu@de.ibm.com> |
9 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> | 9 | * Tuan Ngo-Anh <ngoanh@de.ibm.com> |
@@ -380,6 +380,55 @@ tape_cleanup_device(struct tape_device *device) | |||
380 | } | 380 | } |
381 | 381 | ||
382 | /* | 382 | /* |
383 | * Suspend device. | ||
384 | * | ||
385 | * Called by the common I/O layer if the drive should be suspended on user | ||
386 | * request. We refuse to suspend if the device is loaded or in use for the | ||
387 | * following reason: | ||
388 | * While the Linux guest is suspended, it might be logged off which causes | ||
389 | * devices to be detached. Tape devices are automatically rewound and unloaded | ||
390 | * during DETACH processing (unless the tape device was attached with the | ||
391 | * NOASSIGN or MULTIUSER option). After rewind/unload, there is no way to | ||
392 | * resume the original state of the tape device, since we would need to | ||
393 | * manually re-load the cartridge which was active at suspend time. | ||
394 | */ | ||
395 | int tape_generic_pm_suspend(struct ccw_device *cdev) | ||
396 | { | ||
397 | struct tape_device *device; | ||
398 | |||
399 | device = cdev->dev.driver_data; | ||
400 | if (!device) { | ||
401 | return -ENODEV; | ||
402 | } | ||
403 | |||
404 | DBF_LH(3, "(%08x): tape_generic_pm_suspend(%p)\n", | ||
405 | device->cdev_id, device); | ||
406 | |||
407 | if (device->medium_state != MS_UNLOADED) { | ||
408 | pr_err("A cartridge is loaded in tape device %s, " | ||
409 | "refusing to suspend\n", dev_name(&cdev->dev)); | ||
410 | return -EBUSY; | ||
411 | } | ||
412 | |||
413 | spin_lock_irq(get_ccwdev_lock(device->cdev)); | ||
414 | switch (device->tape_state) { | ||
415 | case TS_INIT: | ||
416 | case TS_NOT_OPER: | ||
417 | case TS_UNUSED: | ||
418 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
419 | break; | ||
420 | default: | ||
421 | pr_err("Tape device %s is busy, refusing to " | ||
422 | "suspend\n", dev_name(&cdev->dev)); | ||
423 | spin_unlock_irq(get_ccwdev_lock(device->cdev)); | ||
424 | return -EBUSY; | ||
425 | } | ||
426 | |||
427 | DBF_LH(3, "(%08x): Drive suspended.\n", device->cdev_id); | ||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | /* | ||
383 | * Set device offline. | 432 | * Set device offline. |
384 | * | 433 | * |
385 | * Called by the common I/O layer if the drive should set offline on user | 434 | * Called by the common I/O layer if the drive should set offline on user |
@@ -1273,6 +1322,7 @@ EXPORT_SYMBOL(tape_generic_remove); | |||
1273 | EXPORT_SYMBOL(tape_generic_probe); | 1322 | EXPORT_SYMBOL(tape_generic_probe); |
1274 | EXPORT_SYMBOL(tape_generic_online); | 1323 | EXPORT_SYMBOL(tape_generic_online); |
1275 | EXPORT_SYMBOL(tape_generic_offline); | 1324 | EXPORT_SYMBOL(tape_generic_offline); |
1325 | EXPORT_SYMBOL(tape_generic_pm_suspend); | ||
1276 | EXPORT_SYMBOL(tape_put_device); | 1326 | EXPORT_SYMBOL(tape_put_device); |
1277 | EXPORT_SYMBOL(tape_get_device_reference); | 1327 | EXPORT_SYMBOL(tape_get_device_reference); |
1278 | EXPORT_SYMBOL(tape_state_verbose); | 1328 | EXPORT_SYMBOL(tape_state_verbose); |
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index d8a2289fcb69..e925808c2149 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * character device driver for reading z/VM system service records | 3 | * character device driver for reading z/VM system service records |
4 | * | 4 | * |
5 | * | 5 | * |
6 | * Copyright 2004 IBM Corporation | 6 | * Copyright IBM Corp. 2004, 2009 |
7 | * character device driver for reading z/VM system service records, | 7 | * character device driver for reading z/VM system service records, |
8 | * Version 1.0 | 8 | * Version 1.0 |
9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> | 9 | * Author(s): Xenia Tkatschow <xenia@us.ibm.com> |
@@ -660,6 +660,29 @@ static struct attribute *vmlogrdr_attrs[] = { | |||
660 | NULL, | 660 | NULL, |
661 | }; | 661 | }; |
662 | 662 | ||
663 | static int vmlogrdr_pm_prepare(struct device *dev) | ||
664 | { | ||
665 | int rc; | ||
666 | struct vmlogrdr_priv_t *priv = dev->driver_data; | ||
667 | |||
668 | rc = 0; | ||
669 | if (priv) { | ||
670 | spin_lock_bh(&priv->priv_lock); | ||
671 | if (priv->dev_in_use) | ||
672 | rc = -EBUSY; | ||
673 | spin_unlock_bh(&priv->priv_lock); | ||
674 | } | ||
675 | if (rc) | ||
676 | pr_err("vmlogrdr: device %s is busy. Refuse to suspend.\n", | ||
677 | dev_name(dev)); | ||
678 | return rc; | ||
679 | } | ||
680 | |||
681 | |||
682 | static struct dev_pm_ops vmlogrdr_pm_ops = { | ||
683 | .prepare = vmlogrdr_pm_prepare, | ||
684 | }; | ||
685 | |||
663 | static struct attribute_group vmlogrdr_attr_group = { | 686 | static struct attribute_group vmlogrdr_attr_group = { |
664 | .attrs = vmlogrdr_attrs, | 687 | .attrs = vmlogrdr_attrs, |
665 | }; | 688 | }; |
@@ -668,6 +691,7 @@ static struct class *vmlogrdr_class; | |||
668 | static struct device_driver vmlogrdr_driver = { | 691 | static struct device_driver vmlogrdr_driver = { |
669 | .name = "vmlogrdr", | 692 | .name = "vmlogrdr", |
670 | .bus = &iucv_bus, | 693 | .bus = &iucv_bus, |
694 | .pm = &vmlogrdr_pm_ops, | ||
671 | }; | 695 | }; |
672 | 696 | ||
673 | 697 | ||
@@ -729,6 +753,7 @@ static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv) | |||
729 | dev->bus = &iucv_bus; | 753 | dev->bus = &iucv_bus; |
730 | dev->parent = iucv_root; | 754 | dev->parent = iucv_root; |
731 | dev->driver = &vmlogrdr_driver; | 755 | dev->driver = &vmlogrdr_driver; |
756 | dev->driver_data = priv; | ||
732 | /* | 757 | /* |
733 | * The release function could be called after the | 758 | * The release function could be called after the |
734 | * module has been unloaded. It's _only_ task is to | 759 | * module has been unloaded. It's _only_ task is to |
diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index 5dcef81fc9d9..92458219a9e9 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Linux driver for System z and s390 unit record devices | 2 | * Linux driver for System z and s390 unit record devices |
3 | * (z/VM virtual punch, reader, printer) | 3 | * (z/VM virtual punch, reader, printer) |
4 | * | 4 | * |
5 | * Copyright IBM Corp. 2001, 2007 | 5 | * Copyright IBM Corp. 2001, 2009 |
6 | * Authors: Malcolm Beattie <beattiem@uk.ibm.com> | 6 | * Authors: Malcolm Beattie <beattiem@uk.ibm.com> |
7 | * Michael Holzheu <holzheu@de.ibm.com> | 7 | * Michael Holzheu <holzheu@de.ibm.com> |
8 | * Frank Munzert <munzert@de.ibm.com> | 8 | * Frank Munzert <munzert@de.ibm.com> |
@@ -60,6 +60,7 @@ static int ur_probe(struct ccw_device *cdev); | |||
60 | static void ur_remove(struct ccw_device *cdev); | 60 | static void ur_remove(struct ccw_device *cdev); |
61 | static int ur_set_online(struct ccw_device *cdev); | 61 | static int ur_set_online(struct ccw_device *cdev); |
62 | static int ur_set_offline(struct ccw_device *cdev); | 62 | static int ur_set_offline(struct ccw_device *cdev); |
63 | static int ur_pm_suspend(struct ccw_device *cdev); | ||
63 | 64 | ||
64 | static struct ccw_driver ur_driver = { | 65 | static struct ccw_driver ur_driver = { |
65 | .name = "vmur", | 66 | .name = "vmur", |
@@ -69,6 +70,7 @@ static struct ccw_driver ur_driver = { | |||
69 | .remove = ur_remove, | 70 | .remove = ur_remove, |
70 | .set_online = ur_set_online, | 71 | .set_online = ur_set_online, |
71 | .set_offline = ur_set_offline, | 72 | .set_offline = ur_set_offline, |
73 | .freeze = ur_pm_suspend, | ||
72 | }; | 74 | }; |
73 | 75 | ||
74 | static DEFINE_MUTEX(vmur_mutex); | 76 | static DEFINE_MUTEX(vmur_mutex); |
@@ -158,6 +160,28 @@ static void urdev_put(struct urdev *urd) | |||
158 | } | 160 | } |
159 | 161 | ||
160 | /* | 162 | /* |
163 | * State and contents of ur devices can be changed by class D users issuing | ||
164 | * CP commands such as PURGE or TRANSFER, while the Linux guest is suspended. | ||
165 | * Also the Linux guest might be logged off, which causes all active spool | ||
166 | * files to be closed. | ||
167 | * So we cannot guarantee that spool files are still the same when the Linux | ||
168 | * guest is resumed. In order to avoid unpredictable results at resume time | ||
169 | * we simply refuse to suspend if a ur device node is open. | ||
170 | */ | ||
171 | static int ur_pm_suspend(struct ccw_device *cdev) | ||
172 | { | ||
173 | struct urdev *urd = cdev->dev.driver_data; | ||
174 | |||
175 | TRACE("ur_pm_suspend: cdev=%p\n", cdev); | ||
176 | if (urd->open_flag) { | ||
177 | pr_err("Unit record device %s is busy, %s refusing to " | ||
178 | "suspend.\n", dev_name(&cdev->dev), ur_banner); | ||
179 | return -EBUSY; | ||
180 | } | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | /* | ||
161 | * Low-level functions to do I/O to a ur device. | 185 | * Low-level functions to do I/O to a ur device. |
162 | * alloc_chan_prog | 186 | * alloc_chan_prog |
163 | * free_chan_prog | 187 | * free_chan_prog |
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c index 21a2a829bf4e..cb7854c10c04 100644 --- a/drivers/s390/char/vmwatchdog.c +++ b/drivers/s390/char/vmwatchdog.c | |||
@@ -1,17 +1,23 @@ | |||
1 | /* | 1 | /* |
2 | * Watchdog implementation based on z/VM Watchdog Timer API | 2 | * Watchdog implementation based on z/VM Watchdog Timer API |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2004,2009 | ||
5 | * | ||
4 | * The user space watchdog daemon can use this driver as | 6 | * The user space watchdog daemon can use this driver as |
5 | * /dev/vmwatchdog to have z/VM execute the specified CP | 7 | * /dev/vmwatchdog to have z/VM execute the specified CP |
6 | * command when the timeout expires. The default command is | 8 | * command when the timeout expires. The default command is |
7 | * "IPL", which which cause an immediate reboot. | 9 | * "IPL", which which cause an immediate reboot. |
8 | */ | 10 | */ |
11 | #define KMSG_COMPONENT "vmwatchdog" | ||
12 | #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt | ||
13 | |||
9 | #include <linux/init.h> | 14 | #include <linux/init.h> |
10 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
11 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
12 | #include <linux/miscdevice.h> | 17 | #include <linux/miscdevice.h> |
13 | #include <linux/module.h> | 18 | #include <linux/module.h> |
14 | #include <linux/moduleparam.h> | 19 | #include <linux/moduleparam.h> |
20 | #include <linux/suspend.h> | ||
15 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
16 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
17 | 23 | ||
@@ -43,6 +49,9 @@ static unsigned int vmwdt_interval = 60; | |||
43 | static unsigned long vmwdt_is_open; | 49 | static unsigned long vmwdt_is_open; |
44 | static int vmwdt_expect_close; | 50 | static int vmwdt_expect_close; |
45 | 51 | ||
52 | #define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ | ||
53 | #define VMWDT_RUNNING 1 /* The watchdog is armed */ | ||
54 | |||
46 | enum vmwdt_func { | 55 | enum vmwdt_func { |
47 | /* function codes */ | 56 | /* function codes */ |
48 | wdt_init = 0, | 57 | wdt_init = 0, |
@@ -92,6 +101,7 @@ static int vmwdt_keepalive(void) | |||
92 | EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); | 101 | EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); |
93 | 102 | ||
94 | func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; | 103 | func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; |
104 | set_bit(VMWDT_RUNNING, &vmwdt_is_open); | ||
95 | ret = __diag288(func, vmwdt_interval, ebc_cmd, len); | 105 | ret = __diag288(func, vmwdt_interval, ebc_cmd, len); |
96 | WARN_ON(ret != 0); | 106 | WARN_ON(ret != 0); |
97 | kfree(ebc_cmd); | 107 | kfree(ebc_cmd); |
@@ -102,6 +112,7 @@ static int vmwdt_disable(void) | |||
102 | { | 112 | { |
103 | int ret = __diag288(wdt_cancel, 0, "", 0); | 113 | int ret = __diag288(wdt_cancel, 0, "", 0); |
104 | WARN_ON(ret != 0); | 114 | WARN_ON(ret != 0); |
115 | clear_bit(VMWDT_RUNNING, &vmwdt_is_open); | ||
105 | return ret; | 116 | return ret; |
106 | } | 117 | } |
107 | 118 | ||
@@ -123,13 +134,13 @@ static int vmwdt_open(struct inode *i, struct file *f) | |||
123 | { | 134 | { |
124 | int ret; | 135 | int ret; |
125 | lock_kernel(); | 136 | lock_kernel(); |
126 | if (test_and_set_bit(0, &vmwdt_is_open)) { | 137 | if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { |
127 | unlock_kernel(); | 138 | unlock_kernel(); |
128 | return -EBUSY; | 139 | return -EBUSY; |
129 | } | 140 | } |
130 | ret = vmwdt_keepalive(); | 141 | ret = vmwdt_keepalive(); |
131 | if (ret) | 142 | if (ret) |
132 | clear_bit(0, &vmwdt_is_open); | 143 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); |
133 | unlock_kernel(); | 144 | unlock_kernel(); |
134 | return ret ? ret : nonseekable_open(i, f); | 145 | return ret ? ret : nonseekable_open(i, f); |
135 | } | 146 | } |
@@ -139,7 +150,7 @@ static int vmwdt_close(struct inode *i, struct file *f) | |||
139 | if (vmwdt_expect_close == 42) | 150 | if (vmwdt_expect_close == 42) |
140 | vmwdt_disable(); | 151 | vmwdt_disable(); |
141 | vmwdt_expect_close = 0; | 152 | vmwdt_expect_close = 0; |
142 | clear_bit(0, &vmwdt_is_open); | 153 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); |
143 | return 0; | 154 | return 0; |
144 | } | 155 | } |
145 | 156 | ||
@@ -223,6 +234,57 @@ static ssize_t vmwdt_write(struct file *f, const char __user *buf, | |||
223 | return count; | 234 | return count; |
224 | } | 235 | } |
225 | 236 | ||
237 | static int vmwdt_resume(void) | ||
238 | { | ||
239 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); | ||
240 | return NOTIFY_DONE; | ||
241 | } | ||
242 | |||
243 | /* | ||
244 | * It makes no sense to go into suspend while the watchdog is running. | ||
245 | * Depending on the memory size, the watchdog might trigger, while we | ||
246 | * are still saving the memory. | ||
247 | * We reuse the open flag to ensure that suspend and watchdog open are | ||
248 | * exclusive operations | ||
249 | */ | ||
250 | static int vmwdt_suspend(void) | ||
251 | { | ||
252 | if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { | ||
253 | pr_err("The watchdog is in use. " | ||
254 | "This prevents hibernation or suspend.\n"); | ||
255 | return NOTIFY_BAD; | ||
256 | } | ||
257 | if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { | ||
258 | clear_bit(VMWDT_OPEN, &vmwdt_is_open); | ||
259 | pr_err("The watchdog is running. " | ||
260 | "This prevents hibernation or suspend.\n"); | ||
261 | return NOTIFY_BAD; | ||
262 | } | ||
263 | return NOTIFY_DONE; | ||
264 | } | ||
265 | |||
266 | /* | ||
267 | * This function is called for suspend and resume. | ||
268 | */ | ||
269 | static int vmwdt_power_event(struct notifier_block *this, unsigned long event, | ||
270 | void *ptr) | ||
271 | { | ||
272 | switch (event) { | ||
273 | case PM_POST_HIBERNATION: | ||
274 | case PM_POST_SUSPEND: | ||
275 | return vmwdt_resume(); | ||
276 | case PM_HIBERNATION_PREPARE: | ||
277 | case PM_SUSPEND_PREPARE: | ||
278 | return vmwdt_suspend(); | ||
279 | default: | ||
280 | return NOTIFY_DONE; | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static struct notifier_block vmwdt_power_notifier = { | ||
285 | .notifier_call = vmwdt_power_event, | ||
286 | }; | ||
287 | |||
226 | static const struct file_operations vmwdt_fops = { | 288 | static const struct file_operations vmwdt_fops = { |
227 | .open = &vmwdt_open, | 289 | .open = &vmwdt_open, |
228 | .release = &vmwdt_close, | 290 | .release = &vmwdt_close, |
@@ -244,12 +306,21 @@ static int __init vmwdt_init(void) | |||
244 | ret = vmwdt_probe(); | 306 | ret = vmwdt_probe(); |
245 | if (ret) | 307 | if (ret) |
246 | return ret; | 308 | return ret; |
247 | return misc_register(&vmwdt_dev); | 309 | ret = register_pm_notifier(&vmwdt_power_notifier); |
310 | if (ret) | ||
311 | return ret; | ||
312 | ret = misc_register(&vmwdt_dev); | ||
313 | if (ret) { | ||
314 | unregister_pm_notifier(&vmwdt_power_notifier); | ||
315 | return ret; | ||
316 | } | ||
317 | return 0; | ||
248 | } | 318 | } |
249 | module_init(vmwdt_init); | 319 | module_init(vmwdt_init); |
250 | 320 | ||
251 | static void __exit vmwdt_exit(void) | 321 | static void __exit vmwdt_exit(void) |
252 | { | 322 | { |
253 | WARN_ON(misc_deregister(&vmwdt_dev) != 0); | 323 | unregister_pm_notifier(&vmwdt_power_notifier); |
324 | misc_deregister(&vmwdt_dev); | ||
254 | } | 325 | } |
255 | module_exit(vmwdt_exit); | 326 | module_exit(vmwdt_exit); |
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 22ce765d537e..a5a62f1f7747 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -1,11 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/ccwgroup.c | ||
3 | * bus driver for ccwgroup | 2 | * bus driver for ccwgroup |
4 | * | 3 | * |
5 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, | 4 | * Copyright IBM Corp. 2002, 2009 |
6 | * IBM Corporation | 5 | * |
7 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) | 6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
8 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 7 | * Cornelia Huck (cornelia.huck@de.ibm.com) |
9 | */ | 8 | */ |
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
11 | #include <linux/errno.h> | 10 | #include <linux/errno.h> |
@@ -501,6 +500,74 @@ static void ccwgroup_shutdown(struct device *dev) | |||
501 | gdrv->shutdown(gdev); | 500 | gdrv->shutdown(gdev); |
502 | } | 501 | } |
503 | 502 | ||
503 | static int ccwgroup_pm_prepare(struct device *dev) | ||
504 | { | ||
505 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
506 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
507 | |||
508 | /* Fail while device is being set online/offline. */ | ||
509 | if (atomic_read(&gdev->onoff)) | ||
510 | return -EAGAIN; | ||
511 | |||
512 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
513 | return 0; | ||
514 | |||
515 | return gdrv->prepare ? gdrv->prepare(gdev) : 0; | ||
516 | } | ||
517 | |||
518 | static void ccwgroup_pm_complete(struct device *dev) | ||
519 | { | ||
520 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
521 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(dev->driver); | ||
522 | |||
523 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
524 | return; | ||
525 | |||
526 | if (gdrv->complete) | ||
527 | gdrv->complete(gdev); | ||
528 | } | ||
529 | |||
530 | static int ccwgroup_pm_freeze(struct device *dev) | ||
531 | { | ||
532 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
533 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
534 | |||
535 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
536 | return 0; | ||
537 | |||
538 | return gdrv->freeze ? gdrv->freeze(gdev) : 0; | ||
539 | } | ||
540 | |||
541 | static int ccwgroup_pm_thaw(struct device *dev) | ||
542 | { | ||
543 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
544 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
545 | |||
546 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
547 | return 0; | ||
548 | |||
549 | return gdrv->thaw ? gdrv->thaw(gdev) : 0; | ||
550 | } | ||
551 | |||
552 | static int ccwgroup_pm_restore(struct device *dev) | ||
553 | { | ||
554 | struct ccwgroup_device *gdev = to_ccwgroupdev(dev); | ||
555 | struct ccwgroup_driver *gdrv = to_ccwgroupdrv(gdev->dev.driver); | ||
556 | |||
557 | if (!gdev->dev.driver || gdev->state != CCWGROUP_ONLINE) | ||
558 | return 0; | ||
559 | |||
560 | return gdrv->restore ? gdrv->restore(gdev) : 0; | ||
561 | } | ||
562 | |||
563 | static struct dev_pm_ops ccwgroup_pm_ops = { | ||
564 | .prepare = ccwgroup_pm_prepare, | ||
565 | .complete = ccwgroup_pm_complete, | ||
566 | .freeze = ccwgroup_pm_freeze, | ||
567 | .thaw = ccwgroup_pm_thaw, | ||
568 | .restore = ccwgroup_pm_restore, | ||
569 | }; | ||
570 | |||
504 | static struct bus_type ccwgroup_bus_type = { | 571 | static struct bus_type ccwgroup_bus_type = { |
505 | .name = "ccwgroup", | 572 | .name = "ccwgroup", |
506 | .match = ccwgroup_bus_match, | 573 | .match = ccwgroup_bus_match, |
@@ -508,6 +575,7 @@ static struct bus_type ccwgroup_bus_type = { | |||
508 | .probe = ccwgroup_probe, | 575 | .probe = ccwgroup_probe, |
509 | .remove = ccwgroup_remove, | 576 | .remove = ccwgroup_remove, |
510 | .shutdown = ccwgroup_shutdown, | 577 | .shutdown = ccwgroup_shutdown, |
578 | .pm = &ccwgroup_pm_ops, | ||
511 | }; | 579 | }; |
512 | 580 | ||
513 | 581 | ||
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 883f16f96f22..1ecd3e567648 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c | |||
@@ -549,8 +549,7 @@ cleanup: | |||
549 | return ret; | 549 | return ret; |
550 | } | 550 | } |
551 | 551 | ||
552 | static int | 552 | int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) |
553 | __chsc_do_secm(struct channel_subsystem *css, int enable, void *page) | ||
554 | { | 553 | { |
555 | struct { | 554 | struct { |
556 | struct chsc_header request; | 555 | struct chsc_header request; |
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index ba59bceace98..425e8f89a6c5 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h | |||
@@ -90,6 +90,7 @@ extern void chsc_free_sei_area(void); | |||
90 | extern int chsc_enable_facility(int); | 90 | extern int chsc_enable_facility(int); |
91 | struct channel_subsystem; | 91 | struct channel_subsystem; |
92 | extern int chsc_secm(struct channel_subsystem *, int); | 92 | extern int chsc_secm(struct channel_subsystem *, int); |
93 | int __chsc_do_secm(struct channel_subsystem *css, int enable, void *page); | ||
93 | 94 | ||
94 | int chsc_chp_vary(struct chp_id chpid, int on); | 95 | int chsc_chp_vary(struct chp_id chpid, int on); |
95 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, | 96 | int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt, |
diff --git a/drivers/s390/cio/chsc_sch.c b/drivers/s390/cio/chsc_sch.c index 93eca1731b81..cc5144b6f9d9 100644 --- a/drivers/s390/cio/chsc_sch.c +++ b/drivers/s390/cio/chsc_sch.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Driver for s390 chsc subchannels | 2 | * Driver for s390 chsc subchannels |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2008 | 4 | * Copyright IBM Corp. 2008, 2009 |
5 | * | ||
5 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> | 6 | * Author(s): Cornelia Huck <cornelia.huck@de.ibm.com> |
6 | * | 7 | * |
7 | */ | 8 | */ |
@@ -112,6 +113,31 @@ static void chsc_subchannel_shutdown(struct subchannel *sch) | |||
112 | cio_disable_subchannel(sch); | 113 | cio_disable_subchannel(sch); |
113 | } | 114 | } |
114 | 115 | ||
116 | static int chsc_subchannel_prepare(struct subchannel *sch) | ||
117 | { | ||
118 | int cc; | ||
119 | struct schib schib; | ||
120 | /* | ||
121 | * Don't allow suspend while the subchannel is not idle | ||
122 | * since we don't have a way to clear the subchannel and | ||
123 | * cannot disable it with a request running. | ||
124 | */ | ||
125 | cc = stsch(sch->schid, &schib); | ||
126 | if (!cc && scsw_stctl(&schib.scsw)) | ||
127 | return -EAGAIN; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int chsc_subchannel_freeze(struct subchannel *sch) | ||
132 | { | ||
133 | return cio_disable_subchannel(sch); | ||
134 | } | ||
135 | |||
136 | static int chsc_subchannel_restore(struct subchannel *sch) | ||
137 | { | ||
138 | return cio_enable_subchannel(sch, (u32)(unsigned long)sch); | ||
139 | } | ||
140 | |||
115 | static struct css_device_id chsc_subchannel_ids[] = { | 141 | static struct css_device_id chsc_subchannel_ids[] = { |
116 | { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, | 142 | { .match_flags = 0x1, .type =SUBCHANNEL_TYPE_CHSC, }, |
117 | { /* end of list */ }, | 143 | { /* end of list */ }, |
@@ -125,6 +151,10 @@ static struct css_driver chsc_subchannel_driver = { | |||
125 | .probe = chsc_subchannel_probe, | 151 | .probe = chsc_subchannel_probe, |
126 | .remove = chsc_subchannel_remove, | 152 | .remove = chsc_subchannel_remove, |
127 | .shutdown = chsc_subchannel_shutdown, | 153 | .shutdown = chsc_subchannel_shutdown, |
154 | .prepare = chsc_subchannel_prepare, | ||
155 | .freeze = chsc_subchannel_freeze, | ||
156 | .thaw = chsc_subchannel_restore, | ||
157 | .restore = chsc_subchannel_restore, | ||
128 | .name = "chsc_subchannel", | 158 | .name = "chsc_subchannel", |
129 | }; | 159 | }; |
130 | 160 | ||
diff --git a/drivers/s390/cio/cmf.c b/drivers/s390/cio/cmf.c index dc98b2c63862..30f516111307 100644 --- a/drivers/s390/cio/cmf.c +++ b/drivers/s390/cio/cmf.c | |||
@@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev, | |||
1204 | 1204 | ||
1205 | DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); | 1205 | DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); |
1206 | 1206 | ||
1207 | int ccw_set_cmf(struct ccw_device *cdev, int enable) | ||
1208 | { | ||
1209 | return cmbops->set(cdev, enable ? 2 : 0); | ||
1210 | } | ||
1211 | |||
1207 | /** | 1212 | /** |
1208 | * enable_cmf() - switch on the channel measurement for a specific device | 1213 | * enable_cmf() - switch on the channel measurement for a specific device |
1209 | * @cdev: The ccw device to be enabled | 1214 | * @cdev: The ccw device to be enabled |
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c index 0085d8901792..85d43c6bcb66 100644 --- a/drivers/s390/cio/css.c +++ b/drivers/s390/cio/css.c | |||
@@ -1,10 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/css.c | 2 | * driver for channel subsystem |
3 | * driver for channel subsystem | ||
4 | * | 3 | * |
5 | * Copyright IBM Corp. 2002,2008 | 4 | * Copyright IBM Corp. 2002, 2009 |
6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) | 5 | * |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | 6 | * Author(s): Arnd Bergmann (arndb@de.ibm.com) |
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
8 | */ | 8 | */ |
9 | 9 | ||
10 | #define KMSG_COMPONENT "cio" | 10 | #define KMSG_COMPONENT "cio" |
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/list.h> | 18 | #include <linux/list.h> |
19 | #include <linux/reboot.h> | 19 | #include <linux/reboot.h> |
20 | #include <linux/suspend.h> | ||
20 | #include <asm/isc.h> | 21 | #include <asm/isc.h> |
21 | #include <asm/crw.h> | 22 | #include <asm/crw.h> |
22 | 23 | ||
@@ -780,6 +781,79 @@ static struct notifier_block css_reboot_notifier = { | |||
780 | }; | 781 | }; |
781 | 782 | ||
782 | /* | 783 | /* |
784 | * Since the css devices are neither on a bus nor have a class | ||
785 | * nor have a special device type, we cannot stop/restart channel | ||
786 | * path measurements via the normal suspend/resume callbacks, but have | ||
787 | * to use notifiers. | ||
788 | */ | ||
789 | static int css_power_event(struct notifier_block *this, unsigned long event, | ||
790 | void *ptr) | ||
791 | { | ||
792 | void *secm_area; | ||
793 | int ret, i; | ||
794 | |||
795 | switch (event) { | ||
796 | case PM_HIBERNATION_PREPARE: | ||
797 | case PM_SUSPEND_PREPARE: | ||
798 | ret = NOTIFY_DONE; | ||
799 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
800 | struct channel_subsystem *css; | ||
801 | |||
802 | css = channel_subsystems[i]; | ||
803 | mutex_lock(&css->mutex); | ||
804 | if (!css->cm_enabled) { | ||
805 | mutex_unlock(&css->mutex); | ||
806 | continue; | ||
807 | } | ||
808 | secm_area = (void *)get_zeroed_page(GFP_KERNEL | | ||
809 | GFP_DMA); | ||
810 | if (secm_area) { | ||
811 | if (__chsc_do_secm(css, 0, secm_area)) | ||
812 | ret = NOTIFY_BAD; | ||
813 | free_page((unsigned long)secm_area); | ||
814 | } else | ||
815 | ret = NOTIFY_BAD; | ||
816 | |||
817 | mutex_unlock(&css->mutex); | ||
818 | } | ||
819 | break; | ||
820 | case PM_POST_HIBERNATION: | ||
821 | case PM_POST_SUSPEND: | ||
822 | ret = NOTIFY_DONE; | ||
823 | for (i = 0; i <= __MAX_CSSID; i++) { | ||
824 | struct channel_subsystem *css; | ||
825 | |||
826 | css = channel_subsystems[i]; | ||
827 | mutex_lock(&css->mutex); | ||
828 | if (!css->cm_enabled) { | ||
829 | mutex_unlock(&css->mutex); | ||
830 | continue; | ||
831 | } | ||
832 | secm_area = (void *)get_zeroed_page(GFP_KERNEL | | ||
833 | GFP_DMA); | ||
834 | if (secm_area) { | ||
835 | if (__chsc_do_secm(css, 1, secm_area)) | ||
836 | ret = NOTIFY_BAD; | ||
837 | free_page((unsigned long)secm_area); | ||
838 | } else | ||
839 | ret = NOTIFY_BAD; | ||
840 | |||
841 | mutex_unlock(&css->mutex); | ||
842 | } | ||
843 | /* search for subchannels, which appeared during hibernation */ | ||
844 | css_schedule_reprobe(); | ||
845 | break; | ||
846 | default: | ||
847 | ret = NOTIFY_DONE; | ||
848 | } | ||
849 | return ret; | ||
850 | |||
851 | } | ||
852 | static struct notifier_block css_power_notifier = { | ||
853 | .notifier_call = css_power_event, | ||
854 | }; | ||
855 | |||
856 | /* | ||
783 | * Now that the driver core is running, we can setup our channel subsystem. | 857 | * Now that the driver core is running, we can setup our channel subsystem. |
784 | * The struct subchannel's are created during probing (except for the | 858 | * The struct subchannel's are created during probing (except for the |
785 | * static console subchannel). | 859 | * static console subchannel). |
@@ -852,6 +926,11 @@ init_channel_subsystem (void) | |||
852 | ret = register_reboot_notifier(&css_reboot_notifier); | 926 | ret = register_reboot_notifier(&css_reboot_notifier); |
853 | if (ret) | 927 | if (ret) |
854 | goto out_unregister; | 928 | goto out_unregister; |
929 | ret = register_pm_notifier(&css_power_notifier); | ||
930 | if (ret) { | ||
931 | unregister_reboot_notifier(&css_reboot_notifier); | ||
932 | goto out_unregister; | ||
933 | } | ||
855 | css_init_done = 1; | 934 | css_init_done = 1; |
856 | 935 | ||
857 | /* Enable default isc for I/O subchannels. */ | 936 | /* Enable default isc for I/O subchannels. */ |
@@ -953,6 +1032,73 @@ static int css_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
953 | return ret; | 1032 | return ret; |
954 | } | 1033 | } |
955 | 1034 | ||
1035 | static int css_pm_prepare(struct device *dev) | ||
1036 | { | ||
1037 | struct subchannel *sch = to_subchannel(dev); | ||
1038 | struct css_driver *drv; | ||
1039 | |||
1040 | if (mutex_is_locked(&sch->reg_mutex)) | ||
1041 | return -EAGAIN; | ||
1042 | if (!sch->dev.driver) | ||
1043 | return 0; | ||
1044 | drv = to_cssdriver(sch->dev.driver); | ||
1045 | /* Notify drivers that they may not register children. */ | ||
1046 | return drv->prepare ? drv->prepare(sch) : 0; | ||
1047 | } | ||
1048 | |||
1049 | static void css_pm_complete(struct device *dev) | ||
1050 | { | ||
1051 | struct subchannel *sch = to_subchannel(dev); | ||
1052 | struct css_driver *drv; | ||
1053 | |||
1054 | if (!sch->dev.driver) | ||
1055 | return; | ||
1056 | drv = to_cssdriver(sch->dev.driver); | ||
1057 | if (drv->complete) | ||
1058 | drv->complete(sch); | ||
1059 | } | ||
1060 | |||
1061 | static int css_pm_freeze(struct device *dev) | ||
1062 | { | ||
1063 | struct subchannel *sch = to_subchannel(dev); | ||
1064 | struct css_driver *drv; | ||
1065 | |||
1066 | if (!sch->dev.driver) | ||
1067 | return 0; | ||
1068 | drv = to_cssdriver(sch->dev.driver); | ||
1069 | return drv->freeze ? drv->freeze(sch) : 0; | ||
1070 | } | ||
1071 | |||
1072 | static int css_pm_thaw(struct device *dev) | ||
1073 | { | ||
1074 | struct subchannel *sch = to_subchannel(dev); | ||
1075 | struct css_driver *drv; | ||
1076 | |||
1077 | if (!sch->dev.driver) | ||
1078 | return 0; | ||
1079 | drv = to_cssdriver(sch->dev.driver); | ||
1080 | return drv->thaw ? drv->thaw(sch) : 0; | ||
1081 | } | ||
1082 | |||
1083 | static int css_pm_restore(struct device *dev) | ||
1084 | { | ||
1085 | struct subchannel *sch = to_subchannel(dev); | ||
1086 | struct css_driver *drv; | ||
1087 | |||
1088 | if (!sch->dev.driver) | ||
1089 | return 0; | ||
1090 | drv = to_cssdriver(sch->dev.driver); | ||
1091 | return drv->restore ? drv->restore(sch) : 0; | ||
1092 | } | ||
1093 | |||
1094 | static struct dev_pm_ops css_pm_ops = { | ||
1095 | .prepare = css_pm_prepare, | ||
1096 | .complete = css_pm_complete, | ||
1097 | .freeze = css_pm_freeze, | ||
1098 | .thaw = css_pm_thaw, | ||
1099 | .restore = css_pm_restore, | ||
1100 | }; | ||
1101 | |||
956 | struct bus_type css_bus_type = { | 1102 | struct bus_type css_bus_type = { |
957 | .name = "css", | 1103 | .name = "css", |
958 | .match = css_bus_match, | 1104 | .match = css_bus_match, |
@@ -960,6 +1106,7 @@ struct bus_type css_bus_type = { | |||
960 | .remove = css_remove, | 1106 | .remove = css_remove, |
961 | .shutdown = css_shutdown, | 1107 | .shutdown = css_shutdown, |
962 | .uevent = css_uevent, | 1108 | .uevent = css_uevent, |
1109 | .pm = &css_pm_ops, | ||
963 | }; | 1110 | }; |
964 | 1111 | ||
965 | /** | 1112 | /** |
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h index 57ebf120f825..9763eeec7458 100644 --- a/drivers/s390/cio/css.h +++ b/drivers/s390/cio/css.h | |||
@@ -70,6 +70,11 @@ struct chp_link; | |||
70 | * @probe: function called on probe | 70 | * @probe: function called on probe |
71 | * @remove: function called on remove | 71 | * @remove: function called on remove |
72 | * @shutdown: called at device shutdown | 72 | * @shutdown: called at device shutdown |
73 | * @prepare: prepare for pm state transition | ||
74 | * @complete: undo work done in @prepare | ||
75 | * @freeze: callback for freezing during hibernation snapshotting | ||
76 | * @thaw: undo work done in @freeze | ||
77 | * @restore: callback for restoring after hibernation | ||
73 | * @name: name of the device driver | 78 | * @name: name of the device driver |
74 | */ | 79 | */ |
75 | struct css_driver { | 80 | struct css_driver { |
@@ -82,6 +87,11 @@ struct css_driver { | |||
82 | int (*probe)(struct subchannel *); | 87 | int (*probe)(struct subchannel *); |
83 | int (*remove)(struct subchannel *); | 88 | int (*remove)(struct subchannel *); |
84 | void (*shutdown)(struct subchannel *); | 89 | void (*shutdown)(struct subchannel *); |
90 | int (*prepare) (struct subchannel *); | ||
91 | void (*complete) (struct subchannel *); | ||
92 | int (*freeze)(struct subchannel *); | ||
93 | int (*thaw) (struct subchannel *); | ||
94 | int (*restore)(struct subchannel *); | ||
85 | const char *name; | 95 | const char *name; |
86 | }; | 96 | }; |
87 | 97 | ||
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 35441fa16be1..3c57c1a18bb8 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c | |||
@@ -138,6 +138,19 @@ static struct css_device_id io_subchannel_ids[] = { | |||
138 | }; | 138 | }; |
139 | MODULE_DEVICE_TABLE(css, io_subchannel_ids); | 139 | MODULE_DEVICE_TABLE(css, io_subchannel_ids); |
140 | 140 | ||
141 | static int io_subchannel_prepare(struct subchannel *sch) | ||
142 | { | ||
143 | struct ccw_device *cdev; | ||
144 | /* | ||
145 | * Don't allow suspend while a ccw device registration | ||
146 | * is still outstanding. | ||
147 | */ | ||
148 | cdev = sch_get_cdev(sch); | ||
149 | if (cdev && !device_is_registered(&cdev->dev)) | ||
150 | return -EAGAIN; | ||
151 | return 0; | ||
152 | } | ||
153 | |||
141 | static struct css_driver io_subchannel_driver = { | 154 | static struct css_driver io_subchannel_driver = { |
142 | .owner = THIS_MODULE, | 155 | .owner = THIS_MODULE, |
143 | .subchannel_type = io_subchannel_ids, | 156 | .subchannel_type = io_subchannel_ids, |
@@ -148,6 +161,7 @@ static struct css_driver io_subchannel_driver = { | |||
148 | .probe = io_subchannel_probe, | 161 | .probe = io_subchannel_probe, |
149 | .remove = io_subchannel_remove, | 162 | .remove = io_subchannel_remove, |
150 | .shutdown = io_subchannel_shutdown, | 163 | .shutdown = io_subchannel_shutdown, |
164 | .prepare = io_subchannel_prepare, | ||
151 | }; | 165 | }; |
152 | 166 | ||
153 | struct workqueue_struct *ccw_device_work; | 167 | struct workqueue_struct *ccw_device_work; |
@@ -1775,6 +1789,15 @@ ccw_device_probe_console(void) | |||
1775 | return &console_cdev; | 1789 | return &console_cdev; |
1776 | } | 1790 | } |
1777 | 1791 | ||
1792 | static int ccw_device_pm_restore(struct device *dev); | ||
1793 | |||
1794 | int ccw_device_force_console(void) | ||
1795 | { | ||
1796 | if (!console_cdev_in_use) | ||
1797 | return -ENODEV; | ||
1798 | return ccw_device_pm_restore(&console_cdev.dev); | ||
1799 | } | ||
1800 | EXPORT_SYMBOL_GPL(ccw_device_force_console); | ||
1778 | 1801 | ||
1779 | const char *cio_get_console_cdev_name(struct subchannel *sch) | 1802 | const char *cio_get_console_cdev_name(struct subchannel *sch) |
1780 | { | 1803 | { |
@@ -1895,6 +1918,242 @@ static void ccw_device_shutdown(struct device *dev) | |||
1895 | disable_cmf(cdev); | 1918 | disable_cmf(cdev); |
1896 | } | 1919 | } |
1897 | 1920 | ||
1921 | static int ccw_device_pm_prepare(struct device *dev) | ||
1922 | { | ||
1923 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1924 | |||
1925 | if (work_pending(&cdev->private->kick_work)) | ||
1926 | return -EAGAIN; | ||
1927 | /* Fail while device is being set online/offline. */ | ||
1928 | if (atomic_read(&cdev->private->onoff)) | ||
1929 | return -EAGAIN; | ||
1930 | |||
1931 | if (cdev->online && cdev->drv && cdev->drv->prepare) | ||
1932 | return cdev->drv->prepare(cdev); | ||
1933 | |||
1934 | return 0; | ||
1935 | } | ||
1936 | |||
1937 | static void ccw_device_pm_complete(struct device *dev) | ||
1938 | { | ||
1939 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1940 | |||
1941 | if (cdev->online && cdev->drv && cdev->drv->complete) | ||
1942 | cdev->drv->complete(cdev); | ||
1943 | } | ||
1944 | |||
1945 | static int ccw_device_pm_freeze(struct device *dev) | ||
1946 | { | ||
1947 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1948 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
1949 | int ret, cm_enabled; | ||
1950 | |||
1951 | /* Fail suspend while device is in transistional state. */ | ||
1952 | if (!dev_fsm_final_state(cdev)) | ||
1953 | return -EAGAIN; | ||
1954 | if (!cdev->online) | ||
1955 | return 0; | ||
1956 | if (cdev->drv && cdev->drv->freeze) { | ||
1957 | ret = cdev->drv->freeze(cdev); | ||
1958 | if (ret) | ||
1959 | return ret; | ||
1960 | } | ||
1961 | |||
1962 | spin_lock_irq(sch->lock); | ||
1963 | cm_enabled = cdev->private->cmb != NULL; | ||
1964 | spin_unlock_irq(sch->lock); | ||
1965 | if (cm_enabled) { | ||
1966 | /* Don't have the css write on memory. */ | ||
1967 | ret = ccw_set_cmf(cdev, 0); | ||
1968 | if (ret) | ||
1969 | return ret; | ||
1970 | } | ||
1971 | /* From here on, disallow device driver I/O. */ | ||
1972 | spin_lock_irq(sch->lock); | ||
1973 | ret = cio_disable_subchannel(sch); | ||
1974 | spin_unlock_irq(sch->lock); | ||
1975 | |||
1976 | return ret; | ||
1977 | } | ||
1978 | |||
1979 | static int ccw_device_pm_thaw(struct device *dev) | ||
1980 | { | ||
1981 | struct ccw_device *cdev = to_ccwdev(dev); | ||
1982 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
1983 | int ret, cm_enabled; | ||
1984 | |||
1985 | if (!cdev->online) | ||
1986 | return 0; | ||
1987 | |||
1988 | spin_lock_irq(sch->lock); | ||
1989 | /* Allow device driver I/O again. */ | ||
1990 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); | ||
1991 | cm_enabled = cdev->private->cmb != NULL; | ||
1992 | spin_unlock_irq(sch->lock); | ||
1993 | if (ret) | ||
1994 | return ret; | ||
1995 | |||
1996 | if (cm_enabled) { | ||
1997 | ret = ccw_set_cmf(cdev, 1); | ||
1998 | if (ret) | ||
1999 | return ret; | ||
2000 | } | ||
2001 | |||
2002 | if (cdev->drv && cdev->drv->thaw) | ||
2003 | ret = cdev->drv->thaw(cdev); | ||
2004 | |||
2005 | return ret; | ||
2006 | } | ||
2007 | |||
2008 | static void __ccw_device_pm_restore(struct ccw_device *cdev) | ||
2009 | { | ||
2010 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
2011 | int ret; | ||
2012 | |||
2013 | if (cio_is_console(sch->schid)) | ||
2014 | goto out; | ||
2015 | /* | ||
2016 | * While we were sleeping, devices may have gone or become | ||
2017 | * available again. Kick re-detection. | ||
2018 | */ | ||
2019 | spin_lock_irq(sch->lock); | ||
2020 | cdev->private->flags.resuming = 1; | ||
2021 | ret = ccw_device_recognition(cdev); | ||
2022 | spin_unlock_irq(sch->lock); | ||
2023 | if (ret) { | ||
2024 | CIO_MSG_EVENT(0, "Couldn't start recognition for device " | ||
2025 | "%s (ret=%d)\n", dev_name(&cdev->dev), ret); | ||
2026 | spin_lock_irq(sch->lock); | ||
2027 | cdev->private->state = DEV_STATE_DISCONNECTED; | ||
2028 | spin_unlock_irq(sch->lock); | ||
2029 | /* notify driver after the resume cb */ | ||
2030 | goto out; | ||
2031 | } | ||
2032 | wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || | ||
2033 | cdev->private->state == DEV_STATE_DISCONNECTED); | ||
2034 | |||
2035 | out: | ||
2036 | cdev->private->flags.resuming = 0; | ||
2037 | } | ||
2038 | |||
2039 | static int resume_handle_boxed(struct ccw_device *cdev) | ||
2040 | { | ||
2041 | cdev->private->state = DEV_STATE_BOXED; | ||
2042 | if (ccw_device_notify(cdev, CIO_BOXED)) | ||
2043 | return 0; | ||
2044 | ccw_device_schedule_sch_unregister(cdev); | ||
2045 | return -ENODEV; | ||
2046 | } | ||
2047 | |||
2048 | static int resume_handle_disc(struct ccw_device *cdev) | ||
2049 | { | ||
2050 | cdev->private->state = DEV_STATE_DISCONNECTED; | ||
2051 | if (ccw_device_notify(cdev, CIO_GONE)) | ||
2052 | return 0; | ||
2053 | ccw_device_schedule_sch_unregister(cdev); | ||
2054 | return -ENODEV; | ||
2055 | } | ||
2056 | |||
2057 | static int ccw_device_pm_restore(struct device *dev) | ||
2058 | { | ||
2059 | struct ccw_device *cdev = to_ccwdev(dev); | ||
2060 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | ||
2061 | int ret = 0, cm_enabled; | ||
2062 | |||
2063 | __ccw_device_pm_restore(cdev); | ||
2064 | spin_lock_irq(sch->lock); | ||
2065 | if (cio_is_console(sch->schid)) { | ||
2066 | cio_enable_subchannel(sch, (u32)(addr_t)sch); | ||
2067 | spin_unlock_irq(sch->lock); | ||
2068 | goto out_restore; | ||
2069 | } | ||
2070 | cdev->private->flags.donotify = 0; | ||
2071 | /* check recognition results */ | ||
2072 | switch (cdev->private->state) { | ||
2073 | case DEV_STATE_OFFLINE: | ||
2074 | break; | ||
2075 | case DEV_STATE_BOXED: | ||
2076 | ret = resume_handle_boxed(cdev); | ||
2077 | spin_unlock_irq(sch->lock); | ||
2078 | if (ret) | ||
2079 | goto out; | ||
2080 | goto out_restore; | ||
2081 | case DEV_STATE_DISCONNECTED: | ||
2082 | goto out_disc_unlock; | ||
2083 | default: | ||
2084 | goto out_unreg_unlock; | ||
2085 | } | ||
2086 | /* check if the device id has changed */ | ||
2087 | if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { | ||
2088 | CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " | ||
2089 | "%04x to %04x)\n", dev_name(&sch->dev), | ||
2090 | cdev->private->dev_id.devno, | ||
2091 | sch->schib.pmcw.dev); | ||
2092 | goto out_unreg_unlock; | ||
2093 | } | ||
2094 | /* check if the device type has changed */ | ||
2095 | if (!ccw_device_test_sense_data(cdev)) { | ||
2096 | ccw_device_update_sense_data(cdev); | ||
2097 | PREPARE_WORK(&cdev->private->kick_work, | ||
2098 | ccw_device_do_unbind_bind); | ||
2099 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
2100 | ret = -ENODEV; | ||
2101 | goto out_unlock; | ||
2102 | } | ||
2103 | if (!cdev->online) { | ||
2104 | ret = 0; | ||
2105 | goto out_unlock; | ||
2106 | } | ||
2107 | ret = ccw_device_online(cdev); | ||
2108 | if (ret) | ||
2109 | goto out_disc_unlock; | ||
2110 | |||
2111 | cm_enabled = cdev->private->cmb != NULL; | ||
2112 | spin_unlock_irq(sch->lock); | ||
2113 | |||
2114 | wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); | ||
2115 | if (cdev->private->state != DEV_STATE_ONLINE) { | ||
2116 | spin_lock_irq(sch->lock); | ||
2117 | goto out_disc_unlock; | ||
2118 | } | ||
2119 | if (cm_enabled) { | ||
2120 | ret = ccw_set_cmf(cdev, 1); | ||
2121 | if (ret) { | ||
2122 | CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " | ||
2123 | "(rc=%d)\n", dev_name(&cdev->dev), ret); | ||
2124 | ret = 0; | ||
2125 | } | ||
2126 | } | ||
2127 | |||
2128 | out_restore: | ||
2129 | if (cdev->online && cdev->drv && cdev->drv->restore) | ||
2130 | ret = cdev->drv->restore(cdev); | ||
2131 | out: | ||
2132 | return ret; | ||
2133 | |||
2134 | out_disc_unlock: | ||
2135 | ret = resume_handle_disc(cdev); | ||
2136 | spin_unlock_irq(sch->lock); | ||
2137 | if (ret) | ||
2138 | return ret; | ||
2139 | goto out_restore; | ||
2140 | |||
2141 | out_unreg_unlock: | ||
2142 | ccw_device_schedule_sch_unregister(cdev); | ||
2143 | ret = -ENODEV; | ||
2144 | out_unlock: | ||
2145 | spin_unlock_irq(sch->lock); | ||
2146 | return ret; | ||
2147 | } | ||
2148 | |||
2149 | static struct dev_pm_ops ccw_pm_ops = { | ||
2150 | .prepare = ccw_device_pm_prepare, | ||
2151 | .complete = ccw_device_pm_complete, | ||
2152 | .freeze = ccw_device_pm_freeze, | ||
2153 | .thaw = ccw_device_pm_thaw, | ||
2154 | .restore = ccw_device_pm_restore, | ||
2155 | }; | ||
2156 | |||
1898 | struct bus_type ccw_bus_type = { | 2157 | struct bus_type ccw_bus_type = { |
1899 | .name = "ccw", | 2158 | .name = "ccw", |
1900 | .match = ccw_bus_match, | 2159 | .match = ccw_bus_match, |
@@ -1902,6 +2161,7 @@ struct bus_type ccw_bus_type = { | |||
1902 | .probe = ccw_device_probe, | 2161 | .probe = ccw_device_probe, |
1903 | .remove = ccw_device_remove, | 2162 | .remove = ccw_device_remove, |
1904 | .shutdown = ccw_device_shutdown, | 2163 | .shutdown = ccw_device_shutdown, |
2164 | .pm = &ccw_pm_ops, | ||
1905 | }; | 2165 | }; |
1906 | 2166 | ||
1907 | /** | 2167 | /** |
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index f1cbbd94ad4e..e3975107a578 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h | |||
@@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *); | |||
87 | int ccw_device_recognition(struct ccw_device *); | 87 | int ccw_device_recognition(struct ccw_device *); |
88 | int ccw_device_online(struct ccw_device *); | 88 | int ccw_device_online(struct ccw_device *); |
89 | int ccw_device_offline(struct ccw_device *); | 89 | int ccw_device_offline(struct ccw_device *); |
90 | void ccw_device_update_sense_data(struct ccw_device *); | ||
91 | int ccw_device_test_sense_data(struct ccw_device *); | ||
90 | void ccw_device_schedule_sch_unregister(struct ccw_device *); | 92 | void ccw_device_schedule_sch_unregister(struct ccw_device *); |
91 | int ccw_purge_blacklisted(void); | 93 | int ccw_purge_blacklisted(void); |
92 | 94 | ||
@@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type; | |||
133 | void retry_set_schib(struct ccw_device *cdev); | 135 | void retry_set_schib(struct ccw_device *cdev); |
134 | void cmf_retry_copy_block(struct ccw_device *); | 136 | void cmf_retry_copy_block(struct ccw_device *); |
135 | int cmf_reenable(struct ccw_device *); | 137 | int cmf_reenable(struct ccw_device *); |
138 | int ccw_set_cmf(struct ccw_device *cdev, int enable); | ||
136 | extern struct device_attribute dev_attr_cmb_enable; | 139 | extern struct device_attribute dev_attr_cmb_enable; |
137 | #endif | 140 | #endif |
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c index e46049261561..3db88c52d287 100644 --- a/drivers/s390/cio/device_fsm.c +++ b/drivers/s390/cio/device_fsm.c | |||
@@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) | |||
177 | panic("Can't stop i/o on subchannel.\n"); | 177 | panic("Can't stop i/o on subchannel.\n"); |
178 | } | 178 | } |
179 | 179 | ||
180 | static int | 180 | void ccw_device_update_sense_data(struct ccw_device *cdev) |
181 | ccw_device_handle_oper(struct ccw_device *cdev) | ||
182 | { | 181 | { |
183 | struct subchannel *sch; | 182 | memset(&cdev->id, 0, sizeof(cdev->id)); |
183 | cdev->id.cu_type = cdev->private->senseid.cu_type; | ||
184 | cdev->id.cu_model = cdev->private->senseid.cu_model; | ||
185 | cdev->id.dev_type = cdev->private->senseid.dev_type; | ||
186 | cdev->id.dev_model = cdev->private->senseid.dev_model; | ||
187 | } | ||
184 | 188 | ||
185 | sch = to_subchannel(cdev->dev.parent); | 189 | int ccw_device_test_sense_data(struct ccw_device *cdev) |
186 | cdev->private->flags.recog_done = 1; | 190 | { |
187 | /* | 191 | return cdev->id.cu_type == cdev->private->senseid.cu_type && |
188 | * Check if cu type and device type still match. If | 192 | cdev->id.cu_model == cdev->private->senseid.cu_model && |
189 | * not, it is certainly another device and we have to | 193 | cdev->id.dev_type == cdev->private->senseid.dev_type && |
190 | * de- and re-register. | 194 | cdev->id.dev_model == cdev->private->senseid.dev_model; |
191 | */ | ||
192 | if (cdev->id.cu_type != cdev->private->senseid.cu_type || | ||
193 | cdev->id.cu_model != cdev->private->senseid.cu_model || | ||
194 | cdev->id.dev_type != cdev->private->senseid.dev_type || | ||
195 | cdev->id.dev_model != cdev->private->senseid.dev_model) { | ||
196 | PREPARE_WORK(&cdev->private->kick_work, | ||
197 | ccw_device_do_unbind_bind); | ||
198 | queue_work(ccw_device_work, &cdev->private->kick_work); | ||
199 | return 0; | ||
200 | } | ||
201 | cdev->private->flags.donotify = 1; | ||
202 | return 1; | ||
203 | } | 195 | } |
204 | 196 | ||
205 | /* | 197 | /* |
@@ -233,7 +225,7 @@ static void | |||
233 | ccw_device_recog_done(struct ccw_device *cdev, int state) | 225 | ccw_device_recog_done(struct ccw_device *cdev, int state) |
234 | { | 226 | { |
235 | struct subchannel *sch; | 227 | struct subchannel *sch; |
236 | int notify, old_lpm, same_dev; | 228 | int old_lpm; |
237 | 229 | ||
238 | sch = to_subchannel(cdev->dev.parent); | 230 | sch = to_subchannel(cdev->dev.parent); |
239 | 231 | ||
@@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
263 | wake_up(&cdev->private->wait_q); | 255 | wake_up(&cdev->private->wait_q); |
264 | return; | 256 | return; |
265 | } | 257 | } |
266 | notify = 0; | 258 | if (cdev->private->flags.resuming) { |
267 | same_dev = 0; /* Keep the compiler quiet... */ | 259 | cdev->private->state = state; |
260 | cdev->private->flags.recog_done = 1; | ||
261 | wake_up(&cdev->private->wait_q); | ||
262 | return; | ||
263 | } | ||
268 | switch (state) { | 264 | switch (state) { |
269 | case DEV_STATE_NOT_OPER: | 265 | case DEV_STATE_NOT_OPER: |
270 | CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " | 266 | CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " |
@@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) | |||
273 | sch->schid.ssid, sch->schid.sch_no); | 269 | sch->schid.ssid, sch->schid.sch_no); |
274 | break; | 270 | break; |
275 | case DEV_STATE_OFFLINE: | 271 | case DEV_STATE_OFFLINE: |
276 | if (cdev->online) { | 272 | if (!cdev->online) { |
277 | same_dev = ccw_device_handle_oper(cdev); | 273 | ccw_device_update_sense_data(cdev); |
278 | notify = 1; | 274 | /* Issue device info message. */ |
275 | CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " | ||
276 | "CU Type/Mod = %04X/%02X, Dev Type/Mod " | ||
277 | "= %04X/%02X\n", | ||
278 | cdev->private->dev_id.ssid, | ||
279 | cdev->private->dev_id.devno, | ||
280 | cdev->id.cu_type, cdev->id.cu_model, | ||
281 | cdev->id.dev_type, cdev->id.dev_model); | ||
282 | break; | ||
279 | } | 283 | } |
280 | /* fill out sense information */ | 284 | cdev->private->state = DEV_STATE_OFFLINE; |
281 | memset(&cdev->id, 0, sizeof(cdev->id)); | 285 | cdev->private->flags.recog_done = 1; |
282 | cdev->id.cu_type = cdev->private->senseid.cu_type; | 286 | if (ccw_device_test_sense_data(cdev)) { |
283 | cdev->id.cu_model = cdev->private->senseid.cu_model; | 287 | cdev->private->flags.donotify = 1; |
284 | cdev->id.dev_type = cdev->private->senseid.dev_type; | 288 | ccw_device_online(cdev); |
285 | cdev->id.dev_model = cdev->private->senseid.dev_model; | 289 | wake_up(&cdev->private->wait_q); |
286 | if (notify) { | 290 | } else { |
287 | cdev->private->state = DEV_STATE_OFFLINE; | 291 | ccw_device_update_sense_data(cdev); |
288 | if (same_dev) { | 292 | PREPARE_WORK(&cdev->private->kick_work, |
289 | /* Get device online again. */ | 293 | ccw_device_do_unbind_bind); |
290 | ccw_device_online(cdev); | 294 | queue_work(ccw_device_work, &cdev->private->kick_work); |
291 | wake_up(&cdev->private->wait_q); | ||
292 | } | ||
293 | return; | ||
294 | } | 295 | } |
295 | /* Issue device info message. */ | 296 | return; |
296 | CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " | ||
297 | "CU Type/Mod = %04X/%02X, Dev Type/Mod = " | ||
298 | "%04X/%02X\n", | ||
299 | cdev->private->dev_id.ssid, | ||
300 | cdev->private->dev_id.devno, | ||
301 | cdev->id.cu_type, cdev->id.cu_model, | ||
302 | cdev->id.dev_type, cdev->id.dev_model); | ||
303 | break; | ||
304 | case DEV_STATE_BOXED: | 297 | case DEV_STATE_BOXED: |
305 | CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " | 298 | CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " |
306 | " subchannel 0.%x.%04x\n", | 299 | " subchannel 0.%x.%04x\n", |
@@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev) | |||
502 | struct subchannel *sch; | 495 | struct subchannel *sch; |
503 | int ret; | 496 | int ret; |
504 | 497 | ||
505 | if ((cdev->private->state != DEV_STATE_NOT_OPER) && | ||
506 | (cdev->private->state != DEV_STATE_BOXED)) | ||
507 | return -EINVAL; | ||
508 | sch = to_subchannel(cdev->dev.parent); | 498 | sch = to_subchannel(cdev->dev.parent); |
509 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); | 499 | ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); |
510 | if (ret != 0) | 500 | if (ret != 0) |
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c index bf0a24af39a0..2d0efee8a290 100644 --- a/drivers/s390/cio/device_ops.c +++ b/drivers/s390/cio/device_ops.c | |||
@@ -1,10 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/cio/device_ops.c | 2 | * Copyright IBM Corp. 2002, 2009 |
3 | * | 3 | * |
4 | * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, | 4 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
5 | * IBM Corporation | 5 | * Cornelia Huck (cornelia.huck@de.ibm.com) |
6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | ||
7 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
8 | */ | 6 | */ |
9 | #include <linux/module.h> | 7 | #include <linux/module.h> |
10 | #include <linux/init.h> | 8 | #include <linux/init.h> |
@@ -116,12 +114,15 @@ int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm) | |||
116 | 114 | ||
117 | if (!cdev || !cdev->dev.parent) | 115 | if (!cdev || !cdev->dev.parent) |
118 | return -ENODEV; | 116 | return -ENODEV; |
117 | sch = to_subchannel(cdev->dev.parent); | ||
118 | if (!sch->schib.pmcw.ena) | ||
119 | return -EINVAL; | ||
119 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 120 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
120 | return -ENODEV; | 121 | return -ENODEV; |
121 | if (cdev->private->state != DEV_STATE_ONLINE && | 122 | if (cdev->private->state != DEV_STATE_ONLINE && |
122 | cdev->private->state != DEV_STATE_W4SENSE) | 123 | cdev->private->state != DEV_STATE_W4SENSE) |
123 | return -EINVAL; | 124 | return -EINVAL; |
124 | sch = to_subchannel(cdev->dev.parent); | 125 | |
125 | ret = cio_clear(sch); | 126 | ret = cio_clear(sch); |
126 | if (ret == 0) | 127 | if (ret == 0) |
127 | cdev->private->intparm = intparm; | 128 | cdev->private->intparm = intparm; |
@@ -162,6 +163,8 @@ int ccw_device_start_key(struct ccw_device *cdev, struct ccw1 *cpa, | |||
162 | if (!cdev || !cdev->dev.parent) | 163 | if (!cdev || !cdev->dev.parent) |
163 | return -ENODEV; | 164 | return -ENODEV; |
164 | sch = to_subchannel(cdev->dev.parent); | 165 | sch = to_subchannel(cdev->dev.parent); |
166 | if (!sch->schib.pmcw.ena) | ||
167 | return -EINVAL; | ||
165 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 168 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
166 | return -ENODEV; | 169 | return -ENODEV; |
167 | if (cdev->private->state == DEV_STATE_VERIFY || | 170 | if (cdev->private->state == DEV_STATE_VERIFY || |
@@ -337,12 +340,15 @@ int ccw_device_halt(struct ccw_device *cdev, unsigned long intparm) | |||
337 | 340 | ||
338 | if (!cdev || !cdev->dev.parent) | 341 | if (!cdev || !cdev->dev.parent) |
339 | return -ENODEV; | 342 | return -ENODEV; |
343 | sch = to_subchannel(cdev->dev.parent); | ||
344 | if (!sch->schib.pmcw.ena) | ||
345 | return -EINVAL; | ||
340 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 346 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
341 | return -ENODEV; | 347 | return -ENODEV; |
342 | if (cdev->private->state != DEV_STATE_ONLINE && | 348 | if (cdev->private->state != DEV_STATE_ONLINE && |
343 | cdev->private->state != DEV_STATE_W4SENSE) | 349 | cdev->private->state != DEV_STATE_W4SENSE) |
344 | return -EINVAL; | 350 | return -EINVAL; |
345 | sch = to_subchannel(cdev->dev.parent); | 351 | |
346 | ret = cio_halt(sch); | 352 | ret = cio_halt(sch); |
347 | if (ret == 0) | 353 | if (ret == 0) |
348 | cdev->private->intparm = intparm; | 354 | cdev->private->intparm = intparm; |
@@ -369,6 +375,8 @@ int ccw_device_resume(struct ccw_device *cdev) | |||
369 | if (!cdev || !cdev->dev.parent) | 375 | if (!cdev || !cdev->dev.parent) |
370 | return -ENODEV; | 376 | return -ENODEV; |
371 | sch = to_subchannel(cdev->dev.parent); | 377 | sch = to_subchannel(cdev->dev.parent); |
378 | if (!sch->schib.pmcw.ena) | ||
379 | return -EINVAL; | ||
372 | if (cdev->private->state == DEV_STATE_NOT_OPER) | 380 | if (cdev->private->state == DEV_STATE_NOT_OPER) |
373 | return -ENODEV; | 381 | return -ENODEV; |
374 | if (cdev->private->state != DEV_STATE_ONLINE || | 382 | if (cdev->private->state != DEV_STATE_ONLINE || |
@@ -580,6 +588,8 @@ int ccw_device_tm_start_key(struct ccw_device *cdev, struct tcw *tcw, | |||
580 | int rc; | 588 | int rc; |
581 | 589 | ||
582 | sch = to_subchannel(cdev->dev.parent); | 590 | sch = to_subchannel(cdev->dev.parent); |
591 | if (!sch->schib.pmcw.ena) | ||
592 | return -EINVAL; | ||
583 | if (cdev->private->state != DEV_STATE_ONLINE) | 593 | if (cdev->private->state != DEV_STATE_ONLINE) |
584 | return -EIO; | 594 | return -EIO; |
585 | /* Adjust requested path mask to excluded varied off paths. */ | 595 | /* Adjust requested path mask to excluded varied off paths. */ |
@@ -669,6 +679,8 @@ int ccw_device_tm_intrg(struct ccw_device *cdev) | |||
669 | { | 679 | { |
670 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 680 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
671 | 681 | ||
682 | if (!sch->schib.pmcw.ena) | ||
683 | return -EINVAL; | ||
672 | if (cdev->private->state != DEV_STATE_ONLINE) | 684 | if (cdev->private->state != DEV_STATE_ONLINE) |
673 | return -EIO; | 685 | return -EIO; |
674 | if (!scsw_is_tm(&sch->schib.scsw) || | 686 | if (!scsw_is_tm(&sch->schib.scsw) || |
diff --git a/drivers/s390/cio/io_sch.h b/drivers/s390/cio/io_sch.h index c4f3e7c9a854..0b8f381bd20e 100644 --- a/drivers/s390/cio/io_sch.h +++ b/drivers/s390/cio/io_sch.h | |||
@@ -107,6 +107,7 @@ struct ccw_device_private { | |||
107 | unsigned int recog_done:1; /* dev. recog. complete */ | 107 | unsigned int recog_done:1; /* dev. recog. complete */ |
108 | unsigned int fake_irb:1; /* deliver faked irb */ | 108 | unsigned int fake_irb:1; /* deliver faked irb */ |
109 | unsigned int intretry:1; /* retry internal operation */ | 109 | unsigned int intretry:1; /* retry internal operation */ |
110 | unsigned int resuming:1; /* recognition while resume */ | ||
110 | } __attribute__((packed)) flags; | 111 | } __attribute__((packed)) flags; |
111 | unsigned long intparm; /* user interruption parameter */ | 112 | unsigned long intparm; /* user interruption parameter */ |
112 | struct qdio_irq *qdio_data; | 113 | struct qdio_irq *qdio_data; |
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c index 7b6f46ddf3c3..d40f7a934f94 100644 --- a/drivers/s390/net/claw.c +++ b/drivers/s390/net/claw.c | |||
@@ -3,12 +3,12 @@ | |||
3 | * ESCON CLAW network driver | 3 | * ESCON CLAW network driver |
4 | * | 4 | * |
5 | * Linux for zSeries version | 5 | * Linux for zSeries version |
6 | * Copyright (C) 2002,2005 IBM Corporation | 6 | * Copyright IBM Corp. 2002, 2009 |
7 | * Author(s) Original code written by: | 7 | * Author(s) Original code written by: |
8 | * Kazuo Iimura (iimura@jp.ibm.com) | 8 | * Kazuo Iimura <iimura@jp.ibm.com> |
9 | * Rewritten by | 9 | * Rewritten by |
10 | * Andy Richter (richtera@us.ibm.com) | 10 | * Andy Richter <richtera@us.ibm.com> |
11 | * Marc Price (mwprice@us.ibm.com) | 11 | * Marc Price <mwprice@us.ibm.com> |
12 | * | 12 | * |
13 | * sysfs parms: | 13 | * sysfs parms: |
14 | * group x.x.rrrr,x.x.wwww | 14 | * group x.x.rrrr,x.x.wwww |
@@ -253,6 +253,11 @@ static void claw_free_wrt_buf(struct net_device *dev); | |||
253 | /* Functions for unpack reads */ | 253 | /* Functions for unpack reads */ |
254 | static void unpack_read(struct net_device *dev); | 254 | static void unpack_read(struct net_device *dev); |
255 | 255 | ||
256 | static int claw_pm_prepare(struct ccwgroup_device *gdev) | ||
257 | { | ||
258 | return -EPERM; | ||
259 | } | ||
260 | |||
256 | /* ccwgroup table */ | 261 | /* ccwgroup table */ |
257 | 262 | ||
258 | static struct ccwgroup_driver claw_group_driver = { | 263 | static struct ccwgroup_driver claw_group_driver = { |
@@ -264,6 +269,7 @@ static struct ccwgroup_driver claw_group_driver = { | |||
264 | .remove = claw_remove_device, | 269 | .remove = claw_remove_device, |
265 | .set_online = claw_new_device, | 270 | .set_online = claw_new_device, |
266 | .set_offline = claw_shutdown_device, | 271 | .set_offline = claw_shutdown_device, |
272 | .prepare = claw_pm_prepare, | ||
267 | }; | 273 | }; |
268 | 274 | ||
269 | /* | 275 | /* |
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c index 54c4649a493b..222e47394437 100644 --- a/drivers/s390/net/ctcm_main.c +++ b/drivers/s390/net/ctcm_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/ctcm_main.c | 2 | * drivers/s390/net/ctcm_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2001, 2007 | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * Author(s): | 5 | * Author(s): |
6 | * Original CTC driver(s): | 6 | * Original CTC driver(s): |
7 | * Fritz Elfert (felfert@millenux.com) | 7 | * Fritz Elfert (felfert@millenux.com) |
@@ -1688,6 +1688,38 @@ static void ctcm_remove_device(struct ccwgroup_device *cgdev) | |||
1688 | put_device(&cgdev->dev); | 1688 | put_device(&cgdev->dev); |
1689 | } | 1689 | } |
1690 | 1690 | ||
1691 | static int ctcm_pm_suspend(struct ccwgroup_device *gdev) | ||
1692 | { | ||
1693 | struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); | ||
1694 | |||
1695 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1696 | return 0; | ||
1697 | netif_device_detach(priv->channel[READ]->netdev); | ||
1698 | ctcm_close(priv->channel[READ]->netdev); | ||
1699 | ccw_device_set_offline(gdev->cdev[1]); | ||
1700 | ccw_device_set_offline(gdev->cdev[0]); | ||
1701 | return 0; | ||
1702 | } | ||
1703 | |||
1704 | static int ctcm_pm_resume(struct ccwgroup_device *gdev) | ||
1705 | { | ||
1706 | struct ctcm_priv *priv = dev_get_drvdata(&gdev->dev); | ||
1707 | int rc; | ||
1708 | |||
1709 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1710 | return 0; | ||
1711 | rc = ccw_device_set_online(gdev->cdev[1]); | ||
1712 | if (rc) | ||
1713 | goto err_out; | ||
1714 | rc = ccw_device_set_online(gdev->cdev[0]); | ||
1715 | if (rc) | ||
1716 | goto err_out; | ||
1717 | ctcm_open(priv->channel[READ]->netdev); | ||
1718 | err_out: | ||
1719 | netif_device_attach(priv->channel[READ]->netdev); | ||
1720 | return rc; | ||
1721 | } | ||
1722 | |||
1691 | static struct ccwgroup_driver ctcm_group_driver = { | 1723 | static struct ccwgroup_driver ctcm_group_driver = { |
1692 | .owner = THIS_MODULE, | 1724 | .owner = THIS_MODULE, |
1693 | .name = CTC_DRIVER_NAME, | 1725 | .name = CTC_DRIVER_NAME, |
@@ -1697,6 +1729,9 @@ static struct ccwgroup_driver ctcm_group_driver = { | |||
1697 | .remove = ctcm_remove_device, | 1729 | .remove = ctcm_remove_device, |
1698 | .set_online = ctcm_new_device, | 1730 | .set_online = ctcm_new_device, |
1699 | .set_offline = ctcm_shutdown_device, | 1731 | .set_offline = ctcm_shutdown_device, |
1732 | .freeze = ctcm_pm_suspend, | ||
1733 | .thaw = ctcm_pm_resume, | ||
1734 | .restore = ctcm_pm_resume, | ||
1700 | }; | 1735 | }; |
1701 | 1736 | ||
1702 | 1737 | ||
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index a45bc24eb5f9..07a25c3f94b6 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c | |||
@@ -1,15 +1,12 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/s390/net/lcs.c | ||
3 | * | ||
4 | * Linux for S/390 Lan Channel Station Network Driver | 2 | * Linux for S/390 Lan Channel Station Network Driver |
5 | * | 3 | * |
6 | * Copyright (C) 1999-2001 IBM Deutschland Entwicklung GmbH, | 4 | * Copyright IBM Corp. 1999, 2009 |
7 | * IBM Corporation | 5 | * Author(s): Original Code written by |
8 | * Author(s): Original Code written by | 6 | * DJ Barrow <djbarrow@de.ibm.com,barrow_dj@yahoo.com> |
9 | * DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) | 7 | * Rewritten by |
10 | * Rewritten by | 8 | * Frank Pavlic <fpavlic@de.ibm.com> and |
11 | * Frank Pavlic (fpavlic@de.ibm.com) and | 9 | * Martin Schwidefsky <schwidefsky@de.ibm.com> |
12 | * Martin Schwidefsky <schwidefsky@de.ibm.com> | ||
13 | * | 10 | * |
14 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
15 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -2313,6 +2310,60 @@ lcs_remove_device(struct ccwgroup_device *ccwgdev) | |||
2313 | put_device(&ccwgdev->dev); | 2310 | put_device(&ccwgdev->dev); |
2314 | } | 2311 | } |
2315 | 2312 | ||
2313 | static int lcs_pm_suspend(struct lcs_card *card) | ||
2314 | { | ||
2315 | if (card->dev) | ||
2316 | netif_device_detach(card->dev); | ||
2317 | lcs_set_allowed_threads(card, 0); | ||
2318 | lcs_wait_for_threads(card, 0xffffffff); | ||
2319 | if (card->state != DEV_STATE_DOWN) | ||
2320 | __lcs_shutdown_device(card->gdev, 1); | ||
2321 | return 0; | ||
2322 | } | ||
2323 | |||
2324 | static int lcs_pm_resume(struct lcs_card *card) | ||
2325 | { | ||
2326 | int rc = 0; | ||
2327 | |||
2328 | if (card->state == DEV_STATE_RECOVER) | ||
2329 | rc = lcs_new_device(card->gdev); | ||
2330 | if (card->dev) | ||
2331 | netif_device_attach(card->dev); | ||
2332 | if (rc) { | ||
2333 | dev_warn(&card->gdev->dev, "The lcs device driver " | ||
2334 | "failed to recover the device\n"); | ||
2335 | } | ||
2336 | return rc; | ||
2337 | } | ||
2338 | |||
2339 | static int lcs_prepare(struct ccwgroup_device *gdev) | ||
2340 | { | ||
2341 | return 0; | ||
2342 | } | ||
2343 | |||
2344 | static void lcs_complete(struct ccwgroup_device *gdev) | ||
2345 | { | ||
2346 | return; | ||
2347 | } | ||
2348 | |||
2349 | static int lcs_freeze(struct ccwgroup_device *gdev) | ||
2350 | { | ||
2351 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2352 | return lcs_pm_suspend(card); | ||
2353 | } | ||
2354 | |||
2355 | static int lcs_thaw(struct ccwgroup_device *gdev) | ||
2356 | { | ||
2357 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2358 | return lcs_pm_resume(card); | ||
2359 | } | ||
2360 | |||
2361 | static int lcs_restore(struct ccwgroup_device *gdev) | ||
2362 | { | ||
2363 | struct lcs_card *card = dev_get_drvdata(&gdev->dev); | ||
2364 | return lcs_pm_resume(card); | ||
2365 | } | ||
2366 | |||
2316 | /** | 2367 | /** |
2317 | * LCS ccwgroup driver registration | 2368 | * LCS ccwgroup driver registration |
2318 | */ | 2369 | */ |
@@ -2325,6 +2376,11 @@ static struct ccwgroup_driver lcs_group_driver = { | |||
2325 | .remove = lcs_remove_device, | 2376 | .remove = lcs_remove_device, |
2326 | .set_online = lcs_new_device, | 2377 | .set_online = lcs_new_device, |
2327 | .set_offline = lcs_shutdown_device, | 2378 | .set_offline = lcs_shutdown_device, |
2379 | .prepare = lcs_prepare, | ||
2380 | .complete = lcs_complete, | ||
2381 | .freeze = lcs_freeze, | ||
2382 | .thaw = lcs_thaw, | ||
2383 | .restore = lcs_restore, | ||
2328 | }; | 2384 | }; |
2329 | 2385 | ||
2330 | /** | 2386 | /** |
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index aec9e5d3cf4b..fdb02d043d3e 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c | |||
@@ -1,11 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV network driver | 2 | * IUCV network driver |
3 | * | 3 | * |
4 | * Copyright 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
6 | * | 5 | * |
7 | * Sysfs integration and all bugs therein by Cornelia Huck | 6 | * Author(s): |
8 | * (cornelia.huck@de.ibm.com) | 7 | * Original netiucv driver: |
8 | * Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) | ||
9 | * Sysfs integration and all bugs therein: | ||
10 | * Cornelia Huck (cornelia.huck@de.ibm.com) | ||
11 | * PM functions: | ||
12 | * Ursula Braun (ursula.braun@de.ibm.com) | ||
9 | * | 13 | * |
10 | * Documentation used: | 14 | * Documentation used: |
11 | * the source of the original IUCV driver by: | 15 | * the source of the original IUCV driver by: |
@@ -149,10 +153,27 @@ PRINT_##importance(header "%02x %02x %02x %02x %02x %02x %02x %02x " \ | |||
149 | 153 | ||
150 | #define PRINTK_HEADER " iucv: " /* for debugging */ | 154 | #define PRINTK_HEADER " iucv: " /* for debugging */ |
151 | 155 | ||
156 | /* dummy device to make sure netiucv_pm functions are called */ | ||
157 | static struct device *netiucv_dev; | ||
158 | |||
159 | static int netiucv_pm_prepare(struct device *); | ||
160 | static void netiucv_pm_complete(struct device *); | ||
161 | static int netiucv_pm_freeze(struct device *); | ||
162 | static int netiucv_pm_restore_thaw(struct device *); | ||
163 | |||
164 | static struct dev_pm_ops netiucv_pm_ops = { | ||
165 | .prepare = netiucv_pm_prepare, | ||
166 | .complete = netiucv_pm_complete, | ||
167 | .freeze = netiucv_pm_freeze, | ||
168 | .thaw = netiucv_pm_restore_thaw, | ||
169 | .restore = netiucv_pm_restore_thaw, | ||
170 | }; | ||
171 | |||
152 | static struct device_driver netiucv_driver = { | 172 | static struct device_driver netiucv_driver = { |
153 | .owner = THIS_MODULE, | 173 | .owner = THIS_MODULE, |
154 | .name = "netiucv", | 174 | .name = "netiucv", |
155 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
176 | .pm = &netiucv_pm_ops, | ||
156 | }; | 177 | }; |
157 | 178 | ||
158 | static int netiucv_callback_connreq(struct iucv_path *, | 179 | static int netiucv_callback_connreq(struct iucv_path *, |
@@ -233,6 +254,7 @@ struct netiucv_priv { | |||
233 | fsm_instance *fsm; | 254 | fsm_instance *fsm; |
234 | struct iucv_connection *conn; | 255 | struct iucv_connection *conn; |
235 | struct device *dev; | 256 | struct device *dev; |
257 | int pm_state; | ||
236 | }; | 258 | }; |
237 | 259 | ||
238 | /** | 260 | /** |
@@ -1265,6 +1287,72 @@ static int netiucv_close(struct net_device *dev) | |||
1265 | return 0; | 1287 | return 0; |
1266 | } | 1288 | } |
1267 | 1289 | ||
1290 | static int netiucv_pm_prepare(struct device *dev) | ||
1291 | { | ||
1292 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1293 | return 0; | ||
1294 | } | ||
1295 | |||
1296 | static void netiucv_pm_complete(struct device *dev) | ||
1297 | { | ||
1298 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1299 | return; | ||
1300 | } | ||
1301 | |||
1302 | /** | ||
1303 | * netiucv_pm_freeze() - Freeze PM callback | ||
1304 | * @dev: netiucv device | ||
1305 | * | ||
1306 | * close open netiucv interfaces | ||
1307 | */ | ||
1308 | static int netiucv_pm_freeze(struct device *dev) | ||
1309 | { | ||
1310 | struct netiucv_priv *priv = dev->driver_data; | ||
1311 | struct net_device *ndev = NULL; | ||
1312 | int rc = 0; | ||
1313 | |||
1314 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1315 | if (priv && priv->conn) | ||
1316 | ndev = priv->conn->netdev; | ||
1317 | if (!ndev) | ||
1318 | goto out; | ||
1319 | netif_device_detach(ndev); | ||
1320 | priv->pm_state = fsm_getstate(priv->fsm); | ||
1321 | rc = netiucv_close(ndev); | ||
1322 | out: | ||
1323 | return rc; | ||
1324 | } | ||
1325 | |||
1326 | /** | ||
1327 | * netiucv_pm_restore_thaw() - Thaw and restore PM callback | ||
1328 | * @dev: netiucv device | ||
1329 | * | ||
1330 | * re-open netiucv interfaces closed during freeze | ||
1331 | */ | ||
1332 | static int netiucv_pm_restore_thaw(struct device *dev) | ||
1333 | { | ||
1334 | struct netiucv_priv *priv = dev->driver_data; | ||
1335 | struct net_device *ndev = NULL; | ||
1336 | int rc = 0; | ||
1337 | |||
1338 | IUCV_DBF_TEXT(trace, 3, __func__); | ||
1339 | if (priv && priv->conn) | ||
1340 | ndev = priv->conn->netdev; | ||
1341 | if (!ndev) | ||
1342 | goto out; | ||
1343 | switch (priv->pm_state) { | ||
1344 | case DEV_STATE_RUNNING: | ||
1345 | case DEV_STATE_STARTWAIT: | ||
1346 | rc = netiucv_open(ndev); | ||
1347 | break; | ||
1348 | default: | ||
1349 | break; | ||
1350 | } | ||
1351 | netif_device_attach(ndev); | ||
1352 | out: | ||
1353 | return rc; | ||
1354 | } | ||
1355 | |||
1268 | /** | 1356 | /** |
1269 | * Start transmission of a packet. | 1357 | * Start transmission of a packet. |
1270 | * Called from generic network device layer. | 1358 | * Called from generic network device layer. |
@@ -1731,7 +1819,6 @@ static int netiucv_register_device(struct net_device *ndev) | |||
1731 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); | 1819 | struct device *dev = kzalloc(sizeof(struct device), GFP_KERNEL); |
1732 | int ret; | 1820 | int ret; |
1733 | 1821 | ||
1734 | |||
1735 | IUCV_DBF_TEXT(trace, 3, __func__); | 1822 | IUCV_DBF_TEXT(trace, 3, __func__); |
1736 | 1823 | ||
1737 | if (dev) { | 1824 | if (dev) { |
@@ -2100,6 +2187,7 @@ static void __exit netiucv_exit(void) | |||
2100 | netiucv_unregister_device(dev); | 2187 | netiucv_unregister_device(dev); |
2101 | } | 2188 | } |
2102 | 2189 | ||
2190 | device_unregister(netiucv_dev); | ||
2103 | driver_unregister(&netiucv_driver); | 2191 | driver_unregister(&netiucv_driver); |
2104 | iucv_unregister(&netiucv_handler, 1); | 2192 | iucv_unregister(&netiucv_handler, 1); |
2105 | iucv_unregister_dbf_views(); | 2193 | iucv_unregister_dbf_views(); |
@@ -2125,10 +2213,25 @@ static int __init netiucv_init(void) | |||
2125 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); | 2213 | IUCV_DBF_TEXT_(setup, 2, "ret %d from driver_register\n", rc); |
2126 | goto out_iucv; | 2214 | goto out_iucv; |
2127 | } | 2215 | } |
2128 | 2216 | /* establish dummy device */ | |
2217 | netiucv_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
2218 | if (!netiucv_dev) { | ||
2219 | rc = -ENOMEM; | ||
2220 | goto out_driver; | ||
2221 | } | ||
2222 | dev_set_name(netiucv_dev, "netiucv"); | ||
2223 | netiucv_dev->bus = &iucv_bus; | ||
2224 | netiucv_dev->parent = iucv_root; | ||
2225 | netiucv_dev->release = (void (*)(struct device *))kfree; | ||
2226 | netiucv_dev->driver = &netiucv_driver; | ||
2227 | rc = device_register(netiucv_dev); | ||
2228 | if (rc) | ||
2229 | goto out_driver; | ||
2129 | netiucv_banner(); | 2230 | netiucv_banner(); |
2130 | return rc; | 2231 | return rc; |
2131 | 2232 | ||
2233 | out_driver: | ||
2234 | driver_unregister(&netiucv_driver); | ||
2132 | out_iucv: | 2235 | out_iucv: |
2133 | iucv_unregister(&netiucv_handler, 1); | 2236 | iucv_unregister(&netiucv_handler, 1); |
2134 | out_dbf: | 2237 | out_dbf: |
diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index 74c49d9a8dba..d53621c4acbb 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_core_main.c | 2 | * drivers/s390/net/qeth_core_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -4195,6 +4195,50 @@ static void qeth_core_shutdown(struct ccwgroup_device *gdev) | |||
4195 | card->discipline.ccwgdriver->shutdown(gdev); | 4195 | card->discipline.ccwgdriver->shutdown(gdev); |
4196 | } | 4196 | } |
4197 | 4197 | ||
4198 | static int qeth_core_prepare(struct ccwgroup_device *gdev) | ||
4199 | { | ||
4200 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4201 | if (card->discipline.ccwgdriver && | ||
4202 | card->discipline.ccwgdriver->prepare) | ||
4203 | return card->discipline.ccwgdriver->prepare(gdev); | ||
4204 | return 0; | ||
4205 | } | ||
4206 | |||
4207 | static void qeth_core_complete(struct ccwgroup_device *gdev) | ||
4208 | { | ||
4209 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4210 | if (card->discipline.ccwgdriver && | ||
4211 | card->discipline.ccwgdriver->complete) | ||
4212 | card->discipline.ccwgdriver->complete(gdev); | ||
4213 | } | ||
4214 | |||
4215 | static int qeth_core_freeze(struct ccwgroup_device *gdev) | ||
4216 | { | ||
4217 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4218 | if (card->discipline.ccwgdriver && | ||
4219 | card->discipline.ccwgdriver->freeze) | ||
4220 | return card->discipline.ccwgdriver->freeze(gdev); | ||
4221 | return 0; | ||
4222 | } | ||
4223 | |||
4224 | static int qeth_core_thaw(struct ccwgroup_device *gdev) | ||
4225 | { | ||
4226 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4227 | if (card->discipline.ccwgdriver && | ||
4228 | card->discipline.ccwgdriver->thaw) | ||
4229 | return card->discipline.ccwgdriver->thaw(gdev); | ||
4230 | return 0; | ||
4231 | } | ||
4232 | |||
4233 | static int qeth_core_restore(struct ccwgroup_device *gdev) | ||
4234 | { | ||
4235 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
4236 | if (card->discipline.ccwgdriver && | ||
4237 | card->discipline.ccwgdriver->restore) | ||
4238 | return card->discipline.ccwgdriver->restore(gdev); | ||
4239 | return 0; | ||
4240 | } | ||
4241 | |||
4198 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | 4242 | static struct ccwgroup_driver qeth_core_ccwgroup_driver = { |
4199 | .owner = THIS_MODULE, | 4243 | .owner = THIS_MODULE, |
4200 | .name = "qeth", | 4244 | .name = "qeth", |
@@ -4204,6 +4248,11 @@ static struct ccwgroup_driver qeth_core_ccwgroup_driver = { | |||
4204 | .set_online = qeth_core_set_online, | 4248 | .set_online = qeth_core_set_online, |
4205 | .set_offline = qeth_core_set_offline, | 4249 | .set_offline = qeth_core_set_offline, |
4206 | .shutdown = qeth_core_shutdown, | 4250 | .shutdown = qeth_core_shutdown, |
4251 | .prepare = qeth_core_prepare, | ||
4252 | .complete = qeth_core_complete, | ||
4253 | .freeze = qeth_core_freeze, | ||
4254 | .thaw = qeth_core_thaw, | ||
4255 | .restore = qeth_core_restore, | ||
4207 | }; | 4256 | }; |
4208 | 4257 | ||
4209 | static ssize_t | 4258 | static ssize_t |
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ecd3d06c0d5c..81d7f268418a 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_l2_main.c | 2 | * drivers/s390/net/qeth_l2_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -1141,12 +1141,62 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) | |||
1141 | qeth_clear_qdio_buffers(card); | 1141 | qeth_clear_qdio_buffers(card); |
1142 | } | 1142 | } |
1143 | 1143 | ||
1144 | static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) | ||
1145 | { | ||
1146 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
1147 | |||
1148 | if (card->dev) | ||
1149 | netif_device_detach(card->dev); | ||
1150 | qeth_set_allowed_threads(card, 0, 1); | ||
1151 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | ||
1152 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1153 | return 0; | ||
1154 | if (card->state == CARD_STATE_UP) { | ||
1155 | card->use_hard_stop = 1; | ||
1156 | __qeth_l2_set_offline(card->gdev, 1); | ||
1157 | } else | ||
1158 | __qeth_l2_set_offline(card->gdev, 0); | ||
1159 | return 0; | ||
1160 | } | ||
1161 | |||
1162 | static int qeth_l2_pm_resume(struct ccwgroup_device *gdev) | ||
1163 | { | ||
1164 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
1165 | int rc = 0; | ||
1166 | |||
1167 | if (gdev->state == CCWGROUP_OFFLINE) | ||
1168 | goto out; | ||
1169 | |||
1170 | if (card->state == CARD_STATE_RECOVER) { | ||
1171 | rc = __qeth_l2_set_online(card->gdev, 1); | ||
1172 | if (rc) { | ||
1173 | if (card->dev) { | ||
1174 | rtnl_lock(); | ||
1175 | dev_close(card->dev); | ||
1176 | rtnl_unlock(); | ||
1177 | } | ||
1178 | } | ||
1179 | } else | ||
1180 | rc = __qeth_l2_set_online(card->gdev, 0); | ||
1181 | out: | ||
1182 | qeth_set_allowed_threads(card, 0xffffffff, 0); | ||
1183 | if (card->dev) | ||
1184 | netif_device_attach(card->dev); | ||
1185 | if (rc) | ||
1186 | dev_warn(&card->gdev->dev, "The qeth device driver " | ||
1187 | "failed to recover an error on the device\n"); | ||
1188 | return rc; | ||
1189 | } | ||
1190 | |||
1144 | struct ccwgroup_driver qeth_l2_ccwgroup_driver = { | 1191 | struct ccwgroup_driver qeth_l2_ccwgroup_driver = { |
1145 | .probe = qeth_l2_probe_device, | 1192 | .probe = qeth_l2_probe_device, |
1146 | .remove = qeth_l2_remove_device, | 1193 | .remove = qeth_l2_remove_device, |
1147 | .set_online = qeth_l2_set_online, | 1194 | .set_online = qeth_l2_set_online, |
1148 | .set_offline = qeth_l2_set_offline, | 1195 | .set_offline = qeth_l2_set_offline, |
1149 | .shutdown = qeth_l2_shutdown, | 1196 | .shutdown = qeth_l2_shutdown, |
1197 | .freeze = qeth_l2_pm_suspend, | ||
1198 | .thaw = qeth_l2_pm_resume, | ||
1199 | .restore = qeth_l2_pm_resume, | ||
1150 | }; | 1200 | }; |
1151 | EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); | 1201 | EXPORT_SYMBOL_GPL(qeth_l2_ccwgroup_driver); |
1152 | 1202 | ||
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 6f2386e9d6e2..54872406864e 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * drivers/s390/net/qeth_l3_main.c | 2 | * drivers/s390/net/qeth_l3_main.c |
3 | * | 3 | * |
4 | * Copyright IBM Corp. 2007 | 4 | * Copyright IBM Corp. 2007, 2009 |
5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, | 5 | * Author(s): Utz Bacher <utz.bacher@de.ibm.com>, |
6 | * Frank Pavlic <fpavlic@de.ibm.com>, | 6 | * Frank Pavlic <fpavlic@de.ibm.com>, |
7 | * Thomas Spatzier <tspat@de.ibm.com>, | 7 | * Thomas Spatzier <tspat@de.ibm.com>, |
@@ -3283,12 +3283,62 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev) | |||
3283 | qeth_clear_qdio_buffers(card); | 3283 | qeth_clear_qdio_buffers(card); |
3284 | } | 3284 | } |
3285 | 3285 | ||
3286 | static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) | ||
3287 | { | ||
3288 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
3289 | |||
3290 | if (card->dev) | ||
3291 | netif_device_detach(card->dev); | ||
3292 | qeth_set_allowed_threads(card, 0, 1); | ||
3293 | wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); | ||
3294 | if (gdev->state == CCWGROUP_OFFLINE) | ||
3295 | return 0; | ||
3296 | if (card->state == CARD_STATE_UP) { | ||
3297 | card->use_hard_stop = 1; | ||
3298 | __qeth_l3_set_offline(card->gdev, 1); | ||
3299 | } else | ||
3300 | __qeth_l3_set_offline(card->gdev, 0); | ||
3301 | return 0; | ||
3302 | } | ||
3303 | |||
3304 | static int qeth_l3_pm_resume(struct ccwgroup_device *gdev) | ||
3305 | { | ||
3306 | struct qeth_card *card = dev_get_drvdata(&gdev->dev); | ||
3307 | int rc = 0; | ||
3308 | |||
3309 | if (gdev->state == CCWGROUP_OFFLINE) | ||
3310 | goto out; | ||
3311 | |||
3312 | if (card->state == CARD_STATE_RECOVER) { | ||
3313 | rc = __qeth_l3_set_online(card->gdev, 1); | ||
3314 | if (rc) { | ||
3315 | if (card->dev) { | ||
3316 | rtnl_lock(); | ||
3317 | dev_close(card->dev); | ||
3318 | rtnl_unlock(); | ||
3319 | } | ||
3320 | } | ||
3321 | } else | ||
3322 | rc = __qeth_l3_set_online(card->gdev, 0); | ||
3323 | out: | ||
3324 | qeth_set_allowed_threads(card, 0xffffffff, 0); | ||
3325 | if (card->dev) | ||
3326 | netif_device_attach(card->dev); | ||
3327 | if (rc) | ||
3328 | dev_warn(&card->gdev->dev, "The qeth device driver " | ||
3329 | "failed to recover an error on the device\n"); | ||
3330 | return rc; | ||
3331 | } | ||
3332 | |||
3286 | struct ccwgroup_driver qeth_l3_ccwgroup_driver = { | 3333 | struct ccwgroup_driver qeth_l3_ccwgroup_driver = { |
3287 | .probe = qeth_l3_probe_device, | 3334 | .probe = qeth_l3_probe_device, |
3288 | .remove = qeth_l3_remove_device, | 3335 | .remove = qeth_l3_remove_device, |
3289 | .set_online = qeth_l3_set_online, | 3336 | .set_online = qeth_l3_set_online, |
3290 | .set_offline = qeth_l3_set_offline, | 3337 | .set_offline = qeth_l3_set_offline, |
3291 | .shutdown = qeth_l3_shutdown, | 3338 | .shutdown = qeth_l3_shutdown, |
3339 | .freeze = qeth_l3_pm_suspend, | ||
3340 | .thaw = qeth_l3_pm_resume, | ||
3341 | .restore = qeth_l3_pm_resume, | ||
3292 | }; | 3342 | }; |
3293 | EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); | 3343 | EXPORT_SYMBOL_GPL(qeth_l3_ccwgroup_driver); |
3294 | 3344 | ||
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c index 164e090c2625..e76a320d373b 100644 --- a/drivers/s390/net/smsgiucv.c +++ b/drivers/s390/net/smsgiucv.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV special message driver | 2 | * IUCV special message driver |
3 | * | 3 | * |
4 | * Copyright 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2003, 2009 |
5 | * | ||
5 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) | 6 | * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com) |
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
@@ -40,6 +41,8 @@ MODULE_AUTHOR | |||
40 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); | 41 | MODULE_DESCRIPTION ("Linux for S/390 IUCV special message driver"); |
41 | 42 | ||
42 | static struct iucv_path *smsg_path; | 43 | static struct iucv_path *smsg_path; |
44 | /* dummy device used as trigger for PM functions */ | ||
45 | static struct device *smsg_dev; | ||
43 | 46 | ||
44 | static DEFINE_SPINLOCK(smsg_list_lock); | 47 | static DEFINE_SPINLOCK(smsg_list_lock); |
45 | static LIST_HEAD(smsg_list); | 48 | static LIST_HEAD(smsg_list); |
@@ -132,14 +135,51 @@ void smsg_unregister_callback(char *prefix, | |||
132 | kfree(cb); | 135 | kfree(cb); |
133 | } | 136 | } |
134 | 137 | ||
138 | static int smsg_pm_freeze(struct device *dev) | ||
139 | { | ||
140 | #ifdef CONFIG_PM_DEBUG | ||
141 | printk(KERN_WARNING "smsg_pm_freeze\n"); | ||
142 | #endif | ||
143 | if (smsg_path) | ||
144 | iucv_path_sever(smsg_path, NULL); | ||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int smsg_pm_restore_thaw(struct device *dev) | ||
149 | { | ||
150 | int rc; | ||
151 | |||
152 | #ifdef CONFIG_PM_DEBUG | ||
153 | printk(KERN_WARNING "smsg_pm_restore_thaw\n"); | ||
154 | #endif | ||
155 | if (smsg_path) { | ||
156 | memset(smsg_path, 0, sizeof(*smsg_path)); | ||
157 | smsg_path->msglim = 255; | ||
158 | smsg_path->flags = 0; | ||
159 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | ||
160 | NULL, NULL, NULL); | ||
161 | printk(KERN_ERR "iucv_path_connect returned with rc %i\n", rc); | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | static struct dev_pm_ops smsg_pm_ops = { | ||
167 | .freeze = smsg_pm_freeze, | ||
168 | .thaw = smsg_pm_restore_thaw, | ||
169 | .restore = smsg_pm_restore_thaw, | ||
170 | }; | ||
171 | |||
135 | static struct device_driver smsg_driver = { | 172 | static struct device_driver smsg_driver = { |
173 | .owner = THIS_MODULE, | ||
136 | .name = "SMSGIUCV", | 174 | .name = "SMSGIUCV", |
137 | .bus = &iucv_bus, | 175 | .bus = &iucv_bus, |
176 | .pm = &smsg_pm_ops, | ||
138 | }; | 177 | }; |
139 | 178 | ||
140 | static void __exit smsg_exit(void) | 179 | static void __exit smsg_exit(void) |
141 | { | 180 | { |
142 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 181 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
182 | device_unregister(smsg_dev); | ||
143 | iucv_unregister(&smsg_handler, 1); | 183 | iucv_unregister(&smsg_handler, 1); |
144 | driver_unregister(&smsg_driver); | 184 | driver_unregister(&smsg_driver); |
145 | } | 185 | } |
@@ -166,12 +206,29 @@ static int __init smsg_init(void) | |||
166 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", | 206 | rc = iucv_path_connect(smsg_path, &smsg_handler, "*MSG ", |
167 | NULL, NULL, NULL); | 207 | NULL, NULL, NULL); |
168 | if (rc) | 208 | if (rc) |
169 | goto out_free; | 209 | goto out_free_path; |
210 | smsg_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
211 | if (!smsg_dev) { | ||
212 | rc = -ENOMEM; | ||
213 | goto out_free_path; | ||
214 | } | ||
215 | dev_set_name(smsg_dev, "smsg_iucv"); | ||
216 | smsg_dev->bus = &iucv_bus; | ||
217 | smsg_dev->parent = iucv_root; | ||
218 | smsg_dev->release = (void (*)(struct device *))kfree; | ||
219 | smsg_dev->driver = &smsg_driver; | ||
220 | rc = device_register(smsg_dev); | ||
221 | if (rc) | ||
222 | goto out_free_dev; | ||
223 | |||
170 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); | 224 | cpcmd("SET SMSG IUCV", NULL, 0, NULL); |
171 | return 0; | 225 | return 0; |
172 | 226 | ||
173 | out_free: | 227 | out_free_dev: |
228 | kfree(smsg_dev); | ||
229 | out_free_path: | ||
174 | iucv_path_free(smsg_path); | 230 | iucv_path_free(smsg_path); |
231 | smsg_path = NULL; | ||
175 | out_register: | 232 | out_register: |
176 | iucv_unregister(&smsg_handler, 1); | 233 | iucv_unregister(&smsg_handler, 1); |
177 | out_driver: | 234 | out_driver: |
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c index b2fe5cdbcaee..d9da5c42ccbe 100644 --- a/drivers/s390/scsi/zfcp_ccw.c +++ b/drivers/s390/scsi/zfcp_ccw.c | |||
@@ -13,6 +13,36 @@ | |||
13 | 13 | ||
14 | #define ZFCP_MODEL_PRIV 0x4 | 14 | #define ZFCP_MODEL_PRIV 0x4 |
15 | 15 | ||
16 | static int zfcp_ccw_suspend(struct ccw_device *cdev) | ||
17 | |||
18 | { | ||
19 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | ||
20 | |||
21 | down(&zfcp_data.config_sema); | ||
22 | |||
23 | zfcp_erp_adapter_shutdown(adapter, 0, "ccsusp1", NULL); | ||
24 | zfcp_erp_wait(adapter); | ||
25 | |||
26 | up(&zfcp_data.config_sema); | ||
27 | |||
28 | return 0; | ||
29 | } | ||
30 | |||
31 | static int zfcp_ccw_activate(struct ccw_device *cdev) | ||
32 | |||
33 | { | ||
34 | struct zfcp_adapter *adapter = dev_get_drvdata(&cdev->dev); | ||
35 | |||
36 | zfcp_erp_modify_adapter_status(adapter, "ccresu1", NULL, | ||
37 | ZFCP_STATUS_COMMON_RUNNING, ZFCP_SET); | ||
38 | zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED, | ||
39 | "ccresu2", NULL); | ||
40 | zfcp_erp_wait(adapter); | ||
41 | flush_work(&adapter->scan_work); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
16 | static struct ccw_device_id zfcp_ccw_device_id[] = { | 46 | static struct ccw_device_id zfcp_ccw_device_id[] = { |
17 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, | 47 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, 0x3) }, |
18 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) }, | 48 | { CCW_DEVICE_DEVTYPE(0x1731, 0x3, 0x1732, ZFCP_MODEL_PRIV) }, |
@@ -227,6 +257,9 @@ static struct ccw_driver zfcp_ccw_driver = { | |||
227 | .set_offline = zfcp_ccw_set_offline, | 257 | .set_offline = zfcp_ccw_set_offline, |
228 | .notify = zfcp_ccw_notify, | 258 | .notify = zfcp_ccw_notify, |
229 | .shutdown = zfcp_ccw_shutdown, | 259 | .shutdown = zfcp_ccw_shutdown, |
260 | .freeze = zfcp_ccw_suspend, | ||
261 | .thaw = zfcp_ccw_activate, | ||
262 | .restore = zfcp_ccw_activate, | ||
230 | }; | 263 | }; |
231 | 264 | ||
232 | /** | 265 | /** |
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 124f660a0383..75ac19b1192f 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c | |||
@@ -303,7 +303,7 @@ static int openprom_sunos_ioctl(struct inode * inode, struct file * file, | |||
303 | struct device_node *dp) | 303 | struct device_node *dp) |
304 | { | 304 | { |
305 | DATA *data = file->private_data; | 305 | DATA *data = file->private_data; |
306 | struct openpromio *opp; | 306 | struct openpromio *opp = NULL; |
307 | int bufsize, error = 0; | 307 | int bufsize, error = 0; |
308 | static int cnt; | 308 | static int cnt; |
309 | void __user *argp = (void __user *)arg; | 309 | void __user *argp = (void __user *)arg; |
diff --git a/drivers/spi/spi_bfin5xx.c b/drivers/spi/spi_bfin5xx.c index f014cc21e813..011c5bddba6a 100644 --- a/drivers/spi/spi_bfin5xx.c +++ b/drivers/spi/spi_bfin5xx.c | |||
@@ -803,7 +803,7 @@ static void bfin_spi_pump_transfers(unsigned long data) | |||
803 | drv_data->rx, drv_data->len_in_bytes); | 803 | drv_data->rx, drv_data->len_in_bytes); |
804 | 804 | ||
805 | /* invalidate caches, if needed */ | 805 | /* invalidate caches, if needed */ |
806 | if (bfin_addr_dcachable((unsigned long) drv_data->rx)) | 806 | if (bfin_addr_dcacheable((unsigned long) drv_data->rx)) |
807 | invalidate_dcache_range((unsigned long) drv_data->rx, | 807 | invalidate_dcache_range((unsigned long) drv_data->rx, |
808 | (unsigned long) (drv_data->rx + | 808 | (unsigned long) (drv_data->rx + |
809 | drv_data->len_in_bytes)); | 809 | drv_data->len_in_bytes)); |
@@ -816,7 +816,7 @@ static void bfin_spi_pump_transfers(unsigned long data) | |||
816 | dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); | 816 | dev_dbg(&drv_data->pdev->dev, "doing DMA out.\n"); |
817 | 817 | ||
818 | /* flush caches, if needed */ | 818 | /* flush caches, if needed */ |
819 | if (bfin_addr_dcachable((unsigned long) drv_data->tx)) | 819 | if (bfin_addr_dcacheable((unsigned long) drv_data->tx)) |
820 | flush_dcache_range((unsigned long) drv_data->tx, | 820 | flush_dcache_range((unsigned long) drv_data->tx, |
821 | (unsigned long) (drv_data->tx + | 821 | (unsigned long) (drv_data->tx + |
822 | drv_data->len_in_bytes)); | 822 | drv_data->len_in_bytes)); |
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c index 1ba9f9a8c308..bb870b8f81bc 100644 --- a/drivers/usb/host/ehci-ps3.c +++ b/drivers/usb/host/ehci-ps3.c | |||
@@ -162,7 +162,7 @@ static int ps3_ehci_probe(struct ps3_system_bus_device *dev) | |||
162 | dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, | 162 | dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, |
163 | (unsigned long)virq); | 163 | (unsigned long)virq); |
164 | 164 | ||
165 | ps3_system_bus_set_driver_data(dev, hcd); | 165 | ps3_system_bus_set_drvdata(dev, hcd); |
166 | 166 | ||
167 | result = usb_add_hcd(hcd, virq, IRQF_DISABLED); | 167 | result = usb_add_hcd(hcd, virq, IRQF_DISABLED); |
168 | 168 | ||
@@ -195,8 +195,7 @@ fail_start: | |||
195 | static int ps3_ehci_remove(struct ps3_system_bus_device *dev) | 195 | static int ps3_ehci_remove(struct ps3_system_bus_device *dev) |
196 | { | 196 | { |
197 | unsigned int tmp; | 197 | unsigned int tmp; |
198 | struct usb_hcd *hcd = | 198 | struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); |
199 | (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); | ||
200 | 199 | ||
201 | BUG_ON(!hcd); | 200 | BUG_ON(!hcd); |
202 | 201 | ||
@@ -208,7 +207,7 @@ static int ps3_ehci_remove(struct ps3_system_bus_device *dev) | |||
208 | ehci_shutdown(hcd); | 207 | ehci_shutdown(hcd); |
209 | usb_remove_hcd(hcd); | 208 | usb_remove_hcd(hcd); |
210 | 209 | ||
211 | ps3_system_bus_set_driver_data(dev, NULL); | 210 | ps3_system_bus_set_drvdata(dev, NULL); |
212 | 211 | ||
213 | BUG_ON(!hcd->regs); | 212 | BUG_ON(!hcd->regs); |
214 | iounmap(hcd->regs); | 213 | iounmap(hcd->regs); |
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 3d1910317328..1d56259c5db1 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c | |||
@@ -162,7 +162,7 @@ static int ps3_ohci_probe(struct ps3_system_bus_device *dev) | |||
162 | dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, | 162 | dev_dbg(&dev->core, "%s:%d: virq %lu\n", __func__, __LINE__, |
163 | (unsigned long)virq); | 163 | (unsigned long)virq); |
164 | 164 | ||
165 | ps3_system_bus_set_driver_data(dev, hcd); | 165 | ps3_system_bus_set_drvdata(dev, hcd); |
166 | 166 | ||
167 | result = usb_add_hcd(hcd, virq, IRQF_DISABLED); | 167 | result = usb_add_hcd(hcd, virq, IRQF_DISABLED); |
168 | 168 | ||
@@ -195,8 +195,7 @@ fail_start: | |||
195 | static int ps3_ohci_remove(struct ps3_system_bus_device *dev) | 195 | static int ps3_ohci_remove(struct ps3_system_bus_device *dev) |
196 | { | 196 | { |
197 | unsigned int tmp; | 197 | unsigned int tmp; |
198 | struct usb_hcd *hcd = | 198 | struct usb_hcd *hcd = ps3_system_bus_get_drvdata(dev); |
199 | (struct usb_hcd *)ps3_system_bus_get_driver_data(dev); | ||
200 | 199 | ||
201 | BUG_ON(!hcd); | 200 | BUG_ON(!hcd); |
202 | 201 | ||
@@ -208,7 +207,7 @@ static int ps3_ohci_remove(struct ps3_system_bus_device *dev) | |||
208 | ohci_shutdown(hcd); | 207 | ohci_shutdown(hcd); |
209 | usb_remove_hcd(hcd); | 208 | usb_remove_hcd(hcd); |
210 | 209 | ||
211 | ps3_system_bus_set_driver_data(dev, NULL); | 210 | ps3_system_bus_set_drvdata(dev, NULL); |
212 | 211 | ||
213 | BUG_ON(!hcd->regs); | 212 | BUG_ON(!hcd->regs); |
214 | iounmap(hcd->regs); | 213 | iounmap(hcd->regs); |
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c index 1e35ba6f18e0..b0b147cb4cb3 100644 --- a/drivers/video/bw2.c +++ b/drivers/video/bw2.c | |||
@@ -111,9 +111,7 @@ struct bw2_par { | |||
111 | u32 flags; | 111 | u32 flags; |
112 | #define BW2_FLAG_BLANKED 0x00000001 | 112 | #define BW2_FLAG_BLANKED 0x00000001 |
113 | 113 | ||
114 | unsigned long physbase; | ||
115 | unsigned long which_io; | 114 | unsigned long which_io; |
116 | unsigned long fbsize; | ||
117 | }; | 115 | }; |
118 | 116 | ||
119 | /** | 117 | /** |
@@ -167,17 +165,15 @@ static int bw2_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
167 | struct bw2_par *par = (struct bw2_par *)info->par; | 165 | struct bw2_par *par = (struct bw2_par *)info->par; |
168 | 166 | ||
169 | return sbusfb_mmap_helper(bw2_mmap_map, | 167 | return sbusfb_mmap_helper(bw2_mmap_map, |
170 | par->physbase, par->fbsize, | 168 | info->fix.smem_start, info->fix.smem_len, |
171 | par->which_io, | 169 | par->which_io, |
172 | vma); | 170 | vma); |
173 | } | 171 | } |
174 | 172 | ||
175 | static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | 173 | static int bw2_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) |
176 | { | 174 | { |
177 | struct bw2_par *par = (struct bw2_par *) info->par; | ||
178 | |||
179 | return sbusfb_ioctl_helper(cmd, arg, info, | 175 | return sbusfb_ioctl_helper(cmd, arg, info, |
180 | FBTYPE_SUN2BW, 1, par->fbsize); | 176 | FBTYPE_SUN2BW, 1, info->fix.smem_len); |
181 | } | 177 | } |
182 | 178 | ||
183 | /* | 179 | /* |
@@ -294,7 +290,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * | |||
294 | 290 | ||
295 | spin_lock_init(&par->lock); | 291 | spin_lock_init(&par->lock); |
296 | 292 | ||
297 | par->physbase = op->resource[0].start; | 293 | info->fix.smem_start = op->resource[0].start; |
298 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; | 294 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
299 | 295 | ||
300 | sbusfb_fill_var(&info->var, dp, 1); | 296 | sbusfb_fill_var(&info->var, dp, 1); |
@@ -317,13 +313,13 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * | |||
317 | goto out_unmap_regs; | 313 | goto out_unmap_regs; |
318 | } | 314 | } |
319 | 315 | ||
320 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | 316 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
321 | 317 | ||
322 | info->flags = FBINFO_DEFAULT; | 318 | info->flags = FBINFO_DEFAULT; |
323 | info->fbops = &bw2_ops; | 319 | info->fbops = &bw2_ops; |
324 | 320 | ||
325 | info->screen_base = of_ioremap(&op->resource[0], 0, | 321 | info->screen_base = of_ioremap(&op->resource[0], 0, |
326 | par->fbsize, "bw2 ram"); | 322 | info->fix.smem_len, "bw2 ram"); |
327 | if (!info->screen_base) | 323 | if (!info->screen_base) |
328 | goto out_unmap_regs; | 324 | goto out_unmap_regs; |
329 | 325 | ||
@@ -338,12 +334,12 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id * | |||
338 | dev_set_drvdata(&op->dev, info); | 334 | dev_set_drvdata(&op->dev, info); |
339 | 335 | ||
340 | printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", | 336 | printk(KERN_INFO "%s: bwtwo at %lx:%lx\n", |
341 | dp->full_name, par->which_io, par->physbase); | 337 | dp->full_name, par->which_io, info->fix.smem_start); |
342 | 338 | ||
343 | return 0; | 339 | return 0; |
344 | 340 | ||
345 | out_unmap_screen: | 341 | out_unmap_screen: |
346 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); | 342 | of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); |
347 | 343 | ||
348 | out_unmap_regs: | 344 | out_unmap_regs: |
349 | of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); | 345 | of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); |
@@ -363,7 +359,7 @@ static int __devexit bw2_remove(struct of_device *op) | |||
363 | unregister_framebuffer(info); | 359 | unregister_framebuffer(info); |
364 | 360 | ||
365 | of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); | 361 | of_iounmap(&op->resource[0], par->regs, sizeof(struct bw2_regs)); |
366 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); | 362 | of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); |
367 | 363 | ||
368 | framebuffer_release(info); | 364 | framebuffer_release(info); |
369 | 365 | ||
diff --git a/drivers/video/cg14.c b/drivers/video/cg14.c index a2d1882791a5..fe45a3b8d0e0 100644 --- a/drivers/video/cg14.c +++ b/drivers/video/cg14.c | |||
@@ -196,9 +196,7 @@ struct cg14_par { | |||
196 | u32 flags; | 196 | u32 flags; |
197 | #define CG14_FLAG_BLANKED 0x00000001 | 197 | #define CG14_FLAG_BLANKED 0x00000001 |
198 | 198 | ||
199 | unsigned long physbase; | ||
200 | unsigned long iospace; | 199 | unsigned long iospace; |
201 | unsigned long fbsize; | ||
202 | 200 | ||
203 | struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; | 201 | struct sbus_mmap_map mmap_map[CG14_MMAP_ENTRIES]; |
204 | 202 | ||
@@ -271,7 +269,7 @@ static int cg14_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
271 | struct cg14_par *par = (struct cg14_par *) info->par; | 269 | struct cg14_par *par = (struct cg14_par *) info->par; |
272 | 270 | ||
273 | return sbusfb_mmap_helper(par->mmap_map, | 271 | return sbusfb_mmap_helper(par->mmap_map, |
274 | par->physbase, par->fbsize, | 272 | info->fix.smem_start, info->fix.smem_len, |
275 | par->iospace, vma); | 273 | par->iospace, vma); |
276 | } | 274 | } |
277 | 275 | ||
@@ -343,7 +341,8 @@ static int cg14_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | |||
343 | 341 | ||
344 | default: | 342 | default: |
345 | ret = sbusfb_ioctl_helper(cmd, arg, info, | 343 | ret = sbusfb_ioctl_helper(cmd, arg, info, |
346 | FBTYPE_MDICOLOR, 8, par->fbsize); | 344 | FBTYPE_MDICOLOR, 8, |
345 | info->fix.smem_len); | ||
347 | break; | 346 | break; |
348 | }; | 347 | }; |
349 | 348 | ||
@@ -462,7 +461,7 @@ static void cg14_unmap_regs(struct of_device *op, struct fb_info *info, | |||
462 | par->cursor, sizeof(struct cg14_cursor)); | 461 | par->cursor, sizeof(struct cg14_cursor)); |
463 | if (info->screen_base) | 462 | if (info->screen_base) |
464 | of_iounmap(&op->resource[1], | 463 | of_iounmap(&op->resource[1], |
465 | info->screen_base, par->fbsize); | 464 | info->screen_base, info->fix.smem_len); |
466 | } | 465 | } |
467 | 466 | ||
468 | static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) | 467 | static int __devinit cg14_probe(struct of_device *op, const struct of_device_id *match) |
@@ -488,14 +487,14 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id | |||
488 | 487 | ||
489 | linebytes = of_getintprop_default(dp, "linebytes", | 488 | linebytes = of_getintprop_default(dp, "linebytes", |
490 | info->var.xres); | 489 | info->var.xres); |
491 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | 490 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
492 | 491 | ||
493 | if (!strcmp(dp->parent->name, "sbus") || | 492 | if (!strcmp(dp->parent->name, "sbus") || |
494 | !strcmp(dp->parent->name, "sbi")) { | 493 | !strcmp(dp->parent->name, "sbi")) { |
495 | par->physbase = op->resource[0].start; | 494 | info->fix.smem_start = op->resource[0].start; |
496 | par->iospace = op->resource[0].flags & IORESOURCE_BITS; | 495 | par->iospace = op->resource[0].flags & IORESOURCE_BITS; |
497 | } else { | 496 | } else { |
498 | par->physbase = op->resource[1].start; | 497 | info->fix.smem_start = op->resource[1].start; |
499 | par->iospace = op->resource[0].flags & IORESOURCE_BITS; | 498 | par->iospace = op->resource[0].flags & IORESOURCE_BITS; |
500 | } | 499 | } |
501 | 500 | ||
@@ -507,7 +506,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id | |||
507 | sizeof(struct cg14_cursor), "cg14 cursor"); | 506 | sizeof(struct cg14_cursor), "cg14 cursor"); |
508 | 507 | ||
509 | info->screen_base = of_ioremap(&op->resource[1], 0, | 508 | info->screen_base = of_ioremap(&op->resource[1], 0, |
510 | par->fbsize, "cg14 ram"); | 509 | info->fix.smem_len, "cg14 ram"); |
511 | 510 | ||
512 | if (!par->regs || !par->clut || !par->cursor || !info->screen_base) | 511 | if (!par->regs || !par->clut || !par->cursor || !info->screen_base) |
513 | goto out_unmap_regs; | 512 | goto out_unmap_regs; |
@@ -557,7 +556,7 @@ static int __devinit cg14_probe(struct of_device *op, const struct of_device_id | |||
557 | 556 | ||
558 | printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", | 557 | printk(KERN_INFO "%s: cgfourteen at %lx:%lx, %dMB\n", |
559 | dp->full_name, | 558 | dp->full_name, |
560 | par->iospace, par->physbase, | 559 | par->iospace, info->fix.smem_start, |
561 | par->ramsize >> 20); | 560 | par->ramsize >> 20); |
562 | 561 | ||
563 | return 0; | 562 | return 0; |
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c index 99f87fb61d05..b2319fa7286f 100644 --- a/drivers/video/cg3.c +++ b/drivers/video/cg3.c | |||
@@ -118,9 +118,7 @@ struct cg3_par { | |||
118 | #define CG3_FLAG_BLANKED 0x00000001 | 118 | #define CG3_FLAG_BLANKED 0x00000001 |
119 | #define CG3_FLAG_RDI 0x00000002 | 119 | #define CG3_FLAG_RDI 0x00000002 |
120 | 120 | ||
121 | unsigned long physbase; | ||
122 | unsigned long which_io; | 121 | unsigned long which_io; |
123 | unsigned long fbsize; | ||
124 | }; | 122 | }; |
125 | 123 | ||
126 | /** | 124 | /** |
@@ -231,17 +229,15 @@ static int cg3_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
231 | struct cg3_par *par = (struct cg3_par *)info->par; | 229 | struct cg3_par *par = (struct cg3_par *)info->par; |
232 | 230 | ||
233 | return sbusfb_mmap_helper(cg3_mmap_map, | 231 | return sbusfb_mmap_helper(cg3_mmap_map, |
234 | par->physbase, par->fbsize, | 232 | info->fix.smem_start, info->fix.smem_len, |
235 | par->which_io, | 233 | par->which_io, |
236 | vma); | 234 | vma); |
237 | } | 235 | } |
238 | 236 | ||
239 | static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | 237 | static int cg3_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) |
240 | { | 238 | { |
241 | struct cg3_par *par = (struct cg3_par *) info->par; | ||
242 | |||
243 | return sbusfb_ioctl_helper(cmd, arg, info, | 239 | return sbusfb_ioctl_helper(cmd, arg, info, |
244 | FBTYPE_SUN3COLOR, 8, par->fbsize); | 240 | FBTYPE_SUN3COLOR, 8, info->fix.smem_len); |
245 | } | 241 | } |
246 | 242 | ||
247 | /* | 243 | /* |
@@ -368,7 +364,7 @@ static int __devinit cg3_probe(struct of_device *op, | |||
368 | 364 | ||
369 | spin_lock_init(&par->lock); | 365 | spin_lock_init(&par->lock); |
370 | 366 | ||
371 | par->physbase = op->resource[0].start; | 367 | info->fix.smem_start = op->resource[0].start; |
372 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; | 368 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
373 | 369 | ||
374 | sbusfb_fill_var(&info->var, dp, 8); | 370 | sbusfb_fill_var(&info->var, dp, 8); |
@@ -382,7 +378,7 @@ static int __devinit cg3_probe(struct of_device *op, | |||
382 | 378 | ||
383 | linebytes = of_getintprop_default(dp, "linebytes", | 379 | linebytes = of_getintprop_default(dp, "linebytes", |
384 | info->var.xres); | 380 | info->var.xres); |
385 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | 381 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
386 | 382 | ||
387 | par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, | 383 | par->regs = of_ioremap(&op->resource[0], CG3_REGS_OFFSET, |
388 | sizeof(struct cg3_regs), "cg3 regs"); | 384 | sizeof(struct cg3_regs), "cg3 regs"); |
@@ -392,7 +388,7 @@ static int __devinit cg3_probe(struct of_device *op, | |||
392 | info->flags = FBINFO_DEFAULT; | 388 | info->flags = FBINFO_DEFAULT; |
393 | info->fbops = &cg3_ops; | 389 | info->fbops = &cg3_ops; |
394 | info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, | 390 | info->screen_base = of_ioremap(&op->resource[0], CG3_RAM_OFFSET, |
395 | par->fbsize, "cg3 ram"); | 391 | info->fix.smem_len, "cg3 ram"); |
396 | if (!info->screen_base) | 392 | if (!info->screen_base) |
397 | goto out_unmap_regs; | 393 | goto out_unmap_regs; |
398 | 394 | ||
@@ -418,7 +414,7 @@ static int __devinit cg3_probe(struct of_device *op, | |||
418 | dev_set_drvdata(&op->dev, info); | 414 | dev_set_drvdata(&op->dev, info); |
419 | 415 | ||
420 | printk(KERN_INFO "%s: cg3 at %lx:%lx\n", | 416 | printk(KERN_INFO "%s: cg3 at %lx:%lx\n", |
421 | dp->full_name, par->which_io, par->physbase); | 417 | dp->full_name, par->which_io, info->fix.smem_start); |
422 | 418 | ||
423 | return 0; | 419 | return 0; |
424 | 420 | ||
@@ -426,7 +422,7 @@ out_dealloc_cmap: | |||
426 | fb_dealloc_cmap(&info->cmap); | 422 | fb_dealloc_cmap(&info->cmap); |
427 | 423 | ||
428 | out_unmap_screen: | 424 | out_unmap_screen: |
429 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); | 425 | of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); |
430 | 426 | ||
431 | out_unmap_regs: | 427 | out_unmap_regs: |
432 | of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); | 428 | of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); |
@@ -447,7 +443,7 @@ static int __devexit cg3_remove(struct of_device *op) | |||
447 | fb_dealloc_cmap(&info->cmap); | 443 | fb_dealloc_cmap(&info->cmap); |
448 | 444 | ||
449 | of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); | 445 | of_iounmap(&op->resource[0], par->regs, sizeof(struct cg3_regs)); |
450 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); | 446 | of_iounmap(&op->resource[0], info->screen_base, info->fix.smem_len); |
451 | 447 | ||
452 | framebuffer_release(info); | 448 | framebuffer_release(info); |
453 | 449 | ||
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c index 940ec04f0f1b..0d47c6030e3d 100644 --- a/drivers/video/cg6.c +++ b/drivers/video/cg6.c | |||
@@ -263,9 +263,7 @@ struct cg6_par { | |||
263 | u32 flags; | 263 | u32 flags; |
264 | #define CG6_FLAG_BLANKED 0x00000001 | 264 | #define CG6_FLAG_BLANKED 0x00000001 |
265 | 265 | ||
266 | unsigned long physbase; | ||
267 | unsigned long which_io; | 266 | unsigned long which_io; |
268 | unsigned long fbsize; | ||
269 | }; | 267 | }; |
270 | 268 | ||
271 | static int cg6_sync(struct fb_info *info) | 269 | static int cg6_sync(struct fb_info *info) |
@@ -596,16 +594,14 @@ static int cg6_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
596 | struct cg6_par *par = (struct cg6_par *)info->par; | 594 | struct cg6_par *par = (struct cg6_par *)info->par; |
597 | 595 | ||
598 | return sbusfb_mmap_helper(cg6_mmap_map, | 596 | return sbusfb_mmap_helper(cg6_mmap_map, |
599 | par->physbase, par->fbsize, | 597 | info->fix.smem_start, info->fix.smem_len, |
600 | par->which_io, vma); | 598 | par->which_io, vma); |
601 | } | 599 | } |
602 | 600 | ||
603 | static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | 601 | static int cg6_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) |
604 | { | 602 | { |
605 | struct cg6_par *par = (struct cg6_par *)info->par; | ||
606 | |||
607 | return sbusfb_ioctl_helper(cmd, arg, info, | 603 | return sbusfb_ioctl_helper(cmd, arg, info, |
608 | FBTYPE_SUNFAST_COLOR, 8, par->fbsize); | 604 | FBTYPE_SUNFAST_COLOR, 8, info->fix.smem_len); |
609 | } | 605 | } |
610 | 606 | ||
611 | /* | 607 | /* |
@@ -631,12 +627,12 @@ static void __devinit cg6_init_fix(struct fb_info *info, int linebytes) | |||
631 | break; | 627 | break; |
632 | }; | 628 | }; |
633 | if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { | 629 | if (((conf >> CG6_FHC_REV_SHIFT) & CG6_FHC_REV_MASK) >= 11) { |
634 | if (par->fbsize <= 0x100000) | 630 | if (info->fix.smem_len <= 0x100000) |
635 | cg6_card_name = "TGX"; | 631 | cg6_card_name = "TGX"; |
636 | else | 632 | else |
637 | cg6_card_name = "TGX+"; | 633 | cg6_card_name = "TGX+"; |
638 | } else { | 634 | } else { |
639 | if (par->fbsize <= 0x100000) | 635 | if (info->fix.smem_len <= 0x100000) |
640 | cg6_card_name = "GX"; | 636 | cg6_card_name = "GX"; |
641 | else | 637 | else |
642 | cg6_card_name = "GX+"; | 638 | cg6_card_name = "GX+"; |
@@ -738,7 +734,8 @@ static void cg6_unmap_regs(struct of_device *op, struct fb_info *info, | |||
738 | of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); | 734 | of_iounmap(&op->resource[0], par->fhc, sizeof(u32)); |
739 | 735 | ||
740 | if (info->screen_base) | 736 | if (info->screen_base) |
741 | of_iounmap(&op->resource[0], info->screen_base, par->fbsize); | 737 | of_iounmap(&op->resource[0], info->screen_base, |
738 | info->fix.smem_len); | ||
742 | } | 739 | } |
743 | 740 | ||
744 | static int __devinit cg6_probe(struct of_device *op, | 741 | static int __devinit cg6_probe(struct of_device *op, |
@@ -759,7 +756,7 @@ static int __devinit cg6_probe(struct of_device *op, | |||
759 | 756 | ||
760 | spin_lock_init(&par->lock); | 757 | spin_lock_init(&par->lock); |
761 | 758 | ||
762 | par->physbase = op->resource[0].start; | 759 | info->fix.smem_start = op->resource[0].start; |
763 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; | 760 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
764 | 761 | ||
765 | sbusfb_fill_var(&info->var, dp, 8); | 762 | sbusfb_fill_var(&info->var, dp, 8); |
@@ -769,11 +766,11 @@ static int __devinit cg6_probe(struct of_device *op, | |||
769 | 766 | ||
770 | linebytes = of_getintprop_default(dp, "linebytes", | 767 | linebytes = of_getintprop_default(dp, "linebytes", |
771 | info->var.xres); | 768 | info->var.xres); |
772 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | 769 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
773 | 770 | ||
774 | dblbuf = of_getintprop_default(dp, "dblbuf", 0); | 771 | dblbuf = of_getintprop_default(dp, "dblbuf", 0); |
775 | if (dblbuf) | 772 | if (dblbuf) |
776 | par->fbsize *= 4; | 773 | info->fix.smem_len *= 4; |
777 | 774 | ||
778 | par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, | 775 | par->fbc = of_ioremap(&op->resource[0], CG6_FBC_OFFSET, |
779 | 4096, "cgsix fbc"); | 776 | 4096, "cgsix fbc"); |
@@ -792,7 +789,7 @@ static int __devinit cg6_probe(struct of_device *op, | |||
792 | info->fbops = &cg6_ops; | 789 | info->fbops = &cg6_ops; |
793 | 790 | ||
794 | info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, | 791 | info->screen_base = of_ioremap(&op->resource[0], CG6_RAM_OFFSET, |
795 | par->fbsize, "cgsix ram"); | 792 | info->fix.smem_len, "cgsix ram"); |
796 | if (!par->fbc || !par->tec || !par->thc || | 793 | if (!par->fbc || !par->tec || !par->thc || |
797 | !par->bt || !par->fhc || !info->screen_base) | 794 | !par->bt || !par->fhc || !info->screen_base) |
798 | goto out_unmap_regs; | 795 | goto out_unmap_regs; |
@@ -817,7 +814,7 @@ static int __devinit cg6_probe(struct of_device *op, | |||
817 | 814 | ||
818 | printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", | 815 | printk(KERN_INFO "%s: CGsix [%s] at %lx:%lx\n", |
819 | dp->full_name, info->fix.id, | 816 | dp->full_name, info->fix.id, |
820 | par->which_io, par->physbase); | 817 | par->which_io, info->fix.smem_start); |
821 | 818 | ||
822 | return 0; | 819 | return 0; |
823 | 820 | ||
diff --git a/drivers/video/leo.c b/drivers/video/leo.c index 7c7e8c2da9d9..e145e2d16fe3 100644 --- a/drivers/video/leo.c +++ b/drivers/video/leo.c | |||
@@ -191,9 +191,7 @@ struct leo_par { | |||
191 | u32 flags; | 191 | u32 flags; |
192 | #define LEO_FLAG_BLANKED 0x00000001 | 192 | #define LEO_FLAG_BLANKED 0x00000001 |
193 | 193 | ||
194 | unsigned long physbase; | ||
195 | unsigned long which_io; | 194 | unsigned long which_io; |
196 | unsigned long fbsize; | ||
197 | }; | 195 | }; |
198 | 196 | ||
199 | static void leo_wait(struct leo_lx_krn __iomem *lx_krn) | 197 | static void leo_wait(struct leo_lx_krn __iomem *lx_krn) |
@@ -420,16 +418,14 @@ static int leo_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
420 | struct leo_par *par = (struct leo_par *)info->par; | 418 | struct leo_par *par = (struct leo_par *)info->par; |
421 | 419 | ||
422 | return sbusfb_mmap_helper(leo_mmap_map, | 420 | return sbusfb_mmap_helper(leo_mmap_map, |
423 | par->physbase, par->fbsize, | 421 | info->fix.smem_start, info->fix.smem_len, |
424 | par->which_io, vma); | 422 | par->which_io, vma); |
425 | } | 423 | } |
426 | 424 | ||
427 | static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) | 425 | static int leo_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) |
428 | { | 426 | { |
429 | struct leo_par *par = (struct leo_par *) info->par; | ||
430 | |||
431 | return sbusfb_ioctl_helper(cmd, arg, info, | 427 | return sbusfb_ioctl_helper(cmd, arg, info, |
432 | FBTYPE_SUNLEO, 32, par->fbsize); | 428 | FBTYPE_SUNLEO, 32, info->fix.smem_len); |
433 | } | 429 | } |
434 | 430 | ||
435 | /* | 431 | /* |
@@ -569,7 +565,7 @@ static int __devinit leo_probe(struct of_device *op, | |||
569 | 565 | ||
570 | spin_lock_init(&par->lock); | 566 | spin_lock_init(&par->lock); |
571 | 567 | ||
572 | par->physbase = op->resource[0].start; | 568 | info->fix.smem_start = op->resource[0].start; |
573 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; | 569 | par->which_io = op->resource[0].flags & IORESOURCE_BITS; |
574 | 570 | ||
575 | sbusfb_fill_var(&info->var, dp, 32); | 571 | sbusfb_fill_var(&info->var, dp, 32); |
@@ -577,7 +573,7 @@ static int __devinit leo_probe(struct of_device *op, | |||
577 | 573 | ||
578 | linebytes = of_getintprop_default(dp, "linebytes", | 574 | linebytes = of_getintprop_default(dp, "linebytes", |
579 | info->var.xres); | 575 | info->var.xres); |
580 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | 576 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
581 | 577 | ||
582 | par->lc_ss0_usr = | 578 | par->lc_ss0_usr = |
583 | of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, | 579 | of_ioremap(&op->resource[0], LEO_OFF_LC_SS0_USR, |
@@ -627,7 +623,7 @@ static int __devinit leo_probe(struct of_device *op, | |||
627 | 623 | ||
628 | printk(KERN_INFO "%s: leo at %lx:%lx\n", | 624 | printk(KERN_INFO "%s: leo at %lx:%lx\n", |
629 | dp->full_name, | 625 | dp->full_name, |
630 | par->which_io, par->physbase); | 626 | par->which_io, info->fix.smem_start); |
631 | 627 | ||
632 | return 0; | 628 | return 0; |
633 | 629 | ||
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c index 7000f2cd5854..7fa4ab01b0d3 100644 --- a/drivers/video/p9100.c +++ b/drivers/video/p9100.c | |||
@@ -134,9 +134,7 @@ struct p9100_par { | |||
134 | u32 flags; | 134 | u32 flags; |
135 | #define P9100_FLAG_BLANKED 0x00000001 | 135 | #define P9100_FLAG_BLANKED 0x00000001 |
136 | 136 | ||
137 | unsigned long physbase; | ||
138 | unsigned long which_io; | 137 | unsigned long which_io; |
139 | unsigned long fbsize; | ||
140 | }; | 138 | }; |
141 | 139 | ||
142 | /** | 140 | /** |
@@ -224,18 +222,16 @@ static int p9100_mmap(struct fb_info *info, struct vm_area_struct *vma) | |||
224 | struct p9100_par *par = (struct p9100_par *)info->par; | 222 | struct p9100_par *par = (struct p9100_par *)info->par; |
225 | 223 | ||
226 | return sbusfb_mmap_helper(p9100_mmap_map, | 224 | return sbusfb_mmap_helper(p9100_mmap_map, |
227 | par->physbase, par->fbsize, | 225 | info->fix.smem_start, info->fix.smem_len, |
228 | par->which_io, vma); | 226 | par->which_io, vma); |
229 | } | 227 | } |
230 | 228 | ||
231 | static int p9100_ioctl(struct fb_info *info, unsigned int cmd, | 229 | static int p9100_ioctl(struct fb_info *info, unsigned int cmd, |
232 | unsigned long arg) | 230 | unsigned long arg) |
233 | { | 231 | { |
234 | struct p9100_par *par = (struct p9100_par *) info->par; | ||
235 | |||
236 | /* Make it look like a cg3. */ | 232 | /* Make it look like a cg3. */ |
237 | return sbusfb_ioctl_helper(cmd, arg, info, | 233 | return sbusfb_ioctl_helper(cmd, arg, info, |
238 | FBTYPE_SUN3COLOR, 8, par->fbsize); | 234 | FBTYPE_SUN3COLOR, 8, info->fix.smem_len); |
239 | } | 235 | } |
240 | 236 | ||
241 | /* | 237 | /* |
@@ -271,7 +267,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id | |||
271 | spin_lock_init(&par->lock); | 267 | spin_lock_init(&par->lock); |
272 | 268 | ||
273 | /* This is the framebuffer and the only resource apps can mmap. */ | 269 | /* This is the framebuffer and the only resource apps can mmap. */ |
274 | par->physbase = op->resource[2].start; | 270 | info->fix.smem_start = op->resource[2].start; |
275 | par->which_io = op->resource[2].flags & IORESOURCE_BITS; | 271 | par->which_io = op->resource[2].flags & IORESOURCE_BITS; |
276 | 272 | ||
277 | sbusfb_fill_var(&info->var, dp, 8); | 273 | sbusfb_fill_var(&info->var, dp, 8); |
@@ -280,7 +276,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id | |||
280 | info->var.blue.length = 8; | 276 | info->var.blue.length = 8; |
281 | 277 | ||
282 | linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); | 278 | linebytes = of_getintprop_default(dp, "linebytes", info->var.xres); |
283 | par->fbsize = PAGE_ALIGN(linebytes * info->var.yres); | 279 | info->fix.smem_len = PAGE_ALIGN(linebytes * info->var.yres); |
284 | 280 | ||
285 | par->regs = of_ioremap(&op->resource[0], 0, | 281 | par->regs = of_ioremap(&op->resource[0], 0, |
286 | sizeof(struct p9100_regs), "p9100 regs"); | 282 | sizeof(struct p9100_regs), "p9100 regs"); |
@@ -290,7 +286,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id | |||
290 | info->flags = FBINFO_DEFAULT; | 286 | info->flags = FBINFO_DEFAULT; |
291 | info->fbops = &p9100_ops; | 287 | info->fbops = &p9100_ops; |
292 | info->screen_base = of_ioremap(&op->resource[2], 0, | 288 | info->screen_base = of_ioremap(&op->resource[2], 0, |
293 | par->fbsize, "p9100 ram"); | 289 | info->fix.smem_len, "p9100 ram"); |
294 | if (!info->screen_base) | 290 | if (!info->screen_base) |
295 | goto out_unmap_regs; | 291 | goto out_unmap_regs; |
296 | 292 | ||
@@ -311,7 +307,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id | |||
311 | 307 | ||
312 | printk(KERN_INFO "%s: p9100 at %lx:%lx\n", | 308 | printk(KERN_INFO "%s: p9100 at %lx:%lx\n", |
313 | dp->full_name, | 309 | dp->full_name, |
314 | par->which_io, par->physbase); | 310 | par->which_io, info->fix.smem_start); |
315 | 311 | ||
316 | return 0; | 312 | return 0; |
317 | 313 | ||
@@ -319,7 +315,7 @@ out_dealloc_cmap: | |||
319 | fb_dealloc_cmap(&info->cmap); | 315 | fb_dealloc_cmap(&info->cmap); |
320 | 316 | ||
321 | out_unmap_screen: | 317 | out_unmap_screen: |
322 | of_iounmap(&op->resource[2], info->screen_base, par->fbsize); | 318 | of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); |
323 | 319 | ||
324 | out_unmap_regs: | 320 | out_unmap_regs: |
325 | of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); | 321 | of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); |
@@ -340,7 +336,7 @@ static int __devexit p9100_remove(struct of_device *op) | |||
340 | fb_dealloc_cmap(&info->cmap); | 336 | fb_dealloc_cmap(&info->cmap); |
341 | 337 | ||
342 | of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); | 338 | of_iounmap(&op->resource[0], par->regs, sizeof(struct p9100_regs)); |
343 | of_iounmap(&op->resource[2], info->screen_base, par->fbsize); | 339 | of_iounmap(&op->resource[2], info->screen_base, info->fix.smem_len); |
344 | 340 | ||
345 | framebuffer_release(info); | 341 | framebuffer_release(info); |
346 | 342 | ||
diff --git a/drivers/video/ps3fb.c b/drivers/video/ps3fb.c index e00c1dff55de..c0af638fe702 100644 --- a/drivers/video/ps3fb.c +++ b/drivers/video/ps3fb.c | |||
@@ -32,25 +32,16 @@ | |||
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | 33 | ||
34 | #include <asm/abs_addr.h> | 34 | #include <asm/abs_addr.h> |
35 | #include <asm/iommu.h> | ||
35 | #include <asm/lv1call.h> | 36 | #include <asm/lv1call.h> |
36 | #include <asm/ps3av.h> | 37 | #include <asm/ps3av.h> |
37 | #include <asm/ps3fb.h> | 38 | #include <asm/ps3fb.h> |
38 | #include <asm/ps3.h> | 39 | #include <asm/ps3.h> |
40 | #include <asm/ps3gpu.h> | ||
39 | 41 | ||
40 | 42 | ||
41 | #define DEVICE_NAME "ps3fb" | 43 | #define DEVICE_NAME "ps3fb" |
42 | 44 | ||
43 | #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC 0x101 | ||
44 | #define L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP 0x102 | ||
45 | #define L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP 0x600 | ||
46 | #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601 | ||
47 | #define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT_SYNC 0x602 | ||
48 | |||
49 | #define L1GPU_FB_BLIT_WAIT_FOR_COMPLETION (1ULL << 32) | ||
50 | |||
51 | #define L1GPU_DISPLAY_SYNC_HSYNC 1 | ||
52 | #define L1GPU_DISPLAY_SYNC_VSYNC 2 | ||
53 | |||
54 | #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) | 45 | #define GPU_CMD_BUF_SIZE (2 * 1024 * 1024) |
55 | #define GPU_FB_START (64 * 1024) | 46 | #define GPU_FB_START (64 * 1024) |
56 | #define GPU_IOIF (0x0d000000UL) | 47 | #define GPU_IOIF (0x0d000000UL) |
@@ -462,33 +453,27 @@ static void ps3fb_sync_image(struct device *dev, u64 frame_offset, | |||
462 | src_offset += GPU_FB_START; | 453 | src_offset += GPU_FB_START; |
463 | 454 | ||
464 | mutex_lock(&ps3_gpu_mutex); | 455 | mutex_lock(&ps3_gpu_mutex); |
465 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 456 | status = lv1_gpu_fb_blit(ps3fb.context_handle, dst_offset, |
466 | L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, | 457 | GPU_IOIF + src_offset, |
467 | dst_offset, GPU_IOIF + src_offset, | 458 | L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | |
468 | L1GPU_FB_BLIT_WAIT_FOR_COMPLETION | | 459 | (width << 16) | height, |
469 | (width << 16) | height, | 460 | line_length); |
470 | line_length); | ||
471 | mutex_unlock(&ps3_gpu_mutex); | 461 | mutex_unlock(&ps3_gpu_mutex); |
472 | 462 | ||
473 | if (status) | 463 | if (status) |
474 | dev_err(dev, | 464 | dev_err(dev, "%s: lv1_gpu_fb_blit failed: %d\n", __func__, |
475 | "%s: lv1_gpu_context_attribute FB_BLIT failed: %d\n", | 465 | status); |
476 | __func__, status); | ||
477 | #ifdef HEAD_A | 466 | #ifdef HEAD_A |
478 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 467 | status = lv1_gpu_display_flip(ps3fb.context_handle, 0, frame_offset); |
479 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, | ||
480 | 0, frame_offset, 0, 0); | ||
481 | if (status) | 468 | if (status) |
482 | dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", | 469 | dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, |
483 | __func__, status); | 470 | status); |
484 | #endif | 471 | #endif |
485 | #ifdef HEAD_B | 472 | #ifdef HEAD_B |
486 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | 473 | status = lv1_gpu_display_flip(ps3fb.context_handle, 1, frame_offset); |
487 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_FLIP, | ||
488 | 1, frame_offset, 0, 0); | ||
489 | if (status) | 474 | if (status) |
490 | dev_err(dev, "%s: lv1_gpu_context_attribute FLIP failed: %d\n", | 475 | dev_err(dev, "%s: lv1_gpu_display_flip failed: %d\n", __func__, |
491 | __func__, status); | 476 | status); |
492 | #endif | 477 | #endif |
493 | } | 478 | } |
494 | 479 | ||
@@ -956,73 +941,6 @@ static irqreturn_t ps3fb_vsync_interrupt(int irq, void *ptr) | |||
956 | } | 941 | } |
957 | 942 | ||
958 | 943 | ||
959 | static int ps3fb_vsync_settings(struct gpu_driver_info *dinfo, | ||
960 | struct device *dev) | ||
961 | { | ||
962 | int error; | ||
963 | |||
964 | dev_dbg(dev, "version_driver:%x\n", dinfo->version_driver); | ||
965 | dev_dbg(dev, "irq outlet:%x\n", dinfo->irq.irq_outlet); | ||
966 | dev_dbg(dev, | ||
967 | "version_gpu: %x memory_size: %x ch: %x core_freq: %d " | ||
968 | "mem_freq:%d\n", | ||
969 | dinfo->version_gpu, dinfo->memory_size, dinfo->hardware_channel, | ||
970 | dinfo->nvcore_frequency/1000000, dinfo->memory_frequency/1000000); | ||
971 | |||
972 | if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { | ||
973 | dev_err(dev, "%s: version_driver err:%x\n", __func__, | ||
974 | dinfo->version_driver); | ||
975 | return -EINVAL; | ||
976 | } | ||
977 | |||
978 | error = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, | ||
979 | &ps3fb.irq_no); | ||
980 | if (error) { | ||
981 | dev_err(dev, "%s: ps3_alloc_irq failed %d\n", __func__, error); | ||
982 | return error; | ||
983 | } | ||
984 | |||
985 | error = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, IRQF_DISABLED, | ||
986 | DEVICE_NAME, dev); | ||
987 | if (error) { | ||
988 | dev_err(dev, "%s: request_irq failed %d\n", __func__, error); | ||
989 | ps3_irq_plug_destroy(ps3fb.irq_no); | ||
990 | return error; | ||
991 | } | ||
992 | |||
993 | dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | | ||
994 | (1 << GPU_INTR_STATUS_FLIP_1); | ||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | static int ps3fb_xdr_settings(u64 xdr_lpar, struct device *dev) | ||
999 | { | ||
1000 | int status; | ||
1001 | |||
1002 | status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, | ||
1003 | xdr_lpar, ps3fb_videomemory.size, 0); | ||
1004 | if (status) { | ||
1005 | dev_err(dev, "%s: lv1_gpu_context_iomap failed: %d\n", | ||
1006 | __func__, status); | ||
1007 | return -ENXIO; | ||
1008 | } | ||
1009 | dev_dbg(dev, "video:%p ioif:%lx lpar:%llx size:%lx\n", | ||
1010 | ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, | ||
1011 | ps3fb_videomemory.size); | ||
1012 | |||
1013 | status = lv1_gpu_context_attribute(ps3fb.context_handle, | ||
1014 | L1GPU_CONTEXT_ATTRIBUTE_FB_SETUP, | ||
1015 | xdr_lpar, GPU_CMD_BUF_SIZE, | ||
1016 | GPU_IOIF, 0); | ||
1017 | if (status) { | ||
1018 | dev_err(dev, | ||
1019 | "%s: lv1_gpu_context_attribute FB_SETUP failed: %d\n", | ||
1020 | __func__, status); | ||
1021 | return -ENXIO; | ||
1022 | } | ||
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | static struct fb_ops ps3fb_ops = { | 944 | static struct fb_ops ps3fb_ops = { |
1027 | .fb_open = ps3fb_open, | 945 | .fb_open = ps3fb_open, |
1028 | .fb_release = ps3fb_release, | 946 | .fb_release = ps3fb_release, |
@@ -1048,49 +966,18 @@ static struct fb_fix_screeninfo ps3fb_fix __initdata = { | |||
1048 | .accel = FB_ACCEL_NONE, | 966 | .accel = FB_ACCEL_NONE, |
1049 | }; | 967 | }; |
1050 | 968 | ||
1051 | static int ps3fb_set_sync(struct device *dev) | ||
1052 | { | ||
1053 | int status; | ||
1054 | |||
1055 | #ifdef HEAD_A | ||
1056 | status = lv1_gpu_context_attribute(0x0, | ||
1057 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1058 | 0, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1059 | if (status) { | ||
1060 | dev_err(dev, | ||
1061 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " | ||
1062 | "%d\n", | ||
1063 | __func__, status); | ||
1064 | return -1; | ||
1065 | } | ||
1066 | #endif | ||
1067 | #ifdef HEAD_B | ||
1068 | status = lv1_gpu_context_attribute(0x0, | ||
1069 | L1GPU_CONTEXT_ATTRIBUTE_DISPLAY_SYNC, | ||
1070 | 1, L1GPU_DISPLAY_SYNC_VSYNC, 0, 0); | ||
1071 | |||
1072 | if (status) { | ||
1073 | dev_err(dev, | ||
1074 | "%s: lv1_gpu_context_attribute DISPLAY_SYNC failed: " | ||
1075 | "%d\n", | ||
1076 | __func__, status); | ||
1077 | return -1; | ||
1078 | } | ||
1079 | #endif | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | 969 | static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) |
1084 | { | 970 | { |
1085 | struct fb_info *info; | 971 | struct fb_info *info; |
1086 | struct ps3fb_par *par; | 972 | struct ps3fb_par *par; |
1087 | int retval = -ENOMEM; | 973 | int retval; |
1088 | u64 ddr_lpar = 0; | 974 | u64 ddr_lpar = 0; |
1089 | u64 lpar_dma_control = 0; | 975 | u64 lpar_dma_control = 0; |
1090 | u64 lpar_driver_info = 0; | 976 | u64 lpar_driver_info = 0; |
1091 | u64 lpar_reports = 0; | 977 | u64 lpar_reports = 0; |
1092 | u64 lpar_reports_size = 0; | 978 | u64 lpar_reports_size = 0; |
1093 | u64 xdr_lpar; | 979 | u64 xdr_lpar; |
980 | struct gpu_driver_info *dinfo; | ||
1094 | void *fb_start; | 981 | void *fb_start; |
1095 | int status; | 982 | int status; |
1096 | struct task_struct *task; | 983 | struct task_struct *task; |
@@ -1101,8 +988,8 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1101 | return -ENOMEM; | 988 | return -ENOMEM; |
1102 | } | 989 | } |
1103 | 990 | ||
1104 | status = ps3_open_hv_device(dev); | 991 | retval = ps3_open_hv_device(dev); |
1105 | if (status) { | 992 | if (retval) { |
1106 | dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", | 993 | dev_err(&dev->core, "%s: ps3_open_hv_device failed\n", |
1107 | __func__); | 994 | __func__); |
1108 | goto err; | 995 | goto err; |
@@ -1116,7 +1003,24 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1116 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ | 1003 | atomic_set(&ps3fb.ext_flip, 0); /* for flip with vsync */ |
1117 | init_waitqueue_head(&ps3fb.wait_vsync); | 1004 | init_waitqueue_head(&ps3fb.wait_vsync); |
1118 | 1005 | ||
1119 | ps3fb_set_sync(&dev->core); | 1006 | #ifdef HEAD_A |
1007 | status = lv1_gpu_display_sync(0x0, 0, L1GPU_DISPLAY_SYNC_VSYNC); | ||
1008 | if (status) { | ||
1009 | dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", | ||
1010 | __func__, status); | ||
1011 | retval = -ENODEV; | ||
1012 | goto err_close_device; | ||
1013 | } | ||
1014 | #endif | ||
1015 | #ifdef HEAD_B | ||
1016 | status = lv1_gpu_display_sync(0x0, 1, L1GPU_DISPLAY_SYNC_VSYNC); | ||
1017 | if (status) { | ||
1018 | dev_err(&dev->core, "%s: lv1_gpu_display_sync failed: %d\n", | ||
1019 | __func__, status); | ||
1020 | retval = -ENODEV; | ||
1021 | goto err_close_device; | ||
1022 | } | ||
1023 | #endif | ||
1120 | 1024 | ||
1121 | max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; | 1025 | max_ps3fb_size = _ALIGN_UP(GPU_IOIF, 256*1024*1024) - GPU_IOIF; |
1122 | if (ps3fb_videomemory.size > max_ps3fb_size) { | 1026 | if (ps3fb_videomemory.size > max_ps3fb_size) { |
@@ -1131,7 +1035,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1131 | if (status) { | 1035 | if (status) { |
1132 | dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", | 1036 | dev_err(&dev->core, "%s: lv1_gpu_memory_allocate failed: %d\n", |
1133 | __func__, status); | 1037 | __func__, status); |
1134 | goto err; | 1038 | goto err_close_device; |
1135 | } | 1039 | } |
1136 | dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); | 1040 | dev_dbg(&dev->core, "ddr:lpar:0x%llx\n", ddr_lpar); |
1137 | 1041 | ||
@@ -1141,33 +1045,85 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1141 | &lpar_reports, &lpar_reports_size); | 1045 | &lpar_reports, &lpar_reports_size); |
1142 | if (status) { | 1046 | if (status) { |
1143 | dev_err(&dev->core, | 1047 | dev_err(&dev->core, |
1144 | "%s: lv1_gpu_context_attribute failed: %d\n", __func__, | 1048 | "%s: lv1_gpu_context_allocate failed: %d\n", __func__, |
1145 | status); | 1049 | status); |
1146 | goto err_gpu_memory_free; | 1050 | goto err_gpu_memory_free; |
1147 | } | 1051 | } |
1148 | 1052 | ||
1149 | /* vsync interrupt */ | 1053 | /* vsync interrupt */ |
1150 | ps3fb.dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); | 1054 | dinfo = (void __force *)ioremap(lpar_driver_info, 128 * 1024); |
1151 | if (!ps3fb.dinfo) { | 1055 | if (!dinfo) { |
1152 | dev_err(&dev->core, "%s: ioremap failed\n", __func__); | 1056 | dev_err(&dev->core, "%s: ioremap failed\n", __func__); |
1153 | goto err_gpu_context_free; | 1057 | goto err_gpu_context_free; |
1154 | } | 1058 | } |
1155 | 1059 | ||
1156 | retval = ps3fb_vsync_settings(ps3fb.dinfo, &dev->core); | 1060 | ps3fb.dinfo = dinfo; |
1157 | if (retval) | 1061 | dev_dbg(&dev->core, "version_driver:%x\n", dinfo->version_driver); |
1062 | dev_dbg(&dev->core, "irq outlet:%x\n", dinfo->irq.irq_outlet); | ||
1063 | dev_dbg(&dev->core, "version_gpu: %x memory_size: %x ch: %x " | ||
1064 | "core_freq: %d mem_freq:%d\n", dinfo->version_gpu, | ||
1065 | dinfo->memory_size, dinfo->hardware_channel, | ||
1066 | dinfo->nvcore_frequency/1000000, | ||
1067 | dinfo->memory_frequency/1000000); | ||
1068 | |||
1069 | if (dinfo->version_driver != GPU_DRIVER_INFO_VERSION) { | ||
1070 | dev_err(&dev->core, "%s: version_driver err:%x\n", __func__, | ||
1071 | dinfo->version_driver); | ||
1072 | retval = -EINVAL; | ||
1073 | goto err_iounmap_dinfo; | ||
1074 | } | ||
1075 | |||
1076 | retval = ps3_irq_plug_setup(PS3_BINDING_CPU_ANY, dinfo->irq.irq_outlet, | ||
1077 | &ps3fb.irq_no); | ||
1078 | if (retval) { | ||
1079 | dev_err(&dev->core, "%s: ps3_alloc_irq failed %d\n", __func__, | ||
1080 | retval); | ||
1158 | goto err_iounmap_dinfo; | 1081 | goto err_iounmap_dinfo; |
1082 | } | ||
1083 | |||
1084 | retval = request_irq(ps3fb.irq_no, ps3fb_vsync_interrupt, | ||
1085 | IRQF_DISABLED, DEVICE_NAME, &dev->core); | ||
1086 | if (retval) { | ||
1087 | dev_err(&dev->core, "%s: request_irq failed %d\n", __func__, | ||
1088 | retval); | ||
1089 | goto err_destroy_plug; | ||
1090 | } | ||
1091 | |||
1092 | dinfo->irq.mask = (1 << GPU_INTR_STATUS_VSYNC_1) | | ||
1093 | (1 << GPU_INTR_STATUS_FLIP_1); | ||
1159 | 1094 | ||
1160 | /* Clear memory to prevent kernel info leakage into userspace */ | 1095 | /* Clear memory to prevent kernel info leakage into userspace */ |
1161 | memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); | 1096 | memset(ps3fb_videomemory.address, 0, ps3fb_videomemory.size); |
1162 | 1097 | ||
1163 | xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); | 1098 | xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); |
1164 | retval = ps3fb_xdr_settings(xdr_lpar, &dev->core); | 1099 | |
1165 | if (retval) | 1100 | status = lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, |
1101 | xdr_lpar, ps3fb_videomemory.size, | ||
1102 | CBE_IOPTE_PP_W | CBE_IOPTE_PP_R | | ||
1103 | CBE_IOPTE_M); | ||
1104 | if (status) { | ||
1105 | dev_err(&dev->core, "%s: lv1_gpu_context_iomap failed: %d\n", | ||
1106 | __func__, status); | ||
1107 | retval = -ENXIO; | ||
1166 | goto err_free_irq; | 1108 | goto err_free_irq; |
1109 | } | ||
1110 | |||
1111 | dev_dbg(&dev->core, "video:%p ioif:%lx lpar:%llx size:%lx\n", | ||
1112 | ps3fb_videomemory.address, GPU_IOIF, xdr_lpar, | ||
1113 | ps3fb_videomemory.size); | ||
1114 | |||
1115 | status = lv1_gpu_fb_setup(ps3fb.context_handle, xdr_lpar, | ||
1116 | GPU_CMD_BUF_SIZE, GPU_IOIF); | ||
1117 | if (status) { | ||
1118 | dev_err(&dev->core, "%s: lv1_gpu_fb_setup failed: %d\n", | ||
1119 | __func__, status); | ||
1120 | retval = -ENXIO; | ||
1121 | goto err_context_unmap; | ||
1122 | } | ||
1167 | 1123 | ||
1168 | info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); | 1124 | info = framebuffer_alloc(sizeof(struct ps3fb_par), &dev->core); |
1169 | if (!info) | 1125 | if (!info) |
1170 | goto err_free_irq; | 1126 | goto err_context_fb_close; |
1171 | 1127 | ||
1172 | par = info->par; | 1128 | par = info->par; |
1173 | par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ | 1129 | par->mode_id = ~ps3fb_mode; /* != ps3fb_mode, to trigger change */ |
@@ -1210,7 +1166,7 @@ static int __devinit ps3fb_probe(struct ps3_system_bus_device *dev) | |||
1210 | if (retval < 0) | 1166 | if (retval < 0) |
1211 | goto err_fb_dealloc; | 1167 | goto err_fb_dealloc; |
1212 | 1168 | ||
1213 | dev->core.driver_data = info; | 1169 | ps3_system_bus_set_drvdata(dev, info); |
1214 | 1170 | ||
1215 | dev_info(info->device, "%s %s, using %u KiB of video memory\n", | 1171 | dev_info(info->device, "%s %s, using %u KiB of video memory\n", |
1216 | dev_driver_string(info->dev), dev_name(info->dev), | 1172 | dev_driver_string(info->dev), dev_name(info->dev), |
@@ -1232,8 +1188,14 @@ err_fb_dealloc: | |||
1232 | fb_dealloc_cmap(&info->cmap); | 1188 | fb_dealloc_cmap(&info->cmap); |
1233 | err_framebuffer_release: | 1189 | err_framebuffer_release: |
1234 | framebuffer_release(info); | 1190 | framebuffer_release(info); |
1191 | err_context_fb_close: | ||
1192 | lv1_gpu_fb_close(ps3fb.context_handle); | ||
1193 | err_context_unmap: | ||
1194 | lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, | ||
1195 | ps3fb_videomemory.size, CBE_IOPTE_M); | ||
1235 | err_free_irq: | 1196 | err_free_irq: |
1236 | free_irq(ps3fb.irq_no, &dev->core); | 1197 | free_irq(ps3fb.irq_no, &dev->core); |
1198 | err_destroy_plug: | ||
1237 | ps3_irq_plug_destroy(ps3fb.irq_no); | 1199 | ps3_irq_plug_destroy(ps3fb.irq_no); |
1238 | err_iounmap_dinfo: | 1200 | err_iounmap_dinfo: |
1239 | iounmap((u8 __force __iomem *)ps3fb.dinfo); | 1201 | iounmap((u8 __force __iomem *)ps3fb.dinfo); |
@@ -1241,14 +1203,16 @@ err_gpu_context_free: | |||
1241 | lv1_gpu_context_free(ps3fb.context_handle); | 1203 | lv1_gpu_context_free(ps3fb.context_handle); |
1242 | err_gpu_memory_free: | 1204 | err_gpu_memory_free: |
1243 | lv1_gpu_memory_free(ps3fb.memory_handle); | 1205 | lv1_gpu_memory_free(ps3fb.memory_handle); |
1206 | err_close_device: | ||
1207 | ps3_close_hv_device(dev); | ||
1244 | err: | 1208 | err: |
1245 | return retval; | 1209 | return retval; |
1246 | } | 1210 | } |
1247 | 1211 | ||
1248 | static int ps3fb_shutdown(struct ps3_system_bus_device *dev) | 1212 | static int ps3fb_shutdown(struct ps3_system_bus_device *dev) |
1249 | { | 1213 | { |
1250 | int status; | 1214 | struct fb_info *info = ps3_system_bus_get_drvdata(dev); |
1251 | struct fb_info *info = dev->core.driver_data; | 1215 | u64 xdr_lpar = ps3_mm_phys_to_lpar(__pa(ps3fb_videomemory.address)); |
1252 | 1216 | ||
1253 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); | 1217 | dev_dbg(&dev->core, " -> %s:%d\n", __func__, __LINE__); |
1254 | 1218 | ||
@@ -1268,20 +1232,14 @@ static int ps3fb_shutdown(struct ps3_system_bus_device *dev) | |||
1268 | unregister_framebuffer(info); | 1232 | unregister_framebuffer(info); |
1269 | fb_dealloc_cmap(&info->cmap); | 1233 | fb_dealloc_cmap(&info->cmap); |
1270 | framebuffer_release(info); | 1234 | framebuffer_release(info); |
1271 | info = dev->core.driver_data = NULL; | 1235 | ps3_system_bus_set_drvdata(dev, NULL); |
1272 | } | 1236 | } |
1273 | iounmap((u8 __force __iomem *)ps3fb.dinfo); | 1237 | iounmap((u8 __force __iomem *)ps3fb.dinfo); |
1274 | 1238 | lv1_gpu_fb_close(ps3fb.context_handle); | |
1275 | status = lv1_gpu_context_free(ps3fb.context_handle); | 1239 | lv1_gpu_context_iomap(ps3fb.context_handle, GPU_IOIF, xdr_lpar, |
1276 | if (status) | 1240 | ps3fb_videomemory.size, CBE_IOPTE_M); |
1277 | dev_dbg(&dev->core, "lv1_gpu_context_free failed: %d\n", | 1241 | lv1_gpu_context_free(ps3fb.context_handle); |
1278 | status); | 1242 | lv1_gpu_memory_free(ps3fb.memory_handle); |
1279 | |||
1280 | status = lv1_gpu_memory_free(ps3fb.memory_handle); | ||
1281 | if (status) | ||
1282 | dev_dbg(&dev->core, "lv1_gpu_memory_free failed: %d\n", | ||
1283 | status); | ||
1284 | |||
1285 | ps3_close_hv_device(dev); | 1243 | ps3_close_hv_device(dev); |
1286 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); | 1244 | dev_dbg(&dev->core, " <- %s:%d\n", __func__, __LINE__); |
1287 | 1245 | ||
diff --git a/drivers/video/tdfxfb.c b/drivers/video/tdfxfb.c index 89f231dc443f..ff43c8885028 100644 --- a/drivers/video/tdfxfb.c +++ b/drivers/video/tdfxfb.c | |||
@@ -1315,7 +1315,6 @@ static int __devinit tdfxfb_setup_i2c_bus(struct tdfxfb_i2c_chan *chan, | |||
1315 | 1315 | ||
1316 | strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); | 1316 | strlcpy(chan->adapter.name, name, sizeof(chan->adapter.name)); |
1317 | chan->adapter.owner = THIS_MODULE; | 1317 | chan->adapter.owner = THIS_MODULE; |
1318 | chan->adapter.class = I2C_CLASS_TV_ANALOG; | ||
1319 | chan->adapter.algo_data = &chan->algo; | 1318 | chan->adapter.algo_data = &chan->algo; |
1320 | chan->adapter.dev.parent = dev; | 1319 | chan->adapter.dev.parent = dev; |
1321 | chan->algo.setsda = tdfxfb_i2c_setsda; | 1320 | chan->algo.setsda = tdfxfb_i2c_setsda; |