mac80211: add preliminary support for the AR913x SoCs

SVN-Revision: 13835
This commit is contained in:
Gabor Juhos 2009-01-03 13:48:27 +00:00
parent e0a77da8fb
commit 23caf183fc
14 changed files with 2393 additions and 0 deletions

View file

@ -0,0 +1,392 @@
From d6f9b4eb74f8be1be90ee315ed3895e6b0265c42 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:07:21 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
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(-)
--- a/drivers/net/wireless/ath9k/beacon.c
+++ b/drivers/net/wireless/ath9k/beacon.c
@@ -164,9 +164,7 @@ static struct ath_buf *ath_beacon_genera
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_genera
}
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 *s
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 *s
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
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;
}
--- 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 a
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 */
--- 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 *
}
/* 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 *
}
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_soft
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
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;
--- 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, in
}
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,
* 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,
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,
/* 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;
--- 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 a
}
/* 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 at
/* 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;
}

View file

@ -0,0 +1,89 @@
From 0ef95ef08ca82a87c85a1656f434a03a98bfab5b Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:07:50 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
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(-)
--- 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)
--- 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 a
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 */
--- 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_
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_op
.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)

View file

@ -0,0 +1,74 @@
From a81f936d72caabbcf5698a6636185a8f6630d692 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:08:22 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/core.h | 7 +++++++
drivers/net/wireless/ath9k/main.c | 8 +++++---
2 files changed, 12 insertions(+), 3 deletions(-)
--- 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
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 */
--- 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_t
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 at
*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 at
* 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_op
.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)

View file

@ -0,0 +1,95 @@
From d23e90c384edfbf039cb8b8d94c0ef90022949e7 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:08:45 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/core.h | 7 +++++++
drivers/net/wireless/ath9k/main.c | 29 +++++++++++++++--------------
2 files changed, 22 insertions(+), 14 deletions(-)
--- 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(st
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 */
--- 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
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
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_op
.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_de
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

View file

@ -0,0 +1,853 @@
From 957a60be8a6b55da588df12e160ac53e3b36238e Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:10:25 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
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(-)
--- 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
--- a/drivers/net/wireless/ath9k/core.h
+++ b/drivers/net/wireless/ath9k/core.h
@@ -857,4 +857,20 @@ static inline void ath_bus_cleanup(struc
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 */
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -28,37 +28,6 @@ MODULE_DESCRIPTION("Support for Atheros
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
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
}
#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 iee
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);
--- /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);
+}

View file

@ -0,0 +1,144 @@
From 5e7bcb74706e6398ea582001fe025e6eb0c5c998 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:10:55 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/core.h | 5 +++--
drivers/net/wireless/ath9k/pci.c | 35 ++++++++++++++++++++---------------
2 files changed, 23 insertions(+), 17 deletions(-)
--- 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;
--- 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(struc
{
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(struc
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
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
sc = hw->priv;
sc->hw = hw;
- sc->pdev = pdev;
+ sc->dev = &pdev->dev;
sc->mem = mem;
sc->bus_ops = &ath_pci_bus_ops;

View file

@ -0,0 +1,331 @@
From 9456893748c407d9fed06046308177edaca38450 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:12:30 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
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(-)
--- 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
--- /dev/null
+++ b/drivers/net/wireless/ath9k/ahb.c
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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);
+}
--- 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) { r
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 */
--- 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);

View file

@ -0,0 +1,222 @@
From 1781a259c5c34d63279b997bded2db672b3665d2 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:13:46 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
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(-)
--- 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_s
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_op
.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
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");
--- 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 {
--- 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_up
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_ha
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
--- 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_s
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_op
.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)
--- /dev/null
+++ b/include/linux/ath9k_platform.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2008 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 */

View file

@ -0,0 +1,32 @@
From 35c21a4ce13a08030f3acb491f353ad959873fe2 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:14:41 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/hw.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
--- 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
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 devi
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:

View file

@ -0,0 +1,60 @@
From 2b4dfbbae2e9e78e09e9e6a82e2d744f54049202 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:15:39 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/hw.c | 14 +++++++-------
1 files changed, 7 insertions(+), 7 deletions(-)
--- 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
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 at
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(
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
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);
}
}

View file

@ -0,0 +1,27 @@
From 36e057a8e3a0a811e24d42ed4d404f23bbd18107 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:16:33 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/initvals.h | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- 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 */

View file

@ -0,0 +1,37 @@
From e5d00646a207c4e9da254283eee2d278de338394 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Fri, 2 Jan 2009 16:17:25 +0100
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 <juhosg@openwrt.org>
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
---
drivers/net/wireless/ath9k/ani.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
--- 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
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
aniState->cckPhyErrCount = cckPhyErrCnt;
}
- if (!DO_ANI(ah))
- return;
-
if (aniState->listenTime > 5 * ahp->ah_aniPeriod) {
if (aniState->ofdmPhyErrCount <= aniState->listenTime *
aniState->ofdmTrigLow / 1000 &&

View file

@ -0,0 +1,22 @@
From 1f5bc9c74fa57783483fda4e2f69ffc545d37994 Mon Sep 17 00:00:00 2001
From: Gabor Juhos <juhosg@openwrt.org>
Date: Mon, 29 Dec 2008 18:35:39 +0100
Subject: [PATCH] ath9k: use signed format to print HAL status
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
---
drivers/net/wireless/ath9k/main.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
--- a/drivers/net/wireless/ath9k/main.c
+++ b/drivers/net/wireless/ath9k/main.c
@@ -1317,7 +1317,7 @@ static int ath_init(u16 devid, struct at
ah = ath9k_hw_attach(devid, sc, sc->mem, &status);
if (ah == NULL) {
DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to attach hardware; HAL status %u\n", status);
+ "Unable to attach hardware; HAL status %d\n", status);
error = -ENXIO;
goto bad;
}

View file

@ -0,0 +1,15 @@
--- a/drivers/net/wireless/ath9k/hw.c
+++ b/drivers/net/wireless/ath9k/hw.c
@@ -525,10 +525,10 @@ static int ath9k_hw_rf_claim(struct ath_
case AR_RAD2122_SREV_MAJOR:
break;
default:
- DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL,
+ DPRINTF(ah->ah_sc, ATH_DBG_FATAL,
"5G Radio Chip Rev 0x%02X is not "
"supported by this driver\n",
- ah->ah_analog5GhzRev);
+ val);
return -EOPNOTSUPP;
}