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