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

Commit b0302aba authored by Larry Finger's avatar Larry Finger Committed by John W. Linville
Browse files

rtlwifi: Convert to asynchronous firmware load

This patch addresses a kernel bugzilla report and two recent mail threads.

The kernel bugzilla report is https://bugzilla.kernel.org/show_bug.cgi?id=42632,
which reports a udev timeout on boot.

The first mail thread, which was on LKML (http://lkml.indiana.edu/hypermail/
linux/kernel/1112.3/00965.html) was for a WARNING that occurs after a
suspend/resume cycle for rtl8192cu.

The scond mail thread (http://marc.info/?l=linux-wireless&m=132655490826766&w=2

)
concerned changes in udev that break drivers that delay while firmware is loaded
on modprobe.

This patch converts all rtlwifi-based drivers to use the asynchronous firmware
loading mechanism. Drivers rtl8192ce, rtl8192cu and rtl8192de share a common
callback routine. Driver rtl8192se needs different handling of the firmware,
thus it has its own code.

Signed-off-by: default avatarLarry Finger <Larry.Finger@lwfinger.net>
Cc: Stable <stable@vger.kernel.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent feced201
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -410,6 +410,7 @@ void rtl_init_rfkill(struct ieee80211_hw *hw)


	wiphy_rfkill_start_polling(hw->wiphy);
	wiphy_rfkill_start_polling(hw->wiphy);
}
}
EXPORT_SYMBOL(rtl_init_rfkill);


void rtl_deinit_rfkill(struct ieee80211_hw *hw)
void rtl_deinit_rfkill(struct ieee80211_hw *hw)
{
{
+45 −1
Original line number Original line Diff line number Diff line
@@ -31,8 +31,50 @@
#include "core.h"
#include "core.h"
#include "cam.h"
#include "cam.h"
#include "base.h"
#include "base.h"
#include "pci.h"
#include "ps.h"
#include "ps.h"


#include <linux/export.h>

void rtl_fw_cb(const struct firmware *firmware, void *context)
{
	struct ieee80211_hw *hw = context;
	struct rtl_priv *rtlpriv = rtl_priv(hw);
	int err;

	RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
			 "Firmware callback routine entered!\n");
	complete(&rtlpriv->firmware_loading_complete);
	if (!firmware) {
		pr_err("Firmware %s not available\n", rtlpriv->cfg->fw_name);
		rtlpriv->max_fw_size = 0;
		return;
	}
	if (firmware->size > rtlpriv->max_fw_size) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
			 "Firmware is too big!\n");
		release_firmware(firmware);
		return;
	}
	memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
	rtlpriv->rtlhal.fwsize = firmware->size;
	release_firmware(firmware);

	err = ieee80211_register_hw(hw);
	if (err) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
			 "Can't register mac80211 hw\n");
		return;
	} else {
		rtlpriv->mac80211.mac80211_registered = 1;
	}
	set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);

	/*init rfkill */
	rtl_init_rfkill(hw);
}
EXPORT_SYMBOL(rtl_fw_cb);

/*mutex for start & stop is must here. */
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
static int rtl_op_start(struct ieee80211_hw *hw)
{
{
@@ -254,10 +296,12 @@ static int rtl_op_config(struct ieee80211_hw *hw, u32 changed)
			 * because that will cause nullfunc send by mac80211
			 * because that will cause nullfunc send by mac80211
			 * fail, and cause pkt loss, we have tested that 5mA
			 * fail, and cause pkt loss, we have tested that 5mA
			 * is worked very well */
			 * is worked very well */
			if (!rtlpriv->psc.multi_buffered)
			if (!rtlpriv->psc.multi_buffered) {
				queue_delayed_work(rtlpriv->works.rtl_wq,
				queue_delayed_work(rtlpriv->works.rtl_wq,
						&rtlpriv->works.ps_work,
						&rtlpriv->works.ps_work,
						MSECS(5));
						MSECS(5));
				pr_info("In section\n");
			}
		} else {
		} else {
			rtl_swlps_rf_awake(hw);
			rtl_swlps_rf_awake(hw);
			rtlpriv->psc.sw_ps_enabled = false;
			rtlpriv->psc.sw_ps_enabled = false;
+2 −0
Original line number Original line Diff line number Diff line
@@ -40,4 +40,6 @@
#define RTL_SUPPORTED_CTRL_FILTER	0xFF
#define RTL_SUPPORTED_CTRL_FILTER	0xFF


extern const struct ieee80211_ops rtl_ops;
extern const struct ieee80211_ops rtl_ops;
void rtl_fw_cb(const struct firmware *firmware, void *context);

#endif
#endif
+9 −17
Original line number Original line Diff line number Diff line
@@ -1565,6 +1565,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)


	rtlpci->driver_is_goingto_unload = true;
	rtlpci->driver_is_goingto_unload = true;
	rtlpriv->cfg->ops->hw_disable(hw);
	rtlpriv->cfg->ops->hw_disable(hw);
	/* some things are not needed if firmware not available */
	if (!rtlpriv->max_fw_size)
		return;
	rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
	rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);


	spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
	spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
@@ -1779,6 +1782,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
	rtlpriv = hw->priv;
	rtlpriv = hw->priv;
	pcipriv = (void *)rtlpriv->priv;
	pcipriv = (void *)rtlpriv->priv;
	pcipriv->dev.pdev = pdev;
	pcipriv->dev.pdev = pdev;
	init_completion(&rtlpriv->firmware_loading_complete);


	/* init cfg & intf_ops */
	/* init cfg & intf_ops */
	rtlpriv->rtlhal.interface = INTF_PCI;
	rtlpriv->rtlhal.interface = INTF_PCI;
@@ -1799,7 +1803,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
	err = pci_request_regions(pdev, KBUILD_MODNAME);
	err = pci_request_regions(pdev, KBUILD_MODNAME);
	if (err) {
	if (err) {
		RT_ASSERT(false, "Can't obtain PCI resources\n");
		RT_ASSERT(false, "Can't obtain PCI resources\n");
		return err;
		goto fail2;
	}
	}


	pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
	pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
@@ -1862,15 +1866,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
		goto fail3;
		goto fail3;
	}
	}


	err = ieee80211_register_hw(hw);
	if (err) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
			 "Can't register mac80211 hw\n");
		goto fail3;
	} else {
		rtlpriv->mac80211.mac80211_registered = 1;
	}

	err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
	err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
	if (err) {
	if (err) {
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
		RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
@@ -1878,9 +1873,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
		goto fail3;
		goto fail3;
	}
	}


	/*init rfkill */
	rtl_init_rfkill(hw);

	rtlpci = rtl_pcidev(pcipriv);
	rtlpci = rtl_pcidev(pcipriv);
	err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
	err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
			  IRQF_SHARED, KBUILD_MODNAME, hw);
			  IRQF_SHARED, KBUILD_MODNAME, hw);
@@ -1889,24 +1881,22 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
			 "%s: failed to register IRQ handler\n",
			 "%s: failed to register IRQ handler\n",
			 wiphy_name(hw->wiphy));
			 wiphy_name(hw->wiphy));
		goto fail3;
		goto fail3;
	} else {
		rtlpci->irq_alloc = 1;
	}
	}
	rtlpci->irq_alloc = 1;


	set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
	return 0;
	return 0;


fail3:
fail3:
	pci_set_drvdata(pdev, NULL);
	pci_set_drvdata(pdev, NULL);
	rtl_deinit_core(hw);
	rtl_deinit_core(hw);
	_rtl_pci_io_handler_release(hw);
	_rtl_pci_io_handler_release(hw);
	ieee80211_free_hw(hw);


	if (rtlpriv->io.pci_mem_start != 0)
	if (rtlpriv->io.pci_mem_start != 0)
		pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
		pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);


fail2:
fail2:
	pci_release_regions(pdev);
	pci_release_regions(pdev);
	complete(&rtlpriv->firmware_loading_complete);


fail1:
fail1:


@@ -1925,6 +1915,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
	struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
	struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
	struct rtl_mac *rtlmac = rtl_mac(rtlpriv);


	/* just in case driver is removed before firmware callback */
	wait_for_completion(&rtlpriv->firmware_loading_complete);
	clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
	clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);


	sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);
	sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);
+0 −1
Original line number Original line Diff line number Diff line
@@ -239,7 +239,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
void rtl_pci_disconnect(struct pci_dev *pdev);
void rtl_pci_disconnect(struct pci_dev *pdev);
int rtl_pci_suspend(struct device *dev);
int rtl_pci_suspend(struct device *dev);
int rtl_pci_resume(struct device *dev);
int rtl_pci_resume(struct device *dev);

static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
static inline u8 pci_read8_sync(struct rtl_priv *rtlpriv, u32 addr)
{
{
	return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
	return readb((u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
Loading