summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNitin Kumbhar <nkumbhar@nvidia.com>2011-02-04 17:08:18 +0530
committerNitin Kumbhar <nkumbhar@nvidia.com>2011-02-04 17:08:18 +0530
commitb6b1f33f279fcb1c4a751f981153affa6469e94c (patch)
treea77ace4c91f29d814982c40bea8c4a172af9ee3e /drivers
parentdf4a2fbff8471de3f75d55b93e2bf94dfd26ff7e (diff)
parenta979d00287bcd3297bd13a59534073e6faa570c9 (diff)
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts: arch/arm/mach-tegra/include/mach/dc.h drivers/video/tegra/dc/hdmi.c drivers/video/tegra/host/nvhost_acm.c Change-Id: Iddf74984cc02f08dca3738967c0580ba7c375337
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/power/main.c50
-rw-r--r--drivers/cpufreq/cpufreq_stats.c30
-rw-r--r--drivers/usb/gadget/fsl_tegra_udc.c2
-rw-r--r--drivers/usb/host/ehci-tegra.c2
-rw-r--r--drivers/video/tegra/dc/dc.c32
-rw-r--r--drivers/video/tegra/dc/dc_reg.h4
-rw-r--r--drivers/video/tegra/dc/hdmi.c33
-rw-r--r--drivers/video/tegra/fb.c13
-rw-r--r--drivers/video/tegra/host/debug.c76
-rw-r--r--drivers/video/tegra/host/dev.h1
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c10
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c96
-rw-r--r--drivers/watchdog/tegra_wdt.c45
13 files changed, 268 insertions, 126 deletions
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 33f9aafb47fb..4ff491f49ee4 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -47,11 +47,10 @@ static DEFINE_MUTEX(dpm_list_mtx);
static pm_message_t pm_transition;
static void dpm_drv_timeout(unsigned long data);
-static DEFINE_TIMER(dpm_drv_wd, dpm_drv_timeout, 0, 0);
-static struct {
+struct dpm_drv_wd_data {
struct device *dev;
struct task_struct *tsk;
-} dpm_drv_wd_data;
+};
/*
* Set once the preparation of devices for a PM transition has started, reset
@@ -605,8 +604,9 @@ static bool is_async(struct device *dev)
*/
static void dpm_drv_timeout(unsigned long data)
{
- struct device *dev = dpm_drv_wd_data.dev;
- struct task_struct *tsk = dpm_drv_wd_data.tsk;
+ struct dpm_drv_wd_data *wd_data = (void *)data;
+ struct device *dev = wd_data->dev;
+ struct task_struct *tsk = wd_data->tsk;
printk(KERN_EMERG "**** DPM device timeout: %s (%s)\n", dev_name(dev),
(dev->driver ? dev->driver->name : "no driver"));
@@ -618,29 +618,6 @@ static void dpm_drv_timeout(unsigned long data)
}
/**
- * dpm_drv_wdset - Sets up driver suspend/resume watchdog timer.
- * @dev: struct device which we're guarding.
- *
- */
-static void dpm_drv_wdset(struct device *dev)
-{
- dpm_drv_wd_data.dev = dev;
- dpm_drv_wd_data.tsk = get_current();
- dpm_drv_wd.data = (unsigned long) &dpm_drv_wd_data;
- mod_timer(&dpm_drv_wd, jiffies + (HZ * 3));
-}
-
-/**
- * dpm_drv_wdclr - clears driver suspend/resume watchdog timer.
- * @dev: struct device which we're no longer guarding.
- *
- */
-static void dpm_drv_wdclr(struct device *dev)
-{
- del_timer_sync(&dpm_drv_wd);
-}
-
-/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
*
@@ -896,8 +873,19 @@ static int async_error;
static int __device_suspend(struct device *dev, pm_message_t state, bool async)
{
int error = 0;
+ struct timer_list timer;
+ struct dpm_drv_wd_data data;
dpm_wait_for_children(dev, async);
+
+ data.dev = dev;
+ data.tsk = get_current();
+ init_timer_on_stack(&timer);
+ timer.expires = jiffies + HZ * 3;
+ timer.function = dpm_drv_timeout;
+ timer.data = (unsigned long)&data;
+ add_timer(&timer);
+
device_lock(dev);
if (async_error)
@@ -939,6 +927,10 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
End:
device_unlock(dev);
+
+ del_timer_sync(&timer);
+ destroy_timer_on_stack(&timer);
+
complete_all(&dev->power.completion);
return error;
@@ -991,9 +983,7 @@ static int dpm_suspend(pm_message_t state)
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- dpm_drv_wdset(dev);
error = device_suspend(dev);
- dpm_drv_wdclr(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 00d73fc8e4e2..ca3f24c296a0 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -305,6 +305,27 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
return 0;
}
+static int cpufreq_stats_create_table_cpu(unsigned int cpu)
+{
+ struct cpufreq_policy *policy;
+ struct cpufreq_frequency_table *table;
+ int ret = -ENODEV;
+
+ policy = cpufreq_cpu_get(cpu);
+ if (!policy)
+ return -ENODEV;
+
+ table = cpufreq_frequency_get_table(cpu);
+ if (!table)
+ goto out;
+
+ ret = cpufreq_stats_create_table(policy, table);
+
+out:
+ cpufreq_cpu_put(policy);
+ return ret;
+}
+
static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
@@ -316,10 +337,14 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
case CPU_ONLINE_FROZEN:
cpufreq_update_policy(cpu);
break;
- case CPU_DEAD:
- case CPU_DEAD_FROZEN:
+ case CPU_DOWN_PREPARE:
+ case CPU_DOWN_PREPARE_FROZEN:
cpufreq_stats_free_table(cpu);
break;
+ case CPU_DOWN_FAILED:
+ case CPU_DOWN_FAILED_FROZEN:
+ cpufreq_stats_create_table_cpu(cpu);
+ break;
}
return NOTIFY_OK;
}
@@ -327,6 +352,7 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
{
.notifier_call = cpufreq_stat_cpu_callback,
+ .priority = 1,
};
static struct notifier_block notifier_policy_block = {
diff --git a/drivers/usb/gadget/fsl_tegra_udc.c b/drivers/usb/gadget/fsl_tegra_udc.c
index 74c1d0b52541..14e62f40a50a 100644
--- a/drivers/usb/gadget/fsl_tegra_udc.c
+++ b/drivers/usb/gadget/fsl_tegra_udc.c
@@ -42,7 +42,7 @@ int fsl_udc_clk_init(struct platform_device *pdev)
}
clk_enable(emc_clk);
- clk_set_rate(emc_clk, 240000000);
+ clk_set_rate(emc_clk, 400000000);
/* we have to remap the registers ourselves as fsl_udc does not
* export them for us.
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 5e14bfbe148c..5765496218a1 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -645,7 +645,7 @@ static int tegra_ehci_probe(struct platform_device *pdev)
}
clk_enable(tegra->emc_clk);
- clk_set_rate(tegra->emc_clk, 240000000);
+ clk_set_rate(tegra->emc_clk, 400000000);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 8cf9726645c9..83070a76834e 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -747,6 +747,18 @@ static int tegra_dc_program_mode(struct tegra_dc *dc, struct tegra_dc_mode *mode
tegra_dc_writel(dc, DE_SELECT_ACTIVE | DE_CONTROL_NORMAL,
DC_DISP_DATA_ENABLE_OPTIONS);
+ val = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY1);
+ if (mode->flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC)
+ val |= PIN1_LVS_OUTPUT;
+ else
+ val &= ~PIN1_LVS_OUTPUT;
+
+ if (mode->flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC)
+ val |= PIN1_LHS_OUTPUT;
+ else
+ val &= ~PIN1_LHS_OUTPUT;
+ tegra_dc_writel(dc, val, DC_COM_PIN_OUTPUT_POLARITY1);
+
/* TODO: MIPI/CRT/HDMI clock cals */
val = DISP_DATA_FORMAT_DF1P1C;
@@ -887,6 +899,23 @@ static void tegra_dc_set_out(struct tegra_dc *dc, struct tegra_dc_out *out)
}
+unsigned tegra_dc_get_out_height(struct tegra_dc *dc)
+{
+ if (dc->out)
+ return dc->out->height;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_get_out_height);
+
+unsigned tegra_dc_get_out_width(struct tegra_dc *dc)
+{
+ if (dc->out)
+ return dc->out->width;
+ else
+ return 0;
+}
+EXPORT_SYMBOL(tegra_dc_get_out_width);
static irqreturn_t tegra_dc_irq(int irq, void *ptr)
{
@@ -1186,8 +1215,9 @@ static void tegra_dc_reset_worker(struct work_struct *work)
mutex_lock(&dc->lock);
_tegra_dc_disable(dc);
+ msleep(100);
tegra_periph_reset_assert(dc->clk);
- msleep(10);
+ msleep(100);
tegra_periph_reset_deassert(dc->clk);
_tegra_dc_enable(dc);
diff --git a/drivers/video/tegra/dc/dc_reg.h b/drivers/video/tegra/dc/dc_reg.h
index d94a17b67cef..240d8a48d03e 100644
--- a/drivers/video/tegra/dc/dc_reg.h
+++ b/drivers/video/tegra/dc/dc_reg.h
@@ -136,6 +136,10 @@
#define DC_COM_PIN_OUTPUT_SELECT4 0x318
#define DC_COM_PIN_OUTPUT_SELECT5 0x319
#define DC_COM_PIN_OUTPUT_SELECT6 0x31a
+
+#define PIN1_LHS_OUTPUT (1 << 30)
+#define PIN1_LVS_OUTPUT (1 << 28)
+
#define DC_COM_PIN_MISC_CONTROL 0x31b
#define DC_COM_PM0_CONTROL 0x31c
#define DC_COM_PM0_DUTY_CYCLE 0x31d
diff --git a/drivers/video/tegra/dc/hdmi.c b/drivers/video/tegra/dc/hdmi.c
index 2b4f46ba1221..24e4fed37b40 100644
--- a/drivers/video/tegra/dc/hdmi.c
+++ b/drivers/video/tegra/dc/hdmi.c
@@ -110,7 +110,7 @@ static const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
.right_margin = 16, /* h_front_porch */
.lower_margin = 9, /* v_front_porch */
.vmode = FB_VMODE_NONINTERLACED,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
},
/* 640x480p 60hz: EIA/CEA-861-B Format 1 */
@@ -125,7 +125,7 @@ static const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
.right_margin = 16, /* h_front_porch */
.lower_margin = 10, /* v_front_porch */
.vmode = FB_VMODE_NONINTERLACED,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
},
/* 720x576p 50hz EIA/CEA-861-B Formats 17 & 18 */
@@ -140,7 +140,7 @@ static const struct fb_videomode tegra_dc_hdmi_supported_modes[] = {
.right_margin = 12, /* h_front_porch */
.lower_margin = 5, /* v_front_porch */
.vmode = FB_VMODE_NONINTERLACED,
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+ .sync = 0,
},
/* 1920x1080p 59.94/60hz EIA/CEA-861-B Format 16 */
@@ -1142,16 +1142,23 @@ static void tegra_dc_hdmi_enable(struct tegra_dc *dc)
val = _tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PWR);
} while (val & SOR_PWR_SETTING_NEW_PENDING);
- _tegra_hdmi_writel(hdmi,
- SOR_STATE_ASY_CRCMODE_COMPLETE |
- SOR_STATE_ASY_OWNER_HEAD0 |
- SOR_STATE_ASY_SUBOWNER_BOTH |
- SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A |
- /* TODO: to look at hsync polarity */
- SOR_STATE_ASY_HSYNCPOL_POS |
- SOR_STATE_ASY_VSYNCPOL_POS |
- SOR_STATE_ASY_DEPOL_POS,
- HDMI_NV_PDISP_SOR_STATE2);
+ val = SOR_STATE_ASY_CRCMODE_COMPLETE |
+ SOR_STATE_ASY_OWNER_HEAD0 |
+ SOR_STATE_ASY_SUBOWNER_BOTH |
+ SOR_STATE_ASY_PROTOCOL_SINGLE_TMDS_A |
+ SOR_STATE_ASY_DEPOL_POS;
+
+ if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_H_SYNC)
+ val |= SOR_STATE_ASY_HSYNCPOL_NEG;
+ else
+ val |= SOR_STATE_ASY_HSYNCPOL_POS;
+
+ if (dc->mode.flags & TEGRA_DC_MODE_FLAG_NEG_V_SYNC)
+ val |= SOR_STATE_ASY_VSYNCPOL_NEG;
+ else
+ val |= SOR_STATE_ASY_VSYNCPOL_POS;
+
+ tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE2);
val = SOR_STATE_ASY_HEAD_OPMODE_AWAKE | SOR_STATE_ASY_ORMODE_NORMAL;
_tegra_hdmi_writel(hdmi, val, HDMI_NV_PDISP_SOR_STATE1);
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 2f51c47a67ab..01b3d756b930 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -209,6 +209,14 @@ static int tegra_fb_set_par(struct fb_info *info)
info->mode->lower_margin;
}
+ mode.flags = 0;
+
+ if (!(info->mode->sync & FB_SYNC_HOR_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_H_SYNC;
+
+ if (!(info->mode->sync & FB_SYNC_VERT_HIGH_ACT))
+ mode.flags |= TEGRA_DC_MODE_FLAG_NEG_V_SYNC;
+
tegra_dc_set_mode(tegra_fb->win->dc, &mode);
tegra_fb->win->w = info->mode->xres;
@@ -776,9 +784,8 @@ struct tegra_fb_info *tegra_fb_register(struct nvhost_device *ndev,
info->var.yres_virtual = fb_data->yres * 2;
info->var.bits_per_pixel = fb_data->bits_per_pixel;
info->var.activate = FB_ACTIVATE_VBL;
- /* TODO: fill in the following by querying the DC */
- info->var.height = -1;
- info->var.width = -1;
+ info->var.height = tegra_dc_get_out_height(dc);
+ info->var.width = tegra_dc_get_out_width(dc);
info->var.pixclock = 0;
info->var.left_margin = 0;
info->var.right_margin = 0;
diff --git a/drivers/video/tegra/host/debug.c b/drivers/video/tegra/host/debug.c
index c1cfd6ee229c..d533310e3999 100644
--- a/drivers/video/tegra/host/debug.c
+++ b/drivers/video/tegra/host/debug.c
@@ -22,7 +22,7 @@
#include "dev.h"
-#ifdef CONFIG_DEBUG_FS
+static struct nvhost_master *debug_master;
enum {
NVHOST_DBG_STATE_CMD = 0,
@@ -134,6 +134,28 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
nvhost_module_busy(&m->mod);
+ seq_printf(s, "---- mlocks ----\n");
+ for (i = 0; i < NV_HOST1X_NB_MLOCKS; i++) {
+ u32 owner = readl(m->sync_aperture + HOST1X_SYNC_MLOCK_OWNER_0 + i * 4);
+ if (owner & 0x1)
+ seq_printf(s, "%d: locked by channel %d\n", i, (owner >> 8) * 0xff);
+ else if (owner & 0x2)
+ seq_printf(s, "%d: locked by cpu\n", i);
+ else
+ seq_printf(s, "%d: unlocked\n", i);
+ }
+ seq_printf(s, "\n---- syncpts ----\n");
+ for (i = 0; i < NV_HOST1X_SYNCPT_NB_PTS; i++) {
+ u32 max = nvhost_syncpt_read_max(&m->syncpt, i);
+ if (!max)
+ continue;
+ seq_printf(s, "id %d (%s) min %d max %d\n",
+ i, nvhost_syncpt_name(i),
+ nvhost_syncpt_update_min(&m->syncpt, i), max);
+
+ }
+
+ seq_printf(s, "\n---- channels ----\n");
for (i = 0; i < NVHOST_NUMCHANNELS; i++) {
void __iomem *regs = m->channels[i].aperture;
u32 dmaput, dmaget, dmactrl;
@@ -152,15 +174,18 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
cbread = readl(m->aperture + HOST1X_SYNC_CBREAD(i));
cbstat = readl(m->aperture + HOST1X_SYNC_CBSTAT(i));
+ seq_printf(s, "%d-%s (%d): ", i, m->channels[i].mod.name,
+ m->channels[i].mod.refcount);
+
if (dmactrl != 0x0 || !m->channels[i].cdma.push_buffer.mapped) {
- seq_printf(s, "%d: inactive\n\n", i);
+ seq_printf(s, "inactive\n\n");
continue;
}
switch (cbstat) {
case 0x00010008:
- seq_printf(s, "%d: waiting on syncpt %d val %d\n",
- i, cbread >> 24, cbread & 0xffffff);
+ seq_printf(s, "waiting on syncpt %d val %d\n",
+ cbread >> 24, cbread & 0xffffff);
break;
case 0x00010009:
@@ -169,13 +194,13 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
val = readl(m->aperture + HOST1X_SYNC_SYNCPT_BASE(base)) & 0xffff;
val += cbread & 0xffff;
- seq_printf(s, "%d: waiting on syncpt %d val %d\n",
- i, cbread >> 24, val);
+ seq_printf(s, "waiting on syncpt %d val %d\n",
+ cbread >> 24, val);
break;
default:
- seq_printf(s, "%d: active class %02x, offset %04x, val %08x\n",
- i, cbstat >> 16, cbstat & 0xffff, cbread);
+ seq_printf(s, "active class %02x, offset %04x, val %08x\n",
+ cbstat >> 16, cbstat & 0xffff, cbread);
break;
}
@@ -244,6 +269,7 @@ static int nvhost_debug_show(struct seq_file *s, void *unused)
return 0;
}
+#ifdef CONFIG_DEBUG_FS
static int nvhost_debug_open(struct inode *inode, struct file *file)
{
@@ -259,12 +285,44 @@ static const struct file_operations nvhost_debug_fops = {
void nvhost_debug_init(struct nvhost_master *master)
{
+ debug_master = master;
debugfs_create_file("tegra_host", S_IRUGO, NULL, master, &nvhost_debug_fops);
}
#else
-void nvhost_debug_add(struct nvhost_master *master)
+void nvhost_debug_init(struct nvhost_master *master)
{
+ debug_master = master;
}
#endif
+static char nvhost_debug_dump_buff[16 * 1024];
+
+void nvhost_debug_dump(void)
+{
+ struct seq_file s;
+ int i;
+ char c;
+
+ memset(&s, 0x0, sizeof(s));
+
+ s.buf = nvhost_debug_dump_buff;
+ s.size = sizeof(nvhost_debug_dump_buff);
+ s.private = debug_master;
+
+ nvhost_debug_show(&s, NULL);
+
+ i = 0;
+ while (i < s.count ) {
+ if ((s.count - i) > 256) {
+ c = s.buf[i + 256];
+ s.buf[i + 256] = 0;
+ printk("%s", s.buf + i);
+ s.buf[i + 256] = c;
+ } else {
+ printk("%s", s.buf + i);
+ }
+ i += 256;
+ }
+}
+
diff --git a/drivers/video/tegra/host/dev.h b/drivers/video/tegra/host/dev.h
index ae9847c2bd74..4f71ff5d9a9d 100644
--- a/drivers/video/tegra/host/dev.h
+++ b/drivers/video/tegra/host/dev.h
@@ -48,5 +48,6 @@ struct nvhost_master {
};
void nvhost_debug_init(struct nvhost_master *master);
+void nvhost_debug_dump(void);
#endif
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 361a74a6a7cf..c2152287506f 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -28,6 +28,8 @@
#include <mach/powergate.h>
#include <mach/clk.h>
+#include "dev.h"
+
#define ACM_TIMEOUT 1*HZ
#define DISABLE_3D_POWERGATING
@@ -218,10 +220,16 @@ static void debug_not_idle(struct nvhost_module *mod)
void nvhost_module_suspend(struct nvhost_module *mod, bool system_suspend)
{
+ int ret;
+
if (system_suspend && (!is_module_idle(mod)))
debug_not_idle(mod);
- wait_event(mod->idle, is_module_idle(mod));
+ ret = wait_event_timeout(mod->idle, is_module_idle(mod),
+ ACM_TIMEOUT + msecs_to_jiffies(500));
+ if (ret == 0)
+ nvhost_debug_dump();
+
if (system_suspend)
printk("tegra_grhost: entered idle\n");
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 674b34ab6f45..2cea073499b7 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -48,6 +48,13 @@
#define NVMAP_NUM_PTES 64
#define NVMAP_CARVEOUT_KILLER_RETRY_TIME 100 /* msecs */
+#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
+static bool carveout_killer = true;
+#else
+static bool carveout_killer;
+#endif
+module_param(carveout_killer, bool, 0640);
+
struct nvmap_carveout_node {
unsigned int heap_bit;
struct nvmap_heap *carveout;
@@ -324,8 +331,8 @@ static struct nvmap_client* get_client_from_carveout_commit(
carveout_commit);
}
-#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
static DECLARE_WAIT_QUEUE_HEAD(wait_reclaim);
+static int wait_count;
bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
{
struct nvmap_carveout_commit *commit;
@@ -359,6 +366,9 @@ bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
sig = task->signal;
if (!task->mm || !sig)
goto end;
+ /* don't try to kill current */
+ if (task == current->group_leader)
+ goto end;
/* don't try to kill higher priority tasks */
if (sig->oom_adj < current_oom_adj)
goto end;
@@ -374,22 +384,22 @@ end:
task_unlock(task);
}
if (selected_task) {
- wait = selected_task != current;
+ wait = true;
if (fatal_signal_pending(selected_task)) {
pr_warning("carveout_killer: process %d dying "
"slowly\n", selected_task->pid);
goto out;
}
pr_info("carveout_killer: killing process %d with oom_adj %d "
- "to reclaim %d\n", selected_task->pid, selected_oom_adj,
- selected_size);
+ "to reclaim %d (for process with oom_adj %d)\n",
+ selected_task->pid, selected_oom_adj,
+ selected_size, current_oom_adj);
force_sig(SIGKILL, selected_task);
}
out:
spin_unlock_irqrestore(&node->clients_lock, flags);
return wait;
}
-#endif
struct nvmap_heap_block *do_nvmap_carveout_alloc(struct nvmap_client *client,
size_t len, size_t align,
@@ -422,63 +432,75 @@ struct nvmap_heap_block *do_nvmap_carveout_alloc(struct nvmap_client *client,
return NULL;
}
+static bool nvmap_carveout_freed(int count)
+{
+ smp_rmb();
+ return count != wait_count;
+}
+
struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
size_t len, size_t align,
unsigned long usage,
unsigned int prot)
{
struct nvmap_heap_block *block;
-#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
struct nvmap_carveout_node *co_heap;
struct nvmap_device *dev = client->dev;
int i;
unsigned long end = jiffies +
msecs_to_jiffies(NVMAP_CARVEOUT_KILLER_RETRY_TIME);
int count = 0;
- DEFINE_WAIT(wait);
do {
- block = do_nvmap_carveout_alloc(client, len, align, usage,
- prot);
+ block = do_nvmap_carveout_alloc(client, len, align,
+ usage, prot);
+ if (!carveout_killer)
+ return block;
+
if (block)
return block;
- if (!count++)
- printk("%s: failed to allocate %u bytes, "
- "firing carveout killer!\n", __func__, len);
- else
- printk("%s: still can't allocate %u bytes, "
- "attempt %d!\n", __func__, len, count);
+ if (!count++) {
+ char task_comm[TASK_COMM_LEN];
+ if (client->task)
+ get_task_comm(task_comm, client->task);
+ else
+ task_comm[0] = 0;
+ pr_info("%s: failed to allocate %u bytes for "
+ "process %s, firing carveout "
+ "killer!\n", __func__, len, task_comm);
+
+ } else {
+ pr_info("%s: still can't allocate %u bytes, "
+ "attempt %d!\n", __func__, len, count);
+ }
/* shrink carveouts that matter and try again */
for (i = 0; i < dev->nr_carveouts; i++) {
+ int count;
co_heap = &dev->heaps[i];
if (!(co_heap->heap_bit & usage))
continue;
- /* indicates we just delivered a sigkill to current,
- or didn't find anything to kill might as well stop
- trying */
+ count = wait_count;
+ /* indicates we didn't find anything to kill,
+ might as well stop trying */
if (!nvmap_shrink_carveout(co_heap))
return NULL;
- prepare_to_wait(&wait_reclaim, &wait,
- TASK_INTERRUPTIBLE);
- schedule_timeout(end - jiffies);
- finish_wait(&wait_reclaim, &wait);
+ if (time_is_after_jiffies(end))
+ wait_event_interruptible_timeout(wait_reclaim,
+ nvmap_carveout_freed(count),
+ end - jiffies);
}
} while (time_is_after_jiffies(end));
if (time_is_before_jiffies(end))
- printk("carveout_killer: timeout expired without allocation "
- "succeeding.\n");
+ pr_info("carveout_killer: timeout expired without "
+ "allocation succeeding.\n");
return NULL;
-#else
- block = do_nvmap_carveout_alloc(client, len, align, usage, prot);
- return block;
-#endif
}
/* remove a handle from the device's tree of all handles; called
@@ -588,17 +610,17 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
client->carveout_commit[i].commit = 0;
}
- get_task_struct(current);
- task_lock(current);
+ get_task_struct(current->group_leader);
+ task_lock(current->group_leader);
/* don't bother to store task struct for kernel threads,
they can't be killed anyway */
if (current->flags & PF_KTHREAD) {
- put_task_struct(current);
+ put_task_struct(current->group_leader);
task = NULL;
} else {
- task = current;
+ task = current->group_leader;
}
- task_unlock(current);
+ task_unlock(current->group_leader);
client->task = task;
spin_lock_init(&client->ref_lock);
@@ -641,9 +663,11 @@ static void destroy_client(struct nvmap_client *client)
kfree(ref);
}
-#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
- wake_up_all(&wait_reclaim);
-#endif
+ if (carveout_killer) {
+ wait_count++;
+ smp_wmb();
+ wake_up_all(&wait_reclaim);
+ }
for (i = 0; i < client->dev->nr_carveouts; i++)
list_del(&client->carveout_commit[i].list);
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index d7ad6238d4f3..d11b99816ca6 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -40,17 +40,17 @@
#define MAX_WDT_PERIOD 1000
#define TIMER_PTV 0x0
- #define TIMER_EN (1 << 31)
- #define TIMER_PERIODIC (1 << 30)
+#define TIMER_EN (1 << 31)
+#define TIMER_PERIODIC (1 << 30)
#define TIMER_PCR 0x4
- #define TIMER_PCR_INTR (1 << 30)
+#define TIMER_PCR_INTR (1 << 30)
#define WDT_EN (1 << 5)
#define WDT_SEL_TMR1 (0 << 4)
#define WDT_SYS_RST (1 << 2)
-static int heartbeat = 30;
+static int heartbeat = 30; /* must be greater than MIN_WDT_PERIOD and lower than MAX_WDT_PERIOD */
struct tegra_wdt {
struct miscdevice miscdev;
@@ -67,31 +67,13 @@ struct tegra_wdt {
static struct tegra_wdt *tegra_wdt_dev;
-static void tegra_wdt_set_timeout(struct tegra_wdt *wdt, int sec)
-{
- u32 ptv, src;
-
- ptv = readl(wdt->wdt_timer + TIMER_PTV);
- src = readl(wdt->wdt_source);
-
- writel(0, wdt->wdt_source);
- wdt->timeout = clamp(sec, MIN_WDT_PERIOD, MAX_WDT_PERIOD);
- if (ptv & TIMER_EN) {
- /* since the watchdog reset occurs when a second interrupt
- * is asserted before the first is processed, program the
- * timer period to one-half of the watchdog period */
- ptv = wdt->timeout * 1000000ul / 2;
- ptv |= (TIMER_EN | TIMER_PERIODIC);
- writel(ptv, wdt->wdt_timer + TIMER_PTV);
- }
- writel(src, wdt->wdt_source);
-}
-
-
static void tegra_wdt_enable(struct tegra_wdt *wdt)
{
u32 val;
+ /* since the watchdog reset occurs when a second interrupt
+ * is asserted before the first is processed, program the
+ * timer period to one-half of the watchdog period */
val = wdt->timeout * 1000000ul / 2;
val |= (TIMER_EN | TIMER_PERIODIC);
writel(val, wdt->wdt_timer + TIMER_PTV);
@@ -133,7 +115,7 @@ static int tegra_wdt_open(struct inode *inode, struct file *file)
return -EBUSY;
wdt->enabled = true;
- tegra_wdt_set_timeout(wdt, heartbeat);
+ wdt->timeout = heartbeat;
tegra_wdt_enable(wdt);
file->private_data = wdt;
return nonseekable_open(inode, file);
@@ -179,7 +161,7 @@ static long tegra_wdt_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
spin_lock(&lock);
tegra_wdt_disable(wdt);
- tegra_wdt_set_timeout(wdt, new_timeout);
+ wdt->timeout = clamp(new_timeout, MIN_WDT_PERIOD, MAX_WDT_PERIOD);
tegra_wdt_enable(wdt);
spin_unlock(&lock);
case WDIOC_GETTIMEOUT:
@@ -268,6 +250,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "last reset due to watchdog timeout\n");
tegra_wdt_disable(wdt);
+ writel(TIMER_PCR_INTR, wdt->wdt_timer + TIMER_PCR);
ret = request_irq(res_irq->start, tegra_wdt_interrupt, IRQF_DISABLED,
dev_name(&pdev->dev), wdt);
@@ -280,8 +263,6 @@ static int tegra_wdt_probe(struct platform_device *pdev)
wdt->res_src = res_src;
wdt->res_wdt = res_wdt;
- wdt->timeout = heartbeat;
-
ret = register_reboot_notifier(&wdt->notifier);
if (ret) {
dev_err(&pdev->dev, "cannot register reboot notifier\n");
@@ -298,6 +279,8 @@ static int tegra_wdt_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, wdt);
tegra_wdt_dev = wdt;
#ifdef CONFIG_TEGRA_WATCHDOG_ENABLE_ON_PROBE
+ wdt->enabled = true;
+ wdt->timeout = heartbeat;
tegra_wdt_enable(wdt);
#endif
return 0;
@@ -334,6 +317,7 @@ static int tegra_wdt_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM
static int tegra_wdt_suspend(struct platform_device *pdev, pm_message_t state)
{
struct tegra_wdt *wdt = platform_get_drvdata(pdev);
@@ -351,12 +335,15 @@ static int tegra_wdt_resume(struct platform_device *pdev)
return 0;
}
+#endif
static struct platform_driver tegra_wdt_driver = {
.probe = tegra_wdt_probe,
.remove = __devexit_p(tegra_wdt_remove),
+#ifdef CONFIG_PM
.suspend = tegra_wdt_suspend,
.resume = tegra_wdt_resume,
+#endif
.driver = {
.owner = THIS_MODULE,
.name = "tegra_wdt",