2012-10-02 18:30:36

by John W. Linville

[permalink] [raw]
Subject: [RFC] rt2x00: check return from dma_map_single

From: "John W. Linville" <[email protected]>

dma_map_single can fail, so it's return value needs to be checked and
handled accordingly. Failure to do so is akin to failing to check the
return from a kmalloc.

http://linuxdriverproject.org/mediawiki/index.php/DMA_Mapping_Error_Analysis

Signed-off-by: John W. Linville <[email protected]>
Cc: Gertjan van Wingerde <[email protected]>
Cc: Ivo van Doorn <[email protected]>
---
Compile tested only...can the experts take a look at how the failures
are handled?

drivers/net/wireless/rt2x00/rt2400pci.c | 11 ++++++++---
drivers/net/wireless/rt2x00/rt2500pci.c | 11 ++++++++---
drivers/net/wireless/rt2x00/rt2500usb.c | 4 +++-
drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++--
drivers/net/wireless/rt2x00/rt2800lib.h | 2 +-
drivers/net/wireless/rt2x00/rt2x00.h | 6 +++---
drivers/net/wireless/rt2x00/rt2x00queue.c | 16 ++++++++++++++--
drivers/net/wireless/rt2x00/rt61pci.c | 8 +++++---
drivers/net/wireless/rt2x00/rt73usb.c | 8 +++++---
9 files changed, 51 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index e3a2d90..e79ada9 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1171,11 +1171,12 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt2400pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt2400pci_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 reg;
+ int err;

/*
* Disable beaconing while we are reloading the beacon data,
@@ -1185,7 +1186,9 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);

- rt2x00queue_map_txskb(entry);
+ err = rt2x00queue_map_txskb(entry);
+ if (err)
+ return err;

/*
* Write the TX descriptor for the beacon.
@@ -1202,6 +1205,8 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
*/
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ return 0;
}

/*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 479d756..988b38e 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1324,11 +1324,12 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt2500pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt2500pci_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 reg;
+ int err;

/*
* Disable beaconing while we are reloading the beacon data,
@@ -1338,7 +1339,9 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);

- rt2x00queue_map_txskb(entry);
+ err = rt2x00queue_map_txskb(entry);
+ if (err)
+ return err;

/*
* Write the TX descriptor for the beacon.
@@ -1355,6 +1358,8 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
*/
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ return 0;
}

/*
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index a12e84f..c476129 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1140,7 +1140,7 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry,
*/
static void rt2500usb_beacondone(struct urb *urb);

-static void rt2500usb_write_beacon(struct queue_entry *entry,
+static int rt2500usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -1219,6 +1219,8 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
+ return 0;
}

static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 540c94f..31ae4c3 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -762,7 +762,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi)
}
EXPORT_SYMBOL_GPL(rt2800_txdone_entry);

-void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+int rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@@ -810,7 +810,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
- return;
+ return 0; /* still use old beacon info */
}

beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -828,6 +828,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
*/
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2800_write_beacon);

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index a128cea..ad766bd 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -171,7 +171,7 @@ void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *tx

void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32* txwi);

-void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
+int rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);

extern const struct rt2x00debug rt2800_rt2x00debug;
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0751b35..50ff18d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -605,8 +605,8 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
void (*write_tx_data) (struct queue_entry *entry,
struct txentry_desc *txdesc);
- void (*write_beacon) (struct queue_entry *entry,
- struct txentry_desc *txdesc);
+ int (*write_beacon) (struct queue_entry *entry,
+ struct txentry_desc *txdesc);
void (*clear_beacon) (struct queue_entry *entry);
int (*get_tx_data_len) (struct queue_entry *entry);

@@ -1152,7 +1152,7 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @entry: Pointer to &struct queue_entry
*/
-void rt2x00queue_map_txskb(struct queue_entry *entry);
+int rt2x00queue_map_txskb(struct queue_entry *entry);

/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index e488b94..75b233e 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -91,20 +91,32 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
skb->data,
skb->len,
DMA_FROM_DEVICE);
+ if (dma_mapping_error(rt2x00dev->dev, skbdesc->skb_dma)) {
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
}

return skb;
}

-void rt2x00queue_map_txskb(struct queue_entry *entry)
+int rt2x00queue_map_txskb(struct queue_entry *entry)
{
struct device *dev = entry->queue->rt2x00dev->dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);

skbdesc->skb_dma =
dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, skbdesc->skb_dma)) {
+ ERROR(entry->queue->rt2x00dev,
+ "rt2x00queue_map_txskb(): can't map skb\n");
+ return -EIO;
+ }
+
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);

@@ -546,7 +558,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
* Map the skb to DMA.
*/
if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
- rt2x00queue_map_txskb(entry);
+ return rt2x00queue_map_txskb(entry);

return 0;
}
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index d6582a2..45f2b2a 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1962,8 +1962,8 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt61pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt61pci_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@@ -1999,7 +1999,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
- return;
+ return 0; /* still use old beacon info */
}

beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -2025,6 +2025,8 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
*/
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
+
+ return 0;
}

static void rt61pci_clear_beacon(struct queue_entry *entry)
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index e5eb43b..97612061 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1529,8 +1529,8 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt73usb_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt73usb_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
unsigned int beacon_base;
@@ -1571,7 +1571,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
- return;
+ return 0; /* still use old beacon info */
}

beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -1594,6 +1594,8 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
*/
dev_kfree_skb(entry->skb);
entry->skb = NULL;
+
+ return 0;
}

static void rt73usb_clear_beacon(struct queue_entry *entry)
--
1.7.11.4



2012-10-03 10:03:19

by Gertjan van Wingerde

[permalink] [raw]
Subject: Re: [RFC] rt2x00: check return from dma_map_single

On Tue, Oct 2, 2012 at 8:21 PM, John W. Linville <[email protected]> wrote:
> From: "John W. Linville" <[email protected]>
>
> dma_map_single can fail, so it's return value needs to be checked and
> handled accordingly. Failure to do so is akin to failing to check the
> return from a kmalloc.
>
> http://linuxdriverproject.org/mediawiki/index.php/DMA_Mapping_Error_Analysis
>
> Signed-off-by: John W. Linville <[email protected]>
> Cc: Gertjan van Wingerde <[email protected]>
> Cc: Ivo van Doorn <[email protected]>
> ---
> Compile tested only...can the experts take a look at how the failures
> are handled?

Next to the comment sent by Ivo (which is a comment I had as well),
see below for an additional remark.

<snip>

> diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
> index e488b94..75b233e 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00queue.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
> @@ -91,20 +91,32 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
> skb->data,
> skb->len,
> DMA_FROM_DEVICE);
> + if (dma_mapping_error(rt2x00dev->dev, skbdesc->skb_dma)) {
> + dev_kfree_skb_any(skb);
> + return NULL;
> + }

Could we use an unlikely() here for the check? This code has been in
rt2x00 for several years now, and we have no reports that dma mappings
failed, so the possibility of it failing seem truly unlikely.

> skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
> }
>
> return skb;
> }
>
> -void rt2x00queue_map_txskb(struct queue_entry *entry)
> +int rt2x00queue_map_txskb(struct queue_entry *entry)
> {
> struct device *dev = entry->queue->rt2x00dev->dev;
> struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
>
> skbdesc->skb_dma =
> dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
> + if (dma_mapping_error(dev, skbdesc->skb_dma)) {
> + ERROR(entry->queue->rt2x00dev,
> + "rt2x00queue_map_txskb(): can't map skb\n");
> + return -EIO;
> + }
> +

Same as above, please use unlikely().

---
Gertjan

2012-10-03 13:15:38

by John W. Linville

[permalink] [raw]
Subject: Re: [RFC] rt2x00: check return from dma_map_single

On Wed, Oct 03, 2012 at 11:33:25AM +0200, Ivo Van Doorn wrote:
> Hi,
>
> On Tue, Oct 2, 2012 at 8:21 PM, John W. Linville <[email protected]> wrote:
> > From: "John W. Linville" <[email protected]>
> >
> > dma_map_single can fail, so it's return value needs to be checked and
> > handled accordingly. Failure to do so is akin to failing to check the
> > return from a kmalloc.
> >
> > http://linuxdriverproject.org/mediawiki/index.php/DMA_Mapping_Error_Analysis
> >
> > Signed-off-by: John W. Linville <[email protected]>
> > Cc: Gertjan van Wingerde <[email protected]>
> > Cc: Ivo van Doorn <[email protected]>
> > ---
> > Compile tested only...can the experts take a look at how the failures
> > are handled?
>
> <snip>
>
> > diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
> > index 0751b35..50ff18d 100644
> > --- a/drivers/net/wireless/rt2x00/rt2x00.h
> > +++ b/drivers/net/wireless/rt2x00/rt2x00.h
> > @@ -605,8 +605,8 @@ struct rt2x00lib_ops {
> > struct txentry_desc *txdesc);
> > void (*write_tx_data) (struct queue_entry *entry,
> > struct txentry_desc *txdesc);
> > - void (*write_beacon) (struct queue_entry *entry,
> > - struct txentry_desc *txdesc);
> > + int (*write_beacon) (struct queue_entry *entry,
> > + struct txentry_desc *txdesc);
> > void (*clear_beacon) (struct queue_entry *entry);
> > int (*get_tx_data_len) (struct queue_entry *entry);
>
> The only thing I am missing in the commit, is the check for
> the return value when write_beacon is being called.

D'oh!! I got in a hurry...that's a lot of trouble to add a return
value just to not check it! :-)

--
John W. Linville Someday the world will need a hero, and you
[email protected] might be all we have. Be ready.

2012-10-03 09:33:26

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [RFC] rt2x00: check return from dma_map_single

Hi,

On Tue, Oct 2, 2012 at 8:21 PM, John W. Linville <[email protected]> wrote:
> From: "John W. Linville" <[email protected]>
>
> dma_map_single can fail, so it's return value needs to be checked and
> handled accordingly. Failure to do so is akin to failing to check the
> return from a kmalloc.
>
> http://linuxdriverproject.org/mediawiki/index.php/DMA_Mapping_Error_Analysis
>
> Signed-off-by: John W. Linville <[email protected]>
> Cc: Gertjan van Wingerde <[email protected]>
> Cc: Ivo van Doorn <[email protected]>
> ---
> Compile tested only...can the experts take a look at how the failures
> are handled?

<snip>

> diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
> index 0751b35..50ff18d 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00.h
> @@ -605,8 +605,8 @@ struct rt2x00lib_ops {
> struct txentry_desc *txdesc);
> void (*write_tx_data) (struct queue_entry *entry,
> struct txentry_desc *txdesc);
> - void (*write_beacon) (struct queue_entry *entry,
> - struct txentry_desc *txdesc);
> + int (*write_beacon) (struct queue_entry *entry,
> + struct txentry_desc *txdesc);
> void (*clear_beacon) (struct queue_entry *entry);
> int (*get_tx_data_len) (struct queue_entry *entry);

The only thing I am missing in the commit, is the check for
the return value when write_beacon is being called.

Ivo

2012-10-03 19:45:36

by John W. Linville

[permalink] [raw]
Subject: [RFC v2] rt2x00: check return from dma_map_single

From: "John W. Linville" <[email protected]>

dma_map_single can fail, so it's return value needs to be checked and
handled accordingly. Failure to do so is akin to failing to check the
return from a kmalloc.

http://linuxdriverproject.org/mediawiki/index.php/DMA_Mapping_Error_Analysis

Signed-off-by: John W. Linville <[email protected]>
Cc: Gertjan van Wingerde <[email protected]>
Cc: Ivo van Doorn <[email protected]>
---
Base on feedback from Ivo and Gertjan...

-- wrap dma_mapping_error calls in unlikely();

-- add an ERROR message for dma_mapping_error clause in
rt2x00queue_alloc_rxskb;

-- actually check the return value from write_beacon.

I'm still not entirely convinced that the failures are being handled
correctly. Also, the call-chain above write_beacon don't seem to check
the existing return codes?

drivers/net/wireless/rt2x00/rt2400pci.c | 11 ++++++++---
drivers/net/wireless/rt2x00/rt2500pci.c | 11 ++++++++---
drivers/net/wireless/rt2x00/rt2500usb.c | 4 +++-
drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++--
drivers/net/wireless/rt2x00/rt2800lib.h | 2 +-
drivers/net/wireless/rt2x00/rt2x00.h | 6 +++---
drivers/net/wireless/rt2x00/rt2x00queue.c | 30 ++++++++++++++++++++++++++----
drivers/net/wireless/rt2x00/rt61pci.c | 8 +++++---
drivers/net/wireless/rt2x00/rt73usb.c | 8 +++++---
9 files changed, 63 insertions(+), 23 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
index e3a2d90..e79ada9 100644
--- a/drivers/net/wireless/rt2x00/rt2400pci.c
+++ b/drivers/net/wireless/rt2x00/rt2400pci.c
@@ -1171,11 +1171,12 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt2400pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt2400pci_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 reg;
+ int err;

/*
* Disable beaconing while we are reloading the beacon data,
@@ -1185,7 +1186,9 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);

- rt2x00queue_map_txskb(entry);
+ err = rt2x00queue_map_txskb(entry);
+ if (err)
+ return err;

/*
* Write the TX descriptor for the beacon.
@@ -1202,6 +1205,8 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
*/
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ return 0;
}

/*
diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
index 479d756..988b38e 100644
--- a/drivers/net/wireless/rt2x00/rt2500pci.c
+++ b/drivers/net/wireless/rt2x00/rt2500pci.c
@@ -1324,11 +1324,12 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt2500pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt2500pci_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
u32 reg;
+ int err;

/*
* Disable beaconing while we are reloading the beacon data,
@@ -1338,7 +1339,9 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);

- rt2x00queue_map_txskb(entry);
+ err = rt2x00queue_map_txskb(entry);
+ if (err)
+ return err;

/*
* Write the TX descriptor for the beacon.
@@ -1355,6 +1358,8 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
*/
rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
rt2x00pci_register_write(rt2x00dev, CSR14, reg);
+
+ return 0;
}

/*
diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
index a12e84f..c476129 100644
--- a/drivers/net/wireless/rt2x00/rt2500usb.c
+++ b/drivers/net/wireless/rt2x00/rt2500usb.c
@@ -1140,7 +1140,7 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry,
*/
static void rt2500usb_beacondone(struct urb *urb);

-static void rt2500usb_write_beacon(struct queue_entry *entry,
+static int rt2500usb_write_beacon(struct queue_entry *entry,
struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -1219,6 +1219,8 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
+
+ return 0;
}

static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 540c94f..31ae4c3 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -762,7 +762,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi)
}
EXPORT_SYMBOL_GPL(rt2800_txdone_entry);

-void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
+int rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
@@ -810,7 +810,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
- return;
+ return 0; /* still use old beacon info */
}

beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -828,6 +828,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
*/
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2800_write_beacon);

diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
index a128cea..ad766bd 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.h
+++ b/drivers/net/wireless/rt2x00/rt2800lib.h
@@ -171,7 +171,7 @@ void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *tx

void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32* txwi);

-void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
+int rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
void rt2800_clear_beacon(struct queue_entry *entry);

extern const struct rt2x00debug rt2800_rt2x00debug;
diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
index 0751b35..50ff18d 100644
--- a/drivers/net/wireless/rt2x00/rt2x00.h
+++ b/drivers/net/wireless/rt2x00/rt2x00.h
@@ -605,8 +605,8 @@ struct rt2x00lib_ops {
struct txentry_desc *txdesc);
void (*write_tx_data) (struct queue_entry *entry,
struct txentry_desc *txdesc);
- void (*write_beacon) (struct queue_entry *entry,
- struct txentry_desc *txdesc);
+ int (*write_beacon) (struct queue_entry *entry,
+ struct txentry_desc *txdesc);
void (*clear_beacon) (struct queue_entry *entry);
int (*get_tx_data_len) (struct queue_entry *entry);

@@ -1152,7 +1152,7 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
* rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
* @entry: Pointer to &struct queue_entry
*/
-void rt2x00queue_map_txskb(struct queue_entry *entry);
+int rt2x00queue_map_txskb(struct queue_entry *entry);

/**
* rt2x00queue_unmap_skb - Unmap a skb from DMA.
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index e488b94..cb8b9e6 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -91,20 +91,35 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
skb->data,
skb->len,
DMA_FROM_DEVICE);
+ if (unlikely(dma_mapping_error(rt2x00dev->dev,
+ skbdesc->skb_dma))) {
+ ERROR(rt2x00dev,
+ "rt2x00queue_alloc_rxskb(): can't map skb\n");
+ dev_kfree_skb_any(skb);
+ return NULL;
+ }
skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
}

return skb;
}

-void rt2x00queue_map_txskb(struct queue_entry *entry)
+int rt2x00queue_map_txskb(struct queue_entry *entry)
{
struct device *dev = entry->queue->rt2x00dev->dev;
struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);

skbdesc->skb_dma =
dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma))) {
+ ERROR(entry->queue->rt2x00dev,
+ "rt2x00queue_map_txskb(): can't map skb\n");
+ return -EIO;
+ }
+
skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);

@@ -546,7 +561,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
* Map the skb to DMA.
*/
if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
- rt2x00queue_map_txskb(entry);
+ return rt2x00queue_map_txskb(entry);

return 0;
}
@@ -724,6 +739,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
struct rt2x00_intf *intf = vif_to_intf(vif);
struct skb_frame_desc *skbdesc;
struct txentry_desc txdesc;
+ int ret;

if (unlikely(!intf->beacon))
return -ENOBUFS;
@@ -754,10 +770,16 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
/*
* Send beacon to hardware.
*/
- rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
+ ret = rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
+ if (ret) {
+ /*
+ * Something went wrong...
+ */
+ rt2x00queue_free_skb(intf->beacon);
+ return -EIO;
+ }

return 0;
-
}

int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
index d6582a2..45f2b2a 100644
--- a/drivers/net/wireless/rt2x00/rt61pci.c
+++ b/drivers/net/wireless/rt2x00/rt61pci.c
@@ -1962,8 +1962,8 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt61pci_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt61pci_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
struct queue_entry_priv_pci *entry_priv = entry->priv_data;
@@ -1999,7 +1999,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
- return;
+ return 0; /* still use old beacon info */
}

beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -2025,6 +2025,8 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
*/
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
+
+ return 0;
}

static void rt61pci_clear_beacon(struct queue_entry *entry)
diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
index e5eb43b..97612061 100644
--- a/drivers/net/wireless/rt2x00/rt73usb.c
+++ b/drivers/net/wireless/rt2x00/rt73usb.c
@@ -1529,8 +1529,8 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry,
/*
* TX data initialization
*/
-static void rt73usb_write_beacon(struct queue_entry *entry,
- struct txentry_desc *txdesc)
+static int rt73usb_write_beacon(struct queue_entry *entry,
+ struct txentry_desc *txdesc)
{
struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
unsigned int beacon_base;
@@ -1571,7 +1571,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
/* skb freed by skb_pad() on failure */
entry->skb = NULL;
rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
- return;
+ return 0; /* still use old beacon info */
}

beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
@@ -1594,6 +1594,8 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
*/
dev_kfree_skb(entry->skb);
entry->skb = NULL;
+
+ return 0;
}

static void rt73usb_clear_beacon(struct queue_entry *entry)
--
1.7.11.4


2012-10-04 18:57:52

by Ivo Van Doorn

[permalink] [raw]
Subject: Re: [RFC v2] rt2x00: check return from dma_map_single

On Wed, Oct 3, 2012 at 9:32 PM, John W. Linville <[email protected]> wrote:
> From: "John W. Linville" <[email protected]>
>
> dma_map_single can fail, so it's return value needs to be checked and
> handled accordingly. Failure to do so is akin to failing to check the
> return from a kmalloc.
>
> http://linuxdriverproject.org/mediawiki/index.php/DMA_Mapping_Error_Analysis
>
> Signed-off-by: John W. Linville <[email protected]>
> Cc: Gertjan van Wingerde <[email protected]>
> Cc: Ivo van Doorn <[email protected]>

Acked-by: Ivo van Doorn <[email protected]>

> ---
> Base on feedback from Ivo and Gertjan...
>
> -- wrap dma_mapping_error calls in unlikely();
>
> -- add an ERROR message for dma_mapping_error clause in
> rt2x00queue_alloc_rxskb;
>
> -- actually check the return value from write_beacon.
>
> I'm still not entirely convinced that the failures are being handled
> correctly. Also, the call-chain above write_beacon don't seem to check
> the existing return codes?
>
> drivers/net/wireless/rt2x00/rt2400pci.c | 11 ++++++++---
> drivers/net/wireless/rt2x00/rt2500pci.c | 11 ++++++++---
> drivers/net/wireless/rt2x00/rt2500usb.c | 4 +++-
> drivers/net/wireless/rt2x00/rt2800lib.c | 6 ++++--
> drivers/net/wireless/rt2x00/rt2800lib.h | 2 +-
> drivers/net/wireless/rt2x00/rt2x00.h | 6 +++---
> drivers/net/wireless/rt2x00/rt2x00queue.c | 30 ++++++++++++++++++++++++++----
> drivers/net/wireless/rt2x00/rt61pci.c | 8 +++++---
> drivers/net/wireless/rt2x00/rt73usb.c | 8 +++++---
> 9 files changed, 63 insertions(+), 23 deletions(-)
>
> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c
> index e3a2d90..e79ada9 100644
> --- a/drivers/net/wireless/rt2x00/rt2400pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2400pci.c
> @@ -1171,11 +1171,12 @@ static void rt2400pci_write_tx_desc(struct queue_entry *entry,
> /*
> * TX data initialization
> */
> -static void rt2400pci_write_beacon(struct queue_entry *entry,
> - struct txentry_desc *txdesc)
> +static int rt2400pci_write_beacon(struct queue_entry *entry,
> + struct txentry_desc *txdesc)
> {
> struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> u32 reg;
> + int err;
>
> /*
> * Disable beaconing while we are reloading the beacon data,
> @@ -1185,7 +1186,9 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
> rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
> rt2x00pci_register_write(rt2x00dev, CSR14, reg);
>
> - rt2x00queue_map_txskb(entry);
> + err = rt2x00queue_map_txskb(entry);
> + if (err)
> + return err;
>
> /*
> * Write the TX descriptor for the beacon.
> @@ -1202,6 +1205,8 @@ static void rt2400pci_write_beacon(struct queue_entry *entry,
> */
> rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
> rt2x00pci_register_write(rt2x00dev, CSR14, reg);
> +
> + return 0;
> }
>
> /*
> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c
> index 479d756..988b38e 100644
> --- a/drivers/net/wireless/rt2x00/rt2500pci.c
> +++ b/drivers/net/wireless/rt2x00/rt2500pci.c
> @@ -1324,11 +1324,12 @@ static void rt2500pci_write_tx_desc(struct queue_entry *entry,
> /*
> * TX data initialization
> */
> -static void rt2500pci_write_beacon(struct queue_entry *entry,
> - struct txentry_desc *txdesc)
> +static int rt2500pci_write_beacon(struct queue_entry *entry,
> + struct txentry_desc *txdesc)
> {
> struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> u32 reg;
> + int err;
>
> /*
> * Disable beaconing while we are reloading the beacon data,
> @@ -1338,7 +1339,9 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
> rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 0);
> rt2x00pci_register_write(rt2x00dev, CSR14, reg);
>
> - rt2x00queue_map_txskb(entry);
> + err = rt2x00queue_map_txskb(entry);
> + if (err)
> + return err;
>
> /*
> * Write the TX descriptor for the beacon.
> @@ -1355,6 +1358,8 @@ static void rt2500pci_write_beacon(struct queue_entry *entry,
> */
> rt2x00_set_field32(&reg, CSR14_BEACON_GEN, 1);
> rt2x00pci_register_write(rt2x00dev, CSR14, reg);
> +
> + return 0;
> }
>
> /*
> diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c
> index a12e84f..c476129 100644
> --- a/drivers/net/wireless/rt2x00/rt2500usb.c
> +++ b/drivers/net/wireless/rt2x00/rt2500usb.c
> @@ -1140,7 +1140,7 @@ static void rt2500usb_write_tx_desc(struct queue_entry *entry,
> */
> static void rt2500usb_beacondone(struct urb *urb);
>
> -static void rt2500usb_write_beacon(struct queue_entry *entry,
> +static int rt2500usb_write_beacon(struct queue_entry *entry,
> struct txentry_desc *txdesc)
> {
> struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> @@ -1219,6 +1219,8 @@ static void rt2500usb_write_beacon(struct queue_entry *entry,
> rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
> rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg0);
> rt2500usb_register_write(rt2x00dev, TXRX_CSR19, reg);
> +
> + return 0;
> }
>
> static int rt2500usb_get_tx_data_len(struct queue_entry *entry)
> diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
> index 540c94f..31ae4c3 100644
> --- a/drivers/net/wireless/rt2x00/rt2800lib.c
> +++ b/drivers/net/wireless/rt2x00/rt2800lib.c
> @@ -762,7 +762,7 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32 *txwi)
> }
> EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
>
> -void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
> +int rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
> {
> struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
> @@ -810,7 +810,7 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
> /* skb freed by skb_pad() on failure */
> entry->skb = NULL;
> rt2800_register_write(rt2x00dev, BCN_TIME_CFG, orig_reg);
> - return;
> + return 0; /* still use old beacon info */
> }
>
> beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
> @@ -828,6 +828,8 @@ void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
> */
> dev_kfree_skb_any(entry->skb);
> entry->skb = NULL;
> +
> + return 0;
> }
> EXPORT_SYMBOL_GPL(rt2800_write_beacon);
>
> diff --git a/drivers/net/wireless/rt2x00/rt2800lib.h b/drivers/net/wireless/rt2x00/rt2800lib.h
> index a128cea..ad766bd 100644
> --- a/drivers/net/wireless/rt2x00/rt2800lib.h
> +++ b/drivers/net/wireless/rt2x00/rt2800lib.h
> @@ -171,7 +171,7 @@ void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *tx
>
> void rt2800_txdone_entry(struct queue_entry *entry, u32 status, __le32* txwi);
>
> -void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
> +int rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
> void rt2800_clear_beacon(struct queue_entry *entry);
>
> extern const struct rt2x00debug rt2800_rt2x00debug;
> diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h
> index 0751b35..50ff18d 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00.h
> +++ b/drivers/net/wireless/rt2x00/rt2x00.h
> @@ -605,8 +605,8 @@ struct rt2x00lib_ops {
> struct txentry_desc *txdesc);
> void (*write_tx_data) (struct queue_entry *entry,
> struct txentry_desc *txdesc);
> - void (*write_beacon) (struct queue_entry *entry,
> - struct txentry_desc *txdesc);
> + int (*write_beacon) (struct queue_entry *entry,
> + struct txentry_desc *txdesc);
> void (*clear_beacon) (struct queue_entry *entry);
> int (*get_tx_data_len) (struct queue_entry *entry);
>
> @@ -1152,7 +1152,7 @@ static inline bool rt2x00_is_soc(struct rt2x00_dev *rt2x00dev)
> * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes.
> * @entry: Pointer to &struct queue_entry
> */
> -void rt2x00queue_map_txskb(struct queue_entry *entry);
> +int rt2x00queue_map_txskb(struct queue_entry *entry);
>
> /**
> * rt2x00queue_unmap_skb - Unmap a skb from DMA.
> diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
> index e488b94..cb8b9e6 100644
> --- a/drivers/net/wireless/rt2x00/rt2x00queue.c
> +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
> @@ -91,20 +91,35 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
> skb->data,
> skb->len,
> DMA_FROM_DEVICE);
> + if (unlikely(dma_mapping_error(rt2x00dev->dev,
> + skbdesc->skb_dma))) {
> + ERROR(rt2x00dev,
> + "rt2x00queue_alloc_rxskb(): can't map skb\n");
> + dev_kfree_skb_any(skb);
> + return NULL;
> + }
> skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
> }
>
> return skb;
> }
>
> -void rt2x00queue_map_txskb(struct queue_entry *entry)
> +int rt2x00queue_map_txskb(struct queue_entry *entry)
> {
> struct device *dev = entry->queue->rt2x00dev->dev;
> struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
>
> skbdesc->skb_dma =
> dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
> + if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma))) {
> + ERROR(entry->queue->rt2x00dev,
> + "rt2x00queue_map_txskb(): can't map skb\n");
> + return -EIO;
> + }
> +
> skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
> +
> + return 0;
> }
> EXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
>
> @@ -546,7 +561,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
> * Map the skb to DMA.
> */
> if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
> - rt2x00queue_map_txskb(entry);
> + return rt2x00queue_map_txskb(entry);
>
> return 0;
> }
> @@ -724,6 +739,7 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
> struct rt2x00_intf *intf = vif_to_intf(vif);
> struct skb_frame_desc *skbdesc;
> struct txentry_desc txdesc;
> + int ret;
>
> if (unlikely(!intf->beacon))
> return -ENOBUFS;
> @@ -754,10 +770,16 @@ int rt2x00queue_update_beacon_locked(struct rt2x00_dev *rt2x00dev,
> /*
> * Send beacon to hardware.
> */
> - rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
> + ret = rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
> + if (ret) {
> + /*
> + * Something went wrong...
> + */
> + rt2x00queue_free_skb(intf->beacon);
> + return -EIO;
> + }
>
> return 0;
> -
> }
>
> int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
> diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c
> index d6582a2..45f2b2a 100644
> --- a/drivers/net/wireless/rt2x00/rt61pci.c
> +++ b/drivers/net/wireless/rt2x00/rt61pci.c
> @@ -1962,8 +1962,8 @@ static void rt61pci_write_tx_desc(struct queue_entry *entry,
> /*
> * TX data initialization
> */
> -static void rt61pci_write_beacon(struct queue_entry *entry,
> - struct txentry_desc *txdesc)
> +static int rt61pci_write_beacon(struct queue_entry *entry,
> + struct txentry_desc *txdesc)
> {
> struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> struct queue_entry_priv_pci *entry_priv = entry->priv_data;
> @@ -1999,7 +1999,7 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
> /* skb freed by skb_pad() on failure */
> entry->skb = NULL;
> rt2x00pci_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
> - return;
> + return 0; /* still use old beacon info */
> }
>
> beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
> @@ -2025,6 +2025,8 @@ static void rt61pci_write_beacon(struct queue_entry *entry,
> */
> dev_kfree_skb_any(entry->skb);
> entry->skb = NULL;
> +
> + return 0;
> }
>
> static void rt61pci_clear_beacon(struct queue_entry *entry)
> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c
> index e5eb43b..97612061 100644
> --- a/drivers/net/wireless/rt2x00/rt73usb.c
> +++ b/drivers/net/wireless/rt2x00/rt73usb.c
> @@ -1529,8 +1529,8 @@ static void rt73usb_write_tx_desc(struct queue_entry *entry,
> /*
> * TX data initialization
> */
> -static void rt73usb_write_beacon(struct queue_entry *entry,
> - struct txentry_desc *txdesc)
> +static int rt73usb_write_beacon(struct queue_entry *entry,
> + struct txentry_desc *txdesc)
> {
> struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
> unsigned int beacon_base;
> @@ -1571,7 +1571,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
> /* skb freed by skb_pad() on failure */
> entry->skb = NULL;
> rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, orig_reg);
> - return;
> + return 0; /* still use old beacon info */
> }
>
> beacon_base = HW_BEACON_OFFSET(entry->entry_idx);
> @@ -1594,6 +1594,8 @@ static void rt73usb_write_beacon(struct queue_entry *entry,
> */
> dev_kfree_skb(entry->skb);
> entry->skb = NULL;
> +
> + return 0;
> }
>
> static void rt73usb_clear_beacon(struct queue_entry *entry)
> --
> 1.7.11.4
>