2007-10-31 01:44:56

by Luis Carlos Cobo

[permalink] [raw]
Subject: [PATCH 5/7] o80211s: (zd1211rw-mac80211) support for mesh interface


Signed-off-by: Luis Carlos Cobo <[email protected]>
---
drivers/net/wireless/zd1211rw-mac80211/zd_chip.c | 1 +
drivers/net/wireless/zd1211rw-mac80211/zd_chip.h | 8 +++
drivers/net/wireless/zd1211rw-mac80211/zd_mac.c | 72 +++++++++++++++++++++-
drivers/net/wireless/zd1211rw-mac80211/zd_mac.h | 3 +
drivers/net/wireless/zd1211rw-mac80211/zd_usb.c | 11 +++-
5 files changed, 92 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
index a220420..fb6d27b 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
@@ -806,6 +806,7 @@ static int hw_init_hmac(struct zd_chip *chip)
{ CR_AFTER_PNP, 0x1 },
{ CR_WEP_PROTECT, 0x114 },
{ CR_IFS_VALUE, IFS_VALUE_DEFAULT },
+ { CR_CAM_MODE, MODE_AP_WDS},
};

ZD_ASSERT(mutex_is_locked(&chip->mutex));
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
index a88a569..46900be 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
@@ -486,6 +486,7 @@ enum {

#define CR_RX_OFFSET CTL_REG(0x065c)

+#define CR_BCN_LENGTH CTL_REG(0x0664)
#define CR_PHY_DELAY CTL_REG(0x066C)
#define CR_BCN_FIFO CTL_REG(0x0670)
#define CR_SNIFFER_ON CTL_REG(0x0674)
@@ -542,6 +543,8 @@ enum {
#define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \
RX_FILTER_CFEND | RX_FILTER_CFACK)

+#define BCN_MODE_IBSS 0x2000000
+
/* Monitor mode sets filter to 0xfffff */

#define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
@@ -575,6 +578,11 @@ enum {

/* CAM: Continuous Access Mode (power management) */
#define CR_CAM_MODE CTL_REG(0x0700)
+#define MODE_IBSS 0x0
+#define MODE_AP 0x1
+#define MODE_STA 0x2
+#define MODE_AP_WDS 0x3
+
#define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
#define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
#define CR_CAM_ADDRESS CTL_REG(0x070C)
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
index ad6a8d5..b668abd 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
@@ -493,6 +493,45 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
/* FIXME: Management frame? */
}

+void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
+{
+ struct zd_mac *mac = zd_hw_mac(hw);
+ u32 tmp, j = 0;
+ /* 4 more bytes for tail CRC */
+ u32 full_len = beacon->len + 4;
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
+ zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
+ /* 0x2 (BIT_1) in vendor driver, maybe they meant 0x1? */
+ while (tmp & 0x2) {
+ zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
+ if ((++j % 100) == 0)
+ printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n");
+ msleep(1);
+ }
+
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1 );
+ if (zd_chip_is_zd1211b(&mac->chip)) {
+ zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
+ }
+
+ for (j=0 ; j < beacon->len; j++) {
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO,s
+ * ((u8 *)(beacon->data + j)));
+ }
+
+ for (j=0; j< 4; j++) {
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
+ }
+
+ zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
+ /* 802.11b/g 2.4G CCK 1Mb
+ * 802.11a, not yet implemented, uses different values (see GPL vendor
+ * driver)
+ */
+ zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
+ (full_len << 19));
+}
+
static int fill_ctrlset(struct zd_mac *mac,
struct sk_buff *skb,
struct ieee80211_tx_control *control)
@@ -701,6 +740,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,

switch (conf->type) {
case IEEE80211_IF_TYPE_MNTR:
+ case IEEE80211_IF_TYPE_MESH:
case IEEE80211_IF_TYPE_STA:
mac->type = conf->type;
break;
@@ -729,15 +769,44 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, int if_id,
struct ieee80211_if_conf *conf)
{
struct zd_mac *mac = zd_hw_mac(hw);
+ int associated;
+
+ if (mac->type == IEEE80211_IF_TYPE_MESH) {
+ associated = true ;
+ if (hw->flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE) {
+ zd_mac_config_beacon(hw, conf->beacon);
+ kfree_skb(conf->beacon);
+ zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | 100);
+ }
+ }
+ else
+ associated = is_valid_ether_addr(conf->bssid);

spin_lock_irq(&mac->lock);
- mac->associated = is_valid_ether_addr(conf->bssid);
+ mac->associated = associated;
spin_unlock_irq(&mac->lock);

/* TODO: do hardware bssid filtering */
return 0;
}

+void zd_process_intr(struct work_struct *work)
+{
+ u16 int_status;
+ struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
+
+ int_status = le16_to_cpu(*(u16*)(mac->intr_buffer+4));
+ if (int_status & INT_CFG_NEXT_BCN) {
+ dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
+ }
+ else {
+ dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
+ }
+
+ zd_chip_enable_hwint(&mac->chip);
+}
+
+
static void set_multicast_hash_handler(struct work_struct *work)
{
struct zd_mac *mac =
@@ -929,6 +998,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler);
+ INIT_WORK(&mac->process_intr, zd_process_intr);

SET_IEEE80211_DEV(hw, &intf->dev);
return hw;
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
index ed5417c..fbfc2e8 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
@@ -169,12 +169,15 @@ struct zd_tx_skb_control_block {
struct zd_mac {
struct zd_chip chip;
spinlock_t lock;
+ spinlock_t intr_lock;
struct ieee80211_hw *hw;
struct housekeeping housekeeping;
struct work_struct set_multicast_hash_work;
struct work_struct set_rts_cts_work;
struct work_struct set_rx_filter_work;
+ struct work_struct process_intr;
struct zd_mc_hash multicast_hash;
+ u8 intr_buffer[USB_MAX_EP_INT_BUFFER];
u8 regdomain;
u8 default_regdomain;
int type;
diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c b/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c
index 15ea70e..972a370 100644
--- a/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c
@@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
#define FW_ZD1211B_PREFIX "zd1211/zd1211b_"

/* USB device initialization */
+static void int_urb_complete(struct urb *urb);

static int request_fw_file(
const struct firmware **fw, const char *name, struct device *device)
@@ -331,11 +332,18 @@ static inline void handle_regs_int(struct urb *urb)
struct zd_usb *usb = urb->context;
struct zd_usb_interrupt *intr = &usb->intr;
int len;
+ u16 int_num;

ZD_ASSERT(in_interrupt());
spin_lock(&intr->lock);

- if (intr->read_regs_enabled) {
+ int_num = le16_to_cpu(*(u16*)(urb->transfer_buffer+2));
+ if( int_num == CR_INTERRUPT ){
+ struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context));
+ memcpy(&mac->intr_buffer, urb->transfer_buffer,
+ USB_MAX_EP_INT_BUFFER);
+ schedule_work(&mac->process_intr);
+ } else if (intr->read_regs_enabled) {
intr->read_regs.length = len = urb->actual_length;

if (len > sizeof(intr->read_regs.buffer))
@@ -346,7 +354,6 @@ static inline void handle_regs_int(struct urb *urb)
goto out;
}

- dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
out:
spin_unlock(&intr->lock);
}
--
1.5.2.5





2007-10-31 19:06:58

by Luis Carlos Cobo

[permalink] [raw]
Subject: Re: [PATCH 5/7] o80211s: (zd1211rw-mac80211) support for mesh interface

On 10/31/07, Dan Williams <[email protected]> wrote:
> Awesome to see this work. I assume you're developing on zd1211 then?

Yes, we started with this device because it's cheap and easy to find,
so more people can test this and contribute. We intend to support any
softmac device with a driver using mac80211.

> Would similar changes be necessary to support other devices?

Yes, basically support the mesh interface type and make sure mesh (WDS
type) frames are not filtered out and are acknowledged (otherwise you
get tons of duplicates).

Apart from that, this driver did not support beaconing, so we had to
add that too. Fortunately the GPL vendor driver is quite complete so
we could port the features from there.

Thanks for the comments, I will include them as well as Johannes' and
resend the patches.

--
Luis Carlos Cobo Rus GnuPG ID: 44019B60
cozybit Inc.

2007-10-31 12:03:42

by Dan Williams

[permalink] [raw]
Subject: Re: [PATCH 5/7] o80211s: (zd1211rw-mac80211) support for mesh interface

On Mon, 2007-10-29 at 18:15 -0700, Luis Carlos Cobo wrote:
> Signed-off-by: Luis Carlos Cobo <[email protected]>
> ---
> drivers/net/wireless/zd1211rw-mac80211/zd_chip.c | 1 +
> drivers/net/wireless/zd1211rw-mac80211/zd_chip.h | 8 +++
> drivers/net/wireless/zd1211rw-mac80211/zd_mac.c | 72 +++++++++++++++++++++-
> drivers/net/wireless/zd1211rw-mac80211/zd_mac.h | 3 +
> drivers/net/wireless/zd1211rw-mac80211/zd_usb.c | 11 +++-
> 5 files changed, 92 insertions(+), 3 deletions(-)

Hi Luis!

Awesome to see this work. I assume you're developing on zd1211 then?
Would similar changes be necessary to support other devices?

> diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
> index a220420..fb6d27b 100644
> --- a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
> +++ b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.c
> @@ -806,6 +806,7 @@ static int hw_init_hmac(struct zd_chip *chip)
> { CR_AFTER_PNP, 0x1 },
> { CR_WEP_PROTECT, 0x114 },
> { CR_IFS_VALUE, IFS_VALUE_DEFAULT },
> + { CR_CAM_MODE, MODE_AP_WDS},
> };
>
> ZD_ASSERT(mutex_is_locked(&chip->mutex));
> diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
> index a88a569..46900be 100644
> --- a/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
> +++ b/drivers/net/wireless/zd1211rw-mac80211/zd_chip.h
> @@ -486,6 +486,7 @@ enum {
>
> #define CR_RX_OFFSET CTL_REG(0x065c)
>
> +#define CR_BCN_LENGTH CTL_REG(0x0664)
> #define CR_PHY_DELAY CTL_REG(0x066C)
> #define CR_BCN_FIFO CTL_REG(0x0670)
> #define CR_SNIFFER_ON CTL_REG(0x0674)
> @@ -542,6 +543,8 @@ enum {
> #define RX_FILTER_CTRL (RX_FILTER_RTS | RX_FILTER_CTS | \
> RX_FILTER_CFEND | RX_FILTER_CFACK)
>
> +#define BCN_MODE_IBSS 0x2000000
> +
> /* Monitor mode sets filter to 0xfffff */
>
> #define CR_ACK_TIMEOUT_EXT CTL_REG(0x0690)
> @@ -575,6 +578,11 @@ enum {
>
> /* CAM: Continuous Access Mode (power management) */
> #define CR_CAM_MODE CTL_REG(0x0700)
> +#define MODE_IBSS 0x0
> +#define MODE_AP 0x1
> +#define MODE_STA 0x2
> +#define MODE_AP_WDS 0x3
> +
> #define CR_CAM_ROLL_TB_LOW CTL_REG(0x0704)
> #define CR_CAM_ROLL_TB_HIGH CTL_REG(0x0708)
> #define CR_CAM_ADDRESS CTL_REG(0x070C)
> diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
> index ad6a8d5..b668abd 100644
> --- a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
> +++ b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.c
> @@ -493,6 +493,45 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs,
> /* FIXME: Management frame? */
> }
>
> +void zd_mac_config_beacon(struct ieee80211_hw *hw, struct sk_buff *beacon)
> +{
> + struct zd_mac *mac = zd_hw_mac(hw);
> + u32 tmp, j = 0;
> + /* 4 more bytes for tail CRC */
> + u32 full_len = beacon->len + 4;
> + zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 0);
> + zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
> + /* 0x2 (BIT_1) in vendor driver, maybe they meant 0x1? */
> + while (tmp & 0x2) {

There should be a break out here to avoid an infinite loop. Maybe add
'|| (j > 1000)' or something like that.

> + zd_ioread32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, &tmp);
> + if ((++j % 100) == 0)
> + printk(KERN_ERR "CR_BCN_FIFO_SEMAPHORE not ready\n");
> + msleep(1);
> + }
> +
> + zd_iowrite32(&mac->chip, CR_BCN_FIFO, full_len - 1 );
> + if (zd_chip_is_zd1211b(&mac->chip)) {
> + zd_iowrite32(&mac->chip, CR_BCN_LENGTH, full_len - 1);
> + }
> +
> + for (j=0 ; j < beacon->len; j++) {
> + zd_iowrite32(&mac->chip, CR_BCN_FIFO,s
> + * ((u8 *)(beacon->data + j)));
> + }
> +
> + for (j=0; j< 4; j++) {
> + zd_iowrite32(&mac->chip, CR_BCN_FIFO, 0x0);
> + }
> +
> + zd_iowrite32(&mac->chip, CR_BCN_FIFO_SEMAPHORE, 1);
> + /* 802.11b/g 2.4G CCK 1Mb
> + * 802.11a, not yet implemented, uses different values (see GPL vendor
> + * driver)
> + */
> + zd_iowrite32(&mac->chip, CR_BCN_PLCP_CFG, 0x00000400 |
> + (full_len << 19));
> +}
> +
> static int fill_ctrlset(struct zd_mac *mac,
> struct sk_buff *skb,
> struct ieee80211_tx_control *control)
> @@ -701,6 +740,7 @@ static int zd_op_add_interface(struct ieee80211_hw *hw,
>
> switch (conf->type) {
> case IEEE80211_IF_TYPE_MNTR:
> + case IEEE80211_IF_TYPE_MESH:
> case IEEE80211_IF_TYPE_STA:
> mac->type = conf->type;
> break;
> @@ -729,15 +769,44 @@ static int zd_op_config_interface(struct ieee80211_hw *hw, int if_id,
> struct ieee80211_if_conf *conf)
> {
> struct zd_mac *mac = zd_hw_mac(hw);
> + int associated;
> +
> + if (mac->type == IEEE80211_IF_TYPE_MESH) {
> + associated = true ;
> + if (hw->flags & IEEE80211_HW_HOST_GEN_BEACON_TEMPLATE) {
> + zd_mac_config_beacon(hw, conf->beacon);
> + kfree_skb(conf->beacon);
> + zd_set_beacon_interval(&mac->chip, BCN_MODE_IBSS | 100);
> + }
> + }
> + else

The } and else should be on the same line.

> + associated = is_valid_ether_addr(conf->bssid);
>
> spin_lock_irq(&mac->lock);
> - mac->associated = is_valid_ether_addr(conf->bssid);
> + mac->associated = associated;
> spin_unlock_irq(&mac->lock);
>
> /* TODO: do hardware bssid filtering */
> return 0;
> }
>
> +void zd_process_intr(struct work_struct *work)
> +{
> + u16 int_status;
> + struct zd_mac *mac = container_of(work, struct zd_mac, process_intr);
> +
> + int_status = le16_to_cpu(*(u16*)(mac->intr_buffer+4));
> + if (int_status & INT_CFG_NEXT_BCN) {
> + dev_dbg_f(zd_mac_dev(mac), "INT_CFG_NEXT_BCN\n");
> + }
> + else {

Same here.

Cheers,
Dan

> + dev_dbg_f(zd_mac_dev(mac), "Unsupported interrupt\n");
> + }
> +
> + zd_chip_enable_hwint(&mac->chip);
> +}
> +
> +
> static void set_multicast_hash_handler(struct work_struct *work)
> {
> struct zd_mac *mac =
> @@ -929,6 +998,7 @@ struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
> INIT_WORK(&mac->set_multicast_hash_work, set_multicast_hash_handler);
> INIT_WORK(&mac->set_rts_cts_work, set_rts_cts_work);
> INIT_WORK(&mac->set_rx_filter_work, set_rx_filter_handler);
> + INIT_WORK(&mac->process_intr, zd_process_intr);
>
> SET_IEEE80211_DEV(hw, &intf->dev);
> return hw;
> diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
> index ed5417c..fbfc2e8 100644
> --- a/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
> +++ b/drivers/net/wireless/zd1211rw-mac80211/zd_mac.h
> @@ -169,12 +169,15 @@ struct zd_tx_skb_control_block {
> struct zd_mac {
> struct zd_chip chip;
> spinlock_t lock;
> + spinlock_t intr_lock;
> struct ieee80211_hw *hw;
> struct housekeeping housekeeping;
> struct work_struct set_multicast_hash_work;
> struct work_struct set_rts_cts_work;
> struct work_struct set_rx_filter_work;
> + struct work_struct process_intr;
> struct zd_mc_hash multicast_hash;
> + u8 intr_buffer[USB_MAX_EP_INT_BUFFER];
> u8 regdomain;
> u8 default_regdomain;
> int type;
> diff --git a/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c b/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c
> index 15ea70e..972a370 100644
> --- a/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c
> +++ b/drivers/net/wireless/zd1211rw-mac80211/zd_usb.c
> @@ -92,6 +92,7 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
> #define FW_ZD1211B_PREFIX "zd1211/zd1211b_"
>
> /* USB device initialization */
> +static void int_urb_complete(struct urb *urb);
>
> static int request_fw_file(
> const struct firmware **fw, const char *name, struct device *device)
> @@ -331,11 +332,18 @@ static inline void handle_regs_int(struct urb *urb)
> struct zd_usb *usb = urb->context;
> struct zd_usb_interrupt *intr = &usb->intr;
> int len;
> + u16 int_num;
>
> ZD_ASSERT(in_interrupt());
> spin_lock(&intr->lock);
>
> - if (intr->read_regs_enabled) {
> + int_num = le16_to_cpu(*(u16*)(urb->transfer_buffer+2));
> + if( int_num == CR_INTERRUPT ){
> + struct zd_mac *mac = zd_hw_mac(zd_usb_to_hw(urb->context));
> + memcpy(&mac->intr_buffer, urb->transfer_buffer,
> + USB_MAX_EP_INT_BUFFER);
> + schedule_work(&mac->process_intr);
> + } else if (intr->read_regs_enabled) {
> intr->read_regs.length = len = urb->actual_length;
>
> if (len > sizeof(intr->read_regs.buffer))
> @@ -346,7 +354,6 @@ static inline void handle_regs_int(struct urb *urb)
> goto out;
> }
>
> - dev_dbg_f(urb_dev(urb), "regs interrupt ignored\n");
> out:
> spin_unlock(&intr->lock);
> }


2007-10-31 12:15:50

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 5/7] o80211s: (zd1211rw-mac80211) support for mesh interface


[big fat explanation why driver changes are nessary missing]

johannes


Attachments:
signature.asc (828.00 B)
This is a digitally signed message part