Hi Arjan,

This patch, the final one, enables monitoring the Digital Temperature
Sensor on the medfield platform.

This driver, registers itself with the generic thermal sysfs framework.
It monitors the dts temperature and sends out a notification when the
temperature reaches critical limit.

Re-submitting the patch, after fixing Jacob's comments on formatting.

--------------------------------------------------------------------
Signed-off-by:  <[email protected]>

Index: kernel/arch/x86/include/asm/mce.h
===================================================================
--- kernel.orig/arch/x86/include/asm/mce.h
+++ kernel/arch/x86/include/asm/mce.h
@@ -220,7 +220,7 @@ extern void (*threshold_cpu_callback)(un
  */

 void intel_init_thermal(struct cpuinfo_x86 *c);
-
+extern int (*platform_thermal_notify)(__u64 msr_val);
 void mce_log_therm_throt_event(__u64 status);

 #ifdef CONFIG_X86_THERMAL_VECTOR
Index: kernel/arch/x86/include/asm/msr-index.h
===================================================================
--- kernel.orig/arch/x86/include/asm/msr-index.h
+++ kernel/arch/x86/include/asm/msr-index.h
@@ -92,6 +92,9 @@
 #define MSR_IA32_MCx_ADDR(x)           (MSR_IA32_MC0_ADDR + 4*(x))
 #define MSR_IA32_MCx_MISC(x)           (MSR_IA32_MC0_MISC + 4*(x))

+#define CMCI_EN                                (1ULL << 30)
+#define CMCI_THRESHOLD_MASK            0xffffULL
+
 /* These are consecutive and not in the normal 4er MCE bank block */
 #define MSR_IA32_MC0_CTL2              0x00000280
 #define MSR_IA32_MCx_CTL2(x)           (MSR_IA32_MC0_CTL2 + (x))
@@ -251,6 +254,17 @@
 #define PACKAGE_THERM_INT_LOW_ENABLE           (1 << 1)
 #define PACKAGE_THERM_INT_PLN_ENABLE           (1 << 24)

+#define THERM_INT_THRESHOLD0_ENABLE    (1 << 15)
+#define THERM_OFFSET_THRESHOLD0        8
+#define THERM_MASK_THRESHOLD0          (0x7f << THERM_OFFSET_THRESHOLD0)
+#define THERM_INT_THRESHOLD1_ENABLE    (1 << 23)
+#define THERM_OFFSET_THRESHOLD1        16
+#define THERM_MASK_THRESHOLD1          (0x7f << THERM_OFFSET_THRESHOLD1)
+#define THERM_STATUS_THRESHOLD0        (1 << 6)
+#define THERM_LOG_THRESHOLD0           (1 << 7)
+#define THERM_STATUS_THRESHOLD1        (1 << 8)
+#define THERM_LOG_THRESHOLD1           (1 << 9)
+
 /* MISC_ENABLE bits: architectural */
 #define MSR_IA32_MISC_ENABLE_FAST_STRING       (1ULL << 0)
 #define MSR_IA32_MISC_ENABLE_TCC               (1ULL << 1)
Index: kernel/arch/x86/kernel/cpu/mcheck/therm_throt.c
===================================================================
--- kernel.orig/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ kernel/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -33,6 +33,7 @@

 /* How long to wait between reporting thermal events */
 #define CHECK_INTERVAL         (300 * HZ)
+#define THRES_INTERVAL         (25 * HZ)

 #define THERMAL_THROTTLING_EVENT       0
 #define POWER_LIMIT_EVENT              1
@@ -53,6 +54,8 @@ struct thermal_state {
        struct _thermal_state core_power_limit;
        struct _thermal_state package_throttle;
        struct _thermal_state package_power_limit;
+       struct _thermal_state core_thresh0;
+       struct _thermal_state core_thresh1;
 };

 static DEFINE_PER_CPU(struct thermal_state, thermal_state);
@@ -61,6 +64,9 @@ static atomic_t therm_throt_en        = ATOMIC_

 static u32 lvtthmr_init __read_mostly;

+/*platform thermal notifier */
+int (*platform_thermal_notify)(__u64 msr_val) = NULL;
+
 #ifdef CONFIG_SYSFS
 #define define_therm_throt_sysdev_one_ro(_name)                                
\
        static SYSDEV_ATTR(_name, 0444,                                 \
@@ -200,6 +206,31 @@ static int therm_throt_process(bool new_
        return 0;
 }

+static int thresh_event_valid(int event)
+{
+       struct _thermal_state *state = NULL;
+       unsigned int this_cpu = smp_processor_id();
+       struct thermal_state *pstate = &per_cpu(thermal_state, this_cpu);
+       u64 now = get_jiffies_64();
+
+       switch (event) {
+       case 0:
+               state = &pstate->core_thresh0;
+               break;
+       case 1:
+               state = &pstate->core_thresh1;
+               break;
+       default:
+               WARN_ON(1);
+       }
+
+       if (time_before64(now, state->next_check))
+               return 0;
+
+       state->next_check = now + THRES_INTERVAL;
+       return 1;
+}
+
 #ifdef CONFIG_SYSFS
 /* Add/Remove thermal_throttle interface for CPU device: */
 static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev,
@@ -324,7 +355,6 @@ static void intel_thermal_interrupt(void
                                THERMAL_THROTTLING_EVENT,
                                CORE_LEVEL) != 0)
                mce_log_therm_throt_event(CORE_THROTTLED | msr_val);
-
        if (cpu_has(c, X86_FEATURE_PLN))
                if (therm_throt_process(msr_val & THERM_STATUS_POWER_LIMIT,
                                        POWER_LIMIT_EVENT,
@@ -345,6 +375,17 @@ static void intel_thermal_interrupt(void
                                mce_log_therm_throt_event(PACKAGE_POWER_LIMIT
                                                          | msr_val);
        }
+
+       /* check whether handler is defined */
+       if (platform_thermal_notify) {
+               /* lower threshold reached */
+               if ((msr_val & THERM_LOG_THRESHOLD0) && thresh_event_valid(0))
+                       platform_thermal_notify(msr_val);
+               /* higher threshold reached */
+               if ((msr_val & THERM_LOG_THRESHOLD1) && thresh_event_valid(1))
+                       platform_thermal_notify(msr_val);
+               /* handle other events if any */
+       }
 }

 static void unexpected_thermal_interrupt(void)
Index: kernel/drivers/hwmon/coretemp.c
===================================================================
--- kernel.orig/drivers/hwmon/coretemp.c
+++ kernel/drivers/hwmon/coretemp.c
@@ -37,21 +37,22 @@
 #include <asm/msr.h>
 #include <asm/processor.h>

+#include <linux/thermal.h>
+#include <linux/workqueue.h>
+#include <asm/mce.h>
+
 #define DRVNAME        "coretemp"
+#define TRIP_POINTS 4

-typedef enum { SHOW_TEMP, SHOW_TJMAX, SHOW_TTARGET, SHOW_LABEL,
-               SHOW_NAME } SHOW;
+static DEFINE_MUTEX(userspace_mutex);

-/*
- * Functions declaration
- */
+enum THRES{TTHRES1, TTHRES2, TTARGET, TJMAX};

-static struct coretemp_data *coretemp_update_device(struct device *dev);
+static struct thermal_zone_device *tzd[NR_CPUS];

 struct coretemp_data {
-       struct device *hwmon_dev;
        struct mutex update_lock;
-       const char *name;
+       char name[THERMAL_NAME_LENGTH];
        u32 id;
        u16 core_id;
        char valid;             /* zero until following fields are valid */
@@ -59,78 +60,228 @@ struct coretemp_data {
        int temp;
        int tjmax;
        int ttarget;
+       bool thres0stat;
+       bool thres1stat;
+       int tthres0;
+       int tthres1;
        u8 alarm;
 };

-/*
- * Sysfs stuff
- */
+static int write_trip_temp(struct thermal_zone_device *, int, long);
+static int read_trip_temp(struct thermal_zone_device *, int, long *);
+static int read_curr_temp(struct thermal_zone_device *, long *);
+static int read_trip_type(struct thermal_zone_device *, int,
+                                               enum thermal_trip_type *);
+static int set_threshold(struct coretemp_data *, enum THRES, long);
+static struct coretemp_data *coretemp_update_device(struct coretemp_data *);
+
+static struct thermal_zone_device_ops tzd_ops = {
+       .get_trip_type = read_trip_type,
+       .get_trip_temp = read_trip_temp,
+       .set_trip_temp = write_trip_temp,
+       .get_temp = read_curr_temp,
+};
+
+struct work_struct *aux0_netlink_handlr;
+struct work_struct *aux1_netlink_handlr;
+
+static int read_trip_type(struct thermal_zone_device *tzd, int trip,
+                               enum thermal_trip_type *type)
+{
+       *type = THERMAL_TRIP_PASSIVE;
+       return 0;
+}

-static ssize_t show_name(struct device *dev, struct device_attribute
-                         *devattr, char *buf)
+static int read_trip_temp(struct thermal_zone_device *tzd, int trip,
+                                               long *temperature)
 {
-       int ret;
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct coretemp_data *data = dev_get_drvdata(dev);
+       struct coretemp_data *data = (struct coretemp_data *)tzd->devdata;
+
+       data = coretemp_update_device(data);

-       if (attr->index == SHOW_NAME)
-               ret = sprintf(buf, "%s\n", data->name);
-       else    /* show label */
-               ret = sprintf(buf, "Core %d\n", data->core_id);
-       return ret;
+       if (!data->valid)
+               return -EINVAL;
+
+       switch (trip) {
+       case TTHRES1:
+               *temperature = data->tthres0;
+               break;
+       case TTHRES2:
+               *temperature = data->tthres1;
+               break;
+       case TTARGET:
+               *temperature = data->ttarget;
+               break;
+       case TJMAX:
+               *temperature = data->tjmax;
+               break;
+       default:
+               WARN_ON(1);
+       }
+       return 0;
 }

-static ssize_t show_alarm(struct device *dev, struct device_attribute
-                         *devattr, char *buf)
+static int read_curr_temp(struct thermal_zone_device *tzd, long *temperature)
 {
-       struct coretemp_data *data = coretemp_update_device(dev);
-       /* read the Out-of-spec log, never clear */
-       return sprintf(buf, "%d\n", data->alarm);
+       struct coretemp_data *data = (struct coretemp_data *)tzd->devdata;
+
+       data = coretemp_update_device(data);
+
+       if (!data->valid)
+               return -EINVAL;
+
+       *temperature = data->temp;
+
+       return 0;
 }

-static ssize_t show_temp(struct device *dev,
-                        struct device_attribute *devattr, char *buf)
+static int write_trip_temp(struct thermal_zone_device *tzd, int trip,
+                                                       long temperature)
 {
-       struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
-       struct coretemp_data *data = coretemp_update_device(dev);
-       int err;
+       struct coretemp_data *data = (struct coretemp_data *)tzd->devdata;
+       int err = 0;

-       if (attr->index == SHOW_TEMP)
-               err = data->valid ? sprintf(buf, "%d\n", data->temp) : -EAGAIN;
-       else if (attr->index == SHOW_TJMAX)
-               err = sprintf(buf, "%d\n", data->tjmax);
-       else
-               err = sprintf(buf, "%d\n", data->ttarget);
+       data = coretemp_update_device(data);
+
+       if (!data->valid)
+               return -EINVAL;
+
+       switch (trip) {
+       case TTHRES1:
+               err = set_threshold(data, TTHRES1, temperature);
+               break;
+       case TTHRES2:
+               err = set_threshold(data, TTHRES2, temperature);
+               break;
+       case TTARGET:
+               data->ttarget = temperature;
+               break;
+       case TJMAX:
+               data->tjmax = temperature;
+               break;
+       default:
+               WARN_ON(1);
+       }
        return err;
 }

-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL,
-                         SHOW_TEMP);
-static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp, NULL,
-                         SHOW_TJMAX);
-static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp, NULL,
-                         SHOW_TTARGET);
-static DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_name, NULL, SHOW_LABEL);
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, SHOW_NAME);
-
-static struct attribute *coretemp_attributes[] = {
-       &sensor_dev_attr_name.dev_attr.attr,
-       &sensor_dev_attr_temp1_label.dev_attr.attr,
-       &dev_attr_temp1_crit_alarm.attr,
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp1_crit.dev_attr.attr,
-       NULL
-};
+static void gen_netlink_aux0(struct work_struct *work)
+{
+       unsigned int this_cpu = smp_processor_id();
+       generate_netlink_event(tzd[this_cpu]->id, THERMAL_AUX0);
+}

-static const struct attribute_group coretemp_group = {
-       .attrs = coretemp_attributes,
-};
+static void gen_netlink_aux1(struct work_struct *work)
+{
+       unsigned int this_cpu = smp_processor_id();
+       generate_netlink_event(tzd[this_cpu]->id, THERMAL_AUX1);
+}
+
+static int coretemp_interrupt(__u64 msr_val)
+{
+       if (msr_val & THERM_LOG_THRESHOLD0) {
+               /* reset the THRESHOLD0 interrupt*/
+               wrmsrl(MSR_IA32_THERM_STATUS, msr_val &
+                                       ~THERM_LOG_THRESHOLD0);
+
+               /* THRM_THRESHOLD0 was hit */
+               if (!(msr_val & THERM_STATUS_THRESHOLD0))
+                       schedule_work(aux0_netlink_handlr);
+       }
+
+       if (msr_val & THERM_LOG_THRESHOLD1) {
+               /* reset the THRESHOLD1 interrupt */
+               wrmsrl(MSR_IA32_THERM_STATUS, msr_val &
+                                       ~THERM_LOG_THRESHOLD1);
+
+               /* THRM_THRESHOLD1 was hit */
+               if (msr_val & THERM_STATUS_THRESHOLD1)
+                       schedule_work(aux1_netlink_handlr);
+       }
+       return 0;
+}

-static struct coretemp_data *coretemp_update_device(struct device *dev)
+static int set_threshold(struct coretemp_data *data, enum THRES trip,
+                                               long val)
 {
-       struct coretemp_data *data = dev_get_drvdata(dev);
+       u32 eax, edx, l;
+       int err = 0;

+       mutex_lock(&userspace_mutex);
+
+       if (val > data->tjmax) {
+               err = -EINVAL;
+               goto exit;
+       }
+
+       switch (trip) {
+       case TTHRES1:
+               if (!data->thres0stat) {
+                       err = -EINVAL;
+                       break;
+               }
+               /* mask the thermal vector in the lapic */
+               l = apic_read(APIC_LVTTHMR);
+               apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
+               platform_thermal_notify = NULL;
+               rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
+               eax &= ~THERM_MASK_THRESHOLD0;
+               eax |= (((data->tjmax/1000) - (val/1000)) <<
+                                               THERM_OFFSET_THRESHOLD0);
+               wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
+               /* workaround to ignore threshold interrupt while moving
+                * threshold boundary across the current temperature.
+               */
+               msleep(20);
+               rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
+               eax &= ~THERM_LOG_THRESHOLD0;
+               wrmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, eax, edx);
+               platform_thermal_notify = coretemp_interrupt;
+               /* unmask the thermal vector */
+               l = apic_read(APIC_LVTTHMR);
+               apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+               break;
+
+       case TTHRES2:
+               if (!data->thres1stat) {
+                       err = -EINVAL;
+                       break;
+               }
+               /* mask the thermal vector in the lapic */
+               l = apic_read(APIC_LVTTHMR);
+               apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
+               platform_thermal_notify = NULL;
+               rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
+               eax &= ~THERM_MASK_THRESHOLD1;
+               eax |= (((data->tjmax/1000) - (val/1000)) <<
+                                       THERM_OFFSET_THRESHOLD1);
+               wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
+               /* workaround to ignore threshold interrupt while moving
+               * threshold boundary across the current temperature.
+               */
+               msleep(20);
+               rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
+               eax &= ~THERM_LOG_THRESHOLD1;
+               wrmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, eax, edx);
+               platform_thermal_notify = coretemp_interrupt;
+               /* unmask the thermal vector */
+               l = apic_read(APIC_LVTTHMR);
+               apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+               break;
+       default:
+               err = -EINVAL;
+       }
+
+exit:
+       mutex_unlock(&userspace_mutex);
+       if (err)
+               return err;
+
+       return 0;
+}
+
+static struct coretemp_data *coretemp_update_device(struct coretemp_data *data)
+{
        mutex_lock(&data->update_lock);

        if (!data->valid || time_after(jiffies, data->last_updated + HZ)) {
@@ -139,14 +290,29 @@ static struct coretemp_data *coretemp_up
                data->valid = 0;
                rdmsr_on_cpu(data->id, MSR_IA32_THERM_STATUS, &eax, &edx);
                data->alarm = (eax >> 5) & 1;
+
                /* update only if data has been valid */
                if (eax & 0x80000000) {
                        data->temp = data->tjmax - (((eax >> 16)
                                                        & 0x7f) * 1000);
                        data->valid = 1;
                } else {
-                       dev_dbg(dev, "Temperature data invalid (0x%x)\n", eax);
+                       printk(KERN_INFO "Temperature invalid (0x%x)\n", eax);
+               }
+
+               /*update thresholds*/
+               rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
+               if (data->thres0stat) {
+                       data->tthres0 = data->tjmax - (((eax &
+                                       THERM_MASK_THRESHOLD0) >>
+                                       THERM_OFFSET_THRESHOLD0) * 1000);
                }
+               if (data->thres1stat) {
+                       data->tthres1 = data->tjmax - (((eax &
+                                       THERM_MASK_THRESHOLD1) >>
+                                       THERM_OFFSET_THRESHOLD1) * 1000);
+               }
+
                data->last_updated = jiffies;
        }

@@ -242,6 +408,34 @@ static int __devinit adjust_tjmax(struct
        return tjmax;
 }

+static void __devinit enable_tthres(struct coretemp_data *data)
+{
+       u32 l, eax, edx;
+       int tthres0 = 0, tthres1 = 90000;
+
+       /* mask the thermal vector in the lapic */
+       l = apic_read(APIC_LVTTHMR);
+       apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
+       rdmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, &eax, &edx);
+       eax |= THERM_INT_THRESHOLD0_ENABLE |
+                       THERM_INT_THRESHOLD1_ENABLE |
+                       ((data->tjmax/1000) - (tthres0/1000)) <<
+                               THERM_OFFSET_THRESHOLD0 |
+                       ((data->tjmax/1000) - (tthres1/1000)) <<
+                               THERM_OFFSET_THRESHOLD1;
+       wrmsr_on_cpu(data->id, MSR_IA32_THERM_INTERRUPT, eax, edx);
+       /* unmask the thermal vector */
+       l = apic_read(APIC_LVTTHMR);
+       apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+
+       data->thres0stat = true;
+       data->tthres0 = tthres0;
+       data->thres1stat = true;
+       data->tthres1 = tthres1;
+       platform_thermal_notify = coretemp_interrupt;
+}
+
+
 static int __devinit get_tjmax(struct cpuinfo_x86 *c, u32 id,
                               struct device *dev)
 {
@@ -282,6 +476,8 @@ static int __devinit get_tjmax(struct cp
                break;
        case 0x17:
        case 0x1c:              /* Atom CPUs */
+       case 0x26:
+       case 0x27:
                return adjust_tjmax(c, id, dev);
                break;
        default:
@@ -303,12 +499,13 @@ static int __devinit coretemp_probe(stru
                dev_err(&pdev->dev, "Out of memory\n");
                goto exit;
        }
-
        data->id = pdev->id;
+
 #ifdef CONFIG_SMP
        data->core_id = c->cpu_core_id;
-#endif
-       data->name = "coretemp";
+#endif
+       sprintf(data->name, "coretemp%d", data->id);
+
        mutex_init(&data->update_lock);

        /* test if we can access the THERM_STATUS MSR */
@@ -337,47 +534,35 @@ static int __devinit coretemp_probe(stru
        }

        data->tjmax = get_tjmax(c, data->id, &pdev->dev);
-       platform_set_drvdata(pdev, data);

+       /* Enable threshold interrupt support for Intel Atom family */
+       if (c->x86_model == 0x26 || c->x86_model == 0x27)
+               enable_tthres(data);
+       else
+               platform_thermal_notify = NULL;
+
+       platform_set_drvdata(pdev, data);
        /*
         * read the still undocumented IA32_TEMPERATURE_TARGET. It exists
         * on older CPUs but not in this register,
         * Atoms don't have it either.
         */
-
        if ((c->x86_model > 0xe) && (c->x86_model != 0x1c)) {
                err = rdmsr_safe_on_cpu(data->id, MSR_IA32_TEMPERATURE_TARGET,
                    &eax, &edx);
-               if (err) {
+               if (err)
                        dev_warn(&pdev->dev, "Unable to read"
                                        " IA32_TEMPERATURE_TARGET MSR\n");
-               } else {
+               else
                        data->ttarget = data->tjmax -
-                                       (((eax >> 8) & 0xff) * 1000);
-                       err = device_create_file(&pdev->dev,
-                                       &sensor_dev_attr_temp1_max.dev_attr);
-                       if (err)
-                               goto exit_free;
-               }
-       }
-
-       if ((err = sysfs_create_group(&pdev->dev.kobj, &coretemp_group)))
-               goto exit_dev;
-
-       data->hwmon_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               dev_err(&pdev->dev, "Class registration failed (%d)\n",
-                       err);
-               goto exit_class;
+                                               (((eax >> 8) & 0xff) * 1000);
        }
+       /*register with the generic thermal sysfs framework */
+       tzd[data->id] = thermal_zone_device_register(data->name,
+                       TRIP_POINTS, data, &tzd_ops, 0, 0, 0, 0);

        return 0;

-exit_class:
-       sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-exit_dev:
-       device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
 exit_free:
        kfree(data);
 exit:
@@ -388,9 +573,6 @@ static int __devexit coretemp_remove(str
 {
        struct coretemp_data *data = platform_get_drvdata(pdev);

-       hwmon_device_unregister(data->hwmon_dev);
-       sysfs_remove_group(&pdev->dev.kobj, &coretemp_group);
-       device_remove_file(&pdev->dev, &sensor_dev_attr_temp1_max.dev_attr);
        platform_set_drvdata(pdev, NULL);
        kfree(data);
        return 0;
@@ -423,6 +605,7 @@ static int __cpuinit coretemp_device_add
        int err;
        struct platform_device *pdev;
        struct pdev_entry *pdev_entry;
+
 #ifdef CONFIG_SMP
        struct cpuinfo_x86 *c = &cpu_data(cpu);
 #endif
@@ -433,8 +616,8 @@ static int __cpuinit coretemp_device_add
        /* Skip second HT entry of each core */
        list_for_each_entry(pdev_entry, &pdev_list, list) {
                if (c->phys_proc_id == pdev_entry->phys_proc_id &&
-                   c->cpu_core_id == pdev_entry->cpu_core_id) {
-                       err = 0;        /* Not an error */
+               c->cpu_core_id == pdev_entry->cpu_core_id) {
+                       err = 0;        /* Not an error */
                        goto exit;
                }
        }
@@ -462,10 +645,12 @@ static int __cpuinit coretemp_device_add

        pdev_entry->pdev = pdev;
        pdev_entry->cpu = cpu;
+
 #ifdef CONFIG_SMP
        pdev_entry->phys_proc_id = c->phys_proc_id;
        pdev_entry->cpu_core_id = c->cpu_core_id;
 #endif
+
        list_add_tail(&pdev_entry->list, &pdev_list);
        mutex_unlock(&pdev_list_mutex);

@@ -476,10 +661,10 @@ exit_device_free:
 exit_device_put:
        platform_device_put(pdev);
 exit:
-       mutex_unlock(&pdev_list_mutex);
        return err;
 }

+#ifdef CONFIG_HOTPLUG_CPU
 static void coretemp_device_remove(unsigned int cpu)
 {
        struct pdev_entry *p, *n;
@@ -514,10 +699,12 @@ static int __cpuinit coretemp_cpu_callba
 static struct notifier_block coretemp_cpu_notifier __refdata = {
        .notifier_call = coretemp_cpu_callback,
 };
+#endif                         /* !CONFIG_HOTPLUG_CPU */

 static int __init coretemp_init(void)
 {
        int i, err = -ENODEV;
+       struct pdev_entry *p, *n;

        /* quick check if we run Intel */
        if (cpu_data(0).x86_vendor != X86_VENDOR_INTEL)
@@ -534,9 +721,12 @@ static int __init coretemp_init(void)
                 * sensors. We check this bit only, all the early CPUs
                 * without thermal sensors will be filtered out.
                 */
-               if (c->cpuid_level >= 6 && (cpuid_eax(0x06) & 0x01))
-                       coretemp_device_add(i);
-               else {
+               if (c->cpuid_level >= 6 && (cpuid_eax(0x06) & 0x01)) {
+                       err = coretemp_device_add(i);
+                       if (err)
+                               goto exit_devices_unreg;
+
+               } else {
                        printk(KERN_INFO DRVNAME ": CPU (model=0x%x)"
                                " has no thermal sensor.\n", c->x86_model);
                }
@@ -546,13 +736,30 @@ static int __init coretemp_init(void)
                goto exit_driver_unreg;
        }

+#ifdef CONFIG_HOTPLUG_CPU
        register_hotcpu_notifier(&coretemp_cpu_notifier);
+#endif
+
+       aux0_netlink_handlr = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
+       aux1_netlink_handlr = kzalloc(sizeof(struct work_struct), GFP_KERNEL);
+
+       if (!aux0_netlink_handlr || !aux1_netlink_handlr)
+               return -ENOMEM;
+
+       INIT_WORK(aux0_netlink_handlr, (void *)gen_netlink_aux0);
+       INIT_WORK(aux1_netlink_handlr, (void *)gen_netlink_aux1);
        return 0;

+exit_devices_unreg:
+       mutex_lock(&pdev_list_mutex);
+       list_for_each_entry_safe(p, n, &pdev_list, list) {
+               platform_device_unregister(p->pdev);
+               list_del(&p->list);
+               kfree(p);
+       }
+       mutex_unlock(&pdev_list_mutex);
 exit_driver_unreg:
-#ifndef CONFIG_HOTPLUG_CPU
        platform_driver_unregister(&coretemp_driver);
-#endif
 exit:
        return err;
 }

Attachment: mfld_dts_driver.patch
Description: mfld_dts_driver.patch

_______________________________________________
Meego-kernel mailing list
[email protected]
http://lists.meego.com/listinfo/meego-kernel

Reply via email to