aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Barksdale <amatus@amatus.name>2014-08-13 18:39:02 -0500
committerDavid Barksdale <amatus@amatus.name>2014-08-13 18:39:02 -0500
commit18351c6816244feb6bcb75d2eb22681fd6941b31 (patch)
tree6bcf7f3917d0299abd76f05a3ffdce935f5be224
parentcddfc3baae08e24185c7716434452ebbd404cd39 (diff)
gpl-source-mybooklive-02.11.09-053.zipgpl-source-mybooklive-02.11.09-053.zip
-rw-r--r--arch/powerpc/Kconfig2
-rw-r--r--drivers/usb/gadget/dwc_otg/dwc_otg_hcd.c24
-rw-r--r--drivers/usb/gadget/dwc_otg/dwc_otg_hcd_intr.c8
-rw-r--r--kernel/Kconfig.exit6
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/exit_profile.c162
-rw-r--r--kernel/exit_profile.h7
-rw-r--r--kernel/ksysfs.c5
8 files changed, 211 insertions, 4 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index e1830f35dee..6a226a5c50a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -244,6 +244,8 @@ source "init/Kconfig"
source "kernel/Kconfig.freezer"
+source "kernel/Kconfig.exit"
+
source "arch/powerpc/sysdev/Kconfig"
source "arch/powerpc/platforms/Kconfig"
diff --git a/drivers/usb/gadget/dwc_otg/dwc_otg_hcd.c b/drivers/usb/gadget/dwc_otg/dwc_otg_hcd.c
index 6b83ee46440..2fdf0ca99ea 100644
--- a/drivers/usb/gadget/dwc_otg/dwc_otg_hcd.c
+++ b/drivers/usb/gadget/dwc_otg/dwc_otg_hcd.c
@@ -273,6 +273,7 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *_p)
dwc_hc_t * channel;
dwc_otg_hc_regs_t * hc_regs;
hcchar_data_t hcchar;
+ unsigned long flags;
num_channels = dwc_otg_hcd->core_if->core_params->host_channels;
if (!dwc_otg_hcd->core_if->dma_enable) {
/* Flush out any channel requests in slave mode. */
@@ -303,6 +304,10 @@ static int32_t dwc_otg_hcd_disconnect_cb(void *_p)
dwc_otg_hc_cleanup(dwc_otg_hcd->core_if,channel);
list_add_tail(&channel->hc_list_entry,
&dwc_otg_hcd->free_hc_list);
+ local_irq_save(flags);
+ dwc_otg_hcd->available_host_channels ++;
+ local_irq_restore(flags);
+
}
}
}
@@ -1042,23 +1047,38 @@ void dwc_otg_hcd_endpoint_disable(struct usb_hcd *_hcd,
{
dwc_otg_qh_t * qh;
dwc_otg_hcd_t * dwc_otg_hcd = hcd_to_dwc_otg_hcd(_hcd);
+ unsigned long flags;
+ int retry = 0;
+
DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD EP DISABLE: _bEndpointAddress=0x%02x, "
"endpoint=%d\n", _ep->desc.bEndpointAddress,
dwc_ep_addr_to_endpoint(_ep->desc.bEndpointAddress));
+
+rescan:
+ local_irq_save(flags);
+
qh = (dwc_otg_qh_t *) (_ep->hcpriv);
if (qh != NULL) {
-#ifdef CONFIG_DWC_DEBUG
/** Check that the QTD list is really empty */
if (!list_empty(&qh->qtd_list)) {
+ if (retry++ < 250) {
+ local_irq_restore(flags);
+ schedule_timeout_uninterruptible(1);
+ goto rescan;
+ }
+#ifdef CONFIG_DWC_DEBUG
DWC_WARN("DWC OTG HCD EP DISABLE:"
" QTD List for this endpoint is not empty\n");
+#endif /* */
}
-#endif /* */
dwc_otg_hcd_qh_remove_and_free(dwc_otg_hcd, qh);
_ep->hcpriv = NULL;
}
+
+ local_irq_restore(flags);
+
return;
}
diff --git a/drivers/usb/gadget/dwc_otg/dwc_otg_hcd_intr.c b/drivers/usb/gadget/dwc_otg/dwc_otg_hcd_intr.c
index 153c9a98c4a..595ea57e534 100644
--- a/drivers/usb/gadget/dwc_otg/dwc_otg_hcd_intr.c
+++ b/drivers/usb/gadget/dwc_otg/dwc_otg_hcd_intr.c
@@ -665,6 +665,7 @@ static dwc_otg_halt_status_e update_isoc_urb_state(dwc_otg_hcd_t * _hcd,
frame_desc->status = -EPROTO;
frame_desc->actual_length =
get_actual_xfer_length(_hc, _hc_regs, _qtd, _halt_status,NULL);
+ break;
default:
DWC_ERROR("%s: Unhandled _halt_status (%d)\n", __func__, _halt_status);
BUG();
@@ -752,7 +753,8 @@ static void release_channel(dwc_otg_hcd_t * _hcd,
DWC_ERROR("%s: No halt_status, channel %d\n", __func__,
_hc->hc_num);
#endif
- free_qtd = 0;
+ free_qtd = 1;
+ dwc_otg_hcd_complete_urb(_hcd, _qtd->urb, -EPROTO);
break;
default:
free_qtd = 0;
@@ -1197,6 +1199,7 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * _hcd,
halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_ACK, must_free);
}
} else {
+#if 0
_qtd->error_count = 0;
if (_hc->qh->ping_state) {
_hc->qh->ping_state = 0;
@@ -1212,6 +1215,7 @@ static int32_t handle_hc_ack_intr(dwc_otg_hcd_t * _hcd,
} else {
halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free);
}
+#endif
}
/*
@@ -1638,7 +1642,7 @@ static void handle_hc_chhltd_intr_dma(dwc_otg_hcd_t * _hcd,
__func__, _hc->hc_num, hcint.b.nyet, hcint.d32,
dwc_read_reg32(&_hcd->core_if->core_global_regs->gintsts));
#endif
- halt_channel(_hcd, _hc, _qtd, _hc->halt_status, must_free);
+ halt_channel(_hcd, _hc, _qtd, DWC_OTG_HC_XFER_NO_HALT_STATUS, must_free);
}
}
}
diff --git a/kernel/Kconfig.exit b/kernel/Kconfig.exit
new file mode 100644
index 00000000000..4d631659b59
--- /dev/null
+++ b/kernel/Kconfig.exit
@@ -0,0 +1,6 @@
+config EXIT_PROFILE
+ bool "Add profiling features to process exit"
+ default n
+ depends on PROFILING
+ help
+ Capture information to the system log during process exit.
diff --git a/kernel/Makefile b/kernel/Makefile
index d7c13d249b2..35c459b81ad 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -96,6 +96,7 @@ obj-$(CONFIG_SMP) += sched_cpupri.o
obj-$(CONFIG_SLOW_WORK) += slow-work.o
obj-$(CONFIG_SLOW_WORK_DEBUG) += slow-work-debugfs.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o
+obj-$(CONFIG_EXIT_PROFILE) += exit_profile.o
ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/exit_profile.c b/kernel/exit_profile.c
new file mode 100644
index 00000000000..e260ac222da
--- /dev/null
+++ b/kernel/exit_profile.c
@@ -0,0 +1,162 @@
+/*
+ * @file exit_profile.c
+ *
+ * @remark Copyright (c) 2012 Western Digital Corporation, Inc.
+ */
+
+#include <linux/kobject.h>
+#include <linux/notifier.h>
+#include <linux/profile.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+
+#include "exit_profile.h"
+
+static int exit_profile_enabled = 0;
+
+static unsigned long long boot_time = 0;
+
+
+/*
+ * log the process' statistics
+ */
+static int task_exit_notify(struct notifier_block *self, unsigned long val, void *data)
+{
+ struct task_struct *tsk = data;
+ struct mm_struct *mm;
+
+ unsigned long long start_time, this_time;
+ struct timespec thistime;
+
+ /* see the comment in fs/proc/task_mmu.c */
+ unsigned long hiwater_rss;
+
+ /* somewhat from fs/proc/array.c */
+ char tcomm[sizeof(tsk->comm)];
+
+ pr_debug("%s: called data %p, val %lu\n", __FUNCTION__, data, val);
+
+ if (tsk == NULL) {
+ printk(KERN_WARNING "%s: val %lu; data %p\n", __FUNCTION__,
+ val, data);
+ return 0;
+ }
+ start_time = (unsigned long long)tsk->real_start_time.tv_sec * NSEC_PER_SEC +
+ tsk->real_start_time.tv_nsec;
+ start_time = nsec_to_clock_t(start_time); /* clock_t because there's no jiffies to nsec */
+ thistime = CURRENT_TIME;
+ this_time = (unsigned long long)thistime.tv_sec * NSEC_PER_SEC +
+ thistime.tv_nsec;
+ this_time = nsec_to_clock_t(this_time); /* clock_t because there's no jiffies to nsec */
+ this_time -= boot_time;
+
+ get_task_comm(tcomm, tsk);
+ mm = tsk->mm;
+ if (mm == NULL) {
+ printk(KERN_WARNING "%s: tsk %p; mm %p\n", __FUNCTION__,
+ tsk, mm);
+ return 0;
+ }
+
+ hiwater_rss = get_mm_rss(mm);
+ if (hiwater_rss < mm->hiwater_rss) {
+ hiwater_rss = mm->hiwater_rss;
+ }
+
+ printk(KERN_INFO "%s: Name %16s; VmHWM %8lu kB; start %llu; end %llu", __FUNCTION__,
+ tcomm,
+ hiwater_rss << (PAGE_SHIFT-10),
+ start_time,
+ this_time);
+
+ if (exit_profile_enabled == 1) {
+ printk("\n");
+ } else if (exit_profile_enabled == 2) {
+ printk("; pid %d; ppid %d\n",
+ tsk->pid,
+ (tsk->real_parent == NULL ? 0 : tsk->real_parent->pid));
+
+ if ((tsk->group_leader == NULL) ||
+ (tsk->group_leader->pid == tsk->pid)) {
+ printk("\n");
+ } else {
+ printk("; tgid %d\n", tsk->group_leader->pid);
+ }
+ } else {
+ if (tsk->real_parent != NULL) {
+ get_task_comm(tcomm, tsk->real_parent);
+ }
+ printk("; pid %d; ppid %d (%s)",
+ tsk->pid,
+ (tsk->real_parent == NULL ? 0 : tsk->real_parent->pid),
+ (tsk->real_parent == NULL ? "none" : tcomm));
+
+ if ((tsk->group_leader == NULL) ||
+ (tsk->group_leader->pid == tsk->pid)) {
+ printk("\n");
+ } else {
+ get_task_comm(tcomm, tsk->group_leader);
+ printk("; tgid %d (%s)\n", tsk->group_leader->pid, tcomm);
+ }
+ }
+
+ return 0;
+}
+static struct notifier_block task_exit_nb = {
+ .notifier_call = task_exit_notify,
+};
+
+
+/*
+ * attach through /sys interfaces
+ */
+static ssize_t exit_profile_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%d\n", exit_profile_enabled);
+}
+
+static ssize_t exit_profile_store(struct kobject *kobj,
+ struct kobj_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%du", &value) != 1) {
+ printk(KERN_WARNING "%s: %s is not an integer\n",
+ __FUNCTION__, buf);
+ }
+
+ if (value != exit_profile_enabled) {
+ if (exit_profile_enabled == 0) {
+ int err;
+ struct timespec boottime;
+
+ /* do this once for all subsequent uses */
+ getboottime(&boottime);
+ boot_time = (unsigned long long)boottime.tv_sec * NSEC_PER_SEC +
+ boottime.tv_nsec;
+ boot_time = nsec_to_clock_t(boot_time); /* clock_t because there's no jiffies to nsec */
+ pr_debug("%s: boot time %llu\n", __FUNCTION__, boot_time);
+
+ err = profile_event_register(PROFILE_TASK_EXIT, &task_exit_nb);
+ if (err) {
+ printk(KERN_WARNING "%s: failed to register task exit notify (%d)\n",
+ __FUNCTION__, err);
+ } else {
+ exit_profile_enabled = value;
+ }
+ } else if (value == 0) {
+ profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb);
+ exit_profile_enabled = 0;
+ } else { /* just update the value to change the information set */
+ exit_profile_enabled = value;
+ }
+ }
+
+ return count;
+}
+struct kobj_attribute exit_profile_attr =
+ __ATTR(exit_profile, 0666, exit_profile_show, exit_profile_store);
+/* EXPORT_SYMBOL_GPL(exit_profile_attr); */
diff --git a/kernel/exit_profile.h b/kernel/exit_profile.h
new file mode 100644
index 00000000000..59e663b324b
--- /dev/null
+++ b/kernel/exit_profile.h
@@ -0,0 +1,7 @@
+/*
+ * @file exit_profile.c
+ *
+ * @remark Copyright (c) 2012 Western Digital Corporation, Inc.
+ */
+
+extern struct kobj_attribute exit_profile_attr;
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 528dd78e7e7..656d28dc6bb 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -17,6 +17,8 @@
#include <linux/profile.h>
#include <linux/sched.h>
+#include "exit_profile.h"
+
#define KERNEL_ATTR_RO(_name) \
static struct kobj_attribute _name##_attr = __ATTR_RO(_name)
@@ -149,6 +151,9 @@ static struct attribute * kernel_attrs[] = {
&kexec_crash_loaded_attr.attr,
&vmcoreinfo_attr.attr,
#endif
+#ifdef CONFIG_EXIT_PROFILE
+ &exit_profile_attr.attr,
+#endif
NULL
};