aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh
Commit message (Expand)AuthorAge
* [PATCH] No arch-specific strpbrk implementationsKyle McMartin2006-04-11
* [PATCH] Configurable NODES_SHIFTYasunori Goto2006-04-11
* [PATCH] Don't pass boot parameters to argv_init[]OGAWA Hirofumi2006-03-31
* [PATCH] for_each_possible_cpu: shKAMEZAWA Hiroyuki2006-03-31
* [PATCH] RTC: Remove some duplicate BCD definitionsMatt Mackall2006-03-28
* [PATCH] RTC: Fix up some RTC whitespace and styleMatt Mackall2006-03-28
* [PATCH] RTC: Remove RTC UIP synchronization on SH MPC1211Matt Mackall2006-03-28
* [PATCH] RTC: Remove RTC UIP synchronization on SH03Matt Mackall2006-03-28
* [PATCH] unify PFN_* macrosDave Hansen2006-03-27
* [PATCH] bitops: sh: use generic bitopsAkinobu Mita2006-03-26
* Merge master.kernel.org:/pub/scm/linux/kernel/git/sam/kbuildLinus Torvalds2006-03-25
|\
| * kbuild: change kbuild to not rely on incorrect GNU make behaviorPaul Smith2006-03-05
* | [PATCH] kill include/linux/platform.h, default_idle() cleanupAdrian Bunk2006-03-24
* | [PATCH] more for_each_cpu() conversionsAndrew Morton2006-03-23
* | [PATCH] hugepage: is_aligned_hugepage_range() cleanupDavid Gibson2006-03-22
* | [PATCH] remove set_page_count() outside mm/Nick Piggin2006-03-22
* | [PATCH] mm: split highorder pagesNick Piggin2006-03-22
* | [PATCH] arch/sh/Kconfig: don't source non-existing Kconfig filesAdrian Bunk2006-03-09
|/
* [PATCH] arch/sh/Kconfig: fix the ISA_DMA_API dependenciesAdrian Bunk2006-02-17
* [PATCH] sh: lvalues abuse in arch/sh/boards/renesas/rts7751r2d/io.cAl Viro2006-02-08
* [PATCH] sh: machine_halt()/machine_power_off() cleanupsPaul Mundt2006-02-01
* [PATCH] sh: Add missing timers directory rule to buildPaul Mundt2006-02-01
* [PATCH] sh: convert voyagergx to platform device, drop sh-busPaul Mundt2006-02-01
* [PATCH] sh: drop maskpos from make_ipr_irq(), remove duplicate irq definitionsPaul Mundt2006-02-01
* [PATCH] sh: unknown mach-type updatesPaul Mundt2006-02-01
* [PATCH] sh: Cleanup struct sh_cpuinfo for clock framework changesPaul Mundt2006-02-01
* [PATCH] sh: Move TRA/EXPEVT/INTEVT definitions for reusePaul Mundt2006-02-01
* [PATCH] sh: Make peripheral clock frequency setting mandatoryPaul Mundt2006-02-01
* [PATCH] sh: SH4-202 microdev updatesPaul Mundt2006-02-01
* [PATCH] sh: Move CPU subtype configuration to its own KconfigPaul Mundt2006-01-17
* [PATCH] sh: Simple timer frameworkPaul Mundt2006-01-17
* [PATCH] sh: Simplistic clock frameworkPaul Mundt2006-01-17
* [PATCH] sh: I/O routine cleanups and ioremap() overhaulPaul Mundt2006-01-17
* [PATCH] sh: IRQ handler updatesPaul Mundt2006-01-17
* [PATCH] sh: kexec() supportkogiidena2006-01-17
* [PATCH] sh: DMA updatesPaul Mundt2006-01-17
* [PATCH] sh: consolidate hp620/hp680/hp690 targets into hp6xxPaul Mundt2006-01-17
* [PATCH] Add sh_bus_type probe and remove methodsRussell King2006-01-13
* [PATCH] sh: task_stack_page()Al Viro2006-01-12
* [PATCH] sh: task_thread_info()Al Viro2006-01-12
* [PATCH] sh: task_pt_regs()Al Viro2006-01-12
* [PATCH] dump_thread() cleanupakpm@osdl.org2006-01-10
* [PATCH] tiny: Make *[ug]id16 support optionalMatt Mackall2006-01-08
* [PATCH] sched: resched and cpu_idle reworkNick Piggin2005-11-09
* [PATCH] sched: disable preempt in idle tasksNick Piggin2005-11-09
* [PATCH] consolidate sys_ptrace()Christoph Hellwig2005-11-07
* [PATCH] sh: Use pfn_valid() for lazy dcache write-back on SH7705Paul Mundt2005-11-07
* [PATCH] sh: Drop hp690 discontig supportPaul Mundt2005-11-07
* [PATCH] sh: SuperHyway support for SH4-202Paul Mundt2005-11-07
* [PATCH] sh: Drop deprecated support for custom ramdisk embeddingPaul Mundt2005-11-07
>22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375






































































































                                                                             



                                                                             


























                                                                                









                                                                              
                                     
               
                                                       
            
                                                         
 
                                       

                   






















                                                                                




























                                                                       



                                                              




                                                                 




                                                                    




                                            
                                         
                                   
                                      




























                                                                         
                                


                            
                                                           




























































                                                                                   
                        
                              

                           
                                                                          


















                                                      


                            


                                                      
                                                      
         
/*
 * Functions related to sysfs handling
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bio.h>
#include <linux/blkdev.h>
#include <linux/blktrace_api.h>

#include "blk.h"

struct queue_sysfs_entry {
	struct attribute attr;
	ssize_t (*show)(struct request_queue *, char *);
	ssize_t (*store)(struct request_queue *, const char *, size_t);
};

static ssize_t
queue_var_show(unsigned int var, char *page)
{
	return sprintf(page, "%d\n", var);
}

static ssize_t
queue_var_store(unsigned long *var, const char *page, size_t count)
{
	char *p = (char *) page;

	*var = simple_strtoul(p, &p, 10);
	return count;
}

static ssize_t queue_requests_show(struct request_queue *q, char *page)
{
	return queue_var_show(q->nr_requests, (page));
}

static ssize_t
queue_requests_store(struct request_queue *q, const char *page, size_t count)
{
	struct request_list *rl = &q->rq;
	unsigned long nr;
	int ret = queue_var_store(&nr, page, count);
	if (nr < BLKDEV_MIN_RQ)
		nr = BLKDEV_MIN_RQ;

	spin_lock_irq(q->queue_lock);
	q->nr_requests = nr;
	blk_queue_congestion_threshold(q);

	if (rl->count[READ] >= queue_congestion_on_threshold(q))
		blk_set_queue_congested(q, READ);
	else if (rl->count[READ] < queue_congestion_off_threshold(q))
		blk_clear_queue_congested(q, READ);

	if (rl->count[WRITE] >= queue_congestion_on_threshold(q))
		blk_set_queue_congested(q, WRITE);
	else if (rl->count[WRITE] < queue_congestion_off_threshold(q))
		blk_clear_queue_congested(q, WRITE);

	if (rl->count[READ] >= q->nr_requests) {
		blk_set_queue_full(q, READ);
	} else if (rl->count[READ]+1 <= q->nr_requests) {
		blk_clear_queue_full(q, READ);
		wake_up(&rl->wait[READ]);
	}

	if (rl->count[WRITE] >= q->nr_requests) {
		blk_set_queue_full(q, WRITE);
	} else if (rl->count[WRITE]+1 <= q->nr_requests) {
		blk_clear_queue_full(q, WRITE);
		wake_up(&rl->wait[WRITE]);
	}
	spin_unlock_irq(q->queue_lock);
	return ret;
}

static ssize_t queue_ra_show(struct request_queue *q, char *page)
{
	int ra_kb = q->backing_dev_info.ra_pages << (PAGE_CACHE_SHIFT - 10);

	return queue_var_show(ra_kb, (page));
}

static ssize_t
queue_ra_store(struct request_queue *q, const char *page, size_t count)
{
	unsigned long ra_kb;
	ssize_t ret = queue_var_store(&ra_kb, page, count);

	spin_lock_irq(q->queue_lock);
	q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
	spin_unlock_irq(q->queue_lock);

	return ret;
}

static ssize_t queue_max_sectors_show(struct request_queue *q, char *page)
{
	int max_sectors_kb = q->max_sectors >> 1;

	return queue_var_show(max_sectors_kb, (page));
}

static ssize_t queue_hw_sector_size_show(struct request_queue *q, char *page)
{
	return queue_var_show(q->hardsect_size, page);
}

static ssize_t
queue_max_sectors_store(struct request_queue *q, const char *page, size_t count)
{
	unsigned long max_sectors_kb,
			max_hw_sectors_kb = q->max_hw_sectors >> 1,
			page_kb = 1 << (PAGE_CACHE_SHIFT - 10);
	ssize_t ret = queue_var_store(&max_sectors_kb, page, count);

	if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb)
		return -EINVAL;
	/*
	 * Take the queue lock to update the readahead and max_sectors
	 * values synchronously:
	 */
	spin_lock_irq(q->queue_lock);
	q->max_sectors = max_sectors_kb << 1;
	spin_unlock_irq(q->queue_lock);

	return ret;
}

static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page)
{
	int max_hw_sectors_kb = q->max_hw_sectors >> 1;

	return queue_var_show(max_hw_sectors_kb, (page));
}

static ssize_t queue_nomerges_show(struct request_queue *q, char *page)
{
	return queue_var_show(blk_queue_nomerges(q), page);
}

static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
				    size_t count)
{
	unsigned long nm;
	ssize_t ret = queue_var_store(&nm, page, count);

	spin_lock_irq(q->queue_lock);
	if (nm)
		queue_flag_set(QUEUE_FLAG_NOMERGES, q);
	else
		queue_flag_clear(QUEUE_FLAG_NOMERGES, q);

	spin_unlock_irq(q->queue_lock);
	return ret;
}

static ssize_t queue_rq_affinity_show(struct request_queue *q, char *page)
{
	unsigned int set = test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags);

	return queue_var_show(set != 0, page);
}

static ssize_t
queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count)
{
	ssize_t ret = -EINVAL;
#if defined(CONFIG_USE_GENERIC_SMP_HELPERS)
	unsigned long val;

	ret = queue_var_store(&val, page, count);
	spin_lock_irq(q->queue_lock);
	if (val)
		queue_flag_set(QUEUE_FLAG_SAME_COMP, q);
	else
		queue_flag_clear(QUEUE_FLAG_SAME_COMP,  q);
	spin_unlock_irq(q->queue_lock);
#endif
	return ret;
}

static struct queue_sysfs_entry queue_requests_entry = {
	.attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR },
	.show = queue_requests_show,
	.store = queue_requests_store,
};

static struct queue_sysfs_entry queue_ra_entry = {
	.attr = {.name = "read_ahead_kb", .mode = S_IRUGO | S_IWUSR },
	.show = queue_ra_show,
	.store = queue_ra_store,
};

static struct queue_sysfs_entry queue_max_sectors_entry = {
	.attr = {.name = "max_sectors_kb", .mode = S_IRUGO | S_IWUSR },
	.show = queue_max_sectors_show,
	.store = queue_max_sectors_store,
};

static struct queue_sysfs_entry queue_max_hw_sectors_entry = {
	.attr = {.name = "max_hw_sectors_kb", .mode = S_IRUGO },
	.show = queue_max_hw_sectors_show,
};

static struct queue_sysfs_entry queue_iosched_entry = {
	.attr = {.name = "scheduler", .mode = S_IRUGO | S_IWUSR },
	.show = elv_iosched_show,
	.store = elv_iosched_store,
};

static struct queue_sysfs_entry queue_hw_sector_size_entry = {
	.attr = {.name = "hw_sector_size", .mode = S_IRUGO },
	.show = queue_hw_sector_size_show,
};

static struct queue_sysfs_entry queue_nomerges_entry = {
	.attr = {.name = "nomerges", .mode = S_IRUGO | S_IWUSR },
	.show = queue_nomerges_show,
	.store = queue_nomerges_store,
};

static struct queue_sysfs_entry queue_rq_affinity_entry = {
	.attr = {.name = "rq_affinity", .mode = S_IRUGO | S_IWUSR },
	.show = queue_rq_affinity_show,
	.store = queue_rq_affinity_store,
};

static struct attribute *default_attrs[] = {
	&queue_requests_entry.attr,
	&queue_ra_entry.attr,
	&queue_max_hw_sectors_entry.attr,
	&queue_max_sectors_entry.attr,
	&queue_iosched_entry.attr,
	&queue_hw_sector_size_entry.attr,
	&queue_nomerges_entry.attr,
	&queue_rq_affinity_entry.attr,
	NULL,
};

#define to_queue(atr) container_of((atr), struct queue_sysfs_entry, attr)

static ssize_t
queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{
	struct queue_sysfs_entry *entry = to_queue(attr);
	struct request_queue *q =
		container_of(kobj, struct request_queue, kobj);
	ssize_t res;

	if (!entry->show)
		return -EIO;
	mutex_lock(&q->sysfs_lock);
	if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
		mutex_unlock(&q->sysfs_lock);
		return -ENOENT;
	}
	res = entry->show(q, page);
	mutex_unlock(&q->sysfs_lock);
	return res;
}

static ssize_t
queue_attr_store(struct kobject *kobj, struct attribute *attr,
		    const char *page, size_t length)
{
	struct queue_sysfs_entry *entry = to_queue(attr);
	struct request_queue *q;
	ssize_t res;

	if (!entry->store)
		return -EIO;

	q = container_of(kobj, struct request_queue, kobj);
	mutex_lock(&q->sysfs_lock);
	if (test_bit(QUEUE_FLAG_DEAD, &q->queue_flags)) {
		mutex_unlock(&q->sysfs_lock);
		return -ENOENT;
	}
	res = entry->store(q, page, length);
	mutex_unlock(&q->sysfs_lock);
	return res;
}

/**
 * blk_cleanup_queue: - release a &struct request_queue when it is no longer needed
 * @kobj:    the kobj belonging of the request queue to be released
 *
 * Description:
 *     blk_cleanup_queue is the pair to blk_init_queue() or
 *     blk_queue_make_request().  It should be called when a request queue is
 *     being released; typically when a block device is being de-registered.
 *     Currently, its primary task it to free all the &struct request
 *     structures that were allocated to the queue and the queue itself.
 *
 * Caveat:
 *     Hopefully the low level driver will have finished any
 *     outstanding requests first...
 **/
static void blk_release_queue(struct kobject *kobj)
{
	struct request_queue *q =
		container_of(kobj, struct request_queue, kobj);
	struct request_list *rl = &q->rq;

	blk_sync_queue(q);

	if (rl->rq_pool)
		mempool_destroy(rl->rq_pool);

	if (q->queue_tags)
		__blk_queue_free_tags(q);

	blk_trace_shutdown(q);

	bdi_destroy(&q->backing_dev_info);
	kmem_cache_free(blk_requestq_cachep, q);
}

static struct sysfs_ops queue_sysfs_ops = {
	.show	= queue_attr_show,
	.store	= queue_attr_store,
};

struct kobj_type blk_queue_ktype = {
	.sysfs_ops	= &queue_sysfs_ops,
	.default_attrs	= default_attrs,
	.release	= blk_release_queue,
};

int blk_register_queue(struct gendisk *disk)
{
	int ret;

	struct request_queue *q = disk->queue;

	if (WARN_ON(!q))
		return -ENXIO;

	if (!q->request_fn)
		return 0;

	ret = kobject_add(&q->kobj, kobject_get(&disk_to_dev(disk)->kobj),
			  "%s", "queue");
	if (ret < 0)
		return ret;

	kobject_uevent(&q->kobj, KOBJ_ADD);

	ret = elv_register_queue(q);
	if (ret) {
		kobject_uevent(&q->kobj, KOBJ_REMOVE);
		kobject_del(&q->kobj);
		return ret;
	}

	return 0;
}

void blk_unregister_queue(struct gendisk *disk)
{
	struct request_queue *q = disk->queue;

	if (WARN_ON(!q))
		return;

	if (q->request_fn) {
		elv_unregister_queue(q);

		kobject_uevent(&q->kobj, KOBJ_REMOVE);
		kobject_del(&q->kobj);
		kobject_put(&disk_to_dev(disk)->kobj);
	}
}