aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/b43')
-rw-r--r--drivers/net/wireless/b43/dma.c70
-rw-r--r--drivers/net/wireless/b43/main.c5
-rw-r--r--drivers/net/wireless/b43/phy_common.c16
-rw-r--r--drivers/net/wireless/b43/phy_common.h4
4 files changed, 70 insertions, 25 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c
index 0cc804d0a214..eae680b53052 100644
--- a/drivers/net/wireless/b43/dma.c
+++ b/drivers/net/wireless/b43/dma.c
@@ -555,11 +555,32 @@ address_error:
return 1;
}
+static bool b43_rx_buffer_is_poisoned(struct b43_dmaring *ring, struct sk_buff *skb)
+{
+ unsigned char *f = skb->data + ring->frameoffset;
+
+ return ((f[0] & f[1] & f[2] & f[3] & f[4] & f[5] & f[6] & f[7]) == 0xFF);
+}
+
+static void b43_poison_rx_buffer(struct b43_dmaring *ring, struct sk_buff *skb)
+{
+ struct b43_rxhdr_fw4 *rxhdr;
+ unsigned char *frame;
+
+ /* This poisons the RX buffer to detect DMA failures. */
+
+ rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
+ rxhdr->frame_len = 0;
+
+ B43_WARN_ON(ring->rx_buffersize < ring->frameoffset + sizeof(struct b43_plcp_hdr6) + 2);
+ frame = skb->data + ring->frameoffset;
+ memset(frame, 0xFF, sizeof(struct b43_plcp_hdr6) + 2 /* padding */);
+}
+
static int setup_rx_descbuffer(struct b43_dmaring *ring,
struct b43_dmadesc_generic *desc,
struct b43_dmadesc_meta *meta, gfp_t gfp_flags)
{
- struct b43_rxhdr_fw4 *rxhdr;
dma_addr_t dmaaddr;
struct sk_buff *skb;
@@ -568,6 +589,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
if (unlikely(!skb))
return -ENOMEM;
+ b43_poison_rx_buffer(ring, skb);
dmaaddr = map_descbuffer(ring, skb->data, ring->rx_buffersize, 0);
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
/* ugh. try to realloc in zone_dma */
@@ -578,6 +600,7 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
skb = __dev_alloc_skb(ring->rx_buffersize, gfp_flags);
if (unlikely(!skb))
return -ENOMEM;
+ b43_poison_rx_buffer(ring, skb);
dmaaddr = map_descbuffer(ring, skb->data,
ring->rx_buffersize, 0);
if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
@@ -592,9 +615,6 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
ring->ops->fill_descriptor(ring, desc, dmaaddr,
ring->rx_buffersize, 0, 0, 0);
- rxhdr = (struct b43_rxhdr_fw4 *)(skb->data);
- rxhdr->frame_len = 0;
-
return 0;
}
@@ -772,23 +792,23 @@ static u64 supported_dma_mask(struct b43_wldev *dev)
tmp = b43_read32(dev, SSB_TMSHIGH);
if (tmp & SSB_TMSHIGH_DMA64)
- return DMA_64BIT_MASK;
+ return DMA_BIT_MASK(64);
mmio_base = b43_dmacontroller_base(0, 0);
b43_write32(dev, mmio_base + B43_DMA32_TXCTL, B43_DMA32_TXADDREXT_MASK);
tmp = b43_read32(dev, mmio_base + B43_DMA32_TXCTL);
if (tmp & B43_DMA32_TXADDREXT_MASK)
- return DMA_32BIT_MASK;
+ return DMA_BIT_MASK(32);
- return DMA_30BIT_MASK;
+ return DMA_BIT_MASK(30);
}
static enum b43_dmatype dma_mask_to_engine_type(u64 dmamask)
{
- if (dmamask == DMA_30BIT_MASK)
+ if (dmamask == DMA_BIT_MASK(30))
return B43_DMA_30BIT;
- if (dmamask == DMA_32BIT_MASK)
+ if (dmamask == DMA_BIT_MASK(32))
return B43_DMA_32BIT;
- if (dmamask == DMA_64BIT_MASK)
+ if (dmamask == DMA_BIT_MASK(64))
return B43_DMA_64BIT;
B43_WARN_ON(1);
return B43_DMA_30BIT;
@@ -999,13 +1019,13 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
err = ssb_dma_set_mask(dev->dev, mask);
if (!err)
break;
- if (mask == DMA_64BIT_MASK) {
- mask = DMA_32BIT_MASK;
+ if (mask == DMA_BIT_MASK(64)) {
+ mask = DMA_BIT_MASK(32);
fallback = 1;
continue;
}
- if (mask == DMA_32BIT_MASK) {
- mask = DMA_30BIT_MASK;
+ if (mask == DMA_BIT_MASK(32)) {
+ mask = DMA_BIT_MASK(30);
fallback = 1;
continue;
}
@@ -1483,12 +1503,17 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
len = le16_to_cpu(rxhdr->frame_len);
} while (len == 0 && i++ < 5);
if (unlikely(len == 0)) {
- /* recycle the descriptor buffer. */
- sync_descbuffer_for_device(ring, meta->dmaaddr,
- ring->rx_buffersize);
- goto drop;
+ dmaaddr = meta->dmaaddr;
+ goto drop_recycle_buffer;
}
}
+ if (unlikely(b43_rx_buffer_is_poisoned(ring, skb))) {
+ /* Something went wrong with the DMA.
+ * The device did not touch the buffer and did not overwrite the poison. */
+ b43dbg(ring->dev->wl, "DMA RX: Dropping poisoned buffer.\n");
+ dmaaddr = meta->dmaaddr;
+ goto drop_recycle_buffer;
+ }
if (unlikely(len > ring->rx_buffersize)) {
/* The data did not fit into one descriptor buffer
* and is split over multiple buffers.
@@ -1501,6 +1526,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
while (1) {
desc = ops->idx2desc(ring, *slot, &meta);
/* recycle the descriptor buffer. */
+ b43_poison_rx_buffer(ring, meta->skb);
sync_descbuffer_for_device(ring, meta->dmaaddr,
ring->rx_buffersize);
*slot = next_slot(ring, *slot);
@@ -1519,8 +1545,7 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
err = setup_rx_descbuffer(ring, desc, meta, GFP_ATOMIC);
if (unlikely(err)) {
b43dbg(ring->dev->wl, "DMA RX: setup_rx_descbuffer() failed\n");
- sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
- goto drop;
+ goto drop_recycle_buffer;
}
unmap_descbuffer(ring, dmaaddr, ring->rx_buffersize, 0);
@@ -1530,6 +1555,11 @@ static void dma_rx(struct b43_dmaring *ring, int *slot)
b43_rx(ring->dev, skb, rxhdr);
drop:
return;
+
+drop_recycle_buffer:
+ /* Poison and recycle the RX buffer. */
+ b43_poison_rx_buffer(ring, skb);
+ sync_descbuffer_for_device(ring, dmaaddr, ring->rx_buffersize);
}
void b43_dma_rx(struct b43_dmaring *ring)
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 4896e0831114..79b685e300c7 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -3974,6 +3974,11 @@ static void setup_struct_phy_for_init(struct b43_wldev *dev,
phy->next_txpwr_check_time = jiffies;
/* PHY TX errors counter. */
atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
+
+#if B43_DEBUG
+ phy->phy_locked = 0;
+ phy->radio_locked = 0;
+#endif
}
static void setup_struct_wldev_for_init(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index 026b61c03fb9..e176b6e0d9cf 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -131,12 +131,16 @@ void b43_radio_lock(struct b43_wldev *dev)
{
u32 macctl;
+#if B43_DEBUG
+ B43_WARN_ON(dev->phy.radio_locked);
+ dev->phy.radio_locked = 1;
+#endif
+
macctl = b43_read32(dev, B43_MMIO_MACCTL);
- B43_WARN_ON(macctl & B43_MACCTL_RADIOLOCK);
macctl |= B43_MACCTL_RADIOLOCK;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
- /* Commit the write and wait for the device
- * to exit any radio register access. */
+ /* Commit the write and wait for the firmware
+ * to finish any radio register access. */
b43_read32(dev, B43_MMIO_MACCTL);
udelay(10);
}
@@ -145,11 +149,15 @@ void b43_radio_unlock(struct b43_wldev *dev)
{
u32 macctl;
+#if B43_DEBUG
+ B43_WARN_ON(!dev->phy.radio_locked);
+ dev->phy.radio_locked = 0;
+#endif
+
/* Commit any write */
b43_read16(dev, B43_MMIO_PHY_VER);
/* unlock */
macctl = b43_read32(dev, B43_MMIO_MACCTL);
- B43_WARN_ON(!(macctl & B43_MACCTL_RADIOLOCK));
macctl &= ~B43_MACCTL_RADIOLOCK;
b43_write32(dev, B43_MMIO_MACCTL, macctl);
}
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index c9f5430d1d7d..b2d99101947b 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -245,8 +245,10 @@ struct b43_phy {
atomic_t txerr_cnt;
#ifdef CONFIG_B43_DEBUG
- /* PHY registers locked by b43_phy_lock()? */
+ /* PHY registers locked (w.r.t. firmware) */
bool phy_locked;
+ /* Radio registers locked (w.r.t. firmware) */
+ bool radio_locked;
#endif /* B43_DEBUG */
};