diff options
author | Andy Shevchenko <andy.shevchenko@gmail.com> | 2010-09-10 03:10:50 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2010-10-23 09:11:13 -0400 |
commit | 130067ed15f6e8a1209898646878f5bc0a17d3dd (patch) | |
tree | 80108295840277210d1bdb8199d4ed60bd6b170e /drivers/mmc | |
parent | 3183aa1534de4e98ffb0527d4f2be7ac9f019a4e (diff) |
mmc_test: move files from sysfs to debugfs
As proposed by Greg K-H it is more logical to keep files for the mmc_test
driver under debugfs.
Additionally this patch brings seq_file API for show() method. It allows
to write unlimited data to the file.
Example of usage:
# mount -t debugfs none /sys/kernel/debug
# modprobe mmc_test
[ 581.395843] mmc_test mmc0:0001: Card claimed for testing.
# echo 25 > /sys/kernel/debug/mmc0/mmc0\:0001/test
[ 604.568542] mmc0: Starting tests of card mmc0:0001...
[ 604.582733] mmc0: Test case 25. Best-case read performance into scattered pages...
[ 604.923553] mmc0: Transfer of 8192 sectors (4096 KiB) took 0.124664314 seconds (33644 kB/s, 32856 KiB/s)
[ 604.933227] mmc0: Result: OK
[ 604.936248] mmc0: Tests completed.
# cat /sys/kernel/debug/mmc0/mmc0\:0001/test
Test 25: 0
1 8192 0.124664314 33644784
Signed-off-by: Andy Shevchenko <ext-andriy.shevchenko@nokia.com>
Cc: Greg KH <greg@kroah.com>
Cc: Adrian Hunter <adrian.hunter@nokia.com>
Cc: Chris Ball <cjb@laptop.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Chris Ball <cjb@laptop.org>
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/mmc_test.c | 142 |
1 files changed, 107 insertions, 35 deletions
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c index 0c8b5685d4b7..6580af7b7cb8 100644 --- a/drivers/mmc/card/mmc_test.c +++ b/drivers/mmc/card/mmc_test.c | |||
@@ -19,6 +19,10 @@ | |||
19 | #include <linux/swap.h> /* For nr_free_buffer_pages() */ | 19 | #include <linux/swap.h> /* For nr_free_buffer_pages() */ |
20 | #include <linux/list.h> | 20 | #include <linux/list.h> |
21 | 21 | ||
22 | #include <linux/debugfs.h> | ||
23 | #include <linux/uaccess.h> | ||
24 | #include <linux/seq_file.h> | ||
25 | |||
22 | #define RESULT_OK 0 | 26 | #define RESULT_OK 0 |
23 | #define RESULT_FAIL 1 | 27 | #define RESULT_FAIL 1 |
24 | #define RESULT_UNSUP_HOST 2 | 28 | #define RESULT_UNSUP_HOST 2 |
@@ -110,6 +114,18 @@ struct mmc_test_general_result { | |||
110 | }; | 114 | }; |
111 | 115 | ||
112 | /** | 116 | /** |
117 | * struct mmc_test_dbgfs_file - debugfs related file. | ||
118 | * @link: double-linked list | ||
119 | * @card: card under test | ||
120 | * @file: file created under debugfs | ||
121 | */ | ||
122 | struct mmc_test_dbgfs_file { | ||
123 | struct list_head link; | ||
124 | struct mmc_card *card; | ||
125 | struct dentry *file; | ||
126 | }; | ||
127 | |||
128 | /** | ||
113 | * struct mmc_test_card - test information. | 129 | * struct mmc_test_card - test information. |
114 | * @card: card under test | 130 | * @card: card under test |
115 | * @scratch: transfer buffer | 131 | * @scratch: transfer buffer |
@@ -2124,14 +2140,12 @@ static void mmc_test_free_result(struct mmc_card *card) | |||
2124 | mutex_unlock(&mmc_test_lock); | 2140 | mutex_unlock(&mmc_test_lock); |
2125 | } | 2141 | } |
2126 | 2142 | ||
2127 | static ssize_t mmc_test_show(struct device *dev, | 2143 | static LIST_HEAD(mmc_test_file_test); |
2128 | struct device_attribute *attr, char *buf) | 2144 | |
2145 | static int mtf_test_show(struct seq_file *sf, void *data) | ||
2129 | { | 2146 | { |
2130 | struct mmc_card *card = mmc_dev_to_card(dev); | 2147 | struct mmc_card *card = (struct mmc_card *)sf->private; |
2131 | struct mmc_test_general_result *gr; | 2148 | struct mmc_test_general_result *gr; |
2132 | char *p = buf; | ||
2133 | size_t len = PAGE_SIZE; | ||
2134 | int ret; | ||
2135 | 2149 | ||
2136 | mutex_lock(&mmc_test_lock); | 2150 | mutex_lock(&mmc_test_lock); |
2137 | 2151 | ||
@@ -2141,49 +2155,44 @@ static ssize_t mmc_test_show(struct device *dev, | |||
2141 | if (gr->card != card) | 2155 | if (gr->card != card) |
2142 | continue; | 2156 | continue; |
2143 | 2157 | ||
2144 | ret = snprintf(p, len, "Test %d: %d\n", gr->testcase + 1, | 2158 | seq_printf(sf, "Test %d: %d\n", gr->testcase + 1, gr->result); |
2145 | gr->result); | ||
2146 | if (ret < 0) | ||
2147 | goto err; | ||
2148 | if (ret >= len) { | ||
2149 | ret = -ENOBUFS; | ||
2150 | goto err; | ||
2151 | } | ||
2152 | p += ret; | ||
2153 | len -= ret; | ||
2154 | 2159 | ||
2155 | list_for_each_entry(tr, &gr->tr_lst, link) { | 2160 | list_for_each_entry(tr, &gr->tr_lst, link) { |
2156 | ret = snprintf(p, len, "%u %d %lu.%09lu %u\n", | 2161 | seq_printf(sf, "%u %d %lu.%09lu %u\n", |
2157 | tr->count, tr->sectors, | 2162 | tr->count, tr->sectors, |
2158 | (unsigned long)tr->ts.tv_sec, | 2163 | (unsigned long)tr->ts.tv_sec, |
2159 | (unsigned long)tr->ts.tv_nsec, | 2164 | (unsigned long)tr->ts.tv_nsec, |
2160 | tr->rate); | 2165 | tr->rate); |
2161 | if (ret < 0) | ||
2162 | goto err; | ||
2163 | if (ret >= len) { | ||
2164 | ret = -ENOBUFS; | ||
2165 | goto err; | ||
2166 | } | ||
2167 | p += ret; | ||
2168 | len -= ret; | ||
2169 | } | 2166 | } |
2170 | } | 2167 | } |
2171 | 2168 | ||
2172 | ret = PAGE_SIZE - len; | ||
2173 | err: | ||
2174 | mutex_unlock(&mmc_test_lock); | 2169 | mutex_unlock(&mmc_test_lock); |
2175 | 2170 | ||
2176 | return ret; | 2171 | return 0; |
2177 | } | 2172 | } |
2178 | 2173 | ||
2179 | static ssize_t mmc_test_store(struct device *dev, | 2174 | static int mtf_test_open(struct inode *inode, struct file *file) |
2180 | struct device_attribute *attr, const char *buf, size_t count) | ||
2181 | { | 2175 | { |
2182 | struct mmc_card *card = mmc_dev_to_card(dev); | 2176 | return single_open(file, mtf_test_show, inode->i_private); |
2177 | } | ||
2178 | |||
2179 | static ssize_t mtf_test_write(struct file *file, const char __user *buf, | ||
2180 | size_t count, loff_t *pos) | ||
2181 | { | ||
2182 | struct seq_file *sf = (struct seq_file *)file->private_data; | ||
2183 | struct mmc_card *card = (struct mmc_card *)sf->private; | ||
2183 | struct mmc_test_card *test; | 2184 | struct mmc_test_card *test; |
2185 | char lbuf[12]; | ||
2184 | long testcase; | 2186 | long testcase; |
2185 | 2187 | ||
2186 | if (strict_strtol(buf, 10, &testcase)) | 2188 | if (count >= sizeof(lbuf)) |
2189 | return -EINVAL; | ||
2190 | |||
2191 | if (copy_from_user(lbuf, buf, count)) | ||
2192 | return -EFAULT; | ||
2193 | lbuf[count] = '\0'; | ||
2194 | |||
2195 | if (strict_strtol(lbuf, 10, &testcase)) | ||
2187 | return -EINVAL; | 2196 | return -EINVAL; |
2188 | 2197 | ||
2189 | test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); | 2198 | test = kzalloc(sizeof(struct mmc_test_card), GFP_KERNEL); |
@@ -2222,7 +2231,69 @@ static ssize_t mmc_test_store(struct device *dev, | |||
2222 | return count; | 2231 | return count; |
2223 | } | 2232 | } |
2224 | 2233 | ||
2225 | static DEVICE_ATTR(test, S_IWUSR | S_IRUGO, mmc_test_show, mmc_test_store); | 2234 | static const struct file_operations mmc_test_fops_test = { |
2235 | .open = mtf_test_open, | ||
2236 | .read = seq_read, | ||
2237 | .write = mtf_test_write, | ||
2238 | .llseek = seq_lseek, | ||
2239 | .release = single_release, | ||
2240 | }; | ||
2241 | |||
2242 | static void mmc_test_free_file_test(struct mmc_card *card) | ||
2243 | { | ||
2244 | struct mmc_test_dbgfs_file *df, *dfs; | ||
2245 | |||
2246 | mutex_lock(&mmc_test_lock); | ||
2247 | |||
2248 | list_for_each_entry_safe(df, dfs, &mmc_test_file_test, link) { | ||
2249 | if (card && df->card != card) | ||
2250 | continue; | ||
2251 | debugfs_remove(df->file); | ||
2252 | list_del(&df->link); | ||
2253 | kfree(df); | ||
2254 | } | ||
2255 | |||
2256 | mutex_unlock(&mmc_test_lock); | ||
2257 | } | ||
2258 | |||
2259 | static int mmc_test_register_file_test(struct mmc_card *card) | ||
2260 | { | ||
2261 | struct dentry *file = NULL; | ||
2262 | struct mmc_test_dbgfs_file *df; | ||
2263 | int ret = 0; | ||
2264 | |||
2265 | mutex_lock(&mmc_test_lock); | ||
2266 | |||
2267 | if (card->debugfs_root) | ||
2268 | file = debugfs_create_file("test", S_IWUSR | S_IRUGO, | ||
2269 | card->debugfs_root, card, &mmc_test_fops_test); | ||
2270 | |||
2271 | if (IS_ERR_OR_NULL(file)) { | ||
2272 | dev_err(&card->dev, | ||
2273 | "Can't create file. Perhaps debugfs is disabled.\n"); | ||
2274 | ret = -ENODEV; | ||
2275 | goto err; | ||
2276 | } | ||
2277 | |||
2278 | df = kmalloc(sizeof(struct mmc_test_dbgfs_file), GFP_KERNEL); | ||
2279 | if (!df) { | ||
2280 | debugfs_remove(file); | ||
2281 | dev_err(&card->dev, | ||
2282 | "Can't allocate memory for internal usage.\n"); | ||
2283 | ret = -ENOMEM; | ||
2284 | goto err; | ||
2285 | } | ||
2286 | |||
2287 | df->card = card; | ||
2288 | df->file = file; | ||
2289 | |||
2290 | list_add(&df->link, &mmc_test_file_test); | ||
2291 | |||
2292 | err: | ||
2293 | mutex_unlock(&mmc_test_lock); | ||
2294 | |||
2295 | return ret; | ||
2296 | } | ||
2226 | 2297 | ||
2227 | static int mmc_test_probe(struct mmc_card *card) | 2298 | static int mmc_test_probe(struct mmc_card *card) |
2228 | { | 2299 | { |
@@ -2231,7 +2302,7 @@ static int mmc_test_probe(struct mmc_card *card) | |||
2231 | if (!mmc_card_mmc(card) && !mmc_card_sd(card)) | 2302 | if (!mmc_card_mmc(card) && !mmc_card_sd(card)) |
2232 | return -ENODEV; | 2303 | return -ENODEV; |
2233 | 2304 | ||
2234 | ret = device_create_file(&card->dev, &dev_attr_test); | 2305 | ret = mmc_test_register_file_test(card); |
2235 | if (ret) | 2306 | if (ret) |
2236 | return ret; | 2307 | return ret; |
2237 | 2308 | ||
@@ -2243,7 +2314,7 @@ static int mmc_test_probe(struct mmc_card *card) | |||
2243 | static void mmc_test_remove(struct mmc_card *card) | 2314 | static void mmc_test_remove(struct mmc_card *card) |
2244 | { | 2315 | { |
2245 | mmc_test_free_result(card); | 2316 | mmc_test_free_result(card); |
2246 | device_remove_file(&card->dev, &dev_attr_test); | 2317 | mmc_test_free_file_test(card); |
2247 | } | 2318 | } |
2248 | 2319 | ||
2249 | static struct mmc_driver mmc_driver = { | 2320 | static struct mmc_driver mmc_driver = { |
@@ -2263,6 +2334,7 @@ static void __exit mmc_test_exit(void) | |||
2263 | { | 2334 | { |
2264 | /* Clear stalled data if card is still plugged */ | 2335 | /* Clear stalled data if card is still plugged */ |
2265 | mmc_test_free_result(NULL); | 2336 | mmc_test_free_result(NULL); |
2337 | mmc_test_free_file_test(NULL); | ||
2266 | 2338 | ||
2267 | mmc_unregister_driver(&mmc_driver); | 2339 | mmc_unregister_driver(&mmc_driver); |
2268 | } | 2340 | } |