aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStuart Hayes <stuart_hayes@dell.com>2010-02-10 14:12:13 -0500
committerMatthew Garrett <mjg@redhat.com>2010-02-25 11:50:49 -0500
commit116ee77b2858d9c89c0327f3a47c8ba864bf4a96 (patch)
tree7919e33f61115510ba7330c029e2143a9256c816
parente5fefd0c8c4e6bd11742625230d1c5026e2afb35 (diff)
dell-laptop: Use buffer with 32-bit physical address
Calls to communicate with system firmware via a SMI (using dcdbas) need to use a buffer that has a physical address of 4GB or less. Currently the dell-laptop driver does not guarantee this, and when the buffer address is higher than 4GB, the address is truncated to 32 bits and the SMI handler writes to the wrong memory address. Signed-off-by: Stuart Hayes <stuart_hayes@dell.com> Acked-by: Matthew Garrett <mjg@redhat.com>
-rw-r--r--drivers/platform/x86/dell-laptop.c122
1 files changed, 83 insertions, 39 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index d8b1b39aa9db..1a0bfd43f8f0 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -22,6 +22,7 @@
22#include <linux/rfkill.h> 22#include <linux/rfkill.h>
23#include <linux/power_supply.h> 23#include <linux/power_supply.h>
24#include <linux/acpi.h> 24#include <linux/acpi.h>
25#include <linux/mm.h>
25#include <linux/i8042.h> 26#include <linux/i8042.h>
26#include "../../firmware/dcdbas.h" 27#include "../../firmware/dcdbas.h"
27 28
@@ -123,6 +124,21 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = {
123 {} 124 {}
124}; 125};
125 126
127static struct calling_interface_buffer *buffer;
128struct page *bufferpage;
129DEFINE_MUTEX(buffer_mutex);
130
131static void get_buffer(void)
132{
133 mutex_lock(&buffer_mutex);
134 memset(buffer, 0, sizeof(struct calling_interface_buffer));
135}
136
137static void release_buffer(void)
138{
139 mutex_unlock(&buffer_mutex);
140}
141
126static void __init parse_da_table(const struct dmi_header *dm) 142static void __init parse_da_table(const struct dmi_header *dm)
127{ 143{
128 /* Final token is a terminator, so we don't want to copy it */ 144 /* Final token is a terminator, so we don't want to copy it */
@@ -225,30 +241,35 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
225 241
226static int dell_rfkill_set(void *data, bool blocked) 242static int dell_rfkill_set(void *data, bool blocked)
227{ 243{
228 struct calling_interface_buffer buffer;
229 int disable = blocked ? 1 : 0; 244 int disable = blocked ? 1 : 0;
230 unsigned long radio = (unsigned long)data; 245 unsigned long radio = (unsigned long)data;
246 int ret = 0;
231 247
232 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 248 get_buffer();
233 dell_send_request(&buffer, 17, 11); 249 dell_send_request(buffer, 17, 11);
234 if (!(buffer.output[1] & BIT(16)))
235 return -EINVAL;
236 250
237 buffer.input[0] = (1 | (radio<<8) | (disable << 16)); 251 if (!(buffer->output[1] & BIT(16))) {
238 dell_send_request(&buffer, 17, 11); 252 ret = -EINVAL;
253 goto out;
254 }
239 255
240 return 0; 256 buffer->input[0] = (1 | (radio<<8) | (disable << 16));
257 dell_send_request(buffer, 17, 11);
258
259out:
260 release_buffer();
261 return ret;
241} 262}
242 263
243static void dell_rfkill_query(struct rfkill *rfkill, void *data) 264static void dell_rfkill_query(struct rfkill *rfkill, void *data)
244{ 265{
245 struct calling_interface_buffer buffer;
246 int status; 266 int status;
247 int bit = (unsigned long)data + 16; 267 int bit = (unsigned long)data + 16;
248 268
249 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 269 get_buffer();
250 dell_send_request(&buffer, 17, 11); 270 dell_send_request(buffer, 17, 11);
251 status = buffer.output[1]; 271 status = buffer->output[1];
272 release_buffer();
252 273
253 rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); 274 rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
254 rfkill_set_hw_state(rfkill, !(status & BIT(16))); 275 rfkill_set_hw_state(rfkill, !(status & BIT(16)));
@@ -273,7 +294,6 @@ static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
273 294
274static int __init dell_setup_rfkill(void) 295static int __init dell_setup_rfkill(void)
275{ 296{
276 struct calling_interface_buffer buffer;
277 int status; 297 int status;
278 int ret; 298 int ret;
279 299
@@ -283,9 +303,10 @@ static int __init dell_setup_rfkill(void)
283 return 0; 303 return 0;
284 } 304 }
285 305
286 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 306 get_buffer();
287 dell_send_request(&buffer, 17, 11); 307 dell_send_request(buffer, 17, 11);
288 status = buffer.output[1]; 308 status = buffer->output[1];
309 release_buffer();
289 310
290 if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { 311 if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
291 wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, 312 wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
@@ -361,39 +382,49 @@ static void dell_cleanup_rfkill(void)
361 382
362static int dell_send_intensity(struct backlight_device *bd) 383static int dell_send_intensity(struct backlight_device *bd)
363{ 384{
364 struct calling_interface_buffer buffer; 385 int ret = 0;
365 386
366 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 387 get_buffer();
367 buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); 388 buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
368 buffer.input[1] = bd->props.brightness; 389 buffer->input[1] = bd->props.brightness;
369 390
370 if (buffer.input[0] == -1) 391 if (buffer->input[0] == -1) {
371 return -ENODEV; 392 ret = -ENODEV;
393 goto out;
394 }
372 395
373 if (power_supply_is_system_supplied() > 0) 396 if (power_supply_is_system_supplied() > 0)
374 dell_send_request(&buffer, 1, 2); 397 dell_send_request(buffer, 1, 2);
375 else 398 else
376 dell_send_request(&buffer, 1, 1); 399 dell_send_request(buffer, 1, 1);
377 400
401out:
402 release_buffer();
378 return 0; 403 return 0;
379} 404}
380 405
381static int dell_get_intensity(struct backlight_device *bd) 406static int dell_get_intensity(struct backlight_device *bd)
382{ 407{
383 struct calling_interface_buffer buffer; 408 int ret = 0;
384 409
385 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 410 get_buffer();
386 buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); 411 buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
387 412
388 if (buffer.input[0] == -1) 413 if (buffer->input[0] == -1) {
389 return -ENODEV; 414 ret = -ENODEV;
415 goto out;
416 }
390 417
391 if (power_supply_is_system_supplied() > 0) 418 if (power_supply_is_system_supplied() > 0)
392 dell_send_request(&buffer, 0, 2); 419 dell_send_request(buffer, 0, 2);
393 else 420 else
394 dell_send_request(&buffer, 0, 1); 421 dell_send_request(buffer, 0, 1);
395 422
396 return buffer.output[1]; 423out:
424 release_buffer();
425 if (ret)
426 return ret;
427 return buffer->output[1];
397} 428}
398 429
399static struct backlight_ops dell_ops = { 430static struct backlight_ops dell_ops = {
@@ -427,7 +458,6 @@ bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
427 458
428static int __init dell_init(void) 459static int __init dell_init(void)
429{ 460{
430 struct calling_interface_buffer buffer;
431 int max_intensity = 0; 461 int max_intensity = 0;
432 int ret; 462 int ret;
433 463
@@ -453,6 +483,17 @@ static int __init dell_init(void)
453 if (ret) 483 if (ret)
454 goto fail_platform_device2; 484 goto fail_platform_device2;
455 485
486 /*
487 * Allocate buffer below 4GB for SMI data--only 32-bit physical addr
488 * is passed to SMI handler.
489 */
490 bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32);
491
492 if (!bufferpage)
493 goto fail_buffer;
494 buffer = page_address(bufferpage);
495 mutex_init(&buffer_mutex);
496
456 ret = dell_setup_rfkill(); 497 ret = dell_setup_rfkill();
457 498
458 if (ret) { 499 if (ret) {
@@ -475,13 +516,13 @@ static int __init dell_init(void)
475 return 0; 516 return 0;
476#endif 517#endif
477 518
478 memset(&buffer, 0, sizeof(struct calling_interface_buffer)); 519 get_buffer();
479 buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); 520 buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
480 521 if (buffer->input[0] != -1) {
481 if (buffer.input[0] != -1) { 522 dell_send_request(buffer, 0, 2);
482 dell_send_request(&buffer, 0, 2); 523 max_intensity = buffer->output[3];
483 max_intensity = buffer.output[3];
484 } 524 }
525 release_buffer();
485 526
486 if (max_intensity) { 527 if (max_intensity) {
487 dell_backlight_device = backlight_device_register( 528 dell_backlight_device = backlight_device_register(
@@ -508,6 +549,8 @@ fail_backlight:
508fail_filter: 549fail_filter:
509 dell_cleanup_rfkill(); 550 dell_cleanup_rfkill();
510fail_rfkill: 551fail_rfkill:
552 free_page((unsigned long)bufferpage);
553fail_buffer:
511 platform_device_del(platform_device); 554 platform_device_del(platform_device);
512fail_platform_device2: 555fail_platform_device2:
513 platform_device_put(platform_device); 556 platform_device_put(platform_device);
@@ -529,6 +572,7 @@ static void __exit dell_exit(void)
529 platform_driver_unregister(&platform_driver); 572 platform_driver_unregister(&platform_driver);
530 } 573 }
531 kfree(da_tokens); 574 kfree(da_tokens);
575 free_page((unsigned long)buffer);
532} 576}
533 577
534module_init(dell_init); 578module_init(dell_init);