2007-06-27 21:14:43

by Michal Schmidt

[permalink] [raw]
Subject: [PATCH 0/4] airo fixes

Hello,

this is a series of four patches for the airo driver:

1/4: airo: don't use the interface name so much before registration
2/4: airo: delay parts of initialization until the netdev is up
3/4: airo: disable the PCI device when unloading module
4/4: airo: start with radio off

The first two fix the race condition Matteo Croce was experiencing.
The third one fixes a bug I noticed during testing.
The last one saves some power when the card is not used.

Michal


2007-06-27 21:18:45

by Michal Schmidt

[permalink] [raw]
Subject: [PATCH 4/4] airo: start with radio off

Don't turn the radio on until the interface is up. This saves some power in
case the driver is loaded but the card is not used.

Signed-off-by: Michal Schmidt <[email protected]>

---
drivers/net/wireless/airo.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index d46d27a..eb3c675 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -2833,7 +2833,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,

ai = dev->priv;
ai->wifidev = NULL;
- ai->flags = 0;
+ ai->flags = 1 << FLAG_RADIO_DOWN;
ai->jobs = 0;
ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {



2007-06-27 21:16:56

by Michal Schmidt

[permalink] [raw]
Subject: [PATCH 2/4] airo: delay parts of initialization until the netdev is up

airo's kernel thread and the IRQ handler are needed only when the interface
is up.
With their initialization moved to .open() there are no more users of
dev->name before registration, so this fixes the race when the
initialization could fail when another netdev stole airo's name.

Signed-off-by: Michal Schmidt <[email protected]>

---
drivers/net/wireless/airo.c | 84 +++++++++++++++++++++++--------------------
1 files changed, 45 insertions(+), 39 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 38346a5..63a4aaa 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1928,28 +1928,55 @@ static int readStatsRid(struct airo_info*ai, StatsRid *sr, int rid, int lock) {
return rc;
}

+static void try_auto_wep(struct airo_info *ai)
+{
+ if (auto_wep && !(ai->flags & FLAG_RADIO_DOWN)) {
+ ai->expires = RUN_AT(3*HZ);
+ wake_up_interruptible(&ai->thr_wait);
+ }
+}
+
static int airo_open(struct net_device *dev) {
- struct airo_info *info = dev->priv;
+ struct airo_info *ai = dev->priv;
Resp rsp;
+ int rc = 0;

- if (test_bit(FLAG_FLASHING, &info->flags))
+ if (test_bit(FLAG_FLASHING, &ai->flags))
return -EIO;

/* Make sure the card is configured.
* Wireless Extensions may postpone config changes until the card
* is open (to pipeline changes and speed-up card setup). If
* those changes are not yet commited, do it now - Jean II */
- if (test_bit (FLAG_COMMIT, &info->flags)) {
- disable_MAC(info, 1);
- writeConfigRid(info, 1);
+ if (test_bit(FLAG_COMMIT, &ai->flags)) {
+ disable_MAC(ai, 1);
+ writeConfigRid(ai, 1);
}

- if (info->wifidev != dev) {
+ if (ai->wifidev != dev) {
+ clear_bit(JOB_DIE, &ai->jobs);
+ ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
+ if (IS_ERR(ai->airo_thread_task))
+ return (int)PTR_ERR(ai->airo_thread_task);
+
+ rc = request_irq(dev->irq, airo_interrupt, IRQF_SHARED,
+ dev->name, dev);
+ if (rc) {
+ airo_print_err(dev->name,
+ "register interrupt %d failed, rc %d",
+ dev->irq, rc);
+ set_bit(JOB_DIE, &ai->jobs);
+ kthread_stop(ai->airo_thread_task);
+ return rc;
+ }
+
/* Power on the MAC controller (which may have been disabled) */
- clear_bit(FLAG_RADIO_DOWN, &info->flags);
- enable_interrupts(info);
+ clear_bit(FLAG_RADIO_DOWN, &ai->flags);
+ enable_interrupts(ai);
+
+ try_auto_wep(ai);
}
- enable_MAC(info, &rsp, 1);
+ enable_MAC(ai, &rsp, 1);

netif_start_queue(dev);
return 0;
@@ -2394,6 +2421,11 @@ static int airo_close(struct net_device *dev) {
disable_MAC(ai, 1);
#endif
disable_interrupts( ai );
+
+ free_irq(dev->irq, dev);
+
+ set_bit(JOB_DIE, &ai->jobs);
+ kthread_stop(ai->airo_thread_task);
}
return 0;
}
@@ -2405,7 +2437,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
set_bit(FLAG_RADIO_DOWN, &ai->flags);
disable_MAC(ai, 1);
disable_interrupts(ai);
- free_irq( dev->irq, dev );
takedown_proc_entry( dev, ai );
if (test_bit(FLAG_REGISTERED, &ai->flags)) {
unregister_netdev( dev );
@@ -2416,9 +2447,6 @@ void stop_airo_card( struct net_device *dev, int freeres )
}
clear_bit(FLAG_REGISTERED, &ai->flags);
}
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
-
/*
* Clean out tx queue
*/
@@ -2802,10 +2830,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
airo_print_err("", "Couldn't alloc_etherdev");
return NULL;
}
- if (dev_alloc_name(dev, dev->name) < 0) {
- airo_print_err("", "Couldn't get name!");
- goto err_out_free;
- }

ai = dev->priv;
ai->wifidev = NULL;
@@ -2821,14 +2845,11 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->config.len = 0;
ai->pci = pci;
init_waitqueue_head (&ai->thr_wait);
- ai->airo_thread_task = kthread_run(airo_thread, dev, dev->name);
- if (IS_ERR(ai->airo_thread_task))
- goto err_out_free;
ai->tfm = NULL;
add_airo_dev(ai);

if (airo_networks_allocate (ai))
- goto err_out_thr;
+ goto err_out_free;
airo_networks_initialize (ai);

/* The Airo-specific entries in the device structure. */
@@ -2851,21 +2872,16 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
dev->base_addr = port;

SET_NETDEV_DEV(dev, dmdev);
+ SET_MODULE_OWNER(dev);

reset_card (dev, 1);
msleep(400);

- rc = request_irq( dev->irq, airo_interrupt, IRQF_SHARED, dev->name, dev );
- if (rc) {
- airo_print_err(dev->name, "register interrupt %d failed, rc %d",
- irq, rc);
- goto err_out_nets;
- }
if (!is_pcmcia) {
if (!request_region(dev->base_addr, 64, DRV_NAME)) {
rc = -EBUSY;
airo_print_err("", "Couldn't request region");
- goto err_out_irq;
+ goto err_out_nets;
}
}

@@ -2921,8 +2937,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
if (setup_proc_entry(dev, dev->priv) < 0)
goto err_out_wifi;

- netif_start_queue(dev);
- SET_MODULE_OWNER(dev);
return dev;

err_out_wifi:
@@ -2940,14 +2954,9 @@ err_out_map:
err_out_res:
if (!is_pcmcia)
release_region( dev->base_addr, 64 );
-err_out_irq:
- free_irq(dev->irq, dev);
err_out_nets:
airo_networks_free(ai);
-err_out_thr:
del_airo_dev(ai);
- set_bit(JOB_DIE, &ai->jobs);
- kthread_stop(ai->airo_thread_task);
err_out_free:
free_netdev(dev);
return NULL;
@@ -3919,10 +3928,7 @@ static u16 setup_card(struct airo_info *ai, u8 *mac, int lock)
rc = readWepKeyRid(ai, &wkr, 0, lock);
} while(lastindex != wkr.kindex);

- if (auto_wep) {
- ai->expires = RUN_AT(3*HZ);
- wake_up_interruptible(&ai->thr_wait);
- }
+ try_auto_wep(ai);

return SUCCESS;
}



2007-06-28 05:02:10

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH 0/4] airo fixes

On Wed, 2007-06-27 at 23:14 +0200, Michal Schmidt wrote:
> Hello,
>
> this is a series of four patches for the airo driver:
>
> 1/4: airo: don't use the interface name so much before registration
> 2/4: airo: delay parts of initialization until the netdev is up
> 3/4: airo: disable the PCI device when unloading module
> 4/4: airo: start with radio off
>
> The first two fix the race condition Matteo Croce was experiencing.
> The third one fixes a bug I noticed during testing.
> The last one saves some power when the card is not used.

These all look good to me, I might be able to find some time to
runtime-test them too if you want more testing.

Dan



2007-06-27 21:18:09

by Michal Schmidt

[permalink] [raw]
Subject: [PATCH 3/4] airo: disable the PCI device when unloading module

Fix an assymetry between pci_{enable,disable}_device. airo did not disable
the PCI device when unloading the module. This caused suspend failures
after modprobe -r airo && modprobe airo.

Signed-off-by: Michal Schmidt <[email protected]>

---
drivers/net/wireless/airo.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 63a4aaa..d46d27a 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -5603,8 +5603,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev,
dev = _init_airo_card(pdev->irq, pdev->resource[0].start, 0, pdev, &pdev->dev);
else
dev = _init_airo_card(pdev->irq, pdev->resource[2].start, 0, pdev, &pdev->dev);
- if (!dev)
+ if (!dev) {
+ pci_disable_device(pdev);
return -ENODEV;
+ }

pci_set_drvdata(pdev, dev);
return 0;
@@ -5616,6 +5618,8 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev)

airo_print_info(dev->name, "Unregistering...");
stop_airo_card(dev, 1);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
}

static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)



2007-06-27 21:15:54

by Michal Schmidt

[permalink] [raw]
Subject: [PATCH 1/4] airo: don't use the interface name so much before registration

Matteo Croce reported Aironet initialization failures. They were caused by
a race in airo. airo finds a free interface name, then initializes the card
and finally registers the interface. Another device may get the same name in
the meantime.
The reason airo gets its name early is to use it in informative printks and
to name the resources it requests. The printks will be just fine without
the interface name and the resources can use the driver's name - that's
what other network drivers do anyway.
Note that we still use the interface name in request_irq and for the
kernel thread. The race is not fixed by this change, but it's a first step.

Signed-off-by: Michal Schmidt <[email protected]>

---
drivers/net/wireless/airo.c | 50 ++++++++++++++++++++++---------------------
1 files changed, 25 insertions(+), 25 deletions(-)

diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index 2d3a180..38346a5 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -52,6 +52,8 @@

#include "airo.h"

+#define DRV_NAME "airo"
+
#ifdef CONFIG_PCI
static struct pci_device_id card_ids[] = {
{ 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, },
@@ -71,7 +73,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state);
static int airo_pci_resume(struct pci_dev *pdev);

static struct pci_driver airo_driver = {
- .name = "airo",
+ .name = DRV_NAME,
.id_table = card_ids,
.probe = airo_pci_probe,
.remove = __devexit_p(airo_pci_remove),
@@ -1250,7 +1252,7 @@ static int flashputbuf(struct airo_info *ai);
static int flashrestart(struct airo_info *ai,struct net_device *dev);

#define airo_print(type, name, fmt, args...) \
- { printk(type "airo(%s): " fmt "\n", name, ##args); }
+ { printk(type DRV_NAME "(%s): " fmt "\n", name, ##args); }

#define airo_print_info(name, fmt, args...) \
airo_print(KERN_INFO, name, fmt, ##args)
@@ -2554,8 +2556,7 @@ static int mpi_init_descriptors (struct airo_info *ai)
* 2) Map PCI memory for issueing commands.
* 3) Allocate memory (shared) to send and receive ethernet frames.
*/
-static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
- const char *name)
+static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci)
{
unsigned long mem_start, mem_len, aux_start, aux_len;
int rc = -1;
@@ -2569,34 +2570,34 @@ static int mpi_map_card(struct airo_info *ai, struct pci_dev *pci,
aux_start = pci_resource_start(pci, 2);
aux_len = AUXMEMSIZE;

- if (!request_mem_region(mem_start, mem_len, name)) {
- airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
- (int)mem_start, (int)mem_len, name);
+ if (!request_mem_region(mem_start, mem_len, DRV_NAME)) {
+ airo_print_err("", "Couldn't get region %x[%x]",
+ (int)mem_start, (int)mem_len);
goto out;
}
- if (!request_mem_region(aux_start, aux_len, name)) {
- airo_print_err(ai->dev->name, "Couldn't get region %x[%x] for %s",
- (int)aux_start, (int)aux_len, name);
+ if (!request_mem_region(aux_start, aux_len, DRV_NAME)) {
+ airo_print_err("", "Couldn't get region %x[%x]",
+ (int)aux_start, (int)aux_len);
goto free_region1;
}

ai->pcimem = ioremap(mem_start, mem_len);
if (!ai->pcimem) {
- airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
- (int)mem_start, (int)mem_len, name);
+ airo_print_err("", "Couldn't map region %x[%x]",
+ (int)mem_start, (int)mem_len);
goto free_region2;
}
ai->pciaux = ioremap(aux_start, aux_len);
if (!ai->pciaux) {
- airo_print_err(ai->dev->name, "Couldn't map region %x[%x] for %s",
- (int)aux_start, (int)aux_len, name);
+ airo_print_err("", "Couldn't map region %x[%x]",
+ (int)aux_start, (int)aux_len);
goto free_memmap;
}

/* Reserve PKTSIZE for each fid and 2K for the Rids */
ai->shared = pci_alloc_consistent(pci, PCI_SHARED_LEN, &ai->shared_dma);
if (!ai->shared) {
- airo_print_err(ai->dev->name, "Couldn't alloc_consistent %d",
+ airo_print_err("", "Couldn't alloc_consistent %d",
PCI_SHARED_LEN);
goto free_auxmap;
}
@@ -2742,7 +2743,7 @@ static int airo_networks_allocate(struct airo_info *ai)
kzalloc(AIRO_MAX_NETWORK_COUNT * sizeof(BSSListElement),
GFP_KERNEL);
if (!ai->networks) {
- airo_print_warn(ai->dev->name, "Out of memory allocating beacons");
+ airo_print_warn("", "Out of memory allocating beacons");
return -ENOMEM;
}

@@ -2770,7 +2771,6 @@ static int airo_test_wpa_capable(struct airo_info *ai)
{
int status;
CapabilityRid cap_rid;
- const char *name = ai->dev->name;

status = readCapabilityRid(ai, &cap_rid, 1);
if (status != SUCCESS) return 0;
@@ -2778,12 +2778,12 @@ static int airo_test_wpa_capable(struct airo_info *ai)
/* Only firmware versions 5.30.17 or better can do WPA */
if ((cap_rid.softVer > 0x530)
|| ((cap_rid.softVer == 0x530) && (cap_rid.softSubVer >= 17))) {
- airo_print_info(name, "WPA is supported.");
+ airo_print_info("", "WPA is supported.");
return 1;
}

/* No WPA support */
- airo_print_info(name, "WPA unsupported (only firmware versions 5.30.17"
+ airo_print_info("", "WPA unsupported (only firmware versions 5.30.17"
" and greater support WPA. Detected %s)", cap_rid.prodVer);
return 0;
}
@@ -2813,7 +2813,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
ai->jobs = 0;
ai->dev = dev;
if (pci && (pci->device == 0x5000 || pci->device == 0xa504)) {
- airo_print_dbg(dev->name, "Found an MPI350 card");
+ airo_print_dbg("", "Found an MPI350 card");
set_bit(FLAG_MPI, &ai->flags);
}
spin_lock_init(&ai->aux_lock);
@@ -2862,16 +2862,16 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
goto err_out_nets;
}
if (!is_pcmcia) {
- if (!request_region( dev->base_addr, 64, dev->name )) {
+ if (!request_region(dev->base_addr, 64, DRV_NAME)) {
rc = -EBUSY;
- airo_print_err(dev->name, "Couldn't request region");
+ airo_print_err("", "Couldn't request region");
goto err_out_irq;
}
}

if (test_bit(FLAG_MPI,&ai->flags)) {
- if (mpi_map_card(ai, pci, dev->name)) {
- airo_print_err(dev->name, "Could not map memory");
+ if (mpi_map_card(ai, pci)) {
+ airo_print_err("", "Could not map memory");
goto err_out_res;
}
}
@@ -4004,7 +4004,7 @@ static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
}
if ( !(max_tries--) ) {
airo_print_err(ai->dev->name,
- "airo: BAP setup error too many retries\n");
+ "BAP setup error too many retries\n");
return ERROR;
}
// -- PC4500 missed it, try again



2007-06-28 06:16:15

by Michal Schmidt

[permalink] [raw]
Subject: Re: [PATCH 0/4] airo fixes

Dan Williams skrev:
> On Wed, 2007-06-27 at 23:14 +0200, Michal Schmidt wrote:
>> Hello,
>>
>> this is a series of four patches for the airo driver:
>>
>> 1/4: airo: don't use the interface name so much before registration
>> 2/4: airo: delay parts of initialization until the netdev is up
>> 3/4: airo: disable the PCI device when unloading module
>> 4/4: airo: start with radio off
>>
>> The first two fix the race condition Matteo Croce was experiencing.
>> The third one fixes a bug I noticed during testing.
>> The last one saves some power when the card is not used.
>
> These all look good to me, I might be able to find some time to
> runtime-test them too if you want more testing.
>
> Dan

That would be nice. Thank you.
Michal