Commit ab5c4f71 authored by Gabor Juhos's avatar Gabor Juhos Committed by John W. Linville

ath9k: allow to load EEPROM content via firmware API

The calibration data for devices w/o a separate
EEPROM chip can be specified via the 'eeprom_data'
field of 'ath9k_platform_data'. The 'eeprom_data'
is usually filled from board specific setup
functions. It is easy if the EEPROM data is mapped
to the memory, but it can be complicated if it is
stored elsewhere.

The patch adds support for loading of the EEPROM
data via the firmware API to avoid this limitation.
Signed-off-by: default avatarGabor Juhos <juhosg@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 0e4b9f2f
...@@ -113,12 +113,29 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data, ...@@ -113,12 +113,29 @@ void ath9k_hw_usb_gen_fill_eeprom(struct ath_hw *ah, u16 *eep_data,
} }
} }
static bool ath9k_hw_nvram_read_blob(struct ath_hw *ah, u32 off,
u16 *data)
{
u16 *blob_data;
if (off * sizeof(u16) > ah->eeprom_blob->size)
return false;
blob_data = (u16 *)ah->eeprom_blob->data;
*data = blob_data[off];
return true;
}
bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data) bool ath9k_hw_nvram_read(struct ath_hw *ah, u32 off, u16 *data)
{ {
struct ath_common *common = ath9k_hw_common(ah); struct ath_common *common = ath9k_hw_common(ah);
bool ret; bool ret;
ret = common->bus_ops->eeprom_read(common, off, data); if (ah->eeprom_blob)
ret = ath9k_hw_nvram_read_blob(ah, off, data);
else
ret = common->bus_ops->eeprom_read(common, off, data);
if (!ret) if (!ret)
ath_dbg(common, EEPROM, ath_dbg(common, EEPROM,
"unable to read eeprom region at offset %u\n", off); "unable to read eeprom region at offset %u\n", off);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/if_ether.h> #include <linux/if_ether.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/firmware.h>
#include "mac.h" #include "mac.h"
#include "ani.h" #include "ani.h"
...@@ -921,6 +922,8 @@ struct ath_hw { ...@@ -921,6 +922,8 @@ struct ath_hw {
bool is_clk_25mhz; bool is_clk_25mhz;
int (*get_mac_revision)(void); int (*get_mac_revision)(void);
int (*external_reset)(void); int (*external_reset)(void);
const struct firmware *eeprom_blob;
}; };
struct ath_bus_ops { struct ath_bus_ops {
......
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
#include "ath9k.h" #include "ath9k.h"
struct ath9k_eeprom_ctx {
struct completion complete;
struct ath_hw *ah;
};
static char *dev_info = "ath9k"; static char *dev_info = "ath9k";
MODULE_AUTHOR("Atheros Communications"); MODULE_AUTHOR("Atheros Communications");
...@@ -506,6 +511,51 @@ static void ath9k_init_misc(struct ath_softc *sc) ...@@ -506,6 +511,51 @@ static void ath9k_init_misc(struct ath_softc *sc)
sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT; sc->ant_comb.count = ATH_ANT_DIV_COMB_INIT_COUNT;
} }
static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob,
void *ctx)
{
struct ath9k_eeprom_ctx *ec = ctx;
if (eeprom_blob)
ec->ah->eeprom_blob = eeprom_blob;
complete(&ec->complete);
}
static int ath9k_eeprom_request(struct ath_softc *sc, const char *name)
{
struct ath9k_eeprom_ctx ec;
struct ath_hw *ah = ah = sc->sc_ah;
int err;
/* try to load the EEPROM content asynchronously */
init_completion(&ec.complete);
ec.ah = sc->sc_ah;
err = request_firmware_nowait(THIS_MODULE, 1, name, sc->dev, GFP_KERNEL,
&ec, ath9k_eeprom_request_cb);
if (err < 0) {
ath_err(ath9k_hw_common(ah),
"EEPROM request failed\n");
return err;
}
wait_for_completion(&ec.complete);
if (!ah->eeprom_blob) {
ath_err(ath9k_hw_common(ah),
"Unable to load EEPROM file %s\n", name);
return -EINVAL;
}
return 0;
}
static void ath9k_eeprom_release(struct ath_softc *sc)
{
release_firmware(sc->sc_ah->eeprom_blob);
}
static int ath9k_init_softc(u16 devid, struct ath_softc *sc, static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
const struct ath_bus_ops *bus_ops) const struct ath_bus_ops *bus_ops)
{ {
...@@ -583,6 +633,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -583,6 +633,12 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
ath_read_cachesize(common, &csz); ath_read_cachesize(common, &csz);
common->cachelsz = csz << 2; /* convert to bytes */ common->cachelsz = csz << 2; /* convert to bytes */
if (pdata->eeprom_name) {
ret = ath9k_eeprom_request(sc, pdata->eeprom_name);
if (ret)
goto err_eeprom;
}
/* Initializes the hardware for all supported chipsets */ /* Initializes the hardware for all supported chipsets */
ret = ath9k_hw_init(ah); ret = ath9k_hw_init(ah);
if (ret) if (ret)
...@@ -619,7 +675,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, ...@@ -619,7 +675,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
err_queues: err_queues:
ath9k_hw_deinit(ah); ath9k_hw_deinit(ah);
err_hw: err_hw:
ath9k_eeprom_release(sc);
err_eeprom:
kfree(ah); kfree(ah);
sc->sc_ah = NULL; sc->sc_ah = NULL;
...@@ -882,6 +939,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc) ...@@ -882,6 +939,7 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
if (sc->dfs_detector != NULL) if (sc->dfs_detector != NULL)
sc->dfs_detector->exit(sc->dfs_detector); sc->dfs_detector->exit(sc->dfs_detector);
ath9k_eeprom_release(sc);
kfree(sc->sc_ah); kfree(sc->sc_ah);
sc->sc_ah = NULL; sc->sc_ah = NULL;
} }
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#define ATH9K_PLAT_EEP_MAX_WORDS 2048 #define ATH9K_PLAT_EEP_MAX_WORDS 2048
struct ath9k_platform_data { struct ath9k_platform_data {
const char *eeprom_name;
u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS]; u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
u8 *macaddr; u8 *macaddr;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment