* [PATCH] Cgroup: add cgroup members's exit data statistics
From: Marco @ 2009-06-02 14:36 UTC (permalink / raw)
To: containers; +Cc: linux-kernel, Linux Embedded
From: Marco Stornelli <marco.stornelli@gmail.com>
This patch adds the possibility for an application to receive statistics information only
for processes belonging to a cgroup. The mechanism is the same of the cpu's exit data statistics.
With this patch, instead of waiting on a specific cpumask, an application can wait for
exit data on a specific container. Through this patch it's possible to have a simple death
notifier mechanism. We can select the processes to watch and wait for their death.
A death notify mechanism is especially useful for embedded systems.
Signed-off-by: Marco Stornelli <marco.stornelli@gmail.com>
---
diff -uprN linux-2.6.29-orig/Documentation/accounting/getdelays.c linux-2.6.29/Documentation/accounting/getdelays.c
--- linux-2.6.29-orig/Documentation/accounting/getdelays.c 2009-03-24 00:12:14.000000000 +0100
+++ linux-2.6.29/Documentation/accounting/getdelays.c 2009-06-02 15:47:01.000000000 +0200
@@ -77,9 +77,11 @@ static void usage(void)
"[-m cpumask] [-t tgid] [-p pid]\n");
fprintf(stderr, " -d: print delayacct stats\n");
fprintf(stderr, " -i: print IO accounting (works only with -p)\n");
+ fprintf(stderr, " -q: print context switch accounting\n");
fprintf(stderr, " -l: listen forever\n");
fprintf(stderr, " -v: debug on\n");
- fprintf(stderr, " -C: container path\n");
+ fprintf(stderr, " -C: container path (container statistics)\n");
+ fprintf(stderr, " -N: container path (death notify)\n");
}
/*
@@ -263,13 +265,14 @@ int main(int argc, char *argv[])
char *logfile = NULL;
int loop = 0;
int containerset = 0;
+ int containernotify = 0;
char containerpath[1024];
int cfd = 0;
struct msgtemplate msg;
while (1) {
- c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:");
+ c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:N:");
if (c < 0)
break;
@@ -290,6 +293,10 @@ int main(int argc, char *argv[])
containerset = 1;
strncpy(containerpath, optarg, strlen(optarg) + 1);
break;
+ case 'N':
+ containernotify = 1;
+ strncpy(containerpath, optarg, strlen(optarg) + 1);
+ break;
case 'w':
logfile = strdup(optarg);
printf("write to file %s\n", logfile);
@@ -364,8 +371,13 @@ int main(int argc, char *argv[])
}
}
- if (tid && containerset) {
- fprintf(stderr, "Select either -t or -C, not both\n");
+ if (tid && (containerset || containernotify)) {
+ fprintf(stderr, "Select either -t or -C or -N\n");
+ goto err;
+ }
+
+ if (containerset && containernotify) {
+ fprintf(stderr, "Select either -C or -N, not both\n");
goto err;
}
@@ -392,7 +404,23 @@ int main(int argc, char *argv[])
goto err;
}
}
- if (!maskset && !tid && !containerset) {
+
+ if (containernotify) {
+ cfd = open(containerpath, O_RDONLY);
+ if (cfd < 0) {
+ perror("error opening container file");
+ goto err;
+ }
+ rc = send_cmd(nl_sd, id, mypid, CGROUPSTATS_CMD_GET,
+ CGROUPSTATS_CMD_ATTR_REGISTER_FD,
+ &cfd, sizeof(__u32));
+ if (rc < 0) {
+ perror("error sending cgroupstats command");
+ goto err;
+ }
+ }
+
+ if (!maskset && !tid && !containerset && !containernotify) {
usage();
goto err;
}
@@ -400,6 +428,7 @@ int main(int argc, char *argv[])
do {
int i;
+ PRINTF("Recv...\n");
rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
PRINTF("received %d bytes\n", rep_len);
@@ -495,6 +524,14 @@ done:
if (rc < 0)
err(rc, "error sending deregister cpumask\n");
}
+ if (containernotify) {
+ rc = send_cmd(nl_sd, id, mypid, CGROUPSTATS_CMD_GET,
+ CGROUPSTATS_CMD_ATTR_DEREGISTER_FD,
+ &cfd, sizeof(__u32));
+ printf("Sent deregister container, retval %d\n", rc);
+ if (rc < 0)
+ err(rc, "error sending deregister container\n");
+ }
err:
close(nl_sd);
if (fd)
--- linux-2.6.29-orig/kernel/taskstats.c 2009-03-24 00:12:14.000000000 +0100
+++ linux-2.6.29/kernel/taskstats.c 2009-06-02 15:54:37.000000000 +0200
@@ -56,6 +56,8 @@ __read_mostly = {
static struct nla_policy
cgroupstats_cmd_get_policy[CGROUPSTATS_CMD_ATTR_MAX+1] __read_mostly = {
[CGROUPSTATS_CMD_ATTR_FD] = { .type = NLA_U32 },
+ [CGROUPSTATS_CMD_ATTR_REGISTER_FD] = { .type = NLA_U32 },
+ [CGROUPSTATS_CMD_ATTR_DEREGISTER_FD] = { .type = NLA_U32 },
};
struct listener {
@@ -70,6 +72,16 @@ struct listener_list {
};
static DEFINE_PER_CPU(struct listener_list, listener_array);
+struct cgroup_listener {
+ struct list_head list;
+ pid_t pid;
+ char valid;
+ struct dentry *d_cgroup;
+ int ready_to_send;
+};
+
+static struct listener_list cgroup_listener_array;
+
enum actions {
REGISTER,
DEREGISTER,
@@ -124,6 +136,63 @@ static int send_reply(struct sk_buff *sk
}
/*
+ * Send taskstats data in @skb to listeners registered for cgroup members exit
+ * data
+ */
+static void send_cgroup_listeners(struct sk_buff *skb,
+ struct listener_list *listeners)
+{
+ struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
+ struct cgroup_listener *s, *tmp;
+ struct sk_buff *skb_next, *skb_cur = skb;
+ void *reply = genlmsg_data(genlhdr);
+ int rc, delcount = 0;
+
+ rc = genlmsg_end(skb, reply);
+ if (rc < 0) {
+ nlmsg_free(skb);
+ return;
+ }
+
+ rc = 0;
+ down_read(&listeners->sem);
+ list_for_each_entry(s, &listeners->list, list) {
+ if (!s->ready_to_send)
+ continue;
+ skb_next = NULL;
+ if (!list_is_last(&s->list, &listeners->list)) {
+ skb_next = skb_clone(skb_cur, GFP_KERNEL);
+ if (!skb_next)
+ break;
+ }
+ rc = genlmsg_unicast(skb_cur, s->pid);
+ if (rc == -ECONNREFUSED) {
+ s->valid = 0;
+ delcount++;
+ }
+ s->ready_to_send = 0;
+ skb_cur = skb_next;
+ }
+ up_read(&listeners->sem);
+
+ if (skb_cur)
+ nlmsg_free(skb_cur);
+
+ if (!delcount)
+ return;
+
+ /* Delete invalidated entries */
+ down_write(&listeners->sem);
+ list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+ if (!s->valid) {
+ list_del(&s->list);
+ kfree(s);
+ }
+ }
+ up_write(&listeners->sem);
+}
+
+/*
* Send taskstats data in @skb to listeners registered for @cpu's exit data
*/
static void send_cpu_listeners(struct sk_buff *skb,
@@ -290,6 +359,43 @@ ret:
return;
}
+
+static int add_cgroup_del_listener(pid_t pid, struct dentry *d_cgroup,
+ int isadd)
+{
+ struct listener_list *listeners = &cgroup_listener_array;
+ struct cgroup_listener *s, *tmp;
+
+ if (isadd == REGISTER) {
+ s = kmalloc(sizeof(struct cgroup_listener), GFP_KERNEL);
+ if (!s)
+ goto cleanup;
+ s->pid = pid;
+ INIT_LIST_HEAD(&s->list);
+ s->valid = 1;
+ s->d_cgroup = d_cgroup;
+ s->ready_to_send = 0;
+
+ down_write(&listeners->sem);
+ list_add(&s->list, &listeners->list);
+ up_write(&listeners->sem);
+ return 0;
+ }
+
+ /* Deregister or cleanup */
+cleanup:
+ down_write(&listeners->sem);
+ list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+ if (s->pid == pid) {
+ list_del(&s->list);
+ kfree(s);
+ break;
+ }
+ }
+ up_write(&listeners->sem);
+ return 0;
+}
+
static int add_del_listener(pid_t pid, const struct cpumask *mask, int isadd)
{
struct listener_list *listeners;
@@ -391,6 +497,32 @@ static int cgroupstats_user_cmd(struct s
struct file *file;
int fput_needed;
+ na = info->attrs[CGROUPSTATS_CMD_ATTR_REGISTER_FD];
+ if (na) {
+ fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_REGISTER_FD]);
+ file = fget_light(fd, &fput_needed);
+ if (!file)
+ return 0;
+
+ rc = add_cgroup_del_listener(info->snd_pid, file->f_dentry,
+ REGISTER);
+ fput_light(file, fput_needed);
+ return rc;
+ }
+
+ na = info->attrs[CGROUPSTATS_CMD_ATTR_DEREGISTER_FD];
+ if (na) {
+ fd = nla_get_u32(info->attrs[CGROUPSTATS_CMD_ATTR_DEREGISTER_FD]);
+ file = fget_light(fd, &fput_needed);
+ if (!file)
+ return 0;
+
+ rc = add_cgroup_del_listener(info->snd_pid, file->f_dentry,
+ DEREGISTER);
+ fput_light(file, fput_needed);
+ return rc;
+ }
+
na = info->attrs[CGROUPSTATS_CMD_ATTR_FD];
if (!na)
return -EINVAL;
@@ -517,15 +649,32 @@ ret:
return sig->stats;
}
+int check_ready_to_send(pid_t pid, struct listener_list *cgroup_list)
+{
+ struct listener_list *listeners = cgroup_list;
+ struct cgroup_listener *s, *tmp;
+ int ready = 0;
+
+ list_for_each_entry_safe(s, tmp, &listeners->list, list) {
+ if (cgroup_verify_pid(pid, s->d_cgroup) > 0) {
+ s->ready_to_send = 1;
+ ready = 1;
+ }
+ }
+
+ return ready;
+}
+
/* Send pid data out on exit */
void taskstats_exit(struct task_struct *tsk, int group_dead)
{
int rc;
struct listener_list *listeners;
+ struct listener_list *cgroup_listeners = &cgroup_listener_array;
struct taskstats *stats;
struct sk_buff *rep_skb;
size_t size;
- int is_thread_group;
+ int is_thread_group, target = 0;
if (!family_registered)
return;
@@ -545,7 +694,16 @@ void taskstats_exit(struct task_struct *
}
listeners = &__raw_get_cpu_var(listener_array);
- if (list_empty(&listeners->list))
+ if (!list_empty(&listeners->list))
+ target |= CPU_TARGET;
+
+ down_write(&cgroup_listeners->sem);
+ if (!list_empty(&cgroup_listeners->list))
+ if (check_ready_to_send(tsk->pid, cgroup_listeners))
+ target |= CGROUP_TARGET;
+ up_write(&cgroup_listeners->sem);
+
+ if (!target)
return;
rc = prepare_reply(NULL, TASKSTATS_CMD_NEW, &rep_skb, size);
@@ -573,7 +731,10 @@ void taskstats_exit(struct task_struct *
memcpy(stats, tsk->signal->stats, sizeof(*stats));
send:
- send_cpu_listeners(rep_skb, listeners);
+ if (target & CPU_TARGET)
+ send_cpu_listeners(rep_skb, listeners);
+ if (target & CGROUP_TARGET)
+ send_cgroup_listeners(rep_skb, cgroup_listeners);
return;
err:
nlmsg_free(rep_skb);
@@ -595,12 +756,15 @@ static struct genl_ops cgroupstats_ops =
void __init taskstats_init_early(void)
{
unsigned int i;
+ struct listener_list *listeners = &cgroup_listener_array;
taskstats_cache = KMEM_CACHE(taskstats, SLAB_PANIC);
for_each_possible_cpu(i) {
INIT_LIST_HEAD(&(per_cpu(listener_array, i).list));
init_rwsem(&(per_cpu(listener_array, i).sem));
}
+ INIT_LIST_HEAD(&listeners->list);
+ init_rwsem(&listeners->sem);
}
static int __init taskstats_init(void)
--- linux-2.6.29-orig/kernel/cgroup.c 2009-03-24 00:12:14.000000000 +0100
+++ linux-2.6.29/kernel/cgroup.c 2009-06-02 15:50:57.000000000 +0200
@@ -2040,6 +2040,44 @@ static int pid_array_load(pid_t *pidarra
}
/**
+ * cgroup_verify_pid - it verifies if a pid is in a cgroup
+ * @dentry: A dentry entry belonging to the cgroup for which stats have
+ * been requested.
+ *
+ * Return value can be < 0 for error, 0 not pid not found, > 0 pid found
+ */
+int cgroup_verify_pid(pid_t pid, struct dentry *dentry)
+{
+ int ret = -EINVAL;
+ struct cgroup *cgrp;
+ struct cgroup_iter it;
+ struct task_struct *tsk;
+
+ /*
+ * Validate dentry by checking the superblock operations,
+ * and make sure it's a directory.
+ */
+ if (dentry->d_sb->s_op != &cgroup_ops ||
+ !S_ISDIR(dentry->d_inode->i_mode))
+ goto err;
+
+ ret = 0;
+ cgrp = dentry->d_fsdata;
+
+ cgroup_iter_start(cgrp, &it);
+ while ((tsk = cgroup_iter_next(cgrp, &it))) {
+ if (tsk->pid == pid) {
+ cgroup_iter_end(cgrp, &it);
+ return 1;
+ }
+ }
+ cgroup_iter_end(cgrp, &it);
+
+err:
+ return ret;
+}
+
+/**
* cgroupstats_build - build and fill cgroupstats
* @stats: cgroupstats to fill information into
* @dentry: A dentry entry belonging to the cgroup for which stats have
--- linux-2.6.29-orig/include/linux/cgroup.h 2009-03-24 00:12:14.000000000 +0100
+++ linux-2.6.29/include/linux/cgroup.h 2009-06-02 15:55:11.000000000 +0200
@@ -32,6 +32,7 @@ extern void cgroup_fork(struct task_stru
extern void cgroup_fork_callbacks(struct task_struct *p);
extern void cgroup_post_fork(struct task_struct *p);
extern void cgroup_exit(struct task_struct *p, int run_callbacks);
+extern int cgroup_verify_pid(pid_t pid, struct dentry *dentry);
extern int cgroupstats_build(struct cgroupstats *stats,
struct dentry *dentry);
@@ -450,6 +451,10 @@ static inline void cgroup_exit(struct ta
static inline void cgroup_lock(void) {}
static inline void cgroup_unlock(void) {}
+static inline int cgroup_verify_pid(pid_t pid, struct dentry *dentry)
+{
+ return -EINVAL;
+}
static inline int cgroupstats_build(struct cgroupstats *stats,
struct dentry *dentry)
{
--- linux-2.6.29-orig/include/linux/cgroupstats.h 2009-03-24 00:12:14.000000000 +0100
+++ linux-2.6.29/include/linux/cgroupstats.h 2009-06-01 11:37:46.000000000 +0200
@@ -63,6 +63,8 @@ enum {
enum {
CGROUPSTATS_CMD_ATTR_UNSPEC = 0,
CGROUPSTATS_CMD_ATTR_FD,
+ CGROUPSTATS_CMD_ATTR_REGISTER_FD,
+ CGROUPSTATS_CMD_ATTR_DEREGISTER_FD,
__CGROUPSTATS_CMD_ATTR_MAX,
};
--- linux-2.6.29-orig/include/linux/taskstats.h 2009-03-24 00:12:14.000000000 +0100
+++ linux-2.6.29/include/linux/taskstats.h 2009-06-02 15:35:24.000000000 +0200
@@ -37,6 +37,9 @@
#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
* in linux/sched.h */
+#define CPU_TARGET 0x1
+#define CGROUP_TARGET 0x2
+
struct taskstats {
/* The version number of this struct. This field is always set to
^ permalink raw reply
* [PATCH 2/2] Modify MMCI/PL180 to handle agressive clocking v2
From: Linus Walleij @ 2009-06-02 12:37 UTC (permalink / raw)
To: Pierre Ossman, linux-arm-kernel; +Cc: linux-embedded, Linus Walleij
This adds a few clk_enable()/clk_disable() calls to the MMCI
driver so as to handle an set_ios() request with clock
frequency set to 0 as an instruction to gate the block clock.
This also breaks out the clock setting code into its own
function to simplify the set_ios() function a bit.
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
---
drivers/mmc/host/mmci.c | 78 ++++++++++++++++++++++++++++++++++------------
1 files changed, 57 insertions(+), 21 deletions(-)
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 36875dc..d9f5c9a 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -37,8 +37,34 @@
static unsigned int fmax = 515633;
+/*
+ * This must be called with host->lock held
+ */
+static void mmci_set_clkreg(struct mmci_host *host, unsigned int desired)
+{
+ u32 clk = 0;
+
+ if (desired) {
+ if (desired >= host->mclk) {
+ clk = MCI_CLK_BYPASS;
+ host->cclk = host->mclk;
+ DBG(host, "MMCI: bypass clock divider, cclk = %u Hz\n", host->cclk);
+ } else {
+ clk = host->mclk / (2 * desired) - 1;
+ if (clk >= 256)
+ clk = 255;
+ host->cclk = host->mclk / (2 * (clk + 1));
+ DBG(host, "MMCI: divide cclk to %u Hz (divide %u by %u)\n",
host->cclk, host->mclk, clk);
+ }
+ if (host->hw_designer == 0x80)
+ clk |= MCI_FCEN; /* Bug fix in ST IP block */
+ clk |= MCI_CLK_ENABLE;
+ }
+ writel(clk, host->base + MMCICLOCK);
+}
+
static void
-mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
+ mmci_request_end(struct mmci_host *host, struct mmc_request *mrq)
{
writel(0, host->base + MMCICOMMAND);
@@ -418,22 +444,7 @@ static void mmci_request(struct mmc_host *mmc,
struct mmc_request *mrq)
static void mmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmci_host *host = mmc_priv(mmc);
- u32 clk = 0, pwr = 0;
-
- if (ios->clock) {
- if (ios->clock >= host->mclk) {
- clk = MCI_CLK_BYPASS;
- host->cclk = host->mclk;
- } else {
- clk = host->mclk / (2 * ios->clock) - 1;
- if (clk >= 256)
- clk = 255;
- host->cclk = host->mclk / (2 * (clk + 1));
- }
- if (host->hw_designer == 0x80)
- clk |= MCI_FCEN; /* Bug fix in ST IP block */
- clk |= MCI_CLK_ENABLE;
- }
+ u32 pwr = 0;
if (host->plat->translate_vdd)
pwr |= host->plat->translate_vdd(mmc_dev(mmc), ios->vdd);
@@ -464,12 +475,23 @@ static void mmci_set_ios(struct mmc_host *mmc,
struct mmc_ios *ios)
}
}
- writel(clk, host->base + MMCICLOCK);
+ spin_lock(&host->lock);
+
+ if (ios->clock == 0) {
+ clk_disable(host->clk);
+ } else {
+ clk_enable(host->clk);
+ mmci_set_clkreg(host, ios->clock);
+ }
if (host->pwr != pwr) {
host->pwr = pwr;
+ clk_enable(host->clk);
writel(pwr, host->base + MMCIPOWER);
+ clk_disable(host->clk);
}
+
+ spin_unlock(&host->lock);
}
static const struct mmc_host_ops mmci_ops = {
@@ -615,6 +637,8 @@ static int __devinit mmci_probe(struct amba_device
*dev, void *id)
host->timer.expires = jiffies + HZ;
add_timer(&host->timer);
+ /* The first IOS will turn the clock on again */
+ clk_disable(host->clk);
return 0;
irq0_free:
@@ -646,17 +670,22 @@ static int __devexit mmci_remove(struct amba_device *dev)
mmc_remove_host(mmc);
+ /* framework may have gated the block clock */
+ clk_enable(host->clk);
+
writel(0, host->base + MMCIMASK0);
writel(0, host->base + MMCIMASK1);
writel(0, host->base + MMCICOMMAND);
writel(0, host->base + MMCIDATACTRL);
+ clk_disable(host->clk);
+
free_irq(dev->irq[0], host);
free_irq(dev->irq[1], host);
iounmap(host->base);
- clk_disable(host->clk);
+
clk_put(host->clk);
mmc_free_host(mmc);
@@ -677,8 +706,11 @@ static int mmci_suspend(struct amba_device *dev,
pm_message_t state)
struct mmci_host *host = mmc_priv(mmc);
ret = mmc_suspend_host(mmc, state);
- if (ret == 0)
+ if (ret == 0) {
+ clk_enable(host->clk);
writel(0, host->base + MMCIMASK0);
+ clk_disable(host->clk);
+ }
}
return ret;
@@ -692,7 +724,11 @@ static int mmci_resume(struct amba_device *dev)
if (mmc) {
struct mmci_host *host = mmc_priv(mmc);
- writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ if (ret == 0) {
+ clk_enable(host->clk);
+ writel(MCI_IRQENABLE, host->base + MMCIMASK0);
+ clk_disable(host->clk);
+ }
ret = mmc_resume_host(mmc);
}
--
1.6.2.1
^ permalink raw reply related
* [PATCH 1/2] MMC Agressive clocking framework v2
From: Linus Walleij @ 2009-06-02 12:36 UTC (permalink / raw)
To: Pierre Ossman, linux-arm-kernel; +Cc: linux-embedded, Linus Walleij
This patch modified the MMC core code to optionally call the
set_ios() operation on the driver with the clock frequency set
to 0 to gate the hardware block clock (and thus the MCI clock)
for an MMC host controller after a grace period of at least 8
MCLK cycles. It is inspired by existing clock gating code found
in the OMAP and Atmel drivers and brings this up to the host
abstraction. Gating is performed before and after any MMC request
or IOS operation, the other optional host operations will not
ungate/gate the clock since they do not necessary touch the
actual host controller hardware.
It exemplifies by implementing this for the MMCI/PL180 MMC/SD
host controller, but it should be simple to switch OMAP and
Atmel over to using this instead.
Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
---
drivers/mmc/core/Kconfig | 11 +++
drivers/mmc/core/core.c | 38 +++++++++++
drivers/mmc/core/core.h | 2 +
drivers/mmc/core/debugfs.c | 10 ++-
drivers/mmc/core/host.c | 160 +++++++++++++++++++++++++++++++++++++++++++-
drivers/mmc/core/host.h | 3 +
include/linux/mmc/host.h | 9 +++
7 files changed, 230 insertions(+), 3 deletions(-)
diff --git a/drivers/mmc/core/Kconfig b/drivers/mmc/core/Kconfig
index ab37a6d..6ae2156 100644
--- a/drivers/mmc/core/Kconfig
+++ b/drivers/mmc/core/Kconfig
@@ -14,3 +14,14 @@ config MMC_UNSAFE_RESUME
This option is usually just for embedded systems which use
a MMC/SD card for rootfs. Most people should say N here.
+config MMC_CLKGATE
+ bool "MMC host clock gaing (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ This will attempt to agressively gate the clock to the MMC host,
+ which typically also will gate the MCI clock to the card. This
+ is done to save power due to gating off the logic and bus noise
+ when MMC is not in use. Your host driver has to support this in
+ order for it to be of any use.
+
+ Of unsure, say N.
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2649117..c64dfe2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -113,6 +113,8 @@ void mmc_request_done(struct mmc_host *host,
struct mmc_request *mrq)
if (mrq->done)
mrq->done(mrq);
+
+ mmc_clk_disable(host);
}
}
@@ -173,6 +175,7 @@ mmc_start_request(struct mmc_host *host, struct
mmc_request *mrq)
mrq->stop->mrq = mrq;
}
}
+ mmc_clk_enable(host);
host->ops->request(host, mrq);
}
@@ -447,6 +450,39 @@ void mmc_set_clock(struct mmc_host *host, unsigned int hz)
mmc_set_ios(host);
}
+#ifdef CONFIG_MMC_CLKGATE
+/*
+ * This gates the clock by setting it to 0 Hz.
+ */
+void mmc_gate_clock(struct mmc_host *host)
+{
+ host->clk_old = host->ios.clock;
+ host->ios.clock = 0;
+ mmc_set_ios(host);
+}
+
+/*
+ * This restores the clock from gating by using the cached
+ * clock value.
+ */
+void mmc_ungate_clock(struct mmc_host *host)
+{
+ /*
+ * We have gated previously so the clock
+ * shall be 0 here!
+ */
+ BUG_ON(host->ios.clock);
+ /*
+ * The clock may however be 0 during intialization,
+ * when some request operations are performed before setting
+ * the frequency. When ungate is requested in that situation
+ * we just ignore the call.
+ */
+ if (host->clk_old)
+ mmc_set_clock(host, host->clk_old);
+}
+#endif
+
/*
* Change the bus mode (open drain/push-pull) of a host.
*/
@@ -861,6 +897,7 @@ void mmc_rescan(struct work_struct *work)
* release the lock here.
*/
mmc_bus_put(host);
+ mmc_clk_enable(host);
if (host->ops->get_cd && host->ops->get_cd(host) == 0)
goto out;
@@ -911,6 +948,7 @@ void mmc_rescan(struct work_struct *work)
mmc_bus_put(host);
}
out:
+ mmc_clk_disable(host);
if (host->caps & MMC_CAP_NEEDS_POLL)
mmc_schedule_delayed_work(&host->detect, HZ);
}
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index c819eff..ee27f81 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -27,6 +27,8 @@ void mmc_detach_bus(struct mmc_host *host);
void mmc_set_chip_select(struct mmc_host *host, int mode);
void mmc_set_clock(struct mmc_host *host, unsigned int hz);
+void mmc_gate_clock(struct mmc_host *host);
+void mmc_ungate_clock(struct mmc_host *host);
void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 610dbd1..1a969bd 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -149,11 +149,17 @@ void mmc_add_host_debugfs(struct mmc_host *host)
host->debugfs_root = root;
if (!debugfs_create_file("ios", S_IRUSR, root, host, &mmc_ios_fops))
- goto err_ios;
+ goto err_remove_files;
+
+#ifdef CONFIG_MMC_CLKGATE
+ if (!debugfs_create_u32("clk_delay", (S_IRUSR | S_IWUSR),
+ root, &host->clk_delay))
+ goto err_remove_files;
+#endif
return;
-err_ios:
+err_remove_files:
debugfs_remove_recursive(root);
host->debugfs_root = NULL;
err_root:
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 5e945e6..a381207 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2003 Russell King, All Rights Reserved.
* Copyright (C) 2007-2008 Pierre Ossman
+ * Copyright (C) 2009 Linus Walleij
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -48,6 +49,160 @@ void mmc_unregister_host_class(void)
static DEFINE_IDR(mmc_host_idr);
static DEFINE_SPINLOCK(mmc_host_lock);
+#ifdef CONFIG_MMC_CLKGATE
+
+/*
+ * Enabling clock gating will make the core call out to the host
+ * once up and once down when it performs a request or card operation
+ * intermingled in any fashion. The driver will see this through
+ * set_ios() operations with ios.clock field set to 0 to gate
+ * (disable) the block clock, and to the old frequency to enable
+ * it again.
+ */
+static void mmc_clk_disable_delayed(struct mmc_host *host)
+{
+ unsigned long tick_ns;
+ unsigned long freq = host->ios.clock;
+ int users;
+
+ if (!freq) {
+ pr_err("%s: frequency set to 0 in disable function, "
+ "this means the clock is already disabled.\n",
+ mmc_hostname(host));
+ return;
+ }
+ /*
+ * New requests may have appeared while we were scheduling,
+ * then there is no reason to delay the check before
+ * clk_disable().
+ */
+ spin_lock(&host->clk_lock);
+ users = host->clk_users;
+ /*
+ * Delay 8 bus cycles (from MMC spec) before attempting
+ * to disable the MMCI block clock. The reference count
+ * may have gone up again after this delay due to
+ * rescheduling!
+ */
+ if (!users) {
+ spin_unlock(&host->clk_lock);
+ tick_ns = (1000000000 + freq - 1) / freq;
+ ndelay(host->clk_delay * tick_ns);
+ } else {
+ /* New users appeared while waiting for this work */
+ host->clk_pending_gate = false;
+ spin_unlock(&host->clk_lock);
+ return;
+ }
+ spin_lock(&host->clk_lock);
+ if (!host->clk_users) {
+ spin_unlock(&host->clk_lock);
+ /* this will set host->ios.clock to 0 */
+ mmc_gate_clock(host);
+ spin_lock(&host->clk_lock);
+#ifdef CONFIG_MMC_DEBUG
+ pr_debug("%s: disabled MCI clock\n",
+ mmc_hostname(host));
+#endif
+ }
+ host->clk_pending_gate = false;
+ spin_unlock(&host->clk_lock);
+}
+
+/*
+ * Internal work. Work to disable the clock at some later point.
+ */
+static void mmc_clk_disable_work(struct work_struct *work)
+{
+ struct mmc_host *host = container_of(work, struct mmc_host,
+ clk_disable_work);
+
+ mmc_clk_disable_delayed(host);
+}
+
+/*
+ * mmc_clk_enable - enable hardware MCI clock
+ * @host: host with potential hardware clock to control
+ *
+ * Increase clock reference count and enable clock if first user.
+ */
+void mmc_clk_enable(struct mmc_host *host)
+{
+ spin_lock(&host->clk_lock);
+ /* If a gate is pending the clock is still on */
+ if (!host->clk_users &&
+ !host->clk_pending_gate) {
+ spin_unlock(&host->clk_lock);
+ mmc_ungate_clock(host);
+ spin_lock(&host->clk_lock);
+#ifdef CONFIG_MMC_DEBUG
+ pr_debug("%s: enabled MCI clock\n",
+ mmc_hostname(host));
+#endif
+ }
+ host->clk_users++;
+ spin_unlock(&host->clk_lock);
+}
+
+/*
+ * mmc_clk_disable - disable hardware MCI clock
+ * @host: host with potential hardware clock to control
+ *
+ * Decrease clock reference count and schedule disablement of clock.
+ */
+void mmc_clk_disable(struct mmc_host *host)
+{
+ spin_lock(&host->clk_lock);
+ host->clk_users--;
+ if (!host->clk_users) {
+ host->clk_pending_gate = true;
+ schedule_work(&host->clk_disable_work);
+ }
+ spin_unlock(&host->clk_lock);
+}
+
+/*
+ * mmc_clk_alloc - set up clock gating code
+ * @host: host with potential hardware clock to control
+ */
+static inline void mmc_clk_alloc(struct mmc_host *host)
+{
+ host->clk_users = 0;
+ host->clk_delay = 8; /* hold MCI clock in 8 cycles by default */
+ host->clk_pending_gate = false;
+ INIT_WORK(&host->clk_disable_work, mmc_clk_disable_work);
+ spin_lock_init(&host->clk_lock);
+}
+
+/*
+ * mmc_clk_remove - shut down clock gating code
+ * @host: host with potential hardware clock to control
+ */
+static inline void mmc_clk_remove(struct mmc_host *host)
+{
+ if (cancel_work_sync(&host->clk_disable_work))
+ mmc_clk_disable_delayed(host);
+ BUG_ON(host->clk_users > 0);
+}
+
+#else
+inline void mmc_clk_enable(struct mmc_host *host)
+{
+}
+
+inline void mmc_clk_disable(struct mmc_host *host)
+{
+}
+
+static inline void mmc_clk_alloc(struct mmc_host *host)
+{
+}
+
+static inline void mmc_clk_remove(struct mmc_host *host)
+{
+}
+#endif
+
/**
* mmc_alloc_host - initialise the per-host structure.
* @extra: sizeof private data structure
@@ -80,6 +235,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct
device *dev)
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
+ mmc_clk_alloc(host);
+
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
@@ -156,6 +313,8 @@ void mmc_remove_host(struct mmc_host *host)
device_del(&host->class_dev);
led_trigger_unregister_simple(host->led);
+
+ mmc_clk_remove(host);
}
EXPORT_SYMBOL(mmc_remove_host);
@@ -176,4 +335,3 @@ void mmc_free_host(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_free_host);
-
diff --git a/drivers/mmc/core/host.h b/drivers/mmc/core/host.h
index c2dc3d2..b36aef9 100644
--- a/drivers/mmc/core/host.h
+++ b/drivers/mmc/core/host.h
@@ -10,9 +10,12 @@
*/
#ifndef _MMC_CORE_HOST_H
#define _MMC_CORE_HOST_H
+#include <linux/mmc/host.h>
int mmc_register_host_class(void);
void mmc_unregister_host_class(void);
+void mmc_clk_enable(struct mmc_host *host);
+void mmc_clk_disable(struct mmc_host *host);
#endif
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 3e7615e..62ae13c 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -119,6 +119,15 @@ struct mmc_host {
#define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
#define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
+#ifdef CONFIG_MMC_CLKGATE
+ int clk_users; /* internal reference counter */
+ unsigned int clk_delay; /* number of MCI clk hold cycles */
+ bool clk_pending_gate; /* pending clock gating */
+ struct work_struct clk_disable_work; /* delayed clock disablement */
+ unsigned int clk_old; /* old clock value cache */
+ spinlock_t clk_lock; /* lock for clk fields */
+#endif
+
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
unsigned short max_hw_segs; /* see blk_queue_max_hw_segments */
--
1.6.2.1
^ permalink raw reply related
* [PATCH 0/2] MMC Agressive clocking framework v2
From: Linus Walleij @ 2009-06-02 12:35 UTC (permalink / raw)
To: Pierre Ossman, linux-arm-kernel; +Cc: linux-embedded, Linus Walleij
ChangeLog v1->v2:
* Switch the gating mechanism from using an additional callback
to setting the "clock" field in the ios structure to 0 and
storing away the current value to ungate the clock later on.
* Remove the mmc_clk_enable/disable around the ios() operations
as a result, if you use clock gating you have to take the
gating into account in your set_ios() code.
* Keep the nesting code (use count) this is used so that quick
bursts of requests can be handled properly while the disable
work is idling in the background and appears quite solid.
Tried my best to clarify why this code look as it does.
* Removed unnecessary depend on MMC!=n in the Kconfig, explicit
(EXPERIMENTAL) in option description.
* Updates MMCI reference implementation to reflect the new use
of the clock field.
* Remove unnecessary #include <clk.h>
* Added a debugfs file appearing in /mmcN/clk_delay that can
be used to trim the delay cycle count to test what happens
with different values.
* Works fine on my system.
Yours,
Linus Walleij
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Russell King - ARM Linux @ 2009-05-15 21:42 UTC (permalink / raw)
To: Jamie Lokier
Cc: George G. Davis, Ben Dooks, David Woodhouse, muzungu,
linux-embedded, linux-arm-kernel
In-Reply-To: <20090515145435.GF8235@shareable.org>
On Fri, May 15, 2009 at 03:54:35PM +0100, Jamie Lokier wrote:
> Register/parameter assignment: How is that relevant to the kernel
> interface, if the kernel itself and modules are all EABI? The system
> call interface is a fixed set of registers.
No it is not. The syscall interface obeys the ABI register allocation
rules as well, otherwise we have to have veneeer layers to reshuffle
the registers prior to calling C functions.
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Nicolas Pitre @ 2009-05-15 16:31 UTC (permalink / raw)
To: David Woodhouse; +Cc: Jamie Lokier, muzungu, linux-embedded, linux-arm-kernel
In-Reply-To: <1242395765.4201.94.camel@macbook.infradead.org>
On Fri, 15 May 2009, David Woodhouse wrote:
> On Fri, 2009-05-15 at 14:51 +0100, Jamie Lokier wrote:
> >
> > Eek, can you say a bit more about the ARM EABI mismatch?
> >
> > I would like to run a shiny modern ARM EABI kernel and userspace, but
> > also need to run one or two OABI binaries (from the gcc 2.95 era) on
> > the same kernel which I cannot recompile because they're built with
> > closed source libraries only supplied as OABI.
> >
> > Does that not work at all?
> >
> > If it does work, which part of userspace must be EABI to work?
>
> It was just a note of caution that sometimes we _do_ change the ABI.
>
> I'm not 100% sure offhand whether the EABI kernel can support OABI
> userspace; I didn't think so though.
Yes it can, for basic stuff. That means basic system calls with issues
are fixed up when necessary. This does not include things like ioctls
though, and in this case your mileage may vary. Notably, ALSA is known
to fail, some features of iptables too. See documentation at the top of
arch/arm/kernel/sys_oabi-compat.c to get an idea of what to watch for.
It is also possible to extend on what is already there for specific
needs that are not covered by the current set of fixups (and contribute
it back). But complete coverage is almost impossible to achieve and
pointless.
Nicolas
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Jamie Lokier @ 2009-05-15 14:56 UTC (permalink / raw)
To: George G. Davis
Cc: Ben Dooks, David Woodhouse, muzungu, linux-embedded,
linux-arm-kernel
In-Reply-To: <20090515145435.GF8235@shareable.org>
Jamie Lokier wrote:
> Structure packing: Isn't that basically the same set of fixups that
> need to be done for 32-bit compatibility on 64-bit kernels? Could it
> even use the same code - sneakily replacing "32" with OABI and "64"
> with EABI?
On second thoughts, I guess there may be a few fixups in common but
not much.
-- Jamie
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Jamie Lokier @ 2009-05-15 14:54 UTC (permalink / raw)
To: George G. Davis
Cc: Ben Dooks, David Woodhouse, muzungu, linux-embedded,
linux-arm-kernel
In-Reply-To: <20090515143230.GE10977@mvista.com>
George G. Davis wrote:
> On Fri, May 15, 2009 at 02:55:57PM +0100, Ben Dooks wrote:
> > On Fri, May 15, 2009 at 02:51:05PM +0100, Jamie Lokier wrote:
> > > Eek, can you say a bit more about the ARM EABI mismatch?
> > >
> > > I would like to run a shiny modern ARM EABI kernel and userspace, but
> > > also need to run one or two OABI binaries (from the gcc 2.95 era) on
> > > the same kernel which I cannot recompile because they're built with
> > > closed source libraries only supplied as OABI.
> > >
> > > Does that not work at all?
> >
> > There are a few ioctl() incompatibilities between the two ABIs, the
> > main problems are within the ALSA API. Mostly it will work, but there
> > are a couple of caveats.
>
> Right, you can run ARM OABI binaries on an ARM eABI kernel by enabling
> OABI_COMPAT. However, as Ben notes, there are (more than, IMNSHO ; )
> "a couple of caveats". Most of the "easy" ABI compatibility fixups
> should be handled already via OABI_COMPAT. However, it's practically
> impossible to fixup all OABI/eABI compatibility issues due to register
> assignment, parameter alignment and/or packing differences between
> the two ABIs. You would have to analyze all kernel and driver
> user interfaces to reassign parameters to registers, align and/or
> repack data structures, etc.,. In fact, some of the existing fixups
> include side effects that in some cases can cause userspace code to
> fail, depending on how it is using I/O parameters, e.g. in some cases,
> library code may try to validate parameters which are relocated and
> those tests fail due to reshuffling of parameters. It's a nasty
> path to go down, quite frankly. I would not recommend trying to
> support OABI binaries on an eABI kernel using OABI_COMPAT.
Structure packing: Isn't that basically the same set of fixups that
need to be done for 32-bit compatibility on 64-bit kernels? Could it
even use the same code - sneakily replacing "32" with OABI and "64"
with EABI?
Register/parameter assignment: How is that relevant to the kernel
interface, if the kernel itself and modules are all EABI? The system
call interface is a fixed set of registers.
It sounds like you're saying I should use OABI kernels and userspace
even with latest kernels, if I have a single OABI binary that might
use anything interesting from the kernel, like readdir, poll, signal
context, ioctl, device read/write, or any other system calls which
take a struct that isn't all 32-bit words.
-- Jamie
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: George G. Davis @ 2009-05-15 14:32 UTC (permalink / raw)
To: Ben Dooks
Cc: Jamie Lokier, David Woodhouse, muzungu, linux-embedded,
linux-arm-kernel
In-Reply-To: <20090515135557.GC18976@trinity.fluff.org>
Hi,
On Fri, May 15, 2009 at 02:55:57PM +0100, Ben Dooks wrote:
> On Fri, May 15, 2009 at 02:51:05PM +0100, Jamie Lokier wrote:
> > Eek, can you say a bit more about the ARM EABI mismatch?
> >
> > I would like to run a shiny modern ARM EABI kernel and userspace, but
> > also need to run one or two OABI binaries (from the gcc 2.95 era) on
> > the same kernel which I cannot recompile because they're built with
> > closed source libraries only supplied as OABI.
> >
> > Does that not work at all?
>
> There are a few ioctl() incompatibilities between the two ABIs, the
> main problems are within the ALSA API. Mostly it will work, but there
> are a couple of caveats.
Right, you can run ARM OABI binaries on an ARM eABI kernel by enabling
OABI_COMPAT. However, as Ben notes, there are (more than, IMNSHO ; )
"a couple of caveats". Most of the "easy" ABI compatibility fixups
should be handled already via OABI_COMPAT. However, it's practically
impossible to fixup all OABI/eABI compatibility issues due to register
assignment, parameter alignment and/or packing differences between
the two ABIs. You would have to analyze all kernel and driver
user interfaces to reassign parameters to registers, align and/or
repack data structures, etc.,. In fact, some of the existing fixups
include side effects that in some cases can cause userspace code to
fail, depending on how it is using I/O parameters, e.g. in some cases,
library code may try to validate parameters which are relocated and
those tests fail due to reshuffling of parameters. It's a nasty
path to go down, quite frankly. I would not recommend trying to
support OABI binaries on an eABI kernel using OABI_COMPAT.
--
Regards,
George
>
> --
> Ben
>
> Q: What's a light-year?
> A: One-third less calories than a regular year.
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-embedded" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Gustavo Zacarias @ 2009-05-15 14:03 UTC (permalink / raw)
To: David Woodhouse; +Cc: Jamie Lokier, muzungu, linux-embedded, linux-arm-kernel
In-Reply-To: <1242395765.4201.94.camel@macbook.infradead.org>
David Woodhouse wrote:
>
> It was just a note of caution that sometimes we _do_ change the ABI.
>
> I'm not 100% sure offhand whether the EABI kernel can support OABI
> userspace; I didn't think so though.
>
He could try CONFIG_OABI_COMPAT=y, at least in 2.6.28+.
No thumb though.
Regards.
-------------------------------------------------------------------
List admin: http://lists.arm.linux.org.uk/mailman/listinfo/linux-arm-kernel
FAQ: http://www.arm.linux.org.uk/mailinglists/faq.php
Etiquette: http://www.arm.linux.org.uk/mailinglists/etiquette.php
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: David Woodhouse @ 2009-05-15 13:56 UTC (permalink / raw)
To: Jamie Lokier; +Cc: muzungu, linux-embedded, linux-arm-kernel
In-Reply-To: <20090515135105.GC8235@shareable.org>
On Fri, 2009-05-15 at 14:51 +0100, Jamie Lokier wrote:
>
> Eek, can you say a bit more about the ARM EABI mismatch?
>
> I would like to run a shiny modern ARM EABI kernel and userspace, but
> also need to run one or two OABI binaries (from the gcc 2.95 era) on
> the same kernel which I cannot recompile because they're built with
> closed source libraries only supplied as OABI.
>
> Does that not work at all?
>
> If it does work, which part of userspace must be EABI to work?
It was just a note of caution that sometimes we _do_ change the ABI.
I'm not 100% sure offhand whether the EABI kernel can support OABI
userspace; I didn't think so though.
--
dwmw2
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Ben Dooks @ 2009-05-15 13:55 UTC (permalink / raw)
To: Jamie Lokier; +Cc: David Woodhouse, muzungu, linux-embedded, linux-arm-kernel
In-Reply-To: <20090515135105.GC8235@shareable.org>
On Fri, May 15, 2009 at 02:51:05PM +0100, Jamie Lokier wrote:
> David Woodhouse wrote:
> > On Fri, 2009-05-15 at 13:50 +0200, muzungu@gmx.net wrote:
> > > Questions:
> > > - Can I run an application compiled with gcc ABI 2.95 on a kernel
> > > compiled with gcc ABI 3.4?
> >
> > Yes. The kernel ABI never changes in a backward-incompatible fashion.
> > Unless you try switching your kernel to ARM EABI and don't update
> > userspace to match -- don't do that :)
>
> Eek, can you say a bit more about the ARM EABI mismatch?
>
> I would like to run a shiny modern ARM EABI kernel and userspace, but
> also need to run one or two OABI binaries (from the gcc 2.95 era) on
> the same kernel which I cannot recompile because they're built with
> closed source libraries only supplied as OABI.
>
> Does that not work at all?
There are a few ioctl() incompatibilities between the two ABIs, the
main problems are within the ALSA API. Mostly it will work, but there
are a couple of caveats.
--
Ben
Q: What's a light-year?
A: One-third less calories than a regular year.
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: Jamie Lokier @ 2009-05-15 13:51 UTC (permalink / raw)
To: David Woodhouse; +Cc: muzungu, linux-embedded, linux-arm-kernel
In-Reply-To: <1242390699.4201.3.camel@macbook.infradead.org>
David Woodhouse wrote:
> On Fri, 2009-05-15 at 13:50 +0200, muzungu@gmx.net wrote:
> > Questions:
> > - Can I run an application compiled with gcc ABI 2.95 on a kernel
> > compiled with gcc ABI 3.4?
>
> Yes. The kernel ABI never changes in a backward-incompatible fashion.
> Unless you try switching your kernel to ARM EABI and don't update
> userspace to match -- don't do that :)
Eek, can you say a bit more about the ARM EABI mismatch?
I would like to run a shiny modern ARM EABI kernel and userspace, but
also need to run one or two OABI binaries (from the gcc 2.95 era) on
the same kernel which I cannot recompile because they're built with
closed source libraries only supplied as OABI.
Does that not work at all?
If it does work, which part of userspace must be EABI to work?
Thanks,
-- Jamie
^ permalink raw reply
* Re: Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: David Woodhouse @ 2009-05-15 12:31 UTC (permalink / raw)
To: muzungu; +Cc: linux-embedded
In-Reply-To: <20090515115009.110740@gmx.net>
On Fri, 2009-05-15 at 13:50 +0200, muzungu@gmx.net wrote:
> Questions:
> - Can I run an application compiled with gcc ABI 2.95 on a kernel
> compiled with gcc ABI 3.4?
Yes. The kernel ABI never changes in a backward-incompatible fashion.
Unless you try switching your kernel to ARM EABI and don't update
userspace to match -- don't do that :)
Unless you're using C++, you're more likely to have problems with
different versions of libraries, and buggy code which doesn't compile
correctly with the new compiler, than you are with GCC ABI variations
per se. Especially in the kernel<->userspace interface.
--
David Woodhouse Open Source Technology Centre
David.Woodhouse@intel.com Intel Corporation
^ permalink raw reply
* Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
From: muzungu @ 2009-05-15 11:50 UTC (permalink / raw)
To: linux-embedded
Hello all
We have a target system with an old Linux environment that we can not easily upgrade to a new one.
The actual development system (linux) has more or less the same age (prox. 10 year)
We intend to do the following:
- Use a new distribution as development environment (linux)
- Still compile the target application for the old system (2.2 and 2.4 kernels, once all compiled with egcs 2.91.66)
- Test the target applications in the new development environment
Questions:
- Can I run an application compiled with gcc ABI 2.95 on a kernel compiled with gcc ABI 3.4?
- In other words: does it matter if the gcc ABI of the compilers for the kernel and the application are different, assuming all the libraries used, have the same gcc ABI as the application?
I guess:
- gcc ABI of librabies and applications compilation must generally match
- gcc ABI of kernel, libraries and applications compilation must generally match to.
Am I wrong?
I would appreciate any help
Roman
--
Neu: GMX FreeDSL Komplettanschluss mit DSL 6.000 Flatrate + Telefonanschluss für nur 17,95 Euro/mtl.!* http://dslspecial.gmx.de/freedsl-surfflat/?ac=OM.AD.PD003K11308T4569a
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Jamie Lokier @ 2009-04-26 23:46 UTC (permalink / raw)
To: Kay Sievers
Cc: Alan Stern, David VomLehn, Alan Cox, Ingo Molnar,
Arjan van de Ven, H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <ac3eb2510904261623g6270b9a4x20252e06fc8d8bf6@mail.gmail.com>
Kay Sievers wrote:
> On Mon, Apr 27, 2009 at 01:12, Jamie Lokier <jamie@shareable.org> wrote:
> > Kay Sievers wrote:
> >> > _If_ the system doesn't wait for all block devices present at boot to
> >> > be enumerated before the boot script, then when the script looks in
> >> > that directory for a specific UUID, it would be good to wait until
> >> > "has everything present at boot been enumerated?" says yes.
> >>
> >> That's what distros do with initramfs today.
> >
> > I don't see how that's possible. Haven't we been discussing how the
> > USB driver does not have any support (yet) for saying when it's found
> > every device present at boot time, and that it can probably be added?
>
> It's easy for the rootfs, or any other mandatory filesystem, unlike it
> is for the console stuff.
>
> There is no timeout, distro's initramfs waits for the specified root
> device until it appears. It's simple, there is nothing else to do for
> it. It does not care what bus it is, or who is probing what for how
> long. It loads all drivers it finds hardware for, and then spins until
> the device shows up and continues.
Ok. I'm specifically _not_ talking about mandatory filesystems.
Thanks :-)
-- Jamie
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Kay Sievers @ 2009-04-26 23:23 UTC (permalink / raw)
To: Jamie Lokier
Cc: Alan Stern, David VomLehn, Alan Cox, Ingo Molnar,
Arjan van de Ven, H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <20090426231208.GA17240@shareable.org>
On Mon, Apr 27, 2009 at 01:12, Jamie Lokier <jamie@shareable.org> wrote:
> Kay Sievers wrote:
>> > _If_ the system doesn't wait for all block devices present at boot to
>> > be enumerated before the boot script, then when the script looks in
>> > that directory for a specific UUID, it would be good to wait until
>> > "has everything present at boot been enumerated?" says yes.
>>
>> That's what distros do with initramfs today.
>
> I don't see how that's possible. Â Haven't we been discussing how the
> USB driver does not have any support (yet) for saying when it's found
> every device present at boot time, and that it can probably be added?
It's easy for the rootfs, or any other mandatory filesystem, unlike it
is for the console stuff.
There is no timeout, distro's initramfs waits for the specified root
device until it appears. It's simple, there is nothing else to do for
it. It does not care what bus it is, or who is probing what for how
long. It loads all drivers it finds hardware for, and then spins until
the device shows up and continues.
Kay
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Jamie Lokier @ 2009-04-26 23:12 UTC (permalink / raw)
To: Kay Sievers
Cc: Alan Stern, David VomLehn, Alan Cox, Ingo Molnar,
Arjan van de Ven, H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <ac3eb2510904261536t7a37f970tfafba71d1e67cfb6@mail.gmail.com>
Kay Sievers wrote:
> > _If_ the system doesn't wait for all block devices present at boot to
> > be enumerated before the boot script, then when the script looks in
> > that directory for a specific UUID, it would be good to wait until
> > "has everything present at boot been enumerated?" says yes.
>
> That's what distros do with initramfs today.
I don't see how that's possible. Haven't we been discussing how the
USB driver does not have any support (yet) for saying when it's found
every device present at boot time, and that it can probably be added?
I have a boot script which does this:
1. *If* USB disk plugged in, mount it on /mnt/usb, do some stuff.
2. If not, do something else.
If I'm not mistaken, the only way to do that right now is pick an
arbitrary time, wait, and proceed with 2 if you didn't see the disk.
The desired USB console behaviour is very similar. Use it if it's
plugged in at boot, use something else otherwise, and no arbitrary
delays.
Did I miss something?
> > Since this is all about making boot faster, it would be quite nice not
> > to wait for all block devices before starting the boot script, or at
> > least the initramfs module-loading script :-)
>
> You wait in initramfs until the device show up. Usually dynamic udev
> rules created from the root= string of the kernel commandline create a
> rule which matches on the UUID, and creates a /dev/root symlink when
> the device shows up. As soon as this link shows up, init mounts it
> and goes ahead.
That's fine when you're waiting for a device to appear that you know
will appear.
The USB console excitement, and my mention of USB disks and such, is
how to decide when the device _isn't_ going to appear, without an
arbitrary timeout.
-- Jamie
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Kay Sievers @ 2009-04-26 22:36 UTC (permalink / raw)
To: Jamie Lokier
Cc: Alan Stern, David VomLehn, Alan Cox, Ingo Molnar,
Arjan van de Ven, H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <20090426213746.GH10627@shareable.org>
On Sun, Apr 26, 2009 at 23:37, Jamie Lokier <jamie@shareable.org> wrote:
> Alan Stern wrote:
>> As for searching for a particular UUID, I believe recent changes to
>> sysfs/udev should improve the situation. There will be a "by_UUID"
>> directory somewhere, containing a bunch of symbolic links whose names
>> are the UUID values of all the registered drives. Programs won't have
>> to read every disk; they'll only have to search through this directory.
>
> That will be great.
It is like that for years now, and it is completely in userspace at
/dev/disk/by-uuid/. I don't know of any plans to add filesystem/raid
signature uuid probing support to the kernel. And I think that will be
almost impossible to get right in the kernel.
Yes, you need to look at all the disks from userspace, if you request
to mount them by filesystem metadata like label/UUID. It works fine
even on boxes with thousands of disks.
> _If_ the system doesn't wait for all block devices present at boot to
> be enumerated before the boot script, then when the script looks in
> that directory for a specific UUID, it would be good to wait until
> "has everything present at boot been enumerated?" says yes.
That's what distros do with initramfs today.
> Otherwise you have hacks like my boot script which waits 5 seconds for
> a disk to show up on USB, and then continues if not. It sounds
> awfully like waiting X seconds for a USB console to show up :-)
>
> Since this is all about making boot faster, it would be quite nice not
> to wait for all block devices before starting the boot script, or at
> least the initramfs module-loading script :-)
You wait in initramfs until the device show up. Usually dynamic udev
rules created from the root= string of the kernel commandline create a
rule which matches on the UUID, and creates a /dev/root symlink when
the device shows up. As soon as this link shows up, init mounts it
and goes ahead.
Thanks,
Kay
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Jamie Lokier @ 2009-04-26 21:37 UTC (permalink / raw)
To: Alan Stern
Cc: David VomLehn, Alan Cox, Ingo Molnar, Arjan van de Ven,
H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <Pine.LNX.4.44L0.0904261715250.26439-100000@netrider.rowland.org>
Alan Stern wrote:
> On Sun, 26 Apr 2009, Jamie Lokier wrote:
>
> > > Are you suggesting this new interface be exported to userspace somehow?
> >
> > Not directly. Only in the same way that open("/dev/console") delays
> > until there's a console, so reading the keyboard can delay until we
> > know if we had a keyboard plugged in at boot, and looking for a disk
> > called UUID=392852908752345749857 can wait until we know if there was
> > one plugged in at boot time.
> >
> > The latter issue with UUID is done in userspace now by reading all
> > disks, but I'm under the impression changes are planned in that
> > department because reading every disk from userspace to locate
> > specific ones is too slow on big systems.
>
> IIUC, David is proposing that no userspace process should get started
> until some (all?) of the console devices and the block device
> containing the root filesystem (all block devices present at boot?)
> have been registered. That would remove the need for your delays, at
> least in part.
>
> As for searching for a particular UUID, I believe recent changes to
> sysfs/udev should improve the situation. There will be a "by_UUID"
> directory somewhere, containing a bunch of symbolic links whose names
> are the UUID values of all the registered drives. Programs won't have
> to read every disk; they'll only have to search through this directory.
That will be great.
_If_ the system doesn't wait for all block devices present at boot to
be enumerated before the boot script, then when the script looks in
that directory for a specific UUID, it would be good to wait until
"has everything present at boot been enumerated?" says yes.
Otherwise you have hacks like my boot script which waits 5 seconds for
a disk to show up on USB, and then continues if not. It sounds
awfully like waiting X seconds for a USB console to show up :-)
Since this is all about making boot faster, it would be quite nice not
to wait for all block devices before starting the boot script, or at
least the initramfs module-loading script :-)
That's outside the scope of bootconsole and root device. I certainly
won't demand it's done, but I'm sure you can see a strong similarity:
the ability to wait in the kernel until a class of devices that were
present at boot have finished enumerating.
-- Jamie
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Alan Stern @ 2009-04-26 21:20 UTC (permalink / raw)
To: Jamie Lokier
Cc: David VomLehn, Alan Cox, Ingo Molnar, Arjan van de Ven,
H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <20090426195249.GC10627@shareable.org>
On Sun, 26 Apr 2009, Jamie Lokier wrote:
> > Are you suggesting this new interface be exported to userspace somehow?
>
> Not directly. Only in the same way that open("/dev/console") delays
> until there's a console, so reading the keyboard can delay until we
> know if we had a keyboard plugged in at boot, and looking for a disk
> called UUID=392852908752345749857 can wait until we know if there was
> one plugged in at boot time.
>
> The latter issue with UUID is done in userspace now by reading all
> disks, but I'm under the impression changes are planned in that
> department because reading every disk from userspace to locate
> specific ones is too slow on big systems.
IIUC, David is proposing that no userspace process should get started
until some (all?) of the console devices and the block device
containing the root filesystem (all block devices present at boot?)
have been registered. That would remove the need for your delays, at
least in part.
As for searching for a particular UUID, I believe recent changes to
sysfs/udev should improve the situation. There will be a "by_UUID"
directory somewhere, containing a bunch of symbolic links whose names
are the UUID values of all the registered drives. Programs won't have
to read every disk; they'll only have to search through this directory.
Alan Stern
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Jamie Lokier @ 2009-04-26 19:52 UTC (permalink / raw)
To: Alan Stern
Cc: David VomLehn, Alan Cox, Ingo Molnar, Arjan van de Ven,
H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <Pine.LNX.4.44L0.0904242309300.3926-100000@netrider.rowland.org>
Alan Stern wrote:
> On Sat, 25 Apr 2009, Jamie Lokier wrote:
>
> > I'm thinking this broader use:
> >
> > - My boot _script_ is waiting for a disk which identifies as
> > UUID=392852908752345749857 to appear before it can mount it on
> > /data. If there's no such disk, it proceeds without it. It's a
> > USB disk, behind a USB hub.
> >
> > - My boot script is looking to see if I'm holding down 'z' on the
> > keyboard, to do something different. But how does it know if
> > there's a USB keyboard plugged in (behind two USB hubs) that
> > hasn't finished being detected?
> >
> > It just seemed to fit comfortably into what's being discussed.
>
> Are you suggesting this new interface be exported to userspace somehow?
Not directly. Only in the same way that open("/dev/console") delays
until there's a console, so reading the keyboard can delay until we
know if we had a keyboard plugged in at boot, and looking for a disk
called UUID=392852908752345749857 can wait until we know if there was
one plugged in at boot time.
The latter issue with UUID is done in userspace now by reading all
disks, but I'm under the impression changes are planned in that
department because reading every disk from userspace to locate
specific ones is too slow on big systems.
-- Jamie
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: David VomLehn @ 2009-04-26 17:55 UTC (permalink / raw)
To: Jamie Lokier
Cc: Alan Stern, Alan Cox, Ingo Molnar, Arjan van de Ven,
H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <20090425014152.GD23106-yetKDKU6eevNLxjTenLetw@public.gmane.org>
On Sat, Apr 25, 2009 at 02:41:52AM +0100, Jamie Lokier wrote:
> David VomLehn wrote:
> > I think this is over-engineered. This focused on boot devices, so you really
> > don't care about things like buses, and I don't perceive a broader use. What
> > really matters is particular boot device types, wherever they came from.
>
> I'm thinking this broader use:
>
> - My boot _script_ is waiting for a disk which identifies as
> UUID=392852908752345749857 to appear before it can mount it on
> /data. If there's no such disk, it proceeds without it. It's a
> USB disk, behind a USB hub.
>
> - My boot script is looking to see if I'm holding down 'z' on the
> keyboard, to do something different. But how does it know if
> there's a USB keyboard plugged in (behind two USB hubs) that
> hasn't finished being detected?
>
> It just seemed to fit comfortably into what's being discussed.
>
> (I do have these a system with these requirements, by the way. It's
> solved at the moment by waiting 5 seconds after booting, and by using
> an older kernel which doesn't have boot parallelisation yet...)
If the keyboard is being used for the console, this should fix your problem.
If not, I think you can fix it by using a hotplug script.
> Only one problem I see: what happens when there's an attempt to open
> /dev/console before you increment the pending count? It seems to me
> you have to wait for all buses to have been detected, which is why I
> mentioned buses, as some buses are _themselves_ slow devices to detect.
A valid point. I just sent an updated patch to address this.
> > The key question is, are there cases where there is enough time between steps
> > 1 and 2, and steps 2 and 3, to add this complexity? If not, let's skip it.
>
> The time between enumerating that a USB device exists and what it's
> class is (could be a console?), and actually initialising the device
> to find out if it's then usable, including loading firmware, can be a
> little while.
>
> I don't know if the times are long enough to matter.
Me neither, but I went ahead and added bus_bootdev_type_found. It's a trivial
piece of code and will allow this case to be handled cleanly.
> Possibly related to all this: it would be really nice if the ATA
> rather slow probe time didn't have to delay boot scripts until they
> depend on the not-yet-probed disks, as sometimes they might not.
Related to boot time, yes, but it sounds like it's not related to the
boot device issue. By the time you get to boot scripts, you've initialized
all the boot devices you're going to.
> -- Jamie
David VomLehn
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [Patch] Wait for console to become available, ver 3
From: Pavel Machek @ 2009-04-25 8:16 UTC (permalink / raw)
To: David VomLehn
Cc: Linux Kernel Mailing List, Linux Embedded Mailing List,
Linux USB Mailing List, Andrew Morton
In-Reply-To: <20090417213148.GA27825@cuplxvomd02.corp.sa.net>
Hi!
> Parallelization to improve boot times has been successful enough that race
> conditions now exist between the init_post() open of /dev/console and
> initialization of the console device. When this occurs, opening /dev/console
> fails and any applications inherited from init have no standard in/out/error
> devices. This is expected behavior if no console device is available, but
> quite unfortunate in the case where the console is just a bit slow waking up.
>
> Some buses, such as USB, offer no guarantees about how long it takes to
> discover devices, so there is no reliable way to distinguish between a missing
> console and a slow one. The pragmatic approach taken in this patch is to
> wait for a while to see if a console shows up, and just go on if it doesn't.
> The default delay is 1000 msec (1 second).
>
> There are two new command line parameters:
> consolewait Wait forever for a console to be registered
> consoledelay=msec Use the given number of milliseconds as the delay
> interval instead of the default
Could you use rootfsdelay for this? Root needs to be mounted for init
to run, so...?
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* Re: Wait for console to become available, v3.2
From: Alan Stern @ 2009-04-25 3:11 UTC (permalink / raw)
To: Jamie Lokier
Cc: David VomLehn, Alan Cox, Ingo Molnar, Arjan van de Ven,
H. Peter Anvin, Thomas Gleixner, Linus Torvalds,
Linux Kernel Mailing List, Linux USB Mailing List,
Linux Embedded Mailing List, Andrew Morton
In-Reply-To: <20090425014152.GD23106@shareable.org>
On Sat, 25 Apr 2009, Jamie Lokier wrote:
> I'm thinking this broader use:
>
> - My boot _script_ is waiting for a disk which identifies as
> UUID=392852908752345749857 to appear before it can mount it on
> /data. If there's no such disk, it proceeds without it. It's a
> USB disk, behind a USB hub.
>
> - My boot script is looking to see if I'm holding down 'z' on the
> keyboard, to do something different. But how does it know if
> there's a USB keyboard plugged in (behind two USB hubs) that
> hasn't finished being detected?
>
> It just seemed to fit comfortably into what's being discussed.
Are you suggesting this new interface be exported to userspace somehow?
Alan Stern
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox