summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorNitin Kumbhar <nkumbhar@nvidia.com>2011-01-18 14:52:31 +0530
committerNitin Kumbhar <nkumbhar@nvidia.com>2011-01-18 14:52:31 +0530
commit754deb500cac53edcff2165ca4edb8c8be896d2c (patch)
tree71356f7bf39e87b5d261ab69c159cb8a114831eb /drivers
parent66e0ed154cfb916b83e3f0074f7cd197effaab39 (diff)
parent5edc1199f320e0d9226fe8b73711c6a171ce78de (diff)
merging android-tegra-2.6.36 into git-master/linux-2.6/android-tegra-2.6.36
Conflicts: drivers/net/wireless/bcm4329/Makefile Change-Id: I31ce81e09c6f18d6966a5cffebc533453bce02d8
Diffstat (limited to 'drivers')
-rw-r--r--drivers/crypto/tegra-aes.c92
-rw-r--r--drivers/net/wireless/bcm4329/Makefile2
-rw-r--r--drivers/net/wireless/bcm4329/dhd_sdio.c60
-rw-r--r--drivers/net/wireless/bcm4329/include/epivers.h10
-rwxr-xr-xdrivers/rtc/alarm.c11
-rw-r--r--drivers/usb/gadget/f_mtp.c6
-rw-r--r--drivers/video/tegra/Kconfig9
-rw-r--r--drivers/video/tegra/dc/dc.c70
-rw-r--r--drivers/video/tegra/dc/dc_priv.h3
-rw-r--r--drivers/video/tegra/fb.c44
-rw-r--r--drivers/video/tegra/host/nvhost_acm.c20
-rw-r--r--drivers/video/tegra/host/nvhost_acm.h2
-rw-r--r--drivers/video/tegra/nvmap/nvmap_dev.c160
-rw-r--r--drivers/watchdog/Kconfig6
-rw-r--r--drivers/watchdog/tegra_wdt.c10
15 files changed, 375 insertions, 130 deletions
diff --git a/drivers/crypto/tegra-aes.c b/drivers/crypto/tegra-aes.c
index d94046a4bb95..f7dd72964f0c 100644
--- a/drivers/crypto/tegra-aes.c
+++ b/drivers/crypto/tegra-aes.c
@@ -32,7 +32,6 @@
#include <linux/mutex.h>
#include <linux/interrupt.h>
#include <linux/completion.h>
-#include <linux/delay.h>
#include <linux/workqueue.h>
#include <mach/arb_sema.h>
@@ -198,7 +197,8 @@ static DEFINE_SPINLOCK(list_lock);
static DEFINE_MUTEX(aes_lock);
static void aes_workqueue_handler(struct work_struct *work);
-static DECLARE_WORK(aes_wq, aes_workqueue_handler);
+static DECLARE_WORK(aes_work, aes_workqueue_handler);
+static struct workqueue_struct *aes_wq;
extern unsigned long long tegra_chip_uid(void);
@@ -222,11 +222,6 @@ static int aes_hw_init(struct tegra_aes_dev *dd)
return ret;
}
- tegra_periph_reset_assert(dd->iclk);
- udelay(50);
- tegra_periph_reset_deassert(dd->iclk);
- udelay(50);
-
ret = clk_enable(dd->iclk);
if (ret < 0) {
dev_err(dd->dev, "%s: iclock enable fail(%d)\n", __func__, ret);
@@ -234,10 +229,24 @@ static int aes_hw_init(struct tegra_aes_dev *dd)
return ret;
}
+ ret = clk_set_rate(dd->iclk, 240000000);
+ if (ret) {
+ dev_err(dd->dev, "%s: iclk set_rate fail(%d)\n", __func__, ret);
+ clk_disable(dd->iclk);
+ clk_disable(dd->pclk);
+ return ret;
+ }
+
aes_writel(dd, 0x33, INT_ENB);
return ret;
}
+static void aes_hw_deinit(struct tegra_aes_dev *dd)
+{
+ clk_disable(dd->iclk);
+ clk_disable(dd->pclk);
+}
+
static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
int nblocks, int mode, bool upd_iv)
{
@@ -245,12 +254,6 @@ static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
int qlen = 0, i, eng_busy, icq_empty, dma_busy, ret = 0;
u32 value;
- ret = aes_hw_init(dd);
- if (ret < 0) {
- dev_err(dd->dev, "%s: hw init fail(%d)\n", __func__, ret);
- return ret;
- }
-
cmdq[qlen++] = UCQOPCODE_DMASETUP << ICQBITSHIFT_OPCODE;
cmdq[qlen++] = in_addr;
cmdq[qlen++] = UCQOPCODE_BLKSTARTENGINE << ICQBITSHIFT_OPCODE |
@@ -314,6 +317,7 @@ static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
aes_writel(dd, value, SECURE_INPUT_SELECT);
aes_writel(dd, out_addr, SECURE_DEST_ADDR);
+ INIT_COMPLETION(dd->op_complete);
for (i = 0; i < qlen - 1; i++) {
do {
@@ -325,13 +329,10 @@ static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
aes_writel(dd, cmdq[i], ICMDQUE_WR);
}
- INIT_COMPLETION(dd->op_complete);
ret = wait_for_completion_timeout(&dd->op_complete, msecs_to_jiffies(150));
if (ret == 0) {
dev_err(dd->dev, "timed out (0x%x)\n",
aes_readl(dd, INTR_STATUS));
- clk_disable(dd->iclk);
- clk_disable(dd->pclk);
return -ETIMEDOUT;
}
@@ -343,8 +344,6 @@ static int aes_start_crypt(struct tegra_aes_dev *dd, u32 in_addr, u32 out_addr,
dma_busy = value & (0x1<<23);
} while (eng_busy & (!icq_empty) & dma_busy);
- clk_disable(dd->iclk);
- clk_disable(dd->pclk);
return 0;
}
@@ -379,7 +378,7 @@ static int aes_set_key(struct tegra_aes_dev *dd)
{
u32 value, cmdq[2];
struct tegra_aes_ctx *ctx = dd->ctx;
- int i, eng_busy, icq_empty, dma_busy, ret = 0;
+ int i, eng_busy, icq_empty, dma_busy;
bool use_ssk = false;
if (!ctx) {
@@ -394,12 +393,6 @@ static int aes_set_key(struct tegra_aes_dev *dd)
use_ssk = true;
}
- ret = aes_hw_init(dd);
- if (ret < 0) {
- dev_err(dd->dev, "%s: hw init fail(%d)\n", __func__, ret);
- return ret;
- }
-
/* disable key read from hw */
value = aes_readl(dd, SECURE_SEC_SEL0+(ctx->slot->slot_num*4));
value &= ~SECURE_SEL0_KEYREAD_ENB0_FIELD;
@@ -451,8 +444,6 @@ static int aes_set_key(struct tegra_aes_dev *dd)
} while (eng_busy & (!icq_empty));
out:
- clk_disable(dd->iclk);
- clk_disable(dd->pclk);
return 0;
}
@@ -536,6 +527,12 @@ static int tegra_aes_handle_req(struct tegra_aes_dev *dd)
return -EBUSY;
}
+ ret = aes_hw_init(dd);
+ if (ret < 0) {
+ dev_err(dd->dev, "%s: hw init fail(%d)\n", __func__, ret);
+ goto fail;
+ }
+
aes_set_key(dd);
/* set iv to the aes hw slot */
@@ -599,6 +596,9 @@ static int tegra_aes_handle_req(struct tegra_aes_dev *dd)
}
out:
+ aes_hw_deinit(dd);
+
+fail:
/* release the hardware semaphore */
tegra_arb_mutex_unlock(dd->res_id);
@@ -703,7 +703,7 @@ static int tegra_aes_crypt(struct ablkcipher_request *req, unsigned long mode)
spin_unlock_irqrestore(&dd->lock, flags);
if (!busy)
- schedule_work(&aes_wq);
+ queue_work(aes_wq, &aes_work);
return err;
}
@@ -746,6 +746,13 @@ static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
return -EBUSY;
}
+ ret = aes_hw_init(dd);
+ if (ret < 0) {
+ dev_err(dd->dev, "%s: hw init fail(%d)\n", __func__, ret);
+ dlen = ret;
+ goto fail;
+ }
+
ctx->dd = dd;
dd->ctx = ctx;
dd->flags = FLAGS_ENCRYPT | FLAGS_RNG;
@@ -770,6 +777,9 @@ static int tegra_aes_get_random(struct crypto_rng *tfm, u8 *rdata,
}
out:
+ aes_hw_deinit(dd);
+
+fail:
/* release the hardware semaphore */
tegra_arb_mutex_unlock(dd->res_id);
mutex_unlock(&aes_lock);
@@ -835,6 +845,12 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
return -EBUSY;
}
+ ret = aes_hw_init(dd);
+ if (ret < 0) {
+ dev_err(dd->dev, "%s: hw init fail(%d)\n", __func__, ret);
+ goto fail;
+ }
+
aes_set_key(dd);
/* set seed to the aes hw slot */
@@ -862,6 +878,9 @@ static int tegra_aes_rng_reset(struct crypto_rng *tfm, u8 *seed,
memcpy(dd->dt, dt, DEFAULT_RNG_BLK_SZ);
out:
+ aes_hw_deinit(dd);
+
+fail:
/* release the hardware semaphore */
tegra_arb_mutex_unlock(dd->res_id);
mutex_unlock(&aes_lock);
@@ -879,7 +898,7 @@ static int tegra_aes_cra_init(struct crypto_tfm *tfm)
static struct crypto_alg algs[] = {
{
- .cra_name = "ecb(aes)",
+ .cra_name = "disabled_ecb(aes)",
.cra_driver_name = "ecb-aes-tegra",
.cra_priority = 100,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
@@ -897,7 +916,7 @@ static struct crypto_alg algs[] = {
.decrypt = tegra_aes_ecb_decrypt,
},
}, {
- .cra_name = "cbc(aes)",
+ .cra_name = "disabled_cbc(aes)",
.cra_driver_name = "cbc-aes-tegra",
.cra_priority = 100,
.cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
@@ -916,7 +935,7 @@ static struct crypto_alg algs[] = {
.decrypt = tegra_aes_cbc_decrypt,
}
}, {
- .cra_name = "ansi_cprng",
+ .cra_name = "disabled_ansi_cprng",
.cra_driver_name = "rng-aes-tegra",
.cra_priority = 100,
.cra_flags = CRYPTO_ALG_TYPE_RNG,
@@ -1024,6 +1043,11 @@ static int tegra_aes_probe(struct platform_device *pdev)
}
init_completion(&dd->op_complete);
+ aes_wq = alloc_workqueue("aes_wq", WQ_HIGHPRI, 16);
+ if (!aes_wq) {
+ dev_err(dev, "alloc_workqueue failed\n");
+ goto out;
+ }
/* get the irq */
err = request_irq(INT_VDE_BSE_V, aes_irq, IRQF_TRIGGER_HIGH,
@@ -1072,7 +1096,8 @@ out:
clk_put(dd->iclk);
if (dd->pclk)
clk_put(dd->pclk);
-
+ if (aes_wq)
+ destroy_workqueue(aes_wq);
free_irq(INT_VDE_BSE_V, dd);
spin_lock(&list_lock);
list_del(&dev_list);
@@ -1094,7 +1119,8 @@ static int __devexit tegra_aes_remove(struct platform_device *pdev)
if (!dd)
return -ENODEV;
- cancel_work_sync(&aes_wq);
+ cancel_work_sync(&aes_work);
+ destroy_workqueue(aes_wq);
free_irq(INT_VDE_BSE_V, dd);
spin_lock(&list_lock);
list_del(&dev_list);
diff --git a/drivers/net/wireless/bcm4329/Makefile b/drivers/net/wireless/bcm4329/Makefile
index 20bdab258433..bffe59160c54 100644
--- a/drivers/net/wireless/bcm4329/Makefile
+++ b/drivers/net/wireless/bcm4329/Makefile
@@ -6,7 +6,7 @@ DHDCFLAGS = -DLINUX -DBCMDRIVER -DBCMDONGLEHOST -DDHDTHREAD -DBCMWPA2 \
-Wall -Wstrict-prototypes -Werror -DCUSTOMER_HW2 -DMMC_SDIO_ABORT \
-DDHD_DEBUG_TRAP -DSOFTAP -DEMBEDDED_PLATFORM -DARP_OFFLOAD_SUPPORT \
-DPKT_FILTER_SUPPORT -DSET_RANDOM_MAC_SOFTAP -DCSCAN \
- -DKEEP_ALIVE -DCONFIG_US_NON_DFS_CHANNELS_ONLY \
+ -DKEEP_ALIVE \
-Idrivers/net/wireless/bcm4329 -Idrivers/net/wireless/bcm4329/include
ifeq ($(CONFIG_BCM4329_WIFI_CONTROL_FUNC),y)
diff --git a/drivers/net/wireless/bcm4329/dhd_sdio.c b/drivers/net/wireless/bcm4329/dhd_sdio.c
index 8915857cf2c8..1742deaf74b0 100644
--- a/drivers/net/wireless/bcm4329/dhd_sdio.c
+++ b/drivers/net/wireless/bcm4329/dhd_sdio.c
@@ -430,7 +430,6 @@ static void dhdsdio_sdtest_set(dhd_bus_t *bus, bool start);
#ifdef DHD_DEBUG_TRAP
static int dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size);
-static int dhdsdio_mem_dump(dhd_bus_t *bus);
#endif /* DHD_DEBUG_TRAP */
static int dhdsdio_download_state(dhd_bus_t *bus, bool enter);
@@ -1847,11 +1846,6 @@ dhdsdio_checkdied(dhd_bus_t *bus, uint8 *data, uint size)
DHD_ERROR(("%s: %s\n", __FUNCTION__, strbuf.origbuf));
}
- if (sdpcm_shared.flags & SDPCM_SHARED_TRAP) {
- /* Mem dump to a file on device */
- dhdsdio_mem_dump(bus);
- }
-
done:
if (mbuffer)
MFREE(bus->dhd->osh, mbuffer, msize);
@@ -1860,60 +1854,6 @@ done:
return bcmerror;
}
-
-static int
-dhdsdio_mem_dump(dhd_bus_t *bus)
-{
- int ret = 0;
- int size; /* Full mem size */
- int start = 0; /* Start address */
- int read_size = 0; /* Read size of each iteration */
- uint8 *buf = NULL, *databuf = NULL;
-
- /* Get full mem size */
- size = bus->ramsize;
- buf = MALLOC(bus->dhd->osh, size);
- if (!buf) {
- printf("%s: Out of memory (%d bytes)\n", __FUNCTION__, size);
- return -1;
- }
-
- /* Read mem content */
- printf("Dump dongle memory");
- databuf = buf;
- while (size)
- {
- read_size = MIN(MEMBLOCK, size);
- if ((ret = dhdsdio_membytes(bus, FALSE, start, databuf, read_size)))
- {
- printf("%s: Error membytes %d\n", __FUNCTION__, ret);
- if (buf) {
- MFREE(bus->dhd->osh, buf, size);
- }
- return -1;
- }
- printf(".");
-
- /* Decrement size and increment start address */
- size -= read_size;
- start += read_size;
- databuf += read_size;
- }
- printf("Done\n");
-
-#ifdef DHD_DEBUG
- /* free buf before return !!! */
- if (write_to_file(bus->dhd, buf, bus->ramsize))
- {
- printf("%s: Error writing to files\n", __FUNCTION__);
- return -1;
- }
- /* buf free handled in write_to_file, not here */
-#else
- MFREE(bus->dhd->osh, buf, size);
-#endif
- return 0;
-}
#endif /* DHD_DEBUG_TRAP */
#ifdef DHD_DEBUG
diff --git a/drivers/net/wireless/bcm4329/include/epivers.h b/drivers/net/wireless/bcm4329/include/epivers.h
index 23ee514a7b6b..00e3cac14dc5 100644
--- a/drivers/net/wireless/bcm4329/include/epivers.h
+++ b/drivers/net/wireless/bcm4329/include/epivers.h
@@ -33,16 +33,16 @@
#define EPI_RC_NUMBER 248
-#define EPI_INCREMENTAL_NUMBER 18
+#define EPI_INCREMENTAL_NUMBER 20
#define EPI_BUILD_NUMBER 0
-#define EPI_VERSION 4, 218, 248, 18
+#define EPI_VERSION 4, 218, 248, 20
-#define EPI_VERSION_NUM 0x04daf812
+#define EPI_VERSION_NUM 0x04daf814
-#define EPI_VERSION_STR "4.218.248.18"
-#define EPI_ROUTER_VERSION_STR "4.219.248.18"
+#define EPI_VERSION_STR "4.218.248.20"
+#define EPI_ROUTER_VERSION_STR "4.219.248.20"
#endif
diff --git a/drivers/rtc/alarm.c b/drivers/rtc/alarm.c
index 45be9101a1d8..abefa27a6745 100755
--- a/drivers/rtc/alarm.c
+++ b/drivers/rtc/alarm.c
@@ -109,12 +109,15 @@ static void alarm_enqueue_locked(struct alarm *alarm)
struct rb_node *parent = NULL;
struct alarm *entry;
int leftmost = 1;
+ bool was_first = false;
pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
- if (base->first == &alarm->node)
+ if (base->first == &alarm->node) {
base->first = rb_next(&alarm->node);
+ was_first = true;
+ }
if (!RB_EMPTY_NODE(&alarm->node)) {
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
@@ -134,10 +137,10 @@ static void alarm_enqueue_locked(struct alarm *alarm)
leftmost = 0;
}
}
- if (leftmost) {
+ if (leftmost)
base->first = &alarm->node;
- update_timer_locked(base, false);
- }
+ if (leftmost || was_first)
+ update_timer_locked(base, was_first);
rb_link_node(&alarm->node, parent, link);
rb_insert_color(&alarm->node, &base->alarms);
diff --git a/drivers/usb/gadget/f_mtp.c b/drivers/usb/gadget/f_mtp.c
index 64fe3b3cd9e6..e07224fd9f89 100644
--- a/drivers/usb/gadget/f_mtp.c
+++ b/drivers/usb/gadget/f_mtp.c
@@ -756,8 +756,10 @@ static void receive_file_work(struct work_struct *data)
/* wait for our last read to complete */
ret = wait_event_interruptible(dev->read_wq,
dev->rx_done || dev->state != STATE_BUSY);
- if (ret < 0 || dev->state != STATE_BUSY) {
- r = ret;
+ if (dev->state == STATE_CANCELED) {
+ r = -ECANCELED;
+ if (!dev->rx_done)
+ usb_ep_dequeue(dev->ep_out, read_req);
break;
}
/* if xfer_file_length is 0xFFFFFFFF, then we read until
diff --git a/drivers/video/tegra/Kconfig b/drivers/video/tegra/Kconfig
index 2b8160877688..c431cc670a46 100644
--- a/drivers/video/tegra/Kconfig
+++ b/drivers/video/tegra/Kconfig
@@ -61,5 +61,14 @@ config NVMAP_HIGHMEM_ONLY
Say Y here to restrict nvmap system memory allocations (both
physical system memory and IOVMM) to just HIGHMEM pages.
+config NVMAP_CARVEOUT_KILLER
+ bool "Reclaim nvmap carveout by killing processes"
+ depends on TEGRA_NVMAP
+ default n
+ help
+ Say Y here to allow the system to reclaim carveout space by killing
+ processes. This will kill the largest consumers of lowest priority
+ first.
+
endif
diff --git a/drivers/video/tegra/dc/dc.c b/drivers/video/tegra/dc/dc.c
index 1777de0f0215..9c8fac2b7149 100644
--- a/drivers/video/tegra/dc/dc.c
+++ b/drivers/video/tegra/dc/dc.c
@@ -886,6 +886,7 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
struct tegra_dc *dc = ptr;
unsigned long status;
unsigned long val;
+ unsigned long underflow_mask;
int i;
status = tegra_dc_readl(dc, DC_CMD_INT_STATUS);
@@ -915,6 +916,45 @@ static irqreturn_t tegra_dc_irq(int irq, void *ptr)
wake_up(&dc->wq);
}
+
+ /*
+ * Overlays can get thier internal state corrupted during and underflow
+ * condition. The only way to fix this state is to reset the DC.
+ * if we get 4 consecutive frames with underflows, assume we're
+ * hosed and reset.
+ */
+ underflow_mask = status & (WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT);
+ if (underflow_mask) {
+ val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+ val |= V_BLANK_INT;
+ tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+ dc->underflow_mask |= underflow_mask;
+ }
+
+ if (status & V_BLANK_INT) {
+ int i;
+
+ for (i = 0; i< DC_N_WINDOWS; i++) {
+ if (dc->underflow_mask & (WIN_A_UF_INT <<i)) {
+ dc->windows[i].underflows++;
+
+ if (dc->windows[i].underflows > 4)
+ schedule_work(&dc->reset_work);
+ } else {
+ dc->windows[i].underflows = 0;
+ }
+ }
+
+ if (!dc->underflow_mask) {
+ val = tegra_dc_readl(dc, DC_CMD_INT_ENABLE);
+ val &= ~V_BLANK_INT;
+ tegra_dc_writel(dc, val, DC_CMD_INT_ENABLE);
+ }
+
+ dc->underflow_mask = 0;
+ }
+
+
return IRQ_HANDLED;
}
@@ -1005,8 +1045,14 @@ static void tegra_dc_init(struct tegra_dc *dc)
tegra_dc_writel(dc, 0x00202020, DC_DISP_MEM_HIGH_PRIORITY);
tegra_dc_writel(dc, 0x00010101, DC_DISP_MEM_HIGH_PRIORITY_TIMER);
- tegra_dc_writel(dc, 0x00000002, DC_CMD_INT_MASK);
- tegra_dc_writel(dc, 0x00000000, DC_CMD_INT_ENABLE);
+ tegra_dc_writel(dc, (FRAME_END_INT |
+ V_BLANK_INT |
+ WIN_A_UF_INT |
+ WIN_B_UF_INT |
+ WIN_C_UF_INT), DC_CMD_INT_MASK);
+ tegra_dc_writel(dc, (WIN_A_UF_INT |
+ WIN_B_UF_INT |
+ WIN_C_UF_INT), DC_CMD_INT_ENABLE);
tegra_dc_writel(dc, 0x00000000, DC_DISP_BORDER_COLOR);
@@ -1105,6 +1151,25 @@ void tegra_dc_disable(struct tegra_dc *dc)
mutex_unlock(&dc->lock);
}
+static void tegra_dc_reset_worker(struct work_struct *work)
+{
+ struct tegra_dc *dc =
+ container_of(work, struct tegra_dc, reset_work);
+
+ dev_warn(&dc->ndev->dev, "overlay stuck in underflow state. resetting.\n");
+
+ mutex_lock(&dc->lock);
+ _tegra_dc_disable(dc);
+
+ tegra_periph_reset_assert(dc->clk);
+ msleep(10);
+ tegra_periph_reset_deassert(dc->clk);
+
+ _tegra_dc_enable(dc);
+ mutex_unlock(&dc->lock);
+}
+
+
static int tegra_dc_probe(struct nvhost_device *ndev)
{
struct tegra_dc *dc;
@@ -1194,6 +1259,7 @@ static int tegra_dc_probe(struct nvhost_device *ndev)
mutex_init(&dc->lock);
init_waitqueue_head(&dc->wq);
+ INIT_WORK(&dc->reset_work, tegra_dc_reset_worker);
dc->n_windows = DC_N_WINDOWS;
for (i = 0; i < dc->n_windows; i++) {
diff --git a/drivers/video/tegra/dc/dc_priv.h b/drivers/video/tegra/dc/dc_priv.h
index 253d03f057d7..3f7fdbff023b 100644
--- a/drivers/video/tegra/dc/dc_priv.h
+++ b/drivers/video/tegra/dc/dc_priv.h
@@ -84,6 +84,9 @@ struct tegra_dc {
u32 syncpt_id;
u32 syncpt_min;
u32 syncpt_max;
+
+ unsigned long underflow_mask;
+ struct work_struct reset_work;
};
static inline void tegra_dc_io_start(struct tegra_dc *dc)
diff --git a/drivers/video/tegra/fb.c b/drivers/video/tegra/fb.c
index 01eaad925da6..2f51c47a67ab 100644
--- a/drivers/video/tegra/fb.c
+++ b/drivers/video/tegra/fb.c
@@ -89,9 +89,27 @@ static int tegra_fb_open(struct fb_info *info, int user)
static int tegra_fb_release(struct fb_info *info, int user)
{
struct tegra_fb_info *tegra_fb = info->par;
+ struct fb_var_screeninfo *var = &info->var;
flush_workqueue(tegra_fb->flip_wq);
+ if (tegra_fb->win->cur_handle) {
+ nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
+ nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
+
+ tegra_fb->win->cur_handle = NULL;
+
+ tegra_fb->win->x = 0;
+ tegra_fb->win->y = 0;
+ tegra_fb->win->w = var->xres;
+ tegra_fb->win->h = var->yres;
+ tegra_fb->win->out_x = 0;
+ tegra_fb->win->out_y = 0;
+ tegra_fb->win->out_w = var->xres;
+ tegra_fb->win->out_h = var->yres;
+ tegra_fb->win->flags = TEGRA_WIN_FLAG_ENABLED;
+ }
+
if (tegra_fb->user_nvmap) {
nvmap_client_put(tegra_fb->user_nvmap);
tegra_fb->user_nvmap = NULL;
@@ -262,25 +280,21 @@ static int tegra_fb_pan_display(struct fb_var_screeninfo *var,
char __iomem *flush_end;
u32 addr;
- flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
- flush_end = flush_start + (var->yres * info->fix.line_length);
-
- info->var.xoffset = var->xoffset;
- info->var.yoffset = var->yoffset;
+ if (!tegra_fb->win->cur_handle) {
+ flush_start = info->screen_base + (var->yoffset * info->fix.line_length);
+ flush_end = flush_start + (var->yres * info->fix.line_length);
- addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
- (var->xoffset * (var->bits_per_pixel/8));
+ info->var.xoffset = var->xoffset;
+ info->var.yoffset = var->yoffset;
- tegra_fb->win->phys_addr = addr;
- /* TODO: update virt_addr */
+ addr = info->fix.smem_start + (var->yoffset * info->fix.line_length) +
+ (var->xoffset * (var->bits_per_pixel/8));
- tegra_dc_update_windows(&tegra_fb->win, 1);
- tegra_dc_sync_windows(&tegra_fb->win, 1);
+ tegra_fb->win->phys_addr = addr;
+ /* TODO: update virt_addr */
- if (WARN_ON(tegra_fb->win->cur_handle)) {
- nvmap_unpin(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
- nvmap_free(tegra_fb->fb_nvmap, tegra_fb->win->cur_handle);
- tegra_fb->win->cur_handle = NULL;
+ tegra_dc_update_windows(&tegra_fb->win, 1);
+ tegra_dc_sync_windows(&tegra_fb->win, 1);
}
return 0;
diff --git a/drivers/video/tegra/host/nvhost_acm.c b/drivers/video/tegra/host/nvhost_acm.c
index 348d0d36a9a0..361a74a6a7cf 100644
--- a/drivers/video/tegra/host/nvhost_acm.c
+++ b/drivers/video/tegra/host/nvhost_acm.c
@@ -31,6 +31,7 @@
#define ACM_TIMEOUT 1*HZ
#define DISABLE_3D_POWERGATING
+#define DISABLE_MPE_POWERGATING
void nvhost_module_busy(struct nvhost_module *mod)
{
@@ -98,6 +99,12 @@ static const char *get_module_clk_id(const char *module, int index)
{
if (index == 1 && strcmp(module, "gr2d") == 0)
return "epp";
+ else if (index == 2 && strcmp(module, "gr2d") == 0)
+ return "emc";
+ else if (index == 1 && strcmp(module, "gr3d") == 0)
+ return "emc";
+ else if (index == 1 && strcmp(module, "mpe") == 0)
+ return "emc";
else if (index == 0)
return module;
return NULL;
@@ -156,6 +163,19 @@ int nvhost_module_init(struct nvhost_module *mod, const char *name,
}
#endif
+#ifdef DISABLE_MPE_POWERGATING
+ /*
+ * Disable power gating for MPE as it seems to cause issues with
+ * camera record stress tests when run in loop.
+ */
+ if (mod->powergate_id == TEGRA_POWERGATE_MPE) {
+ tegra_powergate_sequence_power_up(mod->powergate_id,
+ mod->clk[0]);
+ clk_disable(mod->clk[0]);
+ mod->powergate_id = -1;
+ }
+#endif
+
mutex_init(&mod->lock);
init_waitqueue_head(&mod->idle);
INIT_DELAYED_WORK(&mod->powerdown, powerdown_handler);
diff --git a/drivers/video/tegra/host/nvhost_acm.h b/drivers/video/tegra/host/nvhost_acm.h
index c765d983afb4..f7e28af8e9cb 100644
--- a/drivers/video/tegra/host/nvhost_acm.h
+++ b/drivers/video/tegra/host/nvhost_acm.h
@@ -28,7 +28,7 @@
#include <linux/mutex.h>
#include <linux/clk.h>
-#define NVHOST_MODULE_MAX_CLOCKS 2
+#define NVHOST_MODULE_MAX_CLOCKS 3
struct nvhost_module;
diff --git a/drivers/video/tegra/nvmap/nvmap_dev.c b/drivers/video/tegra/nvmap/nvmap_dev.c
index 1961c714efe5..674b34ab6f45 100644
--- a/drivers/video/tegra/nvmap/nvmap_dev.c
+++ b/drivers/video/tegra/nvmap/nvmap_dev.c
@@ -23,9 +23,11 @@
#include <linux/backing-dev.h>
#include <linux/bitmap.h>
#include <linux/debugfs.h>
+#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/miscdevice.h>
#include <linux/mm.h>
+#include <linux/oom.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -44,6 +46,7 @@
#include "nvmap_mru.h"
#define NVMAP_NUM_PTES 64
+#define NVMAP_CARVEOUT_KILLER_RETRY_TIME 100 /* msecs */
struct nvmap_carveout_node {
unsigned int heap_bit;
@@ -321,10 +324,77 @@ static struct nvmap_client* get_client_from_carveout_commit(
carveout_commit);
}
-struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
- size_t len, size_t align,
- unsigned long usage,
- unsigned int prot)
+#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
+static DECLARE_WAIT_QUEUE_HEAD(wait_reclaim);
+bool nvmap_shrink_carveout(struct nvmap_carveout_node *node)
+{
+ struct nvmap_carveout_commit *commit;
+ size_t selected_size = 0;
+ int selected_oom_adj = OOM_ADJUST_MIN;
+ struct task_struct *selected_task = NULL;
+ unsigned long flags;
+ bool wait = false;
+ int current_oom_adj = OOM_ADJUST_MIN;
+
+ task_lock(current);
+ if (current->signal)
+ current_oom_adj = current->signal->oom_adj;
+ task_unlock(current);
+
+ spin_lock_irqsave(&node->clients_lock, flags);
+ /* find the task with the smallest oom_adj (lowest priority)
+ * and largest carveout allocation -- ignore kernel allocations,
+ * there's no way to handle them */
+ list_for_each_entry(commit, &node->clients, list) {
+ struct nvmap_client *client =
+ get_client_from_carveout_commit(node, commit);
+ size_t size = commit->commit;
+ struct task_struct *task = client->task;
+ struct signal_struct *sig;
+
+ if (!task)
+ continue;
+
+ task_lock(task);
+ sig = task->signal;
+ if (!task->mm || !sig)
+ goto end;
+ /* don't try to kill higher priority tasks */
+ if (sig->oom_adj < current_oom_adj)
+ goto end;
+ if (sig->oom_adj < selected_oom_adj)
+ goto end;
+ if (sig->oom_adj == selected_oom_adj &&
+ size <= selected_size)
+ goto end;
+ selected_oom_adj = sig->oom_adj;
+ selected_size = size;
+ selected_task = task;
+end:
+ task_unlock(task);
+ }
+ if (selected_task) {
+ wait = selected_task != current;
+ 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);
+ 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,
+ unsigned long usage,
+ unsigned int prot)
{
struct nvmap_carveout_node *co_heap;
struct nvmap_device *dev = client->dev;
@@ -349,8 +419,66 @@ struct nvmap_heap_block *nvmap_carveout_alloc(struct nvmap_client *client,
return block;
}
}
+ return NULL;
+}
+
+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);
+ 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);
+
+ /* shrink carveouts that matter and try again */
+ for (i = 0; i < dev->nr_carveouts; i++) {
+ 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 */
+ 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);
+ }
+ } while (time_is_after_jiffies(end));
+
+ if (time_is_before_jiffies(end))
+ printk("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
@@ -433,6 +561,7 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
const char *name)
{
struct nvmap_client *client;
+ struct task_struct *task;
int i;
if (WARN_ON(!dev))
@@ -460,7 +589,17 @@ struct nvmap_client *nvmap_create_client(struct nvmap_device *dev,
}
get_task_struct(current);
- client->task = current;
+ task_lock(current);
+ /* 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);
+ task = NULL;
+ } else {
+ task = current;
+ }
+ task_unlock(current);
+ client->task = task;
spin_lock_init(&client->ref_lock);
atomic_set(&client->count, 1);
@@ -476,6 +615,7 @@ static void destroy_client(struct nvmap_client *client)
if (!client)
return;
+
while ((n = rb_first(&client->handle_refs))) {
struct nvmap_handle_ref *ref;
int pins, dupes;
@@ -501,6 +641,10 @@ static void destroy_client(struct nvmap_client *client)
kfree(ref);
}
+#ifdef CONFIG_NVMAP_CARVEOUT_KILLER
+ wake_up_all(&wait_reclaim);
+#endif
+
for (i = 0; i < client->dev->nr_carveouts; i++)
list_del(&client->carveout_commit[i].list);
@@ -757,7 +901,11 @@ static struct attribute_group heap_extra_attr_group = {
static void client_stringify(struct nvmap_client *client, struct seq_file *s)
{
- char task_comm[sizeof(client->task->comm)];
+ char task_comm[TASK_COMM_LEN];
+ if (!client->task) {
+ seq_printf(s, "%8s %16s %8u", client->name, "kernel", 0);
+ return;
+ }
get_task_comm(task_comm, client->task);
seq_printf(s, "%8s %16s %8u", client->name, task_comm,
client->task->pid);
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 1addd785739a..f775da5a1be5 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -205,6 +205,12 @@ config TEGRA_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called tegra_wdt.
+config TEGRA_WATCHDOG_ENABLE_ON_PROBE
+ tristate "Tegra watchdog"
+ depends on ARCH_TEGRA && TEGRA_WATCHDOG
+ help
+ Say Y here to enable the tegra watchdog at driver
+ probe time, rather than when the device is opened.
config EP93XX_WATCHDOG
tristate "EP93xx Watchdog"
diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c
index d7a9d7609a1f..d7ad6238d4f3 100644
--- a/drivers/watchdog/tegra_wdt.c
+++ b/drivers/watchdog/tegra_wdt.c
@@ -50,7 +50,7 @@
#define WDT_SEL_TMR1 (0 << 4)
#define WDT_SYS_RST (1 << 2)
-static int heartbeat = 60;
+static int heartbeat = 30;
struct tegra_wdt {
struct miscdevice miscdev;
@@ -208,6 +208,7 @@ static int tegra_wdt_probe(struct platform_device *pdev)
{
struct resource *res_src, *res_wdt, *res_irq;
struct tegra_wdt *wdt;
+ u32 src;
int ret = 0;
if (pdev->id != -1) {
@@ -262,6 +263,10 @@ static int tegra_wdt_probe(struct platform_device *pdev)
goto fail;
}
+ src = readl(wdt->wdt_source);
+ if (src & BIT(12))
+ dev_info(&pdev->dev, "last reset due to watchdog timeout\n");
+
tegra_wdt_disable(wdt);
ret = request_irq(res_irq->start, tegra_wdt_interrupt, IRQF_DISABLED,
@@ -292,6 +297,9 @@ 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
+ tegra_wdt_enable(wdt);
+#endif
return 0;
fail:
if (wdt->irq != -1)