Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c809e86c authored by John W. Linville's avatar John W. Linville
Browse files

rtl8180: add software-based support for IBSS mode



Device documentation suggests that hardware support for beaconing
is available.  But I implemented software-based beacon generation
as an experiment and it seems better to have that working now rather
than waiting for something better to materialize.

Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 51e080de
Loading
Loading
Loading
Loading
+8 −0
Original line number Original line Diff line number Diff line
@@ -55,6 +55,14 @@ struct rtl8180_tx_ring {
	struct sk_buff_head queue;
	struct sk_buff_head queue;
};
};


struct rtl8180_vif {
	struct ieee80211_hw *dev;

	/* beaconing */
	struct delayed_work beacon_work;
	bool enable_beacon;
};

struct rtl8180_priv {
struct rtl8180_priv {
	/* common between rtl818x drivers */
	/* common between rtl818x drivers */
	struct rtl818x_csr __iomem *map;
	struct rtl818x_csr __iomem *map;
+72 −10
Original line number Original line Diff line number Diff line
@@ -662,10 +662,59 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
		rtl8180_free_tx_ring(dev, i);
		rtl8180_free_tx_ring(dev, i);
}
}


static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
{
	struct rtl8180_priv *priv = dev->priv;

	return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
	       (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}

void rtl8180_beacon_work(struct work_struct *work)
{
	struct rtl8180_vif *vif_priv =
		container_of(work, struct rtl8180_vif, beacon_work.work);
	struct ieee80211_vif *vif =
		container_of((void *)vif_priv, struct ieee80211_vif, drv_priv);
	struct ieee80211_hw *dev = vif_priv->dev;
	struct ieee80211_mgmt *mgmt;
	struct sk_buff *skb;
	int err = 0;

	/* don't overflow the tx ring */
	if (ieee80211_queue_stopped(dev, 0))
		goto resched;

	/* grab a fresh beacon */
	skb = ieee80211_beacon_get(dev, vif);

	/*
	 * update beacon timestamp w/ TSF value
	 * TODO: make hardware update beacon timestamp
	 */
	mgmt = (struct ieee80211_mgmt *)skb->data;
	mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));

	/* TODO: use actual beacon queue */
	skb_set_queue_mapping(skb, 0);

	err = rtl8180_tx(dev, skb);
	WARN_ON(err);

resched:
	/*
	 * schedule next beacon
	 * TODO: use hardware support for beacon timing
	 */
	schedule_delayed_work(&vif_priv->beacon_work,
			usecs_to_jiffies(1024 * vif->bss_conf.beacon_int));
}

static int rtl8180_add_interface(struct ieee80211_hw *dev,
static int rtl8180_add_interface(struct ieee80211_hw *dev,
				 struct ieee80211_vif *vif)
				 struct ieee80211_vif *vif)
{
{
	struct rtl8180_priv *priv = dev->priv;
	struct rtl8180_priv *priv = dev->priv;
	struct rtl8180_vif *vif_priv;


	/*
	/*
	 * We only support one active interface at a time.
	 * We only support one active interface at a time.
@@ -675,6 +724,7 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,


	switch (vif->type) {
	switch (vif->type) {
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_ADHOC:
		break;
		break;
	default:
	default:
		return -EOPNOTSUPP;
		return -EOPNOTSUPP;
@@ -682,6 +732,12 @@ static int rtl8180_add_interface(struct ieee80211_hw *dev,


	priv->vif = vif;
	priv->vif = vif;


	/* Initialize driver private area */
	vif_priv = (struct rtl8180_vif *)&vif->drv_priv;
	vif_priv->dev = dev;
	INIT_DELAYED_WORK(&vif_priv->beacon_work, rtl8180_beacon_work);
	vif_priv->enable_beacon = false;

	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
	rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG);
	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
	rtl818x_iowrite32(priv, (__le32 __iomem *)&priv->map->MAC[0],
			  le32_to_cpu(*(__le32 *)vif->addr));
			  le32_to_cpu(*(__le32 *)vif->addr));
@@ -715,8 +771,11 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,
				     u32 changed)
				     u32 changed)
{
{
	struct rtl8180_priv *priv = dev->priv;
	struct rtl8180_priv *priv = dev->priv;
	struct rtl8180_vif *vif_priv;
	int i;
	int i;


	vif_priv = (struct rtl8180_vif *)&vif->drv_priv;

	if (changed & BSS_CHANGED_BSSID) {
	if (changed & BSS_CHANGED_BSSID) {
		for (i = 0; i < ETH_ALEN; i++)
		for (i = 0; i < ETH_ALEN; i++)
			rtl818x_iowrite8(priv, &priv->map->BSSID[i],
			rtl818x_iowrite8(priv, &priv->map->BSSID[i],
@@ -732,6 +791,15 @@ static void rtl8180_bss_info_changed(struct ieee80211_hw *dev,


	if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
	if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp)
		priv->rf->conf_erp(dev, info);
		priv->rf->conf_erp(dev, info);

	if (changed & BSS_CHANGED_BEACON_ENABLED)
		vif_priv->enable_beacon = info->enable_beacon;

	if (changed & (BSS_CHANGED_BEACON_ENABLED | BSS_CHANGED_BEACON)) {
		cancel_delayed_work_sync(&vif_priv->beacon_work);
		if (vif_priv->enable_beacon)
			schedule_work(&vif_priv->beacon_work.work);
	}
}
}


static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
static u64 rtl8180_prepare_multicast(struct ieee80211_hw *dev, int mc_count,
@@ -772,14 +840,6 @@ static void rtl8180_configure_filter(struct ieee80211_hw *dev,
	rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
	rtl818x_iowrite32(priv, &priv->map->RX_CONF, priv->rx_conf);
}
}


static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
{
	struct rtl8180_priv *priv = dev->priv;

	return rtl818x_ioread32(priv, &priv->map->TSFT[0]) |
	       (u64)(rtl818x_ioread32(priv, &priv->map->TSFT[1])) << 32;
}

static const struct ieee80211_ops rtl8180_ops = {
static const struct ieee80211_ops rtl8180_ops = {
	.tx			= rtl8180_tx,
	.tx			= rtl8180_tx,
	.start			= rtl8180_start,
	.start			= rtl8180_start,
@@ -916,7 +976,9 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev,
	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
	dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
		     IEEE80211_HW_RX_INCLUDES_FCS |
		     IEEE80211_HW_RX_INCLUDES_FCS |
		     IEEE80211_HW_SIGNAL_UNSPEC;
		     IEEE80211_HW_SIGNAL_UNSPEC;
	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
	dev->vif_data_size = sizeof(struct rtl8180_vif);
	dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
					BIT(NL80211_IFTYPE_ADHOC);
	dev->queues = 1;
	dev->queues = 1;
	dev->max_signal = 65;
	dev->max_signal = 65;