aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/hpfb.c
blob: abd920a663a04a2fbbfd8446c1183af83ebf7228 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
/*
 *	HP300 Topcat framebuffer support (derived from macfb of all things)
 *	Phil Blundell <philb@gnu.org> 1998
 *	DIO-II, colour map and Catseye support by
 *	Kars de Jong <jongk@linux-m68k.org>, May 2004.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/tty.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/fb.h>
#include <linux/dio.h>

#include <asm/io.h>
#include <asm/uaccess.h>

static struct fb_info fb_info = {
	.fix = {
		.id		= "HP300 ",
		.type		= FB_TYPE_PACKED_PIXELS,
		.visual		= FB_VISUAL_PSEUDOCOLOR,
		.accel		= FB_ACCEL_NONE,
	}
};

static unsigned long fb_regs;
static unsigned char fb_bitmask;

#define TC_NBLANK	0x4080
#define TC_WEN		0x4088
#define TC_REN		0x408c
#define TC_FBEN		0x4090
#define TC_PRR		0x40ea

/* These defines match the X window system */
#define RR_CLEAR	0x0
#define RR_COPY		0x3
#define RR_NOOP		0x5
#define RR_XOR		0x6
#define RR_INVERT	0xa
#define RR_COPYINVERTED 0xc
#define RR_SET		0xf

/* blitter regs */
#define BUSY		0x4044
#define WMRR		0x40ef
#define SOURCE_X	0x40f2
#define SOURCE_Y	0x40f6
#define DEST_X		0x40fa
#define DEST_Y		0x40fe
#define WHEIGHT		0x4106
#define WWIDTH		0x4102
#define WMOVE		0x409c

static struct fb_var_screeninfo hpfb_defined = {
	.red		= {
		.length = 8,
	},
	.green		= {
		.length = 8,
	},
	.blue		= {
		.length = 8,
	},
	.activate	= FB_ACTIVATE_NOW,
	.height		= -1,
	.width		= -1,
	.vmode		= FB_VMODE_NONINTERLACED,
};

static int hpfb_setcolreg(unsigned regno, unsigned red, unsigned green,
			  unsigned blue, unsigned transp,
			  struct fb_info *info)
{
	/* use MSBs */
	unsigned char _red  =red>>8;
	unsigned char _green=green>>8;
	unsigned char _blue =blue>>8;
	unsigned char _regno=regno;

	/*
	 *  Set a single color register. The values supplied are
	 *  already rounded down to the hardware's capabilities
	 *  (according to the entries in the `var' structure). Return
	 *  != 0 for invalid regno.
	 */

	if (regno >= info->cmap.len)
		return 1;
	
	while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);

	out_be16(fb_regs + 0x60ba, 0xff);

	out_be16(fb_regs + 0x60b2, _red);
	out_be16(fb_regs + 0x60b4, _green);
	out_be16(fb_regs + 0x60b6, _blue);
	out_be16(fb_regs + 0x60b8, ~_regno);
	out_be16(fb_regs + 0x60f0, 0xff);

	udelay(100);

	while (in_be16(fb_regs + 0x6002) & 0x4) udelay(1);
	out_be16(fb_regs + 0x60b2, 0);
	out_be16(fb_regs + 0x60b4, 0);
	out_be16(fb_regs + 0x60b6, 0);
	out_be16(fb_regs + 0x60b8, 0);

	return 0;
}

/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */

static int hpfb_blank(int blank, struct fb_info *info)
{
	out_8(fb_regs + TC_NBLANK, (blank ? 0x00 : fb_bitmask));

	return 0;
}

static void topcat_blit(int x0, int y0, int x1, int y1, int w, int h, int rr)
{
	if (rr >= 0) {
		while (in_8(fb_regs + BUSY) & fb_bitmask)
			;
	}
	out_8(fb_regs + TC_FBEN, fb_bitmask);
	if (rr >= 0) {
		out_8(fb_regs + TC_WEN, fb_bitmask);
		out_8(fb_regs + WMRR, rr);
	}
	out_be16(fb_regs + SOURCE_X, x0);
	out_be16(fb_regs + SOURCE_Y, y0);
	out_be16(fb_regs + DEST_X, x1);
	out_be16(fb_regs + DEST_Y, y1);
	out_be16(fb_regs + WWIDTH, w);
	out_be16(fb_regs + WHEIGHT, h);
	out_8(fb_regs + WMOVE, fb_bitmask);
}

static void hpfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
{
	topcat_blit(area->sx, area->sy, area->dx, area->dy, area->width, area->height, RR_COPY);
}

static void hpfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
{
	u8 clr;

	clr = region->color & 0xff;

	while (in_8(fb_regs + BUSY) & fb_bitmask)
		;

	/* Foreground */
	out_8(fb_regs + TC_WEN, fb_bitmask & clr);
	out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_SET : RR_INVERT));

	/* Background */
	out_8(fb_regs + TC_WEN, fb_bitmask & ~clr);
	out_8(fb_regs + WMRR, (region->rop == ROP_COPY ? RR_CLEAR : RR_NOOP));

	topcat_blit(region->dx, region->dy, region->dx, region->dy, region->width, region->height, -1);
}

static int hpfb_sync(struct fb_info *info)
{
	/*
	 * Since we also access the framebuffer directly, we have to wait
	 * until the block mover is finished
	 */
	while (in_8(fb_regs + BUSY) & fb_bitmask)
		;

	out_8(fb_regs + TC_WEN, fb_bitmask);
	out_8(fb_regs + TC_PRR, RR_COPY);
	out_8(fb_regs + TC_FBEN, fb_bitmask);

	return 0;
}

static struct fb_ops hpfb_ops = {
	.owner		= THIS_MODULE,
	.fb_setcolreg	= hpfb_setcolreg,
	.fb_blank	= hpfb_blank,
	.fb_fillrect	= hpfb_fillrect,
	.fb_copyarea	= hpfb_copyarea,
	.fb_imageblit	= cfb_imageblit,
	.fb_sync	= hpfb_sync,
};

/* Common to all HP framebuffers */
#define HPFB_FBWMSB	0x05	/* Frame buffer width 		*/
#define HPFB_FBWLSB	0x07
#define HPFB_FBHMSB	0x09	/* Frame buffer height		*/
#define HPFB_FBHLSB	0x0b
#define HPFB_DWMSB	0x0d	/* Display width		*/
#define HPFB_DWLSB	0x0f
#define HPFB_DHMSB	0x11	/* Display height		*/
#define HPFB_DHLSB	0x13
#define HPFB_NUMPLANES	0x5b	/* Number of colour planes	*/
#define HPFB_FBOMSB	0x5d	/* Frame buffer offset		*/
#define HPFB_FBOLSB	0x5f

static int __init hpfb_init_one(unsigned long phys_base, unsigned long virt_base)
{
	unsigned long fboff, fb_width, fb_height, fb_start;

	fb_regs = virt_base;
	fboff = (in_8(fb_regs + HPFB_FBOMSB) << 8) | in_8(fb_regs + HPFB_FBOLSB);

	fb_info.fix.smem_start = (in_8(fb_regs + fboff) << 16);

	if (phys_base >= DIOII_BASE) {
		fb_info.fix.smem_start += phys_base;
	}

	if (DIO_SECID(fb_regs) != DIO_ID2_TOPCAT) {
		/* This is the magic incantation the HP X server uses to make Catseye boards work. */
		while (in_be16(fb_regs+0x4800) & 1)
			;
		out_be16(fb_regs+0x4800, 0);	/* Catseye status */
		out_be16(fb_regs+0x4510, 0);	/* VB */
		out_be16(fb_regs+0x4512, 0);	/* TCNTRL */
		out_be16(fb_regs+0x4514, 0);	/* ACNTRL */
		out_be16(fb_regs+0x4516, 0);	/* PNCNTRL */
		out_be16(fb_regs+0x4206, 0x90);	/* RUG Command/Status */
		out_be16(fb_regs+0x60a2, 0);	/* Overlay Mask */
		out_be16(fb_regs+0x60bc, 0);	/* Ram Select */
	}

	/*
	 *	Fill in the available video resolution
	 */
	fb_width = (in_8(fb_regs + HPFB_FBWMSB) << 8) | in_8(fb_regs + HPFB_FBWLSB);
	fb_info.fix.line_length = fb_width;
	fb_height = (in_8(fb_regs + HPFB_FBHMSB) << 8) | in_8(fb_regs + HPFB_FBHLSB);
	fb_info.fix.smem_len = fb_width * fb_height;
	fb_start = (unsigned long)ioremap_writethrough(fb_info.fix.smem_start,
						       fb_info.fix.smem_len);
	hpfb_defined.xres = (in_8(fb_regs + HPFB_DWMSB) << 8) | in_8(fb_regs + HPFB_DWLSB);
	hpfb_defined.yres = (in_8(fb_regs + HPFB_DHMSB) << 8) | in_8(fb_regs + HPFB_DHLSB);
	hpfb_defined.xres_virtual = hpfb_defined.xres;
	hpfb_defined.yres_virtual = hpfb_defined.yres;
	hpfb_defined.bits_per_pixel = in_8(fb_regs + HPFB_NUMPLANES);

	printk(KERN_INFO "hpfb: framebuffer at 0x%lx, mapped to 0x%lx, size %dk\n",
	       fb_info.fix.smem_start, fb_start, fb_info.fix.smem_len/1024);
	printk(KERN_INFO "hpfb: mode is %dx%dx%d, linelength=%d\n",
	       hpfb_defined.xres, hpfb_defined.yres, hpfb_defined.bits_per_pixel, fb_info.fix.line_length);

	/*
	 *	Give the hardware a bit of a prod and work out how many bits per
	 *	pixel are supported.
	 */
	out_8(fb_regs + TC_WEN, 0xff);
	out_8(fb_regs + TC_PRR, RR_COPY);
	out_8(fb_regs + TC_FBEN, 0xff);
	out_8(fb_start, 0xff);
	fb_bitmask = in_8(fb_start);
	out_8(fb_start, 0);

	/*
	 *	Enable reading/writing of all the planes.
	 */
	out_8(fb_regs + TC_WEN, fb_bitmask);
	out_8(fb_regs + TC_PRR, RR_COPY);
	out_8(fb_regs + TC_REN, fb_bitmask);
	out_8(fb_regs + TC_FBEN, fb_bitmask);

	/*
	 *	Clear the screen.
	 */
	topcat_blit(0, 0, 0, 0, fb_width, fb_height, RR_CLEAR);

	/*
	 *	Let there be consoles..
	 */
	if (DIO_SECID(fb_regs) == DIO_ID2_TOPCAT)
		strcat(fb_info.fix.id, "Topcat");
	else
		strcat(fb_info.fix.id, "Catseye");
	fb_info.fbops = &hpfb_ops;
	fb_info.flags = FBINFO_DEFAULT;
	fb_info.var   = hpfb_defined;
	fb_info.screen_base = (char *)fb_start;

	fb_alloc_cmap(&fb_info.cmap, 1 << hpfb_defined.bits_per_pixel, 0);

	if (register_framebuffer(&fb_info) < 0) {
		fb_dealloc_cmap(&fb_info.cmap);
		return 1;
	}

	printk(KERN_INFO "fb%d: %s frame buffer device\n",
	       fb_info.node, fb_info.fix.id);

	return 0;
}

/* 
 * Check that the secondary ID indicates that we have some hope of working with this
 * framebuffer.  The catseye boards are pretty much like topcats and we can muddle through.
 */

#define topcat_sid_ok(x)  (((x) == DIO_ID2_LRCATSEYE) || ((x) == DIO_ID2_HRCCATSEYE)    \
			   || ((x) == DIO_ID2_HRMCATSEYE) || ((x) == DIO_ID2_TOPCAT))

/* 
 * Initialise the framebuffer
 */
static int __devinit hpfb_dio_probe(struct dio_dev * d, const struct dio_device_id * ent)
{
	unsigned long paddr, vaddr;

	paddr = d->resource.start;
	if (!request_mem_region(d->resource.start, d->resource.end - d->resource.start, d->name))
                return -EBUSY;

	if (d->scode >= DIOII_SCBASE) {
		vaddr = (unsigned long)ioremap(paddr, d->resource.end - d->resource.start);
	} else {
		vaddr = paddr + DIO_VIRADDRBASE;
	}
	printk(KERN_INFO "Topcat found at DIO select code %d "
	       "(secondary id %02x)\n", d->scode, (d->id >> 8) & 0xff);
	if (hpfb_init_one(paddr, vaddr)) {
		if (d->scode >= DIOII_SCBASE)
			iounmap((void *)vaddr);
		return -ENOMEM;
	}
	return 0;
}

static void __devexit hpfb_remove_one(struct dio_dev *d)
{
	unregister_framebuffer(&fb_info);
	if (d->scode >= DIOII_SCBASE)
		iounmap((void *)fb_regs);
        release_mem_region(d->resource.start, d->resource.end - d->resource.start);
}

static struct dio_device_id hpfb_dio_tbl[] = {
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_LRCATSEYE) },
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRCCATSEYE) },
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_HRMCATSEYE) },
    { DIO_ENCODE_ID(DIO_ID_FBUFFER, DIO_ID2_TOPCAT) },
    { 0 }
};

static struct dio_driver hpfb_driver = {
    .name      = "hpfb",
    .id_table  = hpfb_dio_tbl,
    .probe     = hpfb_dio_probe,
    .remove    = __devexit_p(hpfb_remove_one),
};

int __init hpfb_init(void)
{
	unsigned int sid;
	mm_segment_t fs;
	unsigned char i;
	int err;

	/* Topcats can be on the internal IO bus or real DIO devices.
	 * The internal variant sits at 0x560000; it has primary
	 * and secondary ID registers just like the DIO version.
	 * So we merge the two detection routines.
	 *
	 * Perhaps this #define should be in a global header file:
	 * I believe it's common to all internal fbs, not just topcat.
	 */
#define INTFBVADDR 0xf0560000
#define INTFBPADDR 0x560000

	if (!MACH_IS_HP300)
		return -ENXIO;

	if (fb_get_options("hpfb", NULL))
		return -ENODEV;

	err = dio_register_driver(&hpfb_driver);
	if (err)
		return err;

	fs = get_fs();
	set_fs(KERNEL_DS);
	err = get_user(i, (unsigned char *)INTFBVADDR + DIO_IDOFF);
	set_fs(fs);

	if (!err && (i == DIO_ID_FBUFFER) && topcat_sid_ok(sid = DIO_SECID(INTFBVADDR))) {
		if (!request_mem_region(INTFBPADDR, DIO_DEVSIZE, "Internal Topcat"))
			return -EBUSY;
		printk(KERN_INFO "Internal Topcat found (secondary id %02x)\n", sid);
		if (hpfb_init_one(INTFBPADDR, INTFBVADDR)) {
			return -ENOMEM;
		}
	}
	return 0;
}

void __exit hpfb_cleanup_module(void)
{
	dio_unregister_driver(&hpfb_driver);
}

module_init(hpfb_init);
module_exit(hpfb_cleanup_module);

MODULE_LICENSE("GPL");
>/* * fscache cached network filesystem type * - name, version and ops must be filled in before registration * - all other fields will be set during registration */ struct fscache_netfs { uint32_t version; /* indexing version */ const char *name; /* filesystem name */ struct fscache_cookie *primary_index; struct list_head link; /* internal link */ }; /* * slow-path functions for when there is actually caching available, and the * netfs does actually have a valid token * - these are not to be called directly * - these are undefined symbols when FS-Cache is not configured and the * optimiser takes care of not using them */ extern int __fscache_register_netfs(struct fscache_netfs *); extern void __fscache_unregister_netfs(struct fscache_netfs *); extern struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *); extern void __fscache_release_cache_tag(struct fscache_cache_tag *); extern struct fscache_cookie *__fscache_acquire_cookie( struct fscache_cookie *, const struct fscache_cookie_def *, void *); extern void __fscache_relinquish_cookie(struct fscache_cookie *, int); extern void __fscache_update_cookie(struct fscache_cookie *); extern int __fscache_attr_changed(struct fscache_cookie *); extern int __fscache_read_or_alloc_page(struct fscache_cookie *, struct page *, fscache_rw_complete_t, void *, gfp_t); extern int __fscache_read_or_alloc_pages(struct fscache_cookie *, struct address_space *, struct list_head *, unsigned *, fscache_rw_complete_t, void *, gfp_t); extern int __fscache_alloc_page(struct fscache_cookie *, struct page *, gfp_t); extern int __fscache_write_page(struct fscache_cookie *, struct page *, gfp_t); extern void __fscache_uncache_page(struct fscache_cookie *, struct page *); extern bool __fscache_check_page_write(struct fscache_cookie *, struct page *); extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *); extern bool __fscache_maybe_release_page(struct fscache_cookie *, struct page *, gfp_t); extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *, struct inode *); /** * fscache_register_netfs - Register a filesystem as desiring caching services * @netfs: The description of the filesystem * * Register a filesystem as desiring caching services if they're available. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_register_netfs(struct fscache_netfs *netfs) { if (fscache_available()) return __fscache_register_netfs(netfs); else return 0; } /** * fscache_unregister_netfs - Indicate that a filesystem no longer desires * caching services * @netfs: The description of the filesystem * * Indicate that a filesystem no longer desires caching services for the * moment. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_unregister_netfs(struct fscache_netfs *netfs) { if (fscache_available()) __fscache_unregister_netfs(netfs); } /** * fscache_lookup_cache_tag - Look up a cache tag * @name: The name of the tag to search for * * Acquire a specific cache referral tag that can be used to select a specific * cache in which to cache an index. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name) { if (fscache_available()) return __fscache_lookup_cache_tag(name); else return NULL; } /** * fscache_release_cache_tag - Release a cache tag * @tag: The tag to release * * Release a reference to a cache referral tag previously looked up. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_release_cache_tag(struct fscache_cache_tag *tag) { if (fscache_available()) __fscache_release_cache_tag(tag); } /** * fscache_acquire_cookie - Acquire a cookie to represent a cache object * @parent: The cookie that's to be the parent of this one * @def: A description of the cache object, including callback operations * @netfs_data: An arbitrary piece of data to be kept in the cookie to * represent the cache object to the netfs * * This function is used to inform FS-Cache about part of an index hierarchy * that can be used to locate files. This is done by requesting a cookie for * each index in the path to the file. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline struct fscache_cookie *fscache_acquire_cookie( struct fscache_cookie *parent, const struct fscache_cookie_def *def, void *netfs_data) { if (fscache_cookie_valid(parent)) return __fscache_acquire_cookie(parent, def, netfs_data); else return NULL; } /** * fscache_relinquish_cookie - Return the cookie to the cache, maybe discarding * it * @cookie: The cookie being returned * @retire: True if the cache object the cookie represents is to be discarded * * This function returns a cookie to the cache, forcibly discarding the * associated cache object if retire is set to true. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_relinquish_cookie(struct fscache_cookie *cookie, int retire) { if (fscache_cookie_valid(cookie)) __fscache_relinquish_cookie(cookie, retire); } /** * fscache_update_cookie - Request that a cache object be updated * @cookie: The cookie representing the cache object * * Request an update of the index data for the cache object associated with the * cookie. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_update_cookie(struct fscache_cookie *cookie) { if (fscache_cookie_valid(cookie)) __fscache_update_cookie(cookie); } /** * fscache_pin_cookie - Pin a data-storage cache object in its cache * @cookie: The cookie representing the cache object * * Permit data-storage cache objects to be pinned in the cache. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_pin_cookie(struct fscache_cookie *cookie) { return -ENOBUFS; } /** * fscache_pin_cookie - Unpin a data-storage cache object in its cache * @cookie: The cookie representing the cache object * * Permit data-storage cache objects to be unpinned from the cache. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_unpin_cookie(struct fscache_cookie *cookie) { } /** * fscache_attr_changed - Notify cache that an object's attributes changed * @cookie: The cookie representing the cache object * * Send a notification to the cache indicating that an object's attributes have * changed. This includes the data size. These attributes will be obtained * through the get_attr() cookie definition op. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_attr_changed(struct fscache_cookie *cookie) { if (fscache_cookie_valid(cookie)) return __fscache_attr_changed(cookie); else return -ENOBUFS; } /** * fscache_reserve_space - Reserve data space for a cached object * @cookie: The cookie representing the cache object * @i_size: The amount of space to be reserved * * Reserve an amount of space in the cache for the cache object attached to a * cookie so that a write to that object within the space can always be * honoured. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size) { return -ENOBUFS; } /** * fscache_read_or_alloc_page - Read a page from the cache or allocate a block * in which to store it * @cookie: The cookie representing the cache object * @page: The netfs page to fill if possible * @end_io_func: The callback to invoke when and if the page is filled * @context: An arbitrary piece of data to pass on to end_io_func() * @gfp: The conditions under which memory allocation should be made * * Read a page from the cache, or if that's not possible make a potential * one-block reservation in the cache into which the page may be stored once * fetched from the server. * * If the page is not backed by the cache object, or if it there's some reason * it can't be, -ENOBUFS will be returned and nothing more will be done for * that page. * * Else, if that page is backed by the cache, a read will be initiated directly * to the netfs's page and 0 will be returned by this function. The * end_io_func() callback will be invoked when the operation terminates on a * completion or failure. Note that the callback may be invoked before the * return. * * Else, if the page is unbacked, -ENODATA is returned and a block may have * been allocated in the cache. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_read_or_alloc_page(struct fscache_cookie *cookie, struct page *page, fscache_rw_complete_t end_io_func, void *context, gfp_t gfp) { if (fscache_cookie_valid(cookie)) return __fscache_read_or_alloc_page(cookie, page, end_io_func, context, gfp); else return -ENOBUFS; } /** * fscache_read_or_alloc_pages - Read pages from the cache and/or allocate * blocks in which to store them * @cookie: The cookie representing the cache object * @mapping: The netfs inode mapping to which the pages will be attached * @pages: A list of potential netfs pages to be filled * @nr_pages: Number of pages to be read and/or allocated * @end_io_func: The callback to invoke when and if each page is filled * @context: An arbitrary piece of data to pass on to end_io_func() * @gfp: The conditions under which memory allocation should be made * * Read a set of pages from the cache, or if that's not possible, attempt to * make a potential one-block reservation for each page in the cache into which * that page may be stored once fetched from the server. * * If some pages are not backed by the cache object, or if it there's some * reason they can't be, -ENOBUFS will be returned and nothing more will be * done for that pages. * * Else, if some of the pages are backed by the cache, a read will be initiated * directly to the netfs's page and 0 will be returned by this function. The * end_io_func() callback will be invoked when the operation terminates on a * completion or failure. Note that the callback may be invoked before the * return. * * Else, if a page is unbacked, -ENODATA is returned and a block may have * been allocated in the cache. * * Because the function may want to return all of -ENOBUFS, -ENODATA and 0 in * regard to different pages, the return values are prioritised in that order. * Any pages submitted for reading are removed from the pages list. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_read_or_alloc_pages(struct fscache_cookie *cookie, struct address_space *mapping, struct list_head *pages, unsigned *nr_pages, fscache_rw_complete_t end_io_func, void *context, gfp_t gfp) { if (fscache_cookie_valid(cookie)) return __fscache_read_or_alloc_pages(cookie, mapping, pages, nr_pages, end_io_func, context, gfp); else return -ENOBUFS; } /** * fscache_alloc_page - Allocate a block in which to store a page * @cookie: The cookie representing the cache object * @page: The netfs page to allocate a page for * @gfp: The conditions under which memory allocation should be made * * Request Allocation a block in the cache in which to store a netfs page * without retrieving any contents from the cache. * * If the page is not backed by a file then -ENOBUFS will be returned and * nothing more will be done, and no reservation will be made. * * Else, a block will be allocated if one wasn't already, and 0 will be * returned * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_alloc_page(struct fscache_cookie *cookie, struct page *page, gfp_t gfp) { if (fscache_cookie_valid(cookie)) return __fscache_alloc_page(cookie, page, gfp); else return -ENOBUFS; } /** * fscache_write_page - Request storage of a page in the cache * @cookie: The cookie representing the cache object * @page: The netfs page to store * @gfp: The conditions under which memory allocation should be made * * Request the contents of the netfs page be written into the cache. This * request may be ignored if no cache block is currently allocated, in which * case it will return -ENOBUFS. * * If a cache block was already allocated, a write will be initiated and 0 will * be returned. The PG_fscache_write page bit is set immediately and will then * be cleared at the completion of the write to indicate the success or failure * of the operation. Note that the completion may happen before the return. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline int fscache_write_page(struct fscache_cookie *cookie, struct page *page, gfp_t gfp) { if (fscache_cookie_valid(cookie)) return __fscache_write_page(cookie, page, gfp); else return -ENOBUFS; } /** * fscache_uncache_page - Indicate that caching is no longer required on a page * @cookie: The cookie representing the cache object * @page: The netfs page that was being cached. * * Tell the cache that we no longer want a page to be cached and that it should * remove any knowledge of the netfs page it may have. * * Note that this cannot cancel any outstanding I/O operations between this * page and the cache. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_uncache_page(struct fscache_cookie *cookie, struct page *page) { if (fscache_cookie_valid(cookie)) __fscache_uncache_page(cookie, page); } /** * fscache_check_page_write - Ask if a page is being writing to the cache * @cookie: The cookie representing the cache object * @page: The netfs page that is being cached. * * Ask the cache if a page is being written to the cache. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline bool fscache_check_page_write(struct fscache_cookie *cookie, struct page *page) { if (fscache_cookie_valid(cookie)) return __fscache_check_page_write(cookie, page); return false; } /** * fscache_wait_on_page_write - Wait for a page to complete writing to the cache * @cookie: The cookie representing the cache object * @page: The netfs page that is being cached. * * Ask the cache to wake us up when a page is no longer being written to the * cache. * * See Documentation/filesystems/caching/netfs-api.txt for a complete * description. */ static inline void fscache_wait_on_page_write(struct fscache_cookie *cookie, struct page *page) { if (fscache_cookie_valid(cookie)) __fscache_wait_on_page_write(cookie, page); } /** * fscache_maybe_release_page - Consider releasing a page, cancelling a store * @cookie: The cookie representing the cache object * @page: The netfs page that is being cached. * @gfp: The gfp flags passed to releasepage() * * Consider releasing a page for the vmscan algorithm, on behalf of the netfs's * releasepage() call. A storage request on the page may cancelled if it is * not currently being processed. * * The function returns true if the page no longer has a storage request on it, * and false if a storage request is left in place. If true is returned, the * page will have been passed to fscache_uncache_page(). If false is returned * the page cannot be freed yet. */ static inline bool fscache_maybe_release_page(struct fscache_cookie *cookie, struct page *page, gfp_t gfp) { if (fscache_cookie_valid(cookie) && PageFsCache(page)) return __fscache_maybe_release_page(cookie, page, gfp); return false; } /** * fscache_uncache_all_inode_pages - Uncache all an inode's pages * @cookie: The cookie representing the inode's cache object. * @inode: The inode to uncache pages from. * * Uncache all the pages in an inode that are marked PG_fscache, assuming them * to be associated with the given cookie. * * This function may sleep. It will wait for pages that are being written out * and will wait whilst the PG_fscache mark is removed by the cache. */ static inline void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, struct inode *inode) { if (fscache_cookie_valid(cookie)) __fscache_uncache_all_inode_pages(cookie, inode); } #endif /* _LINUX_FSCACHE_H */