2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 00/12] ath9k: add preliminary support for the AR913x SoCs

This patch set introduces preliminary support for the Atheros' AR9130/AR9132
SoCs built-in WMAC device. Tested with compat-wireless-2008-12-29 on 2.6.2{7,8}
kernels.

12 patches will follow as replies:

Gabor Juhos (12):
ath9k: introduce bus specific DMA routines
ath9k: introduce bus specific register access routines
ath9k: introduce bus specific cache size routine
ath9k: introduce bus specific cleanup routine
ath9k: move PCI code into separate file
ath9k: convert to struct device
ath9k: introduce platform driver for AHB bus support
ath9k: get EEPROM contents from platform data on AHB bus
ath9k: enable support for AR9100
ath9k: remove (u16) casts from rtc register access
ath9k: fix ar5416Addac_9100 values
ath9k: fix null pointer dereference in ani monitor code

drivers/net/wireless/ath9k/Makefile | 2
drivers/net/wireless/ath9k/ahb.c | 285 +++++++++++++++++++++++++
drivers/net/wireless/ath9k/ani.c | 6 -
drivers/net/wireless/ath9k/ath9k.h | 4
drivers/net/wireless/ath9k/beacon.c | 29 +--
drivers/net/wireless/ath9k/core.h | 137 ++++++++++++
drivers/net/wireless/ath9k/eeprom.c | 51 ----
drivers/net/wireless/ath9k/hw.c | 17 +
drivers/net/wireless/ath9k/initvals.h | 2
drivers/net/wireless/ath9k/main.c | 315 +++------------------------
drivers/net/wireless/ath9k/pci.c | 381 +++++++++++++++++++++++++++++++++
drivers/net/wireless/ath9k/recv.c | 30 +--
drivers/net/wireless/ath9k/xmit.c | 12 -
include/linux/ath9k_platform.h | 28 ++
14 files changed, 913 insertions(+), 386 deletions(-)
create mode 100644 drivers/net/wireless/ath9k/ahb.c
create mode 100644 drivers/net/wireless/ath9k/pci.c
create mode 100644 include/linux/ath9k_platform.h


2009-01-04 07:30:26

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC 07/12] ath9k: introduce platform driver for AHB bus support

On Sat, Jan 03, 2009 at 02:44:17PM +0100, Gabor Juhos wrote:
> +static dma_addr_t ath_ahb_map_single_to_device(struct ath_softc *sc,
> + void *p, size_t size)
> +{
> + return dma_map_single(NULL, p, size, DMA_TO_DEVICE);
> +}

As said before you should just use dma_* directly. And please make sure
to always pass a struct device to the dma_* routines, even if your
platform might currently not required it the API does.

> +static void ath_ahb_cleanup(struct ath_softc *sc)
> +{
> + struct platform_device *pdev = to_platform_device(sc->dev);
> + struct ieee80211_hw *hw = sc->hw;
> + struct resource *res;
> +
> + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
> + if (res)
> + free_irq(res->start, sc);

If you stored the irq value directly in the softc this whole thing might
be able to be done in a generic way..


2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 09/12] ath9k: enable support for AR9100

Because we have support for the AR9100 devices now, we can enable them.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/hw.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index d2b0ecf..ca0fc53 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -389,6 +389,8 @@ static const char *ath9k_hw_devname(u16 devid)
return "Atheros 5418";
case AR9160_DEVID_PCI:
return "Atheros 9160";
+ case AR5416_AR9100_DEVID:
+ return "Atheros 9100";
case AR9280_DEVID_PCI:
case AR9280_DEVID_PCIE:
return "Atheros 9280";
@@ -1192,6 +1194,7 @@ struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc,
switch (devid) {
case AR5416_DEVID_PCI:
case AR5416_DEVID_PCIE:
+ case AR5416_AR9100_DEVID:
case AR9160_DEVID_PCI:
case AR9280_DEVID_PCI:
case AR9280_DEVID_PCIE:
--
1.5.3.2


2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 08/12] ath9k: get EEPROM contents from platform data on AHB bus

On the AR913x SOCs we have to provide EEPROM contents via platform_data,
because accessing the flash via MMIO is not safe. Additionally different
boards may store the radio calibration data at different locations.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/ahb.c | 27 ++++++++++++++++++
drivers/net/wireless/ath9k/core.h | 2 +
drivers/net/wireless/ath9k/eeprom.c | 51 ++--------------------------------
drivers/net/wireless/ath9k/pci.c | 19 +++++++++++++
include/linux/ath9k_platform.h | 28 +++++++++++++++++++
5 files changed, 79 insertions(+), 48 deletions(-)

diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath9k/ahb.c
index bf37a9e..7fece47 100644
--- a/drivers/net/wireless/ath9k/ahb.c
+++ b/drivers/net/wireless/ath9k/ahb.c
@@ -18,6 +18,7 @@

#include <linux/nl80211.h>
#include <linux/platform_device.h>
+#include <linux/ath9k_platform.h>
#include "core.h"
#include "reg.h"
#include "hw.h"
@@ -101,6 +102,24 @@ static void ath_ahb_cleanup(struct ath_softc *sc)
platform_set_drvdata(pdev, NULL);
}

+static bool ath_ahb_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+ struct ath_softc *sc = ah->ah_sc;
+ struct platform_device *pdev = to_platform_device(sc->dev);
+ struct ath9k_platform_data *pdata;
+
+ pdata = (struct ath9k_platform_data *) pdev->dev.platform_data;
+ if (off >= (ARRAY_SIZE(pdata->eeprom_data))) {
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
+ "%s: flash read failed, offset %08x is out of range\n",
+ __func__, off);
+ return false;
+ }
+
+ *data = pdata->eeprom_data[off];
+ return true;
+}
+
static struct ath_bus_ops ath_ahb_bus_ops = {
.dma_map_single_to_device = ath_ahb_map_single_to_device,
.dma_unmap_single_to_device = ath_ahb_unmap_single_to_device,
@@ -118,6 +137,8 @@ static struct ath_bus_ops ath_ahb_bus_ops = {
.read_cachesize = ath_ahb_read_cachesize,

.cleanup = ath_ahb_cleanup,
+
+ .eeprom_read = ath_ahb_eeprom_read,
};

static int ath_ahb_probe(struct platform_device *pdev)
@@ -130,6 +151,12 @@ static int ath_ahb_probe(struct platform_device *pdev)
int ret = 0;
struct ath_hal *ah;

+ if (!pdev->dev.platform_data) {
+ dev_err(&pdev->dev, "no platform data specified\n");
+ ret = -EINVAL;
+ goto err_out;
+ }
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "no memory resource found\n");
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index bb8b45b..4f915d8 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -726,6 +726,8 @@ struct ath_bus_ops {
void (*read_cachesize)(struct ath_softc *sc, int *csz);

void (*cleanup)(struct ath_softc *sc);
+
+ bool (*eeprom_read)(struct ath_hal *ah, u32 off, u16 *data);
};

struct ath_softc {
diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c
index 14f8d40..73a480e 100644
--- a/drivers/net/wireless/ath9k/eeprom.c
+++ b/drivers/net/wireless/ath9k/eeprom.c
@@ -91,53 +91,11 @@ static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList,
return false;
}

-static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
-{
- (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
-
- if (!ath9k_hw_wait(ah,
- AR_EEPROM_STATUS_DATA,
- AR_EEPROM_STATUS_DATA_BUSY |
- AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
- return false;
- }
-
- *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
- AR_EEPROM_STATUS_DATA_VAL);
-
- return true;
-}
-
-static int ath9k_hw_flash_map(struct ath_hal *ah)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX);
-
- if (!ahp->ah_cal_mem) {
- DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
- "cannot remap eeprom region \n");
- return -EIO;
- }
-
- return 0;
-}
-
-static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data)
-{
- struct ath_hal_5416 *ahp = AH5416(ah);
-
- *data = ioread16(ahp->ah_cal_mem + off);
-
- return true;
-}
-
static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data)
{
- if (ath9k_hw_use_flash(ah))
- return ath9k_hw_flash_read(ah, off, data);
- else
- return ath9k_hw_eeprom_read(ah, off, data);
+ struct ath_softc *sc = ah->ah_sc;
+
+ return sc->bus_ops->eeprom_read(ah, off, data);
}

static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah)
@@ -2805,9 +2763,6 @@ int ath9k_hw_eeprom_attach(struct ath_hal *ah)
int status;
struct ath_hal_5416 *ahp = AH5416(ah);

- if (ath9k_hw_use_flash(ah))
- ath9k_hw_flash_map(ah);
-
if (AR_SREV_9285(ah))
ahp->ah_eep_map = EEP_MAP_4KBITS;
else
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c
index 314bf9d..68b2ea1 100644
--- a/drivers/net/wireless/ath9k/pci.c
+++ b/drivers/net/wireless/ath9k/pci.c
@@ -121,6 +121,23 @@ static void ath_pci_cleanup(struct ath_softc *sc)
ieee80211_free_hw(sc->hw);
}

+static bool ath_pci_eeprom_read(struct ath_hal *ah, u32 off, u16 *data)
+{
+ (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S));
+
+ if (!ath9k_hw_wait(ah,
+ AR_EEPROM_STATUS_DATA,
+ AR_EEPROM_STATUS_DATA_BUSY |
+ AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+ return false;
+ }
+
+ *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA),
+ AR_EEPROM_STATUS_DATA_VAL);
+
+ return true;
+}
+
static struct ath_bus_ops ath_pci_bus_ops = {
.dma_map_single_to_device = ath_pci_map_single_to_device,
.dma_unmap_single_to_device = ath_pci_unmap_single_to_device,
@@ -138,6 +155,8 @@ static struct ath_bus_ops ath_pci_bus_ops = {
.read_cachesize = ath_pci_read_cachesize,

.cleanup = ath_pci_cleanup,
+
+ .eeprom_read = ath_pci_eeprom_read,
};

static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h
new file mode 100644
index 0000000..06b7461
--- /dev/null
+++ b/include/linux/ath9k_platform.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <[email protected]>
+ * Copyright (c) 2009 Imre Kaloz <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _LINUX_ATH9K_PLATFORM_H
+#define _LINUX_ATH9L_PLATFORM_H
+
+#define ATH9K_PLAT_EEP_MAX_WORDS 2048
+
+struct ath9k_platform_data {
+ u16 eeprom_data[ATH9K_PLAT_EEP_MAX_WORDS];
+};
+
+#endif /* _LINUX_ATH9K_PLATFORM_H */
--
1.5.3.2


2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 03/12] ath9k: introduce bus specific cache size routine

The PCI specific bus_read_cachesize routine won't work on the AHB bus,
we have to replace it with a suitable one later.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/core.h | 7 +++++++
drivers/net/wireless/ath9k/main.c | 8 +++++---
2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index db7ae4e..0c8064e 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -721,6 +721,8 @@ struct ath_bus_ops {

u32 (*reg_read)(struct ath_hal *ah, unsigned reg);
void (*reg_write)(struct ath_hal *ah, unsigned reg, u32 val);
+
+ void (*read_cachesize)(struct ath_softc *sc, int *csz);
};

struct ath_softc {
@@ -843,4 +845,9 @@ static inline void ath_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
sc->bus_ops->reg_write(ah, reg, val);
}

+static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
+{
+ sc->bus_ops->read_cachesize(sc, csz);
+}
+
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 9ce89b4..f1da1ac 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -41,8 +41,7 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = {
static void ath_detach(struct ath_softc *sc);

/* return bus cachesize in 4B word units */
-
-static void bus_read_cachesize(struct ath_softc *sc, int *csz)
+static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
{
u8 u8tmp;

@@ -59,6 +58,7 @@ static void bus_read_cachesize(struct ath_softc *sc, int *csz)
*csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
}

+
static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
{
sc->cur_rate_table = sc->hw_rate_table[mode];
@@ -1347,7 +1347,7 @@ static int ath_init(u16 devid, struct ath_softc *sc)
* Cache line size is used to size and align various
* structures used to communicate with the hardware.
*/
- bus_read_cachesize(sc, &csz);
+ ath_read_cachesize(sc, &csz);
/* XXX assert csz is non-zero */
sc->sc_cachelsz = csz << 2; /* convert to bytes */

@@ -2618,6 +2618,8 @@ static struct ath_bus_ops ath_pci_bus_ops = {

.reg_read = ath_pci_reg_read,
.reg_write = ath_pci_reg_write,
+
+ .read_cachesize = ath_pci_read_cachesize,
};

static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
1.5.3.2


2009-01-03 13:44:59

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 05/12] ath9k: move PCI code into separate file

Convert 'struct pci_dev' to 'struct device' to make it usable on the AHB
bus as well.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/Makefile | 1 +
drivers/net/wireless/ath9k/core.h | 16 ++
drivers/net/wireless/ath9k/main.c | 368 ++---------------------------------
drivers/net/wireless/ath9k/pci.c | 357 +++++++++++++++++++++++++++++++++
4 files changed, 395 insertions(+), 347 deletions(-)

diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
index 1209d14..af3f39b 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -11,6 +11,7 @@ ath9k-y += hw.o \
xmit.o \
rc.o

+ath9k-$(CONFIG_PCI) += pci.o
ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o

obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 4833598..73a409b 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -857,4 +857,20 @@ static inline void ath_bus_cleanup(struct ath_softc *sc)
sc->bus_ops->cleanup(sc);
}

+extern struct ieee80211_ops ath9k_ops;
+
+irqreturn_t ath_isr(int irq, void *dev);
+int ath_attach(u16 devid, struct ath_softc *sc);
+void ath_detach(struct ath_softc *sc);
+const char *ath_mac_bb_name(u32 mac_bb_version);
+const char *ath_rf_name(u16 rf_version);
+
+#ifdef CONFIG_PCI
+int ath_pci_init(void);
+void ath_pci_exit(void);
+#else
+static inline int ath_pci_init(void) { return 0; };
+static inline void ath_pci_exit(void) {};
+#endif
+
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index e126b65..423cf3b 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -28,37 +28,6 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");

-static struct pci_device_id ath_pci_id_table[] __devinitdata = {
- { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */
- { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
- { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
- { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
- { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
- { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
- { 0 }
-};
-
-static void ath_detach(struct ath_softc *sc);
-
-/* return bus cachesize in 4B word units */
-static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
-{
- u8 u8tmp;
-
- pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
- *csz = (int)u8tmp;
-
- /*
- * This check was put in to avoid "unplesant" consequences if
- * the bootrom has not fully initialized all PCI devices.
- * Sometimes the cache line size register is not set
- */
-
- if (*csz == 0)
- *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
-}
-
-
static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode)
{
sc->cur_rate_table = sc->hw_rate_table[mode];
@@ -499,7 +468,7 @@ static void ath9k_tasklet(unsigned long data)
ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
}

-static irqreturn_t ath_isr(int irq, void *dev)
+irqreturn_t ath_isr(int irq, void *dev)
{
struct ath_softc *sc = dev;
struct ath_hal *ah = sc->sc_ah;
@@ -1287,7 +1256,7 @@ static int ath_start_rfkill_poll(struct ath_softc *sc)
}
#endif /* CONFIG_RFKILL */

-static void ath_detach(struct ath_softc *sc)
+void ath_detach(struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
int i = 0;
@@ -1538,7 +1507,7 @@ bad:
return error;
}

-static int ath_attach(u16 devid, struct ath_softc *sc)
+int ath_attach(u16 devid, struct ath_softc *sc)
{
struct ieee80211_hw *hw = sc->hw;
int error = 0;
@@ -2466,7 +2435,7 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
return ret;
}

-static struct ieee80211_ops ath9k_ops = {
+struct ieee80211_ops ath9k_ops = {
.tx = ath9k_tx,
.start = ath9k_start,
.stop = ath9k_stop,
@@ -2510,7 +2479,7 @@ static struct {
/*
* Return the MAC/BB name. "????" is returned if the MAC/BB is unknown.
*/
-static const char *
+const char *
ath_mac_bb_name(u32 mac_bb_version)
{
int i;
@@ -2527,7 +2496,7 @@ ath_mac_bb_name(u32 mac_bb_version)
/*
* Return the RF name. "????" is returned if the RF is unknown.
*/
-static const char *
+const char *
ath_rf_name(u16 rf_version)
{
int i;
@@ -2541,306 +2510,7 @@ ath_rf_name(u16 rf_version)
return "????";
}

-static dma_addr_t ath_pci_map_single_to_device(struct ath_softc *sc,
- void *p, size_t size)
-{
- return pci_map_single(sc->pdev, p, size, PCI_DMA_TODEVICE);
-}
-
-static void ath_pci_unmap_single_to_device(struct ath_softc *sc,
- dma_addr_t da, size_t size)
-{
- pci_unmap_single(sc->pdev, da, size, PCI_DMA_TODEVICE);
-}
-
-static dma_addr_t ath_pci_map_single_from_device(struct ath_softc *sc,
- void *p, size_t size)
-{
- return pci_map_single(sc->pdev, p, size, PCI_DMA_FROMDEVICE);
-}
-
-static void ath_pci_unmap_single_from_device(struct ath_softc *sc,
- dma_addr_t da, size_t size)
-{
- pci_unmap_single(sc->pdev, da, size, PCI_DMA_FROMDEVICE);
-}
-
-static int ath_pci_dma_mapping_error(struct ath_softc *sc, dma_addr_t da)
-{
- return pci_dma_mapping_error(sc->pdev, da);
-}
-
-static void ath_pci_sync_single_for_cpu(struct ath_softc *sc, dma_addr_t da,
- size_t size)
-{
- pci_dma_sync_single_for_cpu(sc->pdev, da, size,
- PCI_DMA_FROMDEVICE);
-}
-
-static void *ath_pci_dma_alloc(struct ath_softc *sc, size_t size,
- dma_addr_t *pda)
-{
- return pci_alloc_consistent(sc->pdev, size, pda);
-}
-
-static void ath_pci_dma_free(struct ath_softc *sc, size_t size,
- void *p, dma_addr_t da)
-{
- pci_free_consistent(sc->pdev, size, p, da);
-}
-
-static u32 ath_pci_reg_read(struct ath_hal *ah, unsigned reg)
-{
- return ioread32(ah->ah_sh + reg);
-}
-
-static void ath_pci_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
-{
- iowrite32(val, ah->ah_sh + reg);
-}
-
-static void ath_pci_cleanup(struct ath_softc *sc)
-{
- ath_detach(sc);
- if (sc->pdev->irq)
- free_irq(sc->pdev->irq, sc);
- pci_iounmap(sc->pdev, sc->mem);
- pci_release_region(sc->pdev, 0);
- pci_disable_device(sc->pdev);
- ieee80211_free_hw(sc->hw);
-}
-
-static struct ath_bus_ops ath_pci_bus_ops = {
- .dma_map_single_to_device = ath_pci_map_single_to_device,
- .dma_unmap_single_to_device = ath_pci_unmap_single_to_device,
- .dma_map_single_from_device = ath_pci_map_single_from_device,
- .dma_unmap_single_from_device = ath_pci_unmap_single_from_device,
- .dma_map_single_to_device = ath_pci_map_single_to_device,
- .dma_mapping_error = ath_pci_dma_mapping_error,
- .dma_sync_single_for_cpu = ath_pci_sync_single_for_cpu,
- .dma_alloc = ath_pci_dma_alloc,
- .dma_free = ath_pci_dma_free,
-
- .reg_read = ath_pci_reg_read,
- .reg_write = ath_pci_reg_write,
-
- .read_cachesize = ath_pci_read_cachesize,
-
- .cleanup = ath_pci_cleanup,
-};
-
-static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- void __iomem *mem;
- struct ath_softc *sc;
- struct ieee80211_hw *hw;
- u8 csz;
- u32 val;
- int ret = 0;
- struct ath_hal *ah;
-
- if (pci_enable_device(pdev))
- return -EIO;
-
- ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-
- if (ret) {
- printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
- goto bad;
- }
-
- ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-
- if (ret) {
- printk(KERN_ERR "ath9k: 32-bit DMA consistent "
- "DMA enable failed\n");
- goto bad;
- }
-
- /*
- * Cache line size is used to size and align various
- * structures used to communicate with the hardware.
- */
- pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
- if (csz == 0) {
- /*
- * Linux 2.4.18 (at least) writes the cache line size
- * register as a 16-bit wide register which is wrong.
- * We must have this setup properly for rx buffer
- * DMA to work so force a reasonable value here if it
- * comes up zero.
- */
- csz = L1_CACHE_BYTES / sizeof(u32);
- pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
- }
- /*
- * The default setting of latency timer yields poor results,
- * set it to the value used by other systems. It may be worth
- * tweaking this setting more.
- */
- pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
-
- pci_set_master(pdev);
-
- /*
- * Disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state.
- */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- ret = pci_request_region(pdev, 0, "ath9k");
- if (ret) {
- dev_err(&pdev->dev, "PCI memory region reserve error\n");
- ret = -ENODEV;
- goto bad;
- }
-
- mem = pci_iomap(pdev, 0, 0);
- if (!mem) {
- printk(KERN_ERR "PCI memory map error\n") ;
- ret = -EIO;
- goto bad1;
- }
-
- hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
- if (hw == NULL) {
- printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
- goto bad2;
- }
-
- SET_IEEE80211_DEV(hw, &pdev->dev);
- pci_set_drvdata(pdev, hw);
-
- sc = hw->priv;
- sc->hw = hw;
- sc->pdev = pdev;
- sc->mem = mem;
- sc->bus_ops = &ath_pci_bus_ops;
-
- if (ath_attach(id->device, sc) != 0) {
- ret = -ENODEV;
- goto bad3;
- }
-
- /* setup interrupt service routine */
-
- if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
- printk(KERN_ERR "%s: request_irq failed\n",
- wiphy_name(hw->wiphy));
- ret = -EIO;
- goto bad4;
- }
-
- ah = sc->sc_ah;
- printk(KERN_INFO
- "%s: Atheros AR%s MAC/BB Rev:%x "
- "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
- wiphy_name(hw->wiphy),
- ath_mac_bb_name(ah->ah_macVersion),
- ah->ah_macRev,
- ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
- ah->ah_phyRev,
- (unsigned long)mem, pdev->irq);
-
- return 0;
-bad4:
- ath_detach(sc);
-bad3:
- ieee80211_free_hw(hw);
-bad2:
- pci_iounmap(pdev, mem);
-bad1:
- pci_release_region(pdev, 0);
-bad:
- pci_disable_device(pdev);
- return ret;
-}
-
-static void ath_pci_remove(struct pci_dev *pdev)
-{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath_softc *sc = hw->priv;
-
- ath_pci_cleanup(sc);
-}
-
-#ifdef CONFIG_PM
-
-static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
-{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath_softc *sc = hw->priv;
-
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
- if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
- cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
-#endif
-
- pci_save_state(pdev);
- pci_disable_device(pdev);
- pci_set_power_state(pdev, 3);
-
- return 0;
-}
-
-static int ath_pci_resume(struct pci_dev *pdev)
-{
- struct ieee80211_hw *hw = pci_get_drvdata(pdev);
- struct ath_softc *sc = hw->priv;
- u32 val;
- int err;
-
- err = pci_enable_device(pdev);
- if (err)
- return err;
- pci_restore_state(pdev);
- /*
- * Suspend/Resume resets the PCI configuration space, so we have to
- * re-disable the RETRY_TIMEOUT register (0x41) to keep
- * PCI Tx retries from interfering with C3 CPU state
- */
- pci_read_config_dword(pdev, 0x40, &val);
- if ((val & 0x0000ff00) != 0)
- pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
-
- /* Enable LED */
- ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
- AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
- ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
-
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
- /*
- * check the h/w rfkill state on resume
- * and start the rfkill poll timer
- */
- if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
- queue_delayed_work(sc->hw->workqueue,
- &sc->rf_kill.rfkill_poll, 0);
-#endif
-
- return 0;
-}
-
-#endif /* CONFIG_PM */
-
-MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
-
-static struct pci_driver ath_pci_driver = {
- .name = "ath9k",
- .id_table = ath_pci_id_table,
- .probe = ath_pci_probe,
- .remove = ath_pci_remove,
-#ifdef CONFIG_PM
- .suspend = ath_pci_suspend,
- .resume = ath_pci_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init init_ath_pci(void)
+static int __init ath9k_init(void)
{
int error;

@@ -2852,26 +2522,30 @@ static int __init init_ath_pci(void)
printk(KERN_ERR
"Unable to register rate control algorithm: %d\n",
error);
- ath_rate_control_unregister();
- return error;
+ goto err_out;
}

- if (pci_register_driver(&ath_pci_driver) < 0) {
+ error = ath_pci_init();
+ if (error < 0) {
printk(KERN_ERR
"ath_pci: No devices found, driver not installed.\n");
- ath_rate_control_unregister();
- pci_unregister_driver(&ath_pci_driver);
- return -ENODEV;
+ error = -ENODEV;
+ goto err_rate_unregister;
}

return 0;
+
+ err_rate_unregister:
+ ath_rate_control_unregister();
+ err_out:
+ return error;
}
-module_init(init_ath_pci);
+module_init(ath9k_init);

-static void __exit exit_ath_pci(void)
+static void __exit ath9k_exit(void)
{
+ ath_pci_exit();
ath_rate_control_unregister();
- pci_unregister_driver(&ath_pci_driver);
printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
}
-module_exit(exit_ath_pci);
+module_exit(ath9k_exit);
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c
new file mode 100644
index 0000000..1bb4787
--- /dev/null
+++ b/drivers/net/wireless/ath9k/pci.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/nl80211.h>
+#include "core.h"
+#include "reg.h"
+#include "hw.h"
+
+static struct pci_device_id ath_pci_id_table[] __devinitdata = {
+ { PCI_VDEVICE(ATHEROS, 0x0023) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */
+ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
+ { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */
+ { 0 }
+};
+
+/* return bus cachesize in 4B word units */
+static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
+{
+ u8 u8tmp;
+
+ pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
+ *csz = (int)u8tmp;
+
+ /*
+ * This check was put in to avoid "unplesant" consequences if
+ * the bootrom has not fully initialized all PCI devices.
+ * Sometimes the cache line size register is not set
+ */
+
+ if (*csz == 0)
+ *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */
+}
+
+static dma_addr_t ath_pci_map_single_to_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return pci_map_single(sc->pdev, p, size, PCI_DMA_TODEVICE);
+}
+
+static void ath_pci_unmap_single_to_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ pci_unmap_single(sc->pdev, da, size, PCI_DMA_TODEVICE);
+}
+
+static dma_addr_t ath_pci_map_single_from_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return pci_map_single(sc->pdev, p, size, PCI_DMA_FROMDEVICE);
+}
+
+static void ath_pci_unmap_single_from_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ pci_unmap_single(sc->pdev, da, size, PCI_DMA_FROMDEVICE);
+}
+
+static int ath_pci_dma_mapping_error(struct ath_softc *sc, dma_addr_t da)
+{
+ return pci_dma_mapping_error(sc->pdev, da);
+}
+
+static void ath_pci_sync_single_for_cpu(struct ath_softc *sc, dma_addr_t da,
+ size_t size)
+{
+ pci_dma_sync_single_for_cpu(sc->pdev, da, size,
+ PCI_DMA_FROMDEVICE);
+}
+
+static void *ath_pci_dma_alloc(struct ath_softc *sc, size_t size,
+ dma_addr_t *pda)
+{
+ return pci_alloc_consistent(sc->pdev, size, pda);
+}
+
+static void ath_pci_dma_free(struct ath_softc *sc, size_t size,
+ void *p, dma_addr_t da)
+{
+ pci_free_consistent(sc->pdev, size, p, da);
+}
+
+static u32 ath_pci_reg_read(struct ath_hal *ah, unsigned reg)
+{
+ return ioread32(ah->ah_sh + reg);
+}
+
+static void ath_pci_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
+{
+ iowrite32(val, ah->ah_sh + reg);
+}
+
+static void ath_pci_cleanup(struct ath_softc *sc)
+{
+ ath_detach(sc);
+ if (sc->pdev->irq)
+ free_irq(sc->pdev->irq, sc);
+ pci_iounmap(sc->pdev, sc->mem);
+ pci_release_region(sc->pdev, 0);
+ pci_disable_device(sc->pdev);
+ ieee80211_free_hw(sc->hw);
+}
+
+static struct ath_bus_ops ath_pci_bus_ops = {
+ .dma_map_single_to_device = ath_pci_map_single_to_device,
+ .dma_unmap_single_to_device = ath_pci_unmap_single_to_device,
+ .dma_map_single_from_device = ath_pci_map_single_from_device,
+ .dma_unmap_single_from_device = ath_pci_unmap_single_from_device,
+ .dma_map_single_to_device = ath_pci_map_single_to_device,
+ .dma_mapping_error = ath_pci_dma_mapping_error,
+ .dma_sync_single_for_cpu = ath_pci_sync_single_for_cpu,
+ .dma_alloc = ath_pci_dma_alloc,
+ .dma_free = ath_pci_dma_free,
+
+ .reg_read = ath_pci_reg_read,
+ .reg_write = ath_pci_reg_write,
+
+ .read_cachesize = ath_pci_read_cachesize,
+
+ .cleanup = ath_pci_cleanup,
+};
+
+static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ void __iomem *mem;
+ struct ath_softc *sc;
+ struct ieee80211_hw *hw;
+ u8 csz;
+ u32 val;
+ int ret = 0;
+ struct ath_hal *ah;
+
+ if (pci_enable_device(pdev))
+ return -EIO;
+
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+
+ if (ret) {
+ printk(KERN_ERR "ath9k: 32-bit DMA not available\n");
+ goto bad;
+ }
+
+ ret = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+
+ if (ret) {
+ printk(KERN_ERR "ath9k: 32-bit DMA consistent "
+ "DMA enable failed\n");
+ goto bad;
+ }
+
+ /*
+ * Cache line size is used to size and align various
+ * structures used to communicate with the hardware.
+ */
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+ if (csz == 0) {
+ /*
+ * Linux 2.4.18 (at least) writes the cache line size
+ * register as a 16-bit wide register which is wrong.
+ * We must have this setup properly for rx buffer
+ * DMA to work so force a reasonable value here if it
+ * comes up zero.
+ */
+ csz = L1_CACHE_BYTES / sizeof(u32);
+ pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+ }
+ /*
+ * The default setting of latency timer yields poor results,
+ * set it to the value used by other systems. It may be worth
+ * tweaking this setting more.
+ */
+ pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+ pci_set_master(pdev);
+
+ /*
+ * Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state.
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ ret = pci_request_region(pdev, 0, "ath9k");
+ if (ret) {
+ dev_err(&pdev->dev, "PCI memory region reserve error\n");
+ ret = -ENODEV;
+ goto bad;
+ }
+
+ mem = pci_iomap(pdev, 0, 0);
+ if (!mem) {
+ printk(KERN_ERR "PCI memory map error\n") ;
+ ret = -EIO;
+ goto bad1;
+ }
+
+ hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
+ if (hw == NULL) {
+ printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
+ goto bad2;
+ }
+
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ pci_set_drvdata(pdev, hw);
+
+ sc = hw->priv;
+ sc->hw = hw;
+ sc->pdev = pdev;
+ sc->mem = mem;
+ sc->bus_ops = &ath_pci_bus_ops;
+
+ if (ath_attach(id->device, sc) != 0) {
+ ret = -ENODEV;
+ goto bad3;
+ }
+
+ /* setup interrupt service routine */
+
+ if (request_irq(pdev->irq, ath_isr, IRQF_SHARED, "ath", sc)) {
+ printk(KERN_ERR "%s: request_irq failed\n",
+ wiphy_name(hw->wiphy));
+ ret = -EIO;
+ goto bad4;
+ }
+
+ ah = sc->sc_ah;
+ printk(KERN_INFO
+ "%s: Atheros AR%s MAC/BB Rev:%x "
+ "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n",
+ wiphy_name(hw->wiphy),
+ ath_mac_bb_name(ah->ah_macVersion),
+ ah->ah_macRev,
+ ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+ ah->ah_phyRev,
+ (unsigned long)mem, pdev->irq);
+
+ return 0;
+bad4:
+ ath_detach(sc);
+bad3:
+ ieee80211_free_hw(hw);
+bad2:
+ pci_iounmap(pdev, mem);
+bad1:
+ pci_release_region(pdev, 0);
+bad:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void ath_pci_remove(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath_softc *sc = hw->priv;
+
+ ath_pci_cleanup(sc);
+}
+
+#ifdef CONFIG_PM
+
+static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath_softc *sc = hw->priv;
+
+ ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll);
+#endif
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, 3);
+
+ return 0;
+}
+
+static int ath_pci_resume(struct pci_dev *pdev)
+{
+ struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+ struct ath_softc *sc = hw->priv;
+ u32 val;
+ int err;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ return err;
+ pci_restore_state(pdev);
+ /*
+ * Suspend/Resume resets the PCI configuration space, so we have to
+ * re-disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state
+ */
+ pci_read_config_dword(pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(pdev, 0x40, val & 0xffff00ff);
+
+ /* Enable LED */
+ ath9k_hw_cfg_output(sc->sc_ah, ATH_LED_PIN,
+ AR_GPIO_OUTPUT_MUX_AS_OUTPUT);
+ ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
+
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+ /*
+ * check the h/w rfkill state on resume
+ * and start the rfkill poll timer
+ */
+ if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT)
+ queue_delayed_work(sc->hw->workqueue,
+ &sc->rf_kill.rfkill_poll, 0);
+#endif
+
+ return 0;
+}
+
+#endif /* CONFIG_PM */
+
+MODULE_DEVICE_TABLE(pci, ath_pci_id_table);
+
+static struct pci_driver ath_pci_driver = {
+ .name = "ath9k",
+ .id_table = ath_pci_id_table,
+ .probe = ath_pci_probe,
+ .remove = ath_pci_remove,
+#ifdef CONFIG_PM
+ .suspend = ath_pci_suspend,
+ .resume = ath_pci_resume,
+#endif /* CONFIG_PM */
+};
+
+int __init ath_pci_init(void)
+{
+ return pci_register_driver(&ath_pci_driver);
+}
+
+void ath_pci_exit(void)
+{
+ pci_unregister_driver(&ath_pci_driver);
+}
--
1.5.3.2


2009-01-04 07:27:09

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC 02/12] ath9k: introduce bus specific register access routines

On Sat, Jan 03, 2009 at 02:44:12PM +0100, Gabor Juhos wrote:
> The AHB bus will require different code for register access, so we make
> them replaceable as well.

What kind of different code? ioread*/iowrite* are supposed to be bus-agnostic.


2009-01-04 11:17:40

by Gabor Juhos

[permalink] [raw]
Subject: Re: [RFC 02/12] ath9k: introduce bus specific register access routines

Christoph Hellwig =EDrta:
> On Sat, Jan 03, 2009 at 02:44:12PM +0100, Gabor Juhos wrote:
>> The AHB bus will require different code for register access, so we m=
ake
>> them replaceable as well.
>=20
> What kind of different code? ioread*/iowrite* are supposed to be bus=
-agnostic.
>=20
>=20

I have used __raw_{read,write}*. You are right, I have tried it right n=
ow and it
works with io{read,write}* as well. I will remove them.

2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 12/12] ath9k: fix null pointer dereference in ani monitor code

In 'ath9k_ani_reset' the 'ahp->ah_curani' will be initialized only
if 'DO_ANI(ah)' true. In 'ath9k_hw_ani_monitor' we are using 'ahp->ah_curani'
unconditionally, and it will cause a NULL pointer dereference on AR9100.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/ani.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c
index 251e2d9..ffa6a93 100644
--- a/drivers/net/wireless/ath9k/ani.c
+++ b/drivers/net/wireless/ath9k/ani.c
@@ -555,6 +555,9 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah,
struct ar5416AniState *aniState;
int32_t listenTime;

+ if (!DO_ANI(ah))
+ return;
+
aniState = ahp->ah_curani;
ahp->ah_stats.ast_nodestats = *stats;

@@ -614,9 +617,6 @@ void ath9k_hw_ani_monitor(struct ath_hal *ah,
aniState->cckPhyErrCount = cckPhyErrCnt;
}

- if (!DO_ANI(ah))
- return;
-
if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
aniState->ofdmTrigLow / 1000 &&
--
1.5.3.2


2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 02/12] ath9k: introduce bus specific register access routines

The AHB bus will require different code for register access, so we make
them replaceable as well.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/ath9k.h | 4 ++--
drivers/net/wireless/ath9k/core.h | 17 +++++++++++++++++
drivers/net/wireless/ath9k/main.c | 13 +++++++++++++
3 files changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h
index d278135..dc9b260 100644
--- a/drivers/net/wireless/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath9k/ath9k.h
@@ -587,8 +587,8 @@ struct ath9k_country_entry {
u8 iso[3];
};

-#define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sh + _reg)
-#define REG_READ(_ah, _reg) ioread32(_ah->ah_sh + _reg)
+#define REG_WRITE(_ah, _reg, _val) ath_reg_write(_ah, _reg, _val)
+#define REG_READ(_ah, _reg) ath_reg_read(_ah, _reg)

#define SM(_v, _f) (((_v) << _f##_S) & _f)
#define MS(_v, _f) (((_v) & _f) >> _f##_S)
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index de50e47..db7ae4e 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -718,6 +718,9 @@ struct ath_bus_ops {
size_t size,
void *p,
dma_addr_t da);
+
+ u32 (*reg_read)(struct ath_hal *ah, unsigned reg);
+ void (*reg_write)(struct ath_hal *ah, unsigned reg, u32 val);
};

struct ath_softc {
@@ -826,4 +829,18 @@ static inline void ath_dma_free(struct ath_softc *sc, size_t size,
sc->bus_ops->dma_free(sc, size, p, da);
}

+static inline u32 ath_reg_read(struct ath_hal *ah, unsigned reg)
+{
+ struct ath_softc *sc = ah->ah_sc;
+
+ return sc->bus_ops->reg_read(ah, reg);
+}
+
+static inline void ath_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
+{
+ struct ath_softc *sc = ah->ah_sc;
+
+ sc->bus_ops->reg_write(ah, reg, val);
+}
+
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 62a0a5b..9ce89b4 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -2595,6 +2595,16 @@ static void ath_pci_dma_free(struct ath_softc *sc, size_t size,
pci_free_consistent(sc->pdev, size, p, da);
}

+static u32 ath_pci_reg_read(struct ath_hal *ah, unsigned reg)
+{
+ return ioread32(ah->ah_sh + reg);
+}
+
+static void ath_pci_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
+{
+ iowrite32(val, ah->ah_sh + reg);
+}
+
static struct ath_bus_ops ath_pci_bus_ops = {
.dma_map_single_to_device = ath_pci_map_single_to_device,
.dma_unmap_single_to_device = ath_pci_unmap_single_to_device,
@@ -2605,6 +2615,9 @@ static struct ath_bus_ops ath_pci_bus_ops = {
.dma_sync_single_for_cpu = ath_pci_sync_single_for_cpu,
.dma_alloc = ath_pci_dma_alloc,
.dma_free = ath_pci_dma_free,
+
+ .reg_read = ath_pci_reg_read,
+ .reg_write = ath_pci_reg_write,
};

static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
--
1.5.3.2


2009-01-05 10:32:52

by Sujith

[permalink] [raw]
Subject: [RFC 08/12] ath9k: get EEPROM contents from platform data on AHB bus

Gabor Juhos wrote:
> +#ifndef _LINUX_ATH9K_PLATFORM_H
> +#define _LINUX_ATH9L_PLATFORM_H

Typo ?

Also, after addressing Christopher's comments, I don't think too many
bus specific routines would remain. In that case would it be reasonable
to just have a single file (bus.c, with appropriate ifdefs), instead
of pci.c and ahb.c ?

Sujith

2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 06/12] ath9k: convert to struct device

Now that we have converted all bus specific routines to replaceable, we
can move the PCI specific codes into a separate file.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/core.h | 5 +++--
drivers/net/wireless/ath9k/pci.c | 35 ++++++++++++++++++++---------------
2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 73a409b..6889df7 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -18,7 +18,8 @@
#define CORE_H

#include <linux/etherdevice.h>
-#include <linux/pci.h>
+#include <linux/device.h>
+#include <linux/types.h>
#include <net/mac80211.h>
#include <linux/leds.h>
#include <linux/rfkill.h>
@@ -729,7 +730,7 @@ struct ath_bus_ops {

struct ath_softc {
struct ieee80211_hw *hw;
- struct pci_dev *pdev;
+ struct device *dev;
struct tasklet_struct intr_tq;
struct tasklet_struct bcon_tasklet;
struct ath_hal *sc_ah;
diff --git a/drivers/net/wireless/ath9k/pci.c b/drivers/net/wireless/ath9k/pci.c
index 1bb4787..314bf9d 100644
--- a/drivers/net/wireless/ath9k/pci.c
+++ b/drivers/net/wireless/ath9k/pci.c
@@ -15,6 +15,8 @@
*/

#include <linux/nl80211.h>
+#include <linux/pci.h>
+
#include "core.h"
#include "reg.h"
#include "hw.h"
@@ -34,7 +36,8 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
{
u8 u8tmp;

- pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp);
+ pci_read_config_byte(to_pci_dev(sc->dev), PCI_CACHE_LINE_SIZE,
+ (u8 *)&u8tmp);
*csz = (int)u8tmp;

/*
@@ -50,49 +53,49 @@ static void ath_pci_read_cachesize(struct ath_softc *sc, int *csz)
static dma_addr_t ath_pci_map_single_to_device(struct ath_softc *sc,
void *p, size_t size)
{
- return pci_map_single(sc->pdev, p, size, PCI_DMA_TODEVICE);
+ return pci_map_single(to_pci_dev(sc->dev), p, size, PCI_DMA_TODEVICE);
}

static void ath_pci_unmap_single_to_device(struct ath_softc *sc,
dma_addr_t da, size_t size)
{
- pci_unmap_single(sc->pdev, da, size, PCI_DMA_TODEVICE);
+ pci_unmap_single(to_pci_dev(sc->dev), da, size, PCI_DMA_TODEVICE);
}

static dma_addr_t ath_pci_map_single_from_device(struct ath_softc *sc,
void *p, size_t size)
{
- return pci_map_single(sc->pdev, p, size, PCI_DMA_FROMDEVICE);
+ return pci_map_single(to_pci_dev(sc->dev), p, size, PCI_DMA_FROMDEVICE);
}

static void ath_pci_unmap_single_from_device(struct ath_softc *sc,
dma_addr_t da, size_t size)
{
- pci_unmap_single(sc->pdev, da, size, PCI_DMA_FROMDEVICE);
+ pci_unmap_single(to_pci_dev(sc->dev), da, size, PCI_DMA_FROMDEVICE);
}

static int ath_pci_dma_mapping_error(struct ath_softc *sc, dma_addr_t da)
{
- return pci_dma_mapping_error(sc->pdev, da);
+ return pci_dma_mapping_error(to_pci_dev(sc->dev), da);
}

static void ath_pci_sync_single_for_cpu(struct ath_softc *sc, dma_addr_t da,
size_t size)
{
- pci_dma_sync_single_for_cpu(sc->pdev, da, size,
+ pci_dma_sync_single_for_cpu(to_pci_dev(sc->dev), da, size,
PCI_DMA_FROMDEVICE);
}

static void *ath_pci_dma_alloc(struct ath_softc *sc, size_t size,
dma_addr_t *pda)
{
- return pci_alloc_consistent(sc->pdev, size, pda);
+ return pci_alloc_consistent(to_pci_dev(sc->dev), size, pda);
}

static void ath_pci_dma_free(struct ath_softc *sc, size_t size,
void *p, dma_addr_t da)
{
- pci_free_consistent(sc->pdev, size, p, da);
+ pci_free_consistent(to_pci_dev(sc->dev), size, p, da);
}

static u32 ath_pci_reg_read(struct ath_hal *ah, unsigned reg)
@@ -107,12 +110,14 @@ static void ath_pci_reg_write(struct ath_hal *ah, unsigned reg, u32 val)

static void ath_pci_cleanup(struct ath_softc *sc)
{
+ struct pci_dev *pdev = to_pci_dev(sc->dev);
+
ath_detach(sc);
- if (sc->pdev->irq)
- free_irq(sc->pdev->irq, sc);
- pci_iounmap(sc->pdev, sc->mem);
- pci_release_region(sc->pdev, 0);
- pci_disable_device(sc->pdev);
+ if (pdev->irq)
+ free_irq(pdev->irq, sc);
+ pci_iounmap(pdev, sc->mem);
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
ieee80211_free_hw(sc->hw);
}

@@ -221,7 +226,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)

sc = hw->priv;
sc->hw = hw;
- sc->pdev = pdev;
+ sc->dev = &pdev->dev;
sc->mem = mem;
sc->bus_ops = &ath_pci_bus_ops;

--
1.5.3.2


2009-01-04 11:18:59

by Gabor Juhos

[permalink] [raw]
Subject: Re: [RFC 07/12] ath9k: introduce platform driver for AHB bus support

Christoph Hellwig =EDrta:
> On Sat, Jan 03, 2009 at 02:44:17PM +0100, Gabor Juhos wrote:
>> +static dma_addr_t ath_ahb_map_single_to_device(struct ath_softc *sc=
,
>> + void *p, size_t size)
>> +{
>> + return dma_map_single(NULL, p, size, DMA_TO_DEVICE);
>> +}
>=20
> As said before you should just use dma_* directly. And please make s=
ure
> to always pass a struct device to the dma_* routines, even if your
> platform might currently not required it the API does.
>=20
>> +static void ath_ahb_cleanup(struct ath_softc *sc)
>> +{
>> + struct platform_device *pdev =3D to_platform_device(sc->dev);
>> + struct ieee80211_hw *hw =3D sc->hw;
>> + struct resource *res;
>> +
>> + res =3D platform_get_resource(pdev, IORESOURCE_IRQ, 0);
>> + if (res)
>> + free_irq(res->start, sc);
>=20
> If you stored the irq value directly in the softc this whole thing mi=
ght
> be able to be done in a generic way..
>=20
>=20

I did not want to store it in the softc, because 'struct pci_dev' has i=
t already
and we will duplicate it. However the code will be simpler, so i can ad=
d it of
course.

2009-01-04 11:17:06

by Gabor Juhos

[permalink] [raw]
Subject: Re: [RFC 01/12] ath9k: introduce bus specific DMA routines

Christoph Hellwig =EDrta:
> On Sat, Jan 03, 2009 at 02:44:11PM +0100, Gabor Juhos wrote:
>> In the AR913x SoCs, the WMAC devices are connected to the CPU throug=
h
>> the internal AHB bus instead of PCI. We first patch ath9k driver to =
use
>> replaceable DMA routines, so we can use different code for the AHB b=
us.
>=20
>> - pci_unmap_single(sc->pdev, bf->bf_dmacontext,
>> - skb->len,
>> - PCI_DMA_TODEVICE);
>> + ath_unmap_single_to_device(sc, bf->bf_dmacontext, skb->len);
>=20
> Just use the dma_* routines, as they are bus-agnostic and make sure t=
he
> implementation on your mips SOC works for the ahb bus.
>=20
>=20

Ok, i will try it.

2009-01-06 09:41:43

by Sujith

[permalink] [raw]
Subject: Re: [RFC 08/12] ath9k: get EEPROM contents from platform data on AHB bus

Gabor Juhos wrote:
> > Also, after addressing Christopher's comments, I don't think too many
> > bus specific routines would remain. In that case would it be reasonable
> > to just have a single file (bus.c, with appropriate ifdefs), instead
> > of pci.c and ahb.c ?
>
> We will have 3 of them actually (read_cachesize, read_eeprom, cleanup), but here
> is the whole {pci,platform}_driver specific stuff. Of course we can move all of
> this into one file, but i would like to avoid the unnecessary ifdefs where it is
> possible. Apart from this, if we will put the PCI and AHB stuff into one file,
> we could put it into main.c simply.

Your choice really, it doesn't matter much anyway. :)

Sujith

2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 11/12] ath9k: fix ar5416Addac_9100 values

Writing the register at offset 0x98c4 causes a deadlock on the AR913x
SoCs. Although i don't have detailed knowledge about these registers, but if i
change the register offset according to the 'ar5416Addac' table, it
works. Additionally there is no reference to the 0x98c4 elsewhere.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/initvals.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h
index f3cfa16..80a5d85 100644
--- a/drivers/net/wireless/ath9k/initvals.h
+++ b/drivers/net/wireless/ath9k/initvals.h
@@ -659,7 +659,7 @@ static const u32 ar5416Addac_9100[][2] = {
{0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 },
{0x0000989c, 0x00000000 },
- {0x000098c4, 0x00000000 },
+ {0x000098cc, 0x00000000 },
};

/* ar5416 - howl ar5416_howl.ini */
--
1.5.3.2


2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 10/12] ath9k: remove (u16) casts from rtc register access

The RTC register offsets don't fit into 'u16' on the AR913x, so we have
to remove the existing casts.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/hw.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c
index ca0fc53..68f97ca 100644
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -1026,7 +1026,7 @@ static void ath9k_hw_init_pll(struct ath_hal *ah,
pll |= SM(0xb, AR_RTC_PLL_DIV);
}
}
- REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll);
+ REG_WRITE(ah, (AR_RTC_PLL_CONTROL), pll);

udelay(RTC_PLL_SETTLE_DELAY);

@@ -1566,11 +1566,11 @@ static bool ath9k_hw_set_reset(struct ath_hal *ah, int type)
rst_flags |= AR_RTC_RC_MAC_COLD;
}

- REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags);
+ REG_WRITE(ah, (AR_RTC_RC), rst_flags);
udelay(50);

- REG_WRITE(ah, (u16) (AR_RTC_RC), 0);
- if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) {
+ REG_WRITE(ah, (AR_RTC_RC), 0);
+ if (!ath9k_hw_wait(ah, (AR_RTC_RC), AR_RTC_RC_M, 0)) {
DPRINTF(ah->ah_sc, ATH_DBG_RESET,
"RTC stuck in MAC reset\n");
return false;
@@ -1592,8 +1592,8 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah)
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
AR_RTC_FORCE_WAKE_ON_INT);

- REG_WRITE(ah, (u16) (AR_RTC_RESET), 0);
- REG_WRITE(ah, (u16) (AR_RTC_RESET), 1);
+ REG_WRITE(ah, (AR_RTC_RESET), 0);
+ REG_WRITE(ah, (AR_RTC_RESET), 1);

if (!ath9k_hw_wait(ah,
AR_RTC_STATUS,
@@ -2662,7 +2662,7 @@ static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip)
if (!AR_SREV_9100(ah))
REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF);

- REG_CLR_BIT(ah, (u16) (AR_RTC_RESET),
+ REG_CLR_BIT(ah, (AR_RTC_RESET),
AR_RTC_RESET_EN);
}
}
--
1.5.3.2


2009-01-04 07:26:36

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [RFC 01/12] ath9k: introduce bus specific DMA routines

On Sat, Jan 03, 2009 at 02:44:11PM +0100, Gabor Juhos wrote:
> In the AR913x SoCs, the WMAC devices are connected to the CPU through
> the internal AHB bus instead of PCI. We first patch ath9k driver to use
> replaceable DMA routines, so we can use different code for the AHB bus.

> - pci_unmap_single(sc->pdev, bf->bf_dmacontext,
> - skb->len,
> - PCI_DMA_TODEVICE);
> + ath_unmap_single_to_device(sc, bf->bf_dmacontext, skb->len);

Just use the dma_* routines, as they are bus-agnostic and make sure the
implementation on your mips SOC works for the ahb bus.


2009-01-05 12:24:16

by Gabor Juhos

[permalink] [raw]
Subject: Re: [RFC 08/12] ath9k: get EEPROM contents from platform data on AHB bus

Sujith =EDrta:
> Gabor Juhos wrote:
>> +#ifndef _LINUX_ATH9K_PLATFORM_H
>> +#define _LINUX_ATH9L_PLATFORM_H
>=20
> Typo ?

Oops, yes.

> Also, after addressing Christopher's comments, I don't think too many
> bus specific routines would remain. In that case would it be reasonab=
le
> to just have a single file (bus.c, with appropriate ifdefs), instead
> of pci.c and ahb.c ?

We will have 3 of them actually (read_cachesize, read_eeprom, cleanup),=
but here
is the whole {pci,platform}_driver specific stuff. Of course we can mov=
e all of
this into one file, but i would like to avoid the unnecessary ifdefs wh=
ere it is
possible. Apart from this, if we will put the PCI and AHB stuff into on=
e file,
we could put it into main.c simply.

-Gabor

2009-01-03 13:44:56

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 04/12] ath9k: introduce bus specific cleanup routine

We have left only some PCI specific cleanup code. We have to convert
them as well.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/core.h | 7 +++++++
drivers/net/wireless/ath9k/main.c | 29 +++++++++++++++--------------
2 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 0c8064e..4833598 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -723,6 +723,8 @@ struct ath_bus_ops {
void (*reg_write)(struct ath_hal *ah, unsigned reg, u32 val);

void (*read_cachesize)(struct ath_softc *sc, int *csz);
+
+ void (*cleanup)(struct ath_softc *sc);
};

struct ath_softc {
@@ -850,4 +852,9 @@ static inline void ath_read_cachesize(struct ath_softc *sc, int *csz)
sc->bus_ops->read_cachesize(sc, csz);
}

+static inline void ath_bus_cleanup(struct ath_softc *sc)
+{
+ sc->bus_ops->cleanup(sc);
+}
+
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index f1da1ac..e126b65 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -1276,13 +1276,7 @@ static int ath_start_rfkill_poll(struct ath_softc *sc)
rfkill_free(sc->rf_kill.rfkill);

/* Deinitialize the device */
- ath_detach(sc);
- if (sc->pdev->irq)
- free_irq(sc->pdev->irq, sc);
- pci_iounmap(sc->pdev, sc->mem);
- pci_release_region(sc->pdev, 0);
- pci_disable_device(sc->pdev);
- ieee80211_free_hw(sc->hw);
+ ath_bus_cleanup(sc);
return -EIO;
} else {
sc->sc_flags |= SC_OP_RFKILL_REGISTERED;
@@ -2605,6 +2599,17 @@ static void ath_pci_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
iowrite32(val, ah->ah_sh + reg);
}

+static void ath_pci_cleanup(struct ath_softc *sc)
+{
+ ath_detach(sc);
+ if (sc->pdev->irq)
+ free_irq(sc->pdev->irq, sc);
+ pci_iounmap(sc->pdev, sc->mem);
+ pci_release_region(sc->pdev, 0);
+ pci_disable_device(sc->pdev);
+ ieee80211_free_hw(sc->hw);
+}
+
static struct ath_bus_ops ath_pci_bus_ops = {
.dma_map_single_to_device = ath_pci_map_single_to_device,
.dma_unmap_single_to_device = ath_pci_unmap_single_to_device,
@@ -2620,6 +2625,8 @@ static struct ath_bus_ops ath_pci_bus_ops = {
.reg_write = ath_pci_reg_write,

.read_cachesize = ath_pci_read_cachesize,
+
+ .cleanup = ath_pci_cleanup,
};

static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
@@ -2756,13 +2763,7 @@ static void ath_pci_remove(struct pci_dev *pdev)
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;

- ath_detach(sc);
- if (pdev->irq)
- free_irq(pdev->irq, sc);
- pci_iounmap(pdev, sc->mem);
- pci_release_region(pdev, 0);
- pci_disable_device(pdev);
- ieee80211_free_hw(hw);
+ ath_pci_cleanup(sc);
}

#ifdef CONFIG_PM
--
1.5.3.2


2009-01-03 13:44:55

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 01/12] ath9k: introduce bus specific DMA routines

In the AR913x SoCs, the WMAC devices are connected to the CPU through
the internal AHB bus instead of PCI. We first patch ath9k driver to use
replaceable DMA routines, so we can use different code for the AHB bus.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/beacon.c | 29 +++++---------
drivers/net/wireless/ath9k/core.h | 75 +++++++++++++++++++++++++++++++++++
drivers/net/wireless/ath9k/main.c | 71 +++++++++++++++++++++++++++++---
drivers/net/wireless/ath9k/recv.c | 30 ++++++--------
drivers/net/wireless/ath9k/xmit.c | 12 ++----
5 files changed, 166 insertions(+), 51 deletions(-)

diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c
index 3ab0b43..05cdbc8 100644
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -164,9 +164,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
bf = avp->av_bcbuf;
skb = (struct sk_buff *)bf->bf_mpdu;
if (skb) {
- pci_unmap_single(sc->pdev, bf->bf_dmacontext,
- skb->len,
- PCI_DMA_TODEVICE);
+ ath_unmap_single_to_device(sc, bf->bf_dmacontext, skb->len);
dev_kfree_skb_any(skb);
}

@@ -188,14 +186,12 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
}

bf->bf_buf_addr = bf->bf_dmacontext =
- pci_map_single(sc->pdev, skb->data,
- skb->len,
- PCI_DMA_TODEVICE);
- if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+ ath_map_single_to_device(sc, skb->data, skb->len);
+ if (unlikely(ath_dma_mapping_error(sc, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
DPRINTF(sc, ATH_DBG_CONFIG,
- "pci_dma_mapping_error() on beaconing\n");
+ "dma_mapping_error() on beaconing\n");
return NULL;
}

@@ -343,9 +339,7 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
skb = (struct sk_buff *)bf->bf_mpdu;
- pci_unmap_single(sc->pdev, bf->bf_dmacontext,
- skb->len,
- PCI_DMA_TODEVICE);
+ ath_unmap_single_to_device(sc, bf->bf_dmacontext, skb->len);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
}
@@ -402,14 +396,12 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)

bf->bf_mpdu = skb;
bf->bf_buf_addr = bf->bf_dmacontext =
- pci_map_single(sc->pdev, skb->data,
- skb->len,
- PCI_DMA_TODEVICE);
- if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) {
+ ath_map_single_to_device(sc, skb->data, skb->len);
+ if (unlikely(ath_dma_mapping_error(sc, bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
DPRINTF(sc, ATH_DBG_CONFIG,
- "pci_dma_mapping_error() on beacon alloc\n");
+ "dma_mapping_error() on beacon alloc\n");
return -ENOMEM;
}

@@ -429,9 +421,8 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp)
bf = avp->av_bcbuf;
if (bf->bf_mpdu != NULL) {
struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
- pci_unmap_single(sc->pdev, bf->bf_dmacontext,
- skb->len,
- PCI_DMA_TODEVICE);
+ ath_unmap_single_to_device(sc, bf->bf_dmacontext,
+ skb->len);
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
}
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 4ca2aed..de50e47 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -693,6 +693,33 @@ enum PROT_MODE {
#define SC_OP_RFKILL_SW_BLOCKED BIT(12)
#define SC_OP_RFKILL_HW_BLOCKED BIT(13)

+struct ath_bus_ops {
+ dma_addr_t (*dma_map_single_to_device)(struct ath_softc *sc,
+ void *p,
+ size_t size);
+ void (*dma_unmap_single_to_device)(struct ath_softc *sc,
+ dma_addr_t da,
+ size_t size);
+ dma_addr_t (*dma_map_single_from_device)(struct ath_softc *sc,
+ void *p,
+ size_t size);
+ void (*dma_unmap_single_from_device)(struct ath_softc *sc,
+ dma_addr_t da,
+ size_t size);
+ int (*dma_mapping_error)(struct ath_softc *sc,
+ dma_addr_t da);
+ void (*dma_sync_single_for_cpu)(struct ath_softc *sc,
+ dma_addr_t da,
+ size_t size);
+ void *(*dma_alloc)(struct ath_softc *sc,
+ size_t size,
+ dma_addr_t *pda);
+ void (*dma_free)(struct ath_softc *sc,
+ size_t size,
+ void *p,
+ dma_addr_t da);
+};
+
struct ath_softc {
struct ieee80211_hw *hw;
struct pci_dev *pdev;
@@ -744,6 +771,7 @@ struct ath_softc {
#ifdef CONFIG_ATH9K_DEBUG
struct ath9k_debug sc_debug;
#endif
+ struct ath_bus_ops *bus_ops;
};

int ath_reset(struct ath_softc *sc, bool retry_tx);
@@ -751,4 +779,51 @@ int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
int ath_cabq_update(struct ath_softc *);

+static inline dma_addr_t ath_map_single_to_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return sc->bus_ops->dma_map_single_to_device(sc, p, size);
+}
+
+static inline void ath_unmap_single_to_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ sc->bus_ops->dma_unmap_single_to_device(sc, da, size);
+}
+
+static inline dma_addr_t ath_map_single_from_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return sc->bus_ops->dma_map_single_from_device(sc, p, size);
+}
+
+static inline void ath_unmap_single_from_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ sc->bus_ops->dma_unmap_single_from_device(sc, da, size);
+}
+
+static inline int ath_dma_mapping_error(struct ath_softc *sc, dma_addr_t da)
+{
+ return sc->bus_ops->dma_mapping_error(sc, da);
+}
+
+static inline void ath_sync_single_for_cpu(struct ath_softc *sc, dma_addr_t da,
+ size_t size)
+{
+ sc->bus_ops->dma_sync_single_for_cpu(sc, da, size);
+}
+
+static inline void *ath_dma_alloc(struct ath_softc *sc, size_t size,
+ dma_addr_t *pda)
+{
+ return sc->bus_ops->dma_alloc(sc, size, pda);
+}
+
+static inline void ath_dma_free(struct ath_softc *sc, size_t size,
+ void *p, dma_addr_t da)
+{
+ sc->bus_ops->dma_free(sc, size, p, da);
+}
+
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 70affb7..62a0a5b 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -1722,9 +1722,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
}

/* allocate descriptors */
- dd->dd_desc = pci_alloc_consistent(sc->pdev,
- dd->dd_desc_len,
- &dd->dd_desc_paddr);
+ dd->dd_desc = ath_dma_alloc(sc, dd->dd_desc_len, &dd->dd_desc_paddr);
if (dd->dd_desc == NULL) {
error = -ENOMEM;
goto fail;
@@ -1770,8 +1768,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
}
return 0;
fail2:
- pci_free_consistent(sc->pdev,
- dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+ ath_dma_free(sc, dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
fail:
memset(dd, 0, sizeof(*dd));
return error;
@@ -1784,8 +1781,7 @@ void ath_descdma_cleanup(struct ath_softc *sc,
struct ath_descdma *dd,
struct list_head *head)
{
- pci_free_consistent(sc->pdev,
- dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);
+ ath_dma_free(sc, dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr);

INIT_LIST_HEAD(head);
kfree(dd->dd_bufptr);
@@ -2551,6 +2547,66 @@ ath_rf_name(u16 rf_version)
return "????";
}

+static dma_addr_t ath_pci_map_single_to_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return pci_map_single(sc->pdev, p, size, PCI_DMA_TODEVICE);
+}
+
+static void ath_pci_unmap_single_to_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ pci_unmap_single(sc->pdev, da, size, PCI_DMA_TODEVICE);
+}
+
+static dma_addr_t ath_pci_map_single_from_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return pci_map_single(sc->pdev, p, size, PCI_DMA_FROMDEVICE);
+}
+
+static void ath_pci_unmap_single_from_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ pci_unmap_single(sc->pdev, da, size, PCI_DMA_FROMDEVICE);
+}
+
+static int ath_pci_dma_mapping_error(struct ath_softc *sc, dma_addr_t da)
+{
+ return pci_dma_mapping_error(sc->pdev, da);
+}
+
+static void ath_pci_sync_single_for_cpu(struct ath_softc *sc, dma_addr_t da,
+ size_t size)
+{
+ pci_dma_sync_single_for_cpu(sc->pdev, da, size,
+ PCI_DMA_FROMDEVICE);
+}
+
+static void *ath_pci_dma_alloc(struct ath_softc *sc, size_t size,
+ dma_addr_t *pda)
+{
+ return pci_alloc_consistent(sc->pdev, size, pda);
+}
+
+static void ath_pci_dma_free(struct ath_softc *sc, size_t size,
+ void *p, dma_addr_t da)
+{
+ pci_free_consistent(sc->pdev, size, p, da);
+}
+
+static struct ath_bus_ops ath_pci_bus_ops = {
+ .dma_map_single_to_device = ath_pci_map_single_to_device,
+ .dma_unmap_single_to_device = ath_pci_unmap_single_to_device,
+ .dma_map_single_from_device = ath_pci_map_single_from_device,
+ .dma_unmap_single_from_device = ath_pci_unmap_single_from_device,
+ .dma_map_single_to_device = ath_pci_map_single_to_device,
+ .dma_mapping_error = ath_pci_dma_mapping_error,
+ .dma_sync_single_for_cpu = ath_pci_sync_single_for_cpu,
+ .dma_alloc = ath_pci_dma_alloc,
+ .dma_free = ath_pci_dma_free,
+};
+
static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
void __iomem *mem;
@@ -2639,6 +2695,7 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
sc->hw = hw;
sc->pdev = pdev;
sc->mem = mem;
+ sc->bus_ops = &ath_pci_bus_ops;

if (ath_attach(id->device, sc) != 0) {
ret = -ENODEV;
diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c
index 462e08c..e135038 100644
--- a/drivers/net/wireless/ath9k/recv.c
+++ b/drivers/net/wireless/ath9k/recv.c
@@ -291,15 +291,14 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
}

bf->bf_mpdu = skb;
- bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data,
- sc->rx.bufsize,
- PCI_DMA_FROMDEVICE);
- if (unlikely(pci_dma_mapping_error(sc->pdev,
- bf->bf_buf_addr))) {
+ bf->bf_buf_addr = ath_map_single_from_device(sc,
+ skb->data, sc->rx.bufsize);
+ if (unlikely(ath_dma_mapping_error(sc,
+ bf->bf_buf_addr))) {
dev_kfree_skb_any(skb);
bf->bf_mpdu = NULL;
DPRINTF(sc, ATH_DBG_CONFIG,
- "pci_dma_mapping_error() on RX init\n");
+ "dma_mapping_error() on RX init\n");
error = -ENOMEM;
break;
}
@@ -524,9 +523,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
* 1. accessing the frame
* 2. requeueing the same buffer to h/w
*/
- pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr,
- sc->rx.bufsize,
- PCI_DMA_FROMDEVICE);
+ ath_sync_single_for_cpu(sc, bf->bf_buf_addr, sc->rx.bufsize);

/*
* If we're asked to flush receive queue, directly
@@ -557,9 +554,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
goto requeue;

/* Unmap the frame */
- pci_unmap_single(sc->pdev, bf->bf_buf_addr,
- sc->rx.bufsize,
- PCI_DMA_FROMDEVICE);
+ ath_unmap_single_from_device(sc, bf->bf_buf_addr,
+ sc->rx.bufsize);

skb_put(skb, ds->ds_rxstat.rs_datalen);
skb->protocol = cpu_to_be16(ETH_P_CONTROL);
@@ -599,15 +595,15 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)

/* We will now give hardware our shiny new allocated skb */
bf->bf_mpdu = requeue_skb;
- bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data,
- sc->rx.bufsize,
- PCI_DMA_FROMDEVICE);
- if (unlikely(pci_dma_mapping_error(sc->pdev,
+ bf->bf_buf_addr = ath_map_single_from_device(sc,
+ requeue_skb->data,
+ sc->rx.bufsize);
+ if (unlikely(ath_dma_mapping_error(sc,
bf->bf_buf_addr))) {
dev_kfree_skb_any(requeue_skb);
bf->bf_mpdu = NULL;
DPRINTF(sc, ATH_DBG_CONFIG,
- "pci_dma_mapping_error() on RX\n");
+ "dma_mapping_error() on RX\n");
break;
}
bf->bf_dmacontext = bf->bf_buf_addr;
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c
index c92f0c6..d238b02 100644
--- a/drivers/net/wireless/ath9k/xmit.c
+++ b/drivers/net/wireless/ath9k/xmit.c
@@ -340,10 +340,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc,
}

/* Unmap this frame */
- pci_unmap_single(sc->pdev,
- bf->bf_dmacontext,
- skb->len,
- PCI_DMA_TODEVICE);
+ ath_unmap_single_to_device(sc, bf->bf_dmacontext, skb->len);
/* complete this frame */
ath_tx_complete(sc, skb, &tx_status);

@@ -1713,12 +1710,11 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
/* DMA setup */
bf->bf_mpdu = skb;

- bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
- if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) {
+ bf->bf_dmacontext = ath_map_single_to_device(sc, skb->data, skb->len);
+ if (unlikely(ath_dma_mapping_error(sc, bf->bf_dmacontext))) {
bf->bf_mpdu = NULL;
DPRINTF(sc, ATH_DBG_CONFIG,
- "pci_dma_mapping_error() on TX\n");
+ "dma_mapping_error() on TX\n");
return -ENOMEM;
}

--
1.5.3.2


2009-01-03 13:44:54

by Gabor Juhos

[permalink] [raw]
Subject: [RFC 07/12] ath9k: introduce platform driver for AHB bus support

This patch adds the platform_driver itself, and modifies the main driver
to register it.

Signed-off-by: Gabor Juhos <[email protected]>
Signed-off-by: Imre Kaloz <[email protected]>
---
drivers/net/wireless/ath9k/Makefile | 1 +
drivers/net/wireless/ath9k/ahb.c | 258 +++++++++++++++++++++++++++++++++++
drivers/net/wireless/ath9k/core.h | 8 +
drivers/net/wireless/ath9k/main.c | 10 ++
4 files changed, 277 insertions(+), 0 deletions(-)

diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile
index af3f39b..0062958 100644
--- a/drivers/net/wireless/ath9k/Makefile
+++ b/drivers/net/wireless/ath9k/Makefile
@@ -12,6 +12,7 @@ ath9k-y += hw.o \
rc.o

ath9k-$(CONFIG_PCI) += pci.o
+ath9k-$(CONFIG_ATHEROS_AR71XX) += ahb.o
ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o

obj-$(CONFIG_ATH9K) += ath9k.o
diff --git a/drivers/net/wireless/ath9k/ahb.c b/drivers/net/wireless/ath9k/ahb.c
new file mode 100644
index 0000000..bf37a9e
--- /dev/null
+++ b/drivers/net/wireless/ath9k/ahb.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <[email protected]>
+ * Copyright (c) 2009 Imre Kaloz <[email protected]>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/nl80211.h>
+#include <linux/platform_device.h>
+#include "core.h"
+#include "reg.h"
+#include "hw.h"
+
+static dma_addr_t ath_ahb_map_single_to_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return dma_map_single(NULL, p, size, DMA_TO_DEVICE);
+}
+
+static void ath_ahb_unmap_single_to_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ dma_unmap_single(NULL, da, size, DMA_TO_DEVICE);
+}
+
+static dma_addr_t ath_ahb_map_single_from_device(struct ath_softc *sc,
+ void *p, size_t size)
+{
+ return dma_map_single(NULL, p, size, DMA_FROM_DEVICE);
+}
+
+static void ath_ahb_unmap_single_from_device(struct ath_softc *sc,
+ dma_addr_t da, size_t size)
+{
+ dma_unmap_single(NULL, da, size, DMA_FROM_DEVICE);
+}
+
+static int ath_ahb_dma_mapping_error(struct ath_softc *sc, dma_addr_t da)
+{
+ return dma_mapping_error(NULL, da);
+}
+
+static void ath_ahb_sync_single_for_cpu(struct ath_softc *sc, dma_addr_t da,
+ size_t size)
+{
+ dma_sync_single_for_cpu(NULL, da, size, DMA_FROM_DEVICE);
+}
+
+static void *ath_ahb_dma_alloc(struct ath_softc *sc, size_t size,
+ dma_addr_t *pda)
+{
+ return dma_alloc_coherent(NULL, size, pda, GFP_KERNEL);
+}
+
+static void ath_ahb_dma_free(struct ath_softc *sc, size_t size, void *p,
+ dma_addr_t da)
+{
+ dma_free_coherent(NULL, size, p, da);
+}
+
+static void ath_ahb_reg_write(struct ath_hal *ah, unsigned reg, u32 val)
+{
+ __raw_writel(val, ah->ah_sh + reg);
+}
+
+static u32 ath_ahb_reg_read(struct ath_hal *ah, unsigned reg)
+{
+ return __raw_readl(ah->ah_sh + reg);
+}
+
+/* return bus cachesize in 4B word units */
+static void ath_ahb_read_cachesize(struct ath_softc *sc, int *csz)
+{
+ *csz = L1_CACHE_BYTES >> 2;
+}
+
+static void ath_ahb_cleanup(struct ath_softc *sc)
+{
+ struct platform_device *pdev = to_platform_device(sc->dev);
+ struct ieee80211_hw *hw = sc->hw;
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, sc);
+
+ ath_detach(sc);
+ iounmap(sc->mem);
+ ieee80211_free_hw(hw);
+ platform_set_drvdata(pdev, NULL);
+}
+
+static struct ath_bus_ops ath_ahb_bus_ops = {
+ .dma_map_single_to_device = ath_ahb_map_single_to_device,
+ .dma_unmap_single_to_device = ath_ahb_unmap_single_to_device,
+ .dma_map_single_from_device = ath_ahb_map_single_from_device,
+ .dma_unmap_single_from_device = ath_ahb_unmap_single_from_device,
+ .dma_map_single_to_device = ath_ahb_map_single_to_device,
+ .dma_mapping_error = ath_ahb_dma_mapping_error,
+ .dma_sync_single_for_cpu = ath_ahb_sync_single_for_cpu,
+ .dma_alloc = ath_ahb_dma_alloc,
+ .dma_free = ath_ahb_dma_free,
+
+ .reg_read = ath_ahb_reg_read,
+ .reg_write = ath_ahb_reg_write,
+
+ .read_cachesize = ath_ahb_read_cachesize,
+
+ .cleanup = ath_ahb_cleanup,
+};
+
+static int ath_ahb_probe(struct platform_device *pdev)
+{
+ void __iomem *mem;
+ struct ath_softc *sc;
+ struct ieee80211_hw *hw;
+ struct resource *res;
+ int irq;
+ int ret = 0;
+ struct ath_hal *ah;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no memory resource found\n");
+ ret = -ENXIO;
+ goto err_out;
+ }
+
+ mem = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (mem == NULL) {
+ dev_err(&pdev->dev, "ioremap failed\n");
+ ret = -ENOMEM;
+ goto err_out;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no IRQ resource found\n");
+ ret = -ENXIO;
+ goto err_iounmap;
+ }
+
+ irq = res->start;
+
+ hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
+ if (hw == NULL) {
+ dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
+ ret = -ENOMEM;
+ goto err_iounmap;
+ }
+
+ hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+ IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+ IEEE80211_HW_SIGNAL_DBM |
+ IEEE80211_HW_NOISE_DBM;
+
+ hw->wiphy->interface_modes =
+ BIT(NL80211_IFTYPE_AP) |
+ BIT(NL80211_IFTYPE_STATION) |
+ BIT(NL80211_IFTYPE_ADHOC);
+
+ SET_IEEE80211_DEV(hw, &pdev->dev);
+ platform_set_drvdata(pdev, hw);
+
+ sc = hw->priv;
+ sc->hw = hw;
+ sc->dev = &pdev->dev;
+ sc->mem = mem;
+ sc->bus_ops = &ath_ahb_bus_ops;
+
+ ret = ath_attach(AR5416_AR9100_DEVID, sc);
+ if (ret != 0) {
+ dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
+ ret = -ENODEV;
+ goto err_free_hw;
+ }
+
+ ret = request_irq(irq, ath_isr, IRQF_SHARED, "ath9k", sc);
+ if (ret) {
+ dev_err(&pdev->dev, "request_irq failed, err=%d\n", ret);
+ ret = -EIO;
+ goto err_detach;
+ }
+
+ ah = sc->sc_ah;
+ printk(KERN_INFO
+ "%s: Atheros AR%s MAC/BB Rev:%x, "
+ "AR%s RF Rev:%x, mem=0x%lx, irq=%d\n",
+ wiphy_name(hw->wiphy),
+ ath_mac_bb_name(ah->ah_macVersion),
+ ah->ah_macRev,
+ ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)),
+ ah->ah_phyRev,
+ (unsigned long)mem, irq);
+
+ return 0;
+
+ err_detach:
+ ath_detach(sc);
+ err_free_hw:
+ ieee80211_free_hw(hw);
+ platform_set_drvdata(pdev, NULL);
+ err_iounmap:
+ iounmap(mem);
+ err_out:
+ return ret;
+}
+
+static int ath_ahb_remove(struct platform_device *pdev)
+{
+ struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+
+ if (hw) {
+ struct resource *res;
+ struct ath_softc *sc = hw->priv;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (res)
+ free_irq(res->start, sc);
+
+ ath_detach(sc);
+ iounmap(sc->mem);
+ ieee80211_free_hw(hw);
+ platform_set_drvdata(pdev, NULL);
+ }
+
+ return 0;
+}
+
+static struct platform_driver ath_ahb_driver = {
+ .probe = ath_ahb_probe,
+ .remove = ath_ahb_remove,
+ .driver = {
+ .name = "ath9k",
+ .owner = THIS_MODULE,
+ },
+};
+
+int ath_ahb_init(void)
+{
+ return platform_driver_register(&ath_ahb_driver);
+}
+
+void ath_ahb_exit(void)
+{
+ platform_driver_register(&ath_ahb_driver);
+}
diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h
index 6889df7..bb8b45b 100644
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -874,4 +874,12 @@ static inline int ath_pci_init(void) { return 0; };
static inline void ath_pci_exit(void) {};
#endif

+#ifdef CONFIG_ATHEROS_AR71XX
+int ath_ahb_init(void);
+void ath_ahb_exit(void);
+#else
+static inline int ath_ahb_init(void) { return 0; };
+static inline void ath_ahb_exit(void) {};
+#endif
+
#endif /* CORE_H */
diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c
index 423cf3b..b4aee16 100644
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -2533,8 +2533,17 @@ static int __init ath9k_init(void)
goto err_rate_unregister;
}

+ error = ath_ahb_init();
+ if (error < 0) {
+ error = -ENODEV;
+ goto err_pci_exit;
+ }
+
return 0;

+ err_pci_exit:
+ ath_pci_exit();
+
err_rate_unregister:
ath_rate_control_unregister();
err_out:
@@ -2544,6 +2553,7 @@ module_init(ath9k_init);

static void __exit ath9k_exit(void)
{
+ ath_ahb_exit();
ath_pci_exit();
ath_rate_control_unregister();
printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
--
1.5.3.2