2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-25 13:43:55 +08:00

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John W. Linville says:

====================
This is a batch of updates intended for 3.7.  The ath9k, mwifiex,
and b43 drivers get the bulk of the commits this time, with a handful
of other driver bits thrown-in.  It is mostly just minor fixes and
cleanups, etc.

Also included is a Bluetooth pull, with a lot of refactoring.
Gustavo says:

	"These are the changes I queued for 3.7. There are a many
	small fixes/improvements by Andre Guedes. A l2cap channel
	refcounting refactor by Jaganath. Bluetooth sockets now
	appears in /proc/net, by Masatake Yamato and Sachin Kamat
	changes ours drivers to use devm_kzalloc()."
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2012-08-15 15:26:05 -07:00
commit 2ea214929d
95 changed files with 3508 additions and 1125 deletions

View File

@ -101,7 +101,7 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
}
void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
@ -257,7 +257,7 @@ static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m)
}
/* query bus clock frequency for PMU-enabled chipcommon */
u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
static u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;

View File

@ -77,8 +77,8 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
}
#ifdef CONFIG_BCMA_BLOCKIO
void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
size_t count, u16 offset, u8 reg_width)
static void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
size_t count, u16 offset, u8 reg_width)
{
void __iomem *addr = core->bus->mmio + offset;
if (core->bus->mapped_core != core)
@ -100,8 +100,9 @@ void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
}
}
void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
size_t count, u16 offset, u8 reg_width)
static void bcma_host_pci_block_write(struct bcma_device *core,
const void *buffer, size_t count,
u16 offset, u8 reg_width)
{
void __iomem *addr = core->bus->mmio + offset;
if (core->bus->mapped_core != core)
@ -139,7 +140,7 @@ static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
}
const struct bcma_host_ops bcma_host_pci_ops = {
static const struct bcma_host_ops bcma_host_pci_ops = {
.read8 = bcma_host_pci_read8,
.read16 = bcma_host_pci_read16,
.read32 = bcma_host_pci_read32,

View File

@ -143,7 +143,7 @@ static void bcma_host_soc_awrite32(struct bcma_device *core, u16 offset,
writel(value, core->io_wrap + offset);
}
const struct bcma_host_ops bcma_host_soc_ops = {
static const struct bcma_host_ops bcma_host_soc_ops = {
.read8 = bcma_host_soc_read8,
.read16 = bcma_host_soc_read16,
.read32 = bcma_host_soc_read32,

View File

@ -177,7 +177,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate memory for data structure");
return -ENOMEM;
@ -189,14 +189,12 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
data->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!data->urb) {
BT_ERR("Can't allocate URB");
kfree(data);
return -ENOMEM;
}
if (request_firmware(&firmware, "BCM2033-MD.hex", &udev->dev) < 0) {
BT_ERR("Mini driver request failed");
usb_free_urb(data->urb);
kfree(data);
return -EIO;
}
@ -209,7 +207,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
BT_ERR("Can't allocate memory for mini driver");
release_firmware(firmware);
usb_free_urb(data->urb);
kfree(data);
return -ENOMEM;
}
@ -224,7 +221,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
BT_ERR("Firmware request failed");
usb_free_urb(data->urb);
kfree(data->buffer);
kfree(data);
return -EIO;
}
@ -236,7 +232,6 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
release_firmware(firmware);
usb_free_urb(data->urb);
kfree(data->buffer);
kfree(data);
return -ENOMEM;
}
@ -271,7 +266,6 @@ static void bcm203x_disconnect(struct usb_interface *intf)
usb_free_urb(data->urb);
kfree(data->fw_data);
kfree(data->buffer);
kfree(data);
}
static struct usb_driver bcm203x_driver = {

View File

@ -653,7 +653,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
}
/* Initialize control structure and load firmware */
data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
data = devm_kzalloc(&intf->dev, sizeof(struct bfusb_data), GFP_KERNEL);
if (!data) {
BT_ERR("Can't allocate memory for control structure");
goto done;
@ -674,7 +674,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
goto error;
goto done;
}
BT_DBG("firmware data %p size %zu", firmware->data, firmware->size);
@ -690,7 +690,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
hdev = hci_alloc_dev();
if (!hdev) {
BT_ERR("Can't allocate HCI device");
goto error;
goto done;
}
data->hdev = hdev;
@ -708,7 +708,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);
goto error;
goto done;
}
usb_set_intfdata(intf, data);
@ -718,9 +718,6 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
release:
release_firmware(firmware);
error:
kfree(data);
done:
return -EIO;
}
@ -741,7 +738,6 @@ static void bfusb_disconnect(struct usb_interface *intf)
hci_unregister_dev(hdev);
hci_free_dev(hdev);
kfree(data);
}
static struct usb_driver bfusb_driver = {

View File

@ -849,7 +849,7 @@ static int bluecard_probe(struct pcmcia_device *link)
bluecard_info_t *info;
/* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL);
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@ -864,10 +864,7 @@ static int bluecard_probe(struct pcmcia_device *link)
static void bluecard_detach(struct pcmcia_device *link)
{
bluecard_info_t *info = link->priv;
bluecard_release(link);
kfree(info);
}

View File

@ -443,7 +443,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@ -453,10 +453,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
init_usb_anchor(&data->rx_anchor);
hdev = hci_alloc_dev();
if (!hdev) {
kfree(data);
if (!hdev)
return -ENOMEM;
}
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
@ -475,7 +473,6 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
kfree(data);
return err;
}
@ -500,7 +497,6 @@ static void bpa10x_disconnect(struct usb_interface *intf)
hci_free_dev(data->hdev);
kfree_skb(data->rx_skb[0]);
kfree_skb(data->rx_skb[1]);
kfree(data);
}
static struct usb_driver bpa10x_driver = {

View File

@ -638,7 +638,7 @@ static int bt3c_probe(struct pcmcia_device *link)
bt3c_info_t *info;
/* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL);
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@ -654,10 +654,7 @@ static int bt3c_probe(struct pcmcia_device *link)
static void bt3c_detach(struct pcmcia_device *link)
{
bt3c_info_t *info = link->priv;
bt3c_release(link);
kfree(info);
}
static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data)

View File

@ -956,11 +956,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
BT_INFO("vendor=0x%x, device=0x%x, class=%d, fn=%d",
id->vendor, id->device, id->class, func->num);
card = kzalloc(sizeof(*card), GFP_KERNEL);
if (!card) {
ret = -ENOMEM;
goto done;
}
card = devm_kzalloc(&func->dev, sizeof(*card), GFP_KERNEL);
if (!card)
return -ENOMEM;
card->func = func;
@ -974,8 +972,7 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
if (btmrvl_sdio_register_dev(card) < 0) {
BT_ERR("Failed to register BT device!");
ret = -ENODEV;
goto free_card;
return -ENODEV;
}
/* Disable the interrupts on the card */
@ -1023,9 +1020,6 @@ disable_host_int:
btmrvl_sdio_disable_host_int(card);
unreg_dev:
btmrvl_sdio_unregister_dev(card);
free_card:
kfree(card);
done:
return ret;
}
@ -1047,7 +1041,6 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
BT_DBG("unregester dev");
btmrvl_sdio_unregister_dev(card);
btmrvl_remove_card(card->priv);
kfree(card);
}
}
}

View File

@ -304,7 +304,7 @@ static int btsdio_probe(struct sdio_func *func,
tuple = tuple->next;
}
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = devm_kzalloc(&func->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@ -315,10 +315,8 @@ static int btsdio_probe(struct sdio_func *func,
skb_queue_head_init(&data->txq);
hdev = hci_alloc_dev();
if (!hdev) {
kfree(data);
if (!hdev)
return -ENOMEM;
}
hdev->bus = HCI_SDIO;
hci_set_drvdata(hdev, data);
@ -340,7 +338,6 @@ static int btsdio_probe(struct sdio_func *func,
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
kfree(data);
return err;
}
@ -366,7 +363,6 @@ static void btsdio_remove(struct sdio_func *func)
hci_unregister_dev(hdev);
hci_free_dev(hdev);
kfree(data);
}
static struct sdio_driver btsdio_driver = {

View File

@ -567,7 +567,7 @@ static int btuart_probe(struct pcmcia_device *link)
btuart_info_t *info;
/* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL);
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@ -583,10 +583,7 @@ static int btuart_probe(struct pcmcia_device *link)
static void btuart_detach(struct pcmcia_device *link)
{
btuart_info_t *info = link->priv;
btuart_release(link);
kfree(info);
}
static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data)

View File

@ -952,7 +952,7 @@ static int btusb_probe(struct usb_interface *intf,
return -ENODEV;
}
data = kzalloc(sizeof(*data), GFP_KERNEL);
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@ -975,10 +975,8 @@ static int btusb_probe(struct usb_interface *intf,
}
}
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
kfree(data);
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
return -ENODEV;
}
data->cmdreq_type = USB_TYPE_CLASS;
@ -998,10 +996,8 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->deferred);
hdev = hci_alloc_dev();
if (!hdev) {
kfree(data);
if (!hdev)
return -ENOMEM;
}
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
@ -1069,7 +1065,6 @@ static int btusb_probe(struct usb_interface *intf,
data->isoc, data);
if (err < 0) {
hci_free_dev(hdev);
kfree(data);
return err;
}
}
@ -1077,7 +1072,6 @@ static int btusb_probe(struct usb_interface *intf,
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
kfree(data);
return err;
}
@ -1110,7 +1104,6 @@ static void btusb_disconnect(struct usb_interface *intf)
usb_driver_release_interface(&btusb_driver, data->isoc);
hci_free_dev(hdev);
kfree(data);
}
#ifdef CONFIG_PM

View File

@ -297,16 +297,14 @@ static int bt_ti_probe(struct platform_device *pdev)
struct hci_dev *hdev;
int err;
hst = kzalloc(sizeof(struct ti_st), GFP_KERNEL);
hst = devm_kzalloc(&pdev->dev, sizeof(struct ti_st), GFP_KERNEL);
if (!hst)
return -ENOMEM;
/* Expose "hciX" device to user space */
hdev = hci_alloc_dev();
if (!hdev) {
kfree(hst);
if (!hdev)
return -ENOMEM;
}
BT_DBG("hdev %p", hdev);
@ -321,7 +319,6 @@ static int bt_ti_probe(struct platform_device *pdev)
err = hci_register_dev(hdev);
if (err < 0) {
BT_ERR("Can't register HCI device error %d", err);
kfree(hst);
hci_free_dev(hdev);
return err;
}
@ -347,7 +344,6 @@ static int bt_ti_remove(struct platform_device *pdev)
hci_unregister_dev(hdev);
hci_free_dev(hdev);
kfree(hst);
dev_set_drvdata(&pdev->dev, NULL);
return 0;

View File

@ -550,7 +550,7 @@ static int dtl1_probe(struct pcmcia_device *link)
dtl1_info_t *info;
/* Create new info device */
info = kzalloc(sizeof(*info), GFP_KERNEL);
info = devm_kzalloc(&link->dev, sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
@ -569,7 +569,6 @@ static void dtl1_detach(struct pcmcia_device *link)
dtl1_close(info);
pcmcia_disable_device(link);
kfree(info);
}
static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data)

View File

@ -1331,7 +1331,6 @@ struct ath5k_hw {
unsigned int nexttbtt; /* next beacon time in TU */
struct ath5k_txq *cabq; /* content after beacon */
int power_level; /* Requested tx power in dBm */
bool assoc; /* associate state */
bool enable_beacon; /* true if beacons are on */
@ -1425,6 +1424,7 @@ struct ath5k_hw {
/* Value in dB units */
s16 txp_cck_ofdm_pwr_delta;
bool txp_setup;
int txp_requested; /* Requested tx power in dBm */
} ah_txpower;
struct ath5k_nfcal_hist ah_nfcal_hist;

View File

@ -723,7 +723,7 @@ ath5k_txbuf_setup(struct ath5k_hw *ah, struct ath5k_buf *bf,
ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
ieee80211_get_hdrlen_from_skb(skb), padsize,
get_hw_packet_type(skb),
(ah->power_level * 2),
(ah->ah_txpower.txp_requested * 2),
hw_rate,
info->control.rates[0].count, keyidx, ah->ah_tx_ant, flags,
cts_rate, duration);
@ -1778,7 +1778,8 @@ ath5k_beacon_setup(struct ath5k_hw *ah, struct ath5k_buf *bf)
ds->ds_data = bf->skbaddr;
ret = ah->ah_setup_tx_desc(ah, ds, skb->len,
ieee80211_get_hdrlen_from_skb(skb), padsize,
AR5K_PKT_TYPE_BEACON, (ah->power_level * 2),
AR5K_PKT_TYPE_BEACON,
(ah->ah_txpower.txp_requested * 2),
ieee80211_get_tx_rate(ah->hw, info)->hw_value,
1, AR5K_TXKEYIX_INVALID,
antenna, flags, 0, 0);

View File

@ -207,8 +207,8 @@ ath5k_config(struct ieee80211_hw *hw, u32 changed)
}
if ((changed & IEEE80211_CONF_CHANGE_POWER) &&
(ah->power_level != conf->power_level)) {
ah->power_level = conf->power_level;
(ah->ah_txpower.txp_requested != conf->power_level)) {
ah->ah_txpower.txp_requested = conf->power_level;
/* Half dB steps */
ath5k_hw_set_txpower_limit(ah, (conf->power_level * 2));

View File

@ -3516,6 +3516,7 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
{
unsigned int i;
u16 *rates;
s16 rate_idx_scaled = 0;
/* max_pwr is power level we got from driver/user in 0.5dB
* units, switch to 0.25dB units so we can compare */
@ -3562,20 +3563,32 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
for (i = 8; i <= 15; i++)
rates[i] -= ah->ah_txpower.txp_cck_ofdm_gainf_delta;
/* Save min/max and current tx power for this channel
* in 0.25dB units.
*
* Note: We use rates[0] for current tx power because
* it covers most of the rates, in most cases. It's our
* tx power limit and what the user expects to see. */
ah->ah_txpower.txp_min_pwr = 2 * rates[7];
ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
/* Set max txpower for correct OFDM operation on all rates
* -that is the txpower for 54Mbit-, it's used for the PAPD
* gain probe and it's in 0.5dB units */
ah->ah_txpower.txp_ofdm = rates[7];
/* Now that we have all rates setup use table offset to
* match the power range set by user with the power indices
* on PCDAC/PDADC table */
for (i = 0; i < 16; i++) {
rates[i] += ah->ah_txpower.txp_offset;
rate_idx_scaled = rates[i] + ah->ah_txpower.txp_offset;
/* Don't get out of bounds */
if (rates[i] > 63)
rates[i] = 63;
if (rate_idx_scaled > 63)
rate_idx_scaled = 63;
if (rate_idx_scaled < 0)
rate_idx_scaled = 0;
rates[i] = rate_idx_scaled;
}
/* Min/max in 0.25dB units */
ah->ah_txpower.txp_min_pwr = 2 * rates[7];
ah->ah_txpower.txp_cur_pwr = 2 * rates[0];
ah->ah_txpower.txp_ofdm = rates[7];
}
@ -3639,10 +3652,17 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
if (!ah->ah_txpower.txp_setup ||
(channel->hw_value != curr_channel->hw_value) ||
(channel->center_freq != curr_channel->center_freq)) {
/* Reset TX power values */
/* Reset TX power values but preserve requested
* tx power from above */
int requested_txpower = ah->ah_txpower.txp_requested;
memset(&ah->ah_txpower, 0, sizeof(ah->ah_txpower));
/* Restore TPC setting and requested tx power */
ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
ah->ah_txpower.txp_requested = requested_txpower;
/* Calculate the powertable */
ret = ath5k_setup_channel_powertable(ah, channel,
ee_mode, type);
@ -3789,8 +3809,9 @@ ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
* RF buffer settings on 5211/5212+ so that we
* properly set curve indices.
*/
ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_cur_pwr ?
ah->ah_txpower.txp_cur_pwr / 2 : AR5K_TUNE_MAX_TXPOWER);
ret = ath5k_hw_txpower(ah, channel, ah->ah_txpower.txp_requested ?
ah->ah_txpower.txp_requested * 2 :
AR5K_TUNE_MAX_TXPOWER);
if (ret)
return ret;

View File

@ -4901,90 +4901,79 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
i, cfgCtl, pCtlMode[ctlMode], ctlIndex[i],
chan->channel);
/*
* compare test group from regulatory
* channel list with test mode from pCtlMode
* list
*/
if ((((cfgCtl & ~CTL_MODE_M) |
(pCtlMode[ctlMode] & CTL_MODE_M)) ==
ctlIndex[i]) ||
(((cfgCtl & ~CTL_MODE_M) |
(pCtlMode[ctlMode] & CTL_MODE_M)) ==
((ctlIndex[i] & CTL_MODE_M) |
SD_NO_CTL))) {
twiceMinEdgePower =
ar9003_hw_get_max_edge_power(pEepData,
freq, i,
is2ghz);
/*
* compare test group from regulatory
* channel list with test mode from pCtlMode
* list
*/
if ((((cfgCtl & ~CTL_MODE_M) |
(pCtlMode[ctlMode] & CTL_MODE_M)) ==
ctlIndex[i]) ||
(((cfgCtl & ~CTL_MODE_M) |
(pCtlMode[ctlMode] & CTL_MODE_M)) ==
((ctlIndex[i] & CTL_MODE_M) |
SD_NO_CTL))) {
twiceMinEdgePower =
ar9003_hw_get_max_edge_power(pEepData,
freq, i,
is2ghz);
if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
/*
* Find the minimum of all CTL
* edge powers that apply to
* this channel
*/
twiceMaxEdgePower =
min(twiceMaxEdgePower,
twiceMinEdgePower);
else {
/* specific */
twiceMaxEdgePower =
twiceMinEdgePower;
break;
}
if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL)
/*
* Find the minimum of all CTL
* edge powers that apply to
* this channel
*/
twiceMaxEdgePower =
min(twiceMaxEdgePower,
twiceMinEdgePower);
else {
/* specific */
twiceMaxEdgePower = twiceMinEdgePower;
break;
}
}
}
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower);
ath_dbg(common, REGULATORY,
"SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
scaledPower, minCtlPower);
ath_dbg(common, REGULATORY,
"SEL-Min ctlMode %d pCtlMode %d 2xMaxEdge %d sP %d minCtlPwr %d\n",
ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower,
scaledPower, minCtlPower);
/* Apply ctl mode to correct target power set */
switch (pCtlMode[ctlMode]) {
case CTL_11B:
for (i = ALL_TARGET_LEGACY_1L_5L;
i <= ALL_TARGET_LEGACY_11S; i++)
pPwrArray[i] =
(u8)min((u16)pPwrArray[i],
minCtlPower);
break;
case CTL_11A:
case CTL_11G:
for (i = ALL_TARGET_LEGACY_6_24;
i <= ALL_TARGET_LEGACY_54; i++)
pPwrArray[i] =
(u8)min((u16)pPwrArray[i],
minCtlPower);
break;
case CTL_5GHT20:
case CTL_2GHT20:
for (i = ALL_TARGET_HT20_0_8_16;
i <= ALL_TARGET_HT20_21; i++)
pPwrArray[i] =
(u8)min((u16)pPwrArray[i],
minCtlPower);
pPwrArray[ALL_TARGET_HT20_22] =
(u8)min((u16)pPwrArray[ALL_TARGET_HT20_22],
minCtlPower);
pPwrArray[ALL_TARGET_HT20_23] =
(u8)min((u16)pPwrArray[ALL_TARGET_HT20_23],
minCtlPower);
break;
case CTL_5GHT40:
case CTL_2GHT40:
for (i = ALL_TARGET_HT40_0_8_16;
i <= ALL_TARGET_HT40_23; i++)
pPwrArray[i] =
(u8)min((u16)pPwrArray[i],
minCtlPower);
break;
default:
break;
}
/* Apply ctl mode to correct target power set */
switch (pCtlMode[ctlMode]) {
case CTL_11B:
for (i = ALL_TARGET_LEGACY_1L_5L;
i <= ALL_TARGET_LEGACY_11S; i++)
pPwrArray[i] = (u8)min((u16)pPwrArray[i],
minCtlPower);
break;
case CTL_11A:
case CTL_11G:
for (i = ALL_TARGET_LEGACY_6_24;
i <= ALL_TARGET_LEGACY_54; i++)
pPwrArray[i] = (u8)min((u16)pPwrArray[i],
minCtlPower);
break;
case CTL_5GHT20:
case CTL_2GHT20:
for (i = ALL_TARGET_HT20_0_8_16;
i <= ALL_TARGET_HT20_23; i++)
pPwrArray[i] = (u8)min((u16)pPwrArray[i],
minCtlPower);
break;
case CTL_5GHT40:
case CTL_2GHT40:
for (i = ALL_TARGET_HT40_0_8_16;
i <= ALL_TARGET_HT40_23; i++)
pPwrArray[i] = (u8)min((u16)pPwrArray[i],
minCtlPower);
break;
default:
break;
}
} /* end ctl mode checking */
}

File diff suppressed because it is too large Load Diff

View File

@ -160,10 +160,6 @@ struct ath_rate_table {
u32 user_ratekbps;
u8 ratecode;
u8 dot11rate;
u8 ctrl_rate;
u8 cw40index;
u8 sgi_index;
u8 ht_index;
} info[RATE_TABLE_SIZE];
u32 probe_interval;
u8 initial_ratemax;

View File

@ -341,6 +341,7 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
if (SUPP(CARL9170FW_WLANTX_CAB)) {
if_comb_types |=
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_P2P_GO);
}
}

View File

@ -318,10 +318,10 @@ int carl9170_set_operating_mode(struct ar9170 *ar)
bssid = common->curbssid;
switch (vif->type) {
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_ADHOC:
cam_mode |= AR9170_MAC_CAM_IBSS;
break;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
cam_mode |= AR9170_MAC_CAM_AP;

View File

@ -616,10 +616,12 @@ static int carl9170_op_add_interface(struct ieee80211_hw *hw,
goto unlock;
case NL80211_IFTYPE_MESH_POINT:
case NL80211_IFTYPE_AP:
if ((vif->type == NL80211_IFTYPE_STATION) ||
(vif->type == NL80211_IFTYPE_WDS) ||
(vif->type == NL80211_IFTYPE_AP))
(vif->type == NL80211_IFTYPE_AP) ||
(vif->type == NL80211_IFTYPE_MESH_POINT))
break;
err = -EBUSY;

View File

@ -206,6 +206,7 @@ void carl9170_handle_command_response(struct ar9170 *ar, void *buf, u32 len)
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_MESH_POINT:
carl9170_update_beacon(ar, true);
break;

View File

@ -4,6 +4,7 @@ b43-y += tables.o
b43-$(CONFIG_B43_PHY_N) += tables_nphy.o
b43-$(CONFIG_B43_PHY_N) += radio_2055.o
b43-$(CONFIG_B43_PHY_N) += radio_2056.o
b43-$(CONFIG_B43_PHY_N) += radio_2057.o
b43-y += phy_common.o
b43-y += phy_g.o
b43-y += phy_a.o

View File

@ -241,16 +241,18 @@ enum {
#define B43_SHM_SH_PHYVER 0x0050 /* PHY version */
#define B43_SHM_SH_PHYTYPE 0x0052 /* PHY type */
#define B43_SHM_SH_ANTSWAP 0x005C /* Antenna swap threshold */
#define B43_SHM_SH_HOSTFLO 0x005E /* Hostflags for ucode options (low) */
#define B43_SHM_SH_HOSTFMI 0x0060 /* Hostflags for ucode options (middle) */
#define B43_SHM_SH_HOSTFHI 0x0062 /* Hostflags for ucode options (high) */
#define B43_SHM_SH_HOSTF1 0x005E /* Hostflags 1 for ucode options */
#define B43_SHM_SH_HOSTF2 0x0060 /* Hostflags 2 for ucode options */
#define B43_SHM_SH_HOSTF3 0x0062 /* Hostflags 3 for ucode options */
#define B43_SHM_SH_RFATT 0x0064 /* Current radio attenuation value */
#define B43_SHM_SH_RADAR 0x0066 /* Radar register */
#define B43_SHM_SH_PHYTXNOI 0x006E /* PHY noise directly after TX (lower 8bit only) */
#define B43_SHM_SH_RFRXSP1 0x0072 /* RF RX SP Register 1 */
#define B43_SHM_SH_HOSTF4 0x0078 /* Hostflags 4 for ucode options */
#define B43_SHM_SH_CHAN 0x00A0 /* Current channel (low 8bit only) */
#define B43_SHM_SH_CHAN_5GHZ 0x0100 /* Bit set, if 5 Ghz channel */
#define B43_SHM_SH_CHAN_40MHZ 0x0200 /* Bit set, if 40 Mhz channel width */
#define B43_SHM_SH_HOSTF5 0x00D4 /* Hostflags 5 for ucode options */
#define B43_SHM_SH_BCMCFIFOID 0x0108 /* Last posted cookie to the bcast/mcast FIFO */
/* TSSI information */
#define B43_SHM_SH_TSSI_CCK 0x0058 /* TSSI for last 4 CCK frames (32bit) */
@ -415,6 +417,8 @@ enum {
#define B43_PHYTYPE_HT 0x07
#define B43_PHYTYPE_LCN 0x08
#define B43_PHYTYPE_LCNXN 0x09
#define B43_PHYTYPE_LCN40 0x0a
#define B43_PHYTYPE_AC 0x0b
/* PHYRegisters */
#define B43_PHY_ILT_A_CTRL 0x0072

View File

@ -533,11 +533,11 @@ u64 b43_hf_read(struct b43_wldev *dev)
{
u64 ret;
ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI);
ret = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3);
ret <<= 16;
ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI);
ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2);
ret <<= 16;
ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO);
ret |= b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1);
return ret;
}
@ -550,9 +550,9 @@ void b43_hf_write(struct b43_wldev *dev, u64 value)
lo = (value & 0x00000000FFFFULL);
mi = (value & 0x0000FFFF0000ULL) >> 16;
hi = (value & 0xFFFF00000000ULL) >> 32;
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO, lo);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFMI, mi);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFHI, hi);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1, lo);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF2, mi);
b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF3, hi);
}
/* Read the firmware capabilities bitmask (Opensource firmware only) */
@ -4282,6 +4282,35 @@ out:
return err;
}
static char *b43_phy_name(struct b43_wldev *dev, u8 phy_type)
{
switch (phy_type) {
case B43_PHYTYPE_A:
return "A";
case B43_PHYTYPE_B:
return "B";
case B43_PHYTYPE_G:
return "G";
case B43_PHYTYPE_N:
return "N";
case B43_PHYTYPE_LP:
return "LP";
case B43_PHYTYPE_SSLPN:
return "SSLPN";
case B43_PHYTYPE_HT:
return "HT";
case B43_PHYTYPE_LCN:
return "LCN";
case B43_PHYTYPE_LCNXN:
return "LCNXN";
case B43_PHYTYPE_LCN40:
return "LCN40";
case B43_PHYTYPE_AC:
return "AC";
}
return "UNKNOWN";
}
/* Get PHY and RADIO versioning numbers */
static int b43_phy_versioning(struct b43_wldev *dev)
{
@ -4342,13 +4371,13 @@ static int b43_phy_versioning(struct b43_wldev *dev)
unsupported = 1;
}
if (unsupported) {
b43err(dev->wl, "FOUND UNSUPPORTED PHY "
"(Analog %u, Type %u, Revision %u)\n",
analog_type, phy_type, phy_rev);
b43err(dev->wl, "FOUND UNSUPPORTED PHY (Analog %u, Type %d (%s), Revision %u)\n",
analog_type, phy_type, b43_phy_name(dev, phy_type),
phy_rev);
return -EOPNOTSUPP;
}
b43dbg(dev->wl, "Found PHY: Analog %u, Type %u, Revision %u\n",
analog_type, phy_type, phy_rev);
b43info(dev->wl, "Found PHY: Analog %u, Type %d (%s), Revision %u\n",
analog_type, phy_type, b43_phy_name(dev, phy_type), phy_rev);
/* Get RADIO versioning */
if (dev->dev->core_rev >= 24) {

View File

@ -240,6 +240,21 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
(b43_radio_read16(dev, offset) & mask) | set);
}
bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
u16 value, int delay, int timeout)
{
u16 val;
int i;
for (i = 0; i < timeout; i += delay) {
val = b43_radio_read(dev, offset);
if ((val & mask) == value)
return true;
udelay(delay);
}
return false;
}
u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
{
assert_mac_suspended(dev);
@ -428,7 +443,7 @@ int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
average = (a + b + c + d + 2) / 4;
if (is_ofdm) {
/* Adjust for CCK-boost */
if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTFLO)
if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1)
& B43_HF_CCKBOOST)
average = (average >= 13) ? (average - 13) : 0;
}

View File

@ -364,6 +364,12 @@ void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set);
*/
void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set);
/**
* b43_radio_wait_value - Waits for a given value in masked register read
*/
bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
u16 value, int delay, int timeout);
/**
* b43_radio_lock - Lock firmware radio register access
*/

View File

@ -32,6 +32,7 @@
#include "tables_nphy.h"
#include "radio_2055.h"
#include "radio_2056.h"
#include "radio_2057.h"
#include "main.h"
struct nphy_txgains {
@ -126,6 +127,46 @@ ok:
b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverrideRev7 */
static void b43_nphy_rf_control_override_rev7(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off,
u8 override)
{
const struct nphy_rf_control_override_rev7 *e;
u16 en_addrs[3][2] = {
{ 0x0E7, 0x0EC }, { 0x342, 0x343 }, { 0x346, 0x347 }
};
u16 en_addr;
u16 en_mask = field;
u16 val_addr;
u8 i;
/* Remember: we can get NULL! */
e = b43_nphy_get_rf_ctl_over_rev7(dev, field, override);
for (i = 0; i < 2; i++) {
if (override >= ARRAY_SIZE(en_addrs)) {
b43err(dev->wl, "Invalid override value %d\n", override);
return;
}
en_addr = en_addrs[override][i];
val_addr = (i == 0) ? e->val_addr_core0 : e->val_addr_core1;
if (off) {
b43_phy_mask(dev, en_addr, ~en_mask);
if (e) /* Do it safer, better than wl */
b43_phy_mask(dev, val_addr, ~e->val_mask);
} else {
if (!core || (core & (1 << i))) {
b43_phy_set(dev, en_addr, en_mask);
if (e)
b43_phy_maskset(dev, val_addr, ~e->val_mask, (value << e->val_shift));
}
}
}
}
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
u16 value, u8 core, bool off)
@ -458,6 +499,137 @@ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
b43_nphy_stay_in_carrier_search(dev, false);
}
/**************************************************
* Radio 0x2057
**************************************************/
/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rcal */
static u8 b43_radio_2057_rcal(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u16 tmp;
if (phy->radio_rev == 5) {
b43_phy_mask(dev, 0x342, ~0x2);
udelay(10);
b43_radio_set(dev, R2057_IQTEST_SEL_PU, 0x1);
b43_radio_maskset(dev, 0x1ca, ~0x2, 0x1);
}
b43_radio_set(dev, R2057_RCAL_CONFIG, 0x1);
udelay(10);
b43_radio_set(dev, R2057_RCAL_CONFIG, 0x3);
if (!b43_radio_wait_value(dev, R2057_RCCAL_N1_1, 1, 1, 100, 1000000)) {
b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
return 0;
}
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x2);
tmp = b43_radio_read(dev, R2057_RCAL_STATUS) & 0x3E;
b43_radio_mask(dev, R2057_RCAL_CONFIG, ~0x1);
if (phy->radio_rev == 5) {
b43_radio_mask(dev, R2057_IPA2G_CASCONV_CORE0, ~0x1);
b43_radio_mask(dev, 0x1ca, ~0x2);
}
if (phy->radio_rev <= 4 || phy->radio_rev == 6) {
b43_radio_maskset(dev, R2057_TEMPSENSE_CONFIG, ~0x3C, tmp);
b43_radio_maskset(dev, R2057_BANDGAP_RCAL_TRIM, ~0xF0,
tmp << 2);
}
return tmp & 0x3e;
}
/* http://bcm-v4.sipsolutions.net/PHY/radio2057_rccal */
static u16 b43_radio_2057_rccal(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
bool special = (phy->radio_rev == 3 || phy->radio_rev == 4 ||
phy->radio_rev == 6);
u16 tmp;
if (special) {
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x61);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xC0);
} else {
b43_radio_write(dev, 0x1AE, 0x61);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xE1);
}
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
5000000))
b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
if (special) {
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x69);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
} else {
b43_radio_write(dev, 0x1AE, 0x69);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xD5);
}
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
5000000))
b43dbg(dev->wl, "Radio 0x2057 rccal timeout\n");
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
if (special) {
b43_radio_write(dev, R2057_RCCAL_MASTER, 0x73);
b43_radio_write(dev, R2057_RCCAL_X1, 0x28);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0xB0);
} else {
b43_radio_write(dev, 0x1AE, 0x73);
b43_radio_write(dev, R2057_RCCAL_X1, 0x6E);
b43_radio_write(dev, R2057_RCCAL_TRC0, 0x99);
}
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x55);
if (!b43_radio_wait_value(dev, R2057_RCCAL_DONE_OSCCAP, 1, 1, 500,
5000000)) {
b43err(dev->wl, "Radio 0x2057 rcal timeout\n");
return 0;
}
tmp = b43_radio_read(dev, R2057_RCCAL_DONE_OSCCAP);
b43_radio_write(dev, R2057_RCCAL_START_R1_Q1_P1, 0x15);
return tmp;
}
static void b43_radio_2057_init_pre(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_CHIP0PU);
/* Maybe wl meant to reset and set (order?) RFCTL_CMD_OEPORFORCE? */
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_OEPORFORCE);
b43_phy_set(dev, B43_NPHY_RFCTL_CMD, ~B43_NPHY_RFCTL_CMD_OEPORFORCE);
b43_phy_set(dev, B43_NPHY_RFCTL_CMD, B43_NPHY_RFCTL_CMD_CHIP0PU);
}
static void b43_radio_2057_init_post(struct b43_wldev *dev)
{
b43_radio_set(dev, R2057_XTALPUOVR_PINCTRL, 0x1);
b43_radio_set(dev, R2057_RFPLL_MISC_CAL_RESETN, 0x78);
b43_radio_set(dev, R2057_XTAL_CONFIG2, 0x80);
mdelay(2);
b43_radio_mask(dev, R2057_RFPLL_MISC_CAL_RESETN, ~0x78);
b43_radio_mask(dev, R2057_XTAL_CONFIG2, ~0x80);
if (dev->phy.n->init_por) {
b43_radio_2057_rcal(dev);
b43_radio_2057_rccal(dev);
}
b43_radio_mask(dev, R2057_RFPLL_MASTER, ~0x8);
dev->phy.n->init_por = false;
}
/* http://bcm-v4.sipsolutions.net/802.11/Radio/2057/Init */
static void b43_radio_2057_init(struct b43_wldev *dev)
{
b43_radio_2057_init_pre(dev);
r2057_upload_inittabs(dev);
b43_radio_2057_init_post(dev);
}
/**************************************************
* Radio 0x2056
**************************************************/
@ -545,7 +717,9 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
enum ieee80211_band band = b43_current_band(dev->wl);
u16 offset;
u8 i;
u16 bias, cbias, pag_boost, pgag_boost, mixg_boost, padg_boost;
u16 bias, cbias;
u16 pag_boost, padg_boost, pgag_boost, mixg_boost;
u16 paa_boost, pada_boost, pgaa_boost, mixa_boost;
B43_WARN_ON(dev->phy.rev < 3);
@ -630,7 +804,56 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
}
} else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) {
/* TODO */
u16 freq = dev->phy.channel_freq;
if (freq < 5100) {
paa_boost = 0xA;
pada_boost = 0x77;
pgaa_boost = 0xF;
mixa_boost = 0xF;
} else if (freq < 5340) {
paa_boost = 0x8;
pada_boost = 0x77;
pgaa_boost = 0xFB;
mixa_boost = 0xF;
} else if (freq < 5650) {
paa_boost = 0x0;
pada_boost = 0x77;
pgaa_boost = 0xB;
mixa_boost = 0xF;
} else {
paa_boost = 0x0;
pada_boost = 0x77;
if (freq != 5825)
pgaa_boost = -(freq - 18) / 36 + 168;
else
pgaa_boost = 6;
mixa_boost = 0xF;
}
for (i = 0; i < 2; i++) {
offset = i ? B2056_TX1 : B2056_TX0;
b43_radio_write(dev,
offset | B2056_TX_INTPAA_BOOST_TUNE, paa_boost);
b43_radio_write(dev,
offset | B2056_TX_PADA_BOOST_TUNE, pada_boost);
b43_radio_write(dev,
offset | B2056_TX_PGAA_BOOST_TUNE, pgaa_boost);
b43_radio_write(dev,
offset | B2056_TX_MIXA_BOOST_TUNE, mixa_boost);
b43_radio_write(dev,
offset | B2056_TX_TXSPARE1, 0x30);
b43_radio_write(dev,
offset | B2056_TX_PA_SPARE2, 0xee);
b43_radio_write(dev,
offset | B2056_TX_PADA_CASCBIAS, 0x03);
b43_radio_write(dev,
offset | B2056_TX_INTPAA_IAUX_STAT, 0x50);
b43_radio_write(dev,
offset | B2056_TX_INTPAA_IMAIN_STAT, 0x50);
b43_radio_write(dev,
offset | B2056_TX_INTPAA_CASCBIAS, 0x30);
}
}
udelay(50);
@ -643,6 +866,37 @@ static void b43_radio_2056_setup(struct b43_wldev *dev,
udelay(300);
}
static u8 b43_radio_2056_rcal(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u16 mast2, tmp;
if (phy->rev != 3)
return 0;
mast2 = b43_radio_read(dev, B2056_SYN_PLL_MAST2);
b43_radio_write(dev, B2056_SYN_PLL_MAST2, mast2 | 0x7);
udelay(10);
b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x01);
udelay(10);
b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x09);
if (!b43_radio_wait_value(dev, B2056_SYN_RCAL_CODE_OUT, 0x80, 0x80, 100,
1000000)) {
b43err(dev->wl, "Radio recalibration timeout\n");
return 0;
}
b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x01);
tmp = b43_radio_read(dev, B2056_SYN_RCAL_CODE_OUT);
b43_radio_write(dev, B2056_SYN_RCAL_MASTER, 0x00);
b43_radio_write(dev, B2056_SYN_PLL_MAST2, mast2);
return tmp & 0x1f;
}
static void b43_radio_init2056_pre(struct b43_wldev *dev)
{
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
@ -665,10 +919,8 @@ static void b43_radio_init2056_post(struct b43_wldev *dev)
b43_radio_mask(dev, B2056_SYN_COM_RESET, ~0x2);
b43_radio_mask(dev, B2056_SYN_PLL_MAST2, ~0xFC);
b43_radio_mask(dev, B2056_SYN_RCCAL_CTRL0, ~0x1);
/*
if (nphy->init_por)
Call Radio 2056 Recalibrate
*/
if (dev->phy.n->init_por)
b43_radio_2056_rcal(dev);
}
/*
@ -680,6 +932,8 @@ static void b43_radio_init2056(struct b43_wldev *dev)
b43_radio_init2056_pre(dev);
b2056_upload_inittabs(dev, 0, 0);
b43_radio_init2056_post(dev);
dev->phy.n->init_por = false;
}
/**************************************************
@ -753,8 +1007,6 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
struct ssb_sprom *sprom = dev->dev->bus_sprom;
int i;
u16 val;
bool workaround = false;
if (sprom->revision < 4)
@ -777,15 +1029,7 @@ static void b43_radio_init2055_post(struct b43_wldev *dev)
b43_radio_set(dev, B2055_CAL_MISC, 0x1);
msleep(1);
b43_radio_set(dev, B2055_CAL_MISC, 0x40);
for (i = 0; i < 200; i++) {
val = b43_radio_read(dev, B2055_CAL_COUT2);
if (val & 0x80) {
i = 0;
break;
}
udelay(10);
}
if (i)
if (!b43_radio_wait_value(dev, B2055_CAL_COUT2, 0x80, 0x80, 10, 2000))
b43err(dev->wl, "radio post init timeout\n");
b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
b43_switch_channel(dev, dev->phy.channel);
@ -1860,12 +2104,334 @@ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev)
{
if (dev->phy.rev >= 3)
if (dev->phy.rev >= 7)
; /* TODO */
else if (dev->phy.rev >= 3)
b43_nphy_gain_ctl_workarounds_rev3plus(dev);
else
b43_nphy_gain_ctl_workarounds_rev1_2(dev);
}
/* http://bcm-v4.sipsolutions.net/PHY/N/Read_Lpf_Bw_Ctl */
static u16 b43_nphy_read_lpf_ctl(struct b43_wldev *dev, u16 offset)
{
if (!offset)
offset = (dev->phy.is_40mhz) ? 0x159 : 0x154;
return b43_ntab_read(dev, B43_NTAB16(7, offset)) & 0x7;
}
static void b43_nphy_workarounds_rev7plus(struct b43_wldev *dev)
{
struct ssb_sprom *sprom = dev->dev->bus_sprom;
struct b43_phy *phy = &dev->phy;
u8 rx2tx_events_ipa[9] = { 0x0, 0x1, 0x2, 0x8, 0x5, 0x6, 0xF, 0x3,
0x1F };
u8 rx2tx_delays_ipa[9] = { 8, 6, 6, 4, 4, 16, 43, 1, 1 };
u16 ntab7_15e_16e[] = { 0x10f, 0x10f };
u8 ntab7_138_146[] = { 0x11, 0x11 };
u8 ntab7_133[] = { 0x77, 0x11, 0x11 };
u16 lpf_20, lpf_40, lpf_11b;
u16 bcap_val, bcap_val_11b, bcap_val_11n_20, bcap_val_11n_40;
u16 scap_val, scap_val_11b, scap_val_11n_20, scap_val_11n_40;
bool rccal_ovrd = false;
u16 rx2tx_lut_20_11b, rx2tx_lut_20_11n, rx2tx_lut_40_11n;
u16 bias, conv, filt;
u32 tmp32;
u8 core;
if (phy->rev == 7) {
b43_phy_set(dev, B43_NPHY_FINERX2_CGC, 0x10);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0xFF80, 0x0020);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN0, 0x80FF, 0x2700);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN1, 0xFF80, 0x002E);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN1, 0x80FF, 0x3300);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN2, 0xFF80, 0x0037);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN2, 0x80FF, 0x3A00);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN3, 0xFF80, 0x003C);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN3, 0x80FF, 0x3E00);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN4, 0xFF80, 0x003E);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN4, 0x80FF, 0x3F00);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN5, 0xFF80, 0x0040);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN5, 0x80FF, 0x4000);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN6, 0xFF80, 0x0040);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN6, 0x80FF, 0x4000);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0xFF80, 0x0040);
b43_phy_maskset(dev, B43_NPHY_FREQGAIN7, 0x80FF, 0x4000);
}
if (phy->rev <= 8) {
b43_phy_write(dev, 0x23F, 0x1B0);
b43_phy_write(dev, 0x240, 0x1B0);
}
if (phy->rev >= 8)
b43_phy_maskset(dev, B43_NPHY_TXTAILCNT, ~0xFF, 0x72);
b43_ntab_write(dev, B43_NTAB16(8, 0x00), 2);
b43_ntab_write(dev, B43_NTAB16(8, 0x10), 2);
tmp32 = b43_ntab_read(dev, B43_NTAB32(30, 0));
tmp32 &= 0xffffff;
b43_ntab_write(dev, B43_NTAB32(30, 0), tmp32);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x15e), 2, ntab7_15e_16e);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x16e), 2, ntab7_15e_16e);
if (b43_nphy_ipa(dev))
b43_nphy_set_rf_sequence(dev, 0, rx2tx_events_ipa,
rx2tx_delays_ipa, ARRAY_SIZE(rx2tx_events_ipa));
b43_phy_maskset(dev, 0x299, 0x3FFF, 0x4000);
b43_phy_maskset(dev, 0x29D, 0x3FFF, 0x4000);
lpf_20 = b43_nphy_read_lpf_ctl(dev, 0x154);
lpf_40 = b43_nphy_read_lpf_ctl(dev, 0x159);
lpf_11b = b43_nphy_read_lpf_ctl(dev, 0x152);
if (b43_nphy_ipa(dev)) {
if ((phy->radio_rev == 5 && phy->is_40mhz) ||
phy->radio_rev == 7 || phy->radio_rev == 8) {
bcap_val = b43_radio_read(dev, 0x16b);
scap_val = b43_radio_read(dev, 0x16a);
scap_val_11b = scap_val;
bcap_val_11b = bcap_val;
if (phy->radio_rev == 5 && phy->is_40mhz) {
scap_val_11n_20 = scap_val;
bcap_val_11n_20 = bcap_val;
scap_val_11n_40 = bcap_val_11n_40 = 0xc;
rccal_ovrd = true;
} else { /* Rev 7/8 */
lpf_20 = 4;
lpf_11b = 1;
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
scap_val_11n_20 = 0xc;
bcap_val_11n_20 = 0xc;
scap_val_11n_40 = 0xa;
bcap_val_11n_40 = 0xa;
} else {
scap_val_11n_20 = 0x14;
bcap_val_11n_20 = 0x14;
scap_val_11n_40 = 0xf;
bcap_val_11n_40 = 0xf;
}
rccal_ovrd = true;
}
}
} else {
if (phy->radio_rev == 5) {
lpf_20 = 1;
lpf_40 = 3;
bcap_val = b43_radio_read(dev, 0x16b);
scap_val = b43_radio_read(dev, 0x16a);
scap_val_11b = scap_val;
bcap_val_11b = bcap_val;
scap_val_11n_20 = 0x11;
scap_val_11n_40 = 0x11;
bcap_val_11n_20 = 0x13;
bcap_val_11n_40 = 0x13;
rccal_ovrd = true;
}
}
if (rccal_ovrd) {
rx2tx_lut_20_11b = (bcap_val_11b << 8) |
(scap_val_11b << 3) |
lpf_11b;
rx2tx_lut_20_11n = (bcap_val_11n_20 << 8) |
(scap_val_11n_20 << 3) |
lpf_20;
rx2tx_lut_40_11n = (bcap_val_11n_40 << 8) |
(scap_val_11n_40 << 3) |
lpf_40;
for (core = 0; core < 2; core++) {
b43_ntab_write(dev, B43_NTAB16(7, 0x152 + core * 16),
rx2tx_lut_20_11b);
b43_ntab_write(dev, B43_NTAB16(7, 0x153 + core * 16),
rx2tx_lut_20_11n);
b43_ntab_write(dev, B43_NTAB16(7, 0x154 + core * 16),
rx2tx_lut_20_11n);
b43_ntab_write(dev, B43_NTAB16(7, 0x155 + core * 16),
rx2tx_lut_40_11n);
b43_ntab_write(dev, B43_NTAB16(7, 0x156 + core * 16),
rx2tx_lut_40_11n);
b43_ntab_write(dev, B43_NTAB16(7, 0x157 + core * 16),
rx2tx_lut_40_11n);
b43_ntab_write(dev, B43_NTAB16(7, 0x158 + core * 16),
rx2tx_lut_40_11n);
b43_ntab_write(dev, B43_NTAB16(7, 0x159 + core * 16),
rx2tx_lut_40_11n);
}
b43_nphy_rf_control_override_rev7(dev, 16, 1, 3, false, 2);
}
b43_phy_write(dev, 0x32F, 0x3);
if (phy->radio_rev == 4 || phy->radio_rev == 6)
b43_nphy_rf_control_override_rev7(dev, 4, 1, 3, false, 0);
if (phy->radio_rev == 3 || phy->radio_rev == 4 || phy->radio_rev == 6) {
if (sprom->revision &&
sprom->boardflags2_hi & B43_BFH2_IPALVLSHIFT_3P3) {
b43_radio_write(dev, 0x5, 0x05);
b43_radio_write(dev, 0x6, 0x30);
b43_radio_write(dev, 0x7, 0x00);
b43_radio_set(dev, 0x4f, 0x1);
b43_radio_set(dev, 0xd4, 0x1);
bias = 0x1f;
conv = 0x6f;
filt = 0xaa;
} else {
bias = 0x2b;
conv = 0x7f;
filt = 0xee;
}
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
for (core = 0; core < 2; core++) {
if (core == 0) {
b43_radio_write(dev, 0x5F, bias);
b43_radio_write(dev, 0x64, conv);
b43_radio_write(dev, 0x66, filt);
} else {
b43_radio_write(dev, 0xE8, bias);
b43_radio_write(dev, 0xE9, conv);
b43_radio_write(dev, 0xEB, filt);
}
}
}
}
if (b43_nphy_ipa(dev)) {
if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
if (phy->radio_rev == 3 || phy->radio_rev == 4 ||
phy->radio_rev == 6) {
for (core = 0; core < 2; core++) {
if (core == 0)
b43_radio_write(dev, 0x51,
0x7f);
else
b43_radio_write(dev, 0xd6,
0x7f);
}
}
if (phy->radio_rev == 3) {
for (core = 0; core < 2; core++) {
if (core == 0) {
b43_radio_write(dev, 0x64,
0x13);
b43_radio_write(dev, 0x5F,
0x1F);
b43_radio_write(dev, 0x66,
0xEE);
b43_radio_write(dev, 0x59,
0x8A);
b43_radio_write(dev, 0x80,
0x3E);
} else {
b43_radio_write(dev, 0x69,
0x13);
b43_radio_write(dev, 0xE8,
0x1F);
b43_radio_write(dev, 0xEB,
0xEE);
b43_radio_write(dev, 0xDE,
0x8A);
b43_radio_write(dev, 0x105,
0x3E);
}
}
} else if (phy->radio_rev == 7 || phy->radio_rev == 8) {
if (!phy->is_40mhz) {
b43_radio_write(dev, 0x5F, 0x14);
b43_radio_write(dev, 0xE8, 0x12);
} else {
b43_radio_write(dev, 0x5F, 0x16);
b43_radio_write(dev, 0xE8, 0x16);
}
}
} else {
u16 freq = phy->channel_freq;
if ((freq >= 5180 && freq <= 5230) ||
(freq >= 5745 && freq <= 5805)) {
b43_radio_write(dev, 0x7D, 0xFF);
b43_radio_write(dev, 0xFE, 0xFF);
}
}
} else {
if (phy->radio_rev != 5) {
for (core = 0; core < 2; core++) {
if (core == 0) {
b43_radio_write(dev, 0x5c, 0x61);
b43_radio_write(dev, 0x51, 0x70);
} else {
b43_radio_write(dev, 0xe1, 0x61);
b43_radio_write(dev, 0xd6, 0x70);
}
}
}
}
if (phy->radio_rev == 4) {
b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
for (core = 0; core < 2; core++) {
if (core == 0) {
b43_radio_write(dev, 0x1a1, 0x00);
b43_radio_write(dev, 0x1a2, 0x3f);
b43_radio_write(dev, 0x1a6, 0x3f);
} else {
b43_radio_write(dev, 0x1a7, 0x00);
b43_radio_write(dev, 0x1ab, 0x3f);
b43_radio_write(dev, 0x1ac, 0x3f);
}
}
} else {
b43_phy_set(dev, B43_NPHY_AFECTL_C1, 0x4);
b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x4);
b43_phy_set(dev, B43_NPHY_AFECTL_C2, 0x4);
b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4);
b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x1);
b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x1);
b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x1);
b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x1);
b43_ntab_write(dev, B43_NTAB16(8, 0x05), 0x20);
b43_ntab_write(dev, B43_NTAB16(8, 0x15), 0x20);
b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x4);
b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x4);
b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x4);
b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4);
}
b43_phy_write(dev, B43_NPHY_ENDROP_TLEN, 0x2);
b43_ntab_write(dev, B43_NTAB32(16, 0x100), 20);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x138), 2, ntab7_138_146);
b43_ntab_write(dev, B43_NTAB16(7, 0x141), 0x77);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x133), 3, ntab7_133);
b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x146), 2, ntab7_138_146);
b43_ntab_write(dev, B43_NTAB16(7, 0x123), 0x77);
b43_ntab_write(dev, B43_NTAB16(7, 0x12A), 0x77);
if (!phy->is_40mhz) {
b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x18D);
b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x18D);
} else {
b43_ntab_write(dev, B43_NTAB32(16, 0x03), 0x14D);
b43_ntab_write(dev, B43_NTAB32(16, 0x7F), 0x14D);
}
b43_nphy_gain_ctl_workarounds(dev);
/* TODO
b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x08), 4,
aux_adc_vmid_rev7_core0);
b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x18), 4,
aux_adc_vmid_rev7_core1);
b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x0C), 4,
aux_adc_gain_rev7);
b43_ntab_write_bulk(dev, B43_NTAB16(8, 0x1C), 4,
aux_adc_gain_rev7);
*/
}
static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
{
struct b43_phy_n *nphy = dev->phy.n;
@ -1916,7 +2482,7 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
rx2tx_delays[6] = 1;
rx2tx_events[7] = 0x1F;
}
b43_nphy_set_rf_sequence(dev, 1, rx2tx_events, rx2tx_delays,
b43_nphy_set_rf_sequence(dev, 0, rx2tx_events, rx2tx_delays,
ARRAY_SIZE(rx2tx_events));
}
@ -1926,8 +2492,13 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_maskset(dev, 0x294, 0xF0FF, 0x0700);
b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
if (!dev->phy.is_40mhz) {
b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
} else {
b43_ntab_write(dev, B43_NTAB32(16, 3), 0x14D);
b43_ntab_write(dev, B43_NTAB32(16, 127), 0x14D);
}
b43_nphy_gain_ctl_workarounds(dev);
@ -1963,13 +2534,14 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_ntab_write(dev, B43_NTAB32(30, 3), tmp32);
if (dev->phy.rev == 4 &&
b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
b43_radio_write(dev, B2056_TX0 | B2056_TX_GMBB_IDAC,
0x70);
b43_radio_write(dev, B2056_TX1 | B2056_TX_GMBB_IDAC,
0x70);
}
/* Dropped probably-always-true condition */
b43_phy_write(dev, 0x224, 0x03eb);
b43_phy_write(dev, 0x225, 0x03eb);
b43_phy_write(dev, 0x226, 0x0341);
@ -1982,6 +2554,9 @@ static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
b43_phy_write(dev, 0x22d, 0x042b);
b43_phy_write(dev, 0x22e, 0x0381);
b43_phy_write(dev, 0x22f, 0x0381);
if (dev->phy.rev >= 6 && sprom->boardflags2_lo & B43_BFL2_SINGLEANT_CCK)
; /* TODO: 0x0080000000000000 HF */
}
static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
@ -1996,6 +2571,12 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
u8 events2[7] = { 0x0, 0x3, 0x5, 0x4, 0x2, 0x1, 0x8 };
u8 delays2[7] = { 0x8, 0x6, 0x2, 0x4, 0x4, 0x6, 0x1 };
if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD ||
dev->dev->board_type == 0x8B) {
delays1[0] = 0x1;
delays1[5] = 0x14;
}
if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ &&
nphy->band5g_pwrgain) {
b43_radio_mask(dev, B2055_C1_TX_RF_SPARE, ~0x8);
@ -2007,8 +2588,10 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
b43_ntab_write(dev, B43_NTAB16(8, 0x00), 0x000A);
b43_ntab_write(dev, B43_NTAB16(8, 0x10), 0x000A);
b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
if (dev->phy.rev < 3) {
b43_ntab_write(dev, B43_NTAB16(8, 0x02), 0xCDAA);
b43_ntab_write(dev, B43_NTAB16(8, 0x12), 0xCDAA);
}
if (dev->phy.rev < 2) {
b43_ntab_write(dev, B43_NTAB16(8, 0x08), 0x0000);
@ -2024,11 +2607,6 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
if (sprom->boardflags2_lo & B43_BFL2_SKWRKFEM_BRD &&
dev->dev->board_type == 0x8B) {
delays1[0] = 0x1;
delays1[5] = 0x14;
}
b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
@ -2055,11 +2633,13 @@ static void b43_nphy_workarounds_rev1_2(struct b43_wldev *dev)
b43_phy_write(dev, B43_NPHY_PHASETR_B1, 0xCD);
b43_phy_write(dev, B43_NPHY_PHASETR_B2, 0x20);
b43_phy_mask(dev, B43_NPHY_PIL_DW1,
~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
if (dev->phy.rev < 3) {
b43_phy_mask(dev, B43_NPHY_PIL_DW1,
~B43_NPHY_PIL_DW_64QAM & 0xFFFF);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B1, 0xB5);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B2, 0xA4);
b43_phy_write(dev, B43_NPHY_TXF_20CO_S2B3, 0x00);
}
if (dev->phy.rev == 2)
b43_phy_set(dev, B43_NPHY_FINERX2_CGC,
@ -2083,7 +2663,9 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
b43_phy_set(dev, B43_NPHY_IQFLIP,
B43_NPHY_IQFLIP_ADC1 | B43_NPHY_IQFLIP_ADC2);
if (dev->phy.rev >= 3)
if (dev->phy.rev >= 7)
b43_nphy_workarounds_rev7plus(dev);
else if (dev->phy.rev >= 3)
b43_nphy_workarounds_rev3plus(dev);
else
b43_nphy_workarounds_rev1_2(dev);
@ -2542,7 +3124,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
b43_nphy_ipa_internal_tssi_setup(dev);
if (phy->rev >= 7)
; /* TODO: Override Rev7 with 0x2000, 0, 3, 0, 0 as arguments */
b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, false, 0);
else if (phy->rev >= 3)
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, false);
@ -2554,7 +3136,7 @@ static void b43_nphy_tx_power_ctl_idle_tssi(struct b43_wldev *dev)
b43_nphy_rssi_select(dev, 0, 0);
if (phy->rev >= 7)
; /* TODO: Override Rev7 with 0x2000, 0, 3, 1, 0 as arguments */
b43_nphy_rf_control_override_rev7(dev, 0x2000, 0, 3, true, 0);
else if (phy->rev >= 3)
b43_nphy_rf_control_override(dev, 0x2000, 0, 3, true);
@ -4761,6 +5343,7 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
nphy->hang_avoid = (phy->rev == 3 || phy->rev == 4);
nphy->spur_avoid = (phy->rev >= 3) ?
B43_SPUR_AVOID_AUTO : B43_SPUR_AVOID_DISABLE;
nphy->init_por = true;
nphy->gain_boost = true; /* this way we follow wl, assume it is true */
nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
@ -4801,6 +5384,8 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
nphy->ipa2g_on = sprom->fem.ghz2.extpa_gain == 2;
nphy->ipa5g_on = sprom->fem.ghz5.extpa_gain == 2;
}
nphy->init_por = true;
}
static void b43_nphy_op_free(struct b43_wldev *dev)
@ -4887,7 +5472,9 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
if (blocked) {
b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
~B43_NPHY_RFCTL_CMD_CHIP0PU);
if (dev->phy.rev >= 3) {
if (dev->phy.rev >= 7) {
/* TODO */
} else if (dev->phy.rev >= 3) {
b43_radio_mask(dev, 0x09, ~0x2);
b43_radio_write(dev, 0x204D, 0);
@ -4905,7 +5492,10 @@ static void b43_nphy_op_software_rfkill(struct b43_wldev *dev,
b43_radio_write(dev, 0x3064, 0);
}
} else {
if (dev->phy.rev >= 3) {
if (dev->phy.rev >= 7) {
b43_radio_2057_init(dev);
b43_switch_channel(dev, dev->phy.channel);
} else if (dev->phy.rev >= 3) {
b43_radio_init2056(dev);
b43_switch_channel(dev, dev->phy.channel);
} else {

View File

@ -785,6 +785,7 @@ struct b43_phy_n {
u16 papd_epsilon_offset[2];
s32 preamble_override;
u32 bb_mult_save;
bool init_por;
bool gain_boost;
bool elna_gain_config;

View File

@ -0,0 +1,141 @@
/*
Broadcom B43 wireless driver
IEEE 802.11n 2057 radio device data tables
Copyright (c) 2010 Rafał Miłecki <zajec5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING. If not, write to
the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "b43.h"
#include "radio_2057.h"
#include "phy_common.h"
static u16 r2057_rev4_init[42][2] = {
{ 0x0E, 0x20 }, { 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 },
{ 0x35, 0x26 }, { 0x3C, 0xff }, { 0x3D, 0xff }, { 0x3E, 0xff },
{ 0x3F, 0xff }, { 0x62, 0x33 }, { 0x8A, 0xf0 }, { 0x8B, 0x10 },
{ 0x8C, 0xf0 }, { 0x91, 0x3f }, { 0x92, 0x36 }, { 0xA4, 0x8c },
{ 0xA8, 0x55 }, { 0xAF, 0x01 }, { 0x10F, 0xf0 }, { 0x110, 0x10 },
{ 0x111, 0xf0 }, { 0x116, 0x3f }, { 0x117, 0x36 }, { 0x129, 0x8c },
{ 0x12D, 0x55 }, { 0x134, 0x01 }, { 0x15E, 0x00 }, { 0x15F, 0x00 },
{ 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 },
{ 0x169, 0x02 }, { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 },
{ 0x1A4, 0x00 }, { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 },
{ 0x1AB, 0x00 }, { 0x1AC, 0x00 },
};
static u16 r2057_rev5_init[44][2] = {
{ 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
{ 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
{ 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
{ 0x64, 0x0f }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
{ 0xA1, 0x20 }, { 0xD6, 0x70 }, { 0xDE, 0x88 }, { 0xE1, 0x20 },
{ 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0x106, 0x01 }, { 0x116, 0x3f },
{ 0x117, 0x36 }, { 0x126, 0x20 }, { 0x15E, 0x00 }, { 0x15F, 0x00 },
{ 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 },
{ 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 },
{ 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 },
{ 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 }, { 0x1C2, 0x80 },
};
static u16 r2057_rev5a_init[45][2] = {
{ 0x00, 0x15 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x23, 0x6 },
{ 0x31, 0x00 }, { 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 },
{ 0x59, 0x88 }, { 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f },
{ 0x64, 0x0f }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
{ 0xC9, 0x01 }, { 0xD6, 0x70 }, { 0xDE, 0x88 }, { 0xE1, 0x20 },
{ 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0x106, 0x01 }, { 0x116, 0x3f },
{ 0x117, 0x36 }, { 0x126, 0x20 }, { 0x14E, 0x01 }, { 0x15E, 0x00 },
{ 0x15F, 0x00 }, { 0x160, 0x00 }, { 0x161, 0x00 }, { 0x162, 0x00 },
{ 0x163, 0x00 }, { 0x16A, 0x00 }, { 0x16B, 0x00 }, { 0x16C, 0x00 },
{ 0x1A4, 0x00 }, { 0x1A5, 0x00 }, { 0x1A6, 0x00 }, { 0x1AA, 0x00 },
{ 0x1AB, 0x00 }, { 0x1AC, 0x00 }, { 0x1B7, 0x0c }, { 0x1C1, 0x01 },
{ 0x1C2, 0x80 },
};
static u16 r2057_rev7_init[54][2] = {
{ 0x00, 0x00 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
{ 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
{ 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x13 },
{ 0x66, 0xee }, { 0x6E, 0x58 }, { 0x75, 0x13 }, { 0x7B, 0x13 },
{ 0x7C, 0x14 }, { 0x7D, 0xee }, { 0x81, 0x01 }, { 0x91, 0x3f },
{ 0x92, 0x36 }, { 0xA1, 0x20 }, { 0xD6, 0x70 }, { 0xDE, 0x88 },
{ 0xE1, 0x20 }, { 0xE8, 0x0f }, { 0xE9, 0x13 }, { 0xEB, 0xee },
{ 0xF3, 0x58 }, { 0xFA, 0x13 }, { 0x100, 0x13 }, { 0x101, 0x14 },
{ 0x102, 0xee }, { 0x106, 0x01 }, { 0x116, 0x3f }, { 0x117, 0x36 },
{ 0x126, 0x20 }, { 0x15E, 0x00 }, { 0x15F, 0x00 }, { 0x160, 0x00 },
{ 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 }, { 0x16A, 0x00 },
{ 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 }, { 0x1A5, 0x00 },
{ 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
{ 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
};
static u16 r2057_rev8_init[54][2] = {
{ 0x00, 0x08 }, { 0x01, 0x57 }, { 0x02, 0x20 }, { 0x31, 0x00 },
{ 0x32, 0x00 }, { 0x33, 0x00 }, { 0x51, 0x70 }, { 0x59, 0x88 },
{ 0x5C, 0x20 }, { 0x62, 0x33 }, { 0x63, 0x0f }, { 0x64, 0x0f },
{ 0x6E, 0x58 }, { 0x75, 0x13 }, { 0x7B, 0x13 }, { 0x7C, 0x0f },
{ 0x7D, 0xee }, { 0x81, 0x01 }, { 0x91, 0x3f }, { 0x92, 0x36 },
{ 0xA1, 0x20 }, { 0xC9, 0x01 }, { 0xD6, 0x70 }, { 0xDE, 0x88 },
{ 0xE1, 0x20 }, { 0xE8, 0x0f }, { 0xE9, 0x0f }, { 0xF3, 0x58 },
{ 0xFA, 0x13 }, { 0x100, 0x13 }, { 0x101, 0x0f }, { 0x102, 0xee },
{ 0x106, 0x01 }, { 0x116, 0x3f }, { 0x117, 0x36 }, { 0x126, 0x20 },
{ 0x14E, 0x01 }, { 0x15E, 0x00 }, { 0x15F, 0x00 }, { 0x160, 0x00 },
{ 0x161, 0x00 }, { 0x162, 0x00 }, { 0x163, 0x00 }, { 0x16A, 0x00 },
{ 0x16B, 0x00 }, { 0x16C, 0x00 }, { 0x1A4, 0x00 }, { 0x1A5, 0x00 },
{ 0x1A6, 0x00 }, { 0x1AA, 0x00 }, { 0x1AB, 0x00 }, { 0x1AC, 0x00 },
{ 0x1B7, 0x05 }, { 0x1C2, 0xa0 },
};
void r2057_upload_inittabs(struct b43_wldev *dev)
{
struct b43_phy *phy = &dev->phy;
u16 *table = NULL;
u16 size, i;
if (phy->rev == 7) {
table = r2057_rev4_init[0];
size = ARRAY_SIZE(r2057_rev4_init);
} else if (phy->rev == 8 || phy->rev == 9) {
if (phy->radio_rev == 5) {
if (phy->radio_rev == 8) {
table = r2057_rev5_init[0];
size = ARRAY_SIZE(r2057_rev5_init);
} else {
table = r2057_rev5a_init[0];
size = ARRAY_SIZE(r2057_rev5a_init);
}
} else if (phy->radio_rev == 7) {
table = r2057_rev7_init[0];
size = ARRAY_SIZE(r2057_rev7_init);
} else if (phy->radio_rev == 9) {
table = r2057_rev8_init[0];
size = ARRAY_SIZE(r2057_rev8_init);
}
}
if (table) {
for (i = 0; i < 10; i++) {
pr_info("radio_write 0x%X ", *table);
table++;
pr_info("0x%X\n", *table);
table++;
}
}
}

View File

@ -0,0 +1,430 @@
#ifndef B43_RADIO_2057_H_
#define B43_RADIO_2057_H_
#include <linux/types.h>
#include "tables_nphy.h"
#define R2057_DACBUF_VINCM_CORE0 0x000
#define R2057_IDCODE 0x001
#define R2057_RCCAL_MASTER 0x002
#define R2057_RCCAL_CAP_SIZE 0x003
#define R2057_RCAL_CONFIG 0x004
#define R2057_GPAIO_CONFIG 0x005
#define R2057_GPAIO_SEL1 0x006
#define R2057_GPAIO_SEL0 0x007
#define R2057_CLPO_CONFIG 0x008
#define R2057_BANDGAP_CONFIG 0x009
#define R2057_BANDGAP_RCAL_TRIM 0x00a
#define R2057_AFEREG_CONFIG 0x00b
#define R2057_TEMPSENSE_CONFIG 0x00c
#define R2057_XTAL_CONFIG1 0x00d
#define R2057_XTAL_ICORE_SIZE 0x00e
#define R2057_XTAL_BUF_SIZE 0x00f
#define R2057_XTAL_PULLCAP_SIZE 0x010
#define R2057_RFPLL_MASTER 0x011
#define R2057_VCOMONITOR_VTH_L 0x012
#define R2057_VCOMONITOR_VTH_H 0x013
#define R2057_VCOCAL_BIASRESET_RFPLLREG_VOUT 0x014
#define R2057_VCO_VARCSIZE_IDAC 0x015
#define R2057_VCOCAL_COUNTVAL0 0x016
#define R2057_VCOCAL_COUNTVAL1 0x017
#define R2057_VCOCAL_INTCLK_COUNT 0x018
#define R2057_VCOCAL_MASTER 0x019
#define R2057_VCOCAL_NUMCAPCHANGE 0x01a
#define R2057_VCOCAL_WINSIZE 0x01b
#define R2057_VCOCAL_DELAY_AFTER_REFRESH 0x01c
#define R2057_VCOCAL_DELAY_AFTER_CLOSELOOP 0x01d
#define R2057_VCOCAL_DELAY_AFTER_OPENLOOP 0x01e
#define R2057_VCOCAL_DELAY_BEFORE_OPENLOOP 0x01f
#define R2057_VCO_FORCECAPEN_FORCECAP1 0x020
#define R2057_VCO_FORCECAP0 0x021
#define R2057_RFPLL_REFMASTER_SPAREXTALSIZE 0x022
#define R2057_RFPLL_PFD_RESET_PW 0x023
#define R2057_RFPLL_LOOPFILTER_R2 0x024
#define R2057_RFPLL_LOOPFILTER_R1 0x025
#define R2057_RFPLL_LOOPFILTER_C3 0x026
#define R2057_RFPLL_LOOPFILTER_C2 0x027
#define R2057_RFPLL_LOOPFILTER_C1 0x028
#define R2057_CP_KPD_IDAC 0x029
#define R2057_RFPLL_IDACS 0x02a
#define R2057_RFPLL_MISC_EN 0x02b
#define R2057_RFPLL_MMD0 0x02c
#define R2057_RFPLL_MMD1 0x02d
#define R2057_RFPLL_MISC_CAL_RESETN 0x02e
#define R2057_JTAGXTAL_SIZE_CPBIAS_FILTRES 0x02f
#define R2057_VCO_ALCREF_BBPLLXTAL_SIZE 0x030
#define R2057_VCOCAL_READCAP0 0x031
#define R2057_VCOCAL_READCAP1 0x032
#define R2057_VCOCAL_STATUS 0x033
#define R2057_LOGEN_PUS 0x034
#define R2057_LOGEN_PTAT_RESETS 0x035
#define R2057_VCOBUF_IDACS 0x036
#define R2057_VCOBUF_TUNE 0x037
#define R2057_CMOSBUF_TX2GQ_IDACS 0x038
#define R2057_CMOSBUF_TX2GI_IDACS 0x039
#define R2057_CMOSBUF_TX5GQ_IDACS 0x03a
#define R2057_CMOSBUF_TX5GI_IDACS 0x03b
#define R2057_CMOSBUF_RX2GQ_IDACS 0x03c
#define R2057_CMOSBUF_RX2GI_IDACS 0x03d
#define R2057_CMOSBUF_RX5GQ_IDACS 0x03e
#define R2057_CMOSBUF_RX5GI_IDACS 0x03f
#define R2057_LOGEN_MX2G_IDACS 0x040
#define R2057_LOGEN_MX2G_TUNE 0x041
#define R2057_LOGEN_MX5G_IDACS 0x042
#define R2057_LOGEN_MX5G_TUNE 0x043
#define R2057_LOGEN_MX5G_RCCR 0x044
#define R2057_LOGEN_INDBUF2G_IDAC 0x045
#define R2057_LOGEN_INDBUF2G_IBOOST 0x046
#define R2057_LOGEN_INDBUF2G_TUNE 0x047
#define R2057_LOGEN_INDBUF5G_IDAC 0x048
#define R2057_LOGEN_INDBUF5G_IBOOST 0x049
#define R2057_LOGEN_INDBUF5G_TUNE 0x04a
#define R2057_CMOSBUF_TX_RCCR 0x04b
#define R2057_CMOSBUF_RX_RCCR 0x04c
#define R2057_LOGEN_SEL_PKDET 0x04d
#define R2057_CMOSBUF_SHAREIQ_PTAT 0x04e
#define R2057_RXTXBIAS_CONFIG_CORE0 0x04f
#define R2057_TXGM_TXRF_PUS_CORE0 0x050
#define R2057_TXGM_IDAC_BLEED_CORE0 0x051
#define R2057_TXGM_GAIN_CORE0 0x056
#define R2057_TXGM2G_PKDET_PUS_CORE0 0x057
#define R2057_PAD2G_PTATS_CORE0 0x058
#define R2057_PAD2G_IDACS_CORE0 0x059
#define R2057_PAD2G_BOOST_PU_CORE0 0x05a
#define R2057_PAD2G_CASCV_GAIN_CORE0 0x05b
#define R2057_TXMIX2G_TUNE_BOOST_PU_CORE0 0x05c
#define R2057_TXMIX2G_LODC_CORE0 0x05d
#define R2057_PAD2G_TUNE_PUS_CORE0 0x05e
#define R2057_IPA2G_GAIN_CORE0 0x05f
#define R2057_TSSI2G_SPARE1_CORE0 0x060
#define R2057_TSSI2G_SPARE2_CORE0 0x061
#define R2057_IPA2G_TUNEV_CASCV_PTAT_CORE0 0x062
#define R2057_IPA2G_IMAIN_CORE0 0x063
#define R2057_IPA2G_CASCONV_CORE0 0x064
#define R2057_IPA2G_CASCOFFV_CORE0 0x065
#define R2057_IPA2G_BIAS_FILTER_CORE0 0x066
#define R2057_TX5G_PKDET_CORE0 0x069
#define R2057_PGA_PTAT_TXGM5G_PU_CORE0 0x06a
#define R2057_PAD5G_PTATS1_CORE0 0x06b
#define R2057_PAD5G_CLASS_PTATS2_CORE0 0x06c
#define R2057_PGA_BOOSTPTAT_IMAIN_CORE0 0x06d
#define R2057_PAD5G_CASCV_IMAIN_CORE0 0x06e
#define R2057_TXMIX5G_IBOOST_PAD_IAUX_CORE0 0x06f
#define R2057_PGA_BOOST_TUNE_CORE0 0x070
#define R2057_PGA_GAIN_CORE0 0x071
#define R2057_PAD5G_CASCOFFV_GAIN_PUS_CORE0 0x072
#define R2057_TXMIX5G_BOOST_TUNE_CORE0 0x073
#define R2057_PAD5G_TUNE_MISC_PUS_CORE0 0x074
#define R2057_IPA5G_IAUX_CORE0 0x075
#define R2057_IPA5G_GAIN_CORE0 0x076
#define R2057_TSSI5G_SPARE1_CORE0 0x077
#define R2057_TSSI5G_SPARE2_CORE0 0x078
#define R2057_IPA5G_CASCOFFV_PU_CORE0 0x079
#define R2057_IPA5G_PTAT_CORE0 0x07a
#define R2057_IPA5G_IMAIN_CORE0 0x07b
#define R2057_IPA5G_CASCONV_CORE0 0x07c
#define R2057_IPA5G_BIAS_FILTER_CORE0 0x07d
#define R2057_PAD_BIAS_FILTER_BWS_CORE0 0x080
#define R2057_TR2G_CONFIG1_CORE0_NU 0x081
#define R2057_TR2G_CONFIG2_CORE0_NU 0x082
#define R2057_LNA5G_RFEN_CORE0 0x083
#define R2057_TR5G_CONFIG2_CORE0_NU 0x084
#define R2057_RXRFBIAS_IBOOST_PU_CORE0 0x085
#define R2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE0 0x086
#define R2057_RXGM_CMFBITAIL_AUXPTAT_CORE0 0x087
#define R2057_RXMIX_ICORE_RXGM_IAUX_CORE0 0x088
#define R2057_RXMIX_CMFBITAIL_PU_CORE0 0x089
#define R2057_LNA2_IMAIN_PTAT_PU_CORE0 0x08a
#define R2057_LNA2_IAUX_PTAT_CORE0 0x08b
#define R2057_LNA1_IMAIN_PTAT_PU_CORE0 0x08c
#define R2057_LNA15G_INPUT_MATCH_TUNE_CORE0 0x08d
#define R2057_RXRFBIAS_BANDSEL_CORE0 0x08e
#define R2057_TIA_CONFIG_CORE0 0x08f
#define R2057_TIA_IQGAIN_CORE0 0x090
#define R2057_TIA_IBIAS2_CORE0 0x091
#define R2057_TIA_IBIAS1_CORE0 0x092
#define R2057_TIA_SPARE_Q_CORE0 0x093
#define R2057_TIA_SPARE_I_CORE0 0x094
#define R2057_RXMIX2G_PUS_CORE0 0x095
#define R2057_RXMIX2G_VCMREFS_CORE0 0x096
#define R2057_RXMIX2G_LODC_QI_CORE0 0x097
#define R2057_W12G_BW_LNA2G_PUS_CORE0 0x098
#define R2057_LNA2G_GAIN_CORE0 0x099
#define R2057_LNA2G_TUNE_CORE0 0x09a
#define R2057_RXMIX5G_PUS_CORE0 0x09b
#define R2057_RXMIX5G_VCMREFS_CORE0 0x09c
#define R2057_RXMIX5G_LODC_QI_CORE0 0x09d
#define R2057_W15G_BW_LNA5G_PUS_CORE0 0x09e
#define R2057_LNA5G_GAIN_CORE0 0x09f
#define R2057_LNA5G_TUNE_CORE0 0x0a0
#define R2057_LPFSEL_TXRX_RXBB_PUS_CORE0 0x0a1
#define R2057_RXBB_BIAS_MASTER_CORE0 0x0a2
#define R2057_RXBB_VGABUF_IDACS_CORE0 0x0a3
#define R2057_LPF_VCMREF_TXBUF_VCMREF_CORE0 0x0a4
#define R2057_TXBUF_VINCM_CORE0 0x0a5
#define R2057_TXBUF_IDACS_CORE0 0x0a6
#define R2057_LPF_RESP_RXBUF_BW_CORE0 0x0a7
#define R2057_RXBB_CC_CORE0 0x0a8
#define R2057_RXBB_SPARE3_CORE0 0x0a9
#define R2057_RXBB_RCCAL_HPC_CORE0 0x0aa
#define R2057_LPF_IDACS_CORE0 0x0ab
#define R2057_LPFBYP_DCLOOP_BYP_IDAC_CORE0 0x0ac
#define R2057_TXBUF_GAIN_CORE0 0x0ad
#define R2057_AFELOOPBACK_AACI_RESP_CORE0 0x0ae
#define R2057_RXBUF_DEGEN_CORE0 0x0af
#define R2057_RXBB_SPARE2_CORE0 0x0b0
#define R2057_RXBB_SPARE1_CORE0 0x0b1
#define R2057_RSSI_MASTER_CORE0 0x0b2
#define R2057_W2_MASTER_CORE0 0x0b3
#define R2057_NB_MASTER_CORE0 0x0b4
#define R2057_W2_IDACS0_Q_CORE0 0x0b5
#define R2057_W2_IDACS1_Q_CORE0 0x0b6
#define R2057_W2_IDACS0_I_CORE0 0x0b7
#define R2057_W2_IDACS1_I_CORE0 0x0b8
#define R2057_RSSI_GPAIOSEL_W1_IDACS_CORE0 0x0b9
#define R2057_NB_IDACS_Q_CORE0 0x0ba
#define R2057_NB_IDACS_I_CORE0 0x0bb
#define R2057_BACKUP4_CORE0 0x0c1
#define R2057_BACKUP3_CORE0 0x0c2
#define R2057_BACKUP2_CORE0 0x0c3
#define R2057_BACKUP1_CORE0 0x0c4
#define R2057_SPARE16_CORE0 0x0c5
#define R2057_SPARE15_CORE0 0x0c6
#define R2057_SPARE14_CORE0 0x0c7
#define R2057_SPARE13_CORE0 0x0c8
#define R2057_SPARE12_CORE0 0x0c9
#define R2057_SPARE11_CORE0 0x0ca
#define R2057_TX2G_BIAS_RESETS_CORE0 0x0cb
#define R2057_TX5G_BIAS_RESETS_CORE0 0x0cc
#define R2057_IQTEST_SEL_PU 0x0cd
#define R2057_XTAL_CONFIG2 0x0ce
#define R2057_BUFS_MISC_LPFBW_CORE0 0x0cf
#define R2057_TXLPF_RCCAL_CORE0 0x0d0
#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE0 0x0d1
#define R2057_LPF_GAIN_CORE0 0x0d2
#define R2057_DACBUF_IDACS_BW_CORE0 0x0d3
#define R2057_RXTXBIAS_CONFIG_CORE1 0x0d4
#define R2057_TXGM_TXRF_PUS_CORE1 0x0d5
#define R2057_TXGM_IDAC_BLEED_CORE1 0x0d6
#define R2057_TXGM_GAIN_CORE1 0x0db
#define R2057_TXGM2G_PKDET_PUS_CORE1 0x0dc
#define R2057_PAD2G_PTATS_CORE1 0x0dd
#define R2057_PAD2G_IDACS_CORE1 0x0de
#define R2057_PAD2G_BOOST_PU_CORE1 0x0df
#define R2057_PAD2G_CASCV_GAIN_CORE1 0x0e0
#define R2057_TXMIX2G_TUNE_BOOST_PU_CORE1 0x0e1
#define R2057_TXMIX2G_LODC_CORE1 0x0e2
#define R2057_PAD2G_TUNE_PUS_CORE1 0x0e3
#define R2057_IPA2G_GAIN_CORE1 0x0e4
#define R2057_TSSI2G_SPARE1_CORE1 0x0e5
#define R2057_TSSI2G_SPARE2_CORE1 0x0e6
#define R2057_IPA2G_TUNEV_CASCV_PTAT_CORE1 0x0e7
#define R2057_IPA2G_IMAIN_CORE1 0x0e8
#define R2057_IPA2G_CASCONV_CORE1 0x0e9
#define R2057_IPA2G_CASCOFFV_CORE1 0x0ea
#define R2057_IPA2G_BIAS_FILTER_CORE1 0x0eb
#define R2057_TX5G_PKDET_CORE1 0x0ee
#define R2057_PGA_PTAT_TXGM5G_PU_CORE1 0x0ef
#define R2057_PAD5G_PTATS1_CORE1 0x0f0
#define R2057_PAD5G_CLASS_PTATS2_CORE1 0x0f1
#define R2057_PGA_BOOSTPTAT_IMAIN_CORE1 0x0f2
#define R2057_PAD5G_CASCV_IMAIN_CORE1 0x0f3
#define R2057_TXMIX5G_IBOOST_PAD_IAUX_CORE1 0x0f4
#define R2057_PGA_BOOST_TUNE_CORE1 0x0f5
#define R2057_PGA_GAIN_CORE1 0x0f6
#define R2057_PAD5G_CASCOFFV_GAIN_PUS_CORE1 0x0f7
#define R2057_TXMIX5G_BOOST_TUNE_CORE1 0x0f8
#define R2057_PAD5G_TUNE_MISC_PUS_CORE1 0x0f9
#define R2057_IPA5G_IAUX_CORE1 0x0fa
#define R2057_IPA5G_GAIN_CORE1 0x0fb
#define R2057_TSSI5G_SPARE1_CORE1 0x0fc
#define R2057_TSSI5G_SPARE2_CORE1 0x0fd
#define R2057_IPA5G_CASCOFFV_PU_CORE1 0x0fe
#define R2057_IPA5G_PTAT_CORE1 0x0ff
#define R2057_IPA5G_IMAIN_CORE1 0x100
#define R2057_IPA5G_CASCONV_CORE1 0x101
#define R2057_IPA5G_BIAS_FILTER_CORE1 0x102
#define R2057_PAD_BIAS_FILTER_BWS_CORE1 0x105
#define R2057_TR2G_CONFIG1_CORE1_NU 0x106
#define R2057_TR2G_CONFIG2_CORE1_NU 0x107
#define R2057_LNA5G_RFEN_CORE1 0x108
#define R2057_TR5G_CONFIG2_CORE1_NU 0x109
#define R2057_RXRFBIAS_IBOOST_PU_CORE1 0x10a
#define R2057_RXRF_IABAND_RXGM_IMAIN_PTAT_CORE1 0x10b
#define R2057_RXGM_CMFBITAIL_AUXPTAT_CORE1 0x10c
#define R2057_RXMIX_ICORE_RXGM_IAUX_CORE1 0x10d
#define R2057_RXMIX_CMFBITAIL_PU_CORE1 0x10e
#define R2057_LNA2_IMAIN_PTAT_PU_CORE1 0x10f
#define R2057_LNA2_IAUX_PTAT_CORE1 0x110
#define R2057_LNA1_IMAIN_PTAT_PU_CORE1 0x111
#define R2057_LNA15G_INPUT_MATCH_TUNE_CORE1 0x112
#define R2057_RXRFBIAS_BANDSEL_CORE1 0x113
#define R2057_TIA_CONFIG_CORE1 0x114
#define R2057_TIA_IQGAIN_CORE1 0x115
#define R2057_TIA_IBIAS2_CORE1 0x116
#define R2057_TIA_IBIAS1_CORE1 0x117
#define R2057_TIA_SPARE_Q_CORE1 0x118
#define R2057_TIA_SPARE_I_CORE1 0x119
#define R2057_RXMIX2G_PUS_CORE1 0x11a
#define R2057_RXMIX2G_VCMREFS_CORE1 0x11b
#define R2057_RXMIX2G_LODC_QI_CORE1 0x11c
#define R2057_W12G_BW_LNA2G_PUS_CORE1 0x11d
#define R2057_LNA2G_GAIN_CORE1 0x11e
#define R2057_LNA2G_TUNE_CORE1 0x11f
#define R2057_RXMIX5G_PUS_CORE1 0x120
#define R2057_RXMIX5G_VCMREFS_CORE1 0x121
#define R2057_RXMIX5G_LODC_QI_CORE1 0x122
#define R2057_W15G_BW_LNA5G_PUS_CORE1 0x123
#define R2057_LNA5G_GAIN_CORE1 0x124
#define R2057_LNA5G_TUNE_CORE1 0x125
#define R2057_LPFSEL_TXRX_RXBB_PUS_CORE1 0x126
#define R2057_RXBB_BIAS_MASTER_CORE1 0x127
#define R2057_RXBB_VGABUF_IDACS_CORE1 0x128
#define R2057_LPF_VCMREF_TXBUF_VCMREF_CORE1 0x129
#define R2057_TXBUF_VINCM_CORE1 0x12a
#define R2057_TXBUF_IDACS_CORE1 0x12b
#define R2057_LPF_RESP_RXBUF_BW_CORE1 0x12c
#define R2057_RXBB_CC_CORE1 0x12d
#define R2057_RXBB_SPARE3_CORE1 0x12e
#define R2057_RXBB_RCCAL_HPC_CORE1 0x12f
#define R2057_LPF_IDACS_CORE1 0x130
#define R2057_LPFBYP_DCLOOP_BYP_IDAC_CORE1 0x131
#define R2057_TXBUF_GAIN_CORE1 0x132
#define R2057_AFELOOPBACK_AACI_RESP_CORE1 0x133
#define R2057_RXBUF_DEGEN_CORE1 0x134
#define R2057_RXBB_SPARE2_CORE1 0x135
#define R2057_RXBB_SPARE1_CORE1 0x136
#define R2057_RSSI_MASTER_CORE1 0x137
#define R2057_W2_MASTER_CORE1 0x138
#define R2057_NB_MASTER_CORE1 0x139
#define R2057_W2_IDACS0_Q_CORE1 0x13a
#define R2057_W2_IDACS1_Q_CORE1 0x13b
#define R2057_W2_IDACS0_I_CORE1 0x13c
#define R2057_W2_IDACS1_I_CORE1 0x13d
#define R2057_RSSI_GPAIOSEL_W1_IDACS_CORE1 0x13e
#define R2057_NB_IDACS_Q_CORE1 0x13f
#define R2057_NB_IDACS_I_CORE1 0x140
#define R2057_BACKUP4_CORE1 0x146
#define R2057_BACKUP3_CORE1 0x147
#define R2057_BACKUP2_CORE1 0x148
#define R2057_BACKUP1_CORE1 0x149
#define R2057_SPARE16_CORE1 0x14a
#define R2057_SPARE15_CORE1 0x14b
#define R2057_SPARE14_CORE1 0x14c
#define R2057_SPARE13_CORE1 0x14d
#define R2057_SPARE12_CORE1 0x14e
#define R2057_SPARE11_CORE1 0x14f
#define R2057_TX2G_BIAS_RESETS_CORE1 0x150
#define R2057_TX5G_BIAS_RESETS_CORE1 0x151
#define R2057_SPARE8_CORE1 0x152
#define R2057_SPARE7_CORE1 0x153
#define R2057_BUFS_MISC_LPFBW_CORE1 0x154
#define R2057_TXLPF_RCCAL_CORE1 0x155
#define R2057_RXBB_GPAIOSEL_RXLPF_RCCAL_CORE1 0x156
#define R2057_LPF_GAIN_CORE1 0x157
#define R2057_DACBUF_IDACS_BW_CORE1 0x158
#define R2057_DACBUF_VINCM_CORE1 0x159
#define R2057_RCCAL_START_R1_Q1_P1 0x15a
#define R2057_RCCAL_X1 0x15b
#define R2057_RCCAL_TRC0 0x15c
#define R2057_RCCAL_TRC1 0x15d
#define R2057_RCCAL_DONE_OSCCAP 0x15e
#define R2057_RCCAL_N0_0 0x15f
#define R2057_RCCAL_N0_1 0x160
#define R2057_RCCAL_N1_0 0x161
#define R2057_RCCAL_N1_1 0x162
#define R2057_RCAL_STATUS 0x163
#define R2057_XTALPUOVR_PINCTRL 0x164
#define R2057_OVR_REG0 0x165
#define R2057_OVR_REG1 0x166
#define R2057_OVR_REG2 0x167
#define R2057_OVR_REG3 0x168
#define R2057_OVR_REG4 0x169
#define R2057_RCCAL_SCAP_VAL 0x16a
#define R2057_RCCAL_BCAP_VAL 0x16b
#define R2057_RCCAL_HPC_VAL 0x16c
#define R2057_RCCAL_OVERRIDES 0x16d
#define R2057_TX0_IQCAL_GAIN_BW 0x170
#define R2057_TX0_LOFT_FINE_I 0x171
#define R2057_TX0_LOFT_FINE_Q 0x172
#define R2057_TX0_LOFT_COARSE_I 0x173
#define R2057_TX0_LOFT_COARSE_Q 0x174
#define R2057_TX0_TX_SSI_MASTER 0x175
#define R2057_TX0_IQCAL_VCM_HG 0x176
#define R2057_TX0_IQCAL_IDAC 0x177
#define R2057_TX0_TSSI_VCM 0x178
#define R2057_TX0_TX_SSI_MUX 0x179
#define R2057_TX0_TSSIA 0x17a
#define R2057_TX0_TSSIG 0x17b
#define R2057_TX0_TSSI_MISC1 0x17c
#define R2057_TX0_TXRXCOUPLE_2G_ATTEN 0x17d
#define R2057_TX0_TXRXCOUPLE_2G_PWRUP 0x17e
#define R2057_TX0_TXRXCOUPLE_5G_ATTEN 0x17f
#define R2057_TX0_TXRXCOUPLE_5G_PWRUP 0x180
#define R2057_TX1_IQCAL_GAIN_BW 0x190
#define R2057_TX1_LOFT_FINE_I 0x191
#define R2057_TX1_LOFT_FINE_Q 0x192
#define R2057_TX1_LOFT_COARSE_I 0x193
#define R2057_TX1_LOFT_COARSE_Q 0x194
#define R2057_TX1_TX_SSI_MASTER 0x195
#define R2057_TX1_IQCAL_VCM_HG 0x196
#define R2057_TX1_IQCAL_IDAC 0x197
#define R2057_TX1_TSSI_VCM 0x198
#define R2057_TX1_TX_SSI_MUX 0x199
#define R2057_TX1_TSSIA 0x19a
#define R2057_TX1_TSSIG 0x19b
#define R2057_TX1_TSSI_MISC1 0x19c
#define R2057_TX1_TXRXCOUPLE_2G_ATTEN 0x19d
#define R2057_TX1_TXRXCOUPLE_2G_PWRUP 0x19e
#define R2057_TX1_TXRXCOUPLE_5G_ATTEN 0x19f
#define R2057_TX1_TXRXCOUPLE_5G_PWRUP 0x1a0
#define R2057_AFE_VCM_CAL_MASTER_CORE0 0x1a1
#define R2057_AFE_SET_VCM_I_CORE0 0x1a2
#define R2057_AFE_SET_VCM_Q_CORE0 0x1a3
#define R2057_AFE_STATUS_VCM_IQADC_CORE0 0x1a4
#define R2057_AFE_STATUS_VCM_I_CORE0 0x1a5
#define R2057_AFE_STATUS_VCM_Q_CORE0 0x1a6
#define R2057_AFE_VCM_CAL_MASTER_CORE1 0x1a7
#define R2057_AFE_SET_VCM_I_CORE1 0x1a8
#define R2057_AFE_SET_VCM_Q_CORE1 0x1a9
#define R2057_AFE_STATUS_VCM_IQADC_CORE1 0x1aa
#define R2057_AFE_STATUS_VCM_I_CORE1 0x1ab
#define R2057_AFE_STATUS_VCM_Q_CORE1 0x1ac
#define R2057v7_DACBUF_VINCM_CORE0 0x1ad
#define R2057v7_RCCAL_MASTER 0x1ae
#define R2057v7_TR2G_CONFIG3_CORE0_NU 0x1af
#define R2057v7_TR2G_CONFIG3_CORE1_NU 0x1b0
#define R2057v7_LOGEN_PUS1 0x1b1
#define R2057v7_OVR_REG5 0x1b2
#define R2057v7_OVR_REG6 0x1b3
#define R2057v7_OVR_REG7 0x1b4
#define R2057v7_OVR_REG8 0x1b5
#define R2057v7_OVR_REG9 0x1b6
#define R2057v7_OVR_REG10 0x1b7
#define R2057v7_OVR_REG11 0x1b8
#define R2057v7_OVR_REG12 0x1b9
#define R2057v7_OVR_REG13 0x1ba
#define R2057v7_OVR_REG14 0x1bb
#define R2057v7_OVR_REG15 0x1bc
#define R2057v7_OVR_REG16 0x1bd
#define R2057v7_OVR_REG1 0x1be
#define R2057v7_OVR_REG18 0x1bf
#define R2057v7_OVR_REG19 0x1c0
#define R2057v7_OVR_REG20 0x1c1
#define R2057v7_OVR_REG21 0x1c2
#define R2057v7_OVR_REG2 0x1c3
#define R2057v7_OVR_REG23 0x1c4
#define R2057v7_OVR_REG24 0x1c5
#define R2057v7_OVR_REG25 0x1c6
#define R2057v7_OVR_REG26 0x1c7
#define R2057v7_OVR_REG27 0x1c8
#define R2057v7_OVR_REG28 0x1c9
#define R2057v7_IQTEST_SEL_PU2 0x1ca
#define R2057_VCM_MASK 0x7
void r2057_upload_inittabs(struct b43_wldev *dev);
#endif /* B43_RADIO_2057_H_ */

View File

@ -2757,6 +2757,49 @@ const struct nphy_rf_control_override_rev3 tbl_rf_control_override_rev3[] = {
{ 0x00C0, 6, 0xE7, 0xF9, 0xEC, 0xFB } /* field == 0x4000 (fls 15) */
};
/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
static const struct nphy_rf_control_override_rev7
tbl_rf_control_override_rev7_over0[] = {
{ 0x0004, 0x07A, 0x07D, 0x0002, 1 },
{ 0x0008, 0x07A, 0x07D, 0x0004, 2 },
{ 0x0010, 0x07A, 0x07D, 0x0010, 4 },
{ 0x0020, 0x07A, 0x07D, 0x0020, 5 },
{ 0x0040, 0x07A, 0x07D, 0x0040, 6 },
{ 0x0080, 0x0F8, 0x0FA, 0x0080, 7 },
{ 0x0400, 0x0F8, 0x0FA, 0x0070, 4 },
{ 0x0800, 0x07B, 0x07E, 0xFFFF, 0 },
{ 0x1000, 0x07C, 0x07F, 0xFFFF, 0 },
{ 0x6000, 0x348, 0x349, 0xFFFF, 0 },
{ 0x2000, 0x348, 0x349, 0x000F, 0 },
};
/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
static const struct nphy_rf_control_override_rev7
tbl_rf_control_override_rev7_over1[] = {
{ 0x0002, 0x340, 0x341, 0x0002, 1 },
{ 0x0008, 0x340, 0x341, 0x0008, 3 },
{ 0x0020, 0x340, 0x341, 0x0020, 5 },
{ 0x0010, 0x340, 0x341, 0x0010, 4 },
{ 0x0004, 0x340, 0x341, 0x0004, 2 },
{ 0x0080, 0x340, 0x341, 0x0700, 8 },
{ 0x0800, 0x340, 0x341, 0x4000, 14 },
{ 0x0400, 0x340, 0x341, 0x2000, 13 },
{ 0x0200, 0x340, 0x341, 0x0800, 12 },
{ 0x0100, 0x340, 0x341, 0x0100, 11 },
{ 0x0040, 0x340, 0x341, 0x0040, 6 },
{ 0x0001, 0x340, 0x341, 0x0001, 0 },
};
/* field, val_addr_core0, val_addr_core1, val_mask, val_shift */
static const struct nphy_rf_control_override_rev7
tbl_rf_control_override_rev7_over2[] = {
{ 0x0008, 0x344, 0x345, 0x0008, 3 },
{ 0x0002, 0x344, 0x345, 0x0002, 1 },
{ 0x0001, 0x344, 0x345, 0x0001, 0 },
{ 0x0004, 0x344, 0x345, 0x0004, 2 },
{ 0x0010, 0x344, 0x345, 0x0010, 4 },
};
struct nphy_gain_ctl_workaround_entry nphy_gain_ctl_wa_phy6_radio11_ghz2 = {
{ 10, 14, 19, 27 },
{ -5, 6, 10, 15 },
@ -3248,3 +3291,35 @@ struct nphy_gain_ctl_workaround_entry *b43_nphy_get_gain_ctl_workaround_ent(
return e;
}
const struct nphy_rf_control_override_rev7 *b43_nphy_get_rf_ctl_over_rev7(
struct b43_wldev *dev, u16 field, u8 override)
{
const struct nphy_rf_control_override_rev7 *e;
u8 size, i;
switch (override) {
case 0:
e = tbl_rf_control_override_rev7_over0;
size = ARRAY_SIZE(tbl_rf_control_override_rev7_over0);
break;
case 1:
e = tbl_rf_control_override_rev7_over1;
size = ARRAY_SIZE(tbl_rf_control_override_rev7_over1);
break;
case 2:
e = tbl_rf_control_override_rev7_over2;
size = ARRAY_SIZE(tbl_rf_control_override_rev7_over2);
break;
default:
b43err(dev->wl, "Invalid override value %d\n", override);
return NULL;
}
for (i = 0; i < size; i++) {
if (e[i].field == field)
return &e[i];
}
return NULL;
}

View File

@ -35,6 +35,14 @@ struct nphy_rf_control_override_rev3 {
u8 val_addr1;
};
struct nphy_rf_control_override_rev7 {
u16 field;
u16 val_addr_core0;
u16 val_addr_core1;
u16 val_mask;
u8 val_shift;
};
struct nphy_gain_ctl_workaround_entry {
s8 lna1_gain[4];
s8 lna2_gain[4];
@ -202,5 +210,7 @@ extern const struct nphy_rf_control_override_rev2
tbl_rf_control_override_rev2[];
extern const struct nphy_rf_control_override_rev3
tbl_rf_control_override_rev3[];
const struct nphy_rf_control_override_rev7 *b43_nphy_get_rf_ctl_over_rev7(
struct b43_wldev *dev, u16 field, u8 override);
#endif /* B43_TABLES_NPHY_H_ */

View File

@ -1920,7 +1920,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
return 0;
ssb_write32(gpiodev, B43legacy_GPIO_CONTROL,
(ssb_read32(gpiodev, B43legacy_GPIO_CONTROL)
& mask) | set);
& ~mask) | set);
return 0;
}

View File

@ -86,7 +86,9 @@ MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN driver.");
MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN cards");
MODULE_LICENSE("Dual BSD/GPL");
/* This needs to be adjusted when brcms_firmwares changes */
MODULE_FIRMWARE("brcm/bcm43xx-0.fw");
MODULE_FIRMWARE("brcm/bcm43xx_hdr-0.fw");
/* recognized BCMA Core IDs */
static struct bcma_device_id brcms_coreid_table[] = {

View File

@ -7512,15 +7512,10 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
if (channel > 14) {
rx_status->band = IEEE80211_BAND_5GHZ;
rx_status->freq = ieee80211_ofdm_chan_to_freq(
WF_CHAN_FACTOR_5_G/2, channel);
} else {
rx_status->band = IEEE80211_BAND_2GHZ;
rx_status->freq = ieee80211_dsss_chan_to_freq(channel);
}
rx_status->band =
channel > 14 ? IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
rx_status->freq =
ieee80211_channel_to_frequency(channel, rx_status->band);
rx_status->signal = wlc_phy_rssi_compute(wlc->hw->band->pi, rxh);

View File

@ -67,11 +67,6 @@
#define WL_CHANSPEC_BAND_2G 0x2000
#define INVCHANSPEC 255
/* used to calculate the chan_freq = chan_factor * 500Mhz + 5 * chan_number */
#define WF_CHAN_FACTOR_2_4_G 4814 /* 2.4 GHz band, 2407 MHz */
#define WF_CHAN_FACTOR_5_G 10000 /* 5 GHz band, 5000 MHz */
#define WF_CHAN_FACTOR_4_G 8000 /* 4.9 GHz band for Japan */
#define CHSPEC_CHANNEL(chspec) ((u8)((chspec) & WL_CHANSPEC_CHAN_MASK))
#define CHSPEC_BAND(chspec) ((chspec) & WL_CHANSPEC_BAND_MASK)

View File

@ -4860,7 +4860,7 @@ EXPORT_SYMBOL(il_add_beacon_time);
#ifdef CONFIG_PM
int
static int
il_pci_suspend(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
@ -4877,9 +4877,8 @@ il_pci_suspend(struct device *device)
return 0;
}
EXPORT_SYMBOL(il_pci_suspend);
int
static int
il_pci_resume(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
@ -4906,16 +4905,8 @@ il_pci_resume(struct device *device)
return 0;
}
EXPORT_SYMBOL(il_pci_resume);
const struct dev_pm_ops il_pm_ops = {
.suspend = il_pci_suspend,
.resume = il_pci_resume,
.freeze = il_pci_suspend,
.thaw = il_pci_resume,
.poweroff = il_pci_suspend,
.restore = il_pci_resume,
};
SIMPLE_DEV_PM_OPS(il_pm_ops, il_pci_suspend, il_pci_resume);
EXPORT_SYMBOL(il_pm_ops);
#endif /* CONFIG_PM */

View File

@ -1845,8 +1845,6 @@ __le32 il_add_beacon_time(struct il_priv *il, u32 base, u32 addon,
u32 beacon_interval);
#ifdef CONFIG_PM
int il_pci_suspend(struct device *device);
int il_pci_resume(struct device *device);
extern const struct dev_pm_ops il_pm_ops;
#define IL_LEGACY_PM_OPS (&il_pm_ops)

View File

@ -726,3 +726,29 @@ int mwifiex_get_tx_ba_stream_tbl(struct mwifiex_private *priv,
return count;
}
/*
* This function retrieves the entry for specific tx BA stream table by RA and
* deletes it.
*/
void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra)
{
struct mwifiex_tx_ba_stream_tbl *tbl, *tmp;
unsigned long flags;
if (!ra)
return;
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
list_for_each_entry_safe(tbl, tmp, &priv->tx_ba_stream_tbl_ptr, list) {
if (!memcmp(tbl->ra, ra, ETH_ALEN)) {
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock,
flags);
mwifiex_11n_delete_tx_ba_stream_tbl_entry(priv, tbl);
spin_lock_irqsave(&priv->tx_ba_stream_tbl_lock, flags);
}
}
spin_unlock_irqrestore(&priv->tx_ba_stream_tbl_lock, flags);
return;
}

View File

@ -69,6 +69,7 @@ int mwifiex_cmd_recfg_tx_buf(struct mwifiex_private *priv,
int mwifiex_cmd_amsdu_aggr_ctrl(struct host_cmd_ds_command *cmd,
int cmd_action,
struct mwifiex_ds_11n_amsdu_aggr_ctrl *aa_ctrl);
void mwifiex_del_tx_ba_stream_tbl_by_ra(struct mwifiex_private *priv, u8 *ra);
/*
* This function checks whether AMPDU is allowed or not for a particular TID.
@ -157,4 +158,18 @@ mwifiex_is_ba_stream_setup(struct mwifiex_private *priv,
return false;
}
/*
* This function checks whether associated station is 11n enabled
*/
static inline int mwifiex_is_sta_11n_enabled(struct mwifiex_private *priv,
struct mwifiex_sta_node *node)
{
if (!node || (priv->bss_role != MWIFIEX_BSS_ROLE_UAP) ||
!priv->ap_11n_enabled)
return 0;
return node->is_11n_enabled;
}
#endif /* !_MWIFIEX_11N_H_ */

View File

@ -62,9 +62,7 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
};
struct tx_packet_hdr *tx_header;
skb_put(skb_aggr, sizeof(*tx_header));
tx_header = (struct tx_packet_hdr *) skb_aggr->data;
tx_header = (void *)skb_put(skb_aggr, sizeof(*tx_header));
/* Copy DA and SA */
dt_offset = 2 * ETH_ALEN;
@ -82,12 +80,10 @@ mwifiex_11n_form_amsdu_pkt(struct sk_buff *skb_aggr,
tx_header->eth803_hdr.h_proto = htons(skb_src->len + LLC_SNAP_LEN);
/* Add payload */
skb_put(skb_aggr, skb_src->len);
memcpy(skb_aggr->data + sizeof(*tx_header), skb_src->data,
skb_src->len);
*pad = (((skb_src->len + LLC_SNAP_LEN) & 3)) ? (4 - (((skb_src->len +
LLC_SNAP_LEN)) & 3)) : 0;
skb_put(skb_aggr, *pad);
memcpy(skb_put(skb_aggr, skb_src->len), skb_src->data, skb_src->len);
/* Add padding for new MSDU to start from 4 byte boundary */
*pad = (4 - ((unsigned long)skb_aggr->tail & 0x3)) % 4;
return skb_aggr->len + *pad;
}

View File

@ -54,8 +54,13 @@ mwifiex_11n_dispatch_pkt(struct mwifiex_private *priv,
tbl->rx_reorder_ptr[i] = NULL;
}
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
if (rx_tmp_ptr)
mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
if (rx_tmp_ptr) {
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
else
mwifiex_process_rx_packet(priv->adapter,
rx_tmp_ptr);
}
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@ -97,7 +102,11 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
rx_tmp_ptr = tbl->rx_reorder_ptr[i];
tbl->rx_reorder_ptr[i] = NULL;
spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
mwifiex_handle_uap_rx_forward(priv, rx_tmp_ptr);
else
mwifiex_process_rx_packet(priv->adapter, rx_tmp_ptr);
}
spin_lock_irqsave(&priv->rx_pkt_lock, flags);
@ -148,7 +157,7 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
* This function returns the pointer to an entry in Rx reordering
* table which matches the given TA/TID pair.
*/
static struct mwifiex_rx_reorder_tbl *
struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
{
struct mwifiex_rx_reorder_tbl *tbl;
@ -167,6 +176,31 @@ mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta)
return NULL;
}
/* This function retrieves the pointer to an entry in Rx reordering
* table which matches the given TA and deletes it.
*/
void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta)
{
struct mwifiex_rx_reorder_tbl *tbl, *tmp;
unsigned long flags;
if (!ta)
return;
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
list_for_each_entry_safe(tbl, tmp, &priv->rx_reorder_tbl_ptr, list) {
if (!memcmp(tbl->ta, ta, ETH_ALEN)) {
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock,
flags);
mwifiex_del_rx_reorder_entry(priv, tbl);
spin_lock_irqsave(&priv->rx_reorder_tbl_lock, flags);
}
}
spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags);
return;
}
/*
* This function finds the last sequence number used in the packets
* buffered in Rx reordering table.
@ -226,6 +260,7 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
struct mwifiex_rx_reorder_tbl *tbl, *new_node;
u16 last_seq = 0;
unsigned long flags;
struct mwifiex_sta_node *node;
/*
* If we get a TID, ta pair which is already present dispatch all the
@ -248,13 +283,19 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
new_node->tid = tid;
memcpy(new_node->ta, ta, ETH_ALEN);
new_node->start_win = seq_num;
if (mwifiex_queuing_ra_based(priv))
/* TODO for adhoc */
if (mwifiex_queuing_ra_based(priv)) {
dev_dbg(priv->adapter->dev,
"info: ADHOC:last_seq=%d start_win=%d\n",
"info: AP/ADHOC:last_seq=%d start_win=%d\n",
last_seq, new_node->start_win);
else
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
node = mwifiex_get_sta_entry(priv, ta);
if (node)
last_seq = node->rx_seq[tid];
}
} else {
last_seq = priv->rx_seq[tid];
}
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
last_seq >= new_node->start_win)
@ -396,8 +437,13 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
tbl = mwifiex_11n_get_rx_reorder_tbl(priv, tid, ta);
if (!tbl) {
if (pkt_type != PKT_TYPE_BAR)
mwifiex_process_rx_packet(priv->adapter, payload);
if (pkt_type != PKT_TYPE_BAR) {
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
mwifiex_handle_uap_rx_forward(priv, payload);
else
mwifiex_process_rx_packet(priv->adapter,
payload);
}
return 0;
}
start_win = tbl->start_win;

View File

@ -38,6 +38,8 @@
#define ADDBA_RSP_STATUS_ACCEPT 0
#define MWIFIEX_DEF_11N_RX_SEQ_NUM 0xffff
#define BA_SETUP_MAX_PACKET_THRESHOLD 16
#define BA_SETUP_PACKET_OFFSET 16
static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv)
{
@ -68,5 +70,8 @@ struct mwifiex_rx_reorder_tbl *mwifiex_11n_get_rxreorder_tbl(struct
mwifiex_private
*priv, int tid,
u8 *ta);
struct mwifiex_rx_reorder_tbl *
mwifiex_11n_get_rx_reorder_tbl(struct mwifiex_private *priv, int tid, u8 *ta);
void mwifiex_11n_del_rx_reorder_tbl_by_ta(struct mwifiex_private *priv, u8 *ta);
#endif /* _MWIFIEX_11N_RXREORDER_H_ */

View File

@ -33,8 +33,10 @@ mwifiex-y += uap_cmd.o
mwifiex-y += ie.o
mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o
mwifiex-y += uap_event.o
mwifiex-y += sta_tx.o
mwifiex-y += sta_rx.o
mwifiex-y += uap_txrx.o
mwifiex-y += cfg80211.o
mwifiex-$(CONFIG_DEBUG_FS) += debugfs.o
obj-$(CONFIG_MWIFIEX) += mwifiex.o

View File

@ -99,7 +99,7 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) {
if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index, peer_mac, 1)) {
wiphy_err(wiphy, "deleting the crypto keys\n");
return -EFAULT;
}
@ -171,7 +171,8 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
priv->wep_key_curr_index = key_index;
} else if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
} else if (mwifiex_set_encode(priv, NULL, NULL, 0, key_index,
NULL, 0)) {
wiphy_err(wiphy, "set default Tx key index\n");
return -EFAULT;
}
@ -207,7 +208,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
return 0;
}
if (mwifiex_set_encode(priv, params->key, params->key_len,
if (mwifiex_set_encode(priv, params, params->key, params->key_len,
key_index, peer_mac, 0)) {
wiphy_err(wiphy, "crypto keys added\n");
return -EFAULT;
@ -748,6 +749,7 @@ static const u32 mwifiex_cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
WLAN_CIPHER_SUITE_AES_CMAC,
};
/*
@ -906,6 +908,8 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
priv->ap_11n_enabled = 0;
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
@ -1159,7 +1163,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 0;
ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);
ret = mwifiex_set_encode(priv, NULL, NULL, 0, 0, NULL, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
/* "privacy" is set only for ad-hoc mode */
@ -1206,8 +1210,9 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
"info: setting wep encryption"
" with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
sme->key_idx, NULL, 0);
ret = mwifiex_set_encode(priv, NULL, sme->key,
sme->key_len, sme->key_idx,
NULL, 0);
}
}
done:

View File

@ -447,7 +447,10 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
}
ret = mwifiex_process_sta_event(priv);
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
ret = mwifiex_process_uap_event(priv);
else
ret = mwifiex_process_sta_event(priv);
adapter->event_cause = 0;
adapter->event_skb = NULL;

View File

@ -60,6 +60,9 @@
#define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
#define MWIFIEX_BUF_FLAG_BRIDGED_PKT BIT(1)
#define MWIFIEX_BRIDGED_PKTS_THRESHOLD 1024
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,

View File

@ -65,10 +65,12 @@ enum KEY_TYPE_ID {
KEY_TYPE_ID_TKIP,
KEY_TYPE_ID_AES,
KEY_TYPE_ID_WAPI,
KEY_TYPE_ID_AES_CMAC,
};
#define KEY_MCAST BIT(0)
#define KEY_UNICAST BIT(1)
#define KEY_ENABLED BIT(2)
#define KEY_IGTK BIT(10)
#define WAPI_KEY_LEN 50
@ -424,10 +426,10 @@ struct txpd {
struct rxpd {
u8 bss_type;
u8 bss_num;
u16 rx_pkt_length;
u16 rx_pkt_offset;
u16 rx_pkt_type;
u16 seq_num;
__le16 rx_pkt_length;
__le16 rx_pkt_offset;
__le16 rx_pkt_type;
__le16 seq_num;
u8 priority;
u8 rx_rate;
s8 snr;
@ -439,6 +441,31 @@ struct rxpd {
u8 reserved;
} __packed;
struct uap_txpd {
u8 bss_type;
u8 bss_num;
__le16 tx_pkt_length;
__le16 tx_pkt_offset;
__le16 tx_pkt_type;
__le32 tx_control;
u8 priority;
u8 flags;
u8 pkt_delay_2ms;
u8 reserved1;
__le32 reserved2;
};
struct uap_rxpd {
u8 bss_type;
u8 bss_num;
__le16 rx_pkt_length;
__le16 rx_pkt_offset;
__le16 rx_pkt_type;
__le16 seq_num;
u8 priority;
u8 reserved1;
};
enum mwifiex_chan_scan_mode_bitmasks {
MWIFIEX_PASSIVE_SCAN = BIT(0),
MWIFIEX_DISABLE_CHAN_FILT = BIT(1),
@ -558,6 +585,13 @@ struct mwifiex_ie_type_key_param_set {
u8 key[50];
} __packed;
#define IGTK_PN_LEN 8
struct mwifiex_cmac_param {
u8 ipn[IGTK_PN_LEN];
u8 key[WLAN_KEY_LEN_AES_CMAC];
} __packed;
struct host_cmd_ds_802_11_key_material {
__le16 action;
struct mwifiex_ie_type_key_param_set key_param_set;

View File

@ -64,60 +64,72 @@ static void scan_delay_timer_fn(unsigned long data)
struct cmd_ctrl_node *cmd_node, *tmp_node;
unsigned long flags;
if (!mwifiex_wmm_lists_empty(adapter)) {
if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
if (adapter->scan_delay_cnt == MWIFIEX_MAX_SCAN_DELAY_CNT) {
/*
* Abort scan operation by cancelling all pending scan
* commands
*/
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
cmd_node->wait_q_enabled = false;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = false;
adapter->scan_delay_cnt = 0;
adapter->empty_tx_q_cnt = 0;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
if (priv->user_scan_cfg) {
dev_dbg(priv->adapter->dev,
"info: %s: scan aborted\n", __func__);
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
kfree(priv->user_scan_cfg);
priv->user_scan_cfg = NULL;
}
goto done;
}
if (!atomic_read(&priv->adapter->is_tx_received)) {
adapter->empty_tx_q_cnt++;
if (adapter->empty_tx_q_cnt == MWIFIEX_MAX_EMPTY_TX_Q_CNT) {
/*
* Abort scan operation by cancelling all pending scan
* command
* No Tx traffic for 200msec. Get scan command from
* scan pending queue and put to cmd pending queue to
* resume scan operation
*/
adapter->scan_delay_cnt = 0;
adapter->empty_tx_q_cnt = 0;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q,
list) {
list_del(&cmd_node->list);
cmd_node->wait_q_enabled = false;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
}
cmd_node = list_first_entry(&adapter->scan_pending_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
flags);
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = false;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock,
flags);
if (priv->user_scan_cfg) {
dev_dbg(priv->adapter->dev,
"info: %s: scan aborted\n", __func__);
cfg80211_scan_done(priv->scan_request, 1);
priv->scan_request = NULL;
kfree(priv->user_scan_cfg);
priv->user_scan_cfg = NULL;
}
} else {
/*
* Tx data queue is still not empty, delay scan
* operation further by 20msec.
*/
mod_timer(&priv->scan_delay_timer, jiffies +
msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
adapter->scan_delay_cnt++;
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node,
true);
goto done;
}
queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
} else {
/*
* Tx data queue is empty. Get scan command from scan_pending_q
* and put to cmd_pending_q to resume scan operation
*/
adapter->scan_delay_cnt = 0;
spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
cmd_node = list_first_entry(&adapter->scan_pending_q,
struct cmd_ctrl_node, list);
list_del(&cmd_node->list);
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true);
adapter->empty_tx_q_cnt = 0;
}
/* Delay scan operation further by 20msec */
mod_timer(&priv->scan_delay_timer, jiffies +
msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC));
adapter->scan_delay_cnt++;
done:
if (atomic_read(&priv->adapter->is_tx_received))
atomic_set(&priv->adapter->is_tx_received, false);
return;
}
/*
@ -196,6 +208,7 @@ static int mwifiex_init_priv(struct mwifiex_private *priv)
priv->curr_bcn_size = 0;
priv->wps_ie = NULL;
priv->wps_ie_len = 0;
priv->ap_11n_enabled = 0;
priv->scan_block = false;
@ -345,6 +358,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
adapter->empty_tx_q_cnt = 0;
}
/*
@ -410,6 +424,7 @@ static void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
list_del(&priv->wmm.tid_tbl_ptr[j].ra_list);
list_del(&priv->tx_ba_stream_tbl_ptr);
list_del(&priv->rx_reorder_tbl_ptr);
list_del(&priv->sta_list);
}
}
}
@ -472,6 +487,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
spin_lock_init(&priv->rx_pkt_lock);
spin_lock_init(&priv->wmm.ra_list_spinlock);
spin_lock_init(&priv->curr_bcn_buf_lock);
spin_lock_init(&priv->sta_list_spinlock);
}
}
@ -504,6 +520,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
}
INIT_LIST_HEAD(&priv->tx_ba_stream_tbl_ptr);
INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr);
INIT_LIST_HEAD(&priv->sta_list);
spin_lock_init(&priv->tx_ba_stream_tbl_lock);
spin_lock_init(&priv->rx_reorder_tbl_lock);

View File

@ -213,7 +213,7 @@ struct mwifiex_debug_info {
};
#define MWIFIEX_KEY_INDEX_UNICAST 0x40000000
#define WAPI_RXPN_LEN 16
#define PN_LEN 16
struct mwifiex_ds_encrypt_key {
u32 key_disable;
@ -222,7 +222,8 @@ struct mwifiex_ds_encrypt_key {
u8 key_material[WLAN_MAX_KEY_LEN];
u8 mac_addr[ETH_ALEN];
u32 is_wapi_key;
u8 wapi_rxpn[WAPI_RXPN_LEN];
u8 pn[PN_LEN]; /* packet number */
u8 is_igtk_key;
};
struct mwifiex_power_cfg {

View File

@ -520,6 +520,9 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
mwifiex_wmm_add_buf_txqueue(priv, skb);
atomic_inc(&priv->adapter->tx_pending);
if (priv->adapter->scan_delay_cnt)
atomic_set(&priv->adapter->is_tx_received, true);
if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
mwifiex_set_trans_start(dev);
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);

View File

@ -88,6 +88,7 @@ enum {
#define MWIFIEX_MAX_TOTAL_SCAN_TIME (MWIFIEX_TIMER_10S - MWIFIEX_TIMER_1S)
#define MWIFIEX_MAX_SCAN_DELAY_CNT 50
#define MWIFIEX_MAX_EMPTY_TX_Q_CNT 10
#define MWIFIEX_SCAN_DELAY_MSEC 20
#define RSN_GTK_OUI_OFFSET 2
@ -199,6 +200,9 @@ struct mwifiex_ra_list_tbl {
u8 ra[ETH_ALEN];
u32 total_pkts_size;
u32 is_11n_enabled;
u16 max_amsdu;
u16 pkt_count;
u8 ba_packet_thr;
};
struct mwifiex_tid_tbl {
@ -431,6 +435,9 @@ struct mwifiex_private {
u8 wmm_enabled;
u8 wmm_qosinfo;
struct mwifiex_wmm_desc wmm;
struct list_head sta_list;
/* spin lock for associated station list */
spinlock_t sta_list_spinlock;
struct list_head tx_ba_stream_tbl_ptr;
/* spin lock for tx_ba_stream_tbl_ptr queue */
spinlock_t tx_ba_stream_tbl_lock;
@ -486,6 +493,7 @@ struct mwifiex_private {
u16 assocresp_idx;
u16 rsn_idx;
struct timer_list scan_delay_timer;
u8 ap_11n_enabled;
};
enum mwifiex_ba_status {
@ -550,6 +558,19 @@ struct mwifiex_bss_priv {
u64 fw_tsf;
};
/* This is AP specific structure which stores information
* about associated STA
*/
struct mwifiex_sta_node {
struct list_head list;
u8 mac_addr[ETH_ALEN];
u8 is_wmm_enabled;
u8 is_11n_enabled;
u8 ampdu_sta[MAX_NUM_TID];
u16 rx_seq[MAX_NUM_TID];
u16 max_amsdu;
};
struct mwifiex_if_ops {
int (*init_if) (struct mwifiex_adapter *);
void (*cleanup_if) (struct mwifiex_adapter *);
@ -690,6 +711,9 @@ struct mwifiex_adapter {
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u16 max_mgmt_ie_index;
u8 scan_delay_cnt;
u8 empty_tx_q_cnt;
atomic_t is_tx_received;
atomic_t pending_bridged_pkts;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@ -780,7 +804,15 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
struct host_cmd_ds_command *resp);
int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
struct sk_buff *skb);
int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
struct sk_buff *skb);
int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
struct sk_buff *skb);
int mwifiex_process_sta_event(struct mwifiex_private *);
int mwifiex_process_uap_event(struct mwifiex_private *);
struct mwifiex_sta_node *
mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac);
void mwifiex_delete_all_station_list(struct mwifiex_private *priv);
void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
@ -949,9 +981,9 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
const struct mwifiex_user_scan_cfg *user_scan_in);
int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
int key_len, u8 key_index, const u8 *mac_addr,
int disable);
int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
const u8 *key, int key_len, u8 key_index,
const u8 *mac_addr, int disable);
int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);

View File

@ -989,6 +989,8 @@ mwifiex_config_scan(struct mwifiex_private *priv,
*max_chan_per_scan = 2;
else if (chan_num < MWIFIEX_LIMIT_3_CHANNELS_PER_SCAN_CMD)
*max_chan_per_scan = 3;
else
*max_chan_per_scan = 4;
}
}
@ -1433,9 +1435,9 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
if (ret)
dev_err(priv->adapter->dev, "cannot find ssid "
"%s\n", bss_desc->ssid.ssid);
break;
break;
default:
ret = 0;
ret = 0;
}
}

View File

@ -610,7 +610,7 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
memcpy(&key_material->key_param_set.key[2],
enc_key->key_material, enc_key->key_len);
memcpy(&key_material->key_param_set.key[2 + enc_key->key_len],
enc_key->wapi_rxpn, WAPI_RXPN_LEN);
enc_key->pn, PN_LEN);
key_material->key_param_set.length =
cpu_to_le16(WAPI_KEY_LEN + KEYPARAMSET_FIXED_LEN);
@ -621,23 +621,38 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
return ret;
}
if (enc_key->key_len == WLAN_KEY_LEN_CCMP) {
dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES);
if (cmd_oid == KEY_INFO_ENABLED)
key_material->key_param_set.key_info =
if (enc_key->is_igtk_key) {
dev_dbg(priv->adapter->dev, "cmd: CMAC_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES_CMAC);
if (cmd_oid == KEY_INFO_ENABLED)
key_material->key_param_set.key_info =
cpu_to_le16(KEY_ENABLED);
else
key_material->key_param_set.key_info =
else
key_material->key_param_set.key_info =
cpu_to_le16(!KEY_ENABLED);
if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
key_material->key_param_set.key_info |=
cpu_to_le16(KEY_IGTK);
} else {
dev_dbg(priv->adapter->dev, "cmd: WPA_AES\n");
key_material->key_param_set.key_type_id =
cpu_to_le16(KEY_TYPE_ID_AES);
if (cmd_oid == KEY_INFO_ENABLED)
key_material->key_param_set.key_info =
cpu_to_le16(KEY_ENABLED);
else
key_material->key_param_set.key_info =
cpu_to_le16(!KEY_ENABLED);
if (enc_key->key_index & MWIFIEX_KEY_INDEX_UNICAST)
/* AES pairwise key: unicast */
key_material->key_param_set.key_info |=
key_material->key_param_set.key_info |=
cpu_to_le16(KEY_UNICAST);
else /* AES group key: multicast */
key_material->key_param_set.key_info |=
else /* AES group key: multicast */
key_material->key_param_set.key_info |=
cpu_to_le16(KEY_MCAST);
}
} else if (enc_key->key_len == WLAN_KEY_LEN_TKIP) {
dev_dbg(priv->adapter->dev, "cmd: WPA_TKIP\n");
key_material->key_param_set.key_type_id =
@ -668,6 +683,24 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ sizeof(struct mwifiex_ie_types_header);
if (le16_to_cpu(key_material->key_param_set.key_type_id) ==
KEY_TYPE_ID_AES_CMAC) {
struct mwifiex_cmac_param *param =
(void *)key_material->key_param_set.key;
memcpy(param->ipn, enc_key->pn, IGTK_PN_LEN);
memcpy(param->key, enc_key->key_material,
WLAN_KEY_LEN_AES_CMAC);
key_param_len = sizeof(struct mwifiex_cmac_param);
key_material->key_param_set.key_len =
cpu_to_le16(key_param_len);
key_param_len += KEYPARAMSET_FIXED_LEN;
key_material->key_param_set.length =
cpu_to_le16(key_param_len);
key_param_len += sizeof(struct mwifiex_ie_types_header);
}
cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
+ key_param_len);

View File

@ -184,10 +184,9 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
int mwifiex_process_sta_event(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
int len, ret = 0;
int ret = 0;
u32 eventcause = adapter->event_cause;
struct station_info sinfo;
struct mwifiex_assoc_event *event;
u16 ctrl;
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
@ -279,10 +278,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_MIC_ERR_UNICAST:
dev_dbg(adapter->dev, "event: UNICAST MIC ERROR\n");
cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
NL80211_KEYTYPE_PAIRWISE,
-1, NULL, GFP_KERNEL);
break;
case EVENT_MIC_ERR_MULTICAST:
dev_dbg(adapter->dev, "event: MULTICAST MIC ERROR\n");
cfg80211_michael_mic_failure(priv->netdev, priv->cfg_bssid,
NL80211_KEYTYPE_GROUP,
-1, NULL, GFP_KERNEL);
break;
case EVENT_MIB_CHANGED:
case EVENT_INIT_DONE:
@ -384,11 +389,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
adapter->event_body);
break;
case EVENT_AMSDU_AGGR_CTRL:
dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n",
*(u16 *) adapter->event_body);
ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
adapter->tx_buf_size =
min(adapter->curr_tx_buf_size,
le16_to_cpu(*(__le16 *) adapter->event_body));
min_t(u16, adapter->curr_tx_buf_size, ctrl);
dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
adapter->tx_buf_size);
break;
@ -405,51 +410,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
case EVENT_UAP_STA_ASSOC:
memset(&sinfo, 0, sizeof(sinfo));
event = (struct mwifiex_assoc_event *)
(adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
len = -1;
if (ieee80211_is_assoc_req(event->frame_control))
len = 0;
else if (ieee80211_is_reassoc_req(event->frame_control))
/* There will be ETH_ALEN bytes of
* current_ap_addr before the re-assoc ies.
*/
len = ETH_ALEN;
if (len != -1) {
sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
sinfo.assoc_req_ies = &event->data[len];
len = (u8 *)sinfo.assoc_req_ies -
(u8 *)&event->frame_control;
sinfo.assoc_req_ies_len =
le16_to_cpu(event->len) - (u16)len;
}
}
cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
GFP_KERNEL);
break;
case EVENT_UAP_STA_DEAUTH:
cfg80211_del_sta(priv->netdev, adapter->event_body +
MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL);
break;
case EVENT_UAP_BSS_IDLE:
priv->media_connected = false;
break;
case EVENT_UAP_BSS_ACTIVE:
priv->media_connected = true;
break;
case EVENT_UAP_BSS_START:
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);

View File

@ -942,20 +942,26 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
* This function allocates the IOCTL request buffer, fills it
* with requisite parameters and calls the IOCTL handler.
*/
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
int key_len, u8 key_index,
const u8 *mac_addr, int disable)
int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
const u8 *key, int key_len, u8 key_index,
const u8 *mac_addr, int disable)
{
struct mwifiex_ds_encrypt_key encrypt_key;
memset(&encrypt_key, 0, sizeof(struct mwifiex_ds_encrypt_key));
encrypt_key.key_len = key_len;
if (kp && kp->cipher == WLAN_CIPHER_SUITE_AES_CMAC)
encrypt_key.is_igtk_key = true;
if (!disable) {
encrypt_key.key_index = key_index;
if (key_len)
memcpy(encrypt_key.key_material, key, key_len);
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
if (kp && kp->seq && kp->seq_len)
memcpy(encrypt_key.pn, kp->seq, kp->seq_len);
} else {
encrypt_key.key_disable = true;
if (mac_addr)

View File

@ -54,8 +54,8 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
local_rx_pd = (struct rxpd *) (skb->data);
rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
local_rx_pd->rx_pkt_offset);
rx_pkt_hdr = (void *)local_rx_pd +
le16_to_cpu(local_rx_pd->rx_pkt_offset);
if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr))) {
@ -125,7 +125,7 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct rx_packet_hdr *rx_pkt_hdr;
u8 ta[ETH_ALEN];
u16 rx_pkt_type;
u16 rx_pkt_type, rx_pkt_offset, rx_pkt_length, seq_num;
struct mwifiex_private *priv =
mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
rx_info->bss_type);
@ -134,16 +134,17 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
return -1;
local_rx_pd = (struct rxpd *) (skb->data);
rx_pkt_type = local_rx_pd->rx_pkt_type;
rx_pkt_type = le16_to_cpu(local_rx_pd->rx_pkt_type);
rx_pkt_offset = le16_to_cpu(local_rx_pd->rx_pkt_offset);
rx_pkt_length = le16_to_cpu(local_rx_pd->rx_pkt_length);
seq_num = le16_to_cpu(local_rx_pd->seq_num);
rx_pkt_hdr = (struct rx_packet_hdr *) ((u8 *) local_rx_pd +
local_rx_pd->rx_pkt_offset);
rx_pkt_hdr = (void *)local_rx_pd + rx_pkt_offset;
if ((local_rx_pd->rx_pkt_offset + local_rx_pd->rx_pkt_length) >
(u16) skb->len) {
dev_err(adapter->dev, "wrong rx packet: len=%d,"
" rx_pkt_offset=%d, rx_pkt_length=%d\n", skb->len,
local_rx_pd->rx_pkt_offset, local_rx_pd->rx_pkt_length);
if ((rx_pkt_offset + rx_pkt_length) > (u16) skb->len) {
dev_err(adapter->dev,
"wrong rx packet: len=%d, rx_pkt_offset=%d, rx_pkt_length=%d\n",
skb->len, rx_pkt_offset, rx_pkt_length);
priv->stats.rx_dropped++;
if (adapter->if_ops.data_complete)
@ -154,14 +155,14 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
return ret;
}
if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
if (rx_pkt_type == PKT_TYPE_AMSDU) {
struct sk_buff_head list;
struct sk_buff *rx_skb;
__skb_queue_head_init(&list);
skb_pull(skb, local_rx_pd->rx_pkt_offset);
skb_trim(skb, local_rx_pd->rx_pkt_length);
skb_pull(skb, rx_pkt_offset);
skb_trim(skb, rx_pkt_length);
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false);
@ -189,17 +190,14 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
} else {
if (rx_pkt_type != PKT_TYPE_BAR)
priv->rx_seq[local_rx_pd->priority] =
local_rx_pd->seq_num;
priv->rx_seq[local_rx_pd->priority] = seq_num;
memcpy(ta, priv->curr_bss_params.bss_descriptor.mac_address,
ETH_ALEN);
}
/* Reorder and send to OS */
ret = mwifiex_11n_rx_reorder_pkt(priv, local_rx_pd->seq_num,
local_rx_pd->priority, ta,
(u8) local_rx_pd->rx_pkt_type,
skb);
ret = mwifiex_11n_rx_reorder_pkt(priv, seq_num, local_rx_pd->priority,
ta, (u8) rx_pkt_type, skb);
if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
if (adapter->if_ops.data_complete)

View File

@ -51,6 +51,9 @@ int mwifiex_handle_rx_packet(struct mwifiex_adapter *adapter,
rx_info->bss_num = priv->bss_num;
rx_info->bss_type = priv->bss_type;
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
return mwifiex_process_uap_rx_packet(adapter, skb);
return mwifiex_process_sta_rx_packet(adapter, skb);
}
EXPORT_SYMBOL_GPL(mwifiex_handle_rx_packet);
@ -157,6 +160,8 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
priv->stats.tx_errors++;
}
if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
atomic_dec_return(&adapter->pending_bridged_pkts);
if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
goto done;

View File

@ -167,6 +167,7 @@ mwifiex_set_ht_params(struct mwifiex_private *priv,
if (ht_ie) {
memcpy(&bss_cfg->ht_cap, ht_ie + 2,
sizeof(struct ieee80211_ht_cap));
priv->ap_11n_enabled = 1;
} else {
memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap));
bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP);

View File

@ -0,0 +1,290 @@
/*
* Marvell Wireless LAN device driver: AP event handling
*
* Copyright (C) 2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "decl.h"
#include "main.h"
#include "11n.h"
/*
* This function will return the pointer to station entry in station list
* table which matches specified mac address.
* This function should be called after acquiring RA list spinlock.
* NULL is returned if station entry is not found in associated STA list.
*/
struct mwifiex_sta_node *
mwifiex_get_sta_entry(struct mwifiex_private *priv, u8 *mac)
{
struct mwifiex_sta_node *node;
if (!mac)
return NULL;
list_for_each_entry(node, &priv->sta_list, list) {
if (!memcmp(node->mac_addr, mac, ETH_ALEN))
return node;
}
return NULL;
}
/*
* This function will add a sta_node entry to associated station list
* table with the given mac address.
* If entry exist already, existing entry is returned.
* If received mac address is NULL, NULL is returned.
*/
static struct mwifiex_sta_node *
mwifiex_add_sta_entry(struct mwifiex_private *priv, u8 *mac)
{
struct mwifiex_sta_node *node;
unsigned long flags;
if (!mac)
return NULL;
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
node = mwifiex_get_sta_entry(priv, mac);
if (node)
goto done;
node = kzalloc(sizeof(struct mwifiex_sta_node), GFP_ATOMIC);
if (!node)
goto done;
memcpy(node->mac_addr, mac, ETH_ALEN);
list_add_tail(&node->list, &priv->sta_list);
done:
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return node;
}
/*
* This function will search for HT IE in association request IEs
* and set station HT parameters accordingly.
*/
static void
mwifiex_set_sta_ht_cap(struct mwifiex_private *priv, const u8 *ies,
int ies_len, struct mwifiex_sta_node *node)
{
const struct ieee80211_ht_cap *ht_cap;
if (!ies)
return;
ht_cap = (void *)cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, ies, ies_len);
if (ht_cap) {
node->is_11n_enabled = 1;
node->max_amsdu = le16_to_cpu(ht_cap->cap_info) &
IEEE80211_HT_CAP_MAX_AMSDU ?
MWIFIEX_TX_DATA_BUF_SIZE_8K :
MWIFIEX_TX_DATA_BUF_SIZE_4K;
} else {
node->is_11n_enabled = 0;
}
return;
}
/*
* This function will delete a station entry from station list
*/
static void mwifiex_del_sta_entry(struct mwifiex_private *priv, u8 *mac)
{
struct mwifiex_sta_node *node, *tmp;
unsigned long flags;
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
node = mwifiex_get_sta_entry(priv, mac);
if (node) {
list_for_each_entry_safe(node, tmp, &priv->sta_list,
list) {
list_del(&node->list);
kfree(node);
}
}
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return;
}
/*
* This function will delete all stations from associated station list.
*/
static void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
{
struct mwifiex_sta_node *node, *tmp;
unsigned long flags;
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
list_for_each_entry_safe(node, tmp, &priv->sta_list, list) {
list_del(&node->list);
kfree(node);
}
INIT_LIST_HEAD(&priv->sta_list);
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return;
}
/*
* This function handles AP interface specific events generated by firmware.
*
* Event specific routines are called by this function based
* upon the generated event cause.
*
*
* Events supported for AP -
* - EVENT_UAP_STA_ASSOC
* - EVENT_UAP_STA_DEAUTH
* - EVENT_UAP_BSS_ACTIVE
* - EVENT_UAP_BSS_START
* - EVENT_UAP_BSS_IDLE
* - EVENT_UAP_MIC_COUNTERMEASURES:
*/
int mwifiex_process_uap_event(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
int len, i;
u32 eventcause = adapter->event_cause;
struct station_info sinfo;
struct mwifiex_assoc_event *event;
struct mwifiex_sta_node *node;
u8 *deauth_mac;
struct host_cmd_ds_11n_batimeout *ba_timeout;
u16 ctrl;
switch (eventcause) {
case EVENT_UAP_STA_ASSOC:
memset(&sinfo, 0, sizeof(sinfo));
event = (struct mwifiex_assoc_event *)
(adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER);
if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
len = -1;
if (ieee80211_is_assoc_req(event->frame_control))
len = 0;
else if (ieee80211_is_reassoc_req(event->frame_control))
/* There will be ETH_ALEN bytes of
* current_ap_addr before the re-assoc ies.
*/
len = ETH_ALEN;
if (len != -1) {
sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
sinfo.assoc_req_ies = &event->data[len];
len = (u8 *)sinfo.assoc_req_ies -
(u8 *)&event->frame_control;
sinfo.assoc_req_ies_len =
le16_to_cpu(event->len) - (u16)len;
}
}
cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
GFP_KERNEL);
node = mwifiex_add_sta_entry(priv, event->sta_addr);
if (!node) {
dev_warn(adapter->dev,
"could not create station entry!\n");
return -1;
}
if (!priv->ap_11n_enabled)
break;
mwifiex_set_sta_ht_cap(priv, sinfo.assoc_req_ies,
sinfo.assoc_req_ies_len, node);
for (i = 0; i < MAX_NUM_TID; i++) {
if (node->is_11n_enabled)
node->ampdu_sta[i] =
priv->aggr_prio_tbl[i].ampdu_user;
else
node->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED;
}
memset(node->rx_seq, 0xff, sizeof(node->rx_seq));
break;
case EVENT_UAP_STA_DEAUTH:
deauth_mac = adapter->event_body +
MWIFIEX_UAP_EVENT_EXTRA_HEADER;
cfg80211_del_sta(priv->netdev, deauth_mac, GFP_KERNEL);
if (priv->ap_11n_enabled) {
mwifiex_11n_del_rx_reorder_tbl_by_ta(priv, deauth_mac);
mwifiex_del_tx_ba_stream_tbl_by_ra(priv, deauth_mac);
}
mwifiex_del_sta_entry(priv, deauth_mac);
break;
case EVENT_UAP_BSS_IDLE:
priv->media_connected = false;
mwifiex_clean_txrx(priv);
mwifiex_del_all_sta_list(priv);
break;
case EVENT_UAP_BSS_ACTIVE:
priv->media_connected = true;
break;
case EVENT_UAP_BSS_START:
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
ETH_ALEN);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
break;
case EVENT_AMSDU_AGGR_CTRL:
ctrl = le16_to_cpu(*(__le16 *)adapter->event_body);
dev_dbg(adapter->dev, "event: AMSDU_AGGR_CTRL %d\n", ctrl);
if (priv->media_connected) {
adapter->tx_buf_size =
min_t(u16, adapter->curr_tx_buf_size, ctrl);
dev_dbg(adapter->dev, "event: tx_buf_size %d\n",
adapter->tx_buf_size);
}
break;
case EVENT_ADDBA:
dev_dbg(adapter->dev, "event: ADDBA Request\n");
if (priv->media_connected)
mwifiex_send_cmd_async(priv, HostCmd_CMD_11N_ADDBA_RSP,
HostCmd_ACT_GEN_SET, 0,
adapter->event_body);
break;
case EVENT_DELBA:
dev_dbg(adapter->dev, "event: DELBA Request\n");
if (priv->media_connected)
mwifiex_11n_delete_ba_stream(priv, adapter->event_body);
break;
case EVENT_BA_STREAM_TIEMOUT:
dev_dbg(adapter->dev, "event: BA Stream timeout\n");
if (priv->media_connected) {
ba_timeout = (void *)adapter->event_body;
mwifiex_11n_ba_stream_timeout(priv, ba_timeout);
}
break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
break;
}
return 0;
}

View File

@ -0,0 +1,255 @@
/*
* Marvell Wireless LAN device driver: AP TX and RX data handling
*
* Copyright (C) 2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "decl.h"
#include "ioctl.h"
#include "main.h"
#include "wmm.h"
#include "11n_aggr.h"
#include "11n_rxreorder.h"
static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
struct sk_buff *skb)
{
struct mwifiex_adapter *adapter = priv->adapter;
struct uap_rxpd *uap_rx_pd;
struct rx_packet_hdr *rx_pkt_hdr;
struct sk_buff *new_skb;
struct mwifiex_txinfo *tx_info;
int hdr_chop;
struct timeval tv;
u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
uap_rx_pd = (struct uap_rxpd *)(skb->data);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
if ((atomic_read(&adapter->pending_bridged_pkts) >=
MWIFIEX_BRIDGED_PKTS_THRESHOLD)) {
dev_err(priv->adapter->dev,
"Tx: Bridge packet limit reached. Drop packet!\n");
kfree_skb(skb);
return;
}
if (!memcmp(&rx_pkt_hdr->rfc1042_hdr,
rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)))
/* Chop off the rxpd + the excess memory from
* 802.2/llc/snap header that was removed.
*/
hdr_chop = (u8 *)eth_hdr - (u8 *)uap_rx_pd;
else
/* Chop off the rxpd */
hdr_chop = (u8 *)&rx_pkt_hdr->eth803_hdr - (u8 *)uap_rx_pd;
/* Chop off the leading header bytes so the it points
* to the start of either the reconstructed EthII frame
* or the 802.2/llc/snap frame.
*/
skb_pull(skb, hdr_chop);
if (skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN) {
dev_dbg(priv->adapter->dev,
"data: Tx: insufficient skb headroom %d\n",
skb_headroom(skb));
/* Insufficient skb headroom - allocate a new skb */
new_skb =
skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
if (unlikely(!new_skb)) {
dev_err(priv->adapter->dev,
"Tx: cannot allocate new_skb\n");
kfree_skb(skb);
priv->stats.tx_dropped++;
return;
}
kfree_skb(skb);
skb = new_skb;
dev_dbg(priv->adapter->dev, "info: new skb headroom %d\n",
skb_headroom(skb));
}
tx_info = MWIFIEX_SKB_TXCB(skb);
tx_info->bss_num = priv->bss_num;
tx_info->bss_type = priv->bss_type;
tx_info->flags |= MWIFIEX_BUF_FLAG_BRIDGED_PKT;
do_gettimeofday(&tv);
skb->tstamp = timeval_to_ktime(tv);
mwifiex_wmm_add_buf_txqueue(priv, skb);
atomic_inc(&adapter->tx_pending);
atomic_inc(&adapter->pending_bridged_pkts);
if ((atomic_read(&adapter->tx_pending) >= MAX_TX_PENDING)) {
mwifiex_set_trans_start(priv->netdev);
mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
}
return;
}
/*
* This function contains logic for AP packet forwarding.
*
* If a packet is multicast/broadcast, it is sent to kernel/upper layer
* as well as queued back to AP TX queue so that it can be sent to other
* associated stations.
* If a packet is unicast and RA is present in associated station list,
* it is again requeued into AP TX queue.
* If a packet is unicast and RA is not in associated station list,
* packet is forwarded to kernel to handle routing logic.
*/
int mwifiex_handle_uap_rx_forward(struct mwifiex_private *priv,
struct sk_buff *skb)
{
struct mwifiex_adapter *adapter = priv->adapter;
struct uap_rxpd *uap_rx_pd;
struct rx_packet_hdr *rx_pkt_hdr;
u8 ra[ETH_ALEN];
struct sk_buff *skb_uap;
uap_rx_pd = (struct uap_rxpd *)(skb->data);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
/* don't do packet forwarding in disconnected state */
if (!priv->media_connected) {
dev_err(adapter->dev, "drop packet in disconnected state.\n");
dev_kfree_skb_any(skb);
return 0;
}
memcpy(ra, rx_pkt_hdr->eth803_hdr.h_dest, ETH_ALEN);
if (is_multicast_ether_addr(ra)) {
skb_uap = skb_copy(skb, GFP_ATOMIC);
mwifiex_uap_queue_bridged_pkt(priv, skb_uap);
} else {
if (mwifiex_get_sta_entry(priv, ra)) {
/* Requeue Intra-BSS packet */
mwifiex_uap_queue_bridged_pkt(priv, skb);
return 0;
}
}
/* Forward unicat/Inter-BSS packets to kernel. */
return mwifiex_process_rx_packet(adapter, skb);
}
/*
* This function processes the packet received on AP interface.
*
* The function looks into the RxPD and performs sanity tests on the
* received buffer to ensure its a valid packet before processing it
* further. If the packet is determined to be aggregated, it is
* de-aggregated accordingly. Then skb is passed to AP packet forwarding logic.
*
* The completion callback is called after processing is complete.
*/
int mwifiex_process_uap_rx_packet(struct mwifiex_adapter *adapter,
struct sk_buff *skb)
{
int ret;
struct uap_rxpd *uap_rx_pd;
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct rx_packet_hdr *rx_pkt_hdr;
u16 rx_pkt_type;
u8 ta[ETH_ALEN], pkt_type;
struct mwifiex_sta_node *node;
struct mwifiex_private *priv =
mwifiex_get_priv_by_id(adapter, rx_info->bss_num,
rx_info->bss_type);
if (!priv)
return -1;
uap_rx_pd = (struct uap_rxpd *)(skb->data);
rx_pkt_type = le16_to_cpu(uap_rx_pd->rx_pkt_type);
rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
if ((le16_to_cpu(uap_rx_pd->rx_pkt_offset) +
le16_to_cpu(uap_rx_pd->rx_pkt_length)) > (u16) skb->len) {
dev_err(adapter->dev,
"wrong rx packet: len=%d, offset=%d, length=%d\n",
skb->len, le16_to_cpu(uap_rx_pd->rx_pkt_offset),
le16_to_cpu(uap_rx_pd->rx_pkt_length));
priv->stats.rx_dropped++;
if (adapter->if_ops.data_complete)
adapter->if_ops.data_complete(adapter, skb);
else
dev_kfree_skb_any(skb);
return 0;
}
if (le16_to_cpu(uap_rx_pd->rx_pkt_type) == PKT_TYPE_AMSDU) {
struct sk_buff_head list;
struct sk_buff *rx_skb;
__skb_queue_head_init(&list);
skb_pull(skb, le16_to_cpu(uap_rx_pd->rx_pkt_offset));
skb_trim(skb, le16_to_cpu(uap_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
priv->wdev->iftype, 0, false);
while (!skb_queue_empty(&list)) {
rx_skb = __skb_dequeue(&list);
ret = mwifiex_recv_packet(adapter, rx_skb);
if (ret)
dev_err(adapter->dev,
"AP:Rx A-MSDU failed");
}
return 0;
}
memcpy(ta, rx_pkt_hdr->eth803_hdr.h_source, ETH_ALEN);
if (rx_pkt_type != PKT_TYPE_BAR && uap_rx_pd->priority < MAX_NUM_TID) {
node = mwifiex_get_sta_entry(priv, ta);
if (node)
node->rx_seq[uap_rx_pd->priority] =
le16_to_cpu(uap_rx_pd->seq_num);
}
if (!priv->ap_11n_enabled ||
(!mwifiex_11n_get_rx_reorder_tbl(priv, uap_rx_pd->priority, ta) &&
(le16_to_cpu(uap_rx_pd->rx_pkt_type) != PKT_TYPE_AMSDU))) {
ret = mwifiex_handle_uap_rx_forward(priv, skb);
return ret;
}
/* Reorder and send to kernel */
pkt_type = (u8)le16_to_cpu(uap_rx_pd->rx_pkt_type);
ret = mwifiex_11n_rx_reorder_pkt(priv, le16_to_cpu(uap_rx_pd->seq_num),
uap_rx_pd->priority, ta, pkt_type,
skb);
if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
if (adapter->if_ops.data_complete)
adapter->if_ops.data_complete(adapter, skb);
else
dev_kfree_skb_any(skb);
}
if (ret)
priv->stats.rx_dropped++;
return ret;
}

View File

@ -127,6 +127,29 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
return ra_list;
}
/* This function returns random no between 16 and 32 to be used as threshold
* for no of packets after which BA setup is initiated.
*/
static u8 mwifiex_get_random_ba_threshold(void)
{
u32 sec, usec;
struct timeval ba_tstamp;
u8 ba_threshold;
/* setup ba_packet_threshold here random number between
* [BA_SETUP_PACKET_OFFSET,
* BA_SETUP_PACKET_OFFSET+BA_SETUP_MAX_PACKET_THRESHOLD-1]
*/
do_gettimeofday(&ba_tstamp);
sec = (ba_tstamp.tv_sec & 0xFFFF) + (ba_tstamp.tv_sec >> 16);
usec = (ba_tstamp.tv_usec & 0xFFFF) + (ba_tstamp.tv_usec >> 16);
ba_threshold = (((sec << 16) + usec) % BA_SETUP_MAX_PACKET_THRESHOLD)
+ BA_SETUP_PACKET_OFFSET;
return ba_threshold;
}
/*
* This function allocates and adds a RA list for all TIDs
* with the given RA.
@ -137,6 +160,12 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
int i;
struct mwifiex_ra_list_tbl *ra_list;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_sta_node *node;
unsigned long flags;
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
node = mwifiex_get_sta_entry(priv, ra);
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
for (i = 0; i < MAX_NUM_TID; ++i) {
ra_list = mwifiex_wmm_allocate_ralist_node(adapter, ra);
@ -145,14 +174,24 @@ mwifiex_ralist_add(struct mwifiex_private *priv, u8 *ra)
if (!ra_list)
break;
if (!mwifiex_queuing_ra_based(priv))
ra_list->is_11n_enabled = 0;
if (!mwifiex_queuing_ra_based(priv)) {
ra_list->is_11n_enabled = IS_11N_ENABLED(priv);
else
ra_list->is_11n_enabled = false;
} else {
ra_list->is_11n_enabled =
mwifiex_is_sta_11n_enabled(priv, node);
if (ra_list->is_11n_enabled)
ra_list->max_amsdu = node->max_amsdu;
}
dev_dbg(adapter->dev, "data: ralist %p: is_11n_enabled=%d\n",
ra_list, ra_list->is_11n_enabled);
if (ra_list->is_11n_enabled) {
ra_list->pkt_count = 0;
ra_list->ba_packet_thr =
mwifiex_get_random_ba_threshold();
}
list_add_tail(&ra_list->list,
&priv->wmm.tid_tbl_ptr[i].ra_list);
@ -647,6 +686,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
skb_queue_tail(&ra_list->skb_head, skb);
ra_list->total_pkts_size += skb->len;
ra_list->pkt_count++;
atomic_inc(&priv->wmm.tx_pkts_queued);
@ -986,10 +1026,17 @@ mwifiex_is_11n_aggragation_possible(struct mwifiex_private *priv,
{
int count = 0, total_size = 0;
struct sk_buff *skb, *tmp;
int max_amsdu_size;
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP && priv->ap_11n_enabled &&
ptr->is_11n_enabled)
max_amsdu_size = min_t(int, ptr->max_amsdu, max_buf_size);
else
max_amsdu_size = max_buf_size;
skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
total_size += skb->len;
if (total_size >= max_buf_size)
if (total_size >= max_amsdu_size)
break;
if (++count >= MIN_NUM_AMSDU)
return true;
@ -1050,6 +1097,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
skb_queue_tail(&ptr->skb_head, skb);
ptr->total_pkts_size += skb->len;
ptr->pkt_count++;
tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
@ -1231,7 +1279,8 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
/* ra_list_spinlock has been freed in
mwifiex_send_single_packet() */
} else {
if (mwifiex_is_ampdu_allowed(priv, tid)) {
if (mwifiex_is_ampdu_allowed(priv, tid) &&
ptr->pkt_count > ptr->ba_packet_thr) {
if (mwifiex_space_avail_for_new_ba_stream(adapter)) {
mwifiex_create_ba_tbl(priv, ptr->ra, tid,
BA_SETUP_INPROGRESS);

View File

@ -76,6 +76,7 @@ struct p54_channel_entry {
u16 freq;
u16 data;
int index;
int max_power;
enum ieee80211_band band;
};
@ -173,6 +174,7 @@ static int p54_generate_band(struct ieee80211_hw *dev,
for (i = 0, j = 0; (j < list->band_channel_num[band]) &&
(i < list->entries); i++) {
struct p54_channel_entry *chan = &list->channels[i];
struct ieee80211_channel *dest = &tmp->channels[j];
if (chan->band != band)
continue;
@ -190,14 +192,15 @@ static int p54_generate_band(struct ieee80211_hw *dev,
continue;
}
tmp->channels[j].band = chan->band;
tmp->channels[j].center_freq = chan->freq;
dest->band = chan->band;
dest->center_freq = chan->freq;
dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_CHANNEL_TIME |
SURVEY_INFO_CHANNEL_TIME_BUSY |
SURVEY_INFO_CHANNEL_TIME_TX;
tmp->channels[j].hw_value = (*chan_num);
dest->hw_value = (*chan_num);
j++;
(*chan_num)++;
}
@ -229,10 +232,11 @@ err_out:
return ret;
}
static void p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data)
static struct p54_channel_entry *p54_update_channel_param(struct p54_channel_list *list,
u16 freq, u16 data)
{
int band, i;
int i;
struct p54_channel_entry *entry = NULL;
/*
* usually all lists in the eeprom are mostly sorted.
@ -241,30 +245,78 @@ static void p54_update_channel_param(struct p54_channel_list *list,
*/
for (i = list->entries; i >= 0; i--) {
if (freq == list->channels[i].freq) {
list->channels[i].data |= data;
entry = &list->channels[i];
break;
}
}
if ((i < 0) && (list->entries < list->max_entries)) {
/* entry does not exist yet. Initialize a new one. */
band = p54_get_band_from_freq(freq);
int band = p54_get_band_from_freq(freq);
/*
* filter out frequencies which don't belong into
* any supported band.
*/
if (band < 0)
return ;
if (band >= 0) {
i = list->entries++;
list->band_channel_num[band]++;
i = list->entries++;
list->band_channel_num[band]++;
entry = &list->channels[i];
entry->freq = freq;
entry->band = band;
entry->index = ieee80211_frequency_to_channel(freq);
entry->max_power = 0;
entry->data = 0;
}
}
list->channels[i].freq = freq;
list->channels[i].data = data;
list->channels[i].band = band;
list->channels[i].index = ieee80211_frequency_to_channel(freq);
/* TODO: parse output_limit and fill max_power */
if (entry)
entry->data |= data;
return entry;
}
static int p54_get_maxpower(struct p54_common *priv, void *data)
{
switch (priv->rxhw & PDR_SYNTH_FRONTEND_MASK) {
case PDR_SYNTH_FRONTEND_LONGBOW: {
struct pda_channel_output_limit_longbow *pda = data;
int j;
u16 rawpower = 0;
pda = data;
for (j = 0; j < ARRAY_SIZE(pda->point); j++) {
struct pda_channel_output_limit_point_longbow *point =
&pda->point[j];
rawpower = max_t(u16,
rawpower, le16_to_cpu(point->val_qpsk));
rawpower = max_t(u16,
rawpower, le16_to_cpu(point->val_bpsk));
rawpower = max_t(u16,
rawpower, le16_to_cpu(point->val_16qam));
rawpower = max_t(u16,
rawpower, le16_to_cpu(point->val_64qam));
}
/* longbow seems to use 1/16 dBm units */
return rawpower / 16;
}
case PDR_SYNTH_FRONTEND_DUETTE3:
case PDR_SYNTH_FRONTEND_DUETTE2:
case PDR_SYNTH_FRONTEND_FRISBEE:
case PDR_SYNTH_FRONTEND_XBOW: {
struct pda_channel_output_limit *pda = data;
u8 rawpower = 0;
rawpower = max(rawpower, pda->val_qpsk);
rawpower = max(rawpower, pda->val_bpsk);
rawpower = max(rawpower, pda->val_16qam);
rawpower = max(rawpower, pda->val_64qam);
/* raw values are in 1/4 dBm units */
return rawpower / 4;
}
default:
return 20;
}
}
@ -315,12 +367,19 @@ static int p54_generate_channel_lists(struct ieee80211_hw *dev)
}
if (i < priv->output_limit->entries) {
freq = le16_to_cpup((__le16 *) (i *
priv->output_limit->entry_size +
priv->output_limit->offset +
priv->output_limit->data));
struct p54_channel_entry *tmp;
p54_update_channel_param(list, freq, CHAN_HAS_LIMIT);
void *data = (void *) ((unsigned long) i *
priv->output_limit->entry_size +
priv->output_limit->offset +
priv->output_limit->data);
freq = le16_to_cpup((__le16 *) data);
tmp = p54_update_channel_param(list, freq,
CHAN_HAS_LIMIT);
if (tmp) {
tmp->max_power = p54_get_maxpower(priv, data);
}
}
if (i < priv->curve_data->entries) {
@ -834,11 +893,12 @@ good_eeprom:
goto err;
}
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
err = p54_generate_channel_lists(dev);
if (err)
goto err;
priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK;
if (priv->rxhw == PDR_SYNTH_FRONTEND_XBOW)
p54_init_xbow_synth(priv);
if (!(synth & PDR_SYNTH_24_GHZ_DISABLED))

View File

@ -57,6 +57,18 @@ struct pda_channel_output_limit {
u8 rate_set_size;
} __packed;
struct pda_channel_output_limit_point_longbow {
__le16 val_bpsk;
__le16 val_qpsk;
__le16 val_16qam;
__le16 val_64qam;
} __packed;
struct pda_channel_output_limit_longbow {
__le16 freq;
struct pda_channel_output_limit_point_longbow point[3];
} __packed;
struct pda_pa_curve_data_sample_rev0 {
u8 rf_power;
u8 pa_detector;

View File

@ -488,6 +488,58 @@ static int p54p_open(struct ieee80211_hw *dev)
return 0;
}
static void p54p_firmware_step2(const struct firmware *fw,
void *context)
{
struct p54p_priv *priv = context;
struct ieee80211_hw *dev = priv->common.hw;
struct pci_dev *pdev = priv->pdev;
int err;
if (!fw) {
dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
err = -ENOENT;
goto out;
}
priv->firmware = fw;
err = p54p_open(dev);
if (err)
goto out;
err = p54_read_eeprom(dev);
p54p_stop(dev);
if (err)
goto out;
err = p54_register_common(dev, &pdev->dev);
if (err)
goto out;
out:
complete(&priv->fw_loaded);
if (err) {
struct device *parent = pdev->dev.parent;
if (parent)
device_lock(parent);
/*
* This will indirectly result in a call to p54p_remove.
* Hence, we don't need to bother with freeing any
* allocated ressources at all.
*/
device_release_driver(&pdev->dev);
if (parent)
device_unlock(parent);
}
pci_dev_put(pdev);
}
static int __devinit p54p_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
@ -496,6 +548,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
unsigned long mem_addr, mem_len;
int err;
pci_dev_get(pdev);
err = pci_enable_device(pdev);
if (err) {
dev_err(&pdev->dev, "Cannot enable new PCI device\n");
@ -537,6 +590,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
priv = dev->priv;
priv->pdev = pdev;
init_completion(&priv->fw_loaded);
SET_IEEE80211_DEV(dev, &pdev->dev);
pci_set_drvdata(pdev, dev);
@ -561,32 +615,12 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
spin_lock_init(&priv->lock);
tasklet_init(&priv->tasklet, p54p_tasklet, (unsigned long)dev);
err = request_firmware(&priv->firmware, "isl3886pci",
&priv->pdev->dev);
if (err) {
dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
err = request_firmware(&priv->firmware, "isl3886",
&priv->pdev->dev);
if (err)
goto err_free_common;
}
err = request_firmware_nowait(THIS_MODULE, 1, "isl3886pci",
&priv->pdev->dev, GFP_KERNEL,
priv, p54p_firmware_step2);
if (!err)
return 0;
err = p54p_open(dev);
if (err)
goto err_free_common;
err = p54_read_eeprom(dev);
p54p_stop(dev);
if (err)
goto err_free_common;
err = p54_register_common(dev, &pdev->dev);
if (err)
goto err_free_common;
return 0;
err_free_common:
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);
@ -601,6 +635,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
pci_release_regions(pdev);
err_disable_dev:
pci_disable_device(pdev);
pci_dev_put(pdev);
return err;
}
@ -612,8 +647,9 @@ static void __devexit p54p_remove(struct pci_dev *pdev)
if (!dev)
return;
p54_unregister_common(dev);
priv = dev->priv;
wait_for_completion(&priv->fw_loaded);
p54_unregister_common(dev);
release_firmware(priv->firmware);
pci_free_consistent(pdev, sizeof(*priv->ring_control),
priv->ring_control, priv->ring_control_dma);

View File

@ -105,6 +105,7 @@ struct p54p_priv {
struct sk_buff *tx_buf_data[32];
struct sk_buff *tx_buf_mgmt[4];
struct completion boot_comp;
struct completion fw_loaded;
};
#endif /* P54USB_H */

View File

@ -190,16 +190,30 @@ static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
{
struct ssb_bus *bus = mcore->dev->bus;
mcore->flash_buswidth = 2;
if (bus->chipco.dev) {
mcore->flash_window = 0x1c000000;
mcore->flash_window_size = 0x02000000;
/* When there is no chipcommon on the bus there is 4MB flash */
if (!bus->chipco.dev) {
mcore->flash_buswidth = 2;
mcore->flash_window = SSB_FLASH1;
mcore->flash_window_size = SSB_FLASH1_SZ;
return;
}
/* There is ChipCommon, so use it to read info about flash */
switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
case SSB_CHIPCO_FLASHT_STSER:
case SSB_CHIPCO_FLASHT_ATSER:
pr_err("Serial flash not supported\n");
break;
case SSB_CHIPCO_FLASHT_PARA:
pr_debug("Found parallel flash\n");
mcore->flash_window = SSB_FLASH2;
mcore->flash_window_size = SSB_FLASH2_SZ;
if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
& SSB_CHIPCO_CFG_DS16) == 0)
mcore->flash_buswidth = 1;
} else {
mcore->flash_window = 0x1fc00000;
mcore->flash_window_size = 0x00400000;
else
mcore->flash_buswidth = 2;
break;
}
}

View File

@ -100,6 +100,7 @@
#define BCMA_CC_CHIPST_4706_SFLASH_TYPE BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */
#define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */
#define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */
#define BCMA_CC_CHIPST_5357_NAND_BOOT BIT(4) /* NAND boot, valid for CC rev 38 and/or BCM5357 */
#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
#define BCMA_CC_JCMD_START 0x80000000
#define BCMA_CC_JCMD_BUSY 0x80000000
@ -266,6 +267,29 @@
#define BCMA_CC_SROM_CONTROL_SIZE_16K 0x00000004
#define BCMA_CC_SROM_CONTROL_SIZE_SHIFT 1
#define BCMA_CC_SROM_CONTROL_PRESENT 0x00000001
/* Block 0x140 - 0x190 registers are chipset specific */
#define BCMA_CC_4706_FLASHSCFG 0x18C /* Flash struct configuration */
#define BCMA_CC_4706_FLASHSCFG_MASK 0x000000ff
#define BCMA_CC_4706_FLASHSCFG_SF1 0x00000001 /* 2nd serial flash present */
#define BCMA_CC_4706_FLASHSCFG_PF1 0x00000002 /* 2nd parallel flash present */
#define BCMA_CC_4706_FLASHSCFG_SF1_TYPE 0x00000004 /* 2nd serial flash type : 0 : ST, 1 : Atmel */
#define BCMA_CC_4706_FLASHSCFG_NF1 0x00000008 /* 2nd NAND flash present */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_MASK 0x000000f0
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_4MB 0x00000010 /* 4MB */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_8MB 0x00000020 /* 8MB */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_16MB 0x00000030 /* 16MB */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_32MB 0x00000040 /* 32MB */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_64MB 0x00000050 /* 64MB */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_128MB 0x00000060 /* 128MB */
#define BCMA_CC_4706_FLASHSCFG_1ST_MADDR_SEG_256MB 0x00000070 /* 256MB */
/* NAND flash registers for BCM4706 (corerev = 31) */
#define BCMA_CC_NFLASH_CTL 0x01A0
#define BCMA_CC_NFLASH_CTL_ERR 0x08000000
#define BCMA_CC_NFLASH_CONF 0x01A4
#define BCMA_CC_NFLASH_COL_ADDR 0x01A8
#define BCMA_CC_NFLASH_ROW_ADDR 0x01AC
#define BCMA_CC_NFLASH_DATA 0x01B0
#define BCMA_CC_NFLASH_WAITCNT0 0x01B4
/* 0x1E0 is defined as shared BCMA_CLKCTLST */
#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
#define BCMA_CC_UART0_DATA 0x0300
@ -325,6 +349,60 @@
#define BCMA_CC_PLLCTL_ADDR 0x0660
#define BCMA_CC_PLLCTL_DATA 0x0664
#define BCMA_CC_SPROM 0x0800 /* SPROM beginning */
/* NAND flash MLC controller registers (corerev >= 38) */
#define BCMA_CC_NAND_REVISION 0x0C00
#define BCMA_CC_NAND_CMD_START 0x0C04
#define BCMA_CC_NAND_CMD_ADDR_X 0x0C08
#define BCMA_CC_NAND_CMD_ADDR 0x0C0C
#define BCMA_CC_NAND_CMD_END_ADDR 0x0C10
#define BCMA_CC_NAND_CS_NAND_SELECT 0x0C14
#define BCMA_CC_NAND_CS_NAND_XOR 0x0C18
#define BCMA_CC_NAND_SPARE_RD0 0x0C20
#define BCMA_CC_NAND_SPARE_RD4 0x0C24
#define BCMA_CC_NAND_SPARE_RD8 0x0C28
#define BCMA_CC_NAND_SPARE_RD12 0x0C2C
#define BCMA_CC_NAND_SPARE_WR0 0x0C30
#define BCMA_CC_NAND_SPARE_WR4 0x0C34
#define BCMA_CC_NAND_SPARE_WR8 0x0C38
#define BCMA_CC_NAND_SPARE_WR12 0x0C3C
#define BCMA_CC_NAND_ACC_CONTROL 0x0C40
#define BCMA_CC_NAND_CONFIG 0x0C48
#define BCMA_CC_NAND_TIMING_1 0x0C50
#define BCMA_CC_NAND_TIMING_2 0x0C54
#define BCMA_CC_NAND_SEMAPHORE 0x0C58
#define BCMA_CC_NAND_DEVID 0x0C60
#define BCMA_CC_NAND_DEVID_X 0x0C64
#define BCMA_CC_NAND_BLOCK_LOCK_STATUS 0x0C68
#define BCMA_CC_NAND_INTFC_STATUS 0x0C6C
#define BCMA_CC_NAND_ECC_CORR_ADDR_X 0x0C70
#define BCMA_CC_NAND_ECC_CORR_ADDR 0x0C74
#define BCMA_CC_NAND_ECC_UNC_ADDR_X 0x0C78
#define BCMA_CC_NAND_ECC_UNC_ADDR 0x0C7C
#define BCMA_CC_NAND_READ_ERROR_COUNT 0x0C80
#define BCMA_CC_NAND_CORR_STAT_THRESHOLD 0x0C84
#define BCMA_CC_NAND_READ_ADDR_X 0x0C90
#define BCMA_CC_NAND_READ_ADDR 0x0C94
#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR_X 0x0C98
#define BCMA_CC_NAND_PAGE_PROGRAM_ADDR 0x0C9C
#define BCMA_CC_NAND_COPY_BACK_ADDR_X 0x0CA0
#define BCMA_CC_NAND_COPY_BACK_ADDR 0x0CA4
#define BCMA_CC_NAND_BLOCK_ERASE_ADDR_X 0x0CA8
#define BCMA_CC_NAND_BLOCK_ERASE_ADDR 0x0CAC
#define BCMA_CC_NAND_INV_READ_ADDR_X 0x0CB0
#define BCMA_CC_NAND_INV_READ_ADDR 0x0CB4
#define BCMA_CC_NAND_BLK_WR_PROTECT 0x0CC0
#define BCMA_CC_NAND_ACC_CONTROL_CS1 0x0CD0
#define BCMA_CC_NAND_CONFIG_CS1 0x0CD4
#define BCMA_CC_NAND_TIMING_1_CS1 0x0CD8
#define BCMA_CC_NAND_TIMING_2_CS1 0x0CDC
#define BCMA_CC_NAND_SPARE_RD16 0x0D30
#define BCMA_CC_NAND_SPARE_RD20 0x0D34
#define BCMA_CC_NAND_SPARE_RD24 0x0D38
#define BCMA_CC_NAND_SPARE_RD28 0x0D3C
#define BCMA_CC_NAND_CACHE_ADDR 0x0D40
#define BCMA_CC_NAND_CACHE_DATA 0x0D44
#define BCMA_CC_NAND_CTRL_CONFIG 0x0D48
#define BCMA_CC_NAND_CTRL_STATUS 0x0D4C
/* Divider allocation in 4716/47162/5356 */
#define BCMA_CC_PMU5_MAINPLL_CPU 1
@ -415,6 +493,13 @@
/* 4313 Chip specific ChipControl register bits */
#define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */
/* BCM5357 ChipControl register bits */
#define BCMA_CHIPCTL_5357_EXTPA BIT(14)
#define BCMA_CHIPCTL_5357_ANT_MUX_2O3 BIT(15)
#define BCMA_CHIPCTL_5357_NFLASH BIT(16)
#define BCMA_CHIPCTL_5357_I2S_PINS_ENABLE BIT(18)
#define BCMA_CHIPCTL_5357_I2CSPI_PINS_ENABLE BIT(19)
/* Data for the PMU, if available.
* Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
*/

View File

@ -11,11 +11,13 @@
#define BCMA_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
#define BCMA_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
#define BCMA_CLKCTLST_EXTRESREQ 0x00000700 /* Mask of external resource requests */
#define BCMA_CLKCTLST_EXTRESREQ_SHIFT 8
#define BCMA_CLKCTLST_HAVEALP 0x00010000 /* ALP available */
#define BCMA_CLKCTLST_HAVEHT 0x00020000 /* HT available */
#define BCMA_CLKCTLST_BP_ON_ALP 0x00040000 /* RO: running on ALP clock */
#define BCMA_CLKCTLST_BP_ON_HT 0x00080000 /* RO: running on HT clock */
#define BCMA_CLKCTLST_EXTRESST 0x07000000 /* Mask of external resource status */
#define BCMA_CLKCTLST_EXTRESST_SHIFT 24
/* Is there any BCM4328 on BCMA bus? */
#define BCMA_CLKCTLST_4328A0_HAVEHT 0x00010000 /* 4328a0 has reversed bits */
#define BCMA_CLKCTLST_4328A0_HAVEALP 0x00020000 /* 4328a0 has reversed bits */

View File

@ -504,7 +504,9 @@
#define SSB_CHIPCO_FLASHCTL_ST_SE 0x02D8 /* Sector Erase */
#define SSB_CHIPCO_FLASHCTL_ST_BE 0x00C7 /* Bulk Erase */
#define SSB_CHIPCO_FLASHCTL_ST_DP 0x00B9 /* Deep Power-down */
#define SSB_CHIPCO_FLASHCTL_ST_RSIG 0x03AB /* Read Electronic Signature */
#define SSB_CHIPCO_FLASHCTL_ST_RES 0x03AB /* Read Electronic Signature */
#define SSB_CHIPCO_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */
#define SSB_CHIPCO_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */
/* Status register bits for ST flashes */
#define SSB_CHIPCO_FLASHSTA_ST_WIP 0x01 /* Write In Progress */

View File

@ -27,6 +27,7 @@
#include <linux/poll.h>
#include <net/sock.h>
#include <linux/seq_file.h>
#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31
@ -202,6 +203,10 @@ enum {
struct bt_sock_list {
struct hlist_head head;
rwlock_t lock;
#ifdef CONFIG_PROC_FS
struct file_operations fops;
int (* custom_seq_show)(struct seq_file *, void *);
#endif
};
int bt_sock_register(int proto, const struct net_proto_family *ops);
@ -292,6 +297,11 @@ extern void hci_sock_cleanup(void);
extern int bt_sysfs_init(void);
extern void bt_sysfs_cleanup(void);
extern int bt_procfs_init(struct module* module, struct net *net, const char *name,
struct bt_sock_list* sk_list,
int (* seq_show)(struct seq_file *, void *));
extern void bt_procfs_cleanup(struct net *net, const char *name);
extern struct dentry *bt_debugfs;
int l2cap_init(void);

View File

@ -62,6 +62,15 @@
/* First BR/EDR Controller shall have ID = 0 */
#define HCI_BREDR_ID 0
/* AMP controller status */
#define AMP_CTRL_POWERED_DOWN 0x00
#define AMP_CTRL_BLUETOOTH_ONLY 0x01
#define AMP_CTRL_NO_CAPACITY 0x02
#define AMP_CTRL_LOW_CAPACITY 0x03
#define AMP_CTRL_MEDIUM_CAPACITY 0x04
#define AMP_CTRL_HIGH_CAPACITY 0x05
#define AMP_CTRL_FULL_CAPACITY 0x06
/* HCI device quirks */
enum {
HCI_QUIRK_RESET_ON_CLOSE,
@ -1295,6 +1304,8 @@ struct hci_ev_num_comp_blocks {
} __packed;
/* Low energy meta events */
#define LE_CONN_ROLE_MASTER 0x00
#define HCI_EV_LE_CONN_COMPLETE 0x01
struct hci_ev_le_conn_complete {
__u8 status;

View File

@ -115,12 +115,6 @@ struct oob_data {
u8 randomizer[16];
};
struct adv_entry {
struct list_head list;
bdaddr_t bdaddr;
u8 bdaddr_type;
};
struct le_scan_params {
u8 type;
u16 interval;
@ -356,16 +350,16 @@ extern rwlock_t hci_cb_list_lock;
/* ----- HCI interface to upper protocols ----- */
extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern void l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern int l2cap_disconn_ind(struct hci_conn *hcon);
extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
u16 flags);
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern void sco_connect_cfm(struct hci_conn *hcon, __u8 status);
extern void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);
/* ----- Inquiry cache ----- */
@ -587,8 +581,7 @@ void hci_conn_put_device(struct hci_conn *conn);
static inline void hci_conn_hold(struct hci_conn *conn)
{
BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt),
atomic_read(&conn->refcnt) + 1);
BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
atomic_inc(&conn->refcnt);
cancel_delayed_work(&conn->disc_work);
@ -596,8 +589,7 @@ static inline void hci_conn_hold(struct hci_conn *conn)
static inline void hci_conn_put(struct hci_conn *conn)
{
BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt),
atomic_read(&conn->refcnt) - 1);
BT_DBG("hcon %p orig refcnt %d", conn, atomic_read(&conn->refcnt));
if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo;
@ -1056,7 +1048,7 @@ int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
int mgmt_interleaved_discovery(struct hci_dev *hdev);
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
bool mgmt_valid_hdev(struct hci_dev *hdev);
int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent);
/* HCI info for socket */

View File

@ -671,20 +671,8 @@ enum {
L2CAP_EV_RECV_FRAME,
};
static inline void l2cap_chan_hold(struct l2cap_chan *c)
{
BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
atomic_inc(&c->refcnt);
}
static inline void l2cap_chan_put(struct l2cap_chan *c)
{
BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
if (atomic_dec_and_test(&c->refcnt))
kfree(c);
}
void l2cap_chan_hold(struct l2cap_chan *c);
void l2cap_chan_put(struct l2cap_chan *c);
static inline void l2cap_chan_lock(struct l2cap_chan *chan)
{
@ -771,7 +759,6 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
struct l2cap_chan *l2cap_chan_create(void);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
bdaddr_t *dst, u8 dst_type);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,

View File

@ -108,8 +108,8 @@ struct smp_cmd_security_req {
#define SMP_CONFIRM_FAILED 0x04
#define SMP_PAIRING_NOTSUPP 0x05
#define SMP_ENC_KEY_SIZE 0x06
#define SMP_CMD_NOTSUPP 0x07
#define SMP_UNSPECIFIED 0x08
#define SMP_CMD_NOTSUPP 0x07
#define SMP_UNSPECIFIED 0x08
#define SMP_REPEATED_ATTEMPTS 0x09
#define SMP_MIN_ENC_KEY_SIZE 7
@ -123,8 +123,8 @@ struct smp_chan {
struct l2cap_conn *conn;
u8 preq[7]; /* SMP Pairing Request */
u8 prsp[7]; /* SMP Pairing Response */
u8 prnd[16]; /* SMP Pairing Random (local) */
u8 rrnd[16]; /* SMP Pairing Random (remote) */
u8 prnd[16]; /* SMP Pairing Random (local) */
u8 rrnd[16]; /* SMP Pairing Random (remote) */
u8 pcnf[16]; /* SMP Pairing Confirm */
u8 tk[16]; /* SMP Temporary Key */
u8 enc_key_size;

View File

@ -316,7 +316,7 @@ send_rsp:
static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
BT_DBG("ident %d code %d", hdr->ident, hdr->code);
BT_DBG("ident %d code 0x%2.2x", hdr->ident, hdr->code);
skb_pull(skb, le16_to_cpu(hdr->len));
return 0;
@ -325,17 +325,19 @@ static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
/* Handle A2MP signalling */
static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct a2mp_cmd *hdr = (void *) skb->data;
struct a2mp_cmd *hdr;
struct amp_mgr *mgr = chan->data;
int err = 0;
amp_mgr_get(mgr);
while (skb->len >= sizeof(*hdr)) {
struct a2mp_cmd *hdr = (void *) skb->data;
u16 len = le16_to_cpu(hdr->len);
u16 len;
BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
hdr = (void *) skb->data;
len = le16_to_cpu(hdr->len);
BT_DBG("code 0x%2.2x id %d len %u", hdr->code, hdr->ident, len);
skb_pull(skb, sizeof(*hdr));
@ -393,7 +395,9 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
if (err) {
struct a2mp_cmd_rej rej;
rej.reason = __constant_cpu_to_le16(0);
hdr = (void *) skb->data;
BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
@ -412,7 +416,7 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
static void a2mp_chan_close_cb(struct l2cap_chan *chan)
{
l2cap_chan_destroy(chan);
l2cap_chan_put(chan);
}
static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)

View File

@ -28,6 +28,7 @@
#include <asm/ioctls.h>
#include <net/bluetooth/bluetooth.h>
#include <linux/proc_fs.h>
#define VERSION "2.16"
@ -532,6 +533,146 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
}
EXPORT_SYMBOL(bt_sock_wait_state);
#ifdef CONFIG_PROC_FS
struct bt_seq_state {
struct bt_sock_list *l;
};
static void *bt_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(seq->private->l->lock)
{
struct bt_seq_state *s = seq->private;
struct bt_sock_list *l = s->l;
read_lock(&l->lock);
return seq_hlist_start_head(&l->head, *pos);
}
static void *bt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct bt_seq_state *s = seq->private;
struct bt_sock_list *l = s->l;
return seq_hlist_next(v, &l->head, pos);
}
static void bt_seq_stop(struct seq_file *seq, void *v)
__releases(seq->private->l->lock)
{
struct bt_seq_state *s = seq->private;
struct bt_sock_list *l = s->l;
read_unlock(&l->lock);
}
static int bt_seq_show(struct seq_file *seq, void *v)
{
struct sock *sk;
struct bt_sock *bt;
struct bt_seq_state *s = seq->private;
struct bt_sock_list *l = s->l;
bdaddr_t src_baswapped, dst_baswapped;
if (v == SEQ_START_TOKEN) {
seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent");
if (l->custom_seq_show) {
seq_putc(seq, ' ');
l->custom_seq_show(seq, v);
}
seq_putc(seq, '\n');
} else {
sk = sk_entry(v);
bt = bt_sk(sk);
baswap(&src_baswapped, &bt->src);
baswap(&dst_baswapped, &bt->dst);
seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu",
sk,
atomic_read(&sk->sk_refcnt),
sk_rmem_alloc_get(sk),
sk_wmem_alloc_get(sk),
sock_i_uid(sk),
sock_i_ino(sk),
&src_baswapped,
&dst_baswapped,
bt->parent? sock_i_ino(bt->parent): 0LU);
if (l->custom_seq_show) {
seq_putc(seq, ' ');
l->custom_seq_show(seq, v);
}
seq_putc(seq, '\n');
}
return 0;
}
static struct seq_operations bt_seq_ops = {
.start = bt_seq_start,
.next = bt_seq_next,
.stop = bt_seq_stop,
.show = bt_seq_show,
};
static int bt_seq_open(struct inode *inode, struct file *file)
{
struct bt_sock_list *sk_list;
struct bt_seq_state *s;
sk_list = PDE(inode)->data;
s = __seq_open_private(file, &bt_seq_ops,
sizeof(struct bt_seq_state));
if (s == NULL)
return -ENOMEM;
s->l = sk_list;
return 0;
}
int bt_procfs_init(struct module* module, struct net *net, const char *name,
struct bt_sock_list* sk_list,
int (* seq_show)(struct seq_file *, void *))
{
struct proc_dir_entry * pde;
sk_list->custom_seq_show = seq_show;
sk_list->fops.owner = module;
sk_list->fops.open = bt_seq_open;
sk_list->fops.read = seq_read;
sk_list->fops.llseek = seq_lseek;
sk_list->fops.release = seq_release_private;
pde = proc_net_fops_create(net, name, 0, &sk_list->fops);
if (pde == NULL)
return -ENOMEM;
pde->data = sk_list;
return 0;
}
void bt_procfs_cleanup(struct net *net, const char *name)
{
proc_net_remove(net, name);
}
#else
int bt_procfs_init(struct module* module, struct net *net, const char *name,
struct bt_sock_list* sk_list,
int (* seq_show)(struct seq_file *, void *))
{
return 0;
}
void bt_procfs_cleanup(struct net *net, const char *name)
{
}
#endif
EXPORT_SYMBOL(bt_procfs_init);
EXPORT_SYMBOL(bt_procfs_cleanup);
static struct net_proto_family bt_sock_family_ops = {
.owner = THIS_MODULE,
.family = PF_BLUETOOTH,

View File

@ -29,6 +29,10 @@
#include "bnep.h"
static struct bt_sock_list bnep_sk_list = {
.lock = __RW_LOCK_UNLOCKED(bnep_sk_list.lock)
};
static int bnep_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@ -38,6 +42,8 @@ static int bnep_sock_release(struct socket *sock)
if (!sk)
return 0;
bt_sock_unlink(&bnep_sk_list, sk);
sock_orphan(sk);
sock_put(sk);
return 0;
@ -204,6 +210,7 @@ static int bnep_sock_create(struct net *net, struct socket *sock, int protocol,
sk->sk_protocol = protocol;
sk->sk_state = BT_OPEN;
bt_sock_link(&bnep_sk_list, sk);
return 0;
}
@ -222,19 +229,30 @@ int __init bnep_sock_init(void)
return err;
err = bt_sock_register(BTPROTO_BNEP, &bnep_sock_family_ops);
if (err < 0)
if (err < 0) {
BT_ERR("Can't register BNEP socket");
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "bnep", &bnep_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create BNEP proc file");
bt_sock_unregister(BTPROTO_BNEP);
goto error;
}
BT_INFO("BNEP socket layer initialized");
return 0;
error:
BT_ERR("Can't register BNEP socket");
proto_unregister(&bnep_proto);
return err;
}
void __exit bnep_sock_cleanup(void)
{
bt_procfs_cleanup(&init_net, "bnep");
if (bt_sock_unregister(BTPROTO_BNEP) < 0)
BT_ERR("Can't unregister BNEP socket");

View File

@ -42,6 +42,10 @@
#include "cmtp.h"
static struct bt_sock_list cmtp_sk_list = {
.lock = __RW_LOCK_UNLOCKED(cmtp_sk_list.lock)
};
static int cmtp_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@ -51,6 +55,8 @@ static int cmtp_sock_release(struct socket *sock)
if (!sk)
return 0;
bt_sock_unlink(&cmtp_sk_list, sk);
sock_orphan(sk);
sock_put(sk);
@ -214,6 +220,8 @@ static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol,
sk->sk_protocol = protocol;
sk->sk_state = BT_OPEN;
bt_sock_link(&cmtp_sk_list, sk);
return 0;
}
@ -232,19 +240,30 @@ int cmtp_init_sockets(void)
return err;
err = bt_sock_register(BTPROTO_CMTP, &cmtp_sock_family_ops);
if (err < 0)
if (err < 0) {
BT_ERR("Can't register CMTP socket");
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "cmtp", &cmtp_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create CMTP proc file");
bt_sock_unregister(BTPROTO_HIDP);
goto error;
}
BT_INFO("CMTP socket layer initialized");
return 0;
error:
BT_ERR("Can't register CMTP socket");
proto_unregister(&cmtp_proto);
return err;
}
void cmtp_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "cmtp");
if (bt_sock_unregister(BTPROTO_CMTP) < 0)
BT_ERR("Can't unregister CMTP socket");

View File

@ -696,7 +696,8 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
if (!test_bit(HCI_SETUP, &hdev->dev_flags)) {
if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
mgmt_powered(hdev, 1);
hci_dev_unlock(hdev);
@ -797,7 +798,8 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */
hdev->close(hdev);
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
if (!test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags) &&
mgmt_valid_hdev(hdev)) {
hci_dev_lock(hdev);
mgmt_powered(hdev, 0);
hci_dev_unlock(hdev);

View File

@ -513,7 +513,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
if (hdev->features[3] & LMP_RSSI_INQ)
events[4] |= 0x02; /* Inquiry Result with RSSI */
if (hdev->features[5] & LMP_SNIFF_SUBR)
if (lmp_sniffsubr_capable(hdev))
events[5] |= 0x20; /* Sniff Subrating */
if (hdev->features[5] & LMP_PAUSE_ENC)
@ -522,13 +522,13 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
if (hdev->features[6] & LMP_EXT_INQ)
events[5] |= 0x40; /* Extended Inquiry Result */
if (hdev->features[6] & LMP_NO_FLUSH)
if (lmp_no_flush_capable(hdev))
events[7] |= 0x01; /* Enhanced Flush Complete */
if (hdev->features[7] & LMP_LSTO)
events[6] |= 0x80; /* Link Supervision Timeout Changed */
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
if (lmp_ssp_capable(hdev)) {
events[6] |= 0x01; /* IO Capability Request */
events[6] |= 0x02; /* IO Capability Response */
events[6] |= 0x04; /* User Confirmation Request */
@ -541,7 +541,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
* Features Notification */
}
if (hdev->features[4] & LMP_LE)
if (lmp_le_capable(hdev))
events[7] |= 0x20; /* LE Meta-Event */
hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
@ -623,11 +623,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
struct hci_cp_write_def_link_policy cp;
u16 link_policy = 0;
if (hdev->features[0] & LMP_RSWITCH)
if (lmp_rswitch_capable(hdev))
link_policy |= HCI_LP_RSWITCH;
if (hdev->features[0] & LMP_HOLD)
link_policy |= HCI_LP_HOLD;
if (hdev->features[0] & LMP_SNIFF)
if (lmp_sniff_capable(hdev))
link_policy |= HCI_LP_SNIFF;
if (hdev->features[1] & LMP_PARK)
link_policy |= HCI_LP_PARK;
@ -686,7 +686,7 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
hdev->esco_type |= (ESCO_HV3);
}
if (hdev->features[3] & LMP_ESCO)
if (lmp_esco_capable(hdev))
hdev->esco_type |= (ESCO_EV3);
if (hdev->features[4] & LMP_EV4)
@ -746,7 +746,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
break;
}
if (test_bit(HCI_INIT, &hdev->flags) && hdev->features[4] & LMP_LE)
if (test_bit(HCI_INIT, &hdev->flags) && lmp_le_capable(hdev))
hci_set_le_support(hdev);
done:
@ -1614,43 +1614,30 @@ static void hci_cs_disconnect(struct hci_dev *hdev, u8 status)
static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
{
struct hci_cp_le_create_conn *cp;
struct hci_conn *conn;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
if (!cp)
return;
hci_dev_lock(hdev);
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr),
conn);
if (status) {
if (conn && conn->state == BT_CONNECT) {
conn->state = BT_CLOSED;
mgmt_connect_failed(hdev, &cp->peer_addr, conn->type,
conn->dst_type, status);
hci_proto_connect_cfm(conn, status);
hci_conn_del(conn);
}
} else {
if (!conn) {
conn = hci_conn_add(hdev, LE_LINK, &cp->peer_addr);
if (conn) {
conn->dst_type = cp->peer_addr_type;
conn->out = true;
} else {
BT_ERR("No memory for new connection");
}
}
}
hci_dev_lock(hdev);
hci_dev_unlock(hdev);
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
if (!conn) {
hci_dev_unlock(hdev);
return;
}
BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst),
conn);
conn->state = BT_CLOSED;
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, status);
hci_proto_connect_cfm(conn, status);
hci_conn_del(conn);
hci_dev_unlock(hdev);
}
}
static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
@ -3252,12 +3239,8 @@ static void hci_user_passkey_request_evt(struct hci_dev *hdev,
BT_DBG("%s", hdev->name);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->dev_flags))
mgmt_user_passkey_request(hdev, &ev->bdaddr, ACL_LINK, 0);
hci_dev_unlock(hdev);
}
static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
@ -3350,11 +3333,23 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_dev_lock(hdev);
if (ev->status) {
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
if (!conn)
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
if (!conn) {
conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
BT_ERR("No memory for new connection");
goto unlock;
}
conn->dst_type = ev->bdaddr_type;
if (ev->role == LE_CONN_ROLE_MASTER) {
conn->out = true;
conn->link_mode |= HCI_LM_MASTER;
}
}
if (ev->status) {
mgmt_connect_failed(hdev, &conn->dst, conn->type,
conn->dst_type, ev->status);
hci_proto_connect_cfm(conn, ev->status);
@ -3363,18 +3358,6 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
goto unlock;
}
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
if (!conn) {
BT_ERR("No memory for new connection");
hci_dev_unlock(hdev);
return;
}
conn->dst_type = ev->bdaddr_type;
}
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
conn->dst_type, 0, NULL, 0, NULL);

View File

@ -1100,21 +1100,30 @@ int __init hci_sock_init(void)
return err;
err = bt_sock_register(BTPROTO_HCI, &hci_sock_family_ops);
if (err < 0)
if (err < 0) {
BT_ERR("HCI socket registration failed");
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "hci", &hci_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create HCI proc file");
bt_sock_unregister(BTPROTO_HCI);
goto error;
}
BT_INFO("HCI socket layer initialized");
return 0;
error:
BT_ERR("HCI socket registration failed");
proto_unregister(&hci_sk_proto);
return err;
}
void hci_sock_cleanup(void)
{
bt_procfs_cleanup(&init_net, "hci");
if (bt_sock_unregister(BTPROTO_HCI) < 0)
BT_ERR("HCI socket unregistration failed");

View File

@ -25,6 +25,10 @@
#include "hidp.h"
static struct bt_sock_list hidp_sk_list = {
.lock = __RW_LOCK_UNLOCKED(hidp_sk_list.lock)
};
static int hidp_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@ -34,6 +38,8 @@ static int hidp_sock_release(struct socket *sock)
if (!sk)
return 0;
bt_sock_unlink(&hidp_sk_list, sk);
sock_orphan(sk);
sock_put(sk);
@ -253,6 +259,8 @@ static int hidp_sock_create(struct net *net, struct socket *sock, int protocol,
sk->sk_protocol = protocol;
sk->sk_state = BT_OPEN;
bt_sock_link(&hidp_sk_list, sk);
return 0;
}
@ -271,8 +279,19 @@ int __init hidp_init_sockets(void)
return err;
err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
if (err < 0)
if (err < 0) {
BT_ERR("Can't register HIDP socket");
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "hidp", &hidp_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create HIDP proc file");
bt_sock_unregister(BTPROTO_HIDP);
goto error;
}
BT_INFO("HIDP socket layer initialized");
return 0;
@ -284,6 +303,7 @@ error:
void __exit hidp_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "hidp");
if (bt_sock_unregister(BTPROTO_HIDP) < 0)
BT_ERR("Can't unregister HIDP socket");

View File

@ -416,13 +416,30 @@ struct l2cap_chan *l2cap_chan_create(void)
return chan;
}
void l2cap_chan_destroy(struct l2cap_chan *chan)
static void l2cap_chan_destroy(struct l2cap_chan *chan)
{
BT_DBG("chan %p", chan);
write_lock(&chan_list_lock);
list_del(&chan->global_l);
write_unlock(&chan_list_lock);
l2cap_chan_put(chan);
kfree(chan);
}
void l2cap_chan_hold(struct l2cap_chan *c)
{
BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
atomic_inc(&c->refcnt);
}
void l2cap_chan_put(struct l2cap_chan *c)
{
BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt));
if (atomic_dec_and_test(&c->refcnt))
l2cap_chan_destroy(c);
}
void l2cap_chan_set_defaults(struct l2cap_chan *chan)
@ -5329,7 +5346,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
return exact ? lm1 : lm2;
}
int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{
struct l2cap_conn *conn;
@ -5342,7 +5359,6 @@ int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
} else
l2cap_conn_del(hcon, bt_to_errno(status));
return 0;
}
int l2cap_disconn_ind(struct hci_conn *hcon)
@ -5356,12 +5372,11 @@ int l2cap_disconn_ind(struct hci_conn *hcon)
return conn->disc_reason;
}
int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
l2cap_conn_del(hcon, bt_to_errno(reason));
return 0;
}
static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
@ -5404,6 +5419,11 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid,
state_to_string(chan->state));
if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
l2cap_chan_unlock(chan);
continue;
}
if (chan->scid == L2CAP_CID_LE_DATA) {
if (!status && encrypt) {
chan->sec_level = hcon->sec_level;

View File

@ -34,6 +34,10 @@
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/smp.h>
static struct bt_sock_list l2cap_sk_list = {
.lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
};
static const struct proto_ops l2cap_sock_ops;
static void l2cap_sock_init(struct sock *sk, struct sock *parent);
static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
@ -823,7 +827,7 @@ static void l2cap_sock_kill(struct sock *sk)
/* Kill poor orphan */
l2cap_chan_destroy(l2cap_pi(sk)->chan);
l2cap_chan_put(l2cap_pi(sk)->chan);
sock_set_flag(sk, SOCK_DEAD);
sock_put(sk);
}
@ -886,6 +890,8 @@ static int l2cap_sock_release(struct socket *sock)
if (!sk)
return 0;
bt_sock_unlink(&l2cap_sk_list, sk);
err = l2cap_sock_shutdown(sock, 2);
sock_orphan(sk);
@ -1210,6 +1216,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
return -ENOMEM;
l2cap_sock_init(sk, NULL);
bt_sock_link(&l2cap_sk_list, sk);
return 0;
}
@ -1248,21 +1255,30 @@ int __init l2cap_init_sockets(void)
return err;
err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
if (err < 0)
if (err < 0) {
BT_ERR("L2CAP socket registration failed");
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create L2CAP proc file");
bt_sock_unregister(BTPROTO_L2CAP);
goto error;
}
BT_INFO("L2CAP socket layer initialized");
return 0;
error:
BT_ERR("L2CAP socket registration failed");
proto_unregister(&l2cap_proto);
return err;
}
void l2cap_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "l2cap");
if (bt_sock_unregister(BTPROTO_L2CAP) < 0)
BT_ERR("L2CAP socket unregistration failed");

View File

@ -193,6 +193,11 @@ static u8 mgmt_status_table[] = {
MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
};
bool mgmt_valid_hdev(struct hci_dev *hdev)
{
return hdev->dev_type == HCI_BREDR;
}
static u8 mgmt_status(u8 hci_status)
{
if (hci_status < ARRAY_SIZE(mgmt_status_table))
@ -317,7 +322,6 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len)
{
struct mgmt_rp_read_index_list *rp;
struct list_head *p;
struct hci_dev *d;
size_t rp_len;
u16 count;
@ -328,7 +332,10 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
read_lock(&hci_dev_list_lock);
count = 0;
list_for_each(p, &hci_dev_list) {
list_for_each_entry(d, &hci_dev_list, list) {
if (!mgmt_valid_hdev(d))
continue;
count++;
}
@ -346,6 +353,9 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
if (test_bit(HCI_SETUP, &d->dev_flags))
continue;
if (!mgmt_valid_hdev(d))
continue;
rp->index[i++] = cpu_to_le16(d->id);
BT_DBG("Added hci%u", d->id);
}
@ -370,10 +380,10 @@ static u32 get_supported_settings(struct hci_dev *hdev)
settings |= MGMT_SETTING_DISCOVERABLE;
settings |= MGMT_SETTING_PAIRABLE;
if (hdev->features[6] & LMP_SIMPLE_PAIR)
if (lmp_ssp_capable(hdev))
settings |= MGMT_SETTING_SSP;
if (!(hdev->features[4] & LMP_NO_BREDR)) {
if (lmp_bredr_capable(hdev)) {
settings |= MGMT_SETTING_BREDR;
settings |= MGMT_SETTING_LINK_SECURITY;
}
@ -381,7 +391,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
if (enable_hs)
settings |= MGMT_SETTING_HS;
if (hdev->features[4] & LMP_LE)
if (lmp_le_capable(hdev))
settings |= MGMT_SETTING_LE;
return settings;
@ -403,7 +413,7 @@ static u32 get_current_settings(struct hci_dev *hdev)
if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
settings |= MGMT_SETTING_PAIRABLE;
if (!(hdev->features[4] & LMP_NO_BREDR))
if (lmp_bredr_capable(hdev))
settings |= MGMT_SETTING_BREDR;
if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
@ -1111,7 +1121,7 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_lock(hdev);
if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
if (!lmp_ssp_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
MGMT_STATUS_NOT_SUPPORTED);
goto failed;
@ -1195,7 +1205,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
hci_dev_lock(hdev);
if (!(hdev->features[4] & LMP_LE)) {
if (!lmp_le_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
MGMT_STATUS_NOT_SUPPORTED);
goto unlock;
@ -2191,7 +2201,7 @@ static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
goto unlock;
}
if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
if (!lmp_ssp_capable(hdev)) {
err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
MGMT_STATUS_NOT_SUPPORTED);
goto unlock;
@ -2820,6 +2830,9 @@ static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
int mgmt_index_added(struct hci_dev *hdev)
{
if (!mgmt_valid_hdev(hdev))
return -ENOTSUPP;
return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
}
@ -2827,6 +2840,9 @@ int mgmt_index_removed(struct hci_dev *hdev)
{
u8 status = MGMT_STATUS_INVALID_INDEX;
if (!mgmt_valid_hdev(hdev))
return -ENOTSUPP;
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);

View File

@ -1033,8 +1033,17 @@ int __init rfcomm_init_sockets(void)
return err;
err = bt_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops);
if (err < 0)
if (err < 0) {
BT_ERR("RFCOMM socket layer registration failed");
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "rfcomm", &rfcomm_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create RFCOMM proc file");
bt_sock_unregister(BTPROTO_RFCOMM);
goto error;
}
if (bt_debugfs) {
rfcomm_sock_debugfs = debugfs_create_file("rfcomm", 0444,
@ -1048,13 +1057,14 @@ int __init rfcomm_init_sockets(void)
return 0;
error:
BT_ERR("RFCOMM socket layer registration failed");
proto_unregister(&rfcomm_proto);
return err;
}
void __exit rfcomm_cleanup_sockets(void)
{
bt_procfs_cleanup(&init_net, "rfcomm");
debugfs_remove(rfcomm_sock_debugfs);
if (bt_sock_unregister(BTPROTO_RFCOMM) < 0)

View File

@ -913,7 +913,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
return lm;
}
int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
{
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
if (!status) {
@ -924,16 +924,13 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
sco_conn_ready(conn);
} else
sco_conn_del(hcon, bt_to_errno(status));
return 0;
}
int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
void sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
sco_conn_del(hcon, bt_to_errno(reason));
return 0;
}
int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
@ -1026,6 +1023,13 @@ int __init sco_init(void)
goto error;
}
err = bt_procfs_init(THIS_MODULE, &init_net, "sco", &sco_sk_list, NULL);
if (err < 0) {
BT_ERR("Failed to create SCO proc file");
bt_sock_unregister(BTPROTO_SCO);
goto error;
}
if (bt_debugfs) {
sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
NULL, &sco_debugfs_fops);
@ -1044,6 +1048,8 @@ error:
void __exit sco_exit(void)
{
bt_procfs_cleanup(&init_net, "sco");
debugfs_remove(sco_debugfs);
if (bt_sock_unregister(BTPROTO_SCO) < 0)

View File

@ -136,10 +136,13 @@ bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
* mesh_accept_plinks_update - update accepting_plink in local mesh beacons
*
* @sdata: mesh interface in which mesh beacons are going to be updated
*
* Returns: beacon changed flag if the beacon content changed.
*/
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
{
bool free_plinks;
u32 changed = 0;
/* In case mesh_plink_free_count > 0 and mesh_plinktbl_capacity == 0,
* the mesh interface might be able to establish plinks with peers that
@ -149,8 +152,12 @@ void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata)
*/
free_plinks = mesh_plink_availables(sdata);
if (free_plinks != sdata->u.mesh.accepting_plinks)
ieee80211_mesh_housekeeping_timer((unsigned long) sdata);
if (free_plinks != sdata->u.mesh.accepting_plinks) {
sdata->u.mesh.accepting_plinks = free_plinks;
changed = BSS_CHANGED_BEACON;
}
return changed;
}
int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
@ -262,7 +269,6 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
neighbors = (neighbors > 15) ? 15 : neighbors;
*pos++ = neighbors << 1;
/* Mesh capability */
ifmsh->accepting_plinks = mesh_plink_availables(sdata);
*pos = MESHCONF_CAPAB_FORWARDING;
*pos |= ifmsh->accepting_plinks ?
MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
@ -521,14 +527,13 @@ int ieee80211_new_mesh_header(struct ieee80211s_hdr *meshhdr,
static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata,
struct ieee80211_if_mesh *ifmsh)
{
bool free_plinks;
u32 changed;
ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT);
mesh_path_expire(sdata);
free_plinks = mesh_plink_availables(sdata);
if (free_plinks != sdata->u.mesh.accepting_plinks)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
changed = mesh_accept_plinks_update(sdata);
ieee80211_bss_info_change_notify(sdata, changed);
mod_timer(&ifmsh->housekeeping_timer,
round_jiffies(jiffies + IEEE80211_MESH_HOUSEKEEPING_INTERVAL));

View File

@ -282,7 +282,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata,
u8 *hw_addr,
struct ieee802_11_elems *ie);
bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie);
void mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
u32 mesh_accept_plinks_update(struct ieee80211_sub_if_data *sdata);
void mesh_plink_broken(struct sta_info *sta);
void mesh_plink_deactivate(struct sta_info *sta);
int mesh_plink_open(struct sta_info *sta);

View File

@ -48,17 +48,17 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
u8 *da, __le16 llid, __le16 plid, __le16 reason);
static inline
void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
u32 mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_inc(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
return mesh_accept_plinks_update(sdata);
}
static inline
void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
u32 mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata)
{
atomic_dec(&sdata->u.mesh.mshstats.estab_plinks);
mesh_accept_plinks_update(sdata);
return mesh_accept_plinks_update(sdata);
}
/**
@ -170,22 +170,21 @@ out:
* @sta: mesh peer link to deactivate
*
* All mesh paths with this peer as next hop will be flushed
* Returns beacon changed flag if the beacon content changed.
*
* Locking: the caller must hold sta->lock
*/
static bool __mesh_plink_deactivate(struct sta_info *sta)
static u32 __mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
bool deactivated = false;
u32 changed = 0;
if (sta->plink_state == NL80211_PLINK_ESTAB) {
mesh_plink_dec_estab_count(sdata);
deactivated = true;
}
if (sta->plink_state == NL80211_PLINK_ESTAB)
changed = mesh_plink_dec_estab_count(sdata);
sta->plink_state = NL80211_PLINK_BLOCKED;
mesh_path_flush_by_nexthop(sta);
return deactivated;
return changed;
}
/**
@ -198,18 +197,17 @@ static bool __mesh_plink_deactivate(struct sta_info *sta)
void mesh_plink_deactivate(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
bool deactivated;
u32 changed;
spin_lock_bh(&sta->lock);
deactivated = __mesh_plink_deactivate(sta);
changed = __mesh_plink_deactivate(sta);
sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, sta->llid, sta->plid,
sta->reason);
spin_unlock_bh(&sta->lock);
if (deactivated)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
ieee80211_bss_info_change_notify(sdata, changed);
}
static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
@ -541,15 +539,14 @@ int mesh_plink_open(struct sta_info *sta)
void mesh_plink_block(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
bool deactivated;
u32 changed;
spin_lock_bh(&sta->lock);
deactivated = __mesh_plink_deactivate(sta);
changed = __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_BLOCKED;
spin_unlock_bh(&sta->lock);
if (deactivated)
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
ieee80211_bss_info_change_notify(sdata, changed);
}
@ -852,9 +849,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
del_timer(&sta->plink_timer);
sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
mesh_plink_inc_estab_count(sdata);
changed |= mesh_plink_inc_estab_count(sdata);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= BSS_CHANGED_BEACON;
mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
break;
@ -888,9 +884,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
del_timer(&sta->plink_timer);
sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
mesh_plink_inc_estab_count(sdata);
changed |= mesh_plink_inc_estab_count(sdata);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= BSS_CHANGED_BEACON;
mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n",
sta->sta.addr);
mesh_plink_frame_tx(sdata,
@ -908,13 +903,12 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
case CLS_ACPT:
reason = cpu_to_le16(WLAN_REASON_MESH_CLOSE);
sta->reason = reason;
__mesh_plink_deactivate(sta);
changed |= __mesh_plink_deactivate(sta);
sta->plink_state = NL80211_PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
changed |= mesh_set_ht_prot_mode(sdata);
changed |= BSS_CHANGED_BEACON;
mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
sta->sta.addr, llid, plid, reason);
break;