1eb4f98d5SKalle Valo static int prism2_enable_aux_port(struct net_device *dev, int enable)
2eb4f98d5SKalle Valo {
3eb4f98d5SKalle Valo 	u16 val, reg;
4eb4f98d5SKalle Valo 	int i, tries;
5eb4f98d5SKalle Valo 	unsigned long flags;
6eb4f98d5SKalle Valo 	struct hostap_interface *iface;
7eb4f98d5SKalle Valo 	local_info_t *local;
8eb4f98d5SKalle Valo 
9eb4f98d5SKalle Valo 	iface = netdev_priv(dev);
10eb4f98d5SKalle Valo 	local = iface->local;
11eb4f98d5SKalle Valo 
12eb4f98d5SKalle Valo 	if (local->no_pri) {
13eb4f98d5SKalle Valo 		if (enable) {
14eb4f98d5SKalle Valo 			PDEBUG(DEBUG_EXTRA2, "%s: no PRI f/w - assuming Aux "
15eb4f98d5SKalle Valo 			       "port is already enabled\n", dev->name);
16eb4f98d5SKalle Valo 		}
17eb4f98d5SKalle Valo 		return 0;
18eb4f98d5SKalle Valo 	}
19eb4f98d5SKalle Valo 
20eb4f98d5SKalle Valo 	spin_lock_irqsave(&local->cmdlock, flags);
21eb4f98d5SKalle Valo 
22eb4f98d5SKalle Valo 	/* wait until busy bit is clear */
23eb4f98d5SKalle Valo 	tries = HFA384X_CMD_BUSY_TIMEOUT;
24eb4f98d5SKalle Valo 	while (HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY && tries > 0) {
25eb4f98d5SKalle Valo 		tries--;
26eb4f98d5SKalle Valo 		udelay(1);
27eb4f98d5SKalle Valo 	}
28eb4f98d5SKalle Valo 	if (tries == 0) {
29eb4f98d5SKalle Valo 		reg = HFA384X_INW(HFA384X_CMD_OFF);
30eb4f98d5SKalle Valo 		spin_unlock_irqrestore(&local->cmdlock, flags);
31eb4f98d5SKalle Valo 		printk("%s: prism2_enable_aux_port - timeout - reg=0x%04x\n",
32eb4f98d5SKalle Valo 		       dev->name, reg);
33eb4f98d5SKalle Valo 		return -ETIMEDOUT;
34eb4f98d5SKalle Valo 	}
35eb4f98d5SKalle Valo 
36eb4f98d5SKalle Valo 	val = HFA384X_INW(HFA384X_CONTROL_OFF);
37eb4f98d5SKalle Valo 
38eb4f98d5SKalle Valo 	if (enable) {
39eb4f98d5SKalle Valo 		HFA384X_OUTW(HFA384X_AUX_MAGIC0, HFA384X_PARAM0_OFF);
40eb4f98d5SKalle Valo 		HFA384X_OUTW(HFA384X_AUX_MAGIC1, HFA384X_PARAM1_OFF);
41eb4f98d5SKalle Valo 		HFA384X_OUTW(HFA384X_AUX_MAGIC2, HFA384X_PARAM2_OFF);
42eb4f98d5SKalle Valo 
43eb4f98d5SKalle Valo 		if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_DISABLED)
44eb4f98d5SKalle Valo 			printk("prism2_enable_aux_port: was not disabled!?\n");
45eb4f98d5SKalle Valo 		val &= ~HFA384X_AUX_PORT_MASK;
46eb4f98d5SKalle Valo 		val |= HFA384X_AUX_PORT_ENABLE;
47eb4f98d5SKalle Valo 	} else {
48eb4f98d5SKalle Valo 		HFA384X_OUTW(0, HFA384X_PARAM0_OFF);
49eb4f98d5SKalle Valo 		HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
50eb4f98d5SKalle Valo 		HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
51eb4f98d5SKalle Valo 
52eb4f98d5SKalle Valo 		if ((val & HFA384X_AUX_PORT_MASK) != HFA384X_AUX_PORT_ENABLED)
53eb4f98d5SKalle Valo 			printk("prism2_enable_aux_port: was not enabled!?\n");
54eb4f98d5SKalle Valo 		val &= ~HFA384X_AUX_PORT_MASK;
55eb4f98d5SKalle Valo 		val |= HFA384X_AUX_PORT_DISABLE;
56eb4f98d5SKalle Valo 	}
57eb4f98d5SKalle Valo 	HFA384X_OUTW(val, HFA384X_CONTROL_OFF);
58eb4f98d5SKalle Valo 
59eb4f98d5SKalle Valo 	udelay(5);
60eb4f98d5SKalle Valo 
61eb4f98d5SKalle Valo 	i = 10000;
62eb4f98d5SKalle Valo 	while (i > 0) {
63eb4f98d5SKalle Valo 		val = HFA384X_INW(HFA384X_CONTROL_OFF);
64eb4f98d5SKalle Valo 		val &= HFA384X_AUX_PORT_MASK;
65eb4f98d5SKalle Valo 
66eb4f98d5SKalle Valo 		if ((enable && val == HFA384X_AUX_PORT_ENABLED) ||
67eb4f98d5SKalle Valo 		    (!enable && val == HFA384X_AUX_PORT_DISABLED))
68eb4f98d5SKalle Valo 			break;
69eb4f98d5SKalle Valo 
70eb4f98d5SKalle Valo 		udelay(10);
71eb4f98d5SKalle Valo 		i--;
72eb4f98d5SKalle Valo 	}
73eb4f98d5SKalle Valo 
74eb4f98d5SKalle Valo 	spin_unlock_irqrestore(&local->cmdlock, flags);
75eb4f98d5SKalle Valo 
76eb4f98d5SKalle Valo 	if (i == 0) {
77eb4f98d5SKalle Valo 		printk("prism2_enable_aux_port(%d) timed out\n",
78eb4f98d5SKalle Valo 		       enable);
79eb4f98d5SKalle Valo 		return -ETIMEDOUT;
80eb4f98d5SKalle Valo 	}
81eb4f98d5SKalle Valo 
82eb4f98d5SKalle Valo 	return 0;
83eb4f98d5SKalle Valo }
84eb4f98d5SKalle Valo 
85eb4f98d5SKalle Valo 
86eb4f98d5SKalle Valo static int hfa384x_from_aux(struct net_device *dev, unsigned int addr, int len,
87eb4f98d5SKalle Valo 			    void *buf)
88eb4f98d5SKalle Valo {
89eb4f98d5SKalle Valo 	u16 page, offset;
90eb4f98d5SKalle Valo 	if (addr & 1 || len & 1)
91eb4f98d5SKalle Valo 		return -1;
92eb4f98d5SKalle Valo 
93eb4f98d5SKalle Valo 	page = addr >> 7;
94eb4f98d5SKalle Valo 	offset = addr & 0x7f;
95eb4f98d5SKalle Valo 
96eb4f98d5SKalle Valo 	HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
97eb4f98d5SKalle Valo 	HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
98eb4f98d5SKalle Valo 
99eb4f98d5SKalle Valo 	udelay(5);
100eb4f98d5SKalle Valo 
101eb4f98d5SKalle Valo #ifdef PRISM2_PCI
102eb4f98d5SKalle Valo 	{
103eb4f98d5SKalle Valo 		__le16 *pos = (__le16 *) buf;
104eb4f98d5SKalle Valo 		while (len > 0) {
105eb4f98d5SKalle Valo 			*pos++ = HFA384X_INW_DATA(HFA384X_AUXDATA_OFF);
106eb4f98d5SKalle Valo 			len -= 2;
107eb4f98d5SKalle Valo 		}
108eb4f98d5SKalle Valo 	}
109eb4f98d5SKalle Valo #else /* PRISM2_PCI */
110eb4f98d5SKalle Valo 	HFA384X_INSW(HFA384X_AUXDATA_OFF, buf, len / 2);
111eb4f98d5SKalle Valo #endif /* PRISM2_PCI */
112eb4f98d5SKalle Valo 
113eb4f98d5SKalle Valo 	return 0;
114eb4f98d5SKalle Valo }
115eb4f98d5SKalle Valo 
116eb4f98d5SKalle Valo 
117eb4f98d5SKalle Valo static int hfa384x_to_aux(struct net_device *dev, unsigned int addr, int len,
118eb4f98d5SKalle Valo 			  void *buf)
119eb4f98d5SKalle Valo {
120eb4f98d5SKalle Valo 	u16 page, offset;
121eb4f98d5SKalle Valo 	if (addr & 1 || len & 1)
122eb4f98d5SKalle Valo 		return -1;
123eb4f98d5SKalle Valo 
124eb4f98d5SKalle Valo 	page = addr >> 7;
125eb4f98d5SKalle Valo 	offset = addr & 0x7f;
126eb4f98d5SKalle Valo 
127eb4f98d5SKalle Valo 	HFA384X_OUTW(page, HFA384X_AUXPAGE_OFF);
128eb4f98d5SKalle Valo 	HFA384X_OUTW(offset, HFA384X_AUXOFFSET_OFF);
129eb4f98d5SKalle Valo 
130eb4f98d5SKalle Valo 	udelay(5);
131eb4f98d5SKalle Valo 
132eb4f98d5SKalle Valo #ifdef PRISM2_PCI
133eb4f98d5SKalle Valo 	{
134eb4f98d5SKalle Valo 		__le16 *pos = (__le16 *) buf;
135eb4f98d5SKalle Valo 		while (len > 0) {
136eb4f98d5SKalle Valo 			HFA384X_OUTW_DATA(*pos++, HFA384X_AUXDATA_OFF);
137eb4f98d5SKalle Valo 			len -= 2;
138eb4f98d5SKalle Valo 		}
139eb4f98d5SKalle Valo 	}
140eb4f98d5SKalle Valo #else /* PRISM2_PCI */
141eb4f98d5SKalle Valo 	HFA384X_OUTSW(HFA384X_AUXDATA_OFF, buf, len / 2);
142eb4f98d5SKalle Valo #endif /* PRISM2_PCI */
143eb4f98d5SKalle Valo 
144eb4f98d5SKalle Valo 	return 0;
145eb4f98d5SKalle Valo }
146eb4f98d5SKalle Valo 
147eb4f98d5SKalle Valo 
148eb4f98d5SKalle Valo static int prism2_pda_ok(u8 *buf)
149eb4f98d5SKalle Valo {
150eb4f98d5SKalle Valo 	__le16 *pda = (__le16 *) buf;
151eb4f98d5SKalle Valo 	int pos;
152eb4f98d5SKalle Valo 	u16 len, pdr;
153eb4f98d5SKalle Valo 
154eb4f98d5SKalle Valo 	if (buf[0] == 0xff && buf[1] == 0x00 && buf[2] == 0xff &&
155eb4f98d5SKalle Valo 	    buf[3] == 0x00)
156eb4f98d5SKalle Valo 		return 0;
157eb4f98d5SKalle Valo 
158eb4f98d5SKalle Valo 	pos = 0;
159eb4f98d5SKalle Valo 	while (pos + 1 < PRISM2_PDA_SIZE / 2) {
160eb4f98d5SKalle Valo 		len = le16_to_cpu(pda[pos]);
161eb4f98d5SKalle Valo 		pdr = le16_to_cpu(pda[pos + 1]);
162eb4f98d5SKalle Valo 		if (len == 0 || pos + len > PRISM2_PDA_SIZE / 2)
163eb4f98d5SKalle Valo 			return 0;
164eb4f98d5SKalle Valo 
165eb4f98d5SKalle Valo 		if (pdr == 0x0000 && len == 2) {
166eb4f98d5SKalle Valo 			/* PDA end found */
167eb4f98d5SKalle Valo 			return 1;
168eb4f98d5SKalle Valo 		}
169eb4f98d5SKalle Valo 
170eb4f98d5SKalle Valo 		pos += len + 1;
171eb4f98d5SKalle Valo 	}
172eb4f98d5SKalle Valo 
173eb4f98d5SKalle Valo 	return 0;
174eb4f98d5SKalle Valo }
175eb4f98d5SKalle Valo 
176eb4f98d5SKalle Valo 
177eb4f98d5SKalle Valo #define prism2_download_aux_dump_npages 65536
178eb4f98d5SKalle Valo 
179eb4f98d5SKalle Valo struct prism2_download_aux_dump {
180eb4f98d5SKalle Valo 	local_info_t *local;
181eb4f98d5SKalle Valo 	u16 page[0x80];
182eb4f98d5SKalle Valo };
183eb4f98d5SKalle Valo 
184eb4f98d5SKalle Valo static int prism2_download_aux_dump_proc_show(struct seq_file *m, void *v)
185eb4f98d5SKalle Valo {
186eb4f98d5SKalle Valo 	struct prism2_download_aux_dump *ctx = m->private;
187eb4f98d5SKalle Valo 
188eb4f98d5SKalle Valo 	hfa384x_from_aux(ctx->local->dev, (unsigned long)v - 1, 0x80, ctx->page);
189eb4f98d5SKalle Valo 	seq_write(m, ctx->page, 0x80);
190eb4f98d5SKalle Valo 	return 0;
191eb4f98d5SKalle Valo }
192eb4f98d5SKalle Valo 
193eb4f98d5SKalle Valo static void *prism2_download_aux_dump_proc_start(struct seq_file *m, loff_t *_pos)
194eb4f98d5SKalle Valo {
195eb4f98d5SKalle Valo 	struct prism2_download_aux_dump *ctx = m->private;
196eb4f98d5SKalle Valo 	prism2_enable_aux_port(ctx->local->dev, 1);
197eb4f98d5SKalle Valo 	if (*_pos >= prism2_download_aux_dump_npages)
198eb4f98d5SKalle Valo 		return NULL;
199eb4f98d5SKalle Valo 	return (void *)((unsigned long)*_pos + 1);
200eb4f98d5SKalle Valo }
201eb4f98d5SKalle Valo 
202eb4f98d5SKalle Valo static void *prism2_download_aux_dump_proc_next(struct seq_file *m, void *v, loff_t *_pos)
203eb4f98d5SKalle Valo {
204eb4f98d5SKalle Valo 	++*_pos;
205eb4f98d5SKalle Valo 	if (*_pos >= prism2_download_aux_dump_npages)
206eb4f98d5SKalle Valo 		return NULL;
207eb4f98d5SKalle Valo 	return (void *)((unsigned long)*_pos + 1);
208eb4f98d5SKalle Valo }
209eb4f98d5SKalle Valo 
210eb4f98d5SKalle Valo static void prism2_download_aux_dump_proc_stop(struct seq_file *m, void *v)
211eb4f98d5SKalle Valo {
212eb4f98d5SKalle Valo 	struct prism2_download_aux_dump *ctx = m->private;
213eb4f98d5SKalle Valo 	prism2_enable_aux_port(ctx->local->dev, 0);
214eb4f98d5SKalle Valo }
215eb4f98d5SKalle Valo 
216eb4f98d5SKalle Valo static const struct seq_operations prism2_download_aux_dump_proc_seqops = {
217eb4f98d5SKalle Valo 	.start	= prism2_download_aux_dump_proc_start,
218eb4f98d5SKalle Valo 	.next	= prism2_download_aux_dump_proc_next,
219eb4f98d5SKalle Valo 	.stop	= prism2_download_aux_dump_proc_stop,
220eb4f98d5SKalle Valo 	.show	= prism2_download_aux_dump_proc_show,
221eb4f98d5SKalle Valo };
222eb4f98d5SKalle Valo 
223eb4f98d5SKalle Valo static int prism2_download_aux_dump_proc_open(struct inode *inode, struct file *file)
224eb4f98d5SKalle Valo {
225eb4f98d5SKalle Valo 	int ret = seq_open_private(file, &prism2_download_aux_dump_proc_seqops,
226eb4f98d5SKalle Valo 				   sizeof(struct prism2_download_aux_dump));
227eb4f98d5SKalle Valo 	if (ret == 0) {
228eb4f98d5SKalle Valo 		struct seq_file *m = file->private_data;
229eb4f98d5SKalle Valo 		m->private = PDE_DATA(inode);
230eb4f98d5SKalle Valo 	}
231eb4f98d5SKalle Valo 	return ret;
232eb4f98d5SKalle Valo }
233eb4f98d5SKalle Valo 
234eb4f98d5SKalle Valo static const struct file_operations prism2_download_aux_dump_proc_fops = {
235eb4f98d5SKalle Valo 	.open		= prism2_download_aux_dump_proc_open,
236eb4f98d5SKalle Valo 	.read		= seq_read,
237eb4f98d5SKalle Valo 	.llseek		= seq_lseek,
238eb4f98d5SKalle Valo 	.release	= seq_release_private,
239eb4f98d5SKalle Valo };
240eb4f98d5SKalle Valo 
241eb4f98d5SKalle Valo 
242eb4f98d5SKalle Valo static u8 * prism2_read_pda(struct net_device *dev)
243eb4f98d5SKalle Valo {
244eb4f98d5SKalle Valo 	u8 *buf;
245eb4f98d5SKalle Valo 	int res, i, found = 0;
246eb4f98d5SKalle Valo #define NUM_PDA_ADDRS 4
247eb4f98d5SKalle Valo 	unsigned int pda_addr[NUM_PDA_ADDRS] = {
248eb4f98d5SKalle Valo 		0x7f0000 /* others than HFA3841 */,
249eb4f98d5SKalle Valo 		0x3f0000 /* HFA3841 */,
250eb4f98d5SKalle Valo 		0x390000 /* apparently used in older cards */,
251eb4f98d5SKalle Valo 		0x7f0002 /* Intel PRO/Wireless 2011B (PCI) */,
252eb4f98d5SKalle Valo 	};
253eb4f98d5SKalle Valo 
254eb4f98d5SKalle Valo 	buf = kmalloc(PRISM2_PDA_SIZE, GFP_KERNEL);
255eb4f98d5SKalle Valo 	if (buf == NULL)
256eb4f98d5SKalle Valo 		return NULL;
257eb4f98d5SKalle Valo 
258eb4f98d5SKalle Valo 	/* Note: wlan card should be in initial state (just after init cmd)
259eb4f98d5SKalle Valo 	 * and no other operations should be performed concurrently. */
260eb4f98d5SKalle Valo 
261eb4f98d5SKalle Valo 	prism2_enable_aux_port(dev, 1);
262eb4f98d5SKalle Valo 
263eb4f98d5SKalle Valo 	for (i = 0; i < NUM_PDA_ADDRS; i++) {
264eb4f98d5SKalle Valo 		PDEBUG(DEBUG_EXTRA2, "%s: trying to read PDA from 0x%08x",
265eb4f98d5SKalle Valo 		       dev->name, pda_addr[i]);
266eb4f98d5SKalle Valo 		res = hfa384x_from_aux(dev, pda_addr[i], PRISM2_PDA_SIZE, buf);
267eb4f98d5SKalle Valo 		if (res)
268eb4f98d5SKalle Valo 			continue;
269eb4f98d5SKalle Valo 		if (res == 0 && prism2_pda_ok(buf)) {
270eb4f98d5SKalle Valo 			PDEBUG2(DEBUG_EXTRA2, ": OK\n");
271eb4f98d5SKalle Valo 			found = 1;
272eb4f98d5SKalle Valo 			break;
273eb4f98d5SKalle Valo 		} else {
274eb4f98d5SKalle Valo 			PDEBUG2(DEBUG_EXTRA2, ": failed\n");
275eb4f98d5SKalle Valo 		}
276eb4f98d5SKalle Valo 	}
277eb4f98d5SKalle Valo 
278eb4f98d5SKalle Valo 	prism2_enable_aux_port(dev, 0);
279eb4f98d5SKalle Valo 
280eb4f98d5SKalle Valo 	if (!found) {
281eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: valid PDA not found\n", dev->name);
282eb4f98d5SKalle Valo 		kfree(buf);
283eb4f98d5SKalle Valo 		buf = NULL;
284eb4f98d5SKalle Valo 	}
285eb4f98d5SKalle Valo 
286eb4f98d5SKalle Valo 	return buf;
287eb4f98d5SKalle Valo }
288eb4f98d5SKalle Valo 
289eb4f98d5SKalle Valo 
290eb4f98d5SKalle Valo static int prism2_download_volatile(local_info_t *local,
291eb4f98d5SKalle Valo 				    struct prism2_download_data *param)
292eb4f98d5SKalle Valo {
293eb4f98d5SKalle Valo 	struct net_device *dev = local->dev;
294eb4f98d5SKalle Valo 	int ret = 0, i;
295eb4f98d5SKalle Valo 	u16 param0, param1;
296eb4f98d5SKalle Valo 
297eb4f98d5SKalle Valo 	if (local->hw_downloading) {
298eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Already downloading - aborting new "
299eb4f98d5SKalle Valo 		       "request\n", dev->name);
300eb4f98d5SKalle Valo 		return -1;
301eb4f98d5SKalle Valo 	}
302eb4f98d5SKalle Valo 
303eb4f98d5SKalle Valo 	local->hw_downloading = 1;
304eb4f98d5SKalle Valo 	if (local->pri_only) {
305eb4f98d5SKalle Valo 		hfa384x_disable_interrupts(dev);
306eb4f98d5SKalle Valo 	} else {
307eb4f98d5SKalle Valo 		prism2_hw_shutdown(dev, 0);
308eb4f98d5SKalle Valo 
309eb4f98d5SKalle Valo 		if (prism2_hw_init(dev, 0)) {
310eb4f98d5SKalle Valo 			printk(KERN_WARNING "%s: Could not initialize card for"
311eb4f98d5SKalle Valo 			       " download\n", dev->name);
312eb4f98d5SKalle Valo 			ret = -1;
313eb4f98d5SKalle Valo 			goto out;
314eb4f98d5SKalle Valo 		}
315eb4f98d5SKalle Valo 	}
316eb4f98d5SKalle Valo 
317eb4f98d5SKalle Valo 	if (prism2_enable_aux_port(dev, 1)) {
318eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Could not enable AUX port\n",
319eb4f98d5SKalle Valo 		       dev->name);
320eb4f98d5SKalle Valo 		ret = -1;
321eb4f98d5SKalle Valo 		goto out;
322eb4f98d5SKalle Valo 	}
323eb4f98d5SKalle Valo 
324eb4f98d5SKalle Valo 	param0 = param->start_addr & 0xffff;
325eb4f98d5SKalle Valo 	param1 = param->start_addr >> 16;
326eb4f98d5SKalle Valo 
327eb4f98d5SKalle Valo 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
328eb4f98d5SKalle Valo 	HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
329eb4f98d5SKalle Valo 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
330eb4f98d5SKalle Valo 			     (HFA384X_PROGMODE_ENABLE_VOLATILE << 8),
331eb4f98d5SKalle Valo 			     param0)) {
332eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Download command execution failed\n",
333eb4f98d5SKalle Valo 		       dev->name);
334eb4f98d5SKalle Valo 		ret = -1;
335eb4f98d5SKalle Valo 		goto out;
336eb4f98d5SKalle Valo 	}
337eb4f98d5SKalle Valo 
338eb4f98d5SKalle Valo 	for (i = 0; i < param->num_areas; i++) {
339eb4f98d5SKalle Valo 		PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
340eb4f98d5SKalle Valo 		       dev->name, param->data[i].len, param->data[i].addr);
341eb4f98d5SKalle Valo 		if (hfa384x_to_aux(dev, param->data[i].addr,
342eb4f98d5SKalle Valo 				   param->data[i].len, param->data[i].data)) {
343eb4f98d5SKalle Valo 			printk(KERN_WARNING "%s: RAM download at 0x%08x "
344eb4f98d5SKalle Valo 			       "(len=%d) failed\n", dev->name,
345eb4f98d5SKalle Valo 			       param->data[i].addr, param->data[i].len);
346eb4f98d5SKalle Valo 			ret = -1;
347eb4f98d5SKalle Valo 			goto out;
348eb4f98d5SKalle Valo 		}
349eb4f98d5SKalle Valo 	}
350eb4f98d5SKalle Valo 
351eb4f98d5SKalle Valo 	HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
352eb4f98d5SKalle Valo 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
353eb4f98d5SKalle Valo 	if (hfa384x_cmd_no_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
354eb4f98d5SKalle Valo 				(HFA384X_PROGMODE_DISABLE << 8), param0)) {
355eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Download command execution failed\n",
356eb4f98d5SKalle Valo 		       dev->name);
357eb4f98d5SKalle Valo 		ret = -1;
358eb4f98d5SKalle Valo 		goto out;
359eb4f98d5SKalle Valo 	}
360eb4f98d5SKalle Valo 	/* ProgMode disable causes the hardware to restart itself from the
361eb4f98d5SKalle Valo 	 * given starting address. Give hw some time and ACK command just in
362eb4f98d5SKalle Valo 	 * case restart did not happen. */
363eb4f98d5SKalle Valo 	mdelay(5);
364eb4f98d5SKalle Valo 	HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF);
365eb4f98d5SKalle Valo 
366eb4f98d5SKalle Valo 	if (prism2_enable_aux_port(dev, 0)) {
367eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
368eb4f98d5SKalle Valo 		       dev->name);
369eb4f98d5SKalle Valo 		/* continue anyway.. restart should have taken care of this */
370eb4f98d5SKalle Valo 	}
371eb4f98d5SKalle Valo 
372eb4f98d5SKalle Valo 	mdelay(5);
373eb4f98d5SKalle Valo 	local->hw_downloading = 0;
374eb4f98d5SKalle Valo 	if (prism2_hw_config(dev, 2)) {
375eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Card configuration after RAM "
376eb4f98d5SKalle Valo 		       "download failed\n", dev->name);
377eb4f98d5SKalle Valo 		ret = -1;
378eb4f98d5SKalle Valo 		goto out;
379eb4f98d5SKalle Valo 	}
380eb4f98d5SKalle Valo 
381eb4f98d5SKalle Valo  out:
382eb4f98d5SKalle Valo 	local->hw_downloading = 0;
383eb4f98d5SKalle Valo 	return ret;
384eb4f98d5SKalle Valo }
385eb4f98d5SKalle Valo 
386eb4f98d5SKalle Valo 
387eb4f98d5SKalle Valo static int prism2_enable_genesis(local_info_t *local, int hcr)
388eb4f98d5SKalle Valo {
389eb4f98d5SKalle Valo 	struct net_device *dev = local->dev;
390eb4f98d5SKalle Valo 	u8 initseq[4] = { 0x00, 0xe1, 0xa1, 0xff };
391eb4f98d5SKalle Valo 	u8 readbuf[4];
392eb4f98d5SKalle Valo 
393eb4f98d5SKalle Valo 	printk(KERN_DEBUG "%s: test Genesis mode with HCR 0x%02x\n",
394eb4f98d5SKalle Valo 	       dev->name, hcr);
395eb4f98d5SKalle Valo 	local->func->cor_sreset(local);
396eb4f98d5SKalle Valo 	hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
397eb4f98d5SKalle Valo 	local->func->genesis_reset(local, hcr);
398eb4f98d5SKalle Valo 
399eb4f98d5SKalle Valo 	/* Readback test */
400eb4f98d5SKalle Valo 	hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
401eb4f98d5SKalle Valo 	hfa384x_to_aux(dev, 0x7e0038, sizeof(initseq), initseq);
402eb4f98d5SKalle Valo 	hfa384x_from_aux(dev, 0x7e0038, sizeof(readbuf), readbuf);
403eb4f98d5SKalle Valo 
404eb4f98d5SKalle Valo 	if (memcmp(initseq, readbuf, sizeof(initseq)) == 0) {
405eb4f98d5SKalle Valo 		printk(KERN_DEBUG "Readback test succeeded, HCR 0x%02x\n",
406eb4f98d5SKalle Valo 		       hcr);
407eb4f98d5SKalle Valo 		return 0;
408eb4f98d5SKalle Valo 	} else {
409eb4f98d5SKalle Valo 		printk(KERN_DEBUG "Readback test failed, HCR 0x%02x "
410eb4f98d5SKalle Valo 		       "write %02x %02x %02x %02x read %02x %02x %02x %02x\n",
411eb4f98d5SKalle Valo 		       hcr, initseq[0], initseq[1], initseq[2], initseq[3],
412eb4f98d5SKalle Valo 		       readbuf[0], readbuf[1], readbuf[2], readbuf[3]);
413eb4f98d5SKalle Valo 		return 1;
414eb4f98d5SKalle Valo 	}
415eb4f98d5SKalle Valo }
416eb4f98d5SKalle Valo 
417eb4f98d5SKalle Valo 
418eb4f98d5SKalle Valo static int prism2_get_ram_size(local_info_t *local)
419eb4f98d5SKalle Valo {
420eb4f98d5SKalle Valo 	int ret;
421eb4f98d5SKalle Valo 
422eb4f98d5SKalle Valo 	/* Try to enable genesis mode; 0x1F for x8 SRAM or 0x0F for x16 SRAM */
423eb4f98d5SKalle Valo 	if (prism2_enable_genesis(local, 0x1f) == 0)
424eb4f98d5SKalle Valo 		ret = 8;
425eb4f98d5SKalle Valo 	else if (prism2_enable_genesis(local, 0x0f) == 0)
426eb4f98d5SKalle Valo 		ret = 16;
427eb4f98d5SKalle Valo 	else
428eb4f98d5SKalle Valo 		ret = -1;
429eb4f98d5SKalle Valo 
430eb4f98d5SKalle Valo 	/* Disable genesis mode */
431eb4f98d5SKalle Valo 	local->func->genesis_reset(local, ret == 16 ? 0x07 : 0x17);
432eb4f98d5SKalle Valo 
433eb4f98d5SKalle Valo 	return ret;
434eb4f98d5SKalle Valo }
435eb4f98d5SKalle Valo 
436eb4f98d5SKalle Valo 
437eb4f98d5SKalle Valo static int prism2_download_genesis(local_info_t *local,
438eb4f98d5SKalle Valo 				   struct prism2_download_data *param)
439eb4f98d5SKalle Valo {
440eb4f98d5SKalle Valo 	struct net_device *dev = local->dev;
441eb4f98d5SKalle Valo 	int ram16 = 0, i;
442eb4f98d5SKalle Valo 	int ret = 0;
443eb4f98d5SKalle Valo 
444eb4f98d5SKalle Valo 	if (local->hw_downloading) {
445eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Already downloading - aborting new "
446eb4f98d5SKalle Valo 		       "request\n", dev->name);
447eb4f98d5SKalle Valo 		return -EBUSY;
448eb4f98d5SKalle Valo 	}
449eb4f98d5SKalle Valo 
450eb4f98d5SKalle Valo 	if (!local->func->genesis_reset || !local->func->cor_sreset) {
451eb4f98d5SKalle Valo 		printk(KERN_INFO "%s: Genesis mode downloading not supported "
452eb4f98d5SKalle Valo 		       "with this hwmodel\n", dev->name);
453eb4f98d5SKalle Valo 		return -EOPNOTSUPP;
454eb4f98d5SKalle Valo 	}
455eb4f98d5SKalle Valo 
456eb4f98d5SKalle Valo 	local->hw_downloading = 1;
457eb4f98d5SKalle Valo 
458eb4f98d5SKalle Valo 	if (prism2_enable_aux_port(dev, 1)) {
459eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: failed to enable AUX port\n",
460eb4f98d5SKalle Valo 		       dev->name);
461eb4f98d5SKalle Valo 		ret = -EIO;
462eb4f98d5SKalle Valo 		goto out;
463eb4f98d5SKalle Valo 	}
464eb4f98d5SKalle Valo 
465eb4f98d5SKalle Valo 	if (local->sram_type == -1) {
466eb4f98d5SKalle Valo 		/* 0x1F for x8 SRAM or 0x0F for x16 SRAM */
467eb4f98d5SKalle Valo 		if (prism2_enable_genesis(local, 0x1f) == 0) {
468eb4f98d5SKalle Valo 			ram16 = 0;
469eb4f98d5SKalle Valo 			PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x8 "
470eb4f98d5SKalle Valo 			       "SRAM\n", dev->name);
471eb4f98d5SKalle Valo 		} else if (prism2_enable_genesis(local, 0x0f) == 0) {
472eb4f98d5SKalle Valo 			ram16 = 1;
473eb4f98d5SKalle Valo 			PDEBUG(DEBUG_EXTRA2, "%s: Genesis mode OK using x16 "
474eb4f98d5SKalle Valo 			       "SRAM\n", dev->name);
475eb4f98d5SKalle Valo 		} else {
476eb4f98d5SKalle Valo 			printk(KERN_DEBUG "%s: Could not initiate genesis "
477eb4f98d5SKalle Valo 			       "mode\n", dev->name);
478eb4f98d5SKalle Valo 			ret = -EIO;
479eb4f98d5SKalle Valo 			goto out;
480eb4f98d5SKalle Valo 		}
481eb4f98d5SKalle Valo 	} else {
482eb4f98d5SKalle Valo 		if (prism2_enable_genesis(local, local->sram_type == 8 ?
483eb4f98d5SKalle Valo 					  0x1f : 0x0f)) {
484eb4f98d5SKalle Valo 			printk(KERN_DEBUG "%s: Failed to set Genesis "
485eb4f98d5SKalle Valo 			       "mode (sram_type=%d)\n", dev->name,
486eb4f98d5SKalle Valo 			       local->sram_type);
487eb4f98d5SKalle Valo 			ret = -EIO;
488eb4f98d5SKalle Valo 			goto out;
489eb4f98d5SKalle Valo 		}
490eb4f98d5SKalle Valo 		ram16 = local->sram_type != 8;
491eb4f98d5SKalle Valo 	}
492eb4f98d5SKalle Valo 
493eb4f98d5SKalle Valo 	for (i = 0; i < param->num_areas; i++) {
494eb4f98d5SKalle Valo 		PDEBUG(DEBUG_EXTRA2, "%s: Writing %d bytes at 0x%08x\n",
495eb4f98d5SKalle Valo 		       dev->name, param->data[i].len, param->data[i].addr);
496eb4f98d5SKalle Valo 		if (hfa384x_to_aux(dev, param->data[i].addr,
497eb4f98d5SKalle Valo 				   param->data[i].len, param->data[i].data)) {
498eb4f98d5SKalle Valo 			printk(KERN_WARNING "%s: RAM download at 0x%08x "
499eb4f98d5SKalle Valo 			       "(len=%d) failed\n", dev->name,
500eb4f98d5SKalle Valo 			       param->data[i].addr, param->data[i].len);
501eb4f98d5SKalle Valo 			ret = -EIO;
502eb4f98d5SKalle Valo 			goto out;
503eb4f98d5SKalle Valo 		}
504eb4f98d5SKalle Valo 	}
505eb4f98d5SKalle Valo 
506eb4f98d5SKalle Valo 	PDEBUG(DEBUG_EXTRA2, "Disable genesis mode\n");
507eb4f98d5SKalle Valo 	local->func->genesis_reset(local, ram16 ? 0x07 : 0x17);
508eb4f98d5SKalle Valo 	if (prism2_enable_aux_port(dev, 0)) {
509eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: Failed to disable AUX port\n",
510eb4f98d5SKalle Valo 		       dev->name);
511eb4f98d5SKalle Valo 	}
512eb4f98d5SKalle Valo 
513eb4f98d5SKalle Valo 	mdelay(5);
514eb4f98d5SKalle Valo 	local->hw_downloading = 0;
515eb4f98d5SKalle Valo 
516eb4f98d5SKalle Valo 	PDEBUG(DEBUG_EXTRA2, "Trying to initialize card\n");
517eb4f98d5SKalle Valo 	/*
518eb4f98d5SKalle Valo 	 * Make sure the INIT command does not generate a command completion
519eb4f98d5SKalle Valo 	 * event by disabling interrupts.
520eb4f98d5SKalle Valo 	 */
521eb4f98d5SKalle Valo 	hfa384x_disable_interrupts(dev);
522eb4f98d5SKalle Valo 	if (prism2_hw_init(dev, 1)) {
523eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: Initialization after genesis mode "
524eb4f98d5SKalle Valo 		       "download failed\n", dev->name);
525eb4f98d5SKalle Valo 		ret = -EIO;
526eb4f98d5SKalle Valo 		goto out;
527eb4f98d5SKalle Valo 	}
528eb4f98d5SKalle Valo 
529eb4f98d5SKalle Valo 	PDEBUG(DEBUG_EXTRA2, "Card initialized - running PRI only\n");
530eb4f98d5SKalle Valo 	if (prism2_hw_init2(dev, 1)) {
531eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: Initialization(2) after genesis mode "
532eb4f98d5SKalle Valo 		       "download failed\n", dev->name);
533eb4f98d5SKalle Valo 		ret = -EIO;
534eb4f98d5SKalle Valo 		goto out;
535eb4f98d5SKalle Valo 	}
536eb4f98d5SKalle Valo 
537eb4f98d5SKalle Valo  out:
538eb4f98d5SKalle Valo 	local->hw_downloading = 0;
539eb4f98d5SKalle Valo 	return ret;
540eb4f98d5SKalle Valo }
541eb4f98d5SKalle Valo 
542eb4f98d5SKalle Valo 
543eb4f98d5SKalle Valo #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
544eb4f98d5SKalle Valo /* Note! Non-volatile downloading functionality has not yet been tested
545eb4f98d5SKalle Valo  * thoroughly and it may corrupt flash image and effectively kill the card that
546eb4f98d5SKalle Valo  * is being updated. You have been warned. */
547eb4f98d5SKalle Valo 
548eb4f98d5SKalle Valo static inline int prism2_download_block(struct net_device *dev,
549eb4f98d5SKalle Valo 					u32 addr, u8 *data,
550eb4f98d5SKalle Valo 					u32 bufaddr, int rest_len)
551eb4f98d5SKalle Valo {
552eb4f98d5SKalle Valo 	u16 param0, param1;
553eb4f98d5SKalle Valo 	int block_len;
554eb4f98d5SKalle Valo 
555eb4f98d5SKalle Valo 	block_len = rest_len < 4096 ? rest_len : 4096;
556eb4f98d5SKalle Valo 
557eb4f98d5SKalle Valo 	param0 = addr & 0xffff;
558eb4f98d5SKalle Valo 	param1 = addr >> 16;
559eb4f98d5SKalle Valo 
560eb4f98d5SKalle Valo 	HFA384X_OUTW(block_len, HFA384X_PARAM2_OFF);
561eb4f98d5SKalle Valo 	HFA384X_OUTW(param1, HFA384X_PARAM1_OFF);
562eb4f98d5SKalle Valo 
563eb4f98d5SKalle Valo 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
564eb4f98d5SKalle Valo 			     (HFA384X_PROGMODE_ENABLE_NON_VOLATILE << 8),
565eb4f98d5SKalle Valo 			     param0)) {
566eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Flash download command execution "
567eb4f98d5SKalle Valo 		       "failed\n", dev->name);
568eb4f98d5SKalle Valo 		return -1;
569eb4f98d5SKalle Valo 	}
570eb4f98d5SKalle Valo 
571eb4f98d5SKalle Valo 	if (hfa384x_to_aux(dev, bufaddr, block_len, data)) {
572eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: flash download at 0x%08x "
573eb4f98d5SKalle Valo 		       "(len=%d) failed\n", dev->name, addr, block_len);
574eb4f98d5SKalle Valo 		return -1;
575eb4f98d5SKalle Valo 	}
576eb4f98d5SKalle Valo 
577eb4f98d5SKalle Valo 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
578eb4f98d5SKalle Valo 	HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
579eb4f98d5SKalle Valo 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
580eb4f98d5SKalle Valo 			     (HFA384X_PROGMODE_PROGRAM_NON_VOLATILE << 8),
581eb4f98d5SKalle Valo 			     0)) {
582eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Flash write command execution "
583eb4f98d5SKalle Valo 		       "failed\n", dev->name);
584eb4f98d5SKalle Valo 		return -1;
585eb4f98d5SKalle Valo 	}
586eb4f98d5SKalle Valo 
587eb4f98d5SKalle Valo 	return block_len;
588eb4f98d5SKalle Valo }
589eb4f98d5SKalle Valo 
590eb4f98d5SKalle Valo 
591eb4f98d5SKalle Valo static int prism2_download_nonvolatile(local_info_t *local,
592eb4f98d5SKalle Valo 				       struct prism2_download_data *dl)
593eb4f98d5SKalle Valo {
594eb4f98d5SKalle Valo 	struct net_device *dev = local->dev;
595eb4f98d5SKalle Valo 	int ret = 0, i;
596eb4f98d5SKalle Valo 	struct {
597eb4f98d5SKalle Valo 		__le16 page;
598eb4f98d5SKalle Valo 		__le16 offset;
599eb4f98d5SKalle Valo 		__le16 len;
600eb4f98d5SKalle Valo 	} dlbuffer;
601eb4f98d5SKalle Valo 	u32 bufaddr;
602eb4f98d5SKalle Valo 
603eb4f98d5SKalle Valo 	if (local->hw_downloading) {
604eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Already downloading - aborting new "
605eb4f98d5SKalle Valo 		       "request\n", dev->name);
606eb4f98d5SKalle Valo 		return -1;
607eb4f98d5SKalle Valo 	}
608eb4f98d5SKalle Valo 
609eb4f98d5SKalle Valo 	ret = local->func->get_rid(dev, HFA384X_RID_DOWNLOADBUFFER,
610eb4f98d5SKalle Valo 				   &dlbuffer, 6, 0);
611eb4f98d5SKalle Valo 
612eb4f98d5SKalle Valo 	if (ret < 0) {
613eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Could not read download buffer "
614eb4f98d5SKalle Valo 		       "parameters\n", dev->name);
615eb4f98d5SKalle Valo 		goto out;
616eb4f98d5SKalle Valo 	}
617eb4f98d5SKalle Valo 
618eb4f98d5SKalle Valo 	printk(KERN_DEBUG "Download buffer: %d bytes at 0x%04x:0x%04x\n",
619eb4f98d5SKalle Valo 	       le16_to_cpu(dlbuffer.len),
620eb4f98d5SKalle Valo 	       le16_to_cpu(dlbuffer.page),
621eb4f98d5SKalle Valo 	       le16_to_cpu(dlbuffer.offset));
622eb4f98d5SKalle Valo 
623eb4f98d5SKalle Valo 	bufaddr = (le16_to_cpu(dlbuffer.page) << 7) + le16_to_cpu(dlbuffer.offset);
624eb4f98d5SKalle Valo 
625eb4f98d5SKalle Valo 	local->hw_downloading = 1;
626eb4f98d5SKalle Valo 
627eb4f98d5SKalle Valo 	if (!local->pri_only) {
628eb4f98d5SKalle Valo 		prism2_hw_shutdown(dev, 0);
629eb4f98d5SKalle Valo 
630eb4f98d5SKalle Valo 		if (prism2_hw_init(dev, 0)) {
631eb4f98d5SKalle Valo 			printk(KERN_WARNING "%s: Could not initialize card for"
632eb4f98d5SKalle Valo 			       " download\n", dev->name);
633eb4f98d5SKalle Valo 			ret = -1;
634eb4f98d5SKalle Valo 			goto out;
635eb4f98d5SKalle Valo 		}
636eb4f98d5SKalle Valo 	}
637eb4f98d5SKalle Valo 
638eb4f98d5SKalle Valo 	hfa384x_disable_interrupts(dev);
639eb4f98d5SKalle Valo 
640eb4f98d5SKalle Valo 	if (prism2_enable_aux_port(dev, 1)) {
641eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Could not enable AUX port\n",
642eb4f98d5SKalle Valo 		       dev->name);
643eb4f98d5SKalle Valo 		ret = -1;
644eb4f98d5SKalle Valo 		goto out;
645eb4f98d5SKalle Valo 	}
646eb4f98d5SKalle Valo 
647eb4f98d5SKalle Valo 	printk(KERN_DEBUG "%s: starting flash download\n", dev->name);
648eb4f98d5SKalle Valo 	for (i = 0; i < dl->num_areas; i++) {
649eb4f98d5SKalle Valo 		int rest_len = dl->data[i].len;
650eb4f98d5SKalle Valo 		int data_off = 0;
651eb4f98d5SKalle Valo 
652eb4f98d5SKalle Valo 		while (rest_len > 0) {
653eb4f98d5SKalle Valo 			int block_len;
654eb4f98d5SKalle Valo 
655eb4f98d5SKalle Valo 			block_len = prism2_download_block(
656eb4f98d5SKalle Valo 				dev, dl->data[i].addr + data_off,
657eb4f98d5SKalle Valo 				dl->data[i].data + data_off, bufaddr,
658eb4f98d5SKalle Valo 				rest_len);
659eb4f98d5SKalle Valo 
660eb4f98d5SKalle Valo 			if (block_len < 0) {
661eb4f98d5SKalle Valo 				ret = -1;
662eb4f98d5SKalle Valo 				goto out;
663eb4f98d5SKalle Valo 			}
664eb4f98d5SKalle Valo 
665eb4f98d5SKalle Valo 			rest_len -= block_len;
666eb4f98d5SKalle Valo 			data_off += block_len;
667eb4f98d5SKalle Valo 		}
668eb4f98d5SKalle Valo 	}
669eb4f98d5SKalle Valo 
670eb4f98d5SKalle Valo 	HFA384X_OUTW(0, HFA384X_PARAM1_OFF);
671eb4f98d5SKalle Valo 	HFA384X_OUTW(0, HFA384X_PARAM2_OFF);
672eb4f98d5SKalle Valo 	if (hfa384x_cmd_wait(dev, HFA384X_CMDCODE_DOWNLOAD |
673eb4f98d5SKalle Valo 				(HFA384X_PROGMODE_DISABLE << 8), 0)) {
674eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Download command execution failed\n",
675eb4f98d5SKalle Valo 		       dev->name);
676eb4f98d5SKalle Valo 		ret = -1;
677eb4f98d5SKalle Valo 		goto out;
678eb4f98d5SKalle Valo 	}
679eb4f98d5SKalle Valo 
680eb4f98d5SKalle Valo 	if (prism2_enable_aux_port(dev, 0)) {
681eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: Disabling AUX port failed\n",
682eb4f98d5SKalle Valo 		       dev->name);
683eb4f98d5SKalle Valo 		/* continue anyway.. restart should have taken care of this */
684eb4f98d5SKalle Valo 	}
685eb4f98d5SKalle Valo 
686eb4f98d5SKalle Valo 	mdelay(5);
687eb4f98d5SKalle Valo 
688eb4f98d5SKalle Valo 	local->func->hw_reset(dev);
689eb4f98d5SKalle Valo 	local->hw_downloading = 0;
690eb4f98d5SKalle Valo 	if (prism2_hw_config(dev, 2)) {
691eb4f98d5SKalle Valo 		printk(KERN_WARNING "%s: Card configuration after flash "
692eb4f98d5SKalle Valo 		       "download failed\n", dev->name);
693eb4f98d5SKalle Valo 		ret = -1;
694eb4f98d5SKalle Valo 	} else {
695eb4f98d5SKalle Valo 		printk(KERN_INFO "%s: Card initialized successfully after "
696eb4f98d5SKalle Valo 		       "flash download\n", dev->name);
697eb4f98d5SKalle Valo 	}
698eb4f98d5SKalle Valo 
699eb4f98d5SKalle Valo  out:
700eb4f98d5SKalle Valo 	local->hw_downloading = 0;
701eb4f98d5SKalle Valo 	return ret;
702eb4f98d5SKalle Valo }
703eb4f98d5SKalle Valo #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
704eb4f98d5SKalle Valo 
705eb4f98d5SKalle Valo 
706eb4f98d5SKalle Valo static void prism2_download_free_data(struct prism2_download_data *dl)
707eb4f98d5SKalle Valo {
708eb4f98d5SKalle Valo 	int i;
709eb4f98d5SKalle Valo 
710eb4f98d5SKalle Valo 	if (dl == NULL)
711eb4f98d5SKalle Valo 		return;
712eb4f98d5SKalle Valo 
713eb4f98d5SKalle Valo 	for (i = 0; i < dl->num_areas; i++)
714eb4f98d5SKalle Valo 		kfree(dl->data[i].data);
715eb4f98d5SKalle Valo 	kfree(dl);
716eb4f98d5SKalle Valo }
717eb4f98d5SKalle Valo 
718eb4f98d5SKalle Valo 
719eb4f98d5SKalle Valo static int prism2_download(local_info_t *local,
720eb4f98d5SKalle Valo 			   struct prism2_download_param *param)
721eb4f98d5SKalle Valo {
722eb4f98d5SKalle Valo 	int ret = 0;
723eb4f98d5SKalle Valo 	int i;
724eb4f98d5SKalle Valo 	u32 total_len = 0;
725eb4f98d5SKalle Valo 	struct prism2_download_data *dl = NULL;
726eb4f98d5SKalle Valo 
727eb4f98d5SKalle Valo 	printk(KERN_DEBUG "prism2_download: dl_cmd=%d start_addr=0x%08x "
728eb4f98d5SKalle Valo 	       "num_areas=%d\n",
729eb4f98d5SKalle Valo 	       param->dl_cmd, param->start_addr, param->num_areas);
730eb4f98d5SKalle Valo 
731eb4f98d5SKalle Valo 	if (param->num_areas > 100) {
732eb4f98d5SKalle Valo 		ret = -EINVAL;
733eb4f98d5SKalle Valo 		goto out;
734eb4f98d5SKalle Valo 	}
735eb4f98d5SKalle Valo 
736eb4f98d5SKalle Valo 	dl = kzalloc(sizeof(*dl) + param->num_areas *
737eb4f98d5SKalle Valo 		     sizeof(struct prism2_download_data_area), GFP_KERNEL);
738eb4f98d5SKalle Valo 	if (dl == NULL) {
739eb4f98d5SKalle Valo 		ret = -ENOMEM;
740eb4f98d5SKalle Valo 		goto out;
741eb4f98d5SKalle Valo 	}
742eb4f98d5SKalle Valo 	dl->dl_cmd = param->dl_cmd;
743eb4f98d5SKalle Valo 	dl->start_addr = param->start_addr;
744eb4f98d5SKalle Valo 	dl->num_areas = param->num_areas;
745eb4f98d5SKalle Valo 	for (i = 0; i < param->num_areas; i++) {
746eb4f98d5SKalle Valo 		PDEBUG(DEBUG_EXTRA2,
747eb4f98d5SKalle Valo 		       "  area %d: addr=0x%08x len=%d ptr=0x%p\n",
748eb4f98d5SKalle Valo 		       i, param->data[i].addr, param->data[i].len,
749eb4f98d5SKalle Valo 		       param->data[i].ptr);
750eb4f98d5SKalle Valo 
751eb4f98d5SKalle Valo 		dl->data[i].addr = param->data[i].addr;
752eb4f98d5SKalle Valo 		dl->data[i].len = param->data[i].len;
753eb4f98d5SKalle Valo 
754eb4f98d5SKalle Valo 		total_len += param->data[i].len;
755eb4f98d5SKalle Valo 		if (param->data[i].len > PRISM2_MAX_DOWNLOAD_AREA_LEN ||
756eb4f98d5SKalle Valo 		    total_len > PRISM2_MAX_DOWNLOAD_LEN) {
757eb4f98d5SKalle Valo 			ret = -E2BIG;
758eb4f98d5SKalle Valo 			goto out;
759eb4f98d5SKalle Valo 		}
760eb4f98d5SKalle Valo 
761eb4f98d5SKalle Valo 		dl->data[i].data = kmalloc(dl->data[i].len, GFP_KERNEL);
762eb4f98d5SKalle Valo 		if (dl->data[i].data == NULL) {
763eb4f98d5SKalle Valo 			ret = -ENOMEM;
764eb4f98d5SKalle Valo 			goto out;
765eb4f98d5SKalle Valo 		}
766eb4f98d5SKalle Valo 
767eb4f98d5SKalle Valo 		if (copy_from_user(dl->data[i].data, param->data[i].ptr,
768eb4f98d5SKalle Valo 				   param->data[i].len)) {
769eb4f98d5SKalle Valo 			ret = -EFAULT;
770eb4f98d5SKalle Valo 			goto out;
771eb4f98d5SKalle Valo 		}
772eb4f98d5SKalle Valo 	}
773eb4f98d5SKalle Valo 
774eb4f98d5SKalle Valo 	switch (param->dl_cmd) {
775eb4f98d5SKalle Valo 	case PRISM2_DOWNLOAD_VOLATILE:
776eb4f98d5SKalle Valo 	case PRISM2_DOWNLOAD_VOLATILE_PERSISTENT:
777eb4f98d5SKalle Valo 		ret = prism2_download_volatile(local, dl);
778eb4f98d5SKalle Valo 		break;
779eb4f98d5SKalle Valo 	case PRISM2_DOWNLOAD_VOLATILE_GENESIS:
780eb4f98d5SKalle Valo 	case PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT:
781eb4f98d5SKalle Valo 		ret = prism2_download_genesis(local, dl);
782eb4f98d5SKalle Valo 		break;
783eb4f98d5SKalle Valo 	case PRISM2_DOWNLOAD_NON_VOLATILE:
784eb4f98d5SKalle Valo #ifdef PRISM2_NON_VOLATILE_DOWNLOAD
785eb4f98d5SKalle Valo 		ret = prism2_download_nonvolatile(local, dl);
786eb4f98d5SKalle Valo #else /* PRISM2_NON_VOLATILE_DOWNLOAD */
787eb4f98d5SKalle Valo 		printk(KERN_INFO "%s: non-volatile downloading not enabled\n",
788eb4f98d5SKalle Valo 		       local->dev->name);
789eb4f98d5SKalle Valo 		ret = -EOPNOTSUPP;
790eb4f98d5SKalle Valo #endif /* PRISM2_NON_VOLATILE_DOWNLOAD */
791eb4f98d5SKalle Valo 		break;
792eb4f98d5SKalle Valo 	default:
793eb4f98d5SKalle Valo 		printk(KERN_DEBUG "%s: unsupported download command %d\n",
794eb4f98d5SKalle Valo 		       local->dev->name, param->dl_cmd);
795eb4f98d5SKalle Valo 		ret = -EINVAL;
796eb4f98d5SKalle Valo 		break;
797eb4f98d5SKalle Valo 	}
798eb4f98d5SKalle Valo 
799eb4f98d5SKalle Valo  out:
800eb4f98d5SKalle Valo 	if (ret == 0 && dl &&
801eb4f98d5SKalle Valo 	    param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_GENESIS_PERSISTENT) {
802eb4f98d5SKalle Valo 		prism2_download_free_data(local->dl_pri);
803eb4f98d5SKalle Valo 		local->dl_pri = dl;
804eb4f98d5SKalle Valo 	} else if (ret == 0 && dl &&
805eb4f98d5SKalle Valo 		   param->dl_cmd == PRISM2_DOWNLOAD_VOLATILE_PERSISTENT) {
806eb4f98d5SKalle Valo 		prism2_download_free_data(local->dl_sec);
807eb4f98d5SKalle Valo 		local->dl_sec = dl;
808eb4f98d5SKalle Valo 	} else
809eb4f98d5SKalle Valo 		prism2_download_free_data(dl);
810eb4f98d5SKalle Valo 
811eb4f98d5SKalle Valo 	return ret;
812eb4f98d5SKalle Valo }
813