diff options
author | Nitin Kumbhar <nkumbhar@nvidia.com> | 2011-02-04 17:08:18 +0530 |
---|---|---|
committer | Nitin Kumbhar <nkumbhar@nvidia.com> | 2011-02-04 17:08:18 +0530 |
commit | b6b1f33f279fcb1c4a751f981153affa6469e94c (patch) | |
tree | a77ace4c91f29d814982c40bea8c4a172af9ee3e /drivers | |
parent | df4a2fbff8471de3f75d55b93e2bf94dfd26ff7e (diff) | |
parent | a979d00287bcd3297bd13a59534073e6faa570c9 (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.c | 50 | ||||
-rw-r--r-- | drivers/cpufreq/cpufreq_stats.c | 30 | ||||
-rw-r--r-- | drivers/usb/gadget/fsl_tegra_udc.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 2 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc.c | 32 | ||||
-rw-r--r-- | drivers/video/tegra/dc/dc_reg.h | 4 | ||||
-rw-r--r-- | drivers/video/tegra/dc/hdmi.c | 33 | ||||
-rw-r--r-- | drivers/video/tegra/fb.c | 13 | ||||
-rw-r--r-- | drivers/video/tegra/host/debug.c | 76 | ||||
-rw-r--r-- | drivers/video/tegra/host/dev.h | 1 | ||||
-rw-r--r-- | drivers/video/tegra/host/nvhost_acm.c | 10 | ||||
-rw-r--r-- | drivers/video/tegra/nvmap/nvmap_dev.c | 96 | ||||
-rw-r--r-- | drivers/watchdog/tegra_wdt.c | 45 |
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", |