Blame view

drivers/firmware/dell_rbu.c 19.1 KB
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
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
  /*
   * dell_rbu.c
   * Bios Update driver for Dell systems
   * Author: Dell Inc
   *         Abhay Salunke <abhay_salunke@dell.com>
   *
   * Copyright (C) 2005 Dell Inc.
   *
   * Remote BIOS Update (rbu) driver is used for updating DELL BIOS by
   * creating entries in the /sys file systems on Linux 2.6 and higher
   * kernels. The driver supports two mechanism to update the BIOS namely
   * contiguous and packetized. Both these methods still require having some
   * application to set the CMOS bit indicating the BIOS to update itself
   * after a reboot.
   *
   * Contiguous method:
   * This driver writes the incoming data in a monolithic image by allocating
   * contiguous physical pages large enough to accommodate the incoming BIOS
   * image size.
   *
   * Packetized method:
   * The driver writes the incoming packet image by allocating a new packet
   * on every time the packet data is written. This driver requires an
   * application to break the BIOS image in to fixed sized packet chunks.
   *
   * See Documentation/dell_rbu.txt for more info.
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License v2.0 as published by
   * the Free Software Foundation
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   */
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
37
38
  #include <linux/init.h>
  #include <linux/module.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
40
41
42
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/blkdev.h>
d052d1bef   Russell King   Create platform_d...
43
  #include <linux/platform_device.h>
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
44
45
46
47
48
49
50
51
  #include <linux/spinlock.h>
  #include <linux/moduleparam.h>
  #include <linux/firmware.h>
  #include <linux/dma-mapping.h>
  
  MODULE_AUTHOR("Abhay Salunke <abhay_salunke@dell.com>");
  MODULE_DESCRIPTION("Driver for updating BIOS image on DELL systems");
  MODULE_LICENSE("GPL");
2c5608404   Abhay Salunke   [PATCH] dell_rbu:...
52
  MODULE_VERSION("3.2");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
53
54
55
56
57
58
59
60
61
62
63
  
  #define BIOS_SCAN_LIMIT 0xffffffff
  #define MAX_IMAGE_LENGTH 16
  static struct _rbu_data {
  	void *image_update_buffer;
  	unsigned long image_update_buffer_size;
  	unsigned long bios_image_size;
  	int image_update_ordernum;
  	int dma_alloc;
  	spinlock_t lock;
  	unsigned long packet_read_count;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
64
65
  	unsigned long num_packets;
  	unsigned long packetsize;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
66
  	unsigned long imagesize;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
67
  	int entry_created;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
68
  } rbu_data;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
69
70
  static char image_type[MAX_IMAGE_LENGTH + 1] = "mono";
  module_param_string(image_type, image_type, sizeof (image_type), 0);
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
71
72
  MODULE_PARM_DESC(image_type,
  	"BIOS image type. choose- mono or packet or init");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
73

274b69335   Abhay Salunke   [PATCH] dell_rbu:...
74
75
76
77
  static unsigned long allocation_floor = 0x100000;
  module_param(allocation_floor, ulong, 0644);
  MODULE_PARM_DESC(allocation_floor,
      "Minimum address for allocations when using Packet mode");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
78
79
80
81
82
83
84
85
86
87
88
89
  struct packet_data {
  	struct list_head list;
  	size_t length;
  	void *data;
  	int ordernum;
  };
  
  static struct packet_data packet_data_head;
  
  static struct platform_device *rbu_device;
  static int context;
  static dma_addr_t dell_rbu_dmaaddr;
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
90
  static void init_packet_head(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
91
92
  {
  	INIT_LIST_HEAD(&packet_data_head.list);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
93
94
95
  	rbu_data.packet_read_count = 0;
  	rbu_data.num_packets = 0;
  	rbu_data.packetsize = 0;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
96
  	rbu_data.imagesize = 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
97
  }
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
98
  static int create_packet(void *data, size_t length)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
99
100
101
  {
  	struct packet_data *newpacket;
  	int ordernum = 0;
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
102
103
  	int retval = 0;
  	unsigned int packet_array_size = 0;
5ad9201be   Al Viro   [PATCH] dell_rbu:...
104
105
  	void **invalid_addr_packet_array = NULL;
  	void *packet_data_temp_buf = NULL;
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
106
  	unsigned int idx = 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
107
108
109
110
111
112
113
  
  	pr_debug("create_packet: entry 
  ");
  
  	if (!rbu_data.packetsize) {
  		pr_debug("create_packet: packetsize not specified
  ");
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
114
115
  		retval = -EINVAL;
  		goto out_noalloc;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
116
  	}
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
117

e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
118
  	spin_unlock(&rbu_data.lock);
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
119
120
  
  	newpacket = kzalloc(sizeof (struct packet_data), GFP_KERNEL);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
121

6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
122
123
  	if (!newpacket) {
  		printk(KERN_WARNING
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
124
  			"dell_rbu:%s: failed to allocate new "
eecd58536   Harvey Harrison   firmware: replace...
125
126
  			"packet
  ", __func__);
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
127
128
129
  		retval = -ENOMEM;
  		spin_lock(&rbu_data.lock);
  		goto out_noalloc;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
130
131
132
  	}
  
  	ordernum = get_order(length);
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
133

6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
134
  	/*
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
135
136
137
138
139
140
141
142
143
  	 * BIOS errata mean we cannot allocate packets below 1MB or they will
  	 * be overwritten by BIOS.
  	 *
  	 * array to temporarily hold packets
  	 * that are below the allocation floor
  	 *
  	 * NOTE: very simplistic because we only need the floor to be at 1MB
  	 *       due to BIOS errata. This shouldn't be used for higher floors
  	 *       or you will run out of mem trying to allocate the array.
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
144
  	 */
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
145
146
147
148
149
  	packet_array_size = max(
  	       		(unsigned int)(allocation_floor / rbu_data.packetsize),
  			(unsigned int)1);
  	invalid_addr_packet_array = kzalloc(packet_array_size * sizeof(void*),
  						GFP_KERNEL);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
150

274b69335   Abhay Salunke   [PATCH] dell_rbu:...
151
  	if (!invalid_addr_packet_array) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
152
  		printk(KERN_WARNING
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
153
154
155
  			"dell_rbu:%s: failed to allocate "
  			"invalid_addr_packet_array 
  ",
eecd58536   Harvey Harrison   firmware: replace...
156
  			__func__);
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
157
158
159
  		retval = -ENOMEM;
  		spin_lock(&rbu_data.lock);
  		goto out_alloc_packet;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
160
  	}
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
161
162
163
164
165
166
  	while (!packet_data_temp_buf) {
  		packet_data_temp_buf = (unsigned char *)
  			__get_free_pages(GFP_KERNEL, ordernum);
  		if (!packet_data_temp_buf) {
  			printk(KERN_WARNING
  				"dell_rbu:%s: failed to allocate new "
eecd58536   Harvey Harrison   firmware: replace...
167
168
  				"packet
  ", __func__);
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
169
170
171
172
173
174
175
176
177
178
179
180
181
  			retval = -ENOMEM;
  			spin_lock(&rbu_data.lock);
  			goto out_alloc_packet_array;
  		}
  
  		if ((unsigned long)virt_to_phys(packet_data_temp_buf)
  				< allocation_floor) {
  			pr_debug("packet 0x%lx below floor at 0x%lx.
  ",
  					(unsigned long)virt_to_phys(
  						packet_data_temp_buf),
  					allocation_floor);
  			invalid_addr_packet_array[idx++] = packet_data_temp_buf;
5ad9201be   Al Viro   [PATCH] dell_rbu:...
182
  			packet_data_temp_buf = NULL;
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
183
184
185
186
187
188
189
190
191
192
193
194
  		}
  	}
  	spin_lock(&rbu_data.lock);
  
  	newpacket->data = packet_data_temp_buf;
  
  	pr_debug("create_packet: newpacket at physical addr %lx
  ",
  		(unsigned long)virt_to_phys(newpacket->data));
  
  	/* packets may not have fixed size */
  	newpacket->length = length;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
195
196
  	newpacket->ordernum = ordernum;
  	++rbu_data.num_packets;
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
197
198
  
  	/* initialize the newly created packet headers */
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
199
200
  	INIT_LIST_HEAD(&newpacket->list);
  	list_add_tail(&newpacket->list, &packet_data_head.list);
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
201
202
  
  	memcpy(newpacket->data, data, length);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
203
204
205
  
  	pr_debug("create_packet: exit 
  ");
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  out_alloc_packet_array:
  	/* always free packet array */
  	for (;idx>0;idx--) {
  		pr_debug("freeing unused packet below floor 0x%lx.
  ",
  			(unsigned long)virt_to_phys(
  				invalid_addr_packet_array[idx-1]));
  		free_pages((unsigned long)invalid_addr_packet_array[idx-1],
  			ordernum);
  	}
  	kfree(invalid_addr_packet_array);
  
  out_alloc_packet:
  	/* if error, free data */
  	if (retval)
  		kfree(newpacket);
  
  out_noalloc:
  	return retval;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
225
  }
c6c1c94e8   Greg Kroah-Hartman   dell_rbu: firmwar...
226
  static int packetize_data(const u8 *data, size_t length)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
227
228
  {
  	int rc = 0;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
229
230
231
232
  	int done = 0;
  	int packet_length;
  	u8 *temp;
  	u8 *end = (u8 *) data + length;
cb7cf57a6   Zach Brown   [PATCH] pr_debug:...
233
234
  	pr_debug("packetize_data: data length %zd
  ", length);
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
235
236
237
238
239
240
  	if (!rbu_data.packetsize) {
  		printk(KERN_WARNING
  			"dell_rbu: packetsize not specified
  ");
  		return -EIO;
  	}
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
241

ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
242
243
244
245
246
247
248
249
250
251
252
253
254
  	temp = (u8 *) data;
  
  	/* packetize the hunk */
  	while (!done) {
  		if ((temp + rbu_data.packetsize) < end)
  			packet_length = rbu_data.packetsize;
  		else {
  			/* this is the last packet */
  			packet_length = end - temp;
  			done = 1;
  		}
  
  		if ((rc = create_packet(temp, packet_length)))
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
255
  			return rc;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
256

9e42ef777   Andrew Morton   [PATCH] dell_rbu:...
257
258
  		pr_debug("%p:%td
  ", temp, (end - temp));
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
259
  		temp += packet_length;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
260
  	}
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
261
262
  
  	rbu_data.imagesize = length;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
263
264
265
  
  	return rc;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
266
  static int do_packet_read(char *data, struct list_head *ptemp_list,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
267
  	int length, int bytes_read, int *list_read_count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
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
  {
  	void *ptemp_buf;
  	struct packet_data *newpacket = NULL;
  	int bytes_copied = 0;
  	int j = 0;
  
  	newpacket = list_entry(ptemp_list, struct packet_data, list);
  	*list_read_count += newpacket->length;
  
  	if (*list_read_count > bytes_read) {
  		/* point to the start of unread data */
  		j = newpacket->length - (*list_read_count - bytes_read);
  		/* point to the offset in the packet buffer */
  		ptemp_buf = (u8 *) newpacket->data + j;
  		/*
  		 * check if there is enough room in
  		 * * the incoming buffer
  		 */
  		if (length > (*list_read_count - bytes_read))
  			/*
  			 * copy what ever is there in this
  			 * packet and move on
  			 */
  			bytes_copied = (*list_read_count - bytes_read);
  		else
  			/* copy the remaining */
  			bytes_copied = length;
  		memcpy(data, ptemp_buf, bytes_copied);
  	}
  	return bytes_copied;
  }
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
299
  static int packet_read_list(char *data, size_t * pread_length)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
  {
  	struct list_head *ptemp_list;
  	int temp_count = 0;
  	int bytes_copied = 0;
  	int bytes_read = 0;
  	int remaining_bytes = 0;
  	char *pdest = data;
  
  	/* check if we have any packets */
  	if (0 == rbu_data.num_packets)
  		return -ENOMEM;
  
  	remaining_bytes = *pread_length;
  	bytes_read = rbu_data.packet_read_count;
  
  	ptemp_list = (&packet_data_head.list)->next;
  	while (!list_empty(ptemp_list)) {
  		bytes_copied = do_packet_read(pdest, ptemp_list,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
318
  			remaining_bytes, bytes_read, &temp_count);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
  		remaining_bytes -= bytes_copied;
  		bytes_read += bytes_copied;
  		pdest += bytes_copied;
  		/*
  		 * check if we reached end of buffer before reaching the
  		 * last packet
  		 */
  		if (remaining_bytes == 0)
  			break;
  
  		ptemp_list = ptemp_list->next;
  	}
  	/*finally set the bytes read */
  	*pread_length = bytes_read - rbu_data.packet_read_count;
  	rbu_data.packet_read_count = bytes_read;
  	return 0;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
336
  static void packet_empty_list(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
337
338
339
340
341
342
343
344
  {
  	struct list_head *ptemp_list;
  	struct list_head *pnext_list;
  	struct packet_data *newpacket;
  
  	ptemp_list = (&packet_data_head.list)->next;
  	while (!list_empty(ptemp_list)) {
  		newpacket =
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
345
  			list_entry(ptemp_list, struct packet_data, list);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
346
347
348
349
350
351
352
353
  		pnext_list = ptemp_list->next;
  		list_del(ptemp_list);
  		ptemp_list = pnext_list;
  		/*
  		 * zero out the RBU packet memory before freeing
  		 * to make sure there are no stale RBU packets left in memory
  		 */
  		memset(newpacket->data, 0, rbu_data.packetsize);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
354
355
  		free_pages((unsigned long) newpacket->data,
  			newpacket->ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
356
357
  		kfree(newpacket);
  	}
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
358
359
  	rbu_data.packet_read_count = 0;
  	rbu_data.num_packets = 0;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
360
  	rbu_data.imagesize = 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
361
362
363
364
365
366
  }
  
  /*
   * img_update_free: Frees the buffer allocated for storing BIOS image
   * Always called with lock held and returned with lock held
   */
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
367
  static void img_update_free(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
368
369
370
371
372
373
374
375
  {
  	if (!rbu_data.image_update_buffer)
  		return;
  	/*
  	 * zero out this buffer before freeing it to get rid of any stale
  	 * BIOS image copied in memory.
  	 */
  	memset(rbu_data.image_update_buffer, 0,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
376
  		rbu_data.image_update_buffer_size);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
377
378
  	if (rbu_data.dma_alloc == 1)
  		dma_free_coherent(NULL, rbu_data.bios_image_size,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
379
  			rbu_data.image_update_buffer, dell_rbu_dmaaddr);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
380
  	else
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
381
382
  		free_pages((unsigned long) rbu_data.image_update_buffer,
  			rbu_data.image_update_ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  
  	/*
  	 * Re-initialize the rbu_data variables after a free
  	 */
  	rbu_data.image_update_ordernum = -1;
  	rbu_data.image_update_buffer = NULL;
  	rbu_data.image_update_buffer_size = 0;
  	rbu_data.bios_image_size = 0;
  	rbu_data.dma_alloc = 0;
  }
  
  /*
   * img_update_realloc: This function allocates the contiguous pages to
   * accommodate the requested size of data. The memory address and size
   * values are stored globally and on every call to this function the new
   * size is checked to see if more data is required than the existing size.
   * If true the previous memory is freed and new allocation is done to
   * accommodate the new size. If the incoming size is less then than the
   * already allocated size, then that memory is reused. This function is
   * called with lock held and returns with lock held.
   */
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
404
  static int img_update_realloc(unsigned long size)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  {
  	unsigned char *image_update_buffer = NULL;
  	unsigned long rc;
  	unsigned long img_buf_phys_addr;
  	int ordernum;
  	int dma_alloc = 0;
  
  	/*
  	 * check if the buffer of sufficient size has been
  	 * already allocated
  	 */
  	if (rbu_data.image_update_buffer_size >= size) {
  		/*
  		 * check for corruption
  		 */
  		if ((size != 0) && (rbu_data.image_update_buffer == NULL)) {
  			printk(KERN_ERR "dell_rbu:%s: corruption "
eecd58536   Harvey Harrison   firmware: replace...
422
423
  				"check failed
  ", __func__);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  			return -EINVAL;
  		}
  		/*
  		 * we have a valid pre-allocated buffer with
  		 * sufficient size
  		 */
  		return 0;
  	}
  
  	/*
  	 * free any previously allocated buffer
  	 */
  	img_update_free();
  
  	spin_unlock(&rbu_data.lock);
  
  	ordernum = get_order(size);
  	image_update_buffer =
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
442
  		(unsigned char *) __get_free_pages(GFP_KERNEL, ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
443
444
  
  	img_buf_phys_addr =
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
445
  		(unsigned long) virt_to_phys(image_update_buffer);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
446
447
  
  	if (img_buf_phys_addr > BIOS_SCAN_LIMIT) {
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
448
  		free_pages((unsigned long) image_update_buffer, ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
449
450
  		ordernum = -1;
  		image_update_buffer = dma_alloc_coherent(NULL, size,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
451
  			&dell_rbu_dmaaddr, GFP_KERNEL);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
452
453
454
455
456
457
458
459
460
  		dma_alloc = 1;
  	}
  
  	spin_lock(&rbu_data.lock);
  
  	if (image_update_buffer != NULL) {
  		rbu_data.image_update_buffer = image_update_buffer;
  		rbu_data.image_update_buffer_size = size;
  		rbu_data.bios_image_size =
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
461
  			rbu_data.image_update_buffer_size;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
462
463
464
465
466
  		rbu_data.image_update_ordernum = ordernum;
  		rbu_data.dma_alloc = dma_alloc;
  		rc = 0;
  	} else {
  		pr_debug("Not enough memory for image update:"
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
467
468
  			"size = %ld
  ", size);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
469
470
471
472
473
  		rc = -ENOMEM;
  	}
  
  	return rc;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
474
  static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
475
476
477
478
479
  {
  	int retval;
  	size_t bytes_left;
  	size_t data_length;
  	char *ptempBuf = buffer;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
480
481
482
483
484
485
486
487
  
  	/* check to see if we have something to return */
  	if (rbu_data.num_packets == 0) {
  		pr_debug("read_packet_data: no packets written
  ");
  		retval = -ENOMEM;
  		goto read_rbu_data_exit;
  	}
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
488
  	if (pos > rbu_data.imagesize) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
489
490
  		retval = 0;
  		printk(KERN_WARNING "dell_rbu:read_packet_data: "
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
491
492
  			"data underrun
  ");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
493
494
  		goto read_rbu_data_exit;
  	}
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
495
  	bytes_left = rbu_data.imagesize - pos;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
496
497
498
499
  	data_length = min(bytes_left, count);
  
  	if ((retval = packet_read_list(ptempBuf, &data_length)) < 0)
  		goto read_rbu_data_exit;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
500
  	if ((pos + count) > rbu_data.imagesize) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
501
502
503
504
505
506
507
508
509
  		rbu_data.packet_read_count = 0;
  		/* this was the last copy */
  		retval = bytes_left;
  	} else
  		retval = count;
  
        read_rbu_data_exit:
  	return retval;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
510
  static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
511
  {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
512
513
  	/* check to see if we have something to return */
  	if ((rbu_data.image_update_buffer == NULL) ||
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
514
  		(rbu_data.bios_image_size == 0)) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
515
  		pr_debug("read_rbu_data_mono: image_update_buffer %p ,"
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
516
517
518
519
  			"bios_image_size %lu
  ",
  			rbu_data.image_update_buffer,
  			rbu_data.bios_image_size);
25377479d   Akinobu Mita   dell_rbu: use mem...
520
  		return -ENOMEM;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
521
  	}
25377479d   Akinobu Mita   dell_rbu: use mem...
522
523
  	return memory_read_from_buffer(buffer, count, &pos,
  			rbu_data.image_update_buffer, rbu_data.bios_image_size);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
524
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
525
  static ssize_t read_rbu_data(struct file *filp, struct kobject *kobj,
91a690295   Zhang Rui   sysfs: add parame...
526
527
  			     struct bin_attribute *bin_attr,
  			     char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
  {
  	ssize_t ret_count = 0;
  
  	spin_lock(&rbu_data.lock);
  
  	if (!strcmp(image_type, "mono"))
  		ret_count = read_rbu_mono_data(buffer, pos, count);
  	else if (!strcmp(image_type, "packet"))
  		ret_count = read_packet_data(buffer, pos, count);
  	else
  		pr_debug("read_rbu_data: invalid image type specified
  ");
  
  	spin_unlock(&rbu_data.lock);
  	return ret_count;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
544
  static void callbackfn_rbu(const struct firmware *fw, void *context)
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
545
  {
2c5608404   Abhay Salunke   [PATCH] dell_rbu:...
546
  	rbu_data.entry_created = 0;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
547

9ebfbd45f   Johannes Berg   firmware_class: m...
548
  	if (!fw)
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
549
  		return;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
550

9ebfbd45f   Johannes Berg   firmware_class: m...
551
552
  	if (!fw->size)
  		goto out;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
553
554
555
556
557
558
  	spin_lock(&rbu_data.lock);
  	if (!strcmp(image_type, "mono")) {
  		if (!img_update_realloc(fw->size))
  			memcpy(rbu_data.image_update_buffer,
  				fw->data, fw->size);
  	} else if (!strcmp(image_type, "packet")) {
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
559
560
561
562
563
564
565
566
567
568
569
  		/*
  		 * we need to free previous packets if a
  		 * new hunk of packets needs to be downloaded
  		 */
  		packet_empty_list();
  		if (packetize_data(fw->data, fw->size))
  			/* Incase something goes wrong when we are
  			 * in middle of packetizing the data, we
  			 * need to free up whatever packets might
  			 * have been created before we quit.
  			 */
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
570
  			packet_empty_list();
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
571
572
573
574
  	} else
  		pr_debug("invalid image type specified.
  ");
  	spin_unlock(&rbu_data.lock);
9ebfbd45f   Johannes Berg   firmware_class: m...
575
576
   out:
  	release_firmware(fw);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
577
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
578
  static ssize_t read_rbu_image_type(struct file *filp, struct kobject *kobj,
91a690295   Zhang Rui   sysfs: add parame...
579
580
  				   struct bin_attribute *bin_attr,
  				   char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
581
582
583
  {
  	int size = 0;
  	if (!pos)
81156928f   Pavel Roskin   dell_rbu: use scn...
584
585
  		size = scnprintf(buffer, count, "%s
  ", image_type);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
586
587
  	return size;
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
588
  static ssize_t write_rbu_image_type(struct file *filp, struct kobject *kobj,
91a690295   Zhang Rui   sysfs: add parame...
589
590
  				    struct bin_attribute *bin_attr,
  				    char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
591
592
  {
  	int rc = count;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
593
594
  	int req_firm_rc = 0;
  	int i;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
595
  	spin_lock(&rbu_data.lock);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
  	/*
  	 * Find the first newline or space
  	 */
  	for (i = 0; i < count; ++i)
  		if (buffer[i] == '
  ' || buffer[i] == ' ') {
  			buffer[i] = '\0';
  			break;
  		}
  	if (i == count)
  		buffer[count] = '\0';
  
  	if (strstr(buffer, "mono"))
  		strcpy(image_type, "mono");
  	else if (strstr(buffer, "packet"))
  		strcpy(image_type, "packet");
  	else if (strstr(buffer, "init")) {
  		/*
  		 * If due to the user error the driver gets in a bad
  		 * state where even though it is loaded , the
  		 * /sys/class/firmware/dell_rbu entries are missing.
  		 * to cover this situation the user can recreate entries
  		 * by writing init to image_type.
  		 */
  		if (!rbu_data.entry_created) {
  			spin_unlock(&rbu_data.lock);
  			req_firm_rc = request_firmware_nowait(THIS_MODULE,
  				FW_ACTION_NOHOTPLUG, "dell_rbu",
9ebfbd45f   Johannes Berg   firmware_class: m...
624
  				&rbu_device->dev, GFP_KERNEL, &context,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
625
626
627
628
  				callbackfn_rbu);
  			if (req_firm_rc) {
  				printk(KERN_ERR
  					"dell_rbu:%s request_firmware_nowait"
eecd58536   Harvey Harrison   firmware: replace...
629
630
  					" failed %d
  ", __func__, rc);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
631
632
633
634
635
636
637
638
639
640
641
642
  				rc = -EIO;
  			} else
  				rbu_data.entry_created = 1;
  
  			spin_lock(&rbu_data.lock);
  		}
  	} else {
  		printk(KERN_WARNING "dell_rbu: image_type is invalid
  ");
  		spin_unlock(&rbu_data.lock);
  		return -EINVAL;
  	}
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
643
644
645
646
  
  	/* we must free all previous allocations */
  	packet_empty_list();
  	img_update_free();
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
647
  	spin_unlock(&rbu_data.lock);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
648

e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
649
  	return rc;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
650
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
651
  static ssize_t read_rbu_packet_size(struct file *filp, struct kobject *kobj,
91a690295   Zhang Rui   sysfs: add parame...
652
653
  				    struct bin_attribute *bin_attr,
  				    char *buffer, loff_t pos, size_t count)
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
654
655
656
657
  {
  	int size = 0;
  	if (!pos) {
  		spin_lock(&rbu_data.lock);
81156928f   Pavel Roskin   dell_rbu: use scn...
658
659
  		size = scnprintf(buffer, count, "%lu
  ", rbu_data.packetsize);
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
660
661
662
663
  		spin_unlock(&rbu_data.lock);
  	}
  	return size;
  }
2c3c8bea6   Chris Wright   sysfs: add struct...
664
  static ssize_t write_rbu_packet_size(struct file *filp, struct kobject *kobj,
91a690295   Zhang Rui   sysfs: add parame...
665
666
  				     struct bin_attribute *bin_attr,
  				     char *buffer, loff_t pos, size_t count)
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
667
668
669
670
671
672
673
674
675
676
677
  {
  	unsigned long temp;
  	spin_lock(&rbu_data.lock);
  	packet_empty_list();
  	sscanf(buffer, "%lu", &temp);
  	if (temp < 0xffffffff)
  		rbu_data.packetsize = temp;
  
  	spin_unlock(&rbu_data.lock);
  	return count;
  }
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
678
  static struct bin_attribute rbu_data_attr = {
7b595756e   Tejun Heo   sysfs: kill unnec...
679
  	.attr = {.name = "data", .mode = 0444},
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
680
681
682
683
  	.read = read_rbu_data,
  };
  
  static struct bin_attribute rbu_image_type_attr = {
7b595756e   Tejun Heo   sysfs: kill unnec...
684
  	.attr = {.name = "image_type", .mode = 0644},
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
685
686
687
  	.read = read_rbu_image_type,
  	.write = write_rbu_image_type,
  };
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
688
  static struct bin_attribute rbu_packet_size_attr = {
7b595756e   Tejun Heo   sysfs: kill unnec...
689
  	.attr = {.name = "packet_size", .mode = 0644},
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
690
691
692
  	.read = read_rbu_packet_size,
  	.write = write_rbu_packet_size,
  };
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
693
  static int __init dcdrbu_init(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
694
  {
6897083ab   Akinobu Mita   [PATCH] dell_rbu:...
695
  	int rc;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
696
697
698
  	spin_lock_init(&rbu_data.lock);
  
  	init_packet_head();
6897083ab   Akinobu Mita   [PATCH] dell_rbu:...
699
700
  	rbu_device = platform_device_register_simple("dell_rbu", -1, NULL, 0);
  	if (IS_ERR(rbu_device)) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
701
  		printk(KERN_ERR
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
702
  			"dell_rbu:%s:platform_device_register_simple "
eecd58536   Harvey Harrison   firmware: replace...
703
704
  			"failed
  ", __func__);
6897083ab   Akinobu Mita   [PATCH] dell_rbu:...
705
  		return PTR_ERR(rbu_device);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
706
  	}
41bfcfd9a   Jeff Garzik   [PATCH] firmware/...
707
708
709
710
711
712
713
  	rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
  	if (rc)
  		goto out_devreg;
  	rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
  	if (rc)
  		goto out_data;
  	rc = sysfs_create_bin_file(&rbu_device->dev.kobj,
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
714
  		&rbu_packet_size_attr);
41bfcfd9a   Jeff Garzik   [PATCH] firmware/...
715
716
  	if (rc)
  		goto out_imtype;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
717

2c5608404   Abhay Salunke   [PATCH] dell_rbu:...
718
  	rbu_data.entry_created = 0;
41bfcfd9a   Jeff Garzik   [PATCH] firmware/...
719
  	return 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
720

41bfcfd9a   Jeff Garzik   [PATCH] firmware/...
721
722
723
724
725
726
727
  out_imtype:
  	sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
  out_data:
  	sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
  out_devreg:
  	platform_device_unregister(rbu_device);
  	return rc;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
728
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
729
  static __exit void dcdrbu_exit(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
730
731
732
733
734
735
736
737
738
739
  {
  	spin_lock(&rbu_data.lock);
  	packet_empty_list();
  	img_update_free();
  	spin_unlock(&rbu_data.lock);
  	platform_device_unregister(rbu_device);
  }
  
  module_exit(dcdrbu_exit);
  module_init(dcdrbu_init);
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
740
741
742
  
  /* vim:noet:ts=8:sw=8
  */