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