137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy/* Firmware file reading and download helpers 237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * 337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * See copyright notice in main.c 437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy */ 537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#include <linux/kernel.h> 65a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#include <linux/firmware.h> 844d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy#include <linux/device.h> 99d9779e723a5d23b94abbe5bb7d1197921f6f3ddPaul Gortmaker#include <linux/module.h> 1037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 1137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#include "hermes.h" 1237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#include "hermes_dld.h" 1337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#include "orinoco.h" 1437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 1537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#include "fw.h" 1637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 1737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy/* End markers (for Symbol firmware only) */ 1837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy#define TEXT_END 0x1A /* End of text header */ 1937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 2037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroystruct fw_info { 2137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy char *pri_fw; 2237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy char *sta_fw; 2337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy char *ap_fw; 2437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy u32 pda_addr; 2537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy u16 pda_size; 2637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy}; 2737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 28f733ded107ff15022e3f0f8204f11ab2e83a2aa4Tobias Klauserstatic const struct fw_info orinoco_fw[] = { 2937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, 3037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, 3137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } 3237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy}; 336f48d0e981c026572eac643ed43ebfb883048c14Ben HutchingsMODULE_FIRMWARE("agere_sta_fw.bin"); 346f48d0e981c026572eac643ed43ebfb883048c14Ben HutchingsMODULE_FIRMWARE("agere_ap_fw.bin"); 356f48d0e981c026572eac643ed43ebfb883048c14Ben HutchingsMODULE_FIRMWARE("prism_sta_fw.bin"); 366f48d0e981c026572eac643ed43ebfb883048c14Ben HutchingsMODULE_FIRMWARE("prism_ap_fw.bin"); 376f48d0e981c026572eac643ed43ebfb883048c14Ben HutchingsMODULE_FIRMWARE("symbol_sp24t_prim_fw"); 386f48d0e981c026572eac643ed43ebfb883048c14Ben HutchingsMODULE_FIRMWARE("symbol_sp24t_sec_fw"); 3937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 4037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy/* Structure used to access fields in FW 4137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * Make sure LE decoding macros are used 4237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy */ 4337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroystruct orinoco_fw_header { 4437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy char hdr_vers[6]; /* ASCII string for header version */ 4537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le16 headersize; /* Total length of header */ 4637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le32 entry_point; /* NIC entry point */ 4737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le32 blocks; /* Number of blocks to program */ 4837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le32 block_offset; /* Offset of block data from eof header */ 4937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le32 pdr_offset; /* Offset to PDR data from eof header */ 5037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le32 pri_offset; /* Offset to primary plug data */ 5137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le32 compat_offset; /* Offset to compatibility data*/ 5237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy char signature[0]; /* FW signature length headersize-20 */ 53ba2d3587912f82d1ab4367975b1df460db60fb1eEric Dumazet} __packed; 5437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 557e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy/* Check the range of various header entries. Return a pointer to a 567e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy * description of the problem, or NULL if everything checks out. */ 577e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroystatic const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len) 587e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy{ 597e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy u16 hdrsize; 607e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy 617e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if (len < sizeof(*hdr)) 627e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "image too small"; 637e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if (memcmp(hdr->hdr_vers, "HFW", 3) != 0) 647e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "format not recognised"; 657e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy 667e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy hdrsize = le16_to_cpu(hdr->headersize); 677e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if (hdrsize > len) 687e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "bad headersize"; 697e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len) 707e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "bad block offset"; 717e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len) 727e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "bad PDR offset"; 737e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len) 747e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "bad PRI offset"; 757e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len) 767e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return "bad compat offset"; 777e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy 787e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy /* TODO: consider adding a checksum or CRC to the firmware format */ 797e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy return NULL; 807e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy} 817e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy 822bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) 832bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkovstatic inline const struct firmware * 842bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkovorinoco_cached_fw_get(struct orinoco_private *priv, bool primary) 852bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov{ 862bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (primary) 872bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov return priv->cached_pri_fw; 882bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov else 892bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov return priv->cached_fw; 902bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov} 912bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov#else 922bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov#define orinoco_cached_fw_get(priv, primary) (NULL) 932bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov#endif 942bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov 9537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy/* Download either STA or AP firmware into the card. */ 9637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroystatic int 9737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyorinoco_dl_firmware(struct orinoco_private *priv, 9837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const struct fw_info *fw, 9937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy int ap) 10037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy{ 10137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Plug Data Area (PDA) */ 10237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le16 *pda; 10337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 104933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin struct hermes *hw = &priv->hw; 10537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const struct firmware *fw_entry; 10637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const struct orinoco_fw_header *hdr; 10737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const unsigned char *first_block; 1083faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy const void *end; 10937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const char *firmware; 1107e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy const char *fw_err; 11144d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy struct device *dev = priv->dev; 11237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy int err = 0; 11337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 11437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy pda = kzalloc(fw->pda_size, GFP_KERNEL); 11537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (!pda) 11637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return -ENOMEM; 11737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 11837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ap) 11937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy firmware = fw->ap_fw; 12037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy else 12137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy firmware = fw->sta_fw; 12237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 12344d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "Attempting to download firmware %s\n", firmware); 12437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 12537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Read current plug data */ 12607cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy err = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); 12744d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "Read PDA returned %d\n", err); 12837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (err) 12937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto free; 13037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 1312bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (!orinoco_cached_fw_get(priv, false)) { 13237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy err = request_firmware(&fw_entry, firmware, priv->dev); 13337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 13437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (err) { 13544d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_err(dev, "Cannot find firmware %s\n", firmware); 13637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy err = -ENOENT; 13737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto free; 13837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 13937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } else 1402bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov fw_entry = orinoco_cached_fw_get(priv, false); 14137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 14237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy hdr = (const struct orinoco_fw_header *) fw_entry->data; 14337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 1447e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy fw_err = validate_fw(hdr, fw_entry->size); 1457e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy if (fw_err) { 14644d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_warn(dev, "Invalid firmware image detected (%s). " 14744d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy "Aborting download\n", fw_err); 1487e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy err = -EINVAL; 1497e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy goto abort; 1507e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy } 1517e57811ac5b595bdb53f2aef3bcb2b3d72663fa4David Kilroy 15237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Enable aux port to allow programming */ 15307cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy err = hw->ops->program_init(hw, le32_to_cpu(hdr->entry_point)); 15444d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "Program init returned %d\n", err); 15537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (err != 0) 15637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto abort; 15737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 15837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Program data */ 15937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy first_block = (fw_entry->data + 16037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy le16_to_cpu(hdr->headersize) + 16137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy le32_to_cpu(hdr->block_offset)); 16237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy end = fw_entry->data + fw_entry->size; 16337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 16437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy err = hermes_program(hw, first_block, end); 16544d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "Program returned %d\n", err); 16637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (err != 0) 16737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto abort; 16837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 16937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Update production data */ 17037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy first_block = (fw_entry->data + 17137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy le16_to_cpu(hdr->headersize) + 17237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy le32_to_cpu(hdr->pdr_offset)); 17337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 1743faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy err = hermes_apply_pda_with_defaults(hw, first_block, end, pda, 1753faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy &pda[fw->pda_size / sizeof(*pda)]); 17644d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "Apply PDA returned %d\n", err); 17737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (err) 17837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto abort; 17937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 18037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Tell card we've finished */ 18107cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy err = hw->ops->program_end(hw); 18244d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "Program end returned %d\n", err); 18337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (err != 0) 18437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto abort; 18537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 18637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Check if we're running */ 18744d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_dbg(dev, "hermes_present returned %d\n", hermes_present(hw)); 18837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 18937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyabort: 19037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* If we requested the firmware, release it. */ 1912bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (!orinoco_cached_fw_get(priv, false)) 19237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy release_firmware(fw_entry); 19337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 19437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyfree: 19537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy kfree(pda); 19637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return err; 19737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy} 19837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 19937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy/* 20037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * Process a firmware image - stop the card, load the firmware, reset 20137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * the card and make sure it responds. For the secondary firmware take 20237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * care of the PDA - read it and then write it on top of the firmware. 20337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy */ 20437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroystatic int 20537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroysymbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw, 2063faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy const unsigned char *image, const void *end, 20737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy int secondary) 20837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy{ 209933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin struct hermes *hw = &priv->hw; 21037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy int ret = 0; 21137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const unsigned char *ptr; 21237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const unsigned char *first_block; 21337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 21437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Plug Data Area (PDA) */ 21537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy __le16 *pda = NULL; 21637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 21737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Binary block begins after the 0x1A marker */ 21837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ptr = image; 21937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy while (*ptr++ != TEXT_END); 22037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy first_block = ptr; 22137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 22237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Read the PDA from EEPROM */ 22337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (secondary) { 22437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy pda = kzalloc(fw->pda_size, GFP_KERNEL); 22537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (!pda) 22637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return -ENOMEM; 22737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 22807cefe7ac983374ee4c369f1d4aee3093bf3b44fDavid Kilroy ret = hw->ops->read_pda(hw, pda, fw->pda_addr, fw->pda_size); 22937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ret) 23037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto free; 23137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 23237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 23337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Stop the firmware, so that it can be safely rewritten */ 23437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (priv->stop_fw) { 23537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ret = priv->stop_fw(priv, 1); 23637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ret) 23737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto free; 23837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 23937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 24037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Program the adapter with new firmware */ 24137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ret = hermes_program(hw, first_block, end); 24237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ret) 24337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy goto free; 24437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 24537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Write the PDA to the adapter */ 24637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (secondary) { 2473faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy size_t len = hermes_blocks_length(first_block, end); 24837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ptr = first_block + len; 2493faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy ret = hermes_apply_pda(hw, ptr, end, pda, 2503faa19cd9dfac30aa08bc311ddbd62ee5ccc0d85David Kilroy &pda[fw->pda_size / sizeof(*pda)]); 25137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy kfree(pda); 25237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ret) 25337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return ret; 25437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 25537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 25637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Run the firmware */ 25737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (priv->stop_fw) { 25837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ret = priv->stop_fw(priv, 0); 25937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ret) 26037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return ret; 26137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 26237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 26337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Reset hermes chip and make sure it responds */ 264b42f2074dedef559ecf72dce61a6501f9f9b273aDavid Kilroy ret = hw->ops->init(hw); 26537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 26637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* hermes_reset() should return 0 with the secondary firmware */ 26737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (secondary && ret != 0) 26837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return -ENODEV; 26937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 27037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* And this should work with any firmware */ 27137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (!hermes_present(hw)) 27237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return -ENODEV; 27337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 27437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return 0; 27537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 27637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyfree: 27737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy kfree(pda); 27837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return ret; 27937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy} 28037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 28137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 28237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy/* 28337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * Download the firmware into the card, this also does a PCMCIA soft 28437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * reset on the card, to make sure it's in a sane state. 28537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy */ 28637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroystatic int 28737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroysymbol_dl_firmware(struct orinoco_private *priv, 28837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const struct fw_info *fw) 28937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy{ 29044d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy struct device *dev = priv->dev; 29137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy int ret; 29237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const struct firmware *fw_entry; 29337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 2942bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (!orinoco_cached_fw_get(priv, true)) { 29537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { 29644d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_err(dev, "Cannot find firmware: %s\n", fw->pri_fw); 29737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return -ENOENT; 29837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 29937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } else 3002bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov fw_entry = orinoco_cached_fw_get(priv, true); 30137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 30237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Load primary firmware */ 30337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ret = symbol_dl_image(priv, fw, fw_entry->data, 30437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy fw_entry->data + fw_entry->size, 0); 30537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 3062bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (!orinoco_cached_fw_get(priv, true)) 30737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy release_firmware(fw_entry); 30837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ret) { 30944d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_err(dev, "Primary firmware download failed\n"); 31037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return ret; 31137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 31237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 3132bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (!orinoco_cached_fw_get(priv, false)) { 31437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { 31544d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_err(dev, "Cannot find firmware: %s\n", fw->sta_fw); 31637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return -ENOENT; 31737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 31837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } else 3192bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov fw_entry = orinoco_cached_fw_get(priv, false); 32037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 32137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Load secondary firmware */ 32237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy ret = symbol_dl_image(priv, fw, fw_entry->data, 32337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy fw_entry->data + fw_entry->size, 1); 3242bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov if (!orinoco_cached_fw_get(priv, false)) 32537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy release_firmware(fw_entry); 326933d594313a5928ffc5325d7bbb6e2383d79622ePavel Roskin if (ret) 32744d8dade8f12ffe5c9b7eddd0512c1548c027a4cDavid Kilroy dev_err(dev, "Secondary firmware download failed\n"); 32837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 32937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return ret; 33037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy} 33137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 33237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyint orinoco_download(struct orinoco_private *priv) 33337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy{ 33437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy int err = 0; 33537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* Reload firmware */ 33637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy switch (priv->firmware_type) { 33737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy case FIRMWARE_TYPE_AGERE: 33837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* case FIRMWARE_TYPE_INTERSIL: */ 33937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy err = orinoco_dl_firmware(priv, 34037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy &orinoco_fw[priv->firmware_type], 0); 34137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy break; 34237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 34337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy case FIRMWARE_TYPE_SYMBOL: 34437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy err = symbol_dl_firmware(priv, 34537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy &orinoco_fw[priv->firmware_type]); 34637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy break; 34737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy case FIRMWARE_TYPE_INTERSIL: 34837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy break; 34937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 35037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy /* TODO: if we fail we probably need to reinitialise 35137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy * the driver */ 35237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 35337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy return err; 35437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy} 35537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 3562bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) 35737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyvoid orinoco_cache_fw(struct orinoco_private *priv, int ap) 35837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy{ 35937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const struct firmware *fw_entry = NULL; 36037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const char *pri_fw; 36137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy const char *fw; 36237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 36337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy pri_fw = orinoco_fw[priv->firmware_type].pri_fw; 36437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (ap) 36537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy fw = orinoco_fw[priv->firmware_type].ap_fw; 36637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy else 36737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy fw = orinoco_fw[priv->firmware_type].sta_fw; 36837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 36937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (pri_fw) { 37037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) 37137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy priv->cached_pri_fw = fw_entry; 37237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 37337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 37437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (fw) { 37537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (request_firmware(&fw_entry, fw, priv->dev) == 0) 37637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy priv->cached_fw = fw_entry; 37737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy } 37837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy} 37937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 38037a2e566f82de9a88fe119479162f9984af2180dDavid Kilroyvoid orinoco_uncache_fw(struct orinoco_private *priv) 38137a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy{ 38237a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (priv->cached_pri_fw) 38337a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy release_firmware(priv->cached_pri_fw); 38437a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy if (priv->cached_fw) 38537a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy release_firmware(priv->cached_fw); 38637a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy 38737a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy priv->cached_pri_fw = NULL; 38837a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy priv->cached_fw = NULL; 38937a2e566f82de9a88fe119479162f9984af2180dDavid Kilroy} 3902bfc5cb57b55ed2204bca7668e082f7bf485760aAndrey Borzenkov#endif 391