diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-17 16:15:55 -0500 |
commit | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (patch) | |
tree | a8f4d49d63b1ecc92f2fddceba0655b2472c5bd9 /drivers/hwmon/ibmaem.c | |
parent | 406089d01562f1e2bf9f089fd7637009ebaad589 (diff) |
Patched in Tegra support.
Diffstat (limited to 'drivers/hwmon/ibmaem.c')
-rw-r--r-- | drivers/hwmon/ibmaem.c | 112 |
1 files changed, 67 insertions, 45 deletions
diff --git a/drivers/hwmon/ibmaem.c b/drivers/hwmon/ibmaem.c index a14f634248e..c316294c48b 100644 --- a/drivers/hwmon/ibmaem.c +++ b/drivers/hwmon/ibmaem.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <linux/platform_device.h> | 36 | #include <linux/platform_device.h> |
37 | #include <linux/math64.h> | 37 | #include <linux/math64.h> |
38 | #include <linux/time.h> | 38 | #include <linux/time.h> |
39 | #include <linux/err.h> | ||
40 | 39 | ||
41 | #define REFRESH_INTERVAL (HZ) | 40 | #define REFRESH_INTERVAL (HZ) |
42 | #define IPMI_TIMEOUT (30 * HZ) | 41 | #define IPMI_TIMEOUT (30 * HZ) |
@@ -89,7 +88,8 @@ | |||
89 | #define AEM_MIN_POWER_INTERVAL 200 | 88 | #define AEM_MIN_POWER_INTERVAL 200 |
90 | #define UJ_PER_MJ 1000L | 89 | #define UJ_PER_MJ 1000L |
91 | 90 | ||
92 | static DEFINE_IDA(aem_ida); | 91 | static DEFINE_IDR(aem_idr); |
92 | static DEFINE_SPINLOCK(aem_idr_lock); | ||
93 | 93 | ||
94 | static struct platform_driver aem_driver = { | 94 | static struct platform_driver aem_driver = { |
95 | .driver = { | 95 | .driver = { |
@@ -148,9 +148,8 @@ struct aem_data { | |||
148 | int id; | 148 | int id; |
149 | struct aem_ipmi_data ipmi; | 149 | struct aem_ipmi_data ipmi; |
150 | 150 | ||
151 | /* Function and buffer to update sensors */ | 151 | /* Function to update sensors */ |
152 | void (*update)(struct aem_data *data); | 152 | void (*update)(struct aem_data *data); |
153 | struct aem_read_sensor_resp *rs_resp; | ||
154 | 153 | ||
155 | /* | 154 | /* |
156 | * AEM 1.x sensors: | 155 | * AEM 1.x sensors: |
@@ -247,6 +246,8 @@ static void aem_bmc_gone(int iface); | |||
247 | static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); | 246 | static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data); |
248 | 247 | ||
249 | static void aem_remove_sensors(struct aem_data *data); | 248 | static void aem_remove_sensors(struct aem_data *data); |
249 | static int aem_init_aem1(struct aem_ipmi_data *probe); | ||
250 | static int aem_init_aem2(struct aem_ipmi_data *probe); | ||
250 | static int aem1_find_sensors(struct aem_data *data); | 251 | static int aem1_find_sensors(struct aem_data *data); |
251 | static int aem2_find_sensors(struct aem_data *data); | 252 | static int aem2_find_sensors(struct aem_data *data); |
252 | static void update_aem1_sensors(struct aem_data *data); | 253 | static void update_aem1_sensors(struct aem_data *data); |
@@ -355,16 +356,47 @@ static void aem_msg_handler(struct ipmi_recv_msg *msg, void *user_msg_data) | |||
355 | complete(&data->read_complete); | 356 | complete(&data->read_complete); |
356 | } | 357 | } |
357 | 358 | ||
359 | /* ID functions */ | ||
360 | |||
361 | /* Obtain an id */ | ||
362 | static int aem_idr_get(int *id) | ||
363 | { | ||
364 | int i, err; | ||
365 | |||
366 | again: | ||
367 | if (unlikely(!idr_pre_get(&aem_idr, GFP_KERNEL))) | ||
368 | return -ENOMEM; | ||
369 | |||
370 | spin_lock(&aem_idr_lock); | ||
371 | err = idr_get_new(&aem_idr, NULL, &i); | ||
372 | spin_unlock(&aem_idr_lock); | ||
373 | |||
374 | if (unlikely(err == -EAGAIN)) | ||
375 | goto again; | ||
376 | else if (unlikely(err)) | ||
377 | return err; | ||
378 | |||
379 | *id = i & MAX_ID_MASK; | ||
380 | return 0; | ||
381 | } | ||
382 | |||
383 | /* Release an object ID */ | ||
384 | static void aem_idr_put(int id) | ||
385 | { | ||
386 | spin_lock(&aem_idr_lock); | ||
387 | idr_remove(&aem_idr, id); | ||
388 | spin_unlock(&aem_idr_lock); | ||
389 | } | ||
390 | |||
358 | /* Sensor support functions */ | 391 | /* Sensor support functions */ |
359 | 392 | ||
360 | /* Read a sensor value; must be called with data->lock held */ | 393 | /* Read a sensor value */ |
361 | static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, | 394 | static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, |
362 | void *buf, size_t size) | 395 | void *buf, size_t size) |
363 | { | 396 | { |
364 | int rs_size, res; | 397 | int rs_size, res; |
365 | struct aem_read_sensor_req rs_req; | 398 | struct aem_read_sensor_req rs_req; |
366 | /* Use preallocated rx buffer */ | 399 | struct aem_read_sensor_resp *rs_resp; |
367 | struct aem_read_sensor_resp *rs_resp = data->rs_resp; | ||
368 | struct aem_ipmi_data *ipmi = &data->ipmi; | 400 | struct aem_ipmi_data *ipmi = &data->ipmi; |
369 | 401 | ||
370 | /* AEM registers are 1, 2, 4 or 8 bytes */ | 402 | /* AEM registers are 1, 2, 4 or 8 bytes */ |
@@ -390,6 +422,10 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, | |||
390 | ipmi->tx_message.data_len = sizeof(rs_req); | 422 | ipmi->tx_message.data_len = sizeof(rs_req); |
391 | 423 | ||
392 | rs_size = sizeof(*rs_resp) + size; | 424 | rs_size = sizeof(*rs_resp) + size; |
425 | rs_resp = kzalloc(rs_size, GFP_KERNEL); | ||
426 | if (!rs_resp) | ||
427 | return -ENOMEM; | ||
428 | |||
393 | ipmi->rx_msg_data = rs_resp; | 429 | ipmi->rx_msg_data = rs_resp; |
394 | ipmi->rx_msg_len = rs_size; | 430 | ipmi->rx_msg_len = rs_size; |
395 | 431 | ||
@@ -432,6 +468,7 @@ static int aem_read_sensor(struct aem_data *data, u8 elt, u8 reg, | |||
432 | res = 0; | 468 | res = 0; |
433 | 469 | ||
434 | out: | 470 | out: |
471 | kfree(rs_resp); | ||
435 | return res; | 472 | return res; |
436 | } | 473 | } |
437 | 474 | ||
@@ -489,12 +526,11 @@ static void aem_delete(struct aem_data *data) | |||
489 | { | 526 | { |
490 | list_del(&data->list); | 527 | list_del(&data->list); |
491 | aem_remove_sensors(data); | 528 | aem_remove_sensors(data); |
492 | kfree(data->rs_resp); | ||
493 | hwmon_device_unregister(data->hwmon_dev); | 529 | hwmon_device_unregister(data->hwmon_dev); |
494 | ipmi_destroy_user(data->ipmi.user); | 530 | ipmi_destroy_user(data->ipmi.user); |
495 | platform_set_drvdata(data->pdev, NULL); | 531 | platform_set_drvdata(data->pdev, NULL); |
496 | platform_device_unregister(data->pdev); | 532 | platform_device_unregister(data->pdev); |
497 | ida_simple_remove(&aem_ida, data->id); | 533 | aem_idr_put(data->id); |
498 | kfree(data); | 534 | kfree(data); |
499 | } | 535 | } |
500 | 536 | ||
@@ -551,8 +587,7 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) | |||
551 | data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; | 587 | data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; |
552 | 588 | ||
553 | /* Create sub-device for this fw instance */ | 589 | /* Create sub-device for this fw instance */ |
554 | data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL); | 590 | if (aem_idr_get(&data->id)) |
555 | if (data->id < 0) | ||
556 | goto id_err; | 591 | goto id_err; |
557 | 592 | ||
558 | data->pdev = platform_device_alloc(DRVNAME, data->id); | 593 | data->pdev = platform_device_alloc(DRVNAME, data->id); |
@@ -567,31 +602,24 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) | |||
567 | platform_set_drvdata(data->pdev, data); | 602 | platform_set_drvdata(data->pdev, data); |
568 | 603 | ||
569 | /* Set up IPMI interface */ | 604 | /* Set up IPMI interface */ |
570 | res = aem_init_ipmi_data(&data->ipmi, probe->interface, | 605 | if (aem_init_ipmi_data(&data->ipmi, probe->interface, |
571 | probe->bmc_device); | 606 | probe->bmc_device)) |
572 | if (res) | ||
573 | goto ipmi_err; | 607 | goto ipmi_err; |
574 | 608 | ||
575 | /* Register with hwmon */ | 609 | /* Register with hwmon */ |
576 | data->hwmon_dev = hwmon_device_register(&data->pdev->dev); | 610 | data->hwmon_dev = hwmon_device_register(&data->pdev->dev); |
611 | |||
577 | if (IS_ERR(data->hwmon_dev)) { | 612 | if (IS_ERR(data->hwmon_dev)) { |
578 | dev_err(&data->pdev->dev, "Unable to register hwmon " | 613 | dev_err(&data->pdev->dev, "Unable to register hwmon " |
579 | "device for IPMI interface %d\n", | 614 | "device for IPMI interface %d\n", |
580 | probe->interface); | 615 | probe->interface); |
581 | res = PTR_ERR(data->hwmon_dev); | ||
582 | goto hwmon_reg_err; | 616 | goto hwmon_reg_err; |
583 | } | 617 | } |
584 | 618 | ||
585 | data->update = update_aem1_sensors; | 619 | data->update = update_aem1_sensors; |
586 | data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL); | ||
587 | if (!data->rs_resp) { | ||
588 | res = -ENOMEM; | ||
589 | goto alloc_resp_err; | ||
590 | } | ||
591 | 620 | ||
592 | /* Find sensors */ | 621 | /* Find sensors */ |
593 | res = aem1_find_sensors(data); | 622 | if (aem1_find_sensors(data)) |
594 | if (res) | ||
595 | goto sensor_err; | 623 | goto sensor_err; |
596 | 624 | ||
597 | /* Add to our list of AEM devices */ | 625 | /* Add to our list of AEM devices */ |
@@ -603,8 +631,6 @@ static int aem_init_aem1_inst(struct aem_ipmi_data *probe, u8 module_handle) | |||
603 | return 0; | 631 | return 0; |
604 | 632 | ||
605 | sensor_err: | 633 | sensor_err: |
606 | kfree(data->rs_resp); | ||
607 | alloc_resp_err: | ||
608 | hwmon_device_unregister(data->hwmon_dev); | 634 | hwmon_device_unregister(data->hwmon_dev); |
609 | hwmon_reg_err: | 635 | hwmon_reg_err: |
610 | ipmi_destroy_user(data->ipmi.user); | 636 | ipmi_destroy_user(data->ipmi.user); |
@@ -612,7 +638,7 @@ ipmi_err: | |||
612 | platform_set_drvdata(data->pdev, NULL); | 638 | platform_set_drvdata(data->pdev, NULL); |
613 | platform_device_unregister(data->pdev); | 639 | platform_device_unregister(data->pdev); |
614 | dev_err: | 640 | dev_err: |
615 | ida_simple_remove(&aem_ida, data->id); | 641 | aem_idr_put(data->id); |
616 | id_err: | 642 | id_err: |
617 | kfree(data); | 643 | kfree(data); |
618 | 644 | ||
@@ -620,7 +646,7 @@ id_err: | |||
620 | } | 646 | } |
621 | 647 | ||
622 | /* Find and initialize all AEM1 instances */ | 648 | /* Find and initialize all AEM1 instances */ |
623 | static void aem_init_aem1(struct aem_ipmi_data *probe) | 649 | static int aem_init_aem1(struct aem_ipmi_data *probe) |
624 | { | 650 | { |
625 | int num, i, err; | 651 | int num, i, err; |
626 | 652 | ||
@@ -631,8 +657,11 @@ static void aem_init_aem1(struct aem_ipmi_data *probe) | |||
631 | dev_err(probe->bmc_device, | 657 | dev_err(probe->bmc_device, |
632 | "Error %d initializing AEM1 0x%X\n", | 658 | "Error %d initializing AEM1 0x%X\n", |
633 | err, i); | 659 | err, i); |
660 | return err; | ||
634 | } | 661 | } |
635 | } | 662 | } |
663 | |||
664 | return 0; | ||
636 | } | 665 | } |
637 | 666 | ||
638 | /* Probe functions for AEM2 devices */ | 667 | /* Probe functions for AEM2 devices */ |
@@ -691,8 +720,7 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, | |||
691 | data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; | 720 | data->power_period[i] = AEM_DEFAULT_POWER_INTERVAL; |
692 | 721 | ||
693 | /* Create sub-device for this fw instance */ | 722 | /* Create sub-device for this fw instance */ |
694 | data->id = ida_simple_get(&aem_ida, 0, 0, GFP_KERNEL); | 723 | if (aem_idr_get(&data->id)) |
695 | if (data->id < 0) | ||
696 | goto id_err; | 724 | goto id_err; |
697 | 725 | ||
698 | data->pdev = platform_device_alloc(DRVNAME, data->id); | 726 | data->pdev = platform_device_alloc(DRVNAME, data->id); |
@@ -707,31 +735,24 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, | |||
707 | platform_set_drvdata(data->pdev, data); | 735 | platform_set_drvdata(data->pdev, data); |
708 | 736 | ||
709 | /* Set up IPMI interface */ | 737 | /* Set up IPMI interface */ |
710 | res = aem_init_ipmi_data(&data->ipmi, probe->interface, | 738 | if (aem_init_ipmi_data(&data->ipmi, probe->interface, |
711 | probe->bmc_device); | 739 | probe->bmc_device)) |
712 | if (res) | ||
713 | goto ipmi_err; | 740 | goto ipmi_err; |
714 | 741 | ||
715 | /* Register with hwmon */ | 742 | /* Register with hwmon */ |
716 | data->hwmon_dev = hwmon_device_register(&data->pdev->dev); | 743 | data->hwmon_dev = hwmon_device_register(&data->pdev->dev); |
744 | |||
717 | if (IS_ERR(data->hwmon_dev)) { | 745 | if (IS_ERR(data->hwmon_dev)) { |
718 | dev_err(&data->pdev->dev, "Unable to register hwmon " | 746 | dev_err(&data->pdev->dev, "Unable to register hwmon " |
719 | "device for IPMI interface %d\n", | 747 | "device for IPMI interface %d\n", |
720 | probe->interface); | 748 | probe->interface); |
721 | res = PTR_ERR(data->hwmon_dev); | ||
722 | goto hwmon_reg_err; | 749 | goto hwmon_reg_err; |
723 | } | 750 | } |
724 | 751 | ||
725 | data->update = update_aem2_sensors; | 752 | data->update = update_aem2_sensors; |
726 | data->rs_resp = kzalloc(sizeof(*(data->rs_resp)) + 8, GFP_KERNEL); | ||
727 | if (!data->rs_resp) { | ||
728 | res = -ENOMEM; | ||
729 | goto alloc_resp_err; | ||
730 | } | ||
731 | 753 | ||
732 | /* Find sensors */ | 754 | /* Find sensors */ |
733 | res = aem2_find_sensors(data); | 755 | if (aem2_find_sensors(data)) |
734 | if (res) | ||
735 | goto sensor_err; | 756 | goto sensor_err; |
736 | 757 | ||
737 | /* Add to our list of AEM devices */ | 758 | /* Add to our list of AEM devices */ |
@@ -743,8 +764,6 @@ static int aem_init_aem2_inst(struct aem_ipmi_data *probe, | |||
743 | return 0; | 764 | return 0; |
744 | 765 | ||
745 | sensor_err: | 766 | sensor_err: |
746 | kfree(data->rs_resp); | ||
747 | alloc_resp_err: | ||
748 | hwmon_device_unregister(data->hwmon_dev); | 767 | hwmon_device_unregister(data->hwmon_dev); |
749 | hwmon_reg_err: | 768 | hwmon_reg_err: |
750 | ipmi_destroy_user(data->ipmi.user); | 769 | ipmi_destroy_user(data->ipmi.user); |
@@ -752,7 +771,7 @@ ipmi_err: | |||
752 | platform_set_drvdata(data->pdev, NULL); | 771 | platform_set_drvdata(data->pdev, NULL); |
753 | platform_device_unregister(data->pdev); | 772 | platform_device_unregister(data->pdev); |
754 | dev_err: | 773 | dev_err: |
755 | ida_simple_remove(&aem_ida, data->id); | 774 | aem_idr_put(data->id); |
756 | id_err: | 775 | id_err: |
757 | kfree(data); | 776 | kfree(data); |
758 | 777 | ||
@@ -760,7 +779,7 @@ id_err: | |||
760 | } | 779 | } |
761 | 780 | ||
762 | /* Find and initialize all AEM2 instances */ | 781 | /* Find and initialize all AEM2 instances */ |
763 | static void aem_init_aem2(struct aem_ipmi_data *probe) | 782 | static int aem_init_aem2(struct aem_ipmi_data *probe) |
764 | { | 783 | { |
765 | struct aem_find_instance_resp fi_resp; | 784 | struct aem_find_instance_resp fi_resp; |
766 | int err; | 785 | int err; |
@@ -779,9 +798,12 @@ static void aem_init_aem2(struct aem_ipmi_data *probe) | |||
779 | dev_err(probe->bmc_device, | 798 | dev_err(probe->bmc_device, |
780 | "Error %d initializing AEM2 0x%X\n", | 799 | "Error %d initializing AEM2 0x%X\n", |
781 | err, fi_resp.module_handle); | 800 | err, fi_resp.module_handle); |
801 | return err; | ||
782 | } | 802 | } |
783 | i++; | 803 | i++; |
784 | } | 804 | } |
805 | |||
806 | return 0; | ||
785 | } | 807 | } |
786 | 808 | ||
787 | /* Probe a BMC for AEM firmware instances */ | 809 | /* Probe a BMC for AEM firmware instances */ |
@@ -905,7 +927,7 @@ static ssize_t aem_set_power_period(struct device *dev, | |||
905 | unsigned long temp; | 927 | unsigned long temp; |
906 | int res; | 928 | int res; |
907 | 929 | ||
908 | res = kstrtoul(buf, 10, &temp); | 930 | res = strict_strtoul(buf, 10, &temp); |
909 | if (res) | 931 | if (res) |
910 | return res; | 932 | return res; |
911 | 933 | ||
@@ -1046,7 +1068,7 @@ static struct aem_ro_sensor_template aem2_ro_sensors[] = { | |||
1046 | {"power6_average", aem2_show_pcap_value, POWER_CAP_MIN_WARNING}, | 1068 | {"power6_average", aem2_show_pcap_value, POWER_CAP_MIN_WARNING}, |
1047 | {"power7_average", aem2_show_pcap_value, POWER_CAP_MIN}, | 1069 | {"power7_average", aem2_show_pcap_value, POWER_CAP_MIN}, |
1048 | 1070 | ||
1049 | {"power3_average", aem2_show_pcap_value, POWER_AUX}, | 1071 | {"power3_average", aem2_show_pcap_value, POWER_AUX}, |
1050 | {"power_cap", aem2_show_pcap_value, POWER_CAP}, | 1072 | {"power_cap", aem2_show_pcap_value, POWER_CAP}, |
1051 | {NULL, NULL, 0}, | 1073 | {NULL, NULL, 0}, |
1052 | }; | 1074 | }; |