/* Issue a command to the chip, and (busy!) wait for it to * complete. * * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware * * Callable from any context, but locking is your problem. */ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp) { int err; int k; u16 reg; u16 status; err = hermes_issue_cmd(hw, cmd, parm0); if (err) { if (! hermes_present(hw)) { printk(KERN_WARNING "hermes @ %s0x%lx: " "Card removed while issuing command.\n", IO_TYPE(hw), hw->iobase); err = -ENODEV; } else printk(KERN_ERR "hermes @ %s0x%lx: Error %d issuing command.\n", IO_TYPE(hw), hw->iobase, err); goto out; } reg = hermes_read_regn(hw, EVSTAT); k = CMD_COMPL_TIMEOUT; while ( (! (reg & HERMES_EV_CMD)) && k) { k--; udelay(10); reg = hermes_read_regn(hw, EVSTAT); } if (! hermes_present(hw)) { printk(KERN_WARNING "hermes @ %s0x%lx: " "Card removed while waiting for command completion.\n", IO_TYPE(hw), hw->iobase); err = -ENODEV; goto out; } if (! (reg & HERMES_EV_CMD)) { printk(KERN_ERR "hermes @ %s0x%lx: " "Timeout waiting for command completion.\n", IO_TYPE(hw), hw->iobase); err = -ETIMEDOUT; goto out; } status = hermes_read_regn(hw, STATUS); if (resp) { resp->status = status; resp->resp0 = hermes_read_regn(hw, RESP0); resp->resp1 = hermes_read_regn(hw, RESP1); resp->resp2 = hermes_read_regn(hw, RESP2); } hermes_write_regn(hw, EVACK, HERMES_EV_CMD); if (status & HERMES_STATUS_RESULT) err = -EIO; out: return err; }
static int hermes_doicmd_wait(struct hermes *hw, u16 cmd, u16 parm0, u16 parm1, u16 parm2, struct hermes_response *resp) { int err = 0; int k; u16 status, reg; err = hermes_issue_cmd(hw, cmd, parm0, parm1, parm2); if (err) return err; reg = hermes_read_regn(hw, EVSTAT); k = CMD_INIT_TIMEOUT; while ((!(reg & HERMES_EV_CMD)) && k) { k--; udelay(10); reg = hermes_read_regn(hw, EVSTAT); } hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); if (!hermes_present(hw)) { DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", hw->iobase); err = -ENODEV; goto out; } if (!(reg & HERMES_EV_CMD)) { printk(KERN_ERR "hermes @ %p: " "Timeout waiting for card to reset (reg=0x%04x)!\n", hw->iobase, reg); err = -ETIMEDOUT; goto out; } status = hermes_read_regn(hw, STATUS); if (resp) { resp->status = status; resp->resp0 = hermes_read_regn(hw, RESP0); resp->resp1 = hermes_read_regn(hw, RESP1); resp->resp2 = hermes_read_regn(hw, RESP2); } hermes_write_regn(hw, EVACK, HERMES_EV_CMD); if (status & HERMES_STATUS_RESULT) err = -EIO; out: return err; }
int hermes_allocate(hermes_t *hw, u16 size, u16 *fid) { int err = 0; hermes_response_t resp; int k; u16 reg; if ( (size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX) ) return -EINVAL; err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, &resp); if (err) { printk(KERN_WARNING "hermes @ 0x%x: Frame allocation command failed (0x%X).\n", hw->iobase, err); return err; } reg = hermes_read_regn(hw, EVSTAT); k = ALLOC_COMPL_TIMEOUT; while ( (! (reg & HERMES_EV_ALLOC)) && k) { k--; udelay(10); reg = hermes_read_regn(hw, EVSTAT); } if (! hermes_present(hw)) { printk(KERN_WARNING "hermes @ 0x%x: Card removed waiting for frame allocation.\n", hw->iobase); return -ENODEV; } if (! (reg & HERMES_EV_ALLOC)) { printk(KERN_ERR "hermes @ 0x%x: Timeout waiting for frame allocation\n", hw->iobase); return -ETIMEDOUT; } *fid = hermes_read_regn(hw, ALLOCFID); hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); return 0; }
static int hermes_allocate(struct hermes *hw, u16 size, u16 *fid) { int err = 0; int k; u16 reg; if ((size < HERMES_ALLOC_LEN_MIN) || (size > HERMES_ALLOC_LEN_MAX)) return -EINVAL; err = hermes_docmd_wait(hw, HERMES_CMD_ALLOC, size, NULL); if (err) return err; reg = hermes_read_regn(hw, EVSTAT); k = ALLOC_COMPL_TIMEOUT; while ((!(reg & HERMES_EV_ALLOC)) && k) { k--; udelay(10); reg = hermes_read_regn(hw, EVSTAT); } if (!hermes_present(hw)) { printk(KERN_WARNING "hermes @ %p: " "Card removed waiting for frame allocation.\n", hw->iobase); return -ENODEV; } if (!(reg & HERMES_EV_ALLOC)) { printk(KERN_ERR "hermes @ %p: " "Timeout waiting for frame allocation\n", hw->iobase); return -ETIMEDOUT; } *fid = hermes_read_regn(hw, ALLOCFID); hermes_write_regn(hw, EVACK, HERMES_EV_ALLOC); return 0; }
int hermes_init(hermes_t *hw) { u16 status, reg; int err = 0; int k; /* We don't want to be interrupted while resetting the chipset */ hw->inten = 0x0; hermes_write_regn(hw, INTEN, 0); hermes_write_regn(hw, EVACK, 0xffff); /* Normally it's a "can't happen" for the command register to be busy when we go to issue a command because we are serializing all commands. However we want to have some chance of resetting the card even if it gets into a stupid state, so we actually wait to see if the command register will unbusy itself here. */ k = CMD_BUSY_TIMEOUT; reg = hermes_read_regn(hw, CMD); while (k && (reg & HERMES_CMD_BUSY)) { if (reg == 0xffff) /* Special case - the card has probably been removed, so don't wait for the timeout */ return -ENODEV; k--; udelay(1); reg = hermes_read_regn(hw, CMD); } /* No need to explicitly handle the timeout - if we've timed out hermes_issue_cmd() will probably return -EBUSY below */ /* According to the documentation, EVSTAT may contain obsolete event occurrence information. We have to acknowledge it by writing EVACK. */ reg = hermes_read_regn(hw, EVSTAT); hermes_write_regn(hw, EVACK, reg); /* We don't use hermes_docmd_wait here, because the reset wipes the magic constant in SWSUPPORT0 away, and it gets confused */ err = hermes_issue_cmd(hw, HERMES_CMD_INIT, 0); if (err) return err; reg = hermes_read_regn(hw, EVSTAT); k = CMD_INIT_TIMEOUT; while ( (! (reg & HERMES_EV_CMD)) && k) { k--; udelay(10); reg = hermes_read_regn(hw, EVSTAT); } hermes_write_regn(hw, SWSUPPORT0, HERMES_MAGIC); if (! hermes_present(hw)) { DEBUG(0, "hermes @ 0x%x: Card removed during reset.\n", hw->iobase); err = -ENODEV; goto out; } if (! (reg & HERMES_EV_CMD)) { printk(KERN_ERR "hermes @ %s0x%lx: " "Timeout waiting for card to reset (reg=0x%04x)!\n", IO_TYPE(hw), hw->iobase, reg); err = -ETIMEDOUT; goto out; } status = hermes_read_regn(hw, STATUS); hermes_write_regn(hw, EVACK, HERMES_EV_CMD); if (status & HERMES_STATUS_RESULT) err = -EIO; out: return err; }
static int hermes_docmd_wait(struct hermes *hw, u16 cmd, u16 parm0, struct hermes_response *resp) { int err; int k; u16 reg; u16 status; err = hermes_issue_cmd(hw, cmd, parm0, 0, 0); if (err) { if (!hermes_present(hw)) { if (net_ratelimit()) printk(KERN_WARNING "hermes @ %p: " "Card removed while issuing command " "0x%04x.\n", hw->iobase, cmd); err = -ENODEV; } else if (net_ratelimit()) printk(KERN_ERR "hermes @ %p: " "Error %d issuing command 0x%04x.\n", hw->iobase, err, cmd); goto out; } reg = hermes_read_regn(hw, EVSTAT); k = CMD_COMPL_TIMEOUT; while ((!(reg & HERMES_EV_CMD)) && k) { k--; udelay(10); reg = hermes_read_regn(hw, EVSTAT); } if (!hermes_present(hw)) { printk(KERN_WARNING "hermes @ %p: Card removed " "while waiting for command 0x%04x completion.\n", hw->iobase, cmd); err = -ENODEV; goto out; } if (!(reg & HERMES_EV_CMD)) { printk(KERN_ERR "hermes @ %p: Timeout waiting for " "command 0x%04x completion.\n", hw->iobase, cmd); err = -ETIMEDOUT; goto out; } status = hermes_read_regn(hw, STATUS); if (resp) { resp->status = status; resp->resp0 = hermes_read_regn(hw, RESP0); resp->resp1 = hermes_read_regn(hw, RESP1); resp->resp2 = hermes_read_regn(hw, RESP2); } hermes_write_regn(hw, EVACK, HERMES_EV_CMD); if (status & HERMES_STATUS_RESULT) err = -EIO; out: return err; }
/* Download either STA or AP firmware into the card. */ static int orinoco_dl_firmware(struct orinoco_private *priv, const struct fw_info *fw, int ap) { /* Plug Data Area (PDA) */ __le16 *pda; struct hermes *hw = &priv->hw; const struct firmware *fw_entry; const struct orinoco_fw_header *hdr; const unsigned char *first_block; const void *end; const char *firmware; const char *fw_err; struct device *dev = priv->dev; int err = 0; pda = kzalloc(fw->pda_size, GFP_KERNEL); if (!pda) return -ENOMEM; if (ap) firmware = fw->ap_fw; else firmware = fw->sta_fw; dev_dbg(dev, "Attempting to download firmware %s\n", firmware); /* Read current plug data */ err = hw->ops->read_pda_h(hw, pda, fw->pda_addr, fw->pda_size); dev_dbg(dev, "Read PDA returned %d\n", err); if (err) goto free; if (!orinoco_cached_fw_get(priv, false)) { err = request_firmware(&fw_entry, firmware, priv->dev); if (err) { dev_err(dev, "Cannot find firmware %s\n", firmware); err = -ENOENT; goto free; } } else fw_entry = orinoco_cached_fw_get(priv, false); hdr = (const struct orinoco_fw_header *) fw_entry->data; fw_err = validate_fw(hdr, fw_entry->size); if (fw_err) { dev_warn(dev, "Invalid firmware image detected (%s). " "Aborting download\n", fw_err); err = -EINVAL; goto abort; } /* Enable aux port to allow programming */ err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point)); dev_dbg(dev, "Program init returned %d\n", err); if (err != 0) goto abort; /* Program data */ first_block = (fw_entry->data + le16_to_cpu(hdr->headersize) + le32_to_cpu(hdr->block_offset)); end = fw_entry->data + fw_entry->size; err = hermes_program(hw, first_block, end); dev_dbg(dev, "Program returned %d\n", err); if (err != 0) goto abort; /* Update production data */ first_block = (fw_entry->data + le16_to_cpu(hdr->headersize) + le32_to_cpu(hdr->pdr_offset)); err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, &pda[fw->pda_size / sizeof(*pda)]); dev_dbg(dev, "Apply PDA returned %d\n", err); if (err) goto abort; /* Tell card we've finished */ err = hw->ops->program_end(hw); dev_dbg(dev, "Program end returned %d\n", err); if (err != 0) goto abort; /* Check if we're running */ dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); abort: /* If we requested the firmware, release it. */ if (!orinoco_cached_fw_get(priv, false)) release_firmware(fw_entry); free: kfree(pda); return err; }
/* * Process a firmware image - stop the card, load the firmware, reset * the card and make sure it responds. For the secondary firmware take * care of the PDA - read it and then write it on top of the firmware. */ static int symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, const unsigned char *image, const void *end, int secondary) { struct hermes *hw = &priv->hw; int ret = 0; const unsigned char *ptr; const unsigned char *first_block; /* Plug Data Area (PDA) */ __le16 *pda = NULL; /* Binary block begins after the 0x1A marker */ ptr = image; while (*ptr++ != TEXT_END); first_block = ptr; /* Read the PDA from EEPROM */ if (secondary) { pda = kzalloc(fw->pda_size, GFP_KERNEL); if (!pda) return -ENOMEM; ret = hw->ops->read_pda_h(hw, pda, fw->pda_addr, fw->pda_size); if (ret) goto free; } /* Stop the firmware, so that it can be safely rewritten */ if (priv->stop_fw) { ret = priv->stop_fw(priv, 1); if (ret) goto free; } /* Program the adapter with new firmware */ ret = hermes_program(hw, first_block, end); if (ret) goto free; /* Write the PDA to the adapter */ if (secondary) { size_t len = hermes_blocks_length(first_block, end); ptr = first_block + len; ret = hermes_apply_pda(hw, ptr, end, pda, &pda[fw->pda_size / sizeof(*pda)]); kfree(pda); if (ret) return ret; } /* Run the firmware */ if (priv->stop_fw) { ret = priv->stop_fw(priv, 0); if (ret) return ret; } /* Reset hermes chip and make sure it responds */ ret = hw->ops->init(hw); /* hermes_reset() should return 0 with the secondary firmware */ if (secondary && ret != 0) return -ENODEV; /* And this should work with any firmware */ if (!hermes_present(hw)) return -ENODEV; return 0; free: kfree(pda); return ret; }
/***************************************************************************** * hermes_init * * * * Initialize the card * *****************************************************************************/ int hermes_init (hermes_t * hw) { u32_t status, reg, resp0; int err = 0; int k; /* We don't want to be interrupted while resetting the chipset. By * setting the control mask for hardware interrupt generation to 0, * we won't be disturbed*/ hw->inten = 0x0; hermes_write_reg (hw, HERMES_INTEN, 0); /* Acknowledge any pending events waiting for acknowledgement. We * assume there won't be any important to take care off */ hermes_write_reg (hw, HERMES_EVACK, 0xffff); /* Normally it's a "can't happen" for the command register to * be busy when we go to issue a command because we are * serializing all commands. However we want to have some * chance of resetting the card even if it gets into a stupid * state, so we actually wait to see if the command register * will unbusy itself here. */ k = HERMES_CMD_BUSY_TIMEOUT; reg = hermes_read_reg (hw, HERMES_CMD); while (k && (reg & HERMES_CMD_BUSY)) { if (reg == 0xffff) { /* Special case - the card has probably * been removed, so don't wait for the * timeout */ printf("Hermes: Card removed?\n"); return -ENODEV; } k--; micro_delay (1); reg = hermes_read_reg (hw, HERMES_CMD); } /* No need to explicitly handle the timeout - if we've timed * out hermes_issue_cmd() will probably return -EBUSY below. * But i check to be sure :-) */ if (reg & HERMES_CMD_BUSY) { printf("Hermes: Timeout waiting for the CMD_BUSY to unset\n"); return -EBUSY; } /* According to the documentation, EVSTAT may contain * obsolete event occurrence information. We have to acknowledge * it by writing EVACK. */ reg = hermes_read_reg (hw, HERMES_EVSTAT); hermes_write_reg (hw, HERMES_EVACK, reg); err = hermes_issue_cmd (hw, HERMES_CMD_INIT, 0); if (err){ printf("Hermes: errornr: 0x%x issueing HERMES_CMD_INIT\n", err); return err; } /* here we start waiting for the above command,CMD_INIT, to complete. * Completion is noticeable when the HERMES_EV_CMD bit in the * HERMES_EVSTAT register is set to 1 */ reg = hermes_read_reg (hw, HERMES_EVSTAT); k = HERMES_CMD_INIT_TIMEOUT; while ((!(reg & HERMES_EV_CMD)) && k) { k--; micro_delay (10); reg = hermes_read_reg (hw, HERMES_EVSTAT); } /* the software support register 0 (there are 3) is filled with a * magic number. With this one can test the availability of the card */ hermes_write_reg (hw, HERMES_SWSUPPORT0, HERMES_MAGIC); if (!hermes_present (hw)) { printf("Hermes: Card not present?: got mag. nr.0x%x\n", hermes_read_reg (hw, HERMES_SWSUPPORT0)); } if (!(reg & HERMES_EV_CMD)) { printf("hermes @ %x: Timeout waiting for card to reset\n", hw->iobase); return -ETIMEDOUT; } status = hermes_read_reg (hw, HERMES_STATUS); resp0 = hermes_read_reg (hw, HERMES_RESP0); /* after having issued the command above, the completion set a bit in * the EVSTAT register. This has to be acknowledged, as follows */ hermes_write_reg (hw, HERMES_EVACK, HERMES_EV_CMD); /* Was the status, the result of the issued command, ok? */ /* The expression below should be zero. Non-zero means an error */ if (status & HERMES_STATUS_RESULT) { printf("Hermes:Result of INIT_CMD wrong.error value: 0x%x\n", (status & HERMES_STATUS_RESULT) >> 8); err = -EIO; }