Blame view

drivers/firmware/dell_rbu.c 19 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
39
40
41
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/string.h>
  #include <linux/errno.h>
  #include <linux/blkdev.h>
d052d1bef   Russell King   Create platform_d...
42
  #include <linux/platform_device.h>
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
43
44
45
46
47
48
49
50
  #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:...
51
  MODULE_VERSION("3.2");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
52
53
54
55
56
57
58
59
60
61
62
  
  #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:...
63
64
  	unsigned long num_packets;
  	unsigned long packetsize;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
65
  	unsigned long imagesize;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
66
  	int entry_created;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
67
  } rbu_data;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
68
69
  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:...
70
71
  MODULE_PARM_DESC(image_type,
  	"BIOS image type. choose- mono or packet or init");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
72

274b69335   Abhay Salunke   [PATCH] dell_rbu:...
73
74
75
76
  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:...
77
78
79
80
81
82
83
84
85
86
87
88
  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 ...
89
  static void init_packet_head(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
90
91
  {
  	INIT_LIST_HEAD(&packet_data_head.list);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
92
93
94
  	rbu_data.packet_read_count = 0;
  	rbu_data.num_packets = 0;
  	rbu_data.packetsize = 0;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
95
  	rbu_data.imagesize = 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
96
  }
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
97
  static int create_packet(void *data, size_t length)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
98
99
100
  {
  	struct packet_data *newpacket;
  	int ordernum = 0;
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
101
102
  	int retval = 0;
  	unsigned int packet_array_size = 0;
5ad9201be   Al Viro   [PATCH] dell_rbu:...
103
104
  	void **invalid_addr_packet_array = NULL;
  	void *packet_data_temp_buf = NULL;
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
105
  	unsigned int idx = 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
106
107
108
109
110
111
112
  
  	pr_debug("create_packet: entry 
  ");
  
  	if (!rbu_data.packetsize) {
  		pr_debug("create_packet: packetsize not specified
  ");
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
113
114
  		retval = -EINVAL;
  		goto out_noalloc;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
115
  	}
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
116

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

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

6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
133
  	/*
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
134
135
136
137
138
139
140
141
142
  	 * 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:...
143
  	 */
274b69335   Abhay Salunke   [PATCH] dell_rbu:...
144
145
146
147
148
  	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:...
149

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

ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
241
242
243
244
245
246
247
248
249
250
251
252
253
  	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:...
254
  			return rc;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
255

9e42ef777   Andrew Morton   [PATCH] dell_rbu:...
256
257
  		pr_debug("%p:%td
  ", temp, (end - temp));
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
258
  		temp += packet_length;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
259
  	}
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
260
261
  
  	rbu_data.imagesize = length;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
262
263
264
  
  	return rc;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
265
  static int do_packet_read(char *data, struct list_head *ptemp_list,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
266
  	int length, int bytes_read, int *list_read_count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
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
  {
  	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:...
298
  static int packet_read_list(char *data, size_t * pread_length)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  {
  	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:...
317
  			remaining_bytes, bytes_read, &temp_count);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
  		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 ...
335
  static void packet_empty_list(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
336
337
338
339
340
341
342
343
  {
  	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:...
344
  			list_entry(ptemp_list, struct packet_data, list);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
345
346
347
348
349
350
351
352
  		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:...
353
354
  		free_pages((unsigned long) newpacket->data,
  			newpacket->ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
355
356
  		kfree(newpacket);
  	}
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
357
358
  	rbu_data.packet_read_count = 0;
  	rbu_data.num_packets = 0;
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
359
  	rbu_data.imagesize = 0;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
360
361
362
363
364
365
  }
  
  /*
   * 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 ...
366
  static void img_update_free(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
367
368
369
370
371
372
373
374
  {
  	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:...
375
  		rbu_data.image_update_buffer_size);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
376
377
  	if (rbu_data.dma_alloc == 1)
  		dma_free_coherent(NULL, rbu_data.bios_image_size,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
378
  			rbu_data.image_update_buffer, dell_rbu_dmaaddr);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
379
  	else
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
380
381
  		free_pages((unsigned long) rbu_data.image_update_buffer,
  			rbu_data.image_update_ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
  
  	/*
  	 * 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 ...
403
  static int img_update_realloc(unsigned long size)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  {
  	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...
421
422
  				"check failed
  ", __func__);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
  			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:...
441
  		(unsigned char *) __get_free_pages(GFP_KERNEL, ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
442
443
  
  	img_buf_phys_addr =
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
444
  		(unsigned long) virt_to_phys(image_update_buffer);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
445
446
  
  	if (img_buf_phys_addr > BIOS_SCAN_LIMIT) {
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
447
  		free_pages((unsigned long) image_update_buffer, ordernum);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
448
449
  		ordernum = -1;
  		image_update_buffer = dma_alloc_coherent(NULL, size,
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
450
  			&dell_rbu_dmaaddr, GFP_KERNEL);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
451
452
453
454
455
456
457
458
459
  		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:...
460
  			rbu_data.image_update_buffer_size;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
461
462
463
464
465
  		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:...
466
467
  			"size = %ld
  ", size);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
468
469
470
471
472
  		rc = -ENOMEM;
  	}
  
  	return rc;
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
473
  static ssize_t read_packet_data(char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
474
475
476
477
478
  {
  	int retval;
  	size_t bytes_left;
  	size_t data_length;
  	char *ptempBuf = buffer;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
479
480
481
482
483
484
485
486
  
  	/* 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:...
487
  	if (pos > rbu_data.imagesize) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
488
489
  		retval = 0;
  		printk(KERN_WARNING "dell_rbu:read_packet_data: "
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
490
491
  			"data underrun
  ");
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
492
493
  		goto read_rbu_data_exit;
  	}
ad6ce87e5   Abhay Salunke   [PATCH] dell_rbu:...
494
  	bytes_left = rbu_data.imagesize - pos;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
495
496
497
498
  	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:...
499
  	if ((pos + count) > rbu_data.imagesize) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
500
501
502
503
504
505
506
507
508
  		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 ...
509
  static ssize_t read_rbu_mono_data(char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
510
  {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
511
512
  	/* check to see if we have something to return */
  	if ((rbu_data.image_update_buffer == NULL) ||
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
513
  		(rbu_data.bios_image_size == 0)) {
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
514
  		pr_debug("read_rbu_data_mono: image_update_buffer %p ,"
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
515
516
517
518
  			"bios_image_size %lu
  ",
  			rbu_data.image_update_buffer,
  			rbu_data.bios_image_size);
25377479d   Akinobu Mita   dell_rbu: use mem...
519
  		return -ENOMEM;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
520
  	}
25377479d   Akinobu Mita   dell_rbu: use mem...
521
522
  	return memory_read_from_buffer(buffer, count, &pos,
  			rbu_data.image_update_buffer, rbu_data.bios_image_size);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
523
  }
91a690295   Zhang Rui   sysfs: add parame...
524
525
526
  static ssize_t read_rbu_data(struct kobject *kobj,
  			     struct bin_attribute *bin_attr,
  			     char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
  {
  	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 ...
543
  static void callbackfn_rbu(const struct firmware *fw, void *context)
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
544
  {
2c5608404   Abhay Salunke   [PATCH] dell_rbu:...
545
  	rbu_data.entry_created = 0;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
546

2c5608404   Abhay Salunke   [PATCH] dell_rbu:...
547
  	if (!fw || !fw->size)
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
548
  		return;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
549
550
551
552
553
554
555
  
  	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:...
556
557
558
559
560
561
562
563
564
565
566
  		/*
  		 * 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:...
567
  			packet_empty_list();
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
568
569
570
571
  	} else
  		pr_debug("invalid image type specified.
  ");
  	spin_unlock(&rbu_data.lock);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
572
  }
91a690295   Zhang Rui   sysfs: add parame...
573
574
575
  static ssize_t read_rbu_image_type(struct kobject *kobj,
  				   struct bin_attribute *bin_attr,
  				   char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
576
577
578
  {
  	int size = 0;
  	if (!pos)
81156928f   Pavel Roskin   dell_rbu: use scn...
579
580
  		size = scnprintf(buffer, count, "%s
  ", image_type);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
581
582
  	return size;
  }
91a690295   Zhang Rui   sysfs: add parame...
583
584
585
  static ssize_t write_rbu_image_type(struct kobject *kobj,
  				    struct bin_attribute *bin_attr,
  				    char *buffer, loff_t pos, size_t count)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
586
587
  {
  	int rc = count;
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
588
589
  	int req_firm_rc = 0;
  	int i;
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
590
  	spin_lock(&rbu_data.lock);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
591
592
593
594
595
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",
  				&rbu_device->dev, &context,
  				callbackfn_rbu);
  			if (req_firm_rc) {
  				printk(KERN_ERR
  					"dell_rbu:%s request_firmware_nowait"
eecd58536   Harvey Harrison   firmware: replace...
624
625
  					" failed %d
  ", __func__, rc);
e61c0e336   Abhay Salunke   [PATCH] dell_rbu:...
626
627
628
629
630
631
632
633
634
635
636
637
  				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:...
638
639
640
641
  
  	/* we must free all previous allocations */
  	packet_empty_list();
  	img_update_free();
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
642
  	spin_unlock(&rbu_data.lock);
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
643

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

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

41bfcfd9a   Jeff Garzik   [PATCH] firmware/...
716
717
718
719
720
721
722
  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:...
723
  }
dda8577fb   Andrew Morton   [PATCH] dell_rbu ...
724
  static __exit void dcdrbu_exit(void)
6c54c28e6   Abhay Salunke   [PATCH] dell_rbu:...
725
726
727
728
729
730
731
732
733
734
  {
  	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:...
735
736
737
  
  /* vim:noet:ts=8:sw=8
  */