linux_dsm_epyc7002/drivers/net/wireless/ath/wil6210/netdev.c
Vladimir Kondratiev 2be7d22f06 wireless: add new wil6210 802.11ad 60GHz driver
This adds support for the 60 GHz 802.11ad Wilocity card
through a new driver, wil6210. Wilocity implemented the
firmware, QCA maintains the device driver.

Currently supported:

- STA: with security
- AP: limited to 1 connected STA, security disabled
- Monitor: due to a hardware/firmware limitation
  either control or non-control frames are monitored

Using a STA and AP with this drive, one can assemble
a fully functional BSS. Throughput of 1.2Gbps is achieved
with iperf.

The wil6210 cards have on-board flash memory for the
firmware, the cards comes pre-flashed and no firmware
download is required.

For more details see:

http://wireless.kernel.org/en/users/Drivers/wil6210

Signed-off-by: Vladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: Luis R. Rodriguez <mcgrof@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
2013-01-04 16:10:53 -05:00

158 lines
3.5 KiB
C

/*
* Copyright (c) 2012 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/slab.h>
#include "wil6210.h"
static int wil_open(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
return wil_up(wil);
}
static int wil_stop(struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
return wil_down(wil);
}
/*
* AC to queue mapping
*
* AC_VO -> queue 3
* AC_VI -> queue 2
* AC_BE -> queue 1
* AC_BK -> queue 0
*/
static u16 wil_select_queue(struct net_device *ndev, struct sk_buff *skb)
{
static const u16 wil_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
struct wil6210_priv *wil = ndev_to_wil(ndev);
u16 rc;
skb->priority = cfg80211_classify8021d(skb);
rc = wil_1d_to_queue[skb->priority];
wil_dbg_TXRX(wil, "%s() %d -> %d\n", __func__, (int)skb->priority,
(int)rc);
return rc;
}
static const struct net_device_ops wil_netdev_ops = {
.ndo_open = wil_open,
.ndo_stop = wil_stop,
.ndo_start_xmit = wil_start_xmit,
.ndo_select_queue = wil_select_queue,
.ndo_set_mac_address = eth_mac_addr,
.ndo_validate_addr = eth_validate_addr,
};
void *wil_if_alloc(struct device *dev, void __iomem *csr)
{
struct net_device *ndev;
struct wireless_dev *wdev;
struct wil6210_priv *wil;
struct ieee80211_channel *ch;
int rc = 0;
wdev = wil_cfg80211_init(dev);
if (IS_ERR(wdev)) {
dev_err(dev, "wil_cfg80211_init failed\n");
return wdev;
}
wil = wdev_to_wil(wdev);
wil->csr = csr;
wil->wdev = wdev;
rc = wil_priv_init(wil);
if (rc) {
dev_err(dev, "wil_priv_init failed\n");
goto out_wdev;
}
wdev->iftype = NL80211_IFTYPE_STATION; /* TODO */
/* default monitor channel */
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
ndev = alloc_netdev_mqs(0, "wlan%d", ether_setup, WIL6210_TX_QUEUES, 1);
if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n");
rc = -ENOMEM;
goto out_priv;
}
ndev->netdev_ops = &wil_netdev_ops;
ndev->ieee80211_ptr = wdev;
SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy));
wdev->netdev = ndev;
wil_link_off(wil);
return wil;
out_priv:
wil_priv_deinit(wil);
out_wdev:
wil_wdev_free(wil);
return ERR_PTR(rc);
}
void wil_if_free(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
if (!ndev)
return;
free_netdev(ndev);
wil_priv_deinit(wil);
wil_wdev_free(wil);
}
int wil_if_add(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
int rc;
rc = register_netdev(ndev);
if (rc < 0) {
dev_err(&ndev->dev, "Failed to register netdev: %d\n", rc);
return rc;
}
wil_link_off(wil);
return 0;
}
void wil_if_remove(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
unregister_netdev(ndev);
}