diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2010-05-23 03:14:08 -0400 |
---|---|---|
committer | Reinette Chatre <reinette.chatre@intel.com> | 2010-06-06 02:02:39 -0400 |
commit | 7d47618a2ade0cb6d8a0b2597029c383c1662fa0 (patch) | |
tree | 6d1faddd085fc0ab444affaed93c92bde1ff0ff8 /drivers | |
parent | 9edc71b746efeaadc40e668964b76cda81fef386 (diff) |
iwlwifi: move sysfs_create_group to post request firmware
Move the sysfs_create_group to iwl_ucode_callback after we
have safely got the firmware.
The motivation to do this comes from a warning from lockdep which detected
that we request priv->mutex while holding s_active during a sysfs request
(show_statistics in the example copy pasted). The reverse order exists upon
request_firmware: request_firmware which is a sysfs operation
that requires s_active is run under priv->mutex.
This ensures that we don't get sysfs request before we finish to request
the firmware, avoiding this deadlock.
=======================================================
[ INFO: possible circular locking dependency detected ]
-------------------------------------------------------
cat/2595 is trying to acquire lock:
(&priv->mutex){+.+.+.}, at: [<facfa598>] show_statistics+0x48/0x100 [iwlagn]
but task is already holding lock:
(s_active){++++.+}, at: [<c0580ebd>] sysfs_get_active_two+0x1d/0x50
which lock already depends on the new lock.
the existing dependency chain (in reverse order) is:
-> #1 (s_active){++++.+}:
[<c0489b74>] __lock_acquire+0xc44/0x1230
[<c048a1ed>] lock_acquire+0x8d/0x110
[<c0581499>] sysfs_addrm_finish+0xe9/0x180
[<c057f64a>] sysfs_hash_and_remove+0x4a/0x80
[<c05829d4>] sysfs_remove_group+0x44/0xd0
[<c0714b75>] dpm_sysfs_remove+0x15/0x20
[<c070dac8>] device_del+0x38/0x170
[<c070dc1e>] device_unregister+0x1e/0x60
[<c071838d>] _request_firmware+0x29d/0x550
[<c07186c7>] request_firmware+0x17/0x20
[<fad01bf1>] iwl_mac_start+0xb1/0x1230 [iwlagn]
[<fa46ba06>] ieee80211_open+0x436/0x6f0 [mac80211]
[<c0808cd2>] dev_open+0x92/0xf0
[<c0808b2b>] dev_change_flags+0x7b/0x190
[<c08148e8>] do_setlink+0x178/0x3b0
[<c0815169>] rtnl_setlink+0xf9/0x130
[<c081453b>] rtnetlink_rcv_msg+0x1bb/0x1f0
[<c0827ce6>] netlink_rcv_skb+0x86/0xa0
[<c081436c>] rtnetlink_rcv+0x1c/0x30
[<c08279c3>] netlink_unicast+0x263/0x290
[<c0828768>] netlink_sendmsg+0x1c8/0x2a0
[<c07f85fd>] sock_sendmsg+0xcd/0x100
[<c07f964d>] sys_sendmsg+0x15d/0x290
[<c07f9e6b>] sys_socketcall+0xeb/0x2a0
[<c040ad9f>] sysenter_do_call+0x12/0x38
-> #0 (&priv->mutex){+.+.+.}:
[<c0489f84>] __lock_acquire+0x1054/0x1230
[<c048a1ed>] lock_acquire+0x8d/0x110
[<c08bb358>] __mutex_lock_common+0x58/0x470
[<c08bb84a>] mutex_lock_nested+0x3a/0x50
[<facfa598>] show_statistics+0x48/0x100 [iwlagn]
[<c070d219>] dev_attr_show+0x29/0x50
[<c057fecd>] sysfs_read_file+0xdd/0x190
[<c052880f>] vfs_read+0x9f/0x190
[<c0528d22>] sys_read+0x42/0x70
[<c040ad9f>] sysenter_do_call+0x12/0x38
other info that might help us debug this:
3 locks held by cat/2595:
#0: (&buffer->mutex){+.+.+.}, at: [<c057fe25>] sysfs_read_file+0x35/0x190
#1: (s_active){++++.+}, at: [<c0580ecd>] sysfs_get_active_two+0x2d/0x50
#2: (s_active){++++.+}, at: [<c0580ebd>] sysfs_get_active_two+0x1d/0x50
stack backtrace:
Pid: 2595, comm: cat Not tainted 2.6.33-tp-rc4 #2
Call Trace:
[<c08b99ab>] ? printk+0x1d/0x22
[<c0487752>] print_circular_bug+0xc2/0xd0
[<c0489f84>] __lock_acquire+0x1054/0x1230
[<c0478d81>] ? sched_clock_cpu+0x121/0x180
[<c048a1ed>] lock_acquire+0x8d/0x110
[<facfa598>] ? show_statistics+0x48/0x100 [iwlagn]
[<c08bb358>] __mutex_lock_common+0x58/0x470
[<facfa598>] ? show_statistics+0x48/0x100 [iwlagn]
[<c08bb84a>] mutex_lock_nested+0x3a/0x50
[<facfa598>] ? show_statistics+0x48/0x100 [iwlagn]
[<facfa598>] show_statistics+0x48/0x100 [iwlagn]
[<c0580cf9>] ? sysfs_get_active+0x69/0xb0
[<facfa550>] ? show_statistics+0x0/0x100 [iwlagn]
[<c070d219>] dev_attr_show+0x29/0x50
[<c057fecd>] sysfs_read_file+0xdd/0x190
[<c05ff314>] ? security_file_permission+0x14/0x20
[<c0528242>] ? rw_verify_area+0x62/0xd0
[<c052880f>] vfs_read+0x9f/0x190
[<c047745b>] ? up_read+0x1b/0x30
[<c057fdf0>] ? sysfs_read_file+0x0/0x190
[<c04af3b4>] ? audit_syscall_entry+0x1f4/0x220
[<c0528d22>] sys_read+0x42/0x70
[<c040ad9f>] sysenter_do_call+0x12/0x38
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn.c | 318 |
1 files changed, 159 insertions, 159 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index aef4f71f1981..7726e67044c0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -1484,6 +1484,156 @@ bool iwl_good_ack_health(struct iwl_priv *priv, | |||
1484 | } | 1484 | } |
1485 | 1485 | ||
1486 | 1486 | ||
1487 | /***************************************************************************** | ||
1488 | * | ||
1489 | * sysfs attributes | ||
1490 | * | ||
1491 | *****************************************************************************/ | ||
1492 | |||
1493 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1494 | |||
1495 | /* | ||
1496 | * The following adds a new attribute to the sysfs representation | ||
1497 | * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) | ||
1498 | * used for controlling the debug level. | ||
1499 | * | ||
1500 | * See the level definitions in iwl for details. | ||
1501 | * | ||
1502 | * The debug_level being managed using sysfs below is a per device debug | ||
1503 | * level that is used instead of the global debug level if it (the per | ||
1504 | * device debug level) is set. | ||
1505 | */ | ||
1506 | static ssize_t show_debug_level(struct device *d, | ||
1507 | struct device_attribute *attr, char *buf) | ||
1508 | { | ||
1509 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1510 | return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); | ||
1511 | } | ||
1512 | static ssize_t store_debug_level(struct device *d, | ||
1513 | struct device_attribute *attr, | ||
1514 | const char *buf, size_t count) | ||
1515 | { | ||
1516 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1517 | unsigned long val; | ||
1518 | int ret; | ||
1519 | |||
1520 | ret = strict_strtoul(buf, 0, &val); | ||
1521 | if (ret) | ||
1522 | IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); | ||
1523 | else { | ||
1524 | priv->debug_level = val; | ||
1525 | if (iwl_alloc_traffic_mem(priv)) | ||
1526 | IWL_ERR(priv, | ||
1527 | "Not enough memory to generate traffic log\n"); | ||
1528 | } | ||
1529 | return strnlen(buf, count); | ||
1530 | } | ||
1531 | |||
1532 | static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, | ||
1533 | show_debug_level, store_debug_level); | ||
1534 | |||
1535 | |||
1536 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
1537 | |||
1538 | |||
1539 | static ssize_t show_temperature(struct device *d, | ||
1540 | struct device_attribute *attr, char *buf) | ||
1541 | { | ||
1542 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1543 | |||
1544 | if (!iwl_is_alive(priv)) | ||
1545 | return -EAGAIN; | ||
1546 | |||
1547 | return sprintf(buf, "%d\n", priv->temperature); | ||
1548 | } | ||
1549 | |||
1550 | static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); | ||
1551 | |||
1552 | static ssize_t show_tx_power(struct device *d, | ||
1553 | struct device_attribute *attr, char *buf) | ||
1554 | { | ||
1555 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1556 | |||
1557 | if (!iwl_is_ready_rf(priv)) | ||
1558 | return sprintf(buf, "off\n"); | ||
1559 | else | ||
1560 | return sprintf(buf, "%d\n", priv->tx_power_user_lmt); | ||
1561 | } | ||
1562 | |||
1563 | static ssize_t store_tx_power(struct device *d, | ||
1564 | struct device_attribute *attr, | ||
1565 | const char *buf, size_t count) | ||
1566 | { | ||
1567 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1568 | unsigned long val; | ||
1569 | int ret; | ||
1570 | |||
1571 | ret = strict_strtoul(buf, 10, &val); | ||
1572 | if (ret) | ||
1573 | IWL_INFO(priv, "%s is not in decimal form.\n", buf); | ||
1574 | else { | ||
1575 | ret = iwl_set_tx_power(priv, val, false); | ||
1576 | if (ret) | ||
1577 | IWL_ERR(priv, "failed setting tx power (0x%d).\n", | ||
1578 | ret); | ||
1579 | else | ||
1580 | ret = count; | ||
1581 | } | ||
1582 | return ret; | ||
1583 | } | ||
1584 | |||
1585 | static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); | ||
1586 | |||
1587 | static ssize_t show_rts_ht_protection(struct device *d, | ||
1588 | struct device_attribute *attr, char *buf) | ||
1589 | { | ||
1590 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1591 | |||
1592 | return sprintf(buf, "%s\n", | ||
1593 | priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self"); | ||
1594 | } | ||
1595 | |||
1596 | static ssize_t store_rts_ht_protection(struct device *d, | ||
1597 | struct device_attribute *attr, | ||
1598 | const char *buf, size_t count) | ||
1599 | { | ||
1600 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
1601 | unsigned long val; | ||
1602 | int ret; | ||
1603 | |||
1604 | ret = strict_strtoul(buf, 10, &val); | ||
1605 | if (ret) | ||
1606 | IWL_INFO(priv, "Input is not in decimal form.\n"); | ||
1607 | else { | ||
1608 | if (!iwl_is_associated(priv)) | ||
1609 | priv->cfg->use_rts_for_ht = val ? true : false; | ||
1610 | else | ||
1611 | IWL_ERR(priv, "Sta associated with AP - " | ||
1612 | "Change protection mechanism is not allowed\n"); | ||
1613 | ret = count; | ||
1614 | } | ||
1615 | return ret; | ||
1616 | } | ||
1617 | |||
1618 | static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO, | ||
1619 | show_rts_ht_protection, store_rts_ht_protection); | ||
1620 | |||
1621 | |||
1622 | static struct attribute *iwl_sysfs_entries[] = { | ||
1623 | &dev_attr_temperature.attr, | ||
1624 | &dev_attr_tx_power.attr, | ||
1625 | &dev_attr_rts_ht_protection.attr, | ||
1626 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
1627 | &dev_attr_debug_level.attr, | ||
1628 | #endif | ||
1629 | NULL | ||
1630 | }; | ||
1631 | |||
1632 | static struct attribute_group iwl_attribute_group = { | ||
1633 | .name = NULL, /* put in device directory */ | ||
1634 | .attrs = iwl_sysfs_entries, | ||
1635 | }; | ||
1636 | |||
1487 | /****************************************************************************** | 1637 | /****************************************************************************** |
1488 | * | 1638 | * |
1489 | * uCode download functions | 1639 | * uCode download functions |
@@ -1965,6 +2115,13 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) | |||
1965 | if (err) | 2115 | if (err) |
1966 | IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); | 2116 | IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err); |
1967 | 2117 | ||
2118 | err = sysfs_create_group(&priv->pci_dev->dev.kobj, | ||
2119 | &iwl_attribute_group); | ||
2120 | if (err) { | ||
2121 | IWL_ERR(priv, "failed to create sysfs device attributes\n"); | ||
2122 | goto out_unbind; | ||
2123 | } | ||
2124 | |||
1968 | /* We have our copies now, allow OS release its copies */ | 2125 | /* We have our copies now, allow OS release its copies */ |
1969 | release_firmware(ucode_raw); | 2126 | release_firmware(ucode_raw); |
1970 | complete(&priv->_agn.firmware_loading_complete); | 2127 | complete(&priv->_agn.firmware_loading_complete); |
@@ -3264,141 +3421,6 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw, | |||
3264 | 3421 | ||
3265 | /***************************************************************************** | 3422 | /***************************************************************************** |
3266 | * | 3423 | * |
3267 | * sysfs attributes | ||
3268 | * | ||
3269 | *****************************************************************************/ | ||
3270 | |||
3271 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
3272 | |||
3273 | /* | ||
3274 | * The following adds a new attribute to the sysfs representation | ||
3275 | * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) | ||
3276 | * used for controlling the debug level. | ||
3277 | * | ||
3278 | * See the level definitions in iwl for details. | ||
3279 | * | ||
3280 | * The debug_level being managed using sysfs below is a per device debug | ||
3281 | * level that is used instead of the global debug level if it (the per | ||
3282 | * device debug level) is set. | ||
3283 | */ | ||
3284 | static ssize_t show_debug_level(struct device *d, | ||
3285 | struct device_attribute *attr, char *buf) | ||
3286 | { | ||
3287 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3288 | return sprintf(buf, "0x%08X\n", iwl_get_debug_level(priv)); | ||
3289 | } | ||
3290 | static ssize_t store_debug_level(struct device *d, | ||
3291 | struct device_attribute *attr, | ||
3292 | const char *buf, size_t count) | ||
3293 | { | ||
3294 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3295 | unsigned long val; | ||
3296 | int ret; | ||
3297 | |||
3298 | ret = strict_strtoul(buf, 0, &val); | ||
3299 | if (ret) | ||
3300 | IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf); | ||
3301 | else { | ||
3302 | priv->debug_level = val; | ||
3303 | if (iwl_alloc_traffic_mem(priv)) | ||
3304 | IWL_ERR(priv, | ||
3305 | "Not enough memory to generate traffic log\n"); | ||
3306 | } | ||
3307 | return strnlen(buf, count); | ||
3308 | } | ||
3309 | |||
3310 | static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO, | ||
3311 | show_debug_level, store_debug_level); | ||
3312 | |||
3313 | |||
3314 | #endif /* CONFIG_IWLWIFI_DEBUG */ | ||
3315 | |||
3316 | |||
3317 | static ssize_t show_temperature(struct device *d, | ||
3318 | struct device_attribute *attr, char *buf) | ||
3319 | { | ||
3320 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3321 | |||
3322 | if (!iwl_is_alive(priv)) | ||
3323 | return -EAGAIN; | ||
3324 | |||
3325 | return sprintf(buf, "%d\n", priv->temperature); | ||
3326 | } | ||
3327 | |||
3328 | static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL); | ||
3329 | |||
3330 | static ssize_t show_tx_power(struct device *d, | ||
3331 | struct device_attribute *attr, char *buf) | ||
3332 | { | ||
3333 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3334 | |||
3335 | if (!iwl_is_ready_rf(priv)) | ||
3336 | return sprintf(buf, "off\n"); | ||
3337 | else | ||
3338 | return sprintf(buf, "%d\n", priv->tx_power_user_lmt); | ||
3339 | } | ||
3340 | |||
3341 | static ssize_t store_tx_power(struct device *d, | ||
3342 | struct device_attribute *attr, | ||
3343 | const char *buf, size_t count) | ||
3344 | { | ||
3345 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3346 | unsigned long val; | ||
3347 | int ret; | ||
3348 | |||
3349 | ret = strict_strtoul(buf, 10, &val); | ||
3350 | if (ret) | ||
3351 | IWL_INFO(priv, "%s is not in decimal form.\n", buf); | ||
3352 | else { | ||
3353 | ret = iwl_set_tx_power(priv, val, false); | ||
3354 | if (ret) | ||
3355 | IWL_ERR(priv, "failed setting tx power (0x%d).\n", | ||
3356 | ret); | ||
3357 | else | ||
3358 | ret = count; | ||
3359 | } | ||
3360 | return ret; | ||
3361 | } | ||
3362 | |||
3363 | static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power); | ||
3364 | |||
3365 | static ssize_t show_rts_ht_protection(struct device *d, | ||
3366 | struct device_attribute *attr, char *buf) | ||
3367 | { | ||
3368 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3369 | |||
3370 | return sprintf(buf, "%s\n", | ||
3371 | priv->cfg->use_rts_for_ht ? "RTS/CTS" : "CTS-to-self"); | ||
3372 | } | ||
3373 | |||
3374 | static ssize_t store_rts_ht_protection(struct device *d, | ||
3375 | struct device_attribute *attr, | ||
3376 | const char *buf, size_t count) | ||
3377 | { | ||
3378 | struct iwl_priv *priv = dev_get_drvdata(d); | ||
3379 | unsigned long val; | ||
3380 | int ret; | ||
3381 | |||
3382 | ret = strict_strtoul(buf, 10, &val); | ||
3383 | if (ret) | ||
3384 | IWL_INFO(priv, "Input is not in decimal form.\n"); | ||
3385 | else { | ||
3386 | if (!iwl_is_associated(priv)) | ||
3387 | priv->cfg->use_rts_for_ht = val ? true : false; | ||
3388 | else | ||
3389 | IWL_ERR(priv, "Sta associated with AP - " | ||
3390 | "Change protection mechanism is not allowed\n"); | ||
3391 | ret = count; | ||
3392 | } | ||
3393 | return ret; | ||
3394 | } | ||
3395 | |||
3396 | static DEVICE_ATTR(rts_ht_protection, S_IWUSR | S_IRUGO, | ||
3397 | show_rts_ht_protection, store_rts_ht_protection); | ||
3398 | |||
3399 | |||
3400 | /***************************************************************************** | ||
3401 | * | ||
3402 | * driver setup and teardown | 3424 | * driver setup and teardown |
3403 | * | 3425 | * |
3404 | *****************************************************************************/ | 3426 | *****************************************************************************/ |
@@ -3550,21 +3572,6 @@ static void iwl_uninit_drv(struct iwl_priv *priv) | |||
3550 | kfree(priv->scan_cmd); | 3572 | kfree(priv->scan_cmd); |
3551 | } | 3573 | } |
3552 | 3574 | ||
3553 | static struct attribute *iwl_sysfs_entries[] = { | ||
3554 | &dev_attr_temperature.attr, | ||
3555 | &dev_attr_tx_power.attr, | ||
3556 | &dev_attr_rts_ht_protection.attr, | ||
3557 | #ifdef CONFIG_IWLWIFI_DEBUG | ||
3558 | &dev_attr_debug_level.attr, | ||
3559 | #endif | ||
3560 | NULL | ||
3561 | }; | ||
3562 | |||
3563 | static struct attribute_group iwl_attribute_group = { | ||
3564 | .name = NULL, /* put in device directory */ | ||
3565 | .attrs = iwl_sysfs_entries, | ||
3566 | }; | ||
3567 | |||
3568 | static struct ieee80211_ops iwl_hw_ops = { | 3575 | static struct ieee80211_ops iwl_hw_ops = { |
3569 | .tx = iwl_mac_tx, | 3576 | .tx = iwl_mac_tx, |
3570 | .start = iwl_mac_start, | 3577 | .start = iwl_mac_start, |
@@ -3750,11 +3757,6 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3750 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); | 3757 | IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq); |
3751 | goto out_disable_msi; | 3758 | goto out_disable_msi; |
3752 | } | 3759 | } |
3753 | err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); | ||
3754 | if (err) { | ||
3755 | IWL_ERR(priv, "failed to create sysfs device attributes\n"); | ||
3756 | goto out_free_irq; | ||
3757 | } | ||
3758 | 3760 | ||
3759 | iwl_setup_deferred_work(priv); | 3761 | iwl_setup_deferred_work(priv); |
3760 | iwl_setup_rx_handlers(priv); | 3762 | iwl_setup_rx_handlers(priv); |
@@ -3788,15 +3790,13 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
3788 | 3790 | ||
3789 | err = iwl_request_firmware(priv, true); | 3791 | err = iwl_request_firmware(priv, true); |
3790 | if (err) | 3792 | if (err) |
3791 | goto out_remove_sysfs; | 3793 | goto out_destroy_workqueue; |
3792 | 3794 | ||
3793 | return 0; | 3795 | return 0; |
3794 | 3796 | ||
3795 | out_remove_sysfs: | 3797 | out_destroy_workqueue: |
3796 | destroy_workqueue(priv->workqueue); | 3798 | destroy_workqueue(priv->workqueue); |
3797 | priv->workqueue = NULL; | 3799 | priv->workqueue = NULL; |
3798 | sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); | ||
3799 | out_free_irq: | ||
3800 | free_irq(priv->pci_dev->irq, priv); | 3800 | free_irq(priv->pci_dev->irq, priv); |
3801 | iwl_free_isr_ict(priv); | 3801 | iwl_free_isr_ict(priv); |
3802 | out_disable_msi: | 3802 | out_disable_msi: |