Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 237034
b: refs/heads/master
c: 9be2325
h: refs/heads/master
v: v3
  • Loading branch information
Jussi Kivilinna authored and John W. Linville committed Feb 4, 2011
1 parent f57d886 commit 9894b3c
Show file tree
Hide file tree
Showing 3 changed files with 171 additions and 32 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 512119b36f7945a650877cbc7e9b5f4cc4d92e4c
refs/heads/master: 9be232563666b7d1bd424780aef7ee2aa261ba04
188 changes: 157 additions & 31 deletions trunk/drivers/net/wireless/zd1211rw/zd_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ static const struct ieee80211_channel zd_channels[] = {
static void housekeeping_init(struct zd_mac *mac);
static void housekeeping_enable(struct zd_mac *mac);
static void housekeeping_disable(struct zd_mac *mac);
static void beacon_init(struct zd_mac *mac);
static void beacon_enable(struct zd_mac *mac);
static void beacon_disable(struct zd_mac *mac);

static int zd_reg2alpha2(u8 regdomain, char *alpha2)
{
Expand Down Expand Up @@ -295,6 +298,8 @@ static int zd_op_start(struct ieee80211_hw *hw)
goto disable_rxtx;

housekeeping_enable(mac);
beacon_enable(mac);
set_bit(ZD_DEVICE_RUNNING, &mac->flags);
return 0;
disable_rxtx:
zd_chip_disable_rxtx(chip);
Expand All @@ -313,12 +318,15 @@ static void zd_op_stop(struct ieee80211_hw *hw)
struct sk_buff *skb;
struct sk_buff_head *ack_wait_queue = &mac->ack_wait_queue;

clear_bit(ZD_DEVICE_RUNNING, &mac->flags);

/* The order here deliberately is a little different from the open()
* method, since we need to make sure there is no opportunity for RX
* frames to be processed by mac80211 after we have stopped it.
*/

zd_chip_disable_rxtx(chip);
beacon_disable(mac);
housekeeping_disable(mac);
flush_workqueue(zd_workqueue);

Expand Down Expand Up @@ -594,64 +602,99 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
static int zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
{
struct zd_mac *mac = zd_hw_mac(hw);
int r;
int r, ret;
u32 tmp, j = 0;
/* 4 more bytes for tail CRC */
u32 full_len = beacon->len + 4;
unsigned long end_jiffies, message_jiffies;

mutex_lock(&mac->chip.mutex);

r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
r = zd_iowrite32_locked(&mac->chip, 0, CR_BCN_FIFO_SEMAPHORE);
if (r < 0)
return r;
r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
goto out;
r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE);
if (r < 0)
return r;
goto release_sema;

end_jiffies = jiffies + HZ / 2; /*~500ms*/
message_jiffies = jiffies + HZ / 10; /*~100ms*/
while (tmp & 0x2) {
r = zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
r = zd_ioread32_locked(&mac->chip, &tmp, CR_BCN_FIFO_SEMAPHORE);
if (r < 0)
return r;
if ((++j % 100) == 0) {
printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n");
if (j >= 500) {
printk(KERN_ERR "Giving up beacon config.\n");
return -ETIMEDOUT;
goto release_sema;
if (time_is_before_eq_jiffies(message_jiffies)) {
message_jiffies = jiffies + HZ / 10;
dev_err(zd_mac_dev(mac),
"CR_BCN_FIFO_SEMAPHORE not ready\n");
if (time_is_before_eq_jiffies(end_jiffies)) {
dev_err(zd_mac_dev(mac),
"Giving up beacon config.\n");
r = -ETIMEDOUT;
goto release_sema;
}
}
msleep(1);
msleep(20);
}

r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1);
r = zd_iowrite32_locked(&mac->chip, full_len - 1, CR_BCN_FIFO);
if (r < 0)
return r;
goto release_sema;
if (zd_chip_is_zd1211b(&mac->chip)) {
r = zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
r = zd_iowrite32_locked(&mac->chip, full_len - 1,
CR_BCN_LENGTH);
if (r < 0)
return r;
goto release_sema;
}

for (j = 0 ; j < beacon->len; j++) {
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO,
*((u8 *)(beacon->data + j)));
r = zd_iowrite32_locked(&mac->chip, *((u8 *)(beacon->data + j)),
CR_BCN_FIFO);
if (r < 0)
return r;
goto release_sema;
}

for (j = 0; j < 4; j++) {
r = zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
r = zd_iowrite32_locked(&mac->chip, 0x0, CR_BCN_FIFO);
if (r < 0)
return r;
goto release_sema;
}

r = zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
if (r < 0)
return r;
release_sema:
/*
* Try very hard to release device beacon semaphore, as otherwise
* device/driver can be left in unusable state.
*/
end_jiffies = jiffies + HZ / 2; /*~500ms*/
ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE);
while (ret < 0) {
if (time_is_before_eq_jiffies(end_jiffies)) {
ret = -ETIMEDOUT;
break;
}

msleep(20);
ret = zd_iowrite32_locked(&mac->chip, 1, CR_BCN_FIFO_SEMAPHORE);
}

if (ret < 0)
dev_err(zd_mac_dev(mac), "Could not release "
"CR_BCN_FIFO_SEMAPHORE!\n");
if (r < 0 || ret < 0) {
if (r >= 0)
r = ret;
goto out;
}

/* 802.11b/g 2.4G CCK 1Mb
* 802.11a, not yet implemented, uses different values (see GPL vendor
* driver)
*/
return zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
(full_len << 19));
r = zd_iowrite32_locked(&mac->chip, 0x00000400 | (full_len << 19),
CR_BCN_PLCP_CFG);
out:
mutex_unlock(&mac->chip.mutex);
return r;
}

static int fill_ctrlset(struct zd_mac *mac,
Expand Down Expand Up @@ -942,6 +985,8 @@ static void zd_beacon_done(struct zd_mac *mac)
{
struct sk_buff *skb, *beacon;

if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags))
return;
if (!mac->vif || mac->vif->type != NL80211_IFTYPE_AP)
return;

Expand All @@ -959,11 +1004,14 @@ static void zd_beacon_done(struct zd_mac *mac)
* Fetch next beacon so that tim_count is updated.
*/
beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (!beacon)
return;
if (beacon) {
zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}

zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
spin_lock_irq(&mac->lock);
mac->beacon.last_update = jiffies;
spin_unlock_irq(&mac->lock);
}

static void zd_process_intr(struct work_struct *work)
Expand Down Expand Up @@ -1082,7 +1130,9 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
struct sk_buff *beacon = ieee80211_beacon_get(hw, vif);

if (beacon) {
zd_chip_disable_hwint(&mac->chip);
zd_mac_config_beacon(hw, beacon);
zd_chip_enable_hwint(&mac->chip);
kfree_skb(beacon);
}
}
Expand All @@ -1096,6 +1146,12 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
interval = bss_conf->beacon_int;
}

spin_lock_irq(&mac->lock);
mac->beacon.period = period;
mac->beacon.interval = interval;
mac->beacon.last_update = jiffies;
spin_unlock_irq(&mac->lock);

zd_set_beacon_interval(&mac->chip, interval, period,
mac->type);
}
Expand Down Expand Up @@ -1188,12 +1244,82 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)

zd_chip_init(&mac->chip, hw, intf);
housekeeping_init(mac);
beacon_init(mac);
INIT_WORK(&mac->process_intr, zd_process_intr);

SET_IEEE80211_DEV(hw, &intf->dev);
return hw;
}

#define BEACON_WATCHDOG_DELAY round_jiffies_relative(HZ)

static void beacon_watchdog_handler(struct work_struct *work)
{
struct zd_mac *mac =
container_of(work, struct zd_mac, beacon.watchdog_work.work);
struct sk_buff *beacon;
unsigned long timeout;
int interval, period;

if (!test_bit(ZD_DEVICE_RUNNING, &mac->flags))
goto rearm;
if (mac->type != NL80211_IFTYPE_AP || !mac->vif)
goto rearm;

spin_lock_irq(&mac->lock);
interval = mac->beacon.interval;
period = mac->beacon.period;
timeout = mac->beacon.last_update + msecs_to_jiffies(interval) + HZ;
spin_unlock_irq(&mac->lock);

if (interval > 0 && time_is_before_jiffies(timeout)) {
dev_dbg_f(zd_mac_dev(mac), "beacon interrupt stalled, "
"restarting. "
"(interval: %d, dtim: %d)\n",
interval, period);

zd_chip_disable_hwint(&mac->chip);

beacon = ieee80211_beacon_get(mac->hw, mac->vif);
if (beacon) {
zd_mac_config_beacon(mac->hw, beacon);
kfree_skb(beacon);
}

zd_set_beacon_interval(&mac->chip, interval, period, mac->type);

zd_chip_enable_hwint(&mac->chip);

spin_lock_irq(&mac->lock);
mac->beacon.last_update = jiffies;
spin_unlock_irq(&mac->lock);
}

rearm:
queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work,
BEACON_WATCHDOG_DELAY);
}

static void beacon_init(struct zd_mac *mac)
{
INIT_DELAYED_WORK(&mac->beacon.watchdog_work, beacon_watchdog_handler);
}

static void beacon_enable(struct zd_mac *mac)
{
dev_dbg_f(zd_mac_dev(mac), "\n");

mac->beacon.last_update = jiffies;
queue_delayed_work(zd_workqueue, &mac->beacon.watchdog_work,
BEACON_WATCHDOG_DELAY);
}

static void beacon_disable(struct zd_mac *mac)
{
dev_dbg_f(zd_mac_dev(mac), "\n");
cancel_delayed_work_sync(&mac->beacon.watchdog_work);
}

#define LINK_LED_WORK_DELAY HZ

static void link_led_handler(struct work_struct *work)
Expand Down
13 changes: 13 additions & 0 deletions trunk/drivers/net/wireless/zd1211rw/zd_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ struct housekeeping {
struct delayed_work link_led_work;
};

struct beacon {
struct delayed_work watchdog_work;
unsigned long last_update;
u16 interval;
u8 period;
};

enum zd_device_flags {
ZD_DEVICE_RUNNING,
};

#define ZD_MAC_STATS_BUFFER_SIZE 16

#define ZD_MAC_MAX_ACK_WAITERS 50
Expand All @@ -174,6 +185,7 @@ struct zd_mac {
struct ieee80211_hw *hw;
struct ieee80211_vif *vif;
struct housekeeping housekeeping;
struct beacon beacon;
struct work_struct set_rts_cts_work;
struct work_struct process_intr;
struct zd_mc_hash multicast_hash;
Expand All @@ -182,6 +194,7 @@ struct zd_mac {
u8 default_regdomain;
int type;
int associated;
unsigned long flags;
struct sk_buff_head ack_wait_queue;
struct ieee80211_channel channels[14];
struct ieee80211_rate rates[12];
Expand Down

0 comments on commit 9894b3c

Please sign in to comment.