diff options
Diffstat (limited to 'drivers')
394 files changed, 7737 insertions, 3671 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 8711e3797165..3c2e4aa529c4 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -207,7 +207,7 @@ static int acpi_ac_probe(struct platform_device *pdev) goto end; result = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), - ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler, ac); + ACPI_ALL_NOTIFY, acpi_ac_notify_handler, ac); if (result) { power_supply_unregister(&ac->charger); goto end; @@ -255,7 +255,7 @@ static int acpi_ac_remove(struct platform_device *pdev) return -EINVAL; acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), - ACPI_DEVICE_NOTIFY, acpi_ac_notify_handler); + ACPI_ALL_NOTIFY, acpi_ac_notify_handler); ac = platform_get_drvdata(pdev); if (ac->charger.dev) diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index fbf1aceda8b8..5876a49dfd38 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -62,6 +62,7 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>"); MODULE_DESCRIPTION("ACPI Battery Driver"); MODULE_LICENSE("GPL"); +static int battery_bix_broken_package; static unsigned int cache_time = 1000; module_param(cache_time, uint, 0644); MODULE_PARM_DESC(cache_time, "cache time in milliseconds"); @@ -416,7 +417,12 @@ static int acpi_battery_get_info(struct acpi_battery *battery) ACPI_EXCEPTION((AE_INFO, status, "Evaluating %s", name)); return -ENODEV; } - if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) + + if (battery_bix_broken_package) + result = extract_package(battery, buffer.pointer, + extended_info_offsets + 1, + ARRAY_SIZE(extended_info_offsets) - 1); + else if (test_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags)) result = extract_package(battery, buffer.pointer, extended_info_offsets, ARRAY_SIZE(extended_info_offsets)); @@ -754,6 +760,17 @@ static int battery_notify(struct notifier_block *nb, return 0; } +static struct dmi_system_id bat_dmi_table[] = { + { + .ident = "NEC LZ750/LS", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "NEC"), + DMI_MATCH(DMI_PRODUCT_NAME, "PC-LZ750LS"), + }, + }, + {}, +}; + static int acpi_battery_add(struct acpi_device *device) { int result = 0; @@ -846,6 +863,9 @@ static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie) { if (acpi_disabled) return; + + if (dmi_check_system(bat_dmi_table)) + battery_bix_broken_package = 1; acpi_bus_register_driver(&acpi_battery_driver); } diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index bba9b72e25f8..0710004055c8 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -156,6 +156,16 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) } EXPORT_SYMBOL(acpi_bus_get_private_data); +void acpi_bus_no_hotplug(acpi_handle handle) +{ + struct acpi_device *adev = NULL; + + acpi_bus_get_device(handle, &adev); + if (adev) + adev->flags.no_hotplug = true; +} +EXPORT_SYMBOL_GPL(acpi_bus_no_hotplug); + static void acpi_print_osc_error(acpi_handle handle, struct acpi_osc_context *context, char *error) { diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index c0ed4f273cf2..e3a92a6da39a 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -427,6 +427,9 @@ static const struct pci_device_id ahci_pci_tbl[] = { .driver_data = board_ahci_yes_fbs }, /* 88se9128 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9125), .driver_data = board_ahci_yes_fbs }, /* 88se9125 */ + { PCI_DEVICE_SUB(PCI_VENDOR_ID_MARVELL_EXT, 0x9178, + PCI_VENDOR_ID_MARVELL_EXT, 0x9170), + .driver_data = board_ahci_yes_fbs }, /* 88se9170 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x917a), .driver_data = board_ahci_yes_fbs }, /* 88se9172 */ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL_EXT, 0x9172), diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c index fe3ca0989b14..1ad2f62d34b9 100644 --- a/drivers/ata/sata_sis.c +++ b/drivers/ata/sata_sis.c @@ -83,6 +83,10 @@ static struct pci_driver sis_pci_driver = { .id_table = sis_pci_tbl, .probe = sis_init_one, .remove = ata_pci_remove_one, +#ifdef CONFIG_PM + .suspend = ata_pci_device_suspend, + .resume = ata_pci_device_resume, +#endif }; static struct scsi_host_template sis_sht = { diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c index 4d07cce9c5d9..7e11ef4cb7db 100644 --- a/drivers/bcma/driver_chipcommon_sflash.c +++ b/drivers/bcma/driver_chipcommon_sflash.c @@ -38,7 +38,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = { { "M25P32", 0x15, 0x10000, 64, }, { "M25P64", 0x16, 0x10000, 128, }, { "M25FL128", 0x17, 0x10000, 256, }, - { 0 }, + { NULL }, }; static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = { @@ -56,7 +56,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = { { "SST25VF016", 0x41, 0x1000, 512, }, { "SST25VF032", 0x4a, 0x1000, 1024, }, { "SST25VF064", 0x4b, 0x1000, 2048, }, - { 0 }, + { NULL }, }; static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = { @@ -67,7 +67,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = { { "AT45DB161", 0x2c, 512, 4096, }, { "AT45DB321", 0x34, 512, 8192, }, { "AT45DB642", 0x3c, 1024, 8192, }, - { 0 }, + { NULL }, }; static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode) diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index b61440aaee65..83f6437dd91d 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -73,6 +73,7 @@ struct btsdio_data { #define REG_CL_INTRD 0x13 /* Interrupt Clear */ #define REG_EN_INTRD 0x14 /* Interrupt Enable */ #define REG_MD_STAT 0x20 /* Bluetooth Mode Status */ +#define REG_MD_SET 0x20 /* Bluetooth Mode Set */ static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb) { @@ -212,7 +213,7 @@ static int btsdio_open(struct hci_dev *hdev) } if (data->func->class == SDIO_CLASS_BT_B) - sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL); + sdio_writeb(data->func, 0x00, REG_MD_SET, NULL); sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL); @@ -333,6 +334,9 @@ static int btsdio_probe(struct sdio_func *func, hdev->flush = btsdio_flush; hdev->send = btsdio_send_frame; + if (func->vendor == 0x0104 && func->device == 0x00c5) + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 9f7e539de510..baeaaed299e4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -965,6 +965,45 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev) return 0; } +static int btusb_setup_csr(struct hci_dev *hdev) +{ + struct hci_rp_read_local_version *rp; + struct sk_buff *skb; + int ret; + + BT_DBG("%s", hdev->name); + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb)); + return -PTR_ERR(skb); + } + + rp = (struct hci_rp_read_local_version *) skb->data; + + if (!rp->status) { + if (le16_to_cpu(rp->manufacturer) != 10) { + /* Clear the reset quirk since this is not an actual + * early Bluetooth 1.1 device from CSR. + */ + clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + + /* These fake CSR controllers have all a broken + * stored link key handling and so just disable it. + */ + set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, + &hdev->quirks); + } + } + + ret = -bt_to_errno(rp->status); + + kfree_skb(skb); + + return ret; +} + struct intel_version { u8 status; u8 hw_platform; @@ -1465,10 +1504,15 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_CSR) { struct usb_device *udev = data->udev; + u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice); /* Old firmware would otherwise execute USB reset */ - if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) + if (bcdDevice < 0x117) set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); + + /* Fake CSR devices with broken commands */ + if (bcdDevice <= 0x100) + hdev->setup = btusb_setup_csr; } if (id->driver_info & BTUSB_SNIFFER) { diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 7b167385a1c4..1ef6990a5c7e 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -141,22 +141,28 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type) } static inline ssize_t vhci_get_user(struct vhci_data *data, - const char __user *buf, size_t count) + const struct iovec *iov, + unsigned long count) { + size_t len = iov_length(iov, count); struct sk_buff *skb; __u8 pkt_type, dev_type; + unsigned long i; int ret; - if (count < 2 || count > HCI_MAX_FRAME_SIZE) + if (len < 2 || len > HCI_MAX_FRAME_SIZE) return -EINVAL; - skb = bt_skb_alloc(count, GFP_KERNEL); + skb = bt_skb_alloc(len, GFP_KERNEL); if (!skb) return -ENOMEM; - if (copy_from_user(skb_put(skb, count), buf, count)) { - kfree_skb(skb); - return -EFAULT; + for (i = 0; i < count; i++) { + if (copy_from_user(skb_put(skb, iov[i].iov_len), + iov[i].iov_base, iov[i].iov_len)) { + kfree_skb(skb); + return -EFAULT; + } } pkt_type = *((__u8 *) skb->data); @@ -205,7 +211,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, return -EINVAL; } - return (ret < 0) ? ret : count; + return (ret < 0) ? ret : len; } static inline ssize_t vhci_put_user(struct vhci_data *data, @@ -272,12 +278,13 @@ static ssize_t vhci_read(struct file *file, return ret; } -static ssize_t vhci_write(struct file *file, - const char __user *buf, size_t count, loff_t *pos) +static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov, + unsigned long count, loff_t pos) { + struct file *file = iocb->ki_filp; struct vhci_data *data = file->private_data; - return vhci_get_user(data, buf, count); + return vhci_get_user(data, iov, count); } static unsigned int vhci_poll(struct file *file, poll_table *wait) @@ -342,7 +349,7 @@ static int vhci_release(struct inode *inode, struct file *file) static const struct file_operations vhci_fops = { .owner = THIS_MODULE, .read = vhci_read, - .write = vhci_write, + .aio_write = vhci_write, .poll = vhci_poll, .open = vhci_open, .release = vhci_release, diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c index 8e562dc65601..e1f3337a0cf9 100644 --- a/drivers/char/tpm/tpm_ppi.c +++ b/drivers/char/tpm/tpm_ppi.c @@ -27,15 +27,18 @@ static char *tpm_device_name = "TPM"; static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context, void **return_value) { - acpi_status status; + acpi_status status = AE_OK; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; - status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - if (strstr(buffer.pointer, context) != NULL) { - *return_value = handle; + + if (ACPI_SUCCESS(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) { + if (strstr(buffer.pointer, context) != NULL) { + *return_value = handle; + status = AE_CTRL_TERMINATE; + } kfree(buffer.pointer); - return AE_CTRL_TERMINATE; } - return AE_OK; + + return status; } static inline void ppi_assign_params(union acpi_object params[4], diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c index 8d3009e44fba..5543b7df8e16 100644 --- a/drivers/clk/clk-divider.c +++ b/drivers/clk/clk-divider.c @@ -87,7 +87,7 @@ static unsigned int _get_table_val(const struct clk_div_table *table, return 0; } -static unsigned int _get_val(struct clk_divider *divider, u8 div) +static unsigned int _get_val(struct clk_divider *divider, unsigned int div) { if (divider->flags & CLK_DIVIDER_ONE_BASED) return div; diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index 39b40aaede2b..68e515d093d8 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -26,17 +26,17 @@ static struct clk_onecell_data clk_data; #define ASS_CLK_DIV 0x4 #define ASS_CLK_GATE 0x8 +/* list of all parent clock list */ +static const char *mout_audss_p[] = { "fin_pll", "fout_epll" }; +static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" }; + +#ifdef CONFIG_PM_SLEEP static unsigned long reg_save[][2] = { {ASS_CLK_SRC, 0}, {ASS_CLK_DIV, 0}, {ASS_CLK_GATE, 0}, }; -/* list of all parent clock list */ -static const char *mout_audss_p[] = { "fin_pll", "fout_epll" }; -static const char *mout_i2s_p[] = { "mout_audss", "cdclk0", "sclk_audio0" }; - -#ifdef CONFIG_PM_SLEEP static int exynos_audss_clk_suspend(void) { int i; diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index ad5ff50c5f28..1a7c1b929c69 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -39,7 +39,7 @@ #define SRC_TOP1 0xc214 #define SRC_CAM 0xc220 #define SRC_TV 0xc224 -#define SRC_MFC 0xcc28 +#define SRC_MFC 0xc228 #define SRC_G3D 0xc22c #define E4210_SRC_IMAGE 0xc230 #define SRC_LCD0 0xc234 diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index adf32343c9f9..e52359cf9b6f 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -25,6 +25,7 @@ #define MPLL_LOCK 0x4000 #define MPLL_CON0 0x4100 #define SRC_CORE1 0x4204 +#define GATE_IP_ACP 0x8800 #define CPLL_LOCK 0x10020 #define EPLL_LOCK 0x10030 #define VPLL_LOCK 0x10040 @@ -75,7 +76,6 @@ #define SRC_CDREX 0x20200 #define PLL_DIV2_SEL 0x20a24 #define GATE_IP_DISP1 0x10928 -#define GATE_IP_ACP 0x10000 /* list of PLLs to be registered */ enum exynos5250_plls { @@ -120,7 +120,8 @@ enum exynos5250_clks { spi2, i2s1, i2s2, pcm1, pcm2, pwm, spdif, ac97, hsi2c0, hsi2c1, hsi2c2, hsi2c3, chipid, sysreg, pmu, cmu_top, cmu_core, cmu_mem, tzpc0, tzpc1, tzpc2, tzpc3, tzpc4, tzpc5, tzpc6, tzpc7, tzpc8, tzpc9, hdmi_cec, mct, - wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, g2d, + wdt, rtc, tmu, fimd1, mie1, dsim0, dp, mixer, hdmi, g2d, mdma0, + smmu_mdma0, /* mux clocks */ mout_hdmi = 1024, @@ -354,8 +355,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { GATE(smmu_gscl2, "smmu_gscl2", "aclk266", GATE_IP_GSCL, 9, 0, 0), GATE(smmu_gscl3, "smmu_gscl3", "aclk266", GATE_IP_GSCL, 10, 0, 0), GATE(mfc, "mfc", "aclk333", GATE_IP_MFC, 0, 0, 0), - GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 1, 0, 0), - GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 2, 0, 0), + GATE(smmu_mfcl, "smmu_mfcl", "aclk333", GATE_IP_MFC, 2, 0, 0), + GATE(smmu_mfcr, "smmu_mfcr", "aclk333", GATE_IP_MFC, 1, 0, 0), GATE(rotator, "rotator", "aclk266", GATE_IP_GEN, 1, 0, 0), GATE(jpeg, "jpeg", "aclk166", GATE_IP_GEN, 2, 0, 0), GATE(mdma1, "mdma1", "aclk266", GATE_IP_GEN, 4, 0, 0), @@ -406,7 +407,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { GATE(hsi2c2, "hsi2c2", "aclk66", GATE_IP_PERIC, 30, 0, 0), GATE(hsi2c3, "hsi2c3", "aclk66", GATE_IP_PERIC, 31, 0, 0), GATE(chipid, "chipid", "aclk66", GATE_IP_PERIS, 0, 0, 0), - GATE(sysreg, "sysreg", "aclk66", GATE_IP_PERIS, 1, 0, 0), + GATE(sysreg, "sysreg", "aclk66", + GATE_IP_PERIS, 1, CLK_IGNORE_UNUSED, 0), GATE(pmu, "pmu", "aclk66", GATE_IP_PERIS, 2, CLK_IGNORE_UNUSED, 0), GATE(tzpc0, "tzpc0", "aclk66", GATE_IP_PERIS, 6, 0, 0), GATE(tzpc1, "tzpc1", "aclk66", GATE_IP_PERIS, 7, 0, 0), @@ -492,6 +494,8 @@ static struct samsung_gate_clock exynos5250_gate_clks[] __initdata = { GATE(mixer, "mixer", "mout_aclk200_disp1", GATE_IP_DISP1, 5, 0, 0), GATE(hdmi, "hdmi", "mout_aclk200_disp1", GATE_IP_DISP1, 6, 0, 0), GATE(g2d, "g2d", "aclk200", GATE_IP_ACP, 3, 0, 0), + GATE(mdma0, "mdma0", "aclk266", GATE_IP_ACP, 1, 0, 0), + GATE(smmu_mdma0, "smmu_mdma0", "aclk266", GATE_IP_ACP, 5, 0, 0), }; static struct samsung_pll_rate_table vpll_24mhz_tbl[] __initdata = { diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 16d7b4ac94be..8d19f7c06010 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -839,9 +839,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) /* set default policy */ ret = cpufreq_set_policy(policy, &new_policy); - policy->user_policy.policy = policy->policy; - policy->user_policy.governor = policy->governor; - if (ret) { pr_debug("setting policy failed\n"); if (cpufreq_driver->exit) @@ -1016,15 +1013,17 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, read_unlock_irqrestore(&cpufreq_driver_lock, flags); #endif - if (frozen) - /* Restore the saved policy when doing light-weight init */ - policy = cpufreq_policy_restore(cpu); - else + /* + * Restore the saved policy when doing light-weight init and fall back + * to the full init if that fails. + */ + policy = frozen ? cpufreq_policy_restore(cpu) : NULL; + if (!policy) { + frozen = false; policy = cpufreq_policy_alloc(); - - if (!policy) - goto nomem_out; - + if (!policy) + goto nomem_out; + } /* * In the resume path, since we restore a saved policy, the assignment @@ -1069,8 +1068,10 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, */ cpumask_and(policy->cpus, policy->cpus, cpu_online_mask); - policy->user_policy.min = policy->min; - policy->user_policy.max = policy->max; + if (!frozen) { + policy->user_policy.min = policy->min; + policy->user_policy.max = policy->max; + } blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_START, policy); @@ -1101,6 +1102,11 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif, cpufreq_init_policy(policy); + if (!frozen) { + policy->user_policy.policy = policy->policy; + policy->user_policy.governor = policy->governor; + } + kobject_uevent(&policy->kobj, KOBJ_ADD); up_read(&cpufreq_rwsem); @@ -1118,8 +1124,11 @@ err_get_freq: if (cpufreq_driver->exit) cpufreq_driver->exit(policy); err_set_policy_cpu: - if (frozen) + if (frozen) { + /* Do not leave stale fallback data behind. */ + per_cpu(cpufreq_cpu_data_fallback, cpu) = NULL; cpufreq_policy_put_kobj(policy); + } cpufreq_policy_free(policy); nomem_out: diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 5f1cbae36961..d51f17ed691e 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -581,7 +581,8 @@ static void intel_pstate_timer_func(unsigned long __data) } #define ICPU(model, policy) \ - { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&policy } + { X86_VENDOR_INTEL, 6, model, X86_FEATURE_APERFMPERF,\ + (unsigned long)&policy } static const struct x86_cpu_id intel_pstate_cpu_ids[] = { ICPU(0x2a, core_params), @@ -614,6 +615,11 @@ static int intel_pstate_init_cpu(unsigned int cpunum) cpu = all_cpu_data[cpunum]; intel_pstate_get_cpu_pstates(cpu); + if (!cpu->pstate.current_pstate) { + all_cpu_data[cpunum] = NULL; + kfree(cpu); + return -ENODATA; + } cpu->cpu = cpunum; diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c index 36795639df0d..6e51114057d0 100644 --- a/drivers/cpuidle/cpuidle-calxeda.c +++ b/drivers/cpuidle/cpuidle-calxeda.c @@ -65,7 +65,7 @@ static struct cpuidle_driver calxeda_idle_driver = { .state_count = 2, }; -static int __init calxeda_cpuidle_probe(struct platform_device *pdev) +static int calxeda_cpuidle_probe(struct platform_device *pdev) { return cpuidle_register(&calxeda_idle_driver, NULL); } diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c index 9dd6e01eac33..f757a0f428bd 100644 --- a/drivers/crypto/ixp4xx_crypto.c +++ b/drivers/crypto/ixp4xx_crypto.c @@ -1410,14 +1410,12 @@ static const struct platform_device_info ixp_dev_info __initdata = { static int __init ixp_module_init(void) { int num = ARRAY_SIZE(ixp4xx_algos); - int i, err ; + int i, err; pdev = platform_device_register_full(&ixp_dev_info); if (IS_ERR(pdev)) return PTR_ERR(pdev); - dev = &pdev->dev; - spin_lock_init(&desc_lock); spin_lock_init(&emerg_lock); diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 1a49c777607c..87529181efcc 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -817,7 +817,15 @@ int ioat_dma_self_test(struct ioatdma_device *device) } dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_src)) { + dev_err(dev, "mapping src buffer failed\n"); + goto free_resources; + } dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(dev, dma_dest)) { + dev_err(dev, "mapping dest buffer failed\n"); + goto unmap_src; + } flags = DMA_PREP_INTERRUPT; tx = device->common.device_prep_dma_memcpy(dma_chan, dma_dest, dma_src, IOAT_TEST_SIZE, flags); @@ -855,8 +863,9 @@ int ioat_dma_self_test(struct ioatdma_device *device) } unmap_dma: - dma_unmap_single(dev, dma_src, IOAT_TEST_SIZE, DMA_TO_DEVICE); dma_unmap_single(dev, dma_dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE); +unmap_src: + dma_unmap_single(dev, dma_src, IOAT_TEST_SIZE, DMA_TO_DEVICE); free_resources: dma->device_free_chan_resources(dma_chan); out: diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index c79dd2b1f70e..d3c3b5b15824 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -906,14 +906,12 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm, WARN_ON(readq(>t_entries[i-1]) != gen8_pte_encode(addr, level, true)); -#if 0 /* TODO: Still needed on GEN8? */ /* This next bit makes the above posting read even more important. We * want to flush the TLBs only after we're certain all the PTE updates * have finished. */ I915_WRITE(GFX_FLSH_CNTL_GEN6, GFX_FLSH_CNTL_EN); POSTING_READ(GFX_FLSH_CNTL_GEN6); -#endif } /* diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 54e82a80cf50..769b864465a9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10541,11 +10541,20 @@ static struct intel_quirk intel_quirks[] = { /* Sony Vaio Y cannot use SSC on LVDS */ { 0x0046, 0x104d, 0x9076, quirk_ssc_force_disable }, - /* - * All GM45 Acer (and its brands eMachines and Packard Bell) laptops - * seem to use inverted backlight PWM. - */ - { 0x2a42, 0x1025, PCI_ANY_ID, quirk_invert_brightness }, + /* Acer Aspire 5734Z must invert backlight brightness */ + { 0x2a42, 0x1025, 0x0459, quirk_invert_brightness }, + + /* Acer/eMachines G725 */ + { 0x2a42, 0x1025, 0x0210, quirk_invert_brightness }, + + /* Acer/eMachines e725 */ + { 0x2a42, 0x1025, 0x0212, quirk_invert_brightness }, + + /* Acer/Packard Bell NCL20 */ + { 0x2a42, 0x1025, 0x034b, quirk_invert_brightness }, + + /* Acer Aspire 4736Z */ + { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness }, /* Dell XPS13 HD Sandy Bridge */ { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable }, diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c index 48f06378d3f9..2ea5568b6cf5 100644 --- a/drivers/gpu/drm/nouveau/core/core/subdev.c +++ b/drivers/gpu/drm/nouveau/core/core/subdev.c @@ -104,11 +104,8 @@ nouveau_subdev_create_(struct nouveau_object *parent, if (parent) { struct nouveau_device *device = nv_device(parent); - int subidx = nv_hclass(subdev) & 0xff; - subdev->debug = nouveau_dbgopt(device->dbgopt, subname); subdev->mmio = nv_subdev(device)->mmio; - device->subdev[subidx] = *pobject; } return 0; diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c index 9135b25a29d0..dd01c6c435d6 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/base.c @@ -268,6 +268,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent, if (ret) return ret; + device->subdev[i] = devobj->subdev[i]; + /* note: can't init *any* subdevs until devinit has been run * due to not knowing exactly what the vbios init tables will * mess with. devinit also can't be run until all of its diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c index 8d06eef2b9ee..dbc5e33de94f 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c @@ -161,7 +161,7 @@ nvc0_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c index 434bb4b0fa2e..5c8a63dc506a 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c @@ -334,7 +334,7 @@ nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds) while ((mthd = &mthds[i++]) && (init = mthd->init)) { u32 addr = 0x80000000 | mthd->oclass; for (data = 0; init->count; init++) { - if (data != init->data) { + if (init == mthd->init || data != init->data) { nv_wr32(priv, 0x40448c, init->data); data = init->data; } diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h index 8541aa382ff2..d89dbdf39b0d 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h @@ -75,6 +75,11 @@ struct nouveau_fb { static inline struct nouveau_fb * nouveau_fb(void *obj) { + /* fbram uses this before device subdev pointer is valid */ + if (nv_iclass(obj, NV_SUBDEV_CLASS) && + nv_subidx(obj) == NVDEV_SUBDEV_FB) + return obj; + return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB]; } diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c index 420908cb82b6..df1b1b423093 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c @@ -365,13 +365,13 @@ static u16 init_script(struct nouveau_bios *bios, int index) { struct nvbios_init init = { .bios = bios }; - u16 data; + u16 bmp_ver = bmp_version(bios), data; - if (bmp_version(bios) && bmp_version(bios) < 0x0510) { - if (index > 1) + if (bmp_ver && bmp_ver < 0x0510) { + if (index > 1 || bmp_ver < 0x0100) return 0x0000; - data = bios->bmp_offset + (bios->version.major < 2 ? 14 : 18); + data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18); return nv_ro16(bios, data + (index * 2)); } @@ -1294,7 +1294,11 @@ init_jump(struct nvbios_init *init) u16 offset = nv_ro16(bios, init->offset + 1); trace("JUMP\t0x%04x\n", offset); - init->offset = offset; + + if (init_exec(init)) + init->offset = offset; + else + init->offset += 3; } /** diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 6828d81ed7b9..900fae01793e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -447,6 +447,8 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) if (ret) goto done; + info->offset = ntfy->node->offset; + done: if (ret) nouveau_abi16_ntfy_fini(chan, ntfy); diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 95c740454049..ba0183fb84f3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -51,6 +51,7 @@ static struct nouveau_dsm_priv { bool dsm_detected; bool optimus_detected; acpi_handle dhandle; + acpi_handle other_handle; acpi_handle rom_handle; } nouveau_dsm_priv; @@ -260,9 +261,10 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) if (!dhandle) return false; - if (!acpi_has_method(dhandle, "_DSM")) + if (!acpi_has_method(dhandle, "_DSM")) { + nouveau_dsm_priv.other_handle = dhandle; return false; - + } if (nouveau_test_dsm(dhandle, nouveau_dsm, NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; @@ -338,6 +340,16 @@ static bool nouveau_dsm_detect(void) printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n", acpi_method_name); nouveau_dsm_priv.dsm_detected = true; + /* + * On some systems hotplug events are generated for the device + * being switched off when _DSM is executed. They cause ACPI + * hotplug to trigger and attempt to remove the device from + * the system, which causes it to break down. Prevent that from + * happening by setting the no_hotplug flag for the involved + * ACPI device objects. + */ + acpi_bus_no_hotplug(nouveau_dsm_priv.dhandle); + acpi_bus_no_hotplug(nouveau_dsm_priv.other_handle); ret = true; } diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 29c3efdfc7dd..25ea82f8def3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -610,7 +610,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, ret = nouveau_fence_sync(fence, chan); nouveau_fence_unref(&fence); if (ret) - return ret; + goto fail_free; if (new_bo != old_bo) { ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM); diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index b1970596a782..0b9621c9aeea 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -1143,31 +1143,53 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, } if (tiling_flags & RADEON_TILING_MACRO) { - if (rdev->family >= CHIP_BONAIRE) - tmp = rdev->config.cik.tile_config; - else if (rdev->family >= CHIP_TAHITI) - tmp = rdev->config.si.tile_config; - else if (rdev->family >= CHIP_CAYMAN) - tmp = rdev->config.cayman.tile_config; - else - tmp = rdev->config.evergreen.tile_config; + evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); - switch ((tmp & 0xf0) >> 4) { - case 0: /* 4 banks */ - fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); - break; - case 1: /* 8 banks */ - default: - fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); - break; - case 2: /* 16 banks */ - fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); - break; + /* Set NUM_BANKS. */ + if (rdev->family >= CHIP_BONAIRE) { + unsigned tileb, index, num_banks, tile_split_bytes; + + /* Calculate the macrotile mode index. */ + tile_split_bytes = 64 << tile_split; + tileb = 8 * 8 * target_fb->bits_per_pixel / 8; + tileb = min(tile_split_bytes, tileb); + + for (index = 0; tileb > 64; index++) { + tileb >>= 1; + } + + if (index >= 16) { + DRM_ERROR("Wrong screen bpp (%u) or tile split (%u)\n", + target_fb->bits_per_pixel, tile_split); + return -EINVAL; + } + + num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; + fb_format |= EVERGREEN_GRPH_NUM_BANKS(num_banks); + } else { + /* SI and older. */ + if (rdev->family >= CHIP_TAHITI) + tmp = rdev->config.si.tile_config; + else if (rdev->family >= CHIP_CAYMAN) + tmp = rdev->config.cayman.tile_config; + else + tmp = rdev->config.evergreen.tile_config; + + switch ((tmp & 0xf0) >> 4) { + case 0: /* 4 banks */ + fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_4_BANK); + break; + case 1: /* 8 banks */ + default: + fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_8_BANK); + break; + case 2: /* 16 banks */ + fb_format |= EVERGREEN_GRPH_NUM_BANKS(EVERGREEN_ADDR_SURF_16_BANK); + break; + } } fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_2D_TILED_THIN1); - - evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); fb_format |= EVERGREEN_GRPH_TILE_SPLIT(tile_split); fb_format |= EVERGREEN_GRPH_BANK_WIDTH(bankw); fb_format |= EVERGREEN_GRPH_BANK_HEIGHT(bankh); @@ -1180,19 +1202,12 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, fb_format |= EVERGREEN_GRPH_ARRAY_MODE(EVERGREEN_GRPH_ARRAY_1D_TILED_THIN1); if (rdev->family >= CHIP_BONAIRE) { - u32 num_pipe_configs = rdev->config.cik.max_tile_pipes; - u32 num_rb = rdev->config.cik.max_backends_per_se; - if (num_pipe_configs > 8) - num_pipe_configs = 8; - if (num_pipe_configs == 8) - fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P8_32x32_16x16); - else if (num_pipe_configs == 4) { - if (num_rb == 4) - fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_16x16); - else if (num_rb < 4) - fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P4_8x16); - } else if (num_pipe_configs == 2) - fb_format |= CIK_GRPH_PIPE_CONFIG(CIK_ADDR_SURF_P2); + /* Read the pipe config from the 2D TILED SCANOUT mode. + * It should be the same for the other modes too, but not all + * modes set the pipe config field. */ + u32 pipe_config = (rdev->config.cik.tile_mode_array[10] >> 6) & 0x1f; + + fb_format |= CIK_GRPH_PIPE_CONFIG(pipe_config); } else if ((rdev->family == CHIP_TAHITI) || (rdev->family == CHIP_PITCAIRN)) fb_format |= SI_GRPH_PIPE_CONFIG(SI_ADDR_SURF_P8_32x32_8x16); diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c index b43a3a3c9067..e950fabd7f5e 100644 --- a/drivers/gpu/drm/radeon/cik.c +++ b/drivers/gpu/drm/radeon/cik.c @@ -3057,7 +3057,7 @@ static u32 cik_create_bitmask(u32 bit_width) * Returns the disabled RB bitmask. */ static u32 cik_get_rb_disabled(struct radeon_device *rdev, - u32 max_rb_num, u32 se_num, + u32 max_rb_num_per_se, u32 sh_per_se) { u32 data, mask; @@ -3071,7 +3071,7 @@ static u32 cik_get_rb_disabled(struct radeon_device *rdev, data >>= BACKEND_DISABLE_SHIFT; - mask = cik_create_bitmask(max_rb_num / se_num / sh_per_se); + mask = cik_create_bitmask(max_rb_num_per_se / sh_per_se); return data & mask; } @@ -3088,7 +3088,7 @@ static u32 cik_get_rb_disabled(struct radeon_device *rdev, */ static void cik_setup_rb(struct radeon_device *rdev, u32 se_num, u32 sh_per_se, - u32 max_rb_num) + u32 max_rb_num_per_se) { int i, j; u32 data, mask; @@ -3098,7 +3098,7 @@ static void cik_setup_rb(struct radeon_device *rdev, for (i = 0; i < se_num; i++) { for (j = 0; j < sh_per_se; j++) { cik_select_se_sh(rdev, i, j); - data = cik_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se); + data = cik_get_rb_disabled(rdev, max_rb_num_per_se, sh_per_se); if (rdev->family == CHIP_HAWAII) disabled_rbs |= data << ((i * sh_per_se + j) * HAWAII_RB_BITMAP_WIDTH_PER_SH); else @@ -3108,12 +3108,14 @@ static void cik_setup_rb(struct radeon_device *rdev, cik_select_se_sh(rdev, 0xffffffff, 0xffffffff); mask = 1; - for (i = 0; i < max_rb_num; i++) { + for (i = 0; i < max_rb_num_per_se * se_num; i++) { if (!(disabled_rbs & mask)) enabled_rbs |= mask; mask <<= 1; } + rdev->config.cik.backend_enable_mask = enabled_rbs; + for (i = 0; i < se_num; i++) { cik_select_se_sh(rdev, i, 0xffffffff); data = 0; diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index b1f990d0eaa1..45e1f447bc79 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -1940,7 +1940,7 @@ struct si_asic { unsigned sc_earlyz_tile_fifo_size; unsigned num_tile_pipes; - unsigned num_backends_per_se; + unsigned backend_enable_mask; unsigned backend_disable_mask_per_asic; unsigned backend_map; unsigned num_texture_channel_caches; @@ -1970,7 +1970,7 @@ struct cik_asic { unsigned sc_earlyz_tile_fifo_size; unsigned num_tile_pipes; - unsigned num_backends_per_se; + unsigned backend_enable_mask; unsigned backend_disable_mask_per_asic; unsigned backend_map; unsigned num_texture_channel_caches; diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 9d302eaeea15..485848f889f5 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -33,6 +33,7 @@ static struct radeon_atpx_priv { bool atpx_detected; /* handle for device - and atpx */ acpi_handle dhandle; + acpi_handle other_handle; struct radeon_atpx atpx; } radeon_atpx_priv; @@ -451,9 +452,10 @@ static bool radeon_atpx_pci_probe_handle(struct pci_dev *pdev) return false; status = acpi_get_handle(dhandle, "ATPX", &atpx_handle); - if (ACPI_FAILURE(status)) + if (ACPI_FAILURE(status)) { + radeon_atpx_priv.other_handle = dhandle; return false; - + } radeon_atpx_priv.dhandle = dhandle; radeon_atpx_priv.atpx.handle = atpx_handle; return true; @@ -530,6 +532,16 @@ static bool radeon_atpx_detect(void) printk(KERN_INFO "VGA switcheroo: detected switching method %s handle\n", acpi_method_name); radeon_atpx_priv.atpx_detected = true; + /* + * On some systems hotplug events are generated for the device + * being switched off when ATPX is executed. They cause ACPI + * hotplug to trigger and attempt to remove the device from + * the system, which causes it to break down. Prevent that from + * happening by setting the no_hotplug flag for the involved + * ACPI device objects. + */ + acpi_bus_no_hotplug(radeon_atpx_priv.dhandle); + acpi_bus_no_hotplug(radeon_atpx_priv.other_handle); return true; } return false; diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c index 1958b36ad0e5..db39ea36bf22 100644 --- a/drivers/gpu/drm/radeon/radeon_drv.c +++ b/drivers/gpu/drm/radeon/radeon_drv.c @@ -77,9 +77,10 @@ * 2.33.0 - Add SI tiling mode array query * 2.34.0 - Add CIK tiling mode array query * 2.35.0 - Add CIK macrotile mode array query + * 2.36.0 - Fix CIK DCE tiling setup */ #define KMS_DRIVER_MAJOR 2 -#define KMS_DRIVER_MINOR 35 +#define KMS_DRIVER_MINOR 36 #define KMS_DRIVER_PATCHLEVEL 0 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags); int radeon_driver_unload_kms(struct drm_device *dev); diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 55d0b474bd37..21d593c0ecaf 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -461,6 +461,15 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) case RADEON_INFO_SI_CP_DMA_COMPUTE: *value = 1; break; + case RADEON_INFO_SI_BACKEND_ENABLED_MASK: + if (rdev->family >= CHIP_BONAIRE) { + *value = rdev->config.cik.backend_enable_mask; + } else if (rdev->family >= CHIP_TAHITI) { + *value = rdev->config.si.backend_enable_mask; + } else { + DRM_DEBUG_KMS("BACKEND_ENABLED_MASK is si+ only!\n"); + } + break; default: DRM_DEBUG_KMS("Invalid request %d\n", info->request); return -EINVAL; diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 373d088bac66..b9c0529b4a2e 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -473,7 +473,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p, return -EINVAL; } - if ((start >> 28) != (end >> 28)) { + if ((start >> 28) != ((end - 1) >> 28)) { DRM_ERROR("reloc %LX-%LX crossing 256MB boundary!\n", start, end); return -EINVAL; diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index a36736dab5e0..85e1edfaa3be 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -2811,7 +2811,7 @@ static void si_setup_spi(struct radeon_device *rdev, } static u32 si_get_rb_disabled(struct radeon_device *rdev, - u32 max_rb_num, u32 se_num, + u32 max_rb_num_per_se, u32 sh_per_se) { u32 data, mask; @@ -2825,14 +2825,14 @@ static u32 si_get_rb_disabled(struct radeon_device *rdev, data >>= BACKEND_DISABLE_SHIFT; - mask = si_create_bitmask(max_rb_num / se_num / sh_per_se); + mask = si_create_bitmask(max_rb_num_per_se / sh_per_se); return data & mask; } static void si_setup_rb(struct radeon_device *rdev, u32 se_num, u32 sh_per_se, - u32 max_rb_num) + u32 max_rb_num_per_se) { int i, j; u32 data, mask; @@ -2842,19 +2842,21 @@ static void si_setup_rb(struct radeon_device *rdev, for (i = 0; i < se_num; i++) { for (j = 0; j < sh_per_se; j++) { si_select_se_sh(rdev, i, j); - data = si_get_rb_disabled(rdev, max_rb_num, se_num, sh_per_se); + data = si_get_rb_disabled(rdev, max_rb_num_per_se, sh_per_se); disabled_rbs |= data << ((i * sh_per_se + j) * TAHITI_RB_BITMAP_WIDTH_PER_SH); } } si_select_se_sh(rdev, 0xffffffff, 0xffffffff); mask = 1; - for (i = 0; i < max_rb_num; i++) { + for (i = 0; i < max_rb_num_per_se * se_num; i++) { if (!(disabled_rbs & mask)) enabled_rbs |= mask; mask <<= 1; } + rdev->config.si.backend_enable_mask = enabled_rbs; + for (i = 0; i < se_num; i++) { si_select_se_sh(rdev, i, 0xffffffff); data = 0; diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index f80b700f821c..797ed29a36ea 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -123,7 +123,7 @@ static struct cpuidle_state *cpuidle_state_table; * which is also the index into the MWAIT hint array. * Thus C0 is a dummy. */ -static struct cpuidle_state nehalem_cstates[] __initdata = { +static struct cpuidle_state nehalem_cstates[] = { { .name = "C1-NHM", .desc = "MWAIT 0x00", @@ -156,7 +156,7 @@ static struct cpuidle_state nehalem_cstates[] __initdata = { .enter = NULL } }; -static struct cpuidle_state snb_cstates[] __initdata = { +static struct cpuidle_state snb_cstates[] = { { .name = "C1-SNB", .desc = "MWAIT 0x00", @@ -196,7 +196,7 @@ static struct cpuidle_state snb_cstates[] __initdata = { .enter = NULL } }; -static struct cpuidle_state ivb_cstates[] __initdata = { +static struct cpuidle_state ivb_cstates[] = { { .name = "C1-IVB", .desc = "MWAIT 0x00", @@ -236,7 +236,7 @@ static struct cpuidle_state ivb_cstates[] __initdata = { .enter = NULL } }; -static struct cpuidle_state hsw_cstates[] __initdata = { +static struct cpuidle_state hsw_cstates[] = { { .name = "C1-HSW", .desc = "MWAIT 0x00", @@ -297,7 +297,7 @@ static struct cpuidle_state hsw_cstates[] __initdata = { .enter = NULL } }; -static struct cpuidle_state atom_cstates[] __initdata = { +static struct cpuidle_state atom_cstates[] = { { .name = "C1E-ATM", .desc = "MWAIT 0x00", @@ -329,7 +329,7 @@ static struct cpuidle_state atom_cstates[] __initdata = { { .enter = NULL } }; -static struct cpuidle_state avn_cstates[] __initdata = { +static struct cpuidle_state avn_cstates[] = { { .name = "C1-AVN", .desc = "MWAIT 0x00", @@ -344,6 +344,8 @@ static struct cpuidle_state avn_cstates[] __initdata = { .exit_latency = 15, .target_residency = 45, .enter = &intel_idle }, + { + .enter = NULL } }; /** diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 8e49db690f33..6c17f2dc0f09 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2310,7 +2310,7 @@ static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) inet_get_local_port_range(&init_net, &low, &high); remaining = (high - low) + 1; - rover = net_random() % remaining + low; + rover = prandom_u32() % remaining + low; retry: if (last_used_port != rover && !idr_find(ps, (unsigned short) rover)) { diff --git a/drivers/input/input.c b/drivers/input/input.c index 846ccdd905b1..d2965e4b3224 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -1871,6 +1871,10 @@ void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int break; case EV_ABS: + input_alloc_absinfo(dev); + if (!dev->absinfo) + return; + __set_bit(code, dev->absbit); break; diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index 75762d6ff3ba..aa127ba392a4 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -455,7 +455,18 @@ static void zforce_complete(struct zforce_ts *ts, int cmd, int result) } } -static irqreturn_t zforce_interrupt(int irq, void *dev_id) +static irqreturn_t zforce_irq(int irq, void *dev_id) +{ + struct zforce_ts *ts = dev_id; + struct i2c_client *client = ts->client; + + if (ts->suspended && device_may_wakeup(&client->dev)) + pm_wakeup_event(&client->dev, 500); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t zforce_irq_thread(int irq, void *dev_id) { struct zforce_ts *ts = dev_id; struct i2c_client *client = ts->client; @@ -465,12 +476,10 @@ static irqreturn_t zforce_interrupt(int irq, void *dev_id) u8 *payload; /* - * When suspended, emit a wakeup signal if necessary and return. + * When still suspended, return. * Due to the level-interrupt we will get re-triggered later. */ if (ts->suspended) { - if (device_may_wakeup(&client->dev)) - pm_wakeup_event(&client->dev, 500); msleep(20); return IRQ_HANDLED; } @@ -763,8 +772,8 @@ static int zforce_probe(struct i2c_client *client, * Therefore we can trigger the interrupt anytime it is low and do * not need to limit it to the interrupt edge. */ - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - zforce_interrupt, + ret = devm_request_threaded_irq(&client->dev, client->irq, + zforce_irq, zforce_irq_thread, IRQF_TRIGGER_LOW | IRQF_ONESHOT, input_dev->name, ts); if (ret) { diff --git a/drivers/leds/leds-lp5521.c b/drivers/leds/leds-lp5521.c index 05188351711d..a97263e902ff 100644 --- a/drivers/leds/leds-lp5521.c +++ b/drivers/leds/leds-lp5521.c @@ -244,18 +244,12 @@ static int lp5521_update_program_memory(struct lp55xx_chip *chip, if (i % 2) goto err; - mutex_lock(&chip->lock); - for (i = 0; i < LP5521_PROGRAM_LENGTH; i++) { ret = lp55xx_write(chip, addr[idx] + i, pattern[i]); - if (ret) { - mutex_unlock(&chip->lock); + if (ret) return -EINVAL; - } } - mutex_unlock(&chip->lock); - return size; err: @@ -427,15 +421,17 @@ static ssize_t store_engine_load(struct device *dev, { struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); struct lp55xx_chip *chip = led->chip; + int ret; mutex_lock(&chip->lock); chip->engine_idx = nr; lp5521_load_engine(chip); + ret = lp5521_update_program_memory(chip, buf, len); mutex_unlock(&chip->lock); - return lp5521_update_program_memory(chip, buf, len); + return ret; } store_load(1) store_load(2) diff --git a/drivers/leds/leds-lp5523.c b/drivers/leds/leds-lp5523.c index 6b553d9f4266..fd9ab5f61441 100644 --- a/drivers/leds/leds-lp5523.c +++ b/drivers/leds/leds-lp5523.c @@ -337,18 +337,12 @@ static int lp5523_update_program_memory(struct lp55xx_chip *chip, if (i % 2) goto err; - mutex_lock(&chip->lock); - for (i = 0; i < LP5523_PROGRAM_LENGTH; i++) { ret = lp55xx_write(chip, LP5523_REG_PROG_MEM + i, pattern[i]); - if (ret) { - mutex_unlock(&chip->lock); + if (ret) return -EINVAL; - } } - mutex_unlock(&chip->lock); - return size; err: @@ -548,15 +542,17 @@ static ssize_t store_engine_load(struct device *dev, { struct lp55xx_led *led = i2c_get_clientdata(to_i2c_client(dev)); struct lp55xx_chip *chip = led->chip; + int ret; mutex_lock(&chip->lock); chip->engine_idx = nr; lp5523_load_engine_and_select_page(chip); + ret = lp5523_update_program_memory(chip, buf, len); mutex_unlock(&chip->lock); - return lp5523_update_program_memory(chip, buf, len); + return ret; } store_load(1) store_load(2) diff --git a/drivers/mfd/rtsx_pcr.c b/drivers/mfd/rtsx_pcr.c index 11e20afbdcac..705698fd2c7e 100644 --- a/drivers/mfd/rtsx_pcr.c +++ b/drivers/mfd/rtsx_pcr.c @@ -1228,8 +1228,14 @@ static void rtsx_pci_remove(struct pci_dev *pcidev) pcr->remove_pci = true; - cancel_delayed_work(&pcr->carddet_work); - cancel_delayed_work(&pcr->idle_work); + /* Disable interrupts at the pcr level */ + spin_lock_irq(&pcr->lock); + rtsx_pci_writel(pcr, RTSX_BIER, 0); + pcr->bier = 0; + spin_unlock_irq(&pcr->lock); + + cancel_delayed_work_sync(&pcr->carddet_work); + cancel_delayed_work_sync(&pcr->idle_work); mfd_remove_devices(&pcidev->dev); diff --git a/drivers/mtd/maps/pxa2xx-flash.c b/drivers/mtd/maps/pxa2xx-flash.c index d210d131fef2..0f55589a56b8 100644 --- a/drivers/mtd/maps/pxa2xx-flash.c +++ b/drivers/mtd/maps/pxa2xx-flash.c @@ -73,7 +73,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev) return -ENOMEM; } info->map.cached = - ioremap_cached(info->map.phys, info->map.size); + ioremap_cache(info->map.phys, info->map.size); if (!info->map.cached) printk(KERN_WARNING "Failed to ioremap cached %s\n", info->map.name); diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 539e24a1c86c..cce1f1bf90b4 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -34,14 +34,14 @@ #include "bonding.h" #include "bond_3ad.h" -// General definitions +/* General definitions */ #define AD_SHORT_TIMEOUT 1 #define AD_LONG_TIMEOUT 0 #define AD_STANDBY 0x2 #define AD_MAX_TX_IN_SECOND 3 #define AD_COLLECTOR_MAX_DELAY 0 -// Timer definitions(43.4.4 in the 802.3ad standard) +/* Timer definitions (43.4.4 in the 802.3ad standard) */ #define AD_FAST_PERIODIC_TIME 1 #define AD_SLOW_PERIODIC_TIME 30 #define AD_SHORT_TIMEOUT_TIME (3*AD_FAST_PERIODIC_TIME) @@ -49,7 +49,7 @@ #define AD_CHURN_DETECTION_TIME 60 #define AD_AGGREGATE_WAIT_TIME 2 -// Port state definitions(43.4.2.2 in the 802.3ad standard) +/* Port state definitions (43.4.2.2 in the 802.3ad standard) */ #define AD_STATE_LACP_ACTIVITY 0x1 #define AD_STATE_LACP_TIMEOUT 0x2 #define AD_STATE_AGGREGATION 0x4 @@ -59,7 +59,9 @@ #define AD_STATE_DEFAULTED 0x40 #define AD_STATE_EXPIRED 0x80 -// Port Variables definitions used by the State Machines(43.4.7 in the 802.3ad standard) +/* Port Variables definitions used by the State Machines (43.4.7 in the + * 802.3ad standard) + */ #define AD_PORT_BEGIN 0x1 #define AD_PORT_LACP_ENABLED 0x2 #define AD_PORT_ACTOR_CHURN 0x4 @@ -71,24 +73,23 @@ #define AD_PORT_SELECTED 0x100 #define AD_PORT_MOVED 0x200 -// Port Key definitions -// key is determined according to the link speed, duplex and -// user key(which is yet not supported) -// ------------------------------------------------------------ -// Port key : | User key | Speed |Duplex| -// ------------------------------------------------------------ -// 16 6 1 0 +/* Port Key definitions + * key is determined according to the link speed, duplex and + * user key (which is yet not supported) + * -------------------------------------------------------------- + * Port key : | User key | Speed | Duplex | + * -------------------------------------------------------------- + * 16 6 1 0 + */ #define AD_DUPLEX_KEY_BITS 0x1 #define AD_SPEED_KEY_BITS 0x3E #define AD_USER_KEY_BITS 0xFFC0 -//dalloun #define AD_LINK_SPEED_BITMASK_1MBPS 0x1 #define AD_LINK_SPEED_BITMASK_10MBPS 0x2 #define AD_LINK_SPEED_BITMASK_100MBPS 0x4 #define AD_LINK_SPEED_BITMASK_1000MBPS 0x8 #define AD_LINK_SPEED_BITMASK_10000MBPS 0x10 -//endalloun /* compare MAC addresses */ #define MAC_ADDRESS_EQUAL(A, B) \ @@ -100,7 +101,7 @@ static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR; -// ================= main 802.3ad protocol functions ================== +/* ================= main 802.3ad protocol functions ================== */ static int ad_lacpdu_send(struct port *port); static int ad_marker_send(struct port *port, struct bond_marker *marker); static void ad_mux_machine(struct port *port); @@ -114,13 +115,13 @@ static void ad_initialize_agg(struct aggregator *aggregator); static void ad_initialize_port(struct port *port, int lacp_fast); static void ad_enable_collecting_distributing(struct port *port); static void ad_disable_collecting_distributing(struct port *port); -static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port); -static void ad_marker_response_received(struct bond_marker *marker, struct port *port); +static void ad_marker_info_received(struct bond_marker *marker_info, + struct port *port); +static void ad_marker_response_received(struct bond_marker *marker, + struct port *port); -///////////////////////////////////////////////////////////////////////////////// -// ================= api to bonding and kernel code ================== -///////////////////////////////////////////////////////////////////////////////// +/* ================= api to bonding and kernel code ================== */ /** * __get_bond_by_port - get the port's bonding struct @@ -142,26 +143,32 @@ static inline struct bonding *__get_bond_by_port(struct port *port) * * Return the aggregator of the first slave in @bond, or %NULL if it can't be * found. + * The caller must hold RCU or RTNL lock. */ static inline struct aggregator *__get_first_agg(struct port *port) { struct bonding *bond = __get_bond_by_port(port); struct slave *first_slave; + struct aggregator *agg; /* If there's no bond for this port, or bond has no slaves */ if (bond == NULL) return NULL; + rcu_read_lock(); first_slave = bond_first_slave_rcu(bond); + agg = first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL; rcu_read_unlock(); - return first_slave ? &(SLAVE_AD_INFO(first_slave).aggregator) : NULL; + + return agg; } -/* - * __agg_has_partner +/** + * __agg_has_partner - see if we have a partner + * @agg: the agregator we're looking at * * Return nonzero if aggregator has a partner (denoted by a non-zero ether - * address for the partner). Return 0 if not. + * address for the partner). Return 0 if not. */ static inline int __agg_has_partner(struct aggregator *agg) { @@ -171,7 +178,6 @@ static inline int __agg_has_partner(struct aggregator *agg) /** * __disable_port - disable the port's slave * @port: the port we're looking at - * */ static inline void __disable_port(struct port *port) { @@ -181,7 +187,6 @@ static inline void __disable_port(struct port *port) /** * __enable_port - enable the port's slave, if it's up * @port: the port we're looking at - * */ static inline void __enable_port(struct port *port) { @@ -194,7 +199,6 @@ static inline void __enable_port(struct port *port) /** * __port_is_enabled - check if the port's slave is in active state * @port: the port we're looking at - * */ static inline int __port_is_enabled(struct port *port) { @@ -220,7 +224,6 @@ static inline u32 __get_agg_selection_mode(struct port *port) /** * __check_agg_selection_timer - check if the selection timer has expired * @port: the port we're looking at - * */ static inline int __check_agg_selection_timer(struct port *port) { @@ -235,7 +238,6 @@ static inline int __check_agg_selection_timer(struct port *port) /** * __get_state_machine_lock - lock the port's state machines * @port: the port we're looking at - * */ static inline void __get_state_machine_lock(struct port *port) { @@ -245,7 +247,6 @@ static inline void __get_state_machine_lock(struct port *port) /** * __release_state_machine_lock - unlock the port's state machines * @port: the port we're looking at - * */ static inline void __release_state_machine_lock(struct port *port) { @@ -268,10 +269,11 @@ static u16 __get_link_speed(struct port *port) struct slave *slave = port->slave; u16 speed; - /* this if covers only a special case: when the configuration starts with - * link down, it sets the speed to 0. - * This is done in spite of the fact that the e100 driver reports 0 to be - * compatible with MVT in the future.*/ + /* this if covers only a special case: when the configuration starts + * with link down, it sets the speed to 0. + * This is done in spite of the fact that the e100 driver reports 0 + * to be compatible with MVT in the future. + */ if (slave->link != BOND_LINK_UP) speed = 0; else { @@ -293,7 +295,8 @@ static u16 __get_link_speed(struct port *port) break; default: - speed = 0; // unknown speed value from ethtool. shouldn't happen + /* unknown speed value from ethtool. shouldn't happen */ + speed = 0; break; } } @@ -317,8 +320,9 @@ static u8 __get_duplex(struct port *port) u8 retval; - // handling a special case: when the configuration starts with - // link down, it sets the duplex to 0. + /* handling a special case: when the configuration starts with + * link down, it sets the duplex to 0. + */ if (slave->link != BOND_LINK_UP) retval = 0x0; else { @@ -342,15 +346,14 @@ static u8 __get_duplex(struct port *port) /** * __initialize_port_locks - initialize a port's STATE machine spinlock * @port: the slave of the port we're looking at - * */ static inline void __initialize_port_locks(struct slave *slave) { - // make sure it isn't called twice + /* make sure it isn't called twice */ spin_lock_init(&(SLAVE_AD_INFO(slave).state_machine_lock)); } -//conversions +/* Conversions */ /** * __ad_timer_to_ticks - convert a given timer type to AD module ticks @@ -359,39 +362,38 @@ static inline void __initialize_port_locks(struct slave *slave) * * If @timer_type is %current_while_timer, @par indicates long/short timer. * If @timer_type is %periodic_timer, @par is one of %FAST_PERIODIC_TIME, - * %SLOW_PERIODIC_TIME. + * %SLOW_PERIODIC_TIME. */ static u16 __ad_timer_to_ticks(u16 timer_type, u16 par) { u16 retval = 0; /* to silence the compiler */ switch (timer_type) { - case AD_CURRENT_WHILE_TIMER: // for rx machine usage + case AD_CURRENT_WHILE_TIMER: /* for rx machine usage */ if (par) - retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); // short timeout + retval = (AD_SHORT_TIMEOUT_TIME*ad_ticks_per_sec); else - retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); // long timeout + retval = (AD_LONG_TIMEOUT_TIME*ad_ticks_per_sec); break; - case AD_ACTOR_CHURN_TIMER: // for local churn machine + case AD_ACTOR_CHURN_TIMER: /* for local churn machine */ retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec); break; - case AD_PERIODIC_TIMER: // for periodic machine - retval = (par*ad_ticks_per_sec); // long timeout + case AD_PERIODIC_TIMER: /* for periodic machine */ + retval = (par*ad_ticks_per_sec); /* long timeout */ break; - case AD_PARTNER_CHURN_TIMER: // for remote churn machine + case AD_PARTNER_CHURN_TIMER: /* for remote churn machine */ retval = (AD_CHURN_DETECTION_TIME*ad_ticks_per_sec); break; - case AD_WAIT_WHILE_TIMER: // for selection machine + case AD_WAIT_WHILE_TIMER: /* for selection machine */ retval = (AD_AGGREGATE_WAIT_TIME*ad_ticks_per_sec); break; } + return retval; } -///////////////////////////////////////////////////////////////////////////////// -// ================= ad_rx_machine helper functions ================== -///////////////////////////////////////////////////////////////////////////////// +/* ================= ad_rx_machine helper functions ================== */ /** * __choose_matched - update a port's matched variable from a received lacpdu @@ -451,7 +453,9 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) struct port_params *partner = &port->partner_oper; __choose_matched(lacpdu, port); - // record the new parameter values for the partner operational + /* record the new parameter values for the partner + * operational + */ partner->port_number = ntohs(lacpdu->actor_port); partner->port_priority = ntohs(lacpdu->actor_port_priority); partner->system = lacpdu->actor_system; @@ -459,10 +463,12 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) partner->key = ntohs(lacpdu->actor_key); partner->port_state = lacpdu->actor_state; - // set actor_oper_port_state.defaulted to FALSE + /* set actor_oper_port_state.defaulted to FALSE */ port->actor_oper_port_state &= ~AD_STATE_DEFAULTED; - // set the partner sync. to on if the partner is sync. and the port is matched + /* set the partner sync. to on if the partner is sync, + * and the port is matched + */ if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) partner->port_state |= AD_STATE_SYNCHRONIZATION; @@ -482,11 +488,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) static void __record_default(struct port *port) { if (port) { - // record the partner admin parameters + /* record the partner admin parameters */ memcpy(&port->partner_oper, &port->partner_admin, sizeof(struct port_params)); - // set actor_oper_port_state.defaulted to true + /* set actor_oper_port_state.defaulted to true */ port->actor_oper_port_state |= AD_STATE_DEFAULTED; } } @@ -591,36 +597,6 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port) } /** - * __attach_bond_to_agg - * @port: the port we're looking at - * - * Handle the attaching of the port's control parser/multiplexer and the - * aggregator. This function does nothing since the parser/multiplexer of the - * receive and the parser/multiplexer of the aggregator are already combined. - */ -static void __attach_bond_to_agg(struct port *port) -{ - port = NULL; /* just to satisfy the compiler */ - // This function does nothing since the parser/multiplexer of the receive - // and the parser/multiplexer of the aggregator are already combined -} - -/** - * __detach_bond_from_agg - * @port: the port we're looking at - * - * Handle the detaching of the port's control parser/multiplexer from the - * aggregator. This function does nothing since the parser/multiplexer of the - * receive and the parser/multiplexer of the aggregator are already combined. - */ -static void __detach_bond_from_agg(struct port *port) -{ - port = NULL; /* just to satisfy the compiler */ - // This function does nothing since the parser/multiplexer of the receive - // and the parser/multiplexer of the aggregator are already combined -} - -/** * __agg_ports_are_ready - check if all ports in an aggregator are ready * @aggregator: the aggregator we're looking at * @@ -631,7 +607,9 @@ static int __agg_ports_are_ready(struct aggregator *aggregator) int retval = 1; if (aggregator) { - // scan all ports in this aggregator to verfy if they are all ready + /* scan all ports in this aggregator to verfy if they are + * all ready. + */ for (port = aggregator->lag_ports; port; port = port->next_port_in_aggregator) { @@ -691,7 +669,7 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) bandwidth = aggregator->num_of_ports * 10000; break; default: - bandwidth = 0; /*to silence the compiler ....*/ + bandwidth = 0; /* to silence the compiler */ } } return bandwidth; @@ -701,6 +679,7 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator) * __get_active_agg - get the current active aggregator * @aggregator: the aggregator we're looking at * + * Caller must hold RCU lock. */ static struct aggregator *__get_active_agg(struct aggregator *aggregator) { @@ -708,13 +687,9 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator) struct list_head *iter; struct slave *slave; - rcu_read_lock(); bond_for_each_slave_rcu(bond, slave, iter) - if (SLAVE_AD_INFO(slave).aggregator.is_active) { - rcu_read_unlock(); + if (SLAVE_AD_INFO(slave).aggregator.is_active) return &(SLAVE_AD_INFO(slave).aggregator); - } - rcu_read_unlock(); return NULL; } @@ -722,15 +697,14 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator) /** * __update_lacpdu_from_port - update a port's lacpdu fields * @port: the port we're looking at - * */ static inline void __update_lacpdu_from_port(struct port *port) { struct lacpdu *lacpdu = &port->lacpdu; const struct port_params *partner = &port->partner_oper; - /* update current actual Actor parameters */ - /* lacpdu->subtype initialized + /* update current actual Actor parameters + * lacpdu->subtype initialized * lacpdu->version_number initialized * lacpdu->tlv_type_actor_info initialized * lacpdu->actor_information_length initialized @@ -766,9 +740,7 @@ static inline void __update_lacpdu_from_port(struct port *port) */ } -////////////////////////////////////////////////////////////////////////////////////// -// ================= main 802.3ad protocol code ====================================== -////////////////////////////////////////////////////////////////////////////////////// +/* ================= main 802.3ad protocol code ========================= */ /** * ad_lacpdu_send - send out a lacpdu packet on a given port @@ -798,11 +770,12 @@ static int ad_lacpdu_send(struct port *port) memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); /* Note: source address is set to be the member's PERMANENT address, - because we use it to identify loopback lacpdus in receive. */ + * because we use it to identify loopback lacpdus in receive. + */ memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU; - lacpdu_header->lacpdu = port->lacpdu; // struct copy + lacpdu_header->lacpdu = port->lacpdu; dev_queue_xmit(skb); @@ -839,11 +812,12 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); /* Note: source address is set to be the member's PERMANENT address, - because we use it to identify loopback MARKERs in receive. */ + * because we use it to identify loopback MARKERs in receive. + */ memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); marker_header->hdr.h_proto = PKT_TYPE_LACPDU; - marker_header->marker = *marker; // struct copy + marker_header->marker = *marker; dev_queue_xmit(skb); @@ -853,72 +827,90 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) /** * ad_mux_machine - handle a port's mux state machine * @port: the port we're looking at - * */ static void ad_mux_machine(struct port *port) { mux_states_t last_state; - // keep current State Machine state to compare later if it was changed + /* keep current State Machine state to compare later if it was + * changed + */ last_state = port->sm_mux_state; if (port->sm_vars & AD_PORT_BEGIN) { - port->sm_mux_state = AD_MUX_DETACHED; // next state + port->sm_mux_state = AD_MUX_DETACHED; } else { switch (port->sm_mux_state) { case AD_MUX_DETACHED: if ((port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) /* if SELECTED or STANDBY */ - port->sm_mux_state = AD_MUX_WAITING; // next state + port->sm_mux_state = AD_MUX_WAITING; break; case AD_MUX_WAITING: - // if SELECTED == FALSE return to DETACH state - if (!(port->sm_vars & AD_PORT_SELECTED)) { // if UNSELECTED + /* if SELECTED == FALSE return to DETACH state */ + if (!(port->sm_vars & AD_PORT_SELECTED)) { port->sm_vars &= ~AD_PORT_READY_N; - // in order to withhold the Selection Logic to check all ports READY_N value - // every callback cycle to update ready variable, we check READY_N and update READY here + /* in order to withhold the Selection Logic to + * check all ports READY_N value every callback + * cycle to update ready variable, we check + * READY_N and update READY here + */ __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); - port->sm_mux_state = AD_MUX_DETACHED; // next state + port->sm_mux_state = AD_MUX_DETACHED; break; } - // check if the wait_while_timer expired + /* check if the wait_while_timer expired */ if (port->sm_mux_timer_counter && !(--port->sm_mux_timer_counter)) port->sm_vars |= AD_PORT_READY_N; - // in order to withhold the selection logic to check all ports READY_N value - // every callback cycle to update ready variable, we check READY_N and update READY here + /* in order to withhold the selection logic to check + * all ports READY_N value every callback cycle to + * update ready variable, we check READY_N and update + * READY here + */ __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); - // if the wait_while_timer expired, and the port is in READY state, move to ATTACHED state + /* if the wait_while_timer expired, and the port is + * in READY state, move to ATTACHED state + */ if ((port->sm_vars & AD_PORT_READY) && !port->sm_mux_timer_counter) - port->sm_mux_state = AD_MUX_ATTACHED; // next state + port->sm_mux_state = AD_MUX_ATTACHED; break; case AD_MUX_ATTACHED: - // check also if agg_select_timer expired(so the edable port will take place only after this timer) - if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { - port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state - } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if UNSELECTED or STANDBY + /* check also if agg_select_timer expired (so the + * edable port will take place only after this timer) + */ + if ((port->sm_vars & AD_PORT_SELECTED) && + (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && + !__check_agg_selection_timer(port)) { + port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING; + } else if (!(port->sm_vars & AD_PORT_SELECTED) || + (port->sm_vars & AD_PORT_STANDBY)) { + /* if UNSELECTED or STANDBY */ port->sm_vars &= ~AD_PORT_READY_N; - // in order to withhold the selection logic to check all ports READY_N value - // every callback cycle to update ready variable, we check READY_N and update READY here + /* in order to withhold the selection logic to + * check all ports READY_N value every callback + * cycle to update ready variable, we check + * READY_N and update READY here + */ __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); - port->sm_mux_state = AD_MUX_DETACHED;// next state + port->sm_mux_state = AD_MUX_DETACHED; } break; case AD_MUX_COLLECTING_DISTRIBUTING: - if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) || - !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) - ) { - port->sm_mux_state = AD_MUX_ATTACHED;// next state - + if (!(port->sm_vars & AD_PORT_SELECTED) || + (port->sm_vars & AD_PORT_STANDBY) || + !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)) { + port->sm_mux_state = AD_MUX_ATTACHED; } else { - // if port state hasn't changed make - // sure that a collecting distributing - // port in an active aggregator is enabled + /* if port state hasn't changed make + * sure that a collecting distributing + * port in an active aggregator is enabled + */ if (port->aggregator && port->aggregator->is_active && !__port_is_enabled(port)) { @@ -927,19 +919,18 @@ static void ad_mux_machine(struct port *port) } } break; - default: //to silence the compiler + default: break; } } - // check if the state machine was changed + /* check if the state machine was changed */ if (port->sm_mux_state != last_state) { pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: - __detach_bond_from_agg(port); port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; ad_disable_collecting_distributing(port); port->actor_oper_port_state &= ~AD_STATE_COLLECTING; @@ -950,7 +941,6 @@ static void ad_mux_machine(struct port *port) port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); break; case AD_MUX_ATTACHED: - __attach_bond_to_agg(port); port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION; port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; @@ -963,7 +953,7 @@ static void ad_mux_machine(struct port *port) ad_enable_collecting_distributing(port); port->ntt = true; break; - default: //to silence the compiler + default: break; } } @@ -982,59 +972,63 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) { rx_states_t last_state; - // keep current State Machine state to compare later if it was changed + /* keep current State Machine state to compare later if it was + * changed + */ last_state = port->sm_rx_state; - // check if state machine should change state - // first, check if port was reinitialized + /* check if state machine should change state */ + + /* first, check if port was reinitialized */ if (port->sm_vars & AD_PORT_BEGIN) - /* next state */ port->sm_rx_state = AD_RX_INITIALIZE; - // check if port is not enabled + /* check if port is not enabled */ else if (!(port->sm_vars & AD_PORT_BEGIN) && !port->is_enabled && !(port->sm_vars & AD_PORT_MOVED)) - /* next state */ port->sm_rx_state = AD_RX_PORT_DISABLED; - // check if new lacpdu arrived - else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || (port->sm_rx_state == AD_RX_DEFAULTED) || (port->sm_rx_state == AD_RX_CURRENT))) { - port->sm_rx_timer_counter = 0; // zero timer + /* check if new lacpdu arrived */ + else if (lacpdu && ((port->sm_rx_state == AD_RX_EXPIRED) || + (port->sm_rx_state == AD_RX_DEFAULTED) || + (port->sm_rx_state == AD_RX_CURRENT))) { + port->sm_rx_timer_counter = 0; port->sm_rx_state = AD_RX_CURRENT; } else { - // if timer is on, and if it is expired - if (port->sm_rx_timer_counter && !(--port->sm_rx_timer_counter)) { + /* if timer is on, and if it is expired */ + if (port->sm_rx_timer_counter && + !(--port->sm_rx_timer_counter)) { switch (port->sm_rx_state) { case AD_RX_EXPIRED: - port->sm_rx_state = AD_RX_DEFAULTED; // next state + port->sm_rx_state = AD_RX_DEFAULTED; break; case AD_RX_CURRENT: - port->sm_rx_state = AD_RX_EXPIRED; // next state + port->sm_rx_state = AD_RX_EXPIRED; break; - default: //to silence the compiler + default: break; } } else { - // if no lacpdu arrived and no timer is on + /* if no lacpdu arrived and no timer is on */ switch (port->sm_rx_state) { case AD_RX_PORT_DISABLED: if (port->sm_vars & AD_PORT_MOVED) - port->sm_rx_state = AD_RX_INITIALIZE; // next state + port->sm_rx_state = AD_RX_INITIALIZE; else if (port->is_enabled && (port->sm_vars & AD_PORT_LACP_ENABLED)) - port->sm_rx_state = AD_RX_EXPIRED; // next state + port->sm_rx_state = AD_RX_EXPIRED; else if (port->is_enabled && ((port->sm_vars & AD_PORT_LACP_ENABLED) == 0)) - port->sm_rx_state = AD_RX_LACP_DISABLED; // next state + port->sm_rx_state = AD_RX_LACP_DISABLED; break; - default: //to silence the compiler + default: break; } } } - // check if the State machine was changed or new lacpdu arrived + /* check if the State machine was changed or new lacpdu arrived */ if ((port->sm_rx_state != last_state) || (lacpdu)) { pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, @@ -1049,10 +1043,9 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) __record_default(port); port->actor_oper_port_state &= ~AD_STATE_EXPIRED; port->sm_vars &= ~AD_PORT_MOVED; - port->sm_rx_state = AD_RX_PORT_DISABLED; // next state - - /*- Fall Through -*/ + port->sm_rx_state = AD_RX_PORT_DISABLED; + /* Fall Through */ case AD_RX_PORT_DISABLED: port->sm_vars &= ~AD_PORT_MATCHED; break; @@ -1064,13 +1057,15 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) port->actor_oper_port_state &= ~AD_STATE_EXPIRED; break; case AD_RX_EXPIRED: - //Reset of the Synchronization flag. (Standard 43.4.12) - //This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the - //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port. + /* Reset of the Synchronization flag (Standard 43.4.12) + * This reset cause to disable this port in the + * COLLECTING_DISTRIBUTING state of the mux machine in + * case of EXPIRED even if LINK_DOWN didn't arrive for + * the port. + */ port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; - port->partner_oper.port_state |= - AD_STATE_LACP_ACTIVITY; + port->partner_oper.port_state |= AD_STATE_LACP_ACTIVITY; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; break; @@ -1082,10 +1077,11 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) break; case AD_RX_CURRENT: /* detect loopback situation */ - if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system), &(port->actor_system))) { - pr_err("%s: An illegal loopback occurred on adapter (%s).\n" - "Check the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n", - port->slave->bond->dev->name, port->slave->dev->name); + if (MAC_ADDRESS_EQUAL(&(lacpdu->actor_system), + &(port->actor_system))) { + pr_err("%s: An illegal loopback occurred on adapter (%s).\nCheck the configuration to verify that all adapters are connected to 802.3ad compliant switch ports\n", + port->slave->bond->dev->name, + port->slave->dev->name); return; } __update_selected(lacpdu, port); @@ -1094,7 +1090,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)); port->actor_oper_port_state &= ~AD_STATE_EXPIRED; break; - default: /* to silence the compiler */ + default: break; } } @@ -1103,13 +1099,14 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) /** * ad_tx_machine - handle a port's tx state machine * @port: the port we're looking at - * */ static void ad_tx_machine(struct port *port) { - // check if tx timer expired, to verify that we do not send more than 3 packets per second + /* check if tx timer expired, to verify that we do not send more than + * 3 packets per second + */ if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) { - // check if there is something to send + /* check if there is something to send */ if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) { __update_lacpdu_from_port(port); @@ -1117,14 +1114,16 @@ static void ad_tx_machine(struct port *port) pr_debug("Sent LACPDU on port %d\n", port->actor_port_number); - /* mark ntt as false, so it will not be sent again until - demanded */ + /* mark ntt as false, so it will not be sent + * again until demanded + */ port->ntt = false; } } - // restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND - port->sm_tx_timer_counter = - ad_ticks_per_sec/AD_MAX_TX_IN_SECOND; + /* restart tx timer(to verify that we will not exceed + * AD_MAX_TX_IN_SECOND + */ + port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND; } } @@ -1138,76 +1137,79 @@ static void ad_periodic_machine(struct port *port) { periodic_states_t last_state; - // keep current state machine state to compare later if it was changed + /* keep current state machine state to compare later if it was changed */ last_state = port->sm_periodic_state; - // check if port was reinitialized + /* check if port was reinitialized */ if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) || (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & AD_STATE_LACP_ACTIVITY)) ) { - port->sm_periodic_state = AD_NO_PERIODIC; // next state + port->sm_periodic_state = AD_NO_PERIODIC; } - // check if state machine should change state + /* check if state machine should change state */ else if (port->sm_periodic_timer_counter) { - // check if periodic state machine expired + /* check if periodic state machine expired */ if (!(--port->sm_periodic_timer_counter)) { - // if expired then do tx - port->sm_periodic_state = AD_PERIODIC_TX; // next state + /* if expired then do tx */ + port->sm_periodic_state = AD_PERIODIC_TX; } else { - // If not expired, check if there is some new timeout parameter from the partner state + /* If not expired, check if there is some new timeout + * parameter from the partner state + */ switch (port->sm_periodic_state) { case AD_FAST_PERIODIC: if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) - port->sm_periodic_state = AD_SLOW_PERIODIC; // next state + port->sm_periodic_state = AD_SLOW_PERIODIC; break; case AD_SLOW_PERIODIC: if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { - // stop current timer port->sm_periodic_timer_counter = 0; - port->sm_periodic_state = AD_PERIODIC_TX; // next state + port->sm_periodic_state = AD_PERIODIC_TX; } break; - default: //to silence the compiler + default: break; } } } else { switch (port->sm_periodic_state) { case AD_NO_PERIODIC: - port->sm_periodic_state = AD_FAST_PERIODIC; // next state + port->sm_periodic_state = AD_FAST_PERIODIC; break; case AD_PERIODIC_TX: - if (!(port->partner_oper.port_state - & AD_STATE_LACP_TIMEOUT)) - port->sm_periodic_state = AD_SLOW_PERIODIC; // next state + if (!(port->partner_oper.port_state & + AD_STATE_LACP_TIMEOUT)) + port->sm_periodic_state = AD_SLOW_PERIODIC; else - port->sm_periodic_state = AD_FAST_PERIODIC; // next state + port->sm_periodic_state = AD_FAST_PERIODIC; break; - default: //to silence the compiler + default: break; } } - // check if the state machine was changed + /* check if the state machine was changed */ if (port->sm_periodic_state != last_state) { pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: - port->sm_periodic_timer_counter = 0; // zero timer + port->sm_periodic_timer_counter = 0; break; case AD_FAST_PERIODIC: - port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle + /* decrement 1 tick we lost in the PERIODIC_TX cycle */ + port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_FAST_PERIODIC_TIME))-1; break; case AD_SLOW_PERIODIC: - port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle + /* decrement 1 tick we lost in the PERIODIC_TX cycle */ + port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; break; case AD_PERIODIC_TX: port->ntt = true; break; - default: //to silence the compiler + default: break; } } @@ -1230,30 +1232,38 @@ static void ad_port_selection_logic(struct port *port) struct slave *slave; int found = 0; - // if the port is already Selected, do nothing + /* if the port is already Selected, do nothing */ if (port->sm_vars & AD_PORT_SELECTED) return; bond = __get_bond_by_port(port); - // if the port is connected to other aggregator, detach it + /* if the port is connected to other aggregator, detach it */ if (port->aggregator) { - // detach the port from its former aggregator + /* detach the port from its former aggregator */ temp_aggregator = port->aggregator; for (curr_port = temp_aggregator->lag_ports; curr_port; last_port = curr_port, - curr_port = curr_port->next_port_in_aggregator) { + curr_port = curr_port->next_port_in_aggregator) { if (curr_port == port) { temp_aggregator->num_of_ports--; - if (!last_port) {// if it is the first port attached to the aggregator + /* if it is the first port attached to the + * aggregator + */ + if (!last_port) { temp_aggregator->lag_ports = port->next_port_in_aggregator; - } else {// not the first port attached to the aggregator + } else { + /* not the first port attached to the + * aggregator + */ last_port->next_port_in_aggregator = port->next_port_in_aggregator; } - // clear the port's relations to this aggregator + /* clear the port's relations to this + * aggregator + */ port->aggregator = NULL; port->next_port_in_aggregator = NULL; port->actor_port_aggregator_identifier = 0; @@ -1261,25 +1271,30 @@ static void ad_port_selection_logic(struct port *port) pr_debug("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); - // if the aggregator is empty, clear its parameters, and set it ready to be attached + /* if the aggregator is empty, clear its + * parameters, and set it ready to be attached + */ if (!temp_aggregator->lag_ports) ad_clear_agg(temp_aggregator); break; } } - if (!curr_port) { // meaning: the port was related to an aggregator but was not on the aggregator port list - pr_warning("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n", - port->slave->bond->dev->name, - port->actor_port_number, - port->slave->dev->name, - port->aggregator->aggregator_identifier); + if (!curr_port) { + /* meaning: the port was related to an aggregator + * but was not on the aggregator port list + */ + pr_warn("%s: Warning: Port %d (on %s) was related to aggregator %d but was not on its port list\n", + port->slave->bond->dev->name, + port->actor_port_number, + port->slave->dev->name, + port->aggregator->aggregator_identifier); } } - // search on all aggregators for a suitable aggregator for this port + /* search on all aggregators for a suitable aggregator for this port */ bond_for_each_slave(bond, slave, iter) { aggregator = &(SLAVE_AD_INFO(slave).aggregator); - // keep a free aggregator for later use(if needed) + /* keep a free aggregator for later use(if needed) */ if (!aggregator->lag_ports) { if (!free_aggregator) free_aggregator = aggregator; @@ -1306,23 +1321,26 @@ static void ad_port_selection_logic(struct port *port) port->actor_port_number, port->aggregator->aggregator_identifier); - // mark this port as selected + /* mark this port as selected */ port->sm_vars |= AD_PORT_SELECTED; found = 1; break; } } - // the port couldn't find an aggregator - attach it to a new aggregator + /* the port couldn't find an aggregator - attach it to a new + * aggregator + */ if (!found) { if (free_aggregator) { - // assign port a new aggregator + /* assign port a new aggregator */ port->aggregator = free_aggregator; port->actor_port_aggregator_identifier = port->aggregator->aggregator_identifier; - // update the new aggregator's parameters - // if port was responsed from the end-user + /* update the new aggregator's parameters + * if port was responsed from the end-user + */ if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) /* if port is full duplex */ port->aggregator->is_individual = false; @@ -1341,7 +1359,7 @@ static void ad_port_selection_logic(struct port *port) port->aggregator->lag_ports = port; port->aggregator->num_of_ports++; - // mark this port as selected + /* mark this port as selected */ port->sm_vars |= AD_PORT_SELECTED; pr_debug("Port %d joined LAG %d(new LAG)\n", @@ -1353,23 +1371,24 @@ static void ad_port_selection_logic(struct port *port) port->actor_port_number, port->slave->dev->name); } } - // if all aggregator's ports are READY_N == TRUE, set ready=TRUE in all aggregator's ports - // else set ready=FALSE in all aggregator's ports - __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); + /* if all aggregator's ports are READY_N == TRUE, set ready=TRUE + * in all aggregator's ports, else set ready=FALSE in all + * aggregator's ports + */ + __set_agg_ports_ready(port->aggregator, + __agg_ports_are_ready(port->aggregator)); aggregator = __get_first_agg(port); ad_agg_selection_logic(aggregator); } -/* - * Decide if "agg" is a better choice for the new active aggregator that +/* Decide if "agg" is a better choice for the new active aggregator that * the current best, according to the ad_select policy. */ static struct aggregator *ad_agg_selection_test(struct aggregator *best, struct aggregator *curr) { - /* - * 0. If no best, select current. + /* 0. If no best, select current. * * 1. If the current agg is not individual, and the best is * individual, select current. @@ -1425,9 +1444,9 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, break; default: - pr_warning("%s: Impossible agg select mode %d\n", - curr->slave->bond->dev->name, - __get_agg_selection_mode(curr->lag_ports)); + pr_warn("%s: Impossible agg select mode %d\n", + curr->slave->bond->dev->name, + __get_agg_selection_mode(curr->lag_ports)); break; } @@ -1437,10 +1456,12 @@ static struct aggregator *ad_agg_selection_test(struct aggregator *best, static int agg_device_up(const struct aggregator *agg) { struct port *port = agg->lag_ports; + if (!port) return 0; - return (netif_running(port->slave->dev) && - netif_carrier_ok(port->slave->dev)); + + return netif_running(port->slave->dev) && + netif_carrier_ok(port->slave->dev); } /** @@ -1476,11 +1497,11 @@ static void ad_agg_selection_logic(struct aggregator *agg) struct slave *slave; struct port *port; + rcu_read_lock(); origin = agg; active = __get_active_agg(agg); best = (active && agg_device_up(active)) ? active : NULL; - rcu_read_lock(); bond_for_each_slave_rcu(bond, slave, iter) { agg = &(SLAVE_AD_INFO(slave).aggregator); @@ -1492,8 +1513,7 @@ static void ad_agg_selection_logic(struct aggregator *agg) if (best && __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) { - /* - * For the STABLE policy, don't replace the old active + /* For the STABLE policy, don't replace the old active * aggregator if it's still active (it has an answering * partner) or if both the best and active don't have an * answering partner. @@ -1501,7 +1521,8 @@ static void ad_agg_selection_logic(struct aggregator *agg) if (active && active->lag_ports && active->lag_ports->is_enabled && (__agg_has_partner(active) || - (!__agg_has_partner(active) && !__agg_has_partner(best)))) { + (!__agg_has_partner(active) && + !__agg_has_partner(best)))) { if (!(!active->actor_oper_aggregator_key && best->actor_oper_aggregator_key)) { best = NULL; @@ -1538,7 +1559,7 @@ static void ad_agg_selection_logic(struct aggregator *agg) /* check if any partner replys */ if (best->is_individual) { - pr_warning("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", + pr_warn("%s: Warning: No 802.3ad response from the link partner for any adapters in the bond\n", best->slave ? best->slave->bond->dev->name : "NULL"); } @@ -1552,7 +1573,9 @@ static void ad_agg_selection_logic(struct aggregator *agg) best->partner_oper_aggregator_key, best->is_individual, best->is_active); - /* disable the ports that were related to the former active_aggregator */ + /* disable the ports that were related to the former + * active_aggregator + */ if (active) { for (port = active->lag_ports; port; port = port->next_port_in_aggregator) { @@ -1561,8 +1584,7 @@ static void ad_agg_selection_logic(struct aggregator *agg) } } - /* - * if the selected aggregator is of join individuals + /* if the selected aggregator is of join individuals * (partner_system is NULL), enable their ports */ active = __get_active_agg(origin); @@ -1584,7 +1606,6 @@ static void ad_agg_selection_logic(struct aggregator *agg) /** * ad_clear_agg - clear a given aggregator's parameters * @aggregator: the aggregator we're looking at - * */ static void ad_clear_agg(struct aggregator *aggregator) { @@ -1608,7 +1629,6 @@ static void ad_clear_agg(struct aggregator *aggregator) /** * ad_initialize_agg - initialize a given aggregator's parameters * @aggregator: the aggregator we're looking at - * */ static void ad_initialize_agg(struct aggregator *aggregator) { @@ -1625,7 +1645,6 @@ static void ad_initialize_agg(struct aggregator *aggregator) * ad_initialize_port - initialize a given port's parameters * @aggregator: the aggregator we're looking at * @lacp_fast: boolean. whether fast periodic should be used - * */ static void ad_initialize_port(struct port *port, int lacp_fast) { @@ -1657,8 +1676,10 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->ntt = false; port->actor_admin_port_key = 1; port->actor_oper_port_key = 1; - port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; - port->actor_oper_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; + port->actor_admin_port_state = AD_STATE_AGGREGATION | + AD_STATE_LACP_ACTIVITY; + port->actor_oper_port_state = AD_STATE_AGGREGATION | + AD_STATE_LACP_ACTIVITY; if (lacp_fast) port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT; @@ -1667,7 +1688,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast) memcpy(&port->partner_oper, &tmpl, sizeof(tmpl)); port->is_enabled = true; - // ****** private parameters ****** + /* private parameters */ port->sm_vars = 0x3; port->sm_rx_state = 0; port->sm_rx_timer_counter = 0; @@ -1705,11 +1726,12 @@ static void ad_enable_collecting_distributing(struct port *port) /** * ad_disable_collecting_distributing - disable a port's transmit/receive * @port: the port we're looking at - * */ static void ad_disable_collecting_distributing(struct port *port) { - if (port->aggregator && !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), &(null_mac_addr))) { + if (port->aggregator && + !MAC_ADDRESS_EQUAL(&(port->aggregator->partner_system), + &(null_mac_addr))) { pr_debug("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); @@ -1717,66 +1739,22 @@ static void ad_disable_collecting_distributing(struct port *port) } } -#if 0 -/** - * ad_marker_info_send - send a marker information frame - * @port: the port we're looking at - * - * This function does nothing since we decided not to implement send and handle - * response for marker PDU's, in this stage, but only to respond to marker - * information. - */ -static void ad_marker_info_send(struct port *port) -{ - struct bond_marker marker; - u16 index; - - // fill the marker PDU with the appropriate values - marker.subtype = 0x02; - marker.version_number = 0x01; - marker.tlv_type = AD_MARKER_INFORMATION_SUBTYPE; - marker.marker_length = 0x16; - // convert requester_port to Big Endian - marker.requester_port = (((port->actor_port_number & 0xFF) << 8) |((u16)(port->actor_port_number & 0xFF00) >> 8)); - marker.requester_system = port->actor_system; - // convert requester_port(u32) to Big Endian - marker.requester_transaction_id = - (((++port->transaction_id & 0xFF) << 24) - | ((port->transaction_id & 0xFF00) << 8) - | ((port->transaction_id & 0xFF0000) >> 8) - | ((port->transaction_id & 0xFF000000) >> 24)); - marker.pad = 0; - marker.tlv_type_terminator = 0x00; - marker.terminator_length = 0x00; - for (index = 0; index < 90; index++) - marker.reserved_90[index] = 0; - - // send the marker information - if (ad_marker_send(port, &marker) >= 0) { - pr_debug("Sent Marker Information on port %d\n", - port->actor_port_number); - } -} -#endif - /** * ad_marker_info_received - handle receive of a Marker information frame * @marker_info: Marker info received * @port: the port we're looking at - * */ static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port) { struct bond_marker marker; - // copy the received marker data to the response marker - //marker = *marker_info; + /* copy the received marker data to the response marker */ memcpy(&marker, marker_info, sizeof(struct bond_marker)); - // change the marker subtype to marker response + /* change the marker subtype to marker response */ marker.tlv_type = AD_MARKER_RESPONSE_SUBTYPE; - // send the marker response + /* send the marker response */ if (ad_marker_send(port, &marker) >= 0) { pr_debug("Sent Marker Response on port %d\n", port->actor_port_number); @@ -1793,22 +1771,21 @@ static void ad_marker_info_received(struct bond_marker *marker_info, * information. */ static void ad_marker_response_received(struct bond_marker *marker, - struct port *port) + struct port *port) { - marker = NULL; /* just to satisfy the compiler */ - port = NULL; /* just to satisfy the compiler */ - // DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW + marker = NULL; + port = NULL; + /* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */ } -////////////////////////////////////////////////////////////////////////////////////// -// ================= AD exported functions to the main bonding code ================== -////////////////////////////////////////////////////////////////////////////////////// +/* ========= AD exported functions to the main bonding code ========= */ -// Check aggregators status in team every T seconds +/* Check aggregators status in team every T seconds */ #define AD_AGGREGATOR_SELECTION_TIMER 8 -/* - * bond_3ad_initiate_agg_selection(struct bonding *bond) +/** + * bond_3ad_initiate_agg_selection - initate aggregator selection + * @bond: bonding struct * * Set the aggregation selection timer, to initiate an agg selection in * the very near future. Called during first initialization, and during @@ -1839,7 +1816,9 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); - // initialize how many times this module is called in one second(should be about every 100ms) + /* initialize how many times this module is called in one + * second (should be about every 100ms) + */ ad_ticks_per_sec = tick_resolution; bond_3ad_initiate_agg_selection(bond, @@ -1874,21 +1853,21 @@ void bond_3ad_bind_slave(struct slave *slave) port->actor_port_number = SLAVE_AD_INFO(slave).id; /* key is determined according to the link speed, duplex and user key(which * is yet not supported) - * ------------------------------------------------------------ - * Port key : | User key | Speed |Duplex| - * ------------------------------------------------------------ - * 16 6 1 0 */ - port->actor_admin_port_key = 0; /* initialize this parameter */ + port->actor_admin_port_key = 0; port->actor_admin_port_key |= __get_duplex(port); port->actor_admin_port_key |= (__get_link_speed(port) << 1); port->actor_oper_port_key = port->actor_admin_port_key; - /* if the port is not full duplex, then the port should be not lacp Enabled */ + /* if the port is not full duplex, then the port should be not + * lacp Enabled + */ if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) port->sm_vars &= ~AD_PORT_LACP_ENABLED; /* actor system is the bond's system */ port->actor_system = BOND_AD_INFO(bond).system.sys_mac_addr; - /* tx timer(to verify that no more than MAX_TX_IN_SECOND lacpdu's are sent in one second) */ + /* tx timer(to verify that no more than MAX_TX_IN_SECOND + * lacpdu's are sent in one second) + */ port->sm_tx_timer_counter = ad_ticks_per_sec/AD_MAX_TX_IN_SECOND; port->aggregator = NULL; port->next_port_in_aggregator = NULL; @@ -1925,16 +1904,13 @@ void bond_3ad_unbind_slave(struct slave *slave) struct slave *slave_iter; struct list_head *iter; - // find the aggregator related to this slave aggregator = &(SLAVE_AD_INFO(slave).aggregator); - - // find the port related to this slave port = &(SLAVE_AD_INFO(slave).port); - // if slave is null, the whole port is not initialized + /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warning("Warning: %s: Trying to unbind an uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + pr_warn("Warning: %s: Trying to unbind an uninitialized port on %s\n", + slave->bond->dev->name, slave->dev->name); return; } @@ -1946,34 +1922,42 @@ void bond_3ad_unbind_slave(struct slave *slave) __update_lacpdu_from_port(port); ad_lacpdu_send(port); - // check if this aggregator is occupied + /* check if this aggregator is occupied */ if (aggregator->lag_ports) { - // check if there are other ports related to this aggregator except - // the port related to this slave(thats ensure us that there is a - // reason to search for new aggregator, and that we will find one - if ((aggregator->lag_ports != port) || (aggregator->lag_ports->next_port_in_aggregator)) { - // find new aggregator for the related port(s) + /* check if there are other ports related to this aggregator + * except the port related to this slave(thats ensure us that + * there is a reason to search for new aggregator, and that we + * will find one + */ + if ((aggregator->lag_ports != port) || + (aggregator->lag_ports->next_port_in_aggregator)) { + /* find new aggregator for the related port(s) */ bond_for_each_slave(bond, slave_iter, iter) { new_aggregator = &(SLAVE_AD_INFO(slave_iter).aggregator); - // if the new aggregator is empty, or it is connected to our port only - if (!new_aggregator->lag_ports - || ((new_aggregator->lag_ports == port) - && !new_aggregator->lag_ports->next_port_in_aggregator)) + /* if the new aggregator is empty, or it is + * connected to our port only + */ + if (!new_aggregator->lag_ports || + ((new_aggregator->lag_ports == port) && + !new_aggregator->lag_ports->next_port_in_aggregator)) break; } if (!slave_iter) new_aggregator = NULL; - // if new aggregator found, copy the aggregator's parameters - // and connect the related lag_ports to the new aggregator + + /* if new aggregator found, copy the aggregator's + * parameters and connect the related lag_ports to the + * new aggregator + */ if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); - if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { + if ((new_aggregator->lag_ports == port) && + new_aggregator->is_active) { pr_info("%s: Removing an active aggregator\n", aggregator->slave->bond->dev->name); - // select new active aggregator select_new_active_agg = 1; } @@ -1989,30 +1973,33 @@ void bond_3ad_unbind_slave(struct slave *slave) new_aggregator->is_active = aggregator->is_active; new_aggregator->num_of_ports = aggregator->num_of_ports; - // update the information that is written on the ports about the aggregator + /* update the information that is written on + * the ports about the aggregator + */ for (temp_port = aggregator->lag_ports; temp_port; temp_port = temp_port->next_port_in_aggregator) { temp_port->aggregator = new_aggregator; temp_port->actor_port_aggregator_identifier = new_aggregator->aggregator_identifier; } - // clear the aggregator ad_clear_agg(aggregator); if (select_new_active_agg) ad_agg_selection_logic(__get_first_agg(port)); } else { - pr_warning("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n", - slave->bond->dev->name); + pr_warn("%s: Warning: unbinding aggregator, and could not find a new aggregator for its ports\n", + slave->bond->dev->name); } - } else { // in case that the only port related to this aggregator is the one we want to remove + } else { + /* in case that the only port related to this + * aggregator is the one we want to remove + */ select_new_active_agg = aggregator->is_active; - // clear the aggregator ad_clear_agg(aggregator); if (select_new_active_agg) { pr_info("%s: Removing an active aggregator\n", slave->bond->dev->name); - // select new active aggregator + /* select new active aggregator */ temp_aggregator = __get_first_agg(port); if (temp_aggregator) ad_agg_selection_logic(temp_aggregator); @@ -2021,15 +2008,19 @@ void bond_3ad_unbind_slave(struct slave *slave) } pr_debug("Unbinding port %d\n", port->actor_port_number); - // find the aggregator that this port is connected to + + /* find the aggregator that this port is connected to */ bond_for_each_slave(bond, slave_iter, iter) { temp_aggregator = &(SLAVE_AD_INFO(slave_iter).aggregator); prev_port = NULL; - // search the port in the aggregator's related ports + /* search the port in the aggregator's related ports */ for (temp_port = temp_aggregator->lag_ports; temp_port; prev_port = temp_port, - temp_port = temp_port->next_port_in_aggregator) { - if (temp_port == port) { // the aggregator found - detach the port from this aggregator + temp_port = temp_port->next_port_in_aggregator) { + if (temp_port == port) { + /* the aggregator found - detach the port from + * this aggregator + */ if (prev_port) prev_port->next_port_in_aggregator = temp_port->next_port_in_aggregator; else @@ -2037,12 +2028,11 @@ void bond_3ad_unbind_slave(struct slave *slave) temp_aggregator->num_of_ports--; if (temp_aggregator->num_of_ports == 0) { select_new_active_agg = temp_aggregator->is_active; - // clear the aggregator ad_clear_agg(temp_aggregator); if (select_new_active_agg) { pr_info("%s: Removing an active aggregator\n", slave->bond->dev->name); - // select new active aggregator + /* select new active aggregator */ ad_agg_selection_logic(__get_first_agg(port)); } } @@ -2083,15 +2073,16 @@ void bond_3ad_state_machine_handler(struct work_struct *work) goto re_arm; /* check if agg_select_timer timer after initialize is timed out */ - if (BOND_AD_INFO(bond).agg_select_timer && !(--BOND_AD_INFO(bond).agg_select_timer)) { + if (BOND_AD_INFO(bond).agg_select_timer && + !(--BOND_AD_INFO(bond).agg_select_timer)) { slave = bond_first_slave_rcu(bond); port = slave ? &(SLAVE_AD_INFO(slave).port) : NULL; /* select the active aggregator for the bond */ if (port) { if (!port->slave) { - pr_warning("%s: Warning: bond's first port is uninitialized\n", - bond->dev->name); + pr_warn("%s: Warning: bond's first port is uninitialized\n", + bond->dev->name); goto re_arm; } @@ -2105,8 +2096,8 @@ void bond_3ad_state_machine_handler(struct work_struct *work) bond_for_each_slave_rcu(bond, slave, iter) { port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - pr_warning("%s: Warning: Found an uninitialized port\n", - bond->dev->name); + pr_warn("%s: Warning: Found an uninitialized port\n", + bond->dev->name); goto re_arm; } @@ -2145,7 +2136,8 @@ re_arm: * received frames (loopback). Since only the payload is given to this * function, it check for loopback. */ -static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u16 length) +static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, + u16 length) { struct port *port; int ret = RX_HANDLER_ANOTHER; @@ -2155,8 +2147,8 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1 port = &(SLAVE_AD_INFO(slave).port); if (!port->slave) { - pr_warning("%s: Warning: port of slave %s is uninitialized\n", - slave->dev->name, slave->bond->dev->name); + pr_warn("%s: Warning: port of slave %s is uninitialized\n", + slave->dev->name, slave->bond->dev->name); return ret; } @@ -2173,7 +2165,9 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u1 case AD_TYPE_MARKER: ret = RX_HANDLER_CONSUMED; - // No need to convert fields to Little Endian since we don't use the marker's fields. + /* No need to convert fields to Little Endian since we + * don't use the marker's fields. + */ switch (((struct bond_marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: @@ -2211,8 +2205,8 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warning("Warning: %s: speed changed for uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + pr_warn("Warning: %s: speed changed for uninitialized port on %s\n", + slave->bond->dev->name, slave->dev->name); return; } @@ -2244,8 +2238,8 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warning("%s: Warning: duplex changed for uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + pr_warn("%s: Warning: duplex changed for uninitialized port on %s\n", + slave->bond->dev->name, slave->dev->name); return; } @@ -2278,8 +2272,8 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) /* if slave is null, the whole port is not initialized */ if (!port->slave) { - pr_warning("Warning: %s: link status changed for uninitialized port on %s\n", - slave->bond->dev->name, slave->dev->name); + pr_warn("Warning: %s: link status changed for uninitialized port on %s\n", + slave->bond->dev->name, slave->dev->name); return; } @@ -2317,10 +2311,13 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) __release_state_machine_lock(port); } -/* - * set link state for bonding master: if we have an active - * aggregator, we're up, if not, we're down. Presumes that we cannot - * have an active aggregator if there are no slaves with link up. +/** + * bond_3ad_set_carrier - set link state for bonding master + * @bond - bonding structure + * + * if we have an active aggregator, we're up, if not, we're down. + * Presumes that we cannot have an active aggregator if there are + * no slaves with link up. * * This behavior complies with IEEE 802.3 section 43.3.9. * @@ -2331,32 +2328,32 @@ int bond_3ad_set_carrier(struct bonding *bond) { struct aggregator *active; struct slave *first_slave; + int ret = 1; rcu_read_lock(); first_slave = bond_first_slave_rcu(bond); - rcu_read_unlock(); - if (!first_slave) - return 0; + if (!first_slave) { + ret = 0; + goto out; + } active = __get_active_agg(&(SLAVE_AD_INFO(first_slave).aggregator)); if (active) { /* are enough slaves available to consider link up? */ if (active->num_of_ports < bond->params.min_links) { if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); - return 1; + goto out; } } else if (!netif_carrier_ok(bond->dev)) { netif_carrier_on(bond->dev); - return 1; + goto out; } - return 0; - } - - if (netif_carrier_ok(bond->dev)) { + } else if (netif_carrier_ok(bond->dev)) { netif_carrier_off(bond->dev); - return 1; } - return 0; +out: + rcu_read_unlock(); + return ret; } /** @@ -2388,7 +2385,8 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond, ad_info->ports = aggregator->num_of_ports; ad_info->actor_key = aggregator->actor_oper_aggregator_key; ad_info->partner_key = aggregator->partner_oper_aggregator_key; - memcpy(ad_info->partner_system, aggregator->partner_system.mac_addr_value, ETH_ALEN); + memcpy(ad_info->partner_system, + aggregator->partner_system.mac_addr_value, ETH_ALEN); return 0; } @@ -2460,7 +2458,8 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) } /* we couldn't find any suitable slave after the agg_no, so use the - * first suitable found, if found. */ + * first suitable found, if found. + */ if (first_ok_slave) bond_dev_queue_xmit(bond, skb, first_ok_slave->dev); else @@ -2493,7 +2492,10 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, return ret; } -/* +/** + * bond_3ad_update_lacp_rate - change the lacp rate + * @bond - bonding struct + * * When modify lacp_rate parameter via sysfs, * update actor_oper_port_state of each port. * diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index e06c4453eabb..f2fe6cba384e 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3213,37 +3213,34 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) return -EPERM; - slave_dev = dev_get_by_name(net, ifr->ifr_slave); + slave_dev = __dev_get_by_name(net, ifr->ifr_slave); pr_debug("slave_dev=%p:\n", slave_dev); if (!slave_dev) - res = -ENODEV; - else { - pr_debug("slave_dev->name=%s:\n", slave_dev->name); - switch (cmd) { - case BOND_ENSLAVE_OLD: - case SIOCBONDENSLAVE: - res = bond_enslave(bond_dev, slave_dev); - break; - case BOND_RELEASE_OLD: - case SIOCBONDRELEASE: - res = bond_release(bond_dev, slave_dev); - break; - case BOND_SETHWADDR_OLD: - case SIOCBONDSETHWADDR: - bond_set_dev_addr(bond_dev, slave_dev); - res = 0; - break; - case BOND_CHANGE_ACTIVE_OLD: - case SIOCBONDCHANGEACTIVE: - res = bond_option_active_slave_set(bond, slave_dev); - break; - default: - res = -EOPNOTSUPP; - } + return -ENODEV; - dev_put(slave_dev); + pr_debug("slave_dev->name=%s:\n", slave_dev->name); + switch (cmd) { + case BOND_ENSLAVE_OLD: + case SIOCBONDENSLAVE: + res = bond_enslave(bond_dev, slave_dev); + break; + case BOND_RELEASE_OLD: + case SIOCBONDRELEASE: + res = bond_release(bond_dev, slave_dev); + break; + case BOND_SETHWADDR_OLD: + case SIOCBONDSETHWADDR: + bond_set_dev_addr(bond_dev, slave_dev); + res = 0; + break; + case BOND_CHANGE_ACTIVE_OLD: + case SIOCBONDCHANGEACTIVE: + res = bond_option_active_slave_set(bond, slave_dev); + break; + default: + res = -EOPNOTSUPP; } return res; @@ -3692,7 +3689,8 @@ static inline int bond_slave_override(struct bonding *bond, } -static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { /* * This helper function exists to help dev_pick_tx get the correct diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index 9e7d95dae2c7..d447b881bbde 100644 --- a/drivers/net/can/Kconfig +++ b/drivers/net/can/Kconfig @@ -104,7 +104,7 @@ config CAN_JANZ_ICAN3 config CAN_FLEXCAN tristate "Support for Freescale FLEXCAN based chips" - depends on ARM || PPC + depends on (ARM && CPU_LITTLE_ENDIAN) || PPC ---help--- Say Y here if you want to support for Freescale FlexCAN. diff --git a/drivers/net/can/sja1000/plx_pci.c b/drivers/net/can/sja1000/plx_pci.c index 5df7f9848823..fbb61a0d901f 100644 --- a/drivers/net/can/sja1000/plx_pci.c +++ b/drivers/net/can/sja1000/plx_pci.c @@ -44,7 +44,8 @@ MODULE_SUPPORTED_DEVICE("Adlink PCI-7841/cPCI-7841, " "esd CAN-PCI/PMC/266, " "esd CAN-PCIe/2000, " "Connect Tech Inc. CANpro/104-Plus Opto (CRG001), " - "IXXAT PC-I 04/PCI") + "IXXAT PC-I 04/PCI, " + "ELCUS CAN-200-PCI") MODULE_LICENSE("GPL v2"); #define PLX_PCI_MAX_CHAN 2 @@ -122,6 +123,11 @@ struct plx_pci_card { #define ESD_PCI_SUB_SYS_ID_PCIE2000 0x0200 #define ESD_PCI_SUB_SYS_ID_PCI104200 0x0501 +#define CAN200PCI_DEVICE_ID 0x9030 +#define CAN200PCI_VENDOR_ID 0x10b5 +#define CAN200PCI_SUB_DEVICE_ID 0x0301 +#define CAN200PCI_SUB_VENDOR_ID 0xe1c5 + #define IXXAT_PCI_VENDOR_ID 0x10b5 #define IXXAT_PCI_DEVICE_ID 0x9050 #define IXXAT_PCI_SUB_SYS_ID 0x2540 @@ -233,6 +239,14 @@ static struct plx_pci_card_info plx_pci_card_info_cti = { /* based on PLX9030 */ }; +static struct plx_pci_card_info plx_pci_card_info_elcus = { + "Eclus CAN-200-PCI", 2, + PLX_PCI_CAN_CLOCK, PLX_PCI_OCR, PLX_PCI_CDR, + {1, 0x00, 0x00}, { {2, 0x00, 0x80}, {3, 0x00, 0x80} }, + &plx_pci_reset_common + /* based on PLX9030 */ +}; + static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = { { /* Adlink PCI-7841/cPCI-7841 */ @@ -318,6 +332,13 @@ static DEFINE_PCI_DEVICE_TABLE(plx_pci_tbl) = { 0, 0, (kernel_ulong_t)&plx_pci_card_info_cti }, + { + /* Elcus CAN-200-PCI */ + CAN200PCI_VENDOR_ID, CAN200PCI_DEVICE_ID, + CAN200PCI_SUB_VENDOR_ID, CAN200PCI_SUB_DEVICE_ID, + 0, 0, + (kernel_ulong_t)&plx_pci_card_info_elcus + }, { 0,} }; MODULE_DEVICE_TABLE(pci, plx_pci_tbl); diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c index 60d95b44d0f7..3e2bd9d635ab 100644 --- a/drivers/net/can/ti_hecc.c +++ b/drivers/net/can/ti_hecc.c @@ -518,10 +518,10 @@ static netdev_tx_t ti_hecc_xmit(struct sk_buff *skb, struct net_device *ndev) data = (cf->can_id & CAN_SFF_MASK) << 18; hecc_write_mbx(priv, mbxno, HECC_CANMID, data); hecc_write_mbx(priv, mbxno, HECC_CANMDL, - be32_to_cpu(*(u32 *)(cf->data))); + be32_to_cpu(*(__be32 *)(cf->data))); if (cf->can_dlc > 4) hecc_write_mbx(priv, mbxno, HECC_CANMDH, - be32_to_cpu(*(u32 *)(cf->data + 4))); + be32_to_cpu(*(__be32 *)(cf->data + 4))); else *(u32 *)(cf->data + 4) = 0; can_put_echo_skb(skb, ndev, mbxno); @@ -569,12 +569,10 @@ static int ti_hecc_rx_pkt(struct ti_hecc_priv *priv, int mbxno) cf->can_id |= CAN_RTR_FLAG; cf->can_dlc = get_can_dlc(data & 0xF); data = hecc_read_mbx(priv, mbxno, HECC_CANMDL); - *(u32 *)(cf->data) = cpu_to_be32(data); + *(__be32 *)(cf->data) = cpu_to_be32(data); if (cf->can_dlc > 4) { data = hecc_read_mbx(priv, mbxno, HECC_CANMDH); - *(u32 *)(cf->data + 4) = cpu_to_be32(data); - } else { - *(u32 *)(cf->data + 4) = 0; + *(__be32 *)(cf->data + 4) = cpu_to_be32(data); } spin_lock_irqsave(&priv->mbx_lock, flags); hecc_clear_bit(priv, HECC_CANME, mbx_mask); diff --git a/drivers/net/eql.c b/drivers/net/eql.c index f219d38acf58..7a79b6046879 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -395,6 +395,7 @@ static int __eql_insert_slave(slave_queue_t *queue, slave_t *slave) if (duplicate_slave) eql_kill_one_slave(queue, duplicate_slave); + dev_hold(slave->dev); list_add(&slave->list, &queue->all_slaves); queue->num_slaves++; slave->dev->flags |= IFF_SLAVE; @@ -413,39 +414,35 @@ static int eql_enslave(struct net_device *master_dev, slaving_request_t __user * if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) return -EFAULT; - slave_dev = dev_get_by_name(&init_net, srq.slave_name); - if (slave_dev) { - if ((master_dev->flags & IFF_UP) == IFF_UP) { - /* slave is not a master & not already a slave: */ - if (!eql_is_master(slave_dev) && - !eql_is_slave(slave_dev)) { - slave_t *s = kmalloc(sizeof(*s), GFP_KERNEL); - equalizer_t *eql = netdev_priv(master_dev); - int ret; - - if (!s) { - dev_put(slave_dev); - return -ENOMEM; - } - - memset(s, 0, sizeof(*s)); - s->dev = slave_dev; - s->priority = srq.priority; - s->priority_bps = srq.priority; - s->priority_Bps = srq.priority / 8; - - spin_lock_bh(&eql->queue.lock); - ret = __eql_insert_slave(&eql->queue, s); - if (ret) { - dev_put(slave_dev); - kfree(s); - } - spin_unlock_bh(&eql->queue.lock); - - return ret; - } + slave_dev = __dev_get_by_name(&init_net, srq.slave_name); + if (!slave_dev) + return -ENODEV; + + if ((master_dev->flags & IFF_UP) == IFF_UP) { + /* slave is not a master & not already a slave: */ + if (!eql_is_master(slave_dev) && !eql_is_slave(slave_dev)) { + slave_t *s = kmalloc(sizeof(*s), GFP_KERNEL); + equalizer_t *eql = netdev_priv(master_dev); + int ret; + + if (!s) + return -ENOMEM; + + memset(s, 0, sizeof(*s)); + s->dev = slave_dev; + s->priority = srq.priority; + s->priority_bps = srq.priority; + s->priority_Bps = srq.priority / 8; + + spin_lock_bh(&eql->queue.lock); + ret = __eql_insert_slave(&eql->queue, s); + if (ret) + kfree(s); + + spin_unlock_bh(&eql->queue.lock); + + return ret; } - dev_put(slave_dev); } return -EINVAL; @@ -461,24 +458,20 @@ static int eql_emancipate(struct net_device *master_dev, slaving_request_t __use if (copy_from_user(&srq, srqp, sizeof (slaving_request_t))) return -EFAULT; - slave_dev = dev_get_by_name(&init_net, srq.slave_name); - ret = -EINVAL; - if (slave_dev) { - spin_lock_bh(&eql->queue.lock); - - if (eql_is_slave(slave_dev)) { - slave_t *slave = __eql_find_slave_dev(&eql->queue, - slave_dev); + slave_dev = __dev_get_by_name(&init_net, srq.slave_name); + if (!slave_dev) + return -ENODEV; - if (slave) { - eql_kill_one_slave(&eql->queue, slave); - ret = 0; - } + ret = -EINVAL; + spin_lock_bh(&eql->queue.lock); + if (eql_is_slave(slave_dev)) { + slave_t *slave = __eql_find_slave_dev(&eql->queue, slave_dev); + if (slave) { + eql_kill_one_slave(&eql->queue, slave); + ret = 0; } - dev_put(slave_dev); - - spin_unlock_bh(&eql->queue.lock); } + spin_unlock_bh(&eql->queue.lock); return ret; } @@ -494,7 +487,7 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp) if (copy_from_user(&sc, scp, sizeof (slave_config_t))) return -EFAULT; - slave_dev = dev_get_by_name(&init_net, sc.slave_name); + slave_dev = __dev_get_by_name(&init_net, sc.slave_name); if (!slave_dev) return -ENODEV; @@ -510,8 +503,6 @@ static int eql_g_slave_cfg(struct net_device *dev, slave_config_t __user *scp) } spin_unlock_bh(&eql->queue.lock); - dev_put(slave_dev); - if (!ret && copy_to_user(scp, &sc, sizeof (slave_config_t))) ret = -EFAULT; @@ -529,7 +520,7 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp) if (copy_from_user(&sc, scp, sizeof (slave_config_t))) return -EFAULT; - slave_dev = dev_get_by_name(&init_net, sc.slave_name); + slave_dev = __dev_get_by_name(&init_net, sc.slave_name); if (!slave_dev) return -ENODEV; @@ -548,8 +539,6 @@ static int eql_s_slave_cfg(struct net_device *dev, slave_config_t __user *scp) } spin_unlock_bh(&eql->queue.lock); - dev_put(slave_dev); - return ret; } diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c index 9142b473175c..c53384d41c96 100644 --- a/drivers/net/ethernet/3com/3c509.c +++ b/drivers/net/ethernet/3com/3c509.c @@ -252,7 +252,7 @@ static int el3_isa_id_sequence(__be16 *phys_addr) for (i = 0; i < el3_cards; i++) { struct el3_private *lp = netdev_priv(el3_devs[i]); if (lp->type == EL3_PNP && - ether_addr_equal(phys_addr, el3_devs[i]->dev_addr)) { + ether_addr_equal((u8 *)phys_addr, el3_devs[i]->dev_addr)) { if (el3_debug > 3) pr_debug("3c509 with address %02x %02x %02x %02x %02x %02x was found by ISAPnP\n", phys_addr[0] & 0xff, phys_addr[0] >> 8, diff --git a/drivers/net/ethernet/amd/amd8111e.h b/drivers/net/ethernet/amd/amd8111e.h index b1fae36360d2..a75092d584cc 100644 --- a/drivers/net/ethernet/amd/amd8111e.h +++ b/drivers/net/ethernet/amd/amd8111e.h @@ -751,7 +751,7 @@ struct amd8111e_priv{ const char *name; struct pci_dev *pci_dev; /* Ptr to the associated pci_dev */ struct net_device* amd8111e_net_dev; /* ptr to associated net_device */ - /* Transmit and recive skbs */ + /* Transmit and receive skbs */ struct sk_buff *tx_skbuff[NUM_TX_BUFFERS]; struct sk_buff *rx_skbuff[NUM_RX_BUFFERS]; /* Transmit and receive dma mapped addr */ diff --git a/drivers/net/ethernet/atheros/alx/alx.h b/drivers/net/ethernet/atheros/alx/alx.h index d71103dbf2cd..8fc93c5f6abc 100644 --- a/drivers/net/ethernet/atheros/alx/alx.h +++ b/drivers/net/ethernet/atheros/alx/alx.h @@ -106,6 +106,9 @@ struct alx_priv { u16 msg_enable; bool msi; + + /* protects hw.stats */ + spinlock_t stats_lock; }; extern const struct ethtool_ops alx_ethtool_ops; diff --git a/drivers/net/ethernet/atheros/alx/ethtool.c b/drivers/net/ethernet/atheros/alx/ethtool.c index 45b36507abc1..08e22df2a300 100644 --- a/drivers/net/ethernet/atheros/alx/ethtool.c +++ b/drivers/net/ethernet/atheros/alx/ethtool.c @@ -46,6 +46,66 @@ #include "reg.h" #include "hw.h" +/* The order of these strings must match the order of the fields in + * struct alx_hw_stats + * See hw.h + */ +static const char alx_gstrings_stats[][ETH_GSTRING_LEN] = { + "rx_packets", + "rx_bcast_packets", + "rx_mcast_packets", + "rx_pause_packets", + "rx_ctrl_packets", + "rx_fcs_errors", + "rx_length_errors", + "rx_bytes", + "rx_runt_packets", + "rx_fragments", + "rx_64B_or_less_packets", + "rx_65B_to_127B_packets", + "rx_128B_to_255B_packets", + "rx_256B_to_511B_packets", + "rx_512B_to_1023B_packets", + "rx_1024B_to_1518B_packets", + "rx_1519B_to_mtu_packets", + "rx_oversize_packets", + "rx_rxf_ov_drop_packets", + "rx_rrd_ov_drop_packets", + "rx_align_errors", + "rx_bcast_bytes", + "rx_mcast_bytes", + "rx_address_errors", + "tx_packets", + "tx_bcast_packets", + "tx_mcast_packets", + "tx_pause_packets", + "tx_exc_defer_packets", + "tx_ctrl_packets", + "tx_defer_packets", + "tx_bytes", + "tx_64B_or_less_packets", + "tx_65B_to_127B_packets", + "tx_128B_to_255B_packets", + "tx_256B_to_511B_packets", + "tx_512B_to_1023B_packets", + "tx_1024B_to_1518B_packets", + "tx_1519B_to_mtu_packets", + "tx_single_collision", + "tx_multiple_collisions", + "tx_late_collision", + "tx_abort_collision", + "tx_underrun", + "tx_trd_eop", + "tx_length_errors", + "tx_trunc_packets", + "tx_bcast_bytes", + "tx_mcast_bytes", + "tx_update", +}; + +#define ALX_NUM_STATS ARRAY_SIZE(alx_gstrings_stats) + + static u32 alx_get_supported_speeds(struct alx_hw *hw) { u32 supported = SUPPORTED_10baseT_Half | @@ -201,6 +261,44 @@ static void alx_set_msglevel(struct net_device *netdev, u32 data) alx->msg_enable = data; } +static void alx_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *estats, u64 *data) +{ + struct alx_priv *alx = netdev_priv(netdev); + struct alx_hw *hw = &alx->hw; + + spin_lock(&alx->stats_lock); + + alx_update_hw_stats(hw); + BUILD_BUG_ON(sizeof(hw->stats) - offsetof(struct alx_hw_stats, rx_ok) < + ALX_NUM_STATS * sizeof(u64)); + memcpy(data, &hw->stats.rx_ok, ALX_NUM_STATS * sizeof(u64)); + + spin_unlock(&alx->stats_lock); +} + +static void alx_get_strings(struct net_device *netdev, u32 stringset, u8 *buf) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(buf, &alx_gstrings_stats, sizeof(alx_gstrings_stats)); + break; + default: + WARN_ON(1); + break; + } +} + +static int alx_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ALX_NUM_STATS; + default: + return -EINVAL; + } +} + const struct ethtool_ops alx_ethtool_ops = { .get_settings = alx_get_settings, .set_settings = alx_set_settings, @@ -209,4 +307,7 @@ const struct ethtool_ops alx_ethtool_ops = { .get_msglevel = alx_get_msglevel, .set_msglevel = alx_set_msglevel, .get_link = ethtool_op_get_link, + .get_strings = alx_get_strings, + .get_sset_count = alx_get_sset_count, + .get_ethtool_stats = alx_get_ethtool_stats, }; diff --git a/drivers/net/ethernet/atheros/alx/hw.c b/drivers/net/ethernet/atheros/alx/hw.c index 1e8c24a3cb4e..7712f068f6d4 100644 --- a/drivers/net/ethernet/atheros/alx/hw.c +++ b/drivers/net/ethernet/atheros/alx/hw.c @@ -1050,3 +1050,61 @@ bool alx_get_phy_info(struct alx_hw *hw) return true; } + +void alx_update_hw_stats(struct alx_hw *hw) +{ + /* RX stats */ + hw->stats.rx_ok += alx_read_mem32(hw, ALX_MIB_RX_OK); + hw->stats.rx_bcast += alx_read_mem32(hw, ALX_MIB_RX_BCAST); + hw->stats.rx_mcast += alx_read_mem32(hw, ALX_MIB_RX_MCAST); + hw->stats.rx_pause += alx_read_mem32(hw, ALX_MIB_RX_PAUSE); + hw->stats.rx_ctrl += alx_read_mem32(hw, ALX_MIB_RX_CTRL); + hw->stats.rx_fcs_err += alx_read_mem32(hw, ALX_MIB_RX_FCS_ERR); + hw->stats.rx_len_err += alx_read_mem32(hw, ALX_MIB_RX_LEN_ERR); + hw->stats.rx_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BYTE_CNT); + hw->stats.rx_runt += alx_read_mem32(hw, ALX_MIB_RX_RUNT); + hw->stats.rx_frag += alx_read_mem32(hw, ALX_MIB_RX_FRAG); + hw->stats.rx_sz_64B += alx_read_mem32(hw, ALX_MIB_RX_SZ_64B); + hw->stats.rx_sz_127B += alx_read_mem32(hw, ALX_MIB_RX_SZ_127B); + hw->stats.rx_sz_255B += alx_read_mem32(hw, ALX_MIB_RX_SZ_255B); + hw->stats.rx_sz_511B += alx_read_mem32(hw, ALX_MIB_RX_SZ_511B); + hw->stats.rx_sz_1023B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1023B); + hw->stats.rx_sz_1518B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1518B); + hw->stats.rx_sz_max += alx_read_mem32(hw, ALX_MIB_RX_SZ_MAX); + hw->stats.rx_ov_sz += alx_read_mem32(hw, ALX_MIB_RX_OV_SZ); + hw->stats.rx_ov_rxf += alx_read_mem32(hw, ALX_MIB_RX_OV_RXF); + hw->stats.rx_ov_rrd += alx_read_mem32(hw, ALX_MIB_RX_OV_RRD); + hw->stats.rx_align_err += alx_read_mem32(hw, ALX_MIB_RX_ALIGN_ERR); + hw->stats.rx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BCCNT); + hw->stats.rx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_MCCNT); + hw->stats.rx_err_addr += alx_read_mem32(hw, ALX_MIB_RX_ERRADDR); + + /* TX stats */ + hw->stats.tx_ok += alx_read_mem32(hw, ALX_MIB_TX_OK); + hw->stats.tx_bcast += alx_read_mem32(hw, ALX_MIB_TX_BCAST); + hw->stats.tx_mcast += alx_read_mem32(hw, ALX_MIB_TX_MCAST); + hw->stats.tx_pause += alx_read_mem32(hw, ALX_MIB_TX_PAUSE); + hw->stats.tx_exc_defer += alx_read_mem32(hw, ALX_MIB_TX_EXC_DEFER); + hw->stats.tx_ctrl += alx_read_mem32(hw, ALX_MIB_TX_CTRL); + hw->stats.tx_defer += alx_read_mem32(hw, ALX_MIB_TX_DEFER); + hw->stats.tx_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BYTE_CNT); + hw->stats.tx_sz_64B += alx_read_mem32(hw, ALX_MIB_TX_SZ_64B); + hw->stats.tx_sz_127B += alx_read_mem32(hw, ALX_MIB_TX_SZ_127B); + hw->stats.tx_sz_255B += alx_read_mem32(hw, ALX_MIB_TX_SZ_255B); + hw->stats.tx_sz_511B += alx_read_mem32(hw, ALX_MIB_TX_SZ_511B); + hw->stats.tx_sz_1023B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1023B); + hw->stats.tx_sz_1518B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1518B); + hw->stats.tx_sz_max += alx_read_mem32(hw, ALX_MIB_TX_SZ_MAX); + hw->stats.tx_single_col += alx_read_mem32(hw, ALX_MIB_TX_SINGLE_COL); + hw->stats.tx_multi_col += alx_read_mem32(hw, ALX_MIB_TX_MULTI_COL); + hw->stats.tx_late_col += alx_read_mem32(hw, ALX_MIB_TX_LATE_COL); + hw->stats.tx_abort_col += alx_read_mem32(hw, ALX_MIB_TX_ABORT_COL); + hw->stats.tx_underrun += alx_read_mem32(hw, ALX_MIB_TX_UNDERRUN); + hw->stats.tx_trd_eop += alx_read_mem32(hw, ALX_MIB_TX_TRD_EOP); + hw->stats.tx_len_err += alx_read_mem32(hw, ALX_MIB_TX_LEN_ERR); + hw->stats.tx_trunc += alx_read_mem32(hw, ALX_MIB_TX_TRUNC); + hw->stats.tx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BCCNT); + hw->stats.tx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_MCCNT); + + hw->stats.update += alx_read_mem32(hw, ALX_MIB_UPDATE); +} diff --git a/drivers/net/ethernet/atheros/alx/hw.h b/drivers/net/ethernet/atheros/alx/hw.h index 96f3b4381e17..15548802d6f8 100644 --- a/drivers/net/ethernet/atheros/alx/hw.h +++ b/drivers/net/ethernet/atheros/alx/hw.h @@ -381,6 +381,73 @@ struct alx_rrd { ALX_ISR_RX_Q6 | \ ALX_ISR_RX_Q7) +/* Statistics counters collected by the MAC + * + * The order of the fields must match the strings in alx_gstrings_stats + * All stats fields should be u64 + * See ethtool.c + */ +struct alx_hw_stats { + /* rx */ + u64 rx_ok; /* good RX packets */ + u64 rx_bcast; /* good RX broadcast packets */ + u64 rx_mcast; /* good RX multicast packets */ + u64 rx_pause; /* RX pause frames */ + u64 rx_ctrl; /* RX control packets other than pause frames */ + u64 rx_fcs_err; /* RX packets with bad FCS */ + u64 rx_len_err; /* RX packets with length != actual size */ + u64 rx_byte_cnt; /* good bytes received. FCS is NOT included */ + u64 rx_runt; /* RX packets < 64 bytes with good FCS */ + u64 rx_frag; /* RX packets < 64 bytes with bad FCS */ + u64 rx_sz_64B; /* 64 byte RX packets */ + u64 rx_sz_127B; /* 65-127 byte RX packets */ + u64 rx_sz_255B; /* 128-255 byte RX packets */ + u64 rx_sz_511B; /* 256-511 byte RX packets */ + u64 rx_sz_1023B; /* 512-1023 byte RX packets */ + u64 rx_sz_1518B; /* 1024-1518 byte RX packets */ + u64 rx_sz_max; /* 1519 byte to MTU RX packets */ + u64 rx_ov_sz; /* truncated RX packets, size > MTU */ + u64 rx_ov_rxf; /* frames dropped due to RX FIFO overflow */ + u64 rx_ov_rrd; /* frames dropped due to RRD overflow */ + u64 rx_align_err; /* alignment errors */ + u64 rx_bc_byte_cnt; /* RX broadcast bytes, excluding FCS */ + u64 rx_mc_byte_cnt; /* RX multicast bytes, excluding FCS */ + u64 rx_err_addr; /* packets dropped due to address filtering */ + + /* tx */ + u64 tx_ok; /* good TX packets */ + u64 tx_bcast; /* good TX broadcast packets */ + u64 tx_mcast; /* good TX multicast packets */ + u64 tx_pause; /* TX pause frames */ + u64 tx_exc_defer; /* TX packets deferred excessively */ + u64 tx_ctrl; /* TX control frames, excluding pause frames */ + u64 tx_defer; /* TX packets deferred */ + u64 tx_byte_cnt; /* bytes transmitted, FCS is NOT included */ + u64 tx_sz_64B; /* 64 byte TX packets */ + u64 tx_sz_127B; /* 65-127 byte TX packets */ + u64 tx_sz_255B; /* 128-255 byte TX packets */ + u64 tx_sz_511B; /* 256-511 byte TX packets */ + u64 tx_sz_1023B; /* 512-1023 byte TX packets */ + u64 tx_sz_1518B; /* 1024-1518 byte TX packets */ + u64 tx_sz_max; /* 1519 byte to MTU TX packets */ + u64 tx_single_col; /* packets TX after a single collision */ + u64 tx_multi_col; /* packets TX after multiple collisions */ + u64 tx_late_col; /* TX packets with late collisions */ + u64 tx_abort_col; /* TX packets aborted w/excessive collisions */ + u64 tx_underrun; /* TX packets aborted due to TX FIFO underrun + * or TRD FIFO underrun + */ + u64 tx_trd_eop; /* reads beyond the EOP into the next frame + * when TRD was not written timely + */ + u64 tx_len_err; /* TX packets where length != actual size */ + u64 tx_trunc; /* TX packets truncated due to size > MTU */ + u64 tx_bc_byte_cnt; /* broadcast bytes transmitted, excluding FCS */ + u64 tx_mc_byte_cnt; /* multicast bytes transmitted, excluding FCS */ + u64 update; +}; + + /* maximum interrupt vectors for msix */ #define ALX_MAX_MSIX_INTRS 16 @@ -424,6 +491,9 @@ struct alx_hw { /* PHY link patch flag */ bool lnk_patch; + + /* cumulated stats from the hardware (registers are cleared on read) */ + struct alx_hw_stats stats; }; static inline int alx_hw_revision(struct alx_hw *hw) @@ -491,6 +561,7 @@ bool alx_phy_configured(struct alx_hw *hw); void alx_configure_basic(struct alx_hw *hw); void alx_disable_rss(struct alx_hw *hw); bool alx_get_phy_info(struct alx_hw *hw); +void alx_update_hw_stats(struct alx_hw *hw); static inline u32 alx_speed_to_ethadv(int speed, u8 duplex) { diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index c3c4c266b846..e92ffd6e1c15 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1166,10 +1166,60 @@ static void alx_poll_controller(struct net_device *netdev) } #endif +static struct rtnl_link_stats64 *alx_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *net_stats) +{ + struct alx_priv *alx = netdev_priv(dev); + struct alx_hw_stats *hw_stats = &alx->hw.stats; + + spin_lock(&alx->stats_lock); + + alx_update_hw_stats(&alx->hw); + + net_stats->tx_bytes = hw_stats->tx_byte_cnt; + net_stats->rx_bytes = hw_stats->rx_byte_cnt; + net_stats->multicast = hw_stats->rx_mcast; + net_stats->collisions = hw_stats->tx_single_col + + hw_stats->tx_multi_col + + hw_stats->tx_late_col + + hw_stats->tx_abort_col; + + net_stats->rx_errors = hw_stats->rx_frag + + hw_stats->rx_fcs_err + + hw_stats->rx_len_err + + hw_stats->rx_ov_sz + + hw_stats->rx_ov_rrd + + hw_stats->rx_align_err + + hw_stats->rx_ov_rxf; + + net_stats->rx_fifo_errors = hw_stats->rx_ov_rxf; + net_stats->rx_length_errors = hw_stats->rx_len_err; + net_stats->rx_crc_errors = hw_stats->rx_fcs_err; + net_stats->rx_frame_errors = hw_stats->rx_align_err; + net_stats->rx_dropped = hw_stats->rx_ov_rrd; + + net_stats->tx_errors = hw_stats->tx_late_col + + hw_stats->tx_abort_col + + hw_stats->tx_underrun + + hw_stats->tx_trunc; + + net_stats->tx_aborted_errors = hw_stats->tx_abort_col; + net_stats->tx_fifo_errors = hw_stats->tx_underrun; + net_stats->tx_window_errors = hw_stats->tx_late_col; + + net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; + net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; + + spin_unlock(&alx->stats_lock); + + return net_stats; +} + static const struct net_device_ops alx_netdev_ops = { .ndo_open = alx_open, .ndo_stop = alx_stop, .ndo_start_xmit = alx_start_xmit, + .ndo_get_stats64 = alx_get_stats64, .ndo_set_rx_mode = alx_set_rx_mode, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = alx_set_mac_address, diff --git a/drivers/net/ethernet/atheros/alx/reg.h b/drivers/net/ethernet/atheros/alx/reg.h index e4358c98bc4e..af006b44b2a6 100644 --- a/drivers/net/ethernet/atheros/alx/reg.h +++ b/drivers/net/ethernet/atheros/alx/reg.h @@ -404,15 +404,59 @@ /* MIB */ #define ALX_MIB_BASE 0x1700 + #define ALX_MIB_RX_OK (ALX_MIB_BASE + 0) +#define ALX_MIB_RX_BCAST (ALX_MIB_BASE + 4) +#define ALX_MIB_RX_MCAST (ALX_MIB_BASE + 8) +#define ALX_MIB_RX_PAUSE (ALX_MIB_BASE + 12) +#define ALX_MIB_RX_CTRL (ALX_MIB_BASE + 16) +#define ALX_MIB_RX_FCS_ERR (ALX_MIB_BASE + 20) +#define ALX_MIB_RX_LEN_ERR (ALX_MIB_BASE + 24) +#define ALX_MIB_RX_BYTE_CNT (ALX_MIB_BASE + 28) +#define ALX_MIB_RX_RUNT (ALX_MIB_BASE + 32) +#define ALX_MIB_RX_FRAG (ALX_MIB_BASE + 36) +#define ALX_MIB_RX_SZ_64B (ALX_MIB_BASE + 40) +#define ALX_MIB_RX_SZ_127B (ALX_MIB_BASE + 44) +#define ALX_MIB_RX_SZ_255B (ALX_MIB_BASE + 48) +#define ALX_MIB_RX_SZ_511B (ALX_MIB_BASE + 52) +#define ALX_MIB_RX_SZ_1023B (ALX_MIB_BASE + 56) +#define ALX_MIB_RX_SZ_1518B (ALX_MIB_BASE + 60) +#define ALX_MIB_RX_SZ_MAX (ALX_MIB_BASE + 64) +#define ALX_MIB_RX_OV_SZ (ALX_MIB_BASE + 68) +#define ALX_MIB_RX_OV_RXF (ALX_MIB_BASE + 72) +#define ALX_MIB_RX_OV_RRD (ALX_MIB_BASE + 76) +#define ALX_MIB_RX_ALIGN_ERR (ALX_MIB_BASE + 80) +#define ALX_MIB_RX_BCCNT (ALX_MIB_BASE + 84) +#define ALX_MIB_RX_MCCNT (ALX_MIB_BASE + 88) #define ALX_MIB_RX_ERRADDR (ALX_MIB_BASE + 92) + #define ALX_MIB_TX_OK (ALX_MIB_BASE + 96) +#define ALX_MIB_TX_BCAST (ALX_MIB_BASE + 100) +#define ALX_MIB_TX_MCAST (ALX_MIB_BASE + 104) +#define ALX_MIB_TX_PAUSE (ALX_MIB_BASE + 108) +#define ALX_MIB_TX_EXC_DEFER (ALX_MIB_BASE + 112) +#define ALX_MIB_TX_CTRL (ALX_MIB_BASE + 116) +#define ALX_MIB_TX_DEFER (ALX_MIB_BASE + 120) +#define ALX_MIB_TX_BYTE_CNT (ALX_MIB_BASE + 124) +#define ALX_MIB_TX_SZ_64B (ALX_MIB_BASE + 128) +#define ALX_MIB_TX_SZ_127B (ALX_MIB_BASE + 132) +#define ALX_MIB_TX_SZ_255B (ALX_MIB_BASE + 136) +#define ALX_MIB_TX_SZ_511B (ALX_MIB_BASE + 140) +#define ALX_MIB_TX_SZ_1023B (ALX_MIB_BASE + 144) +#define ALX_MIB_TX_SZ_1518B (ALX_MIB_BASE + 148) +#define ALX_MIB_TX_SZ_MAX (ALX_MIB_BASE + 152) +#define ALX_MIB_TX_SINGLE_COL (ALX_MIB_BASE + 156) +#define ALX_MIB_TX_MULTI_COL (ALX_MIB_BASE + 160) +#define ALX_MIB_TX_LATE_COL (ALX_MIB_BASE + 164) +#define ALX_MIB_TX_ABORT_COL (ALX_MIB_BASE + 168) +#define ALX_MIB_TX_UNDERRUN (ALX_MIB_BASE + 172) +#define ALX_MIB_TX_TRD_EOP (ALX_MIB_BASE + 176) +#define ALX_MIB_TX_LEN_ERR (ALX_MIB_BASE + 180) +#define ALX_MIB_TX_TRUNC (ALX_MIB_BASE + 184) +#define ALX_MIB_TX_BCCNT (ALX_MIB_BASE + 188) #define ALX_MIB_TX_MCCNT (ALX_MIB_BASE + 192) +#define ALX_MIB_UPDATE (ALX_MIB_BASE + 196) -#define ALX_RX_STATS_BIN ALX_MIB_RX_OK -#define ALX_RX_STATS_END ALX_MIB_RX_ERRADDR -#define ALX_TX_STATS_BIN ALX_MIB_TX_OK -#define ALX_TX_STATS_END ALX_MIB_TX_MCCNT #define ALX_ISR 0x1600 #define ALX_ISR_DIS BIT(31) diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c index 29801750f239..4d3258dd0a88 100644 --- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c +++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c @@ -1500,31 +1500,40 @@ static struct net_device_stats *atl1c_get_stats(struct net_device *netdev) struct net_device_stats *net_stats = &netdev->stats; atl1c_update_hw_stats(adapter); - net_stats->rx_packets = hw_stats->rx_ok; - net_stats->tx_packets = hw_stats->tx_ok; net_stats->rx_bytes = hw_stats->rx_byte_cnt; net_stats->tx_bytes = hw_stats->tx_byte_cnt; net_stats->multicast = hw_stats->rx_mcast; net_stats->collisions = hw_stats->tx_1_col + - hw_stats->tx_2_col * 2 + - hw_stats->tx_late_col + hw_stats->tx_abort_col; - net_stats->rx_errors = hw_stats->rx_frag + hw_stats->rx_fcs_err + - hw_stats->rx_len_err + hw_stats->rx_sz_ov + - hw_stats->rx_rrd_ov + hw_stats->rx_align_err; + hw_stats->tx_2_col + + hw_stats->tx_late_col + + hw_stats->tx_abort_col; + + net_stats->rx_errors = hw_stats->rx_frag + + hw_stats->rx_fcs_err + + hw_stats->rx_len_err + + hw_stats->rx_sz_ov + + hw_stats->rx_rrd_ov + + hw_stats->rx_align_err + + hw_stats->rx_rxf_ov; + net_stats->rx_fifo_errors = hw_stats->rx_rxf_ov; net_stats->rx_length_errors = hw_stats->rx_len_err; net_stats->rx_crc_errors = hw_stats->rx_fcs_err; net_stats->rx_frame_errors = hw_stats->rx_align_err; - net_stats->rx_over_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov; + net_stats->rx_dropped = hw_stats->rx_rrd_ov; - net_stats->rx_missed_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov; + net_stats->tx_errors = hw_stats->tx_late_col + + hw_stats->tx_abort_col + + hw_stats->tx_underrun + + hw_stats->tx_trunc; - net_stats->tx_errors = hw_stats->tx_late_col + hw_stats->tx_abort_col + - hw_stats->tx_underrun + hw_stats->tx_trunc; net_stats->tx_fifo_errors = hw_stats->tx_underrun; net_stats->tx_aborted_errors = hw_stats->tx_abort_col; net_stats->tx_window_errors = hw_stats->tx_late_col; + net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; + net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; + return net_stats; } diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c index 7a73f3a9fcb5..d5c2d3e912e5 100644 --- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c +++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c @@ -1177,32 +1177,40 @@ static struct net_device_stats *atl1e_get_stats(struct net_device *netdev) struct atl1e_hw_stats *hw_stats = &adapter->hw_stats; struct net_device_stats *net_stats = &netdev->stats; - net_stats->rx_packets = hw_stats->rx_ok; - net_stats->tx_packets = hw_stats->tx_ok; net_stats->rx_bytes = hw_stats->rx_byte_cnt; net_stats->tx_bytes = hw_stats->tx_byte_cnt; net_stats->multicast = hw_stats->rx_mcast; net_stats->collisions = hw_stats->tx_1_col + - hw_stats->tx_2_col * 2 + - hw_stats->tx_late_col + hw_stats->tx_abort_col; + hw_stats->tx_2_col + + hw_stats->tx_late_col + + hw_stats->tx_abort_col; + + net_stats->rx_errors = hw_stats->rx_frag + + hw_stats->rx_fcs_err + + hw_stats->rx_len_err + + hw_stats->rx_sz_ov + + hw_stats->rx_rrd_ov + + hw_stats->rx_align_err + + hw_stats->rx_rxf_ov; - net_stats->rx_errors = hw_stats->rx_frag + hw_stats->rx_fcs_err + - hw_stats->rx_len_err + hw_stats->rx_sz_ov + - hw_stats->rx_rrd_ov + hw_stats->rx_align_err; net_stats->rx_fifo_errors = hw_stats->rx_rxf_ov; net_stats->rx_length_errors = hw_stats->rx_len_err; net_stats->rx_crc_errors = hw_stats->rx_fcs_err; net_stats->rx_frame_errors = hw_stats->rx_align_err; - net_stats->rx_over_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov; + net_stats->rx_dropped = hw_stats->rx_rrd_ov; - net_stats->rx_missed_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov; + net_stats->tx_errors = hw_stats->tx_late_col + + hw_stats->tx_abort_col + + hw_stats->tx_underrun + + hw_stats->tx_trunc; - net_stats->tx_errors = hw_stats->tx_late_col + hw_stats->tx_abort_col + - hw_stats->tx_underrun + hw_stats->tx_trunc; net_stats->tx_fifo_errors = hw_stats->tx_underrun; net_stats->tx_aborted_errors = hw_stats->tx_abort_col; net_stats->tx_window_errors = hw_stats->tx_late_col; + net_stats->rx_packets = hw_stats->rx_ok + net_stats->rx_errors; + net_stats->tx_packets = hw_stats->tx_ok + net_stats->tx_errors; + return net_stats; } diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c index 55d86ecdacfe..287272dd69da 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.c +++ b/drivers/net/ethernet/atheros/atlx/atl1.c @@ -1678,33 +1678,42 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) struct net_device *netdev = adapter->netdev; struct stats_msg_block *smb = adapter->smb.smb; + u64 new_rx_errors = smb->rx_frag + + smb->rx_fcs_err + + smb->rx_len_err + + smb->rx_sz_ov + + smb->rx_rxf_ov + + smb->rx_rrd_ov + + smb->rx_align_err; + u64 new_tx_errors = smb->tx_late_col + + smb->tx_abort_col + + smb->tx_underrun + + smb->tx_trunc; + /* Fill out the OS statistics structure */ - adapter->soft_stats.rx_packets += smb->rx_ok; - adapter->soft_stats.tx_packets += smb->tx_ok; + adapter->soft_stats.rx_packets += smb->rx_ok + new_rx_errors; + adapter->soft_stats.tx_packets += smb->tx_ok + new_tx_errors; adapter->soft_stats.rx_bytes += smb->rx_byte_cnt; adapter->soft_stats.tx_bytes += smb->tx_byte_cnt; adapter->soft_stats.multicast += smb->rx_mcast; - adapter->soft_stats.collisions += (smb->tx_1_col + smb->tx_2_col * 2 + - smb->tx_late_col + smb->tx_abort_col * adapter->hw.max_retry); + adapter->soft_stats.collisions += smb->tx_1_col + + smb->tx_2_col + + smb->tx_late_col + + smb->tx_abort_col; /* Rx Errors */ - adapter->soft_stats.rx_errors += (smb->rx_frag + smb->rx_fcs_err + - smb->rx_len_err + smb->rx_sz_ov + smb->rx_rxf_ov + - smb->rx_rrd_ov + smb->rx_align_err); + adapter->soft_stats.rx_errors += new_rx_errors; adapter->soft_stats.rx_fifo_errors += smb->rx_rxf_ov; adapter->soft_stats.rx_length_errors += smb->rx_len_err; adapter->soft_stats.rx_crc_errors += smb->rx_fcs_err; adapter->soft_stats.rx_frame_errors += smb->rx_align_err; - adapter->soft_stats.rx_missed_errors += (smb->rx_rrd_ov + - smb->rx_rxf_ov); adapter->soft_stats.rx_pause += smb->rx_pause; adapter->soft_stats.rx_rrd_ov += smb->rx_rrd_ov; adapter->soft_stats.rx_trunc += smb->rx_sz_ov; /* Tx Errors */ - adapter->soft_stats.tx_errors += (smb->tx_late_col + - smb->tx_abort_col + smb->tx_underrun + smb->tx_trunc); + adapter->soft_stats.tx_errors += new_tx_errors; adapter->soft_stats.tx_fifo_errors += smb->tx_underrun; adapter->soft_stats.tx_aborted_errors += smb->tx_abort_col; adapter->soft_stats.tx_window_errors += smb->tx_late_col; @@ -1718,23 +1727,18 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) adapter->soft_stats.tx_trunc += smb->tx_trunc; adapter->soft_stats.tx_pause += smb->tx_pause; - netdev->stats.rx_packets = adapter->soft_stats.rx_packets; - netdev->stats.tx_packets = adapter->soft_stats.tx_packets; netdev->stats.rx_bytes = adapter->soft_stats.rx_bytes; netdev->stats.tx_bytes = adapter->soft_stats.tx_bytes; netdev->stats.multicast = adapter->soft_stats.multicast; netdev->stats.collisions = adapter->soft_stats.collisions; netdev->stats.rx_errors = adapter->soft_stats.rx_errors; - netdev->stats.rx_over_errors = - adapter->soft_stats.rx_missed_errors; netdev->stats.rx_length_errors = adapter->soft_stats.rx_length_errors; netdev->stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; netdev->stats.rx_frame_errors = adapter->soft_stats.rx_frame_errors; netdev->stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; - netdev->stats.rx_missed_errors = - adapter->soft_stats.rx_missed_errors; + netdev->stats.rx_dropped = adapter->soft_stats.rx_rrd_ov; netdev->stats.tx_errors = adapter->soft_stats.tx_errors; netdev->stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; netdev->stats.tx_aborted_errors = @@ -1743,6 +1747,9 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) adapter->soft_stats.tx_window_errors; netdev->stats.tx_carrier_errors = adapter->soft_stats.tx_carrier_errors; + + netdev->stats.rx_packets = adapter->soft_stats.rx_packets; + netdev->stats.tx_packets = adapter->soft_stats.tx_packets; } static void atl1_update_mailbox(struct atl1_adapter *adapter) @@ -1872,7 +1879,7 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) adapter->rx_buffer_len); if (unlikely(!skb)) { /* Better luck next round */ - adapter->netdev->stats.rx_dropped++; + adapter->soft_stats.rx_dropped++; break; } diff --git a/drivers/net/ethernet/atheros/atlx/atl1.h b/drivers/net/ethernet/atheros/atlx/atl1.h index 3bf79a56220d..34a58cd846a0 100644 --- a/drivers/net/ethernet/atheros/atlx/atl1.h +++ b/drivers/net/ethernet/atheros/atlx/atl1.h @@ -666,6 +666,7 @@ struct atl1_sft_stats { u64 rx_errors; u64 rx_length_errors; u64 rx_crc_errors; + u64 rx_dropped; u64 rx_frame_errors; u64 rx_fifo_errors; u64 rx_missed_errors; diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 7f968a9b52c8..0297a79a38e1 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1518,14 +1518,12 @@ static int bgmac_probe(struct bcma_device *core) err = bgmac_mii_register(bgmac); if (err) { bgmac_err(bgmac, "Cannot register MDIO\n"); - err = -ENOTSUPP; goto err_dma_free; } err = register_netdev(bgmac->net_dev); if (err) { bgmac_err(bgmac, "Cannot register net device\n"); - err = -ENOTSUPP; goto err_mii_unregister; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index eb105abcf0e7..391f29ef6d2e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -520,10 +520,12 @@ struct bnx2x_fastpath { #define BNX2X_FP_STATE_IDLE 0 #define BNX2X_FP_STATE_NAPI (1 << 0) /* NAPI owns this FP */ #define BNX2X_FP_STATE_POLL (1 << 1) /* poll owns this FP */ -#define BNX2X_FP_STATE_NAPI_YIELD (1 << 2) /* NAPI yielded this FP */ -#define BNX2X_FP_STATE_POLL_YIELD (1 << 3) /* poll yielded this FP */ +#define BNX2X_FP_STATE_DISABLED (1 << 2) +#define BNX2X_FP_STATE_NAPI_YIELD (1 << 3) /* NAPI yielded this FP */ +#define BNX2X_FP_STATE_POLL_YIELD (1 << 4) /* poll yielded this FP */ +#define BNX2X_FP_OWNED (BNX2X_FP_STATE_NAPI | BNX2X_FP_STATE_POLL) #define BNX2X_FP_YIELD (BNX2X_FP_STATE_NAPI_YIELD | BNX2X_FP_STATE_POLL_YIELD) -#define BNX2X_FP_LOCKED (BNX2X_FP_STATE_NAPI | BNX2X_FP_STATE_POLL) +#define BNX2X_FP_LOCKED (BNX2X_FP_OWNED | BNX2X_FP_STATE_DISABLED) #define BNX2X_FP_USER_PEND (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_POLL_YIELD) /* protect state */ spinlock_t lock; @@ -613,7 +615,7 @@ static inline bool bnx2x_fp_lock_napi(struct bnx2x_fastpath *fp) { bool rc = true; - spin_lock(&fp->lock); + spin_lock_bh(&fp->lock); if (fp->state & BNX2X_FP_LOCKED) { WARN_ON(fp->state & BNX2X_FP_STATE_NAPI); fp->state |= BNX2X_FP_STATE_NAPI_YIELD; @@ -622,7 +624,7 @@ static inline bool bnx2x_fp_lock_napi(struct bnx2x_fastpath *fp) /* we don't care if someone yielded */ fp->state = BNX2X_FP_STATE_NAPI; } - spin_unlock(&fp->lock); + spin_unlock_bh(&fp->lock); return rc; } @@ -631,14 +633,16 @@ static inline bool bnx2x_fp_unlock_napi(struct bnx2x_fastpath *fp) { bool rc = false; - spin_lock(&fp->lock); + spin_lock_bh(&fp->lock); WARN_ON(fp->state & (BNX2X_FP_STATE_POLL | BNX2X_FP_STATE_NAPI_YIELD)); if (fp->state & BNX2X_FP_STATE_POLL_YIELD) rc = true; - fp->state = BNX2X_FP_STATE_IDLE; - spin_unlock(&fp->lock); + + /* state ==> idle, unless currently disabled */ + fp->state &= BNX2X_FP_STATE_DISABLED; + spin_unlock_bh(&fp->lock); return rc; } @@ -669,7 +673,9 @@ static inline bool bnx2x_fp_unlock_poll(struct bnx2x_fastpath *fp) if (fp->state & BNX2X_FP_STATE_POLL_YIELD) rc = true; - fp->state = BNX2X_FP_STATE_IDLE; + + /* state ==> idle, unless currently disabled */ + fp->state &= BNX2X_FP_STATE_DISABLED; spin_unlock_bh(&fp->lock); return rc; } @@ -677,9 +683,23 @@ static inline bool bnx2x_fp_unlock_poll(struct bnx2x_fastpath *fp) /* true if a socket is polling, even if it did not get the lock */ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp) { - WARN_ON(!(fp->state & BNX2X_FP_LOCKED)); + WARN_ON(!(fp->state & BNX2X_FP_OWNED)); return fp->state & BNX2X_FP_USER_PEND; } + +/* false if fp is currently owned */ +static inline bool bnx2x_fp_ll_disable(struct bnx2x_fastpath *fp) +{ + int rc = true; + + spin_lock_bh(&fp->lock); + if (fp->state & BNX2X_FP_OWNED) + rc = false; + fp->state |= BNX2X_FP_STATE_DISABLED; + spin_unlock_bh(&fp->lock); + + return rc; +} #else static inline void bnx2x_fp_init_lock(struct bnx2x_fastpath *fp) { @@ -709,6 +729,10 @@ static inline bool bnx2x_fp_ll_polling(struct bnx2x_fastpath *fp) { return false; } +static inline bool bnx2x_fp_ll_disable(struct bnx2x_fastpath *fp) +{ + return true; +} #endif /* CONFIG_NET_RX_BUSY_POLL */ /* Use 2500 as a mini-jumbo MTU for FCoE */ @@ -1542,6 +1566,7 @@ struct bnx2x { #define NO_ISCSI_FLAG (1 << 14) #define NO_FCOE_FLAG (1 << 15) #define BC_SUPPORTS_PFC_STATS (1 << 17) +#define TX_SWITCHING (1 << 18) #define BC_SUPPORTS_FCOE_FEATURES (1 << 19) #define USING_SINGLE_MSIX_FLAG (1 << 20) #define BC_SUPPORTS_DCBX_MSG_NON_PMF (1 << 21) @@ -2057,7 +2082,6 @@ int bnx2x_del_all_macs(struct bnx2x *bp, void bnx2x_func_init(struct bnx2x *bp, struct bnx2x_func_init_params *p); void bnx2x_init_sb(struct bnx2x *bp, dma_addr_t mapping, int vfid, u8 vf_valid, int fw_sb_id, int igu_sb_id); -u32 bnx2x_get_pretend_reg(struct bnx2x *bp); int bnx2x_get_gpio(struct bnx2x *bp, int gpio_num, u8 port); int bnx2x_set_gpio(struct bnx2x *bp, int gpio_num, u32 mode, u8 port); int bnx2x_set_mult_gpio(struct bnx2x *bp, u8 pins, u32 mode); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 282ebf61f530..9d7419e0390b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -30,6 +30,43 @@ #include "bnx2x_init.h" #include "bnx2x_sp.h" +static void bnx2x_free_fp_mem_cnic(struct bnx2x *bp); +static int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp); +static int bnx2x_alloc_fp_mem(struct bnx2x *bp); +static int bnx2x_poll(struct napi_struct *napi, int budget); + +static void bnx2x_add_all_napi_cnic(struct bnx2x *bp) +{ + int i; + + /* Add NAPI objects */ + for_each_rx_queue_cnic(bp, i) { + netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), + bnx2x_poll, NAPI_POLL_WEIGHT); + napi_hash_add(&bnx2x_fp(bp, i, napi)); + } +} + +static void bnx2x_add_all_napi(struct bnx2x *bp) +{ + int i; + + /* Add NAPI objects */ + for_each_eth_queue(bp, i) { + netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), + bnx2x_poll, NAPI_POLL_WEIGHT); + napi_hash_add(&bnx2x_fp(bp, i, napi)); + } +} + +static int bnx2x_calc_num_queues(struct bnx2x *bp) +{ + return bnx2x_num_queues ? + min_t(int, bnx2x_num_queues, BNX2X_MAX_QUEUES(bp)) : + min_t(int, netif_get_num_default_rss_queues(), + BNX2X_MAX_QUEUES(bp)); +} + /** * bnx2x_move_fp - move content of the fastpath structure. * @@ -145,7 +182,7 @@ static void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta) } } -int load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ +int bnx2x_load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ /* free skb in the packet ring at pos idx * return idx of last bd freed @@ -160,6 +197,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, struct sk_buff *skb = tx_buf->skb; u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; int nbd; + u16 split_bd_len = 0; /* prefetch skb end pointer to speedup dev_kfree_skb() */ prefetch(&skb->end); @@ -167,10 +205,7 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, DP(NETIF_MSG_TX_DONE, "fp[%d]: pkt_idx %d buff @(%p)->skb %p\n", txdata->txq_index, idx, tx_buf, skb); - /* unmap first bd */ tx_start_bd = &txdata->tx_desc_ring[bd_idx].start_bd; - dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd), - BD_UNMAP_LEN(tx_start_bd), DMA_TO_DEVICE); nbd = le16_to_cpu(tx_start_bd->nbd) - 1; #ifdef BNX2X_STOP_ON_ERROR @@ -188,12 +223,19 @@ static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, --nbd; bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); - /* ...and the TSO split header bd since they have no mapping */ + /* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */ if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { + tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd; + split_bd_len = BD_UNMAP_LEN(tx_data_bd); --nbd; bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); } + /* unmap first bd */ + dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd), + BD_UNMAP_LEN(tx_start_bd) + split_bd_len, + DMA_TO_DEVICE); + /* now free frags */ while (nbd > 0) { @@ -813,7 +855,7 @@ void bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe, skb->ip_summed = CHECKSUM_UNNECESSARY; } -int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) +static int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) { struct bnx2x *bp = fp->bp; u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons; @@ -1483,7 +1525,7 @@ static void bnx2x_free_rx_skbs(struct bnx2x *bp) } } -void bnx2x_free_skbs_cnic(struct bnx2x *bp) +static void bnx2x_free_skbs_cnic(struct bnx2x *bp) { bnx2x_free_tx_skbs_cnic(bp); bnx2x_free_rx_skbs_cnic(bp); @@ -1792,26 +1834,22 @@ static void bnx2x_napi_disable_cnic(struct bnx2x *bp) { int i; - local_bh_disable(); for_each_rx_queue_cnic(bp, i) { napi_disable(&bnx2x_fp(bp, i, napi)); - while (!bnx2x_fp_lock_napi(&bp->fp[i])) - mdelay(1); + while (!bnx2x_fp_ll_disable(&bp->fp[i])) + usleep_range(1000, 2000); } - local_bh_enable(); } static void bnx2x_napi_disable(struct bnx2x *bp) { int i; - local_bh_disable(); for_each_eth_queue(bp, i) { napi_disable(&bnx2x_fp(bp, i, napi)); - while (!bnx2x_fp_lock_napi(&bp->fp[i])) - mdelay(1); + while (!bnx2x_fp_ll_disable(&bp->fp[i])) + usleep_range(1000, 2000); } - local_bh_enable(); } void bnx2x_netif_start(struct bnx2x *bp) @@ -1834,7 +1872,8 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) bnx2x_napi_disable_cnic(bp); } -u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb) +u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { struct bnx2x *bp = netdev_priv(dev); @@ -2302,16 +2341,16 @@ static int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port) int path = BP_PATH(bp); DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n", - path, load_count[path][0], load_count[path][1], - load_count[path][2]); - load_count[path][0]++; - load_count[path][1 + port]++; + path, bnx2x_load_count[path][0], bnx2x_load_count[path][1], + bnx2x_load_count[path][2]); + bnx2x_load_count[path][0]++; + bnx2x_load_count[path][1 + port]++; DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n", - path, load_count[path][0], load_count[path][1], - load_count[path][2]); - if (load_count[path][0] == 1) + path, bnx2x_load_count[path][0], bnx2x_load_count[path][1], + bnx2x_load_count[path][2]); + if (bnx2x_load_count[path][0] == 1) return FW_MSG_CODE_DRV_LOAD_COMMON; - else if (load_count[path][1 + port] == 1) + else if (bnx2x_load_count[path][1 + port] == 1) return FW_MSG_CODE_DRV_LOAD_PORT; else return FW_MSG_CODE_DRV_LOAD_FUNCTION; @@ -3069,7 +3108,7 @@ int bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) /* * net_device service functions */ -int bnx2x_poll(struct napi_struct *napi, int budget) +static int bnx2x_poll(struct napi_struct *napi, int budget) { int work_done = 0; u8 cos; @@ -4196,7 +4235,7 @@ static void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index) /* end of fastpath */ } -void bnx2x_free_fp_mem_cnic(struct bnx2x *bp) +static void bnx2x_free_fp_mem_cnic(struct bnx2x *bp) { int i; for_each_cnic_queue(bp, i) @@ -4410,7 +4449,7 @@ alloc_mem_err: return 0; } -int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp) +static int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp) { if (!NO_FCOE(bp)) /* FCoE */ @@ -4423,7 +4462,7 @@ int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp) return 0; } -int bnx2x_alloc_fp_mem(struct bnx2x *bp) +static int bnx2x_alloc_fp_mem(struct bnx2x *bp) { int i; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index da8fcaa74495..17d1689aec6b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -26,10 +26,8 @@ #include "bnx2x_sriov.h" /* This is used as a replacement for an MCP if it's not present */ -extern int load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */ - -extern int num_queues; -extern int int_mode; +extern int bnx2x_load_count[2][3]; /* per-path: 0-common, 1-port0, 2-port1 */ +extern int bnx2x_num_queues; /************************ Macros ********************************/ #define BNX2X_PCI_FREE(x, y, size) \ @@ -417,35 +415,8 @@ int bnx2x_set_eth_mac(struct bnx2x *bp, bool set); * If bp->state is OPEN, should be called with * netif_addr_lock_bh() */ -void bnx2x_set_rx_mode(struct net_device *dev); void bnx2x_set_rx_mode_inner(struct bnx2x *bp); -/** - * bnx2x_set_storm_rx_mode - configure MAC filtering rules in a FW. - * - * @bp: driver handle - * - * If bp->state is OPEN, should be called with - * netif_addr_lock_bh(). - */ -int bnx2x_set_storm_rx_mode(struct bnx2x *bp); - -/** - * bnx2x_set_q_rx_mode - configures rx_mode for a single queue. - * - * @bp: driver handle - * @cl_id: client id - * @rx_mode_flags: rx mode configuration - * @rx_accept_flags: rx accept configuration - * @tx_accept_flags: tx accept configuration (tx switch) - * @ramrod_flags: ramrod configuration - */ -int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id, - unsigned long rx_mode_flags, - unsigned long rx_accept_flags, - unsigned long tx_accept_flags, - unsigned long ramrod_flags); - /* Parity errors related */ void bnx2x_set_pf_load(struct bnx2x *bp); bool bnx2x_clear_pf_load(struct bnx2x *bp); @@ -524,7 +495,8 @@ int bnx2x_set_vf_mac(struct net_device *dev, int queue, u8 *mac); int bnx2x_set_vf_vlan(struct net_device *netdev, int vf, u16 vlan, u8 qos); /* select_queue callback */ -u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb); +u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv); static inline void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp, @@ -564,9 +536,6 @@ int bnx2x_reload_if_running(struct net_device *dev); int bnx2x_change_mac_addr(struct net_device *dev, void *p); -/* NAPI poll Rx part */ -int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget); - /* NAPI poll Tx part */ int bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata); @@ -577,13 +546,9 @@ int bnx2x_resume(struct pci_dev *pdev); /* Release IRQ vectors */ void bnx2x_free_irq(struct bnx2x *bp); -void bnx2x_free_fp_mem_cnic(struct bnx2x *bp); void bnx2x_free_fp_mem(struct bnx2x *bp); -int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp); -int bnx2x_alloc_fp_mem(struct bnx2x *bp); void bnx2x_init_rx_rings(struct bnx2x *bp); void bnx2x_init_rx_rings_cnic(struct bnx2x *bp); -void bnx2x_free_skbs_cnic(struct bnx2x *bp); void bnx2x_free_skbs(struct bnx2x *bp); void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw); void bnx2x_netif_start(struct bnx2x *bp); @@ -607,15 +572,6 @@ int bnx2x_enable_msix(struct bnx2x *bp); int bnx2x_enable_msi(struct bnx2x *bp); /** - * bnx2x_poll - NAPI callback - * - * @napi: napi structure - * @budget: - * - */ -int bnx2x_poll(struct napi_struct *napi, int budget); - -/** * bnx2x_low_latency_recv - LL callback * * @napi: napi structure @@ -861,30 +817,6 @@ static inline void bnx2x_free_rx_sge(struct bnx2x *bp, sge->addr_lo = 0; } -static inline void bnx2x_add_all_napi_cnic(struct bnx2x *bp) -{ - int i; - - /* Add NAPI objects */ - for_each_rx_queue_cnic(bp, i) { - netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), - bnx2x_poll, NAPI_POLL_WEIGHT); - napi_hash_add(&bnx2x_fp(bp, i, napi)); - } -} - -static inline void bnx2x_add_all_napi(struct bnx2x *bp) -{ - int i; - - /* Add NAPI objects */ - for_each_eth_queue(bp, i) { - netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), - bnx2x_poll, NAPI_POLL_WEIGHT); - napi_hash_add(&bnx2x_fp(bp, i, napi)); - } -} - static inline void bnx2x_del_all_napi_cnic(struct bnx2x *bp) { int i; @@ -918,14 +850,6 @@ static inline void bnx2x_disable_msi(struct bnx2x *bp) } } -static inline int bnx2x_calc_num_queues(struct bnx2x *bp) -{ - return num_queues ? - min_t(int, num_queues, BNX2X_MAX_QUEUES(bp)) : - min_t(int, netif_get_num_default_rss_queues(), - BNX2X_MAX_QUEUES(bp)); -} - static inline void bnx2x_clear_sge_mask_next_elems(struct bnx2x_fastpath *fp) { int i, j; @@ -1172,8 +1096,6 @@ static inline u8 bnx2x_fp_qzone_id(struct bnx2x_fastpath *fp) return fp->cl_id; } -u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp); - static inline void bnx2x_init_txdata(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, u32 cid, int txq_index, __le16 *tx_cons_sb, @@ -1206,47 +1128,6 @@ static inline u8 bnx2x_cnic_igu_sb_id(struct bnx2x *bp) return bp->igu_base_sb; } -static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp) -{ - struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp); - unsigned long q_type = 0; - - bnx2x_fcoe(bp, rx_queue) = BNX2X_NUM_ETH_QUEUES(bp); - bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp, - BNX2X_FCOE_ETH_CL_ID_IDX); - bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID(bp); - bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID; - bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id; - bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX; - bnx2x_init_txdata(bp, bnx2x_fcoe(bp, txdata_ptr[0]), - fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX, - fp); - - DP(NETIF_MSG_IFUP, "created fcoe tx data (fp index %d)\n", fp->index); - - /* qZone id equals to FW (per path) client id */ - bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp); - /* init shortcut */ - bnx2x_fcoe(bp, ustorm_rx_prods_offset) = - bnx2x_rx_ustorm_prods_offset(fp); - - /* Configure Queue State object */ - __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type); - __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type); - - /* No multi-CoS for FCoE L2 client */ - BUG_ON(fp->max_cos != 1); - - bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, - &fp->cid, 1, BP_FUNC(bp), bnx2x_sp(bp, q_rdata), - bnx2x_sp_mapping(bp, q_rdata), q_type); - - DP(NETIF_MSG_IFUP, - "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n", - fp->index, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id, - fp->igu_sb_id); -} - static inline int bnx2x_clean_tx_queue(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata) { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 11fc79585491..9b6b3d7304b6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -205,6 +205,11 @@ typedef int (*read_sfp_module_eeprom_func_p)(struct bnx2x_phy *phy, (_bank + (_addr & 0xf)), \ _val) +static int bnx2x_check_half_open_conn(struct link_params *params, + struct link_vars *vars, u8 notify); +static int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, + struct link_params *params); + static u32 bnx2x_bits_en(struct bnx2x *bp, u32 reg, u32 bits) { u32 val = REG_RD(bp, reg); @@ -1399,57 +1404,6 @@ static void bnx2x_update_pfc_xmac(struct link_params *params, udelay(30); } - -static void bnx2x_emac_get_pfc_stat(struct link_params *params, - u32 pfc_frames_sent[2], - u32 pfc_frames_received[2]) -{ - /* Read pfc statistic */ - struct bnx2x *bp = params->bp; - u32 emac_base = params->port ? GRCBASE_EMAC1 : GRCBASE_EMAC0; - u32 val_xon = 0; - u32 val_xoff = 0; - - DP(NETIF_MSG_LINK, "pfc statistic read from EMAC\n"); - - /* PFC received frames */ - val_xoff = REG_RD(bp, emac_base + - EMAC_REG_RX_PFC_STATS_XOFF_RCVD); - val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_RCVD_COUNT; - val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_RCVD); - val_xon &= EMAC_REG_RX_PFC_STATS_XON_RCVD_COUNT; - - pfc_frames_received[0] = val_xon + val_xoff; - - /* PFC received sent */ - val_xoff = REG_RD(bp, emac_base + - EMAC_REG_RX_PFC_STATS_XOFF_SENT); - val_xoff &= EMAC_REG_RX_PFC_STATS_XOFF_SENT_COUNT; - val_xon = REG_RD(bp, emac_base + EMAC_REG_RX_PFC_STATS_XON_SENT); - val_xon &= EMAC_REG_RX_PFC_STATS_XON_SENT_COUNT; - - pfc_frames_sent[0] = val_xon + val_xoff; -} - -/* Read pfc statistic*/ -void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, - u32 pfc_frames_sent[2], - u32 pfc_frames_received[2]) -{ - /* Read pfc statistic */ - struct bnx2x *bp = params->bp; - - DP(NETIF_MSG_LINK, "pfc statistic\n"); - - if (!vars->link_up) - return; - - if (vars->mac_type == MAC_TYPE_EMAC) { - DP(NETIF_MSG_LINK, "About to read PFC stats from EMAC\n"); - bnx2x_emac_get_pfc_stat(params, pfc_frames_sent, - pfc_frames_received); - } -} /******************************************************************/ /* MAC/PBF section */ /******************************************************************/ @@ -8648,8 +8602,8 @@ static void bnx2x_set_limiting_mode(struct link_params *params, } } -int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, - struct link_params *params) +static int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, + struct link_params *params) { struct bnx2x *bp = params->bp; u16 edc_mode; @@ -13413,9 +13367,9 @@ static u8 bnx2x_analyze_link_error(struct link_params *params, * a fault, for example, due to break in the TX side of fiber. * ******************************************************************************/ -int bnx2x_check_half_open_conn(struct link_params *params, - struct link_vars *vars, - u8 notify) +static int bnx2x_check_half_open_conn(struct link_params *params, + struct link_vars *vars, + u8 notify) { struct bnx2x *bp = params->bp; u32 lss_status = 0; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index 4df45234fdc0..389f5f8cb0a3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -533,19 +533,11 @@ int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos); int bnx2x_ets_e3b0_config(const struct link_params *params, const struct link_vars *vars, struct bnx2x_ets_params *ets_params); -/* Read pfc statistic*/ -void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars, - u32 pfc_frames_sent[2], - u32 pfc_frames_received[2]); + void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars, u32 chip_id, u32 shmem_base, u32 shmem2_base, u8 port); -int bnx2x_sfp_module_detection(struct bnx2x_phy *phy, - struct link_params *params); - void bnx2x_period_func(struct link_params *params, struct link_vars *vars); -int bnx2x_check_half_open_conn(struct link_params *params, - struct link_vars *vars, u8 notify); #endif /* BNX2X_LINK_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 18498fed520b..cf17b660b4ee 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -94,8 +94,8 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1); MODULE_FIRMWARE(FW_FILE_NAME_E1H); MODULE_FIRMWARE(FW_FILE_NAME_E2); -int num_queues; -module_param(num_queues, int, 0); +int bnx2x_num_queues; +module_param_named(num_queues, bnx2x_num_queues, int, 0); MODULE_PARM_DESC(num_queues, " Set number of queues (default is as a number of CPUs)"); @@ -103,7 +103,7 @@ static int disable_tpa; module_param(disable_tpa, int, 0); MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature"); -int int_mode; +static int int_mode; module_param(int_mode, int, 0); MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X " "(1 INT#x; 2 MSI)"); @@ -279,6 +279,12 @@ MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl); #define BNX2X_PREV_WAIT_NEEDED 1 static DEFINE_SEMAPHORE(bnx2x_prev_sem); static LIST_HEAD(bnx2x_prev_list); + +/* Forward declaration */ +static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev); +static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp); +static int bnx2x_set_storm_rx_mode(struct bnx2x *bp); + /**************************************************************************** * General service functions ****************************************************************************/ @@ -3001,6 +3007,9 @@ static unsigned long bnx2x_get_common_flags(struct bnx2x *bp, if (zero_stats) __set_bit(BNX2X_Q_FLG_ZERO_STATS, &flags); + if (bp->flags & TX_SWITCHING) + __set_bit(BNX2X_Q_FLG_TX_SWITCH, &flags); + __set_bit(BNX2X_Q_FLG_PCSUM_ON_PKT, &flags); __set_bit(BNX2X_Q_FLG_TUN_INC_INNER_IP_ID, &flags); @@ -5857,11 +5866,11 @@ static void bnx2x_init_eq_ring(struct bnx2x *bp) } /* called with netif_addr_lock_bh() */ -int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id, - unsigned long rx_mode_flags, - unsigned long rx_accept_flags, - unsigned long tx_accept_flags, - unsigned long ramrod_flags) +static int bnx2x_set_q_rx_mode(struct bnx2x *bp, u8 cl_id, + unsigned long rx_mode_flags, + unsigned long rx_accept_flags, + unsigned long tx_accept_flags, + unsigned long ramrod_flags) { struct bnx2x_rx_mode_ramrod_params ramrod_param; int rc; @@ -5969,7 +5978,7 @@ static int bnx2x_fill_accept_flags(struct bnx2x *bp, u32 rx_mode, } /* called with netif_addr_lock_bh() */ -int bnx2x_set_storm_rx_mode(struct bnx2x *bp) +static int bnx2x_set_storm_rx_mode(struct bnx2x *bp) { unsigned long rx_mode_flags = 0, ramrod_flags = 0; unsigned long rx_accept_flags = 0, tx_accept_flags = 0; @@ -6165,6 +6174,47 @@ static void bnx2x_init_tx_rings(struct bnx2x *bp) bnx2x_init_tx_ring_one(bp->fp[i].txdata_ptr[cos]); } +static void bnx2x_init_fcoe_fp(struct bnx2x *bp) +{ + struct bnx2x_fastpath *fp = bnx2x_fcoe_fp(bp); + unsigned long q_type = 0; + + bnx2x_fcoe(bp, rx_queue) = BNX2X_NUM_ETH_QUEUES(bp); + bnx2x_fcoe(bp, cl_id) = bnx2x_cnic_eth_cl_id(bp, + BNX2X_FCOE_ETH_CL_ID_IDX); + bnx2x_fcoe(bp, cid) = BNX2X_FCOE_ETH_CID(bp); + bnx2x_fcoe(bp, fw_sb_id) = DEF_SB_ID; + bnx2x_fcoe(bp, igu_sb_id) = bp->igu_dsb_id; + bnx2x_fcoe(bp, rx_cons_sb) = BNX2X_FCOE_L2_RX_INDEX; + bnx2x_init_txdata(bp, bnx2x_fcoe(bp, txdata_ptr[0]), + fp->cid, FCOE_TXQ_IDX(bp), BNX2X_FCOE_L2_TX_INDEX, + fp); + + DP(NETIF_MSG_IFUP, "created fcoe tx data (fp index %d)\n", fp->index); + + /* qZone id equals to FW (per path) client id */ + bnx2x_fcoe(bp, cl_qzone_id) = bnx2x_fp_qzone_id(fp); + /* init shortcut */ + bnx2x_fcoe(bp, ustorm_rx_prods_offset) = + bnx2x_rx_ustorm_prods_offset(fp); + + /* Configure Queue State object */ + __set_bit(BNX2X_Q_TYPE_HAS_RX, &q_type); + __set_bit(BNX2X_Q_TYPE_HAS_TX, &q_type); + + /* No multi-CoS for FCoE L2 client */ + BUG_ON(fp->max_cos != 1); + + bnx2x_init_queue_obj(bp, &bnx2x_sp_obj(bp, fp).q_obj, fp->cl_id, + &fp->cid, 1, BP_FUNC(bp), bnx2x_sp(bp, q_rdata), + bnx2x_sp_mapping(bp, q_rdata), q_type); + + DP(NETIF_MSG_IFUP, + "queue[%d]: bnx2x_init_sb(%p,%p) cl_id %d fw_sb %d igu_sb %d\n", + fp->index, bp, fp->status_blk.e2_sb, fp->cl_id, fp->fw_sb_id, + fp->igu_sb_id); +} + void bnx2x_nic_init_cnic(struct bnx2x *bp) { if (!NO_FCOE(bp)) @@ -8737,16 +8787,16 @@ u32 bnx2x_send_unload_req(struct bnx2x *bp, int unload_mode) int path = BP_PATH(bp); DP(NETIF_MSG_IFDOWN, "NO MCP - load counts[%d] %d, %d, %d\n", - path, load_count[path][0], load_count[path][1], - load_count[path][2]); - load_count[path][0]--; - load_count[path][1 + port]--; + path, bnx2x_load_count[path][0], bnx2x_load_count[path][1], + bnx2x_load_count[path][2]); + bnx2x_load_count[path][0]--; + bnx2x_load_count[path][1 + port]--; DP(NETIF_MSG_IFDOWN, "NO MCP - new load counts[%d] %d, %d, %d\n", - path, load_count[path][0], load_count[path][1], - load_count[path][2]); - if (load_count[path][0] == 0) + path, bnx2x_load_count[path][0], bnx2x_load_count[path][1], + bnx2x_load_count[path][2]); + if (bnx2x_load_count[path][0] == 0) reset_code = FW_MSG_CODE_DRV_UNLOAD_COMMON; - else if (load_count[path][1 + port] == 0) + else if (bnx2x_load_count[path][1 + port] == 0) reset_code = FW_MSG_CODE_DRV_UNLOAD_PORT; else reset_code = FW_MSG_CODE_DRV_UNLOAD_FUNCTION; @@ -9772,7 +9822,7 @@ period_task_exit: * Init service functions */ -u32 bnx2x_get_pretend_reg(struct bnx2x *bp) +static u32 bnx2x_get_pretend_reg(struct bnx2x *bp) { u32 base = PXP2_REG_PGL_PRETEND_FUNC_F0; u32 stride = PXP2_REG_PGL_PRETEND_FUNC_F1 - base; @@ -12005,7 +12055,7 @@ static int bnx2x_set_mc_list(struct bnx2x *bp) } /* If bp->state is OPEN, should be called with netif_addr_lock_bh() */ -void bnx2x_set_rx_mode(struct net_device *dev) +static void bnx2x_set_rx_mode(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); @@ -12783,8 +12833,6 @@ static int set_is_vf(int chip_id) } } -struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev); - static int bnx2x_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -13859,7 +13907,7 @@ static int bnx2x_unregister_cnic(struct net_device *dev) return 0; } -struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) +static struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) { struct bnx2x *bp = netdev_priv(dev); struct cnic_eth_dev *cp = &bp->cnic_eth_dev; @@ -13909,7 +13957,7 @@ struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev) return cp; } -u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp) +static u32 bnx2x_rx_ustorm_prods_offset(struct bnx2x_fastpath *fp) { struct bnx2x *bp = fp->bp; u32 offset = BAR_USTRORM_INTMEM; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 98cccd487fc2..0fb6ff2ac8e3 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -355,23 +355,6 @@ static bool bnx2x_get_credit_vlan(struct bnx2x_vlan_mac_obj *o) return vp->get(vp, 1); } - -static bool bnx2x_get_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) -{ - struct bnx2x_credit_pool_obj *mp = o->macs_pool; - struct bnx2x_credit_pool_obj *vp = o->vlans_pool; - - if (!mp->get(mp, 1)) - return false; - - if (!vp->get(vp, 1)) { - mp->put(mp, 1); - return false; - } - - return true; -} - static bool bnx2x_put_cam_offset_mac(struct bnx2x_vlan_mac_obj *o, int offset) { struct bnx2x_credit_pool_obj *mp = o->macs_pool; @@ -400,22 +383,6 @@ static bool bnx2x_put_credit_vlan(struct bnx2x_vlan_mac_obj *o) return vp->put(vp, 1); } -static bool bnx2x_put_credit_vlan_mac(struct bnx2x_vlan_mac_obj *o) -{ - struct bnx2x_credit_pool_obj *mp = o->macs_pool; - struct bnx2x_credit_pool_obj *vp = o->vlans_pool; - - if (!mp->put(mp, 1)) - return false; - - if (!vp->put(vp, 1)) { - mp->get(mp, 1); - return false; - } - - return true; -} - /** * __bnx2x_vlan_mac_h_write_trylock - try getting the vlan mac writer lock * @@ -507,22 +474,6 @@ static void __bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, } } -/** - * bnx2x_vlan_mac_h_write_unlock - unlock the vlan mac head list writer lock - * - * @bp: device handle - * @o: vlan_mac object - * - * @details Notice if a pending execution exists, it would perform it - - * possibly releasing and reclaiming the execution queue lock. - */ -void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *o) -{ - spin_lock_bh(&o->exe_queue.lock); - __bnx2x_vlan_mac_h_write_unlock(bp, o); - spin_unlock_bh(&o->exe_queue.lock); -} /** * __bnx2x_vlan_mac_h_read_lock - lock the vlan mac head list reader lock @@ -685,25 +636,6 @@ static int bnx2x_check_vlan_add(struct bnx2x *bp, return 0; } -static int bnx2x_check_vlan_mac_add(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *o, - union bnx2x_classification_ramrod_data *data) -{ - struct bnx2x_vlan_mac_registry_elem *pos; - - DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for ADD command\n", - data->vlan_mac.mac, data->vlan_mac.vlan); - - list_for_each_entry(pos, &o->head, link) - if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && - ether_addr_equal_unaligned(data->vlan_mac.mac, pos->u.vlan_mac.mac) && - (data->vlan_mac.is_inner_mac == - pos->u.vlan_mac.is_inner_mac)) - return -EEXIST; - - return 0; -} - /* check_del() callbacks */ static struct bnx2x_vlan_mac_registry_elem * bnx2x_check_mac_del(struct bnx2x *bp, @@ -738,26 +670,6 @@ static struct bnx2x_vlan_mac_registry_elem * return NULL; } -static struct bnx2x_vlan_mac_registry_elem * - bnx2x_check_vlan_mac_del(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *o, - union bnx2x_classification_ramrod_data *data) -{ - struct bnx2x_vlan_mac_registry_elem *pos; - - DP(BNX2X_MSG_SP, "Checking VLAN_MAC (%pM, %d) for DEL command\n", - data->vlan_mac.mac, data->vlan_mac.vlan); - - list_for_each_entry(pos, &o->head, link) - if ((data->vlan_mac.vlan == pos->u.vlan_mac.vlan) && - ether_addr_equal_unaligned(data->vlan_mac.mac, pos->u.vlan_mac.mac) && - (data->vlan_mac.is_inner_mac == - pos->u.vlan_mac.is_inner_mac)) - return pos; - - return NULL; -} - /* check_move() callback */ static bool bnx2x_check_move(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *src_o, @@ -809,8 +721,8 @@ static inline u8 bnx2x_vlan_mac_get_rx_tx_flag(struct bnx2x_vlan_mac_obj *o) return rx_tx_flag; } -void bnx2x_set_mac_in_nig(struct bnx2x *bp, - bool add, unsigned char *dev_addr, int index) +static void bnx2x_set_mac_in_nig(struct bnx2x *bp, + bool add, unsigned char *dev_addr, int index) { u32 wb_data[2]; u32 reg_offset = BP_PORT(bp) ? NIG_REG_LLH1_FUNC_MEM : @@ -1124,97 +1036,6 @@ static void bnx2x_set_one_vlan_e2(struct bnx2x *bp, rule_cnt); } -static void bnx2x_set_one_vlan_mac_e2(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *o, - struct bnx2x_exeq_elem *elem, - int rule_idx, int cam_offset) -{ - struct bnx2x_raw_obj *raw = &o->raw; - struct eth_classify_rules_ramrod_data *data = - (struct eth_classify_rules_ramrod_data *)(raw->rdata); - int rule_cnt = rule_idx + 1; - union eth_classify_rule_cmd *rule_entry = &data->rules[rule_idx]; - enum bnx2x_vlan_mac_cmd cmd = elem->cmd_data.vlan_mac.cmd; - bool add = (cmd == BNX2X_VLAN_MAC_ADD) ? true : false; - u16 vlan = elem->cmd_data.vlan_mac.u.vlan_mac.vlan; - u8 *mac = elem->cmd_data.vlan_mac.u.vlan_mac.mac; - - /* Reset the ramrod data buffer for the first rule */ - if (rule_idx == 0) - memset(data, 0, sizeof(*data)); - - /* Set a rule header */ - bnx2x_vlan_mac_set_cmd_hdr_e2(bp, o, add, CLASSIFY_RULE_OPCODE_PAIR, - &rule_entry->pair.header); - - /* Set VLAN and MAC themselves */ - rule_entry->pair.vlan = cpu_to_le16(vlan); - bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, - &rule_entry->pair.mac_mid, - &rule_entry->pair.mac_lsb, mac); - rule_entry->pair.inner_mac = - cpu_to_le16(elem->cmd_data.vlan_mac.u.vlan_mac.is_inner_mac); - /* MOVE: Add a rule that will add this MAC to the target Queue */ - if (cmd == BNX2X_VLAN_MAC_MOVE) { - rule_entry++; - rule_cnt++; - - /* Setup ramrod data */ - bnx2x_vlan_mac_set_cmd_hdr_e2(bp, - elem->cmd_data.vlan_mac.target_obj, - true, CLASSIFY_RULE_OPCODE_PAIR, - &rule_entry->pair.header); - - /* Set a VLAN itself */ - rule_entry->pair.vlan = cpu_to_le16(vlan); - bnx2x_set_fw_mac_addr(&rule_entry->pair.mac_msb, - &rule_entry->pair.mac_mid, - &rule_entry->pair.mac_lsb, mac); - rule_entry->pair.inner_mac = - cpu_to_le16(elem->cmd_data.vlan_mac.u. - vlan_mac.is_inner_mac); - } - - /* Set the ramrod data header */ - /* TODO: take this to the higher level in order to prevent multiple - writing */ - bnx2x_vlan_mac_set_rdata_hdr_e2(raw->cid, raw->state, &data->header, - rule_cnt); -} - -/** - * bnx2x_set_one_vlan_mac_e1h - - * - * @bp: device handle - * @o: bnx2x_vlan_mac_obj - * @elem: bnx2x_exeq_elem - * @rule_idx: rule_idx - * @cam_offset: cam_offset - */ -static void bnx2x_set_one_vlan_mac_e1h(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *o, - struct bnx2x_exeq_elem *elem, - int rule_idx, int cam_offset) -{ - struct bnx2x_raw_obj *raw = &o->raw; - struct mac_configuration_cmd *config = - (struct mac_configuration_cmd *)(raw->rdata); - /* 57710 and 57711 do not support MOVE command, - * so it's either ADD or DEL - */ - bool add = (elem->cmd_data.vlan_mac.cmd == BNX2X_VLAN_MAC_ADD) ? - true : false; - - /* Reset the ramrod data buffer */ - memset(config, 0, sizeof(*config)); - - bnx2x_vlan_mac_set_rdata_e1x(bp, o, BNX2X_FILTER_VLAN_MAC_PENDING, - cam_offset, add, - elem->cmd_data.vlan_mac.u.vlan_mac.mac, - elem->cmd_data.vlan_mac.u.vlan_mac.vlan, - ETH_VLAN_FILTER_CLASSIFY, config); -} - /** * bnx2x_vlan_mac_restore - reconfigure next MAC/VLAN/VLAN-MAC element * @@ -1314,24 +1135,6 @@ static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan( return NULL; } -static struct bnx2x_exeq_elem *bnx2x_exeq_get_vlan_mac( - struct bnx2x_exe_queue_obj *o, - struct bnx2x_exeq_elem *elem) -{ - struct bnx2x_exeq_elem *pos; - struct bnx2x_vlan_mac_ramrod_data *data = - &elem->cmd_data.vlan_mac.u.vlan_mac; - - /* Check pending for execution commands */ - list_for_each_entry(pos, &o->exe_queue, link) - if (!memcmp(&pos->cmd_data.vlan_mac.u.vlan_mac, data, - sizeof(*data)) && - (pos->cmd_data.vlan_mac.cmd == elem->cmd_data.vlan_mac.cmd)) - return pos; - - return NULL; -} - /** * bnx2x_validate_vlan_mac_add - check if an ADD command can be executed * @@ -2239,69 +2042,6 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp, } } -void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *vlan_mac_obj, - u8 cl_id, u32 cid, u8 func_id, void *rdata, - dma_addr_t rdata_mapping, int state, - unsigned long *pstate, bnx2x_obj_type type, - struct bnx2x_credit_pool_obj *macs_pool, - struct bnx2x_credit_pool_obj *vlans_pool) -{ - union bnx2x_qable_obj *qable_obj = - (union bnx2x_qable_obj *)vlan_mac_obj; - - bnx2x_init_vlan_mac_common(vlan_mac_obj, cl_id, cid, func_id, rdata, - rdata_mapping, state, pstate, type, - macs_pool, vlans_pool); - - /* CAM pool handling */ - vlan_mac_obj->get_credit = bnx2x_get_credit_vlan_mac; - vlan_mac_obj->put_credit = bnx2x_put_credit_vlan_mac; - /* CAM offset is relevant for 57710 and 57711 chips only which have a - * single CAM for both MACs and VLAN-MAC pairs. So the offset - * will be taken from MACs' pool object only. - */ - vlan_mac_obj->get_cam_offset = bnx2x_get_cam_offset_mac; - vlan_mac_obj->put_cam_offset = bnx2x_put_cam_offset_mac; - - if (CHIP_IS_E1(bp)) { - BNX2X_ERR("Do not support chips others than E2\n"); - BUG(); - } else if (CHIP_IS_E1H(bp)) { - vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e1h; - vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; - vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; - vlan_mac_obj->check_move = bnx2x_check_move_always_err; - vlan_mac_obj->ramrod_cmd = RAMROD_CMD_ID_ETH_SET_MAC; - - /* Exe Queue */ - bnx2x_exe_queue_init(bp, - &vlan_mac_obj->exe_queue, 1, qable_obj, - bnx2x_validate_vlan_mac, - bnx2x_remove_vlan_mac, - bnx2x_optimize_vlan_mac, - bnx2x_execute_vlan_mac, - bnx2x_exeq_get_vlan_mac); - } else { - vlan_mac_obj->set_one_rule = bnx2x_set_one_vlan_mac_e2; - vlan_mac_obj->check_del = bnx2x_check_vlan_mac_del; - vlan_mac_obj->check_add = bnx2x_check_vlan_mac_add; - vlan_mac_obj->check_move = bnx2x_check_move; - vlan_mac_obj->ramrod_cmd = - RAMROD_CMD_ID_ETH_CLASSIFICATION_RULES; - - /* Exe Queue */ - bnx2x_exe_queue_init(bp, - &vlan_mac_obj->exe_queue, - CLASSIFY_RULES_COUNT, - qable_obj, bnx2x_validate_vlan_mac, - bnx2x_remove_vlan_mac, - bnx2x_optimize_vlan_mac, - bnx2x_execute_vlan_mac, - bnx2x_exeq_get_vlan_mac); - } -} - /* RX_MODE verbs: DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */ static inline void __storm_memset_mac_filters(struct bnx2x *bp, struct tstorm_eth_mac_filter_config *mac_filters, @@ -4988,6 +4728,13 @@ static void bnx2x_q_fill_update_data(struct bnx2x *bp, test_bit(BNX2X_Q_UPDATE_SILENT_VLAN_REM, ¶ms->update_flags); data->silent_vlan_value = cpu_to_le16(params->silent_removal_value); data->silent_vlan_mask = cpu_to_le16(params->silent_removal_mask); + + /* tx switching */ + data->tx_switching_flg = + test_bit(BNX2X_Q_UPDATE_TX_SWITCHING, ¶ms->update_flags); + data->tx_switching_change_flg = + test_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG, + ¶ms->update_flags); } static inline int bnx2x_q_send_update(struct bnx2x *bp, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 6a53c15c85a3..00d7f214a40a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -448,9 +448,6 @@ enum { BNX2X_LLH_CAM_MAX_PF_LINE = NIG_REG_LLH1_FUNC_MEM_SIZE / 2 }; -void bnx2x_set_mac_in_nig(struct bnx2x *bp, - bool add, unsigned char *dev_addr, int index); - /** RX_MODE verbs:DROP_ALL/ACCEPT_ALL/ACCEPT_ALL_MULTI/ACCEPT_ALL_VLAN/NORMAL */ /* RX_MODE ramrod special flags: set in rx_mode_flags field in @@ -770,7 +767,9 @@ enum { BNX2X_Q_UPDATE_DEF_VLAN_EN, BNX2X_Q_UPDATE_DEF_VLAN_EN_CHNG, BNX2X_Q_UPDATE_SILENT_VLAN_REM_CHNG, - BNX2X_Q_UPDATE_SILENT_VLAN_REM + BNX2X_Q_UPDATE_SILENT_VLAN_REM, + BNX2X_Q_UPDATE_TX_SWITCHING_CHNG, + BNX2X_Q_UPDATE_TX_SWITCHING }; /* Allowed Queue states */ @@ -1307,22 +1306,12 @@ void bnx2x_init_vlan_obj(struct bnx2x *bp, unsigned long *pstate, bnx2x_obj_type type, struct bnx2x_credit_pool_obj *vlans_pool); -void bnx2x_init_vlan_mac_obj(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *vlan_mac_obj, - u8 cl_id, u32 cid, u8 func_id, void *rdata, - dma_addr_t rdata_mapping, int state, - unsigned long *pstate, bnx2x_obj_type type, - struct bnx2x_credit_pool_obj *macs_pool, - struct bnx2x_credit_pool_obj *vlans_pool); - int bnx2x_vlan_mac_h_read_lock(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o); void bnx2x_vlan_mac_h_read_unlock(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o); int bnx2x_vlan_mac_h_write_lock(struct bnx2x *bp, struct bnx2x_vlan_mac_obj *o); -void bnx2x_vlan_mac_h_write_unlock(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *o); int bnx2x_config_vlan_mac(struct bnx2x *bp, struct bnx2x_vlan_mac_ramrod_params *p); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 31ab924600c1..d0e246b8a871 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -799,10 +799,10 @@ int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp, return -ENOMEM; } -int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp, - struct bnx2x_virtf *vf, - struct bnx2x_vfop_cmd *cmd, - int qid, u16 vid, bool add) +static int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vfop_cmd *cmd, + int qid, u16 vid, bool add) { struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); int rc; @@ -3130,6 +3130,60 @@ void bnx2x_unlock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf, vf->abs_vfid, vf->op_current); } +static int bnx2x_set_pf_tx_switching(struct bnx2x *bp, bool enable) +{ + struct bnx2x_queue_state_params q_params; + u32 prev_flags; + int i, rc; + + /* Verify changes are needed and record current Tx switching state */ + prev_flags = bp->flags; + if (enable) + bp->flags |= TX_SWITCHING; + else + bp->flags &= ~TX_SWITCHING; + if (prev_flags == bp->flags) + return 0; + + /* Verify state enables the sending of queue ramrods */ + if ((bp->state != BNX2X_STATE_OPEN) || + (bnx2x_get_q_logical_state(bp, + &bnx2x_sp_obj(bp, &bp->fp[0]).q_obj) != + BNX2X_Q_LOGICAL_STATE_ACTIVE)) + return 0; + + /* send q. update ramrod to configure Tx switching */ + memset(&q_params, 0, sizeof(q_params)); + __set_bit(RAMROD_COMP_WAIT, &q_params.ramrod_flags); + q_params.cmd = BNX2X_Q_CMD_UPDATE; + __set_bit(BNX2X_Q_UPDATE_TX_SWITCHING_CHNG, + &q_params.params.update.update_flags); + if (enable) + __set_bit(BNX2X_Q_UPDATE_TX_SWITCHING, + &q_params.params.update.update_flags); + else + __clear_bit(BNX2X_Q_UPDATE_TX_SWITCHING, + &q_params.params.update.update_flags); + + /* send the ramrod on all the queues of the PF */ + for_each_eth_queue(bp, i) { + struct bnx2x_fastpath *fp = &bp->fp[i]; + + /* Set the appropriate Queue object */ + q_params.q_obj = &bnx2x_sp_obj(bp, fp).q_obj; + + /* Update the Queue state */ + rc = bnx2x_queue_state_change(bp, &q_params); + if (rc) { + BNX2X_ERR("Failed to configure Tx switching\n"); + return rc; + } + } + + DP(BNX2X_MSG_IOV, "%s Tx Switching\n", enable ? "Enabled" : "Disabled"); + return 0; +} + int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param) { struct bnx2x *bp = netdev_priv(pci_get_drvdata(dev)); @@ -3157,12 +3211,14 @@ int bnx2x_sriov_configure(struct pci_dev *dev, int num_vfs_param) bp->requested_nr_virtfn = num_vfs_param; if (num_vfs_param == 0) { + bnx2x_set_pf_tx_switching(bp, false); pci_disable_sriov(dev); return 0; } else { return bnx2x_enable_sriov(bp); } } + #define IGU_ENTRY_SIZE 4 int bnx2x_enable_sriov(struct bnx2x *bp) @@ -3240,6 +3296,11 @@ int bnx2x_enable_sriov(struct bnx2x *bp) */ DP(BNX2X_MSG_IOV, "about to call enable sriov\n"); bnx2x_disable_sriov(bp); + + rc = bnx2x_set_pf_tx_switching(bp, true); + if (rc) + return rc; + rc = pci_enable_sriov(bp->pdev, req_vfs); if (rc) { BNX2X_ERR("pci_enable_sriov failed with %d\n", rc); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index d72ab7e24de0..d9fcca1b5a9d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -665,11 +665,6 @@ int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp, struct bnx2x_vfop_filters *macs, int qid, bool drv_only); -int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp, - struct bnx2x_virtf *vf, - struct bnx2x_vfop_cmd *cmd, - int qid, u16 vid, bool add); - int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vfop_cmd *cmd, @@ -727,13 +722,6 @@ void bnx2x_vf_enable_access(struct bnx2x *bp, u8 abs_vfid); /* Handles an FLR (or VF_DISABLE) notification form the MCP */ void bnx2x_vf_handle_flr_event(struct bnx2x *bp); -void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type, - u16 length); -void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, - u16 type, u16 length); -void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv); -void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list); - bool bnx2x_tlv_supported(u16 tlvtype); u32 bnx2x_crc_vf_bulletin(struct bnx2x *bp, @@ -750,7 +738,6 @@ int bnx2x_vfpf_init(struct bnx2x *bp); void bnx2x_vfpf_close_vf(struct bnx2x *bp); int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp, bool is_leading); -int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx); int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set); int bnx2x_vfpf_config_rss(struct bnx2x *bp, struct bnx2x_config_rss_params *params); @@ -814,7 +801,6 @@ static inline int bnx2x_vfpf_release(struct bnx2x *bp) {return 0; } static inline int bnx2x_vfpf_init(struct bnx2x *bp) {return 0; } static inline void bnx2x_vfpf_close_vf(struct bnx2x *bp) {} static inline int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp, bool is_leading) {return 0; } -static inline int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) {return 0; } static inline int bnx2x_vfpf_config_mac(struct bnx2x *bp, u8 *addr, u8 vf_qid, bool set) {return 0; } static inline int bnx2x_vfpf_config_rss(struct bnx2x *bp, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 1b1ad31b4553..3fa6c2a2a5a9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -21,9 +21,11 @@ #include "bnx2x_cmn.h" #include <linux/crc32.h> +static int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx); + /* place a given tlv on the tlv buffer at a given offset */ -void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type, - u16 length) +static void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, + u16 offset, u16 type, u16 length) { struct channel_tlv *tl = (struct channel_tlv *)(tlvs_list + offset); @@ -33,8 +35,8 @@ void bnx2x_add_tlv(struct bnx2x *bp, void *tlvs_list, u16 offset, u16 type, } /* Clear the mailbox and init the header of the first tlv */ -void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, - u16 type, u16 length) +static void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, + u16 type, u16 length) { mutex_lock(&bp->vf2pf_mutex); @@ -52,7 +54,8 @@ void bnx2x_vfpf_prep(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv, } /* releases the mailbox */ -void bnx2x_vfpf_finalize(struct bnx2x *bp, struct vfpf_first_tlv *first_tlv) +static void bnx2x_vfpf_finalize(struct bnx2x *bp, + struct vfpf_first_tlv *first_tlv) { DP(BNX2X_MSG_IOV, "done sending [%d] tlv over vf pf channel\n", first_tlv->tl.type); @@ -85,7 +88,7 @@ static void *bnx2x_search_tlv_list(struct bnx2x *bp, void *tlvs_list, } /* list the types and lengths of the tlvs on the buffer */ -void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list) +static void bnx2x_dp_tlv_list(struct bnx2x *bp, void *tlvs_list) { int i = 1; struct channel_tlv *tlv = (struct channel_tlv *)tlvs_list; @@ -633,7 +636,7 @@ int bnx2x_vfpf_setup_q(struct bnx2x *bp, struct bnx2x_fastpath *fp, return rc; } -int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) +static int bnx2x_vfpf_teardown_queue(struct bnx2x *bp, int qidx) { struct vfpf_q_op_tlv *req = &bp->vf2pf_mbox->req.q_op; struct pfvf_general_resp_tlv *resp = &bp->vf2pf_mbox->resp.general_resp; diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index cb05be905def..81e8402a74b4 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -423,7 +423,7 @@ u64 cxgb4_select_ntuple(struct net_device *dev, * in the Compressed Filter Tuple. */ if (tp->vlan_shift >= 0 && l2t->vlan != VLAN_NONE) - ntuple |= (F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift; + ntuple |= (u64)(F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift; if (tp->port_shift >= 0) ntuple |= (u64)l2t->lport << tp->port_shift; diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 4ccaf9af6fc9..8d09615da585 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -34,7 +34,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "4.9.224.0u" +#define DRV_VER "10.0.600.0u" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" @@ -42,7 +42,7 @@ #define OC_NAME_BE OC_NAME "(be3)" #define OC_NAME_LANCER OC_NAME "(Lancer)" #define OC_NAME_SH OC_NAME "(Skyhawk)" -#define DRV_DESC "Emulex OneConnect 10Gbps NIC Driver" +#define DRV_DESC "Emulex OneConnect NIC Driver" #define BE_VENDOR_ID 0x19a2 #define EMULEX_VENDOR_ID 0x10df @@ -283,7 +283,6 @@ struct be_rx_compl_info { u32 rss_hash; u16 vlan_tag; u16 pkt_size; - u16 rxq_idx; u16 port; u8 vlanf; u8 num_rcvd; @@ -493,7 +492,7 @@ struct be_adapter { u16 pvid; struct phy_info phy; u8 wol_cap; - bool wol; + bool wol_en; u32 uc_macs; /* Count of secondary UC MAC programmed */ u16 asic_rev; u16 qnq_vid; diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 94c35c8d799d..48076a6370c3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1101,23 +1101,22 @@ static int be_cmd_mccq_ext_create(struct be_adapter *adapter, OPCODE_COMMON_MCC_CREATE_EXT, sizeof(*req), wrb, NULL); req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size)); - if (lancer_chip(adapter)) { - req->hdr.version = 1; - req->cq_id = cpu_to_le16(cq->id); - - AMAP_SET_BITS(struct amap_mcc_context_lancer, ring_size, ctxt, - be_encoded_q_len(mccq->len)); - AMAP_SET_BITS(struct amap_mcc_context_lancer, valid, ctxt, 1); - AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_id, - ctxt, cq->id); - AMAP_SET_BITS(struct amap_mcc_context_lancer, async_cq_valid, - ctxt, 1); - - } else { + if (BEx_chip(adapter)) { AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1); AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt, be_encoded_q_len(mccq->len)); AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id); + } else { + req->hdr.version = 1; + req->cq_id = cpu_to_le16(cq->id); + + AMAP_SET_BITS(struct amap_mcc_context_v1, ring_size, ctxt, + be_encoded_q_len(mccq->len)); + AMAP_SET_BITS(struct amap_mcc_context_v1, valid, ctxt, 1); + AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_id, + ctxt, cq->id); + AMAP_SET_BITS(struct amap_mcc_context_v1, async_cq_valid, + ctxt, 1); } /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */ @@ -1187,7 +1186,7 @@ int be_cmd_mccq_create(struct be_adapter *adapter, int status; status = be_cmd_mccq_ext_create(adapter, mccq, cq); - if (status && !lancer_chip(adapter)) { + if (status && BEx_chip(adapter)) { dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 " "or newer to avoid conflicting priorities between NIC " "and FCoE traffic"); @@ -2692,6 +2691,13 @@ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege, struct be_cmd_resp_get_fn_privileges *resp = embedded_payload(wrb); *privilege = le32_to_cpu(resp->privilege_mask); + + /* In UMC mode FW does not return right privileges. + * Override with correct privilege equivalent to PF. + */ + if (BEx_chip(adapter) && be_is_mc(adapter) && + be_physfn(adapter)) + *privilege = MAX_PRIVILEGES; } err: @@ -2736,7 +2742,8 @@ err: * If pmac_id is returned, pmac_id_valid is returned as true */ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, - bool *pmac_id_valid, u32 *pmac_id, u8 domain) + bool *pmac_id_valid, u32 *pmac_id, u32 if_handle, + u8 domain) { struct be_mcc_wrb *wrb; struct be_cmd_req_get_mac_list *req; @@ -2774,7 +2781,7 @@ int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, req->mac_type = MAC_ADDRESS_TYPE_NETWORK; if (*pmac_id_valid) { req->mac_id = cpu_to_le32(*pmac_id); - req->iface_id = cpu_to_le16(adapter->if_handle); + req->iface_id = cpu_to_le16(if_handle); req->perm_override = 0; } else { req->perm_override = 1; @@ -2827,17 +2834,21 @@ out: return status; } -int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac) +int be_cmd_get_active_mac(struct be_adapter *adapter, u32 curr_pmac_id, u8 *mac, + u32 if_handle, bool active, u32 domain) { - bool active = true; + if (!active) + be_cmd_get_mac_from_list(adapter, mac, &active, &curr_pmac_id, + if_handle, domain); if (BEx_chip(adapter)) return be_cmd_mac_addr_query(adapter, mac, false, - adapter->if_handle, curr_pmac_id); + if_handle, curr_pmac_id); else /* Fetch the MAC address using pmac_id */ return be_cmd_get_mac_from_list(adapter, mac, &active, - &curr_pmac_id, 0); + &curr_pmac_id, + if_handle, domain); } int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) @@ -2856,7 +2867,7 @@ int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac) adapter->if_handle, 0); } else { status = be_cmd_get_mac_from_list(adapter, mac, &pmac_valid, - NULL, 0); + NULL, adapter->if_handle, 0); } return status; @@ -2917,7 +2928,8 @@ int be_cmd_set_mac(struct be_adapter *adapter, u8 *mac, int if_id, u32 dom) int status; status = be_cmd_get_mac_from_list(adapter, old_mac, &active_mac, - &pmac_id, dom); + &pmac_id, if_id, dom); + if (!status && active_mac) be_cmd_pmac_del(adapter, if_id, pmac_id, dom); @@ -2997,7 +3009,7 @@ int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, ctxt, intf_id); AMAP_SET_BITS(struct amap_get_hsw_req_context, pvid_valid, ctxt, 1); - if (!BEx_chip(adapter)) { + if (!BEx_chip(adapter) && mode) { AMAP_SET_BITS(struct amap_get_hsw_req_context, interface_id, ctxt, adapter->hba_port_num); AMAP_SET_BITS(struct amap_get_hsw_req_context, pport, ctxt, 1); @@ -3028,14 +3040,16 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) { struct be_mcc_wrb *wrb; struct be_cmd_req_acpi_wol_magic_config_v1 *req; - int status; - int payload_len = sizeof(*req); + int status = 0; struct be_dma_mem cmd; if (!be_cmd_allowed(adapter, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, CMD_SUBSYSTEM_ETH)) return -EPERM; + if (be_is_wol_excluded(adapter)) + return status; + if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1; @@ -3060,7 +3074,7 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG, - payload_len, wrb, &cmd); + sizeof(*req), wrb, &cmd); req->hdr.version = 1; req->query_options = BE_GET_WOL_CAP; @@ -3070,13 +3084,9 @@ int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter) struct be_cmd_resp_acpi_wol_magic_config_v1 *resp; resp = (struct be_cmd_resp_acpi_wol_magic_config_v1 *) cmd.va; - /* the command could succeed misleadingly on old f/w - * which is not aware of the V1 version. fake an error. */ - if (resp->hdr.response_length < payload_len) { - status = -1; - goto err; - } adapter->wol_cap = resp->wol_settings; + if (adapter->wol_cap & BE_WOL_CAP) + adapter->wol_en = true; } err: mutex_unlock(&adapter->mbox_lock); @@ -3085,6 +3095,76 @@ err: return status; } + +int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level) +{ + struct be_dma_mem extfat_cmd; + struct be_fat_conf_params *cfgs; + int status; + int i, j; + + memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); + extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); + extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, + &extfat_cmd.dma); + if (!extfat_cmd.va) + return -ENOMEM; + + status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); + if (status) + goto err; + + cfgs = (struct be_fat_conf_params *) + (extfat_cmd.va + sizeof(struct be_cmd_resp_hdr)); + for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { + u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); + for (j = 0; j < num_modes; j++) { + if (cfgs->module[i].trace_lvl[j].mode == MODE_UART) + cfgs->module[i].trace_lvl[j].dbg_lvl = + cpu_to_le32(level); + } + } + + status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, cfgs); +err: + pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, + extfat_cmd.dma); + return status; +} + +int be_cmd_get_fw_log_level(struct be_adapter *adapter) +{ + struct be_dma_mem extfat_cmd; + struct be_fat_conf_params *cfgs; + int status, j; + int level = 0; + + memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); + extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); + extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, + &extfat_cmd.dma); + + if (!extfat_cmd.va) { + dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", + __func__); + goto err; + } + + status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); + if (!status) { + cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + + sizeof(struct be_cmd_resp_hdr)); + for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) { + if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) + level = cfgs->module[0].trace_lvl[j].dbg_lvl; + } + } + pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, + extfat_cmd.dma); +err: + return level; +} + int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, struct be_dma_mem *cmd) { @@ -3609,6 +3689,40 @@ int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable) return status; } +/* Uses MBOX */ +int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile_id) +{ + struct be_cmd_req_get_active_profile *req; + struct be_mcc_wrb *wrb; + int status; + + if (mutex_lock_interruptible(&adapter->mbox_lock)) + return -1; + + wrb = wrb_from_mbox(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_GET_ACTIVE_PROFILE, sizeof(*req), + wrb, NULL); + + status = be_mbox_notify_wait(adapter); + if (!status) { + struct be_cmd_resp_get_active_profile *resp = + embedded_payload(wrb); + *profile_id = le16_to_cpu(resp->active_profile_id); + } + +err: + mutex_unlock(&adapter->mbox_lock); + return status; +} + int be_roce_mcc_cmd(void *netdev_handle, void *wrb_payload, int wrb_payload_size, u16 *cmd_status, u16 *ext_status) { diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 0075686276aa..fc4e076dc202 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -216,6 +216,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_GET_FUNC_CONFIG 160 #define OPCODE_COMMON_GET_PROFILE_CONFIG 164 #define OPCODE_COMMON_SET_PROFILE_CONFIG 165 +#define OPCODE_COMMON_GET_ACTIVE_PROFILE 167 #define OPCODE_COMMON_SET_HSW_CONFIG 153 #define OPCODE_COMMON_GET_FN_PRIVILEGES 170 #define OPCODE_COMMON_READ_OBJECT 171 @@ -452,7 +453,7 @@ struct amap_mcc_context_be { u8 rsvd2[32]; } __packed; -struct amap_mcc_context_lancer { +struct amap_mcc_context_v1 { u8 async_cq_id[16]; u8 ring_size[4]; u8 rsvd0[12]; @@ -476,7 +477,7 @@ struct be_cmd_req_mcc_ext_create { u16 num_pages; u16 cq_id; u32 async_event_bitmap[1]; - u8 context[sizeof(struct amap_mcc_context_be) / 8]; + u8 context[sizeof(struct amap_mcc_context_v1) / 8]; struct phys_addr pages[8]; } __packed; @@ -1097,6 +1098,14 @@ struct be_cmd_resp_query_fw_cfg { u32 function_caps; }; +/* Is BE in a multi-channel mode */ +static inline bool be_is_mc(struct be_adapter *adapter) +{ + return adapter->function_mode & FLEX10_MODE || + adapter->function_mode & VNIC_MODE || + adapter->function_mode & UMC_ENABLED; +} + /******************** RSS Config ****************************************/ /* RSS type Input parameters used to compute RX hash * RSS_ENABLE_IPV4 SRC IPv4, DST IPv4 @@ -1917,6 +1926,17 @@ struct be_cmd_resp_set_profile_config { struct be_cmd_resp_hdr hdr; }; +struct be_cmd_req_get_active_profile { + struct be_cmd_req_hdr hdr; + u32 rsvd; +} __packed; + +struct be_cmd_resp_get_active_profile { + struct be_cmd_resp_hdr hdr; + u16 active_profile_id; + u16 next_profile_id; +} __packed; + struct be_cmd_enable_disable_vf { struct be_cmd_req_hdr hdr; u8 enable; @@ -2037,8 +2057,10 @@ int be_cmd_get_fn_privileges(struct be_adapter *adapter, u32 *privilege, int be_cmd_set_fn_privileges(struct be_adapter *adapter, u32 privileges, u32 vf_num); int be_cmd_get_mac_from_list(struct be_adapter *adapter, u8 *mac, - bool *pmac_id_active, u32 *pmac_id, u8 domain); -int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id, u8 *mac); + bool *pmac_id_active, u32 *pmac_id, + u32 if_handle, u8 domain); +int be_cmd_get_active_mac(struct be_adapter *adapter, u32 pmac_id, u8 *mac, + u32 if_handle, bool active, u32 domain); int be_cmd_get_perm_mac(struct be_adapter *adapter, u8 *mac); int be_cmd_set_mac_list(struct be_adapter *adapter, u8 *mac_array, u8 mac_count, u32 domain); @@ -2048,6 +2070,8 @@ int be_cmd_set_hsw_config(struct be_adapter *adapter, u16 pvid, u32 domain, int be_cmd_get_hsw_config(struct be_adapter *adapter, u16 *pvid, u32 domain, u16 intf_id, u8 *mode); int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter); +int be_cmd_set_fw_log_level(struct be_adapter *adapter, u32 level); +int be_cmd_get_fw_log_level(struct be_adapter *adapter); int be_cmd_get_ext_fat_capabilites(struct be_adapter *adapter, struct be_dma_mem *cmd); int be_cmd_set_ext_fat_capabilites(struct be_adapter *adapter, @@ -2063,6 +2087,7 @@ int be_cmd_get_func_config(struct be_adapter *adapter, int be_cmd_get_profile_config(struct be_adapter *adapter, struct be_resources *res, u8 domain); int be_cmd_set_profile_config(struct be_adapter *adapter, u32 bps, u8 domain); +int be_cmd_get_active_profile(struct be_adapter *adapter, u16 *profile); int be_cmd_get_if_id(struct be_adapter *adapter, struct be_vf_cfg *vf_cfg, int vf_num); int be_cmd_enable_vf(struct be_adapter *adapter, u8 domain); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 08330034d9ef..05be0070f55f 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -713,12 +713,13 @@ be_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct be_adapter *adapter = netdev_priv(netdev); - if (be_is_wol_supported(adapter)) { + if (adapter->wol_cap & BE_WOL_CAP) { wol->supported |= WAKE_MAGIC; - if (adapter->wol) + if (adapter->wol_en) wol->wolopts |= WAKE_MAGIC; - } else + } else { wol->wolopts = 0; + } memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -730,15 +731,15 @@ be_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) if (wol->wolopts & ~WAKE_MAGIC) return -EOPNOTSUPP; - if (!be_is_wol_supported(adapter)) { + if (!(adapter->wol_cap & BE_WOL_CAP)) { dev_warn(&adapter->pdev->dev, "WOL not supported\n"); return -EOPNOTSUPP; } if (wol->wolopts & WAKE_MAGIC) - adapter->wol = true; + adapter->wol_en = true; else - adapter->wol = false; + adapter->wol_en = false; return 0; } @@ -904,73 +905,21 @@ static u32 be_get_msg_level(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - if (lancer_chip(adapter)) { - dev_err(&adapter->pdev->dev, "Operation not supported\n"); - return -EOPNOTSUPP; - } - return adapter->msg_enable; } -static void be_set_fw_log_level(struct be_adapter *adapter, u32 level) -{ - struct be_dma_mem extfat_cmd; - struct be_fat_conf_params *cfgs; - int status; - int i, j; - - memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); - extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); - extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, - &extfat_cmd.dma); - if (!extfat_cmd.va) { - dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", - __func__); - goto err; - } - status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); - if (!status) { - cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + - sizeof(struct be_cmd_resp_hdr)); - for (i = 0; i < le32_to_cpu(cfgs->num_modules); i++) { - u32 num_modes = le32_to_cpu(cfgs->module[i].num_modes); - for (j = 0; j < num_modes; j++) { - if (cfgs->module[i].trace_lvl[j].mode == - MODE_UART) - cfgs->module[i].trace_lvl[j].dbg_lvl = - cpu_to_le32(level); - } - } - status = be_cmd_set_ext_fat_capabilites(adapter, &extfat_cmd, - cfgs); - if (status) - dev_err(&adapter->pdev->dev, - "Message level set failed\n"); - } else { - dev_err(&adapter->pdev->dev, "Message level get failed\n"); - } - - pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, - extfat_cmd.dma); -err: - return; -} - static void be_set_msg_level(struct net_device *netdev, u32 level) { struct be_adapter *adapter = netdev_priv(netdev); - if (lancer_chip(adapter)) { - dev_err(&adapter->pdev->dev, "Operation not supported\n"); - return; - } - if (adapter->msg_enable == level) return; if ((level & NETIF_MSG_HW) != (adapter->msg_enable & NETIF_MSG_HW)) - be_set_fw_log_level(adapter, level & NETIF_MSG_HW ? - FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL); + if (BEx_chip(adapter)) + be_cmd_set_fw_log_level(adapter, level & NETIF_MSG_HW ? + FW_LOG_LEVEL_DEFAULT : + FW_LOG_LEVEL_FATAL); adapter->msg_enable = level; return; diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 3acf137b5784..6d22d6f439e3 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -121,12 +121,6 @@ static const char * const ue_status_hi_desc[] = { "Unknown" }; -/* Is BE in a multi-channel mode */ -static inline bool be_is_mc(struct be_adapter *adapter) { - return (adapter->function_mode & FLEX10_MODE || - adapter->function_mode & VNIC_MODE || - adapter->function_mode & UMC_ENABLED); -} static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q) { @@ -258,6 +252,12 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; + /* Proceed further only if, User provided MAC is different + * from active MAC + */ + if (ether_addr_equal(addr->sa_data, netdev->dev_addr)) + return 0; + /* The PMAC_ADD cmd may fail if the VF doesn't have FILTMGMT * privilege or if PF did not provision the new MAC address. * On BE3, this cmd will always fail if the VF doesn't have the @@ -280,7 +280,8 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) /* Decide if the new MAC is successfully activated only after * querying the FW */ - status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac); + status = be_cmd_get_active_mac(adapter, curr_pmac_id, mac, + adapter->if_handle, true, 0); if (status) goto err; @@ -1442,12 +1443,12 @@ static inline bool csum_passed(struct be_rx_compl_info *rxcp) (rxcp->ip_csum || rxcp->ipv6); } -static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo, - u16 frag_idx) +static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo) { struct be_adapter *adapter = rxo->adapter; struct be_rx_page_info *rx_page_info; struct be_queue_info *rxq = &rxo->q; + u16 frag_idx = rxq->tail; rx_page_info = &rxo->page_info_tbl[frag_idx]; BUG_ON(!rx_page_info->page); @@ -1459,6 +1460,7 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo, rx_page_info->last_page_user = false; } + queue_tail_inc(rxq); atomic_dec(&rxq->used); return rx_page_info; } @@ -1467,15 +1469,13 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo, static void be_rx_compl_discard(struct be_rx_obj *rxo, struct be_rx_compl_info *rxcp) { - struct be_queue_info *rxq = &rxo->q; struct be_rx_page_info *page_info; u16 i, num_rcvd = rxcp->num_rcvd; for (i = 0; i < num_rcvd; i++) { - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); - index_inc(&rxcp->rxq_idx, rxq->len); } } @@ -1486,13 +1486,12 @@ static void be_rx_compl_discard(struct be_rx_obj *rxo, static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, struct be_rx_compl_info *rxcp) { - struct be_queue_info *rxq = &rxo->q; struct be_rx_page_info *page_info; u16 i, j; u16 hdr_len, curr_frag_len, remaining; u8 *start; - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); start = page_address(page_info->page) + page_info->page_offset; prefetch(start); @@ -1526,10 +1525,9 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, } /* More frags present for this completion */ - index_inc(&rxcp->rxq_idx, rxq->len); remaining = rxcp->pkt_size - curr_frag_len; for (i = 1, j = 0; i < rxcp->num_rcvd; i++) { - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); curr_frag_len = min(remaining, rx_frag_size); /* Coalesce all frags from the same physical page in one slot */ @@ -1550,7 +1548,6 @@ static void skb_fill_rx_data(struct be_rx_obj *rxo, struct sk_buff *skb, skb->data_len += curr_frag_len; skb->truesize += rx_frag_size; remaining -= curr_frag_len; - index_inc(&rxcp->rxq_idx, rxq->len); page_info->page = NULL; } BUG_ON(j > MAX_SKB_FRAGS); @@ -1598,7 +1595,6 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo, struct be_adapter *adapter = rxo->adapter; struct be_rx_page_info *page_info; struct sk_buff *skb = NULL; - struct be_queue_info *rxq = &rxo->q; u16 remaining, curr_frag_len; u16 i, j; @@ -1610,7 +1606,7 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo, remaining = rxcp->pkt_size; for (i = 0, j = -1; i < rxcp->num_rcvd; i++) { - page_info = get_rx_page_info(rxo, rxcp->rxq_idx); + page_info = get_rx_page_info(rxo); curr_frag_len = min(remaining, rx_frag_size); @@ -1628,7 +1624,6 @@ static void be_rx_compl_process_gro(struct be_rx_obj *rxo, skb_frag_size_add(&skb_shinfo(skb)->frags[j], curr_frag_len); skb->truesize += rx_frag_size; remaining -= curr_frag_len; - index_inc(&rxcp->rxq_idx, rxq->len); memset(page_info, 0, sizeof(*page_info)); } BUG_ON(j > MAX_SKB_FRAGS); @@ -1663,8 +1658,6 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl, AMAP_GET_BITS(struct amap_eth_rx_compl_v1, l4_cksm, compl); rxcp->ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, ip_version, compl); - rxcp->rxq_idx = - AMAP_GET_BITS(struct amap_eth_rx_compl_v1, fragndx, compl); rxcp->num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, numfrags, compl); rxcp->pkt_type = @@ -1695,8 +1688,6 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl, AMAP_GET_BITS(struct amap_eth_rx_compl_v0, l4_cksm, compl); rxcp->ipv6 = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, ip_version, compl); - rxcp->rxq_idx = - AMAP_GET_BITS(struct amap_eth_rx_compl_v0, fragndx, compl); rxcp->num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, numfrags, compl); rxcp->pkt_type = @@ -1914,7 +1905,6 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) struct be_rx_compl_info *rxcp; struct be_adapter *adapter = rxo->adapter; int flush_wait = 0; - u16 tail; /* Consume pending rx completions. * Wait for the flush completion (identified by zero num_rcvd) @@ -1947,9 +1937,8 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo) be_cq_notify(adapter, rx_cq->id, false, 0); /* Then free posted rx buffers that were not used */ - tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; - for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { - page_info = get_rx_page_info(rxo, tail); + while (atomic_read(&rxq->used) > 0) { + page_info = get_rx_page_info(rxo); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); } @@ -2884,14 +2873,11 @@ static int be_vfs_mac_query(struct be_adapter *adapter) int status, vf; u8 mac[ETH_ALEN]; struct be_vf_cfg *vf_cfg; - bool active = false; for_all_vfs(adapter, vf_cfg, vf) { - be_cmd_get_mac_from_list(adapter, mac, &active, - &vf_cfg->pmac_id, 0); - - status = be_cmd_mac_addr_query(adapter, mac, false, - vf_cfg->if_handle, 0); + status = be_cmd_get_active_mac(adapter, vf_cfg->pmac_id, + mac, vf_cfg->if_handle, + false, vf+1); if (status) return status; memcpy(vf_cfg->mac_addr, mac, ETH_ALEN); @@ -3233,6 +3219,7 @@ static int be_get_resources(struct be_adapter *adapter) /* Routine to query per function resource limits */ static int be_get_config(struct be_adapter *adapter) { + u16 profile_id; int status; status = be_cmd_query_fw_cfg(adapter, &adapter->port_num, @@ -3242,6 +3229,13 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; + if (be_physfn(adapter)) { + status = be_cmd_get_active_profile(adapter, &profile_id); + if (!status) + dev_info(&adapter->pdev->dev, + "Using profile 0x%x\n", profile_id); + } + status = be_get_resources(adapter); if (status) return status; @@ -3396,11 +3390,6 @@ static int be_setup(struct be_adapter *adapter) goto err; be_cmd_get_fn_privileges(adapter, &adapter->cmd_privileges, 0); - /* In UMC mode FW does not return right privileges. - * Override with correct privilege equivalent to PF. - */ - if (be_is_mc(adapter)) - adapter->cmd_privileges = MAX_PRIVILEGES; status = be_mac_setup(adapter); if (status) @@ -3419,6 +3408,8 @@ static int be_setup(struct be_adapter *adapter) be_set_rx_mode(adapter->netdev); + be_cmd_get_acpi_wol_cap(adapter); + be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc); if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc) @@ -4288,74 +4279,22 @@ static void be_remove(struct pci_dev *pdev) free_netdev(adapter->netdev); } -bool be_is_wol_supported(struct be_adapter *adapter) -{ - return ((adapter->wol_cap & BE_WOL_CAP) && - !be_is_wol_excluded(adapter)) ? true : false; -} - -u32 be_get_fw_log_level(struct be_adapter *adapter) -{ - struct be_dma_mem extfat_cmd; - struct be_fat_conf_params *cfgs; - int status; - u32 level = 0; - int j; - - if (lancer_chip(adapter)) - return 0; - - memset(&extfat_cmd, 0, sizeof(struct be_dma_mem)); - extfat_cmd.size = sizeof(struct be_cmd_resp_get_ext_fat_caps); - extfat_cmd.va = pci_alloc_consistent(adapter->pdev, extfat_cmd.size, - &extfat_cmd.dma); - - if (!extfat_cmd.va) { - dev_err(&adapter->pdev->dev, "%s: Memory allocation failure\n", - __func__); - goto err; - } - - status = be_cmd_get_ext_fat_capabilites(adapter, &extfat_cmd); - if (!status) { - cfgs = (struct be_fat_conf_params *)(extfat_cmd.va + - sizeof(struct be_cmd_resp_hdr)); - for (j = 0; j < le32_to_cpu(cfgs->module[0].num_modes); j++) { - if (cfgs->module[0].trace_lvl[j].mode == MODE_UART) - level = cfgs->module[0].trace_lvl[j].dbg_lvl; - } - } - pci_free_consistent(adapter->pdev, extfat_cmd.size, extfat_cmd.va, - extfat_cmd.dma); -err: - return level; -} - static int be_get_initial_config(struct be_adapter *adapter) { - int status; - u32 level; + int status, level; status = be_cmd_get_cntl_attributes(adapter); if (status) return status; - status = be_cmd_get_acpi_wol_cap(adapter); - if (status) { - /* in case of a failure to get wol capabillities - * check the exclusion list to determine WOL capability */ - if (!be_is_wol_excluded(adapter)) - adapter->wol_cap |= BE_WOL_CAP; - } - - if (be_is_wol_supported(adapter)) - adapter->wol = true; - /* Must be a power of 2 or else MODULO will BUG_ON */ adapter->be_get_temp_freq = 64; - level = be_get_fw_log_level(adapter); - adapter->msg_enable = level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0; + if (BEx_chip(adapter)) { + level = be_cmd_get_fw_log_level(adapter); + adapter->msg_enable = + level <= FW_LOG_LEVEL_DEFAULT ? NETIF_MSG_HW : 0; + } adapter->cfg_num_qs = netif_get_num_default_rss_queues(); return 0; @@ -4618,7 +4557,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdev; - if (adapter->wol) + if (adapter->wol_en) be_setup_wol(adapter, true); be_intr_set(adapter, false); @@ -4674,7 +4613,7 @@ static int be_resume(struct pci_dev *pdev) msecs_to_jiffies(1000)); netif_device_attach(netdev); - if (adapter->wol) + if (adapter->wol_en) be_setup_wol(adapter, false); return 0; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index d3d7ede27ef1..5900dbaec242 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -889,11 +889,9 @@ static int gfar_set_hash_opts(struct gfar_private *priv, static int gfar_check_filer_hardware(struct gfar_private *priv) { - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 i; - regs = priv->gfargrp[0].regs; - /* Check if we are in FIFO mode */ i = gfar_read(®s->ecntrl); i &= ECNTRL_FIFM; @@ -927,7 +925,7 @@ static int gfar_check_filer_hardware(struct gfar_private *priv) /* Sets the properties for arbitrary filer rule * to the first 4 Layer 4 Bytes */ - regs->rbifx = 0xC0C1C2C3; + gfar_write(®s->rbifx, 0xC0C1C2C3); return 0; } @@ -1055,10 +1053,18 @@ static void gfar_set_basic_ip(struct ethtool_tcpip4_spec *value, struct ethtool_tcpip4_spec *mask, struct filer_table *tab) { - gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab); - gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab); - gfar_set_attribute(value->pdst, mask->pdst, RQFCR_PID_DPT, tab); - gfar_set_attribute(value->psrc, mask->psrc, RQFCR_PID_SPT, tab); + gfar_set_attribute(be32_to_cpu(value->ip4src), + be32_to_cpu(mask->ip4src), + RQFCR_PID_SIA, tab); + gfar_set_attribute(be32_to_cpu(value->ip4dst), + be32_to_cpu(mask->ip4dst), + RQFCR_PID_DIA, tab); + gfar_set_attribute(be16_to_cpu(value->pdst), + be16_to_cpu(mask->pdst), + RQFCR_PID_DPT, tab); + gfar_set_attribute(be16_to_cpu(value->psrc), + be16_to_cpu(mask->psrc), + RQFCR_PID_SPT, tab); gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab); } @@ -1067,12 +1073,17 @@ static void gfar_set_user_ip(struct ethtool_usrip4_spec *value, struct ethtool_usrip4_spec *mask, struct filer_table *tab) { - gfar_set_attribute(value->ip4src, mask->ip4src, RQFCR_PID_SIA, tab); - gfar_set_attribute(value->ip4dst, mask->ip4dst, RQFCR_PID_DIA, tab); + gfar_set_attribute(be32_to_cpu(value->ip4src), + be32_to_cpu(mask->ip4src), + RQFCR_PID_SIA, tab); + gfar_set_attribute(be32_to_cpu(value->ip4dst), + be32_to_cpu(mask->ip4dst), + RQFCR_PID_DIA, tab); gfar_set_attribute(value->tos, mask->tos, RQFCR_PID_TOS, tab); gfar_set_attribute(value->proto, mask->proto, RQFCR_PID_L4P, tab); - gfar_set_attribute(value->l4_4_bytes, mask->l4_4_bytes, RQFCR_PID_ARB, - tab); + gfar_set_attribute(be32_to_cpu(value->l4_4_bytes), + be32_to_cpu(mask->l4_4_bytes), + RQFCR_PID_ARB, tab); } @@ -1139,7 +1150,41 @@ static void gfar_set_ether(struct ethhdr *value, struct ethhdr *mask, } } - gfar_set_attribute(value->h_proto, mask->h_proto, RQFCR_PID_ETY, tab); + gfar_set_attribute(be16_to_cpu(value->h_proto), + be16_to_cpu(mask->h_proto), + RQFCR_PID_ETY, tab); +} + +static inline u32 vlan_tci_vid(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_VID_MASK; +} + +static inline u32 vlan_tci_vidm(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_VID_MASK; +} + +static inline u32 vlan_tci_cfi(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_CFI_MASK; +} + +static inline u32 vlan_tci_cfim(struct ethtool_rx_flow_spec *rule) +{ + return be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_CFI_MASK; +} + +static inline u32 vlan_tci_prio(struct ethtool_rx_flow_spec *rule) +{ + return (be16_to_cpu(rule->h_ext.vlan_tci) & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; +} + +static inline u32 vlan_tci_priom(struct ethtool_rx_flow_spec *rule) +{ + return (be16_to_cpu(rule->m_ext.vlan_tci) & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; } /* Convert a rule to binary filter format of gianfar */ @@ -1153,22 +1198,21 @@ static int gfar_convert_to_filer(struct ethtool_rx_flow_spec *rule, u32 old_index = tab->index; /* Check if vlan is wanted */ - if ((rule->flow_type & FLOW_EXT) && (rule->m_ext.vlan_tci != 0xFFFF)) { + if ((rule->flow_type & FLOW_EXT) && + (rule->m_ext.vlan_tci != cpu_to_be16(0xFFFF))) { if (!rule->m_ext.vlan_tci) - rule->m_ext.vlan_tci = 0xFFFF; + rule->m_ext.vlan_tci = cpu_to_be16(0xFFFF); vlan = RQFPR_VLN; vlan_mask = RQFPR_VLN; /* Separate the fields */ - id = rule->h_ext.vlan_tci & VLAN_VID_MASK; - id_mask = rule->m_ext.vlan_tci & VLAN_VID_MASK; - cfi = rule->h_ext.vlan_tci & VLAN_CFI_MASK; - cfi_mask = rule->m_ext.vlan_tci & VLAN_CFI_MASK; - prio = (rule->h_ext.vlan_tci & VLAN_PRIO_MASK) >> - VLAN_PRIO_SHIFT; - prio_mask = (rule->m_ext.vlan_tci & VLAN_PRIO_MASK) >> - VLAN_PRIO_SHIFT; + id = vlan_tci_vid(rule); + id_mask = vlan_tci_vidm(rule); + cfi = vlan_tci_cfi(rule); + cfi_mask = vlan_tci_cfim(rule); + prio = vlan_tci_prio(rule); + prio_mask = vlan_tci_priom(rule); if (cfi == VLAN_TAG_PRESENT && cfi_mask == VLAN_TAG_PRESENT) { vlan |= RQFPR_CFI; @@ -1666,10 +1710,10 @@ static void gfar_invert_masks(struct ethtool_rx_flow_spec *flow) for (i = 0; i < sizeof(flow->m_u); i++) flow->m_u.hdata[i] ^= 0xFF; - flow->m_ext.vlan_etype ^= 0xFFFF; - flow->m_ext.vlan_tci ^= 0xFFFF; - flow->m_ext.data[0] ^= ~0; - flow->m_ext.data[1] ^= ~0; + flow->m_ext.vlan_etype ^= cpu_to_be16(0xFFFF); + flow->m_ext.vlan_tci ^= cpu_to_be16(0xFFFF); + flow->m_ext.data[0] ^= cpu_to_be32(~0); + flow->m_ext.data[1] ^= cpu_to_be32(~0); } static int gfar_add_cls(struct gfar_private *priv, diff --git a/drivers/net/ethernet/freescale/gianfar_ptp.c b/drivers/net/ethernet/freescale/gianfar_ptp.c index e006a09ba899..6ba2fd44dbd7 100644 --- a/drivers/net/ethernet/freescale/gianfar_ptp.c +++ b/drivers/net/ethernet/freescale/gianfar_ptp.c @@ -134,7 +134,7 @@ struct gianfar_ptp_registers { #define REG_SIZE sizeof(struct gianfar_ptp_registers) struct etsects { - struct gianfar_ptp_registers *regs; + struct gianfar_ptp_registers __iomem *regs; spinlock_t lock; /* protects regs */ struct ptp_clock *clock; struct ptp_clock_info caps; diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig index 9fb2eb8cf152..333bb54d0bdf 100644 --- a/drivers/net/ethernet/intel/Kconfig +++ b/drivers/net/ethernet/intel/Kconfig @@ -243,6 +243,7 @@ config IXGBEVF config I40E tristate "Intel(R) Ethernet Controller XL710 Family support" + select PTP_1588_CLOCK depends on PCI ---help--- This driver supports Intel(R) Ethernet Controller XL710 Family of diff --git a/drivers/net/ethernet/intel/i40e/Makefile b/drivers/net/ethernet/intel/i40e/Makefile index 6ec1a795f184..e4d2e27078a7 100644 --- a/drivers/net/ethernet/intel/i40e/Makefile +++ b/drivers/net/ethernet/intel/i40e/Makefile @@ -40,4 +40,5 @@ i40e-objs := i40e_main.o \ i40e_debugfs.o \ i40e_diag.o \ i40e_txrx.o \ + i40e_ptp.o \ i40e_virtchnl_pf.o diff --git a/drivers/net/ethernet/intel/i40e/Module.symvers b/drivers/net/ethernet/intel/i40e/Module.symvers new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/Module.symvers diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 4d4cdbf6fad7..91b00523d3d4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -50,6 +50,9 @@ #include <net/ip6_checksum.h> #include <linux/ethtool.h> #include <linux/if_vlan.h> +#include <linux/clocksource.h> +#include <linux/net_tstamp.h> +#include <linux/ptp_clock_kernel.h> #include "i40e_type.h" #include "i40e_prototype.h" #include "i40e_virtchnl.h" @@ -88,8 +91,7 @@ /* The values in here are decimal coded as hex as is the case in the NVM map*/ #define I40E_CURRENT_NVM_VERSION_HI 0x2 -#define I40E_CURRENT_NVM_VERSION_LO 0x1 - +#define I40E_CURRENT_NVM_VERSION_LO 0x30 /* magic for getting defines into strings */ #define STRINGIFY(foo) #foo @@ -242,6 +244,7 @@ struct i40e_pf { #define I40E_FLAG_DCB_ENABLED (u64)(1 << 20) #define I40E_FLAG_FDIR_ENABLED (u64)(1 << 21) #define I40E_FLAG_FDIR_ATR_ENABLED (u64)(1 << 22) +#define I40E_FLAG_PTP (u64)(1 << 25) #define I40E_FLAG_MFP_ENABLED (u64)(1 << 26) #ifdef CONFIG_I40E_VXLAN #define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) @@ -302,6 +305,20 @@ struct i40e_pf { u32 fcoe_hmc_filt_num; u32 fcoe_hmc_cntx_num; struct i40e_filter_control_settings filter_settings; + + struct ptp_clock *ptp_clock; + struct ptp_clock_info ptp_caps; + struct sk_buff *ptp_tx_skb; + struct work_struct ptp_tx_work; + struct hwtstamp_config tstamp_config; + unsigned long ptp_tx_start; + unsigned long last_rx_ptp_check; + spinlock_t tmreg_lock; /* Used to protect the device time registers. */ + u64 ptp_base_adj; + u32 tx_hwtstamp_timeouts; + u32 rx_hwtstamp_cleared; + bool ptp_tx; + bool ptp_rx; }; struct i40e_mac_filter { @@ -566,4 +583,12 @@ struct i40e_mac_filter *i40e_find_mac(struct i40e_vsi *vsi, u8 *macaddr, bool is_vf, bool is_netdev); void i40e_vlan_stripping_enable(struct i40e_vsi *vsi); +void i40e_ptp_rx_hang(struct i40e_vsi *vsi); +void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf); +void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index); +void i40e_ptp_set_increment(struct i40e_pf *pf); +int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr); +int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr); +void i40e_ptp_init(struct i40e_pf *pf); +void i40e_ptp_stop(struct i40e_pf *pf); #endif /* _I40E_H_ */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index c75aa2d07491..a50e6b3479ae 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -128,7 +128,7 @@ static void i40e_free_adminq_arq(struct i40e_hw *hw) /** * i40e_alloc_arq_bufs - Allocate pre-posted buffers for the receive queue - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure **/ static i40e_status i40e_alloc_arq_bufs(struct i40e_hw *hw) { @@ -195,7 +195,7 @@ unwind_alloc_arq_bufs: /** * i40e_alloc_asq_bufs - Allocate empty buffer structs for the send queue - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure **/ static i40e_status i40e_alloc_asq_bufs(struct i40e_hw *hw) { @@ -235,7 +235,7 @@ unwind_alloc_asq_bufs: /** * i40e_free_arq_bufs - Free receive queue buffer info elements - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure **/ static void i40e_free_arq_bufs(struct i40e_hw *hw) { @@ -254,7 +254,7 @@ static void i40e_free_arq_bufs(struct i40e_hw *hw) /** * i40e_free_asq_bufs - Free send queue buffer info elements - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure **/ static void i40e_free_asq_bufs(struct i40e_hw *hw) { @@ -277,7 +277,7 @@ static void i40e_free_asq_bufs(struct i40e_hw *hw) /** * i40e_config_asq_regs - configure ASQ registers - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * Configure base address and length registers for the transmit queue **/ @@ -304,7 +304,7 @@ static void i40e_config_asq_regs(struct i40e_hw *hw) /** * i40e_config_arq_regs - ARQ register configuration - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * Configure base address and length registers for the receive (event queue) **/ @@ -334,7 +334,7 @@ static void i40e_config_arq_regs(struct i40e_hw *hw) /** * i40e_init_asq - main initialization routine for ASQ - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * This is the main initialization routine for the Admin Send Queue * Prior to calling this function, drivers *MUST* set the following fields @@ -391,7 +391,7 @@ init_adminq_exit: /** * i40e_init_arq - initialize ARQ - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * The main initialization routine for the Admin Receive (Event) Queue. * Prior to calling this function, drivers *MUST* set the following fields @@ -448,7 +448,7 @@ init_adminq_exit: /** * i40e_shutdown_asq - shutdown the ASQ - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * The main shutdown routine for the Admin Send Queue **/ @@ -479,7 +479,7 @@ static i40e_status i40e_shutdown_asq(struct i40e_hw *hw) /** * i40e_shutdown_arq - shutdown ARQ - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * The main shutdown routine for the Admin Receive Queue **/ @@ -510,7 +510,7 @@ static i40e_status i40e_shutdown_arq(struct i40e_hw *hw) /** * i40e_init_adminq - main initialization routine for Admin Queue - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure * * Prior to calling this function, drivers *MUST* set the following fields * in the hw->aq structure: @@ -607,7 +607,7 @@ init_adminq_exit: /** * i40e_shutdown_adminq - shutdown routine for the Admin Queue - * @hw: pointer to the hardware structure + * @hw: pointer to the hardware structure **/ i40e_status i40e_shutdown_adminq(struct i40e_hw *hw) { @@ -626,7 +626,7 @@ i40e_status i40e_shutdown_adminq(struct i40e_hw *hw) /** * i40e_clean_asq - cleans Admin send queue - * @asq: pointer to the adminq send ring + * @hw: pointer to the hardware structure * * returns the number of free desc **/ @@ -922,7 +922,7 @@ i40e_status i40e_clean_arq_element(struct i40e_hw *hw, "AQRX: Event received with error 0x%X.\n", hw->aq.arq_last_status); } else { - memcpy(&e->desc, desc, sizeof(struct i40e_aq_desc)); + e->desc = *desc; datalen = le16_to_cpu(desc->datalen); e->msg_size = min(datalen, e->msg_size); if (e->msg_buf != NULL && (e->msg_size != 0)) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index c009eb47058a..be61a474fd84 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -1195,8 +1195,8 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { } v4; struct { u8 data[16]; - } v6; - } ipaddr; + } v6; + } ipaddr; __le16 flags; #define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0 #define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \ diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 807312bb62a2..aedc71b6f3f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -74,7 +74,8 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw) /** * i40e_debug_aq * @hw: debug mask related to admin queue - * @cap: pointer to adminq command descriptor + * @mask: debug mask + * @desc: pointer to admin queue descriptor * @buffer: pointer to command buffer * * Dumps debug log about adminq command with descriptor contents. @@ -161,7 +162,6 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, return status; } - /** * i40e_init_shared_code - Initialize the shared code * @hw: pointer to hardware structure @@ -599,8 +599,7 @@ i40e_status i40e_aq_get_link_info(struct i40e_hw *hw, goto aq_get_link_info_exit; /* save off old link status information */ - memcpy(&hw->phy.link_info_old, hw_link_info, - sizeof(struct i40e_link_status)); + hw->phy.link_info_old = *hw_link_info; /* update link status */ hw_link_info->phy_type = (enum i40e_aq_phy_type)resp->phy_type; @@ -630,7 +629,7 @@ aq_get_link_info_exit: /** * i40e_aq_add_vsi * @hw: pointer to the hw struct - * @vsi: pointer to a vsi context struct + * @vsi_ctx: pointer to a vsi context struct * @cmd_details: pointer to command details structure or NULL * * Add a VSI context to the hardware. @@ -682,7 +681,8 @@ aq_add_vsi_exit: * @cmd_details: pointer to command details structure or NULL **/ i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw, - u16 seid, bool set, struct i40e_asq_cmd_details *cmd_details) + u16 seid, bool set, + struct i40e_asq_cmd_details *cmd_details) { struct i40e_aq_desc desc; struct i40e_aqc_set_vsi_promiscuous_modes *cmd = @@ -776,7 +776,7 @@ i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw, /** * i40e_get_vsi_params - get VSI configuration info * @hw: pointer to the hw struct - * @vsi: pointer to a vsi context struct + * @vsi_ctx: pointer to a vsi context struct * @cmd_details: pointer to command details structure or NULL **/ i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw, @@ -818,7 +818,7 @@ aq_get_vsi_params_exit: /** * i40e_aq_update_vsi_params * @hw: pointer to the hw struct - * @vsi: pointer to a vsi context struct + * @vsi_ctx: pointer to a vsi context struct * @cmd_details: pointer to command details structure or NULL * * Update a VSI context. @@ -921,7 +921,6 @@ i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw, /** * i40e_aq_send_driver_version * @hw: pointer to the hw struct - * @event: driver event: driver ok, start or stop * @dv: driver's major, minor version * @cmd_details: pointer to command details structure or NULL * @@ -1039,10 +1038,10 @@ i40e_status i40e_aq_add_veb(struct i40e_hw *hw, u16 uplink_seid, * @hw: pointer to the hw struct * @veb_seid: the SEID of the VEB to query * @switch_id: the uplink switch id - * @floating_veb: set to true if the VEB is floating + * @floating: set to true if the VEB is floating * @statistic_index: index of the stats counter block for this VEB * @vebs_used: number of VEB's used by function - * @vebs_unallocated: total VEB's not reserved by any function + * @vebs_free: total VEB's not reserved by any function * @cmd_details: pointer to command details structure or NULL * * This retrieves the parameters for a particular VEB, specified by @@ -1179,6 +1178,8 @@ i40e_status i40e_aq_remove_macvlan(struct i40e_hw *hw, u16 seid, * i40e_aq_send_msg_to_vf * @hw: pointer to the hardware structure * @vfid: vf id to send msg + * @v_opcode: opcodes for VF-PF communication + * @v_retval: return error code * @msg: pointer to the msg buffer * @msglen: msg length * @cmd_details: pointer to command details @@ -1723,6 +1724,7 @@ i40e_status i40e_aq_start_lldp(struct i40e_hw *hw, * @udp_port: the UDP port to add * @header_len: length of the tunneling header length in DWords * @protocol_index: protocol index type + * @filter_index: pointer to filter index * @cmd_details: pointer to command details structure or NULL **/ i40e_status i40e_aq_add_udp_tunnel(struct i40e_hw *hw, diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index 0220b18b2b18..36a5cc89bf0b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1083,7 +1083,7 @@ static ssize_t i40e_dbg_command_write(struct file *filp, vsi = i40e_dbg_find_vsi(pf, vsi_seid); if (!vsi) { dev_info(&pf->pdev->dev, - "add relay: vsi VSI %d not found\n", vsi_seid); + "add relay: VSI %d not found\n", vsi_seid); goto command_write_done; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b886ee5bd99d..7b87d5115816 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -108,6 +108,8 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("rx_oversize", stats.rx_oversize), I40E_PF_STAT("rx_jabber", stats.rx_jabber), I40E_PF_STAT("VF_admin_queue_requests", vf_aq_requests), + I40E_PF_STAT("tx_hwtstamp_timeouts", tx_hwtstamp_timeouts), + I40E_PF_STAT("rx_hwtstamp_cleared", rx_hwtstamp_cleared), }; #define I40E_QUEUE_STATS_LEN(n) \ @@ -748,7 +750,36 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, static int i40e_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { - return ethtool_op_get_ts_info(dev, info); + struct i40e_pf *pf = i40e_netdev_to_pf(dev); + + info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE | + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE | + SOF_TIMESTAMPING_TX_HARDWARE | + SOF_TIMESTAMPING_RX_HARDWARE | + SOF_TIMESTAMPING_RAW_HARDWARE; + + if (pf->ptp_clock) + info->phc_index = ptp_clock_index(pf->ptp_clock); + else + info->phc_index = -1; + + info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + + info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | + (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | + (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); + + return 0; } static int i40e_link_test(struct net_device *netdev, u64 *data) @@ -1634,7 +1665,7 @@ static int i40e_set_channels(struct net_device *dev, * class queue mapping */ new_count = i40e_reconfig_rss_queues(pf, count); - if (new_count > 1) + if (new_count > 0) return 0; else return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c index 76dfef3e0104..bf2d4cc5b569 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c @@ -89,11 +89,9 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, sd_entry->u.pd_table.pd_entry = (struct i40e_hmc_pd_entry *) sd_entry->u.pd_table.pd_entry_virt_mem.va; - memcpy(&sd_entry->u.pd_table.pd_page_addr, &mem, - sizeof(struct i40e_dma_mem)); + sd_entry->u.pd_table.pd_page_addr = mem; } else { - memcpy(&sd_entry->u.bp.addr, &mem, - sizeof(struct i40e_dma_mem)); + sd_entry->u.bp.addr = mem; sd_entry->u.bp.sd_pd_index = sd_index; } /* initialize the sd entry */ @@ -164,7 +162,7 @@ i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, if (ret_code) goto exit; - memcpy(&pd_entry->bp.addr, &mem, sizeof(struct i40e_dma_mem)); + pd_entry->bp.addr = mem; pd_entry->bp.sd_pd_index = pd_index; pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; /* Set page address and valid bit */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index 72bf30aba150..0cd4701234f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -116,7 +116,6 @@ struct i40e_hmc_info { * @hw: pointer to our hw struct * @pa: pointer to physical address * @sd_index: segment descriptor index - * @hmc_fn_id: hmc function id * @type: if sd entry is direct or paged **/ #define I40E_SET_PF_SD_ENTRY(hw, pa, sd_index, type) \ @@ -138,7 +137,6 @@ struct i40e_hmc_info { * I40E_CLEAR_PF_SD_ENTRY - marks the sd entry as invalid in the hardware * @hw: pointer to our hw struct * @sd_index: segment descriptor index - * @hmc_fn_id: hmc function id * @type: if sd entry is direct or paged **/ #define I40E_CLEAR_PF_SD_ENTRY(hw, sd_index, type) \ @@ -159,7 +157,6 @@ struct i40e_hmc_info { * @hw: pointer to our hw struct * @sd_idx: segment descriptor index * @pd_idx: page descriptor index - * @hmc_fn_id: hmc function id **/ #define I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, pd_idx) \ wr32((hw), I40E_PFHMC_PDINV, \ diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 101ed4107312..d5d98fe2691d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -485,8 +485,7 @@ i40e_status i40e_configure_lan_hmc(struct i40e_hw *hw, /* Make one big object, a single SD */ info.count = 1; ret_code = i40e_create_lan_hmc_object(hw, &info); - if ((ret_code) && - (model == I40E_HMC_MODEL_DIRECT_PREFERRED)) + if (ret_code && (model == I40E_HMC_MODEL_DIRECT_PREFERRED)) goto try_type_paged; else if (ret_code) goto configure_lan_hmc_out; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 1b792ee592d0..7bfa78967276 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -38,7 +38,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 0 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 25 +#define DRV_VERSION_BUILD 30 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN @@ -356,7 +356,6 @@ static struct rtnl_link_stats64 *i40e_get_netdev_stats_struct( struct rtnl_link_stats64 *vsi_stats = i40e_get_vsi_stats_struct(vsi); int i; - if (test_bit(__I40E_DOWN, &vsi->state)) return stats; @@ -1698,6 +1697,27 @@ static int i40e_change_mtu(struct net_device *netdev, int new_mtu) } /** + * i40e_ioctl - Access the hwtstamp interface + * @netdev: network interface device structure + * @ifr: interface request data + * @cmd: ioctl command + **/ +int i40e_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) +{ + struct i40e_netdev_priv *np = netdev_priv(netdev); + struct i40e_pf *pf = np->vsi->back; + + switch (cmd) { + case SIOCGHWTSTAMP: + return i40e_ptp_get_ts_config(pf, ifr); + case SIOCSHWTSTAMP: + return i40e_ptp_set_ts_config(pf, ifr); + default: + return -EOPNOTSUPP; + } +} + +/** * i40e_vlan_stripping_enable - Turn on vlan stripping for the VSI * @vsi: the vsi being adjusted **/ @@ -1824,7 +1844,10 @@ int i40e_vsi_add_vlan(struct i40e_vsi *vsi, s16 vid) return -ENOMEM; } } + } + /* Do not assume that I40E_VLAN_ANY should be reset to VLAN 0 */ + if (vid > 0 && !vsi->info.pvid) { list_for_each_entry(f, &vsi->mac_filter_list, list) { if (i40e_find_filter(vsi, f->macaddr, I40E_VLAN_ANY, is_vf, is_netdev)) { @@ -2150,7 +2173,8 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) tx_ctx.base = (ring->dma / 128); tx_ctx.qlen = ring->count; tx_ctx.fd_ena = !!(vsi->back->flags & (I40E_FLAG_FDIR_ENABLED | - I40E_FLAG_FDIR_ATR_ENABLED)); + I40E_FLAG_FDIR_ATR_ENABLED)); + tx_ctx.timesync_ena = !!(vsi->back->flags & I40E_FLAG_PTP); /* As part of VSI creation/update, FW allocates certain * Tx arbitration queue sets for each TC enabled for @@ -2184,7 +2208,10 @@ static int i40e_configure_tx_ring(struct i40e_ring *ring) } /* Now associate this queue with this PCI function */ - qtx_ctl = I40E_QTX_CTL_PF_QUEUE; + if (vsi->type == I40E_VSI_VMDQ2) + qtx_ctl = I40E_QTX_CTL_VM_QUEUE; + else + qtx_ctl = I40E_QTX_CTL_PF_QUEUE; qtx_ctl |= ((hw->pf_id << I40E_QTX_CTL_PF_INDX_SHIFT) & I40E_QTX_CTL_PF_INDX_MASK); wr32(hw, I40E_QTX_CTL(pf_q), qtx_ctl); @@ -2488,6 +2515,7 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw) I40E_PFINT_ICR0_ENA_GRST_MASK | I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK | I40E_PFINT_ICR0_ENA_GPIO_MASK | + I40E_PFINT_ICR0_ENA_TIMESYNC_MASK | I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK | I40E_PFINT_ICR0_ENA_HMC_ERR_MASK | I40E_PFINT_ICR0_ENA_VFLR_MASK | @@ -2831,6 +2859,18 @@ static irqreturn_t i40e_intr(int irq, void *data) dev_info(&pf->pdev->dev, "HMC error interrupt\n"); } + if (icr0 & I40E_PFINT_ICR0_TIMESYNC_MASK) { + u32 prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_0); + + if (prttsyn_stat & I40E_PRTTSYN_STAT_0_TXTIME_MASK) { + ena_mask &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; + i40e_ptp_tx_hwtstamp(pf); + prttsyn_stat &= ~I40E_PRTTSYN_STAT_0_TXTIME_MASK; + } + + wr32(hw, I40E_PRTTSYN_STAT_0, prttsyn_stat); + } + /* If a critical error is pending we have no choice but to reset the * device. * Report and mask out any remaining unexpected interrupts. @@ -3008,11 +3048,13 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) continue; /* turn on/off the queue */ - if (enable) + if (enable) { + wr32(hw, I40E_QTX_HEAD(pf_q), 0); tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK | I40E_QTX_ENA_QENA_STAT_MASK; - else + } else { tx_reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; + } wr32(hw, I40E_QTX_ENA(pf_q), tx_reg); @@ -3113,7 +3155,7 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) **/ int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request) { - int ret; + int ret = 0; /* do rx first for enable and last for disable */ if (request) { @@ -3122,10 +3164,9 @@ int i40e_vsi_control_rings(struct i40e_vsi *vsi, bool request) return ret; ret = i40e_vsi_control_tx(vsi, request); } else { - ret = i40e_vsi_control_tx(vsi, request); - if (ret) - return ret; - ret = i40e_vsi_control_rx(vsi, request); + /* Ignore return value, we need to shutdown whatever we can */ + i40e_vsi_control_tx(vsi, request); + i40e_vsi_control_rx(vsi, request); } return ret; @@ -3564,7 +3605,7 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi) /* Get the VSI level BW configuration per TC */ aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config, - NULL); + NULL); if (aq_ret) { dev_info(&pf->pdev->dev, "couldn't get pf vsi ets bw config, err %d, aq_err %d\n", @@ -4303,6 +4344,9 @@ static void i40e_link_event(struct i40e_pf *pf) if (pf->vf) i40e_vc_notify_link_state(pf); + + if (pf->flags & I40E_FLAG_PTP) + i40e_ptp_set_increment(pf); } /** @@ -4384,6 +4428,8 @@ static void i40e_watchdog_subtask(struct i40e_pf *pf) for (i = 0; i < I40E_MAX_VEB; i++) if (pf->veb[i]) i40e_update_veb_stats(pf->veb[i]); + + i40e_ptp_rx_hang(pf->vsi[pf->lan_vsi]); } /** @@ -6032,6 +6078,7 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = i40e_set_mac, .ndo_change_mtu = i40e_change_mtu, + .ndo_do_ioctl = i40e_ioctl, .ndo_tx_timeout = i40e_tx_timeout, .ndo_vlan_rx_add_vid = i40e_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = i40e_vlan_rx_kill_vid, @@ -7298,6 +7345,8 @@ no_autoneg: ~I40E_PRTDCB_MFLCN_RFCE_MASK); fc_complete: + i40e_ptp_init(pf); + return ret; } @@ -7611,6 +7660,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_pf_reset; } + i40e_clear_pxe_mode(hw); err = i40e_get_capabilities(pf); if (err) goto err_adminq_setup; @@ -7801,6 +7851,8 @@ static void i40e_remove(struct pci_dev *pdev) i40e_dbg_pf_exit(pf); + i40e_ptp_stop(pf); + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { i40e_free_vfs(pf); pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 37d66c87abc9..e12bf07fd23d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -244,6 +244,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, /** * i40e_calc_nvm_checksum - Calculates and returns the checksum * @hw: pointer to hardware structure + * @checksum: pointer to the checksum * * This function calculate SW Checksum that covers the whole 64kB shadow RAM * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index c7c3d8231b36..f8c53a6ec580 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -93,9 +93,9 @@ i40e_status i40e_aq_set_vsi_broadcast(struct i40e_hw *hw, u16 vsi_id, bool set_filter, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_vsi_unicast_promiscuous(struct i40e_hw *hw, - u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details); + u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_set_vsi_multicast_promiscuous(struct i40e_hw *hw, - u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details); + u16 vsi_id, bool set, struct i40e_asq_cmd_details *cmd_details); i40e_status i40e_aq_get_vsi_params(struct i40e_hw *hw, struct i40e_vsi_context *vsi_ctx, struct i40e_asq_cmd_details *cmd_details); diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c new file mode 100644 index 000000000000..e33ec6c842b7 --- /dev/null +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -0,0 +1,662 @@ +/******************************************************************************* + * + * Intel Ethernet Controller XL710 Family Linux Driver + * Copyright(c) 2013 - 2014 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. If not, see <http://www.gnu.org/licenses/>. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + ******************************************************************************/ + +#include "i40e.h" +#include <linux/export.h> +#include <linux/ptp_classify.h> + +/* The XL710 timesync is very much like Intel's 82599 design when it comes to + * the fundamental clock design. However, the clock operations are much simpler + * in the XL710 because the device supports a full 64 bits of nanoseconds. + * Because the field is so wide, we can forgo the cycle counter and just + * operate with the nanosecond field directly without fear of overflow. + * + * Much like the 82599, the update period is dependent upon the link speed: + * At 40Gb link or no link, the period is 1.6ns. + * At 10Gb link, the period is multiplied by 2. (3.2ns) + * At 1Gb link, the period is multiplied by 20. (32ns) + * 1588 functionality is not supported at 100Mbps. + */ +#define I40E_PTP_40GB_INCVAL 0x0199999999ULL +#define I40E_PTP_10GB_INCVAL 0x0333333333ULL +#define I40E_PTP_1GB_INCVAL 0x2000000000ULL + +#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 (0x1 << \ + I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) +#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (0x2 << \ + I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) +#define I40E_PTP_TX_TIMEOUT (HZ * 15) + +/** + * i40e_ptp_read - Read the PHC time from the device + * @pf: Board private structure + * @ts: timespec structure to hold the current time value + * + * This function reads the PRTTSYN_TIME registers and stores them in a + * timespec. However, since the registers are 64 bits of nanoseconds, we must + * convert the result to a timespec before we can return. + **/ +static void i40e_ptp_read(struct i40e_pf *pf, struct timespec *ts) +{ + struct i40e_hw *hw = &pf->hw; + u32 hi, lo; + u64 ns; + + /* The timer latches on the lowest register read. */ + lo = rd32(hw, I40E_PRTTSYN_TIME_L); + hi = rd32(hw, I40E_PRTTSYN_TIME_H); + + ns = (((u64)hi) << 32) | lo; + + *ts = ns_to_timespec(ns); +} + +/** + * i40e_ptp_write - Write the PHC time to the device + * @pf: Board private structure + * @ts: timespec structure that holds the new time value + * + * This function writes the PRTTSYN_TIME registers with the user value. Since + * we receive a timespec from the stack, we must convert that timespec into + * nanoseconds before programming the registers. + **/ +static void i40e_ptp_write(struct i40e_pf *pf, const struct timespec *ts) +{ + struct i40e_hw *hw = &pf->hw; + u64 ns = timespec_to_ns(ts); + + /* The timer will not update until the high register is written, so + * write the low register first. + */ + wr32(hw, I40E_PRTTSYN_TIME_L, ns & 0xFFFFFFFF); + wr32(hw, I40E_PRTTSYN_TIME_H, ns >> 32); +} + +/** + * i40e_ptp_convert_to_hwtstamp - Convert device clock to system time + * @hwtstamps: Timestamp structure to update + * @timestamp: Timestamp from the hardware + * + * We need to convert the NIC clock value into a hwtstamp which can be used by + * the upper level timestamping functions. Since the timestamp is simply a 64- + * bit nanosecond value, we can call ns_to_ktime directly to handle this. + **/ +static void i40e_ptp_convert_to_hwtstamp(struct skb_shared_hwtstamps *hwtstamps, + u64 timestamp) +{ + memset(hwtstamps, 0, sizeof(*hwtstamps)); + + hwtstamps->hwtstamp = ns_to_ktime(timestamp); +} + +/** + * i40e_ptp_adjfreq - Adjust the PHC frequency + * @ptp: The PTP clock structure + * @ppb: Parts per billion adjustment from the base + * + * Adjust the frequency of the PHC by the indicated parts per billion from the + * base frequency. + **/ +static int i40e_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb) +{ + struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); + struct i40e_hw *hw = &pf->hw; + u64 adj, freq, diff; + int neg_adj = 0; + + if (ppb < 0) { + neg_adj = 1; + ppb = -ppb; + } + + smp_mb(); /* Force any pending update before accessing. */ + adj = ACCESS_ONCE(pf->ptp_base_adj); + + freq = adj; + freq *= ppb; + diff = div_u64(freq, 1000000000ULL); + + if (neg_adj) + adj -= diff; + else + adj += diff; + + wr32(hw, I40E_PRTTSYN_INC_L, adj & 0xFFFFFFFF); + wr32(hw, I40E_PRTTSYN_INC_H, adj >> 32); + + return 0; +} + +/** + * i40e_ptp_adjtime - Adjust the PHC time + * @ptp: The PTP clock structure + * @delta: Offset in nanoseconds to adjust the PHC time by + * + * Adjust the frequency of the PHC by the indicated parts per billion from the + * base frequency. + **/ +static int i40e_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); + struct timespec now, then = ns_to_timespec(delta); + unsigned long flags; + + spin_lock_irqsave(&pf->tmreg_lock, flags); + + i40e_ptp_read(pf, &now); + now = timespec_add(now, then); + i40e_ptp_write(pf, (const struct timespec *)&now); + + spin_unlock_irqrestore(&pf->tmreg_lock, flags); + + return 0; +} + +/** + * i40e_ptp_gettime - Get the time of the PHC + * @ptp: The PTP clock structure + * @ts: timespec structure to hold the current time value + * + * Read the device clock and return the correct value on ns, after converting it + * into a timespec struct. + **/ +static int i40e_ptp_gettime(struct ptp_clock_info *ptp, struct timespec *ts) +{ + struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); + unsigned long flags; + + spin_lock_irqsave(&pf->tmreg_lock, flags); + i40e_ptp_read(pf, ts); + spin_unlock_irqrestore(&pf->tmreg_lock, flags); + + return 0; +} + +/** + * i40e_ptp_settime - Set the time of the PHC + * @ptp: The PTP clock structure + * @ts: timespec structure that holds the new time value + * + * Set the device clock to the user input value. The conversion from timespec + * to ns happens in the write function. + **/ +static int i40e_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec *ts) +{ + struct i40e_pf *pf = container_of(ptp, struct i40e_pf, ptp_caps); + unsigned long flags; + + spin_lock_irqsave(&pf->tmreg_lock, flags); + i40e_ptp_write(pf, ts); + spin_unlock_irqrestore(&pf->tmreg_lock, flags); + + return 0; +} + +/** + * i40e_ptp_tx_work + * @work: pointer to work struct + * + * This work function polls the PRTTSYN_STAT_0.TXTIME bit to determine when a + * Tx timestamp event has occurred, in order to pass the Tx timestamp value up + * the stack in the skb. + */ +static void i40e_ptp_tx_work(struct work_struct *work) +{ + struct i40e_pf *pf = container_of(work, struct i40e_pf, + ptp_tx_work); + struct i40e_hw *hw = &pf->hw; + u32 prttsyn_stat_0; + + if (!pf->ptp_tx_skb) + return; + + if (time_is_before_jiffies(pf->ptp_tx_start + + I40E_PTP_TX_TIMEOUT)) { + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; + pf->tx_hwtstamp_timeouts++; + dev_warn(&pf->pdev->dev, "clearing Tx timestamp hang"); + return; + } + + prttsyn_stat_0 = rd32(hw, I40E_PRTTSYN_STAT_0); + if (prttsyn_stat_0 & I40E_PRTTSYN_STAT_0_TXTIME_MASK) + i40e_ptp_tx_hwtstamp(pf); + else + schedule_work(&pf->ptp_tx_work); +} + +/** + * i40e_ptp_enable - Enable/disable ancillary features of the PHC subsystem + * @ptp: The PTP clock structure + * @rq: The requested feature to change + * @on: Enable/disable flag + * + * The XL710 does not support any of the ancillary features of the PHC + * subsystem, so this function may just return. + **/ +static int i40e_ptp_enable(struct ptp_clock_info *ptp, + struct ptp_clock_request *rq, int on) +{ + return -EOPNOTSUPP; +} + +/** + * i40e_ptp_rx_hang - Detect error case when Rx timestamp registers are hung + * @vsi: The VSI with the rings relevant to 1588 + * + * This watchdog task is scheduled to detect error case where hardware has + * dropped an Rx packet that was timestamped when the ring is full. The + * particular error is rare but leaves the device in a state unable to timestamp + * any future packets. + **/ +void i40e_ptp_rx_hang(struct i40e_vsi *vsi) +{ + struct i40e_pf *pf = vsi->back; + struct i40e_hw *hw = &pf->hw; + struct i40e_ring *rx_ring; + unsigned long rx_event; + u32 prttsyn_stat; + int n; + + if (pf->flags & I40E_FLAG_PTP) + return; + + prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); + + /* Unless all four receive timestamp registers are latched, we are not + * concerned about a possible PTP Rx hang, so just update the timeout + * counter and exit. + */ + if (!(prttsyn_stat & ((I40E_PRTTSYN_STAT_1_RXT0_MASK << + I40E_PRTTSYN_STAT_1_RXT0_SHIFT) | + (I40E_PRTTSYN_STAT_1_RXT1_MASK << + I40E_PRTTSYN_STAT_1_RXT1_SHIFT) | + (I40E_PRTTSYN_STAT_1_RXT2_MASK << + I40E_PRTTSYN_STAT_1_RXT2_SHIFT) | + (I40E_PRTTSYN_STAT_1_RXT3_MASK << + I40E_PRTTSYN_STAT_1_RXT3_SHIFT)))) { + pf->last_rx_ptp_check = jiffies; + return; + } + + /* Determine the most recent watchdog or rx_timestamp event. */ + rx_event = pf->last_rx_ptp_check; + for (n = 0; n < vsi->num_queue_pairs; n++) { + rx_ring = vsi->rx_rings[n]; + if (time_after(rx_ring->last_rx_timestamp, rx_event)) + rx_event = rx_ring->last_rx_timestamp; + } + + /* Only need to read the high RXSTMP register to clear the lock */ + if (time_is_before_jiffies(rx_event + 5 * HZ)) { + rd32(hw, I40E_PRTTSYN_RXTIME_H(0)); + rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); + rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); + rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); + pf->last_rx_ptp_check = jiffies; + pf->rx_hwtstamp_cleared++; + dev_warn(&vsi->back->pdev->dev, + "%s: clearing Rx timestamp hang", + __func__); + } +} + +/** + * i40e_ptp_tx_hwtstamp - Utility function which returns the Tx timestamp + * @pf: Board private structure + * + * Read the value of the Tx timestamp from the registers, convert it into a + * value consumable by the stack, and store that result into the shhwtstamps + * struct before returning it up the stack. + **/ +void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf) +{ + struct skb_shared_hwtstamps shhwtstamps; + struct i40e_hw *hw = &pf->hw; + u32 hi, lo; + u64 ns; + + lo = rd32(hw, I40E_PRTTSYN_TXTIME_L); + hi = rd32(hw, I40E_PRTTSYN_TXTIME_H); + + ns = (((u64)hi) << 32) | lo; + + i40e_ptp_convert_to_hwtstamp(&shhwtstamps, ns); + skb_tstamp_tx(pf->ptp_tx_skb, &shhwtstamps); + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; +} + +/** + * i40e_ptp_rx_hwtstamp - Utility function which checks for an Rx timestamp + * @pf: Board private structure + * @skb: Particular skb to send timestamp with + * @index: Index into the receive timestamp registers for the timestamp + * + * The XL710 receives a notification in the receive descriptor with an offset + * into the set of RXTIME registers where the timestamp is for that skb. This + * function goes and fetches the receive timestamp from that offset, if a valid + * one exists. The RXTIME registers are in ns, so we must convert the result + * first. + **/ +void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) +{ + u32 prttsyn_stat, hi, lo; + struct i40e_hw *hw; + u64 ns; + + /* Since we cannot turn off the Rx timestamp logic if the device is + * doing Tx timestamping, check if Rx timestamping is configured. + */ + if (!pf->ptp_rx) + return; + + hw = &pf->hw; + + prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); + + if (!(prttsyn_stat & (1 << index))) + return; + + lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index)); + hi = rd32(hw, I40E_PRTTSYN_RXTIME_H(index)); + + ns = (((u64)hi) << 32) | lo; + + i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns); +} + +/** + * i40e_ptp_set_increment - Utility function to update clock increment rate + * @pf: Board private structure + * + * During a link change, the DMA frequency that drives the 1588 logic will + * change. In order to keep the PRTTSYN_TIME registers in units of nanoseconds, + * we must update the increment value per clock tick. + **/ +void i40e_ptp_set_increment(struct i40e_pf *pf) +{ + struct i40e_link_status *hw_link_info; + struct i40e_hw *hw = &pf->hw; + u64 incval; + + hw_link_info = &hw->phy.link_info; + + i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); + + switch (hw_link_info->link_speed) { + case I40E_LINK_SPEED_10GB: + incval = I40E_PTP_10GB_INCVAL; + break; + case I40E_LINK_SPEED_1GB: + incval = I40E_PTP_1GB_INCVAL; + break; + case I40E_LINK_SPEED_100MB: + dev_warn(&pf->pdev->dev, + "%s: 1588 functionality is not supported at 100 Mbps. Stopping the PHC.\n", + __func__); + incval = 0; + break; + case I40E_LINK_SPEED_40GB: + default: + incval = I40E_PTP_40GB_INCVAL; + break; + } + + /* Write the new increment value into the increment register. The + * hardware will not update the clock until both registers have been + * written. + */ + wr32(hw, I40E_PRTTSYN_INC_L, incval & 0xFFFFFFFF); + wr32(hw, I40E_PRTTSYN_INC_H, incval >> 32); + + /* Update the base adjustement value. */ + ACCESS_ONCE(pf->ptp_base_adj) = incval; + smp_mb(); /* Force the above update. */ +} + +/** + * i40e_ptp_get_ts_config - ioctl interface to read the HW timestamping + * @pf: Board private structure + * @ifreq: ioctl data + * + * Obtain the current hardware timestamping settigs as requested. To do this, + * keep a shadow copy of the timestamp settings rather than attempting to + * deconstruct it from the registers. + **/ +int i40e_ptp_get_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +{ + struct hwtstamp_config *config = &pf->tstamp_config; + + return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? + -EFAULT : 0; +} + +/** + * i40e_ptp_set_ts_config - ioctl interface to control the HW timestamping + * @pf: Board private structure + * @ifreq: ioctl data + * + * Respond to the user filter requests and make the appropriate hardware + * changes here. The XL710 cannot support splitting of the Tx/Rx timestamping + * logic, so keep track in software of whether to indicate these timestamps + * or not. + * + * It is permissible to "upgrade" the user request to a broader filter, as long + * as the user receives the timestamps they care about and the user is notified + * the filter has been broadened. + **/ +int i40e_ptp_set_ts_config(struct i40e_pf *pf, struct ifreq *ifr) +{ + struct i40e_hw *hw = &pf->hw; + struct hwtstamp_config *config = &pf->tstamp_config; + u32 pf_id, tsyntype, regval; + + if (copy_from_user(config, ifr->ifr_data, sizeof(*config))) + return -EFAULT; + + /* Reserved for future extensions. */ + if (config->flags) + return -EINVAL; + + /* Confirm that 1588 is supported on this PF. */ + pf_id = (rd32(hw, I40E_PRTTSYN_CTL0) & I40E_PRTTSYN_CTL0_PF_ID_MASK) >> + I40E_PRTTSYN_CTL0_PF_ID_SHIFT; + if (hw->pf_id != pf_id) + return -EINVAL; + + switch (config->tx_type) { + case HWTSTAMP_TX_OFF: + pf->ptp_tx = false; + break; + case HWTSTAMP_TX_ON: + pf->ptp_tx = true; + break; + default: + return -ERANGE; + } + + switch (config->rx_filter) { + case HWTSTAMP_FILTER_NONE: + pf->ptp_rx = false; + tsyntype = 0; + break; + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: + pf->ptp_rx = true; + tsyntype = I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK | + I40E_PRTTSYN_CTL1_TSYNTYPE_V1 | + I40E_PRTTSYN_CTL1_UDP_ENA_MASK; + config->rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT; + break; + case HWTSTAMP_FILTER_PTP_V2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: + case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: + case HWTSTAMP_FILTER_PTP_V2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: + case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: + case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: + case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: + pf->ptp_rx = true; + tsyntype = I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK | + I40E_PRTTSYN_CTL1_TSYNTYPE_V2 | + I40E_PRTTSYN_CTL1_UDP_ENA_MASK; + config->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT; + break; + case HWTSTAMP_FILTER_ALL: + default: + return -ERANGE; + } + + /* Clear out all 1588-related registers to clear and unlatch them. */ + rd32(hw, I40E_PRTTSYN_STAT_0); + rd32(hw, I40E_PRTTSYN_TXTIME_H); + rd32(hw, I40E_PRTTSYN_RXTIME_H(0)); + rd32(hw, I40E_PRTTSYN_RXTIME_H(1)); + rd32(hw, I40E_PRTTSYN_RXTIME_H(2)); + rd32(hw, I40E_PRTTSYN_RXTIME_H(3)); + + /* Enable/disable the Tx timestamp interrupt based on user input. */ + regval = rd32(hw, I40E_PRTTSYN_CTL0); + if (pf->ptp_tx) + regval |= I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; + else + regval &= ~I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK; + wr32(hw, I40E_PRTTSYN_CTL0, regval); + + regval = rd32(hw, I40E_PFINT_ICR0_ENA); + if (pf->ptp_tx) + regval |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; + else + regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK; + wr32(hw, I40E_PFINT_ICR0_ENA, regval); + + /* There is no simple on/off switch for Rx. To "disable" Rx support, + * ignore any received timestamps, rather than turn off the clock. + */ + if (pf->ptp_rx) { + regval = rd32(hw, I40E_PRTTSYN_CTL1); + /* clear everything but the enable bit */ + regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK; + /* now enable bits for desired Rx timestamps */ + regval |= tsyntype; + wr32(hw, I40E_PRTTSYN_CTL1, regval); + } + + return copy_to_user(ifr->ifr_data, config, sizeof(*config)) ? + -EFAULT : 0; +} + +/** + * i40e_ptp_init - Initialize the 1588 support and register the PHC + * @pf: Board private structure + * + * This function registers the device clock as a PHC. If it is successful, it + * starts the clock in the hardware. + **/ +void i40e_ptp_init(struct i40e_pf *pf) +{ + struct i40e_hw *hw = &pf->hw; + struct net_device *netdev = pf->vsi[pf->lan_vsi]->netdev; + + strncpy(pf->ptp_caps.name, "i40e", sizeof(pf->ptp_caps.name)); + pf->ptp_caps.owner = THIS_MODULE; + pf->ptp_caps.max_adj = 999999999; + pf->ptp_caps.n_ext_ts = 0; + pf->ptp_caps.pps = 0; + pf->ptp_caps.adjfreq = i40e_ptp_adjfreq; + pf->ptp_caps.adjtime = i40e_ptp_adjtime; + pf->ptp_caps.gettime = i40e_ptp_gettime; + pf->ptp_caps.settime = i40e_ptp_settime; + pf->ptp_caps.enable = i40e_ptp_enable; + + /* Attempt to register the clock before enabling the hardware. */ + pf->ptp_clock = ptp_clock_register(&pf->ptp_caps, &pf->pdev->dev); + if (IS_ERR(pf->ptp_clock)) { + pf->ptp_clock = NULL; + dev_err(&pf->pdev->dev, "%s: ptp_clock_register failed\n", + __func__); + } else { + struct timespec ts; + u32 regval; + + spin_lock_init(&pf->tmreg_lock); + INIT_WORK(&pf->ptp_tx_work, i40e_ptp_tx_work); + + dev_info(&pf->pdev->dev, "%s: added PHC on %s\n", __func__, + netdev->name); + pf->flags |= I40E_FLAG_PTP; + + /* Ensure the clocks are running. */ + regval = rd32(hw, I40E_PRTTSYN_CTL0); + regval |= I40E_PRTTSYN_CTL0_TSYNENA_MASK; + wr32(hw, I40E_PRTTSYN_CTL0, regval); + regval = rd32(hw, I40E_PRTTSYN_CTL1); + regval |= I40E_PRTTSYN_CTL1_TSYNENA_MASK; + wr32(hw, I40E_PRTTSYN_CTL1, regval); + + /* Set the increment value per clock tick. */ + i40e_ptp_set_increment(pf); + + /* reset the tstamp_config */ + memset(&pf->tstamp_config, 0, sizeof(pf->tstamp_config)); + + /* Set the clock value. */ + ts = ktime_to_timespec(ktime_get_real()); + i40e_ptp_settime(&pf->ptp_caps, &ts); + } +} + +/** + * i40e_ptp_stop - Disable the driver/hardware support and unregister the PHC + * @pf: Board private structure + * + * This function handles the cleanup work required from the initialization by + * clearing out the important information and unregistering the PHC. + **/ +void i40e_ptp_stop(struct i40e_pf *pf) +{ + pf->flags &= ~I40E_FLAG_PTP; + pf->ptp_tx = false; + pf->ptp_rx = false; + + cancel_work_sync(&pf->ptp_tx_work); + if (pf->ptp_tx_skb) { + dev_kfree_skb_any(pf->ptp_tx_skb); + pf->ptp_tx_skb = NULL; + } + + if (pf->ptp_clock) { + ptp_clock_unregister(pf->ptp_clock); + pf->ptp_clock = NULL; + dev_info(&pf->pdev->dev, "%s: removed PHC on %s\n", __func__, + pf->vsi[pf->lan_vsi]->netdev->name); + } +} diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 43d88dd66ed4..f57a8f8ca385 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -892,6 +892,10 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; + /* likely incorrect csum if alternate IP extention headers found */ + if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) + return; + /* IP or L4 or outmost IP checksum error */ if (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | (1 << I40E_RX_DESC_ERROR_L4E_SHIFT) | @@ -973,8 +977,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) rx_desc = I40E_RX_DESC(rx_ring, i); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); - rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) - >> I40E_RXD_QW1_STATUS_SHIFT; + rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> + I40E_RXD_QW1_STATUS_SHIFT; while (rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT)) { union i40e_rx_desc *next_rxd; @@ -1084,6 +1088,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) } skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); + if (unlikely(rx_status & I40E_RXD_QW1_STATUS_TSYNVALID_MASK)) { + i40e_ptp_rx_hwtstamp(vsi->back, skb, (rx_status & + I40E_RXD_QW1_STATUS_TSYNINDX_MASK) >> + I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT); + rx_ring->last_rx_timestamp = jiffies; + } + /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; total_rx_packets++; @@ -1422,6 +1433,46 @@ static int i40e_tso(struct i40e_ring *tx_ring, struct sk_buff *skb, } /** + * i40e_tsyn - set up the tsyn context descriptor + * @tx_ring: ptr to the ring to send + * @skb: ptr to the skb we're sending + * @tx_flags: the collected send information + * + * Returns 0 if no Tx timestamp can happen and 1 if the timestamp will happen + **/ +static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb, + u32 tx_flags, u64 *cd_type_cmd_tso_mss) +{ + struct i40e_pf *pf; + + if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP))) + return 0; + + /* Tx timestamps cannot be sampled when doing TSO */ + if (tx_flags & I40E_TX_FLAGS_TSO) + return 0; + + /* only timestamp the outbound packet if the user has requested it and + * we are not already transmitting a packet to be timestamped + */ + pf = i40e_netdev_to_pf(tx_ring->netdev); + if (pf->ptp_tx && !pf->ptp_tx_skb) { + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; + pf->ptp_tx_skb = skb_get(skb); + } else { + return 0; + } + + *cd_type_cmd_tso_mss |= (u64)I40E_TX_CTX_DESC_TSYN << + I40E_TXD_CTX_QW1_CMD_SHIFT; + + pf->ptp_tx_start = jiffies; + schedule_work(&pf->ptp_tx_work); + + return 1; +} + +/** * i40e_tx_enable_csum - Enable Tx checksum offloads * @skb: send buffer * @tx_flags: Tx flags currently set @@ -1797,6 +1848,7 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, __be16 protocol; u32 td_cmd = 0; u8 hdr_len = 0; + int tsyn; int tso; if (0 == i40e_xmit_descriptor_count(skb, tx_ring)) return NETDEV_TX_BUSY; @@ -1827,6 +1879,11 @@ static netdev_tx_t i40e_xmit_frame_ring(struct sk_buff *skb, skb_tx_timestamp(skb); + tsyn = i40e_tsyn(tx_ring, skb, tx_flags, &cd_type_cmd_tso_mss); + + if (tsyn) + tx_flags |= I40E_TX_FLAGS_TSYN; + /* always enable CRC insertion offload */ td_cmd |= I40E_TX_DESC_CMD_ICRC; diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 6f8506c181d9..d5349698e513 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -29,9 +29,8 @@ /* Interrupt Throttling and Rate Limiting (storm control) Goodies */ -#define I40E_MAX_ITR 0x07FF -#define I40E_MIN_ITR 0x0001 -#define I40E_ITR_USEC_RESOLUTION 2 +#define I40E_MAX_ITR 0x0FF0 /* reg uses 2 usec resolution */ +#define I40E_MIN_ITR 0x0004 /* reg uses 2 usec resolution */ #define I40E_MAX_IRATE 0x03F #define I40E_MIN_IRATE 0x001 #define I40E_IRATE_USEC_RESOLUTION 4 @@ -137,6 +136,7 @@ enum i40e_dyn_idx_t { #define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) #define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) #define I40E_TX_FLAGS_FSO (u32)(1 << 7) +#define I40E_TX_FLAGS_TSYN (u32)(1 << 8) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 @@ -249,6 +249,8 @@ struct i40e_ring { u8 atr_sample_rate; u8 atr_count; + unsigned long last_rx_timestamp; + bool ring_active; /* is ring online or not */ /* stats structs */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 12473ad5c8e6..ccfc52debb19 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -60,15 +60,6 @@ /* Max default timeout in ms, */ #define I40E_MAX_NVM_TIMEOUT 18000 -/* Check whether address is multicast. This is little-endian specific check.*/ -#define I40E_IS_MULTICAST(address) \ - (bool)(((u8 *)(address))[0] & ((u8)0x01)) - -/* Check whether an address is broadcast. */ -#define I40E_IS_BROADCAST(address) \ - ((((u8 *)(address))[0] == ((u8)0xff)) && \ - (((u8 *)(address))[1] == ((u8)0xff))) - /* Switch from mc to the 2usec global time (this is the GTIME resolution) */ #define I40E_MS_TO_GTIME(time) (((time) * 1000) / 2) @@ -84,6 +75,7 @@ typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *); /* bitfields for Tx queue mapping in QTX_CTL */ #define I40E_QTX_CTL_VF_QUEUE 0x0 +#define I40E_QTX_CTL_VM_QUEUE 0x1 #define I40E_QTX_CTL_PF_QUEUE 0x2 /* debug masks - set these bits in hw->debug_mask to control output */ @@ -508,7 +500,9 @@ enum i40e_rx_desc_status_bits { I40E_RX_DESC_STATUS_FLM_SHIFT = 11, I40E_RX_DESC_STATUS_FLTSTAT_SHIFT = 12, /* 2 BITS */ I40E_RX_DESC_STATUS_LPBK_SHIFT = 14, - I40E_RX_DESC_STATUS_UDP_0_SHIFT = 16 + I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT = 15, + I40E_RX_DESC_STATUS_RESERVED_SHIFT = 16, /* 2 BITS */ + I40E_RX_DESC_STATUS_UDP_0_SHIFT = 18 }; #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 51a4f6125437..44bb3597d736 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -386,8 +386,8 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) vf->lan_vsi_index = vsi->idx; vf->lan_vsi_id = vsi->id; dev_info(&pf->pdev->dev, - "LAN VSI index %d, VSI id %d\n", - vsi->idx, vsi->id); + "VF %d assigned LAN VSI index %d, VSI id %d\n", + vf->vf_id, vsi->idx, vsi->id); /* If the port VLAN has been configured and then the * VF driver was removed then the VSI port VLAN * configuration was destroyed. Check if there is @@ -1525,9 +1525,13 @@ static int i40e_vc_del_mac_addr_msg(struct i40e_vf *vf, u8 *msg, u16 msglen) } for (i = 0; i < al->num_elements; i++) { - ret = i40e_check_vf_permission(vf, al->list[i].addr); - if (ret) + if (is_broadcast_ether_addr(al->list[i].addr) || + is_zero_ether_addr(al->list[i].addr)) { + dev_err(&pf->pdev->dev, "invalid VF MAC addr %pM\n", + al->list[i].addr); + ret = I40E_ERR_INVALID_MAC_ADDR; goto error_param; + } } vsi = pf->vsi[vsi_id]; @@ -1788,7 +1792,7 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode, local_vf_id, v_opcode, msglen); return ret; } - wr32(hw, I40E_VFGEN_RSTAT1(local_vf_id), I40E_VFR_VFACTIVE); + switch (v_opcode) { case I40E_VIRTCHNL_OP_VERSION: ret = i40e_vc_get_version_msg(vf); @@ -2072,6 +2076,20 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, goto error_pvid; } + if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) + dev_err(&pf->pdev->dev, + "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n", + vf_id); + + /* Check for condition where there was already a port VLAN ID + * filter set and now it is being deleted by setting it to zero. + * Before deleting all the old VLAN filters we must add new ones + * with -1 (I40E_VLAN_ANY) or otherwise we're left with all our + * MAC addresses deleted. + */ + if (!(vlan_id || qos) && vsi->info.pvid) + ret = i40e_vsi_add_vlan(vsi, I40E_VLAN_ANY); + if (vsi->info.pvid) { /* kill old VLAN */ ret = i40e_vsi_kill_vlan(vsi, (le16_to_cpu(vsi->info.pvid) & @@ -2100,6 +2118,10 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, vsi->back->hw.aq.asq_last_status); goto error_pvid; } + /* Kill non-vlan MAC filters - ignore error return since + * there might not be any non-vlan MAC filters. + */ + i40e_vsi_kill_vlan(vsi, I40E_VLAN_ANY); } if (ret) { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 8f2b3b2a2a90..ffdb01d853db 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -21,6 +21,8 @@ * ******************************************************************************/ +#include <linux/prefetch.h> + #include "i40evf.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 49531cd18987..3a4373f689eb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -585,6 +585,11 @@ static inline u16 ixgbe_desc_unused(struct ixgbe_ring *ring) return ((ntc > ntu) ? 0 : ring->count) + ntc - ntu - 1; } +static inline void ixgbe_write_tail(struct ixgbe_ring *ring, u32 value) +{ + writel(value, ring->tail); +} + #define IXGBE_RX_DESC(R, i) \ (&(((union ixgbe_adv_rx_desc *)((R)->desc))[i])) #define IXGBE_TX_DESC(R, i) \ @@ -742,6 +747,7 @@ struct ixgbe_adapter { #ifdef IXGBE_FCOE struct ixgbe_fcoe fcoe; #endif /* IXGBE_FCOE */ + u8 __iomem *io_addr; /* Mainly for iounmap use */ u32 wol; u16 bd_number; @@ -798,6 +804,7 @@ enum ixgbe_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, __IXGBE_DOWN, + __IXGBE_REMOVING, __IXGBE_SERVICE_SCHED, __IXGBE_IN_SFP_INIT, __IXGBE_PTP_RUNNING, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index d259dc76604e..f2e3919750ec 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -124,24 +124,65 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw); s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw); -#define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg))) +#define IXGBE_FAILED_READ_REG 0xffffffffU -#ifndef writeq -#define writeq(val, addr) writel((u32) (val), addr); \ - writel((u32) (val >> 32), (addr + 4)); -#endif +static inline bool ixgbe_removed(void __iomem *addr) +{ + return unlikely(!addr); +} -#define IXGBE_WRITE_REG64(a, reg, value) writeq((value), ((a)->hw_addr + (reg))) +void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg); -#define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg)) +static inline void ixgbe_write_reg(struct ixgbe_hw *hw, u32 reg, u32 value) +{ + u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr); -#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\ - writel((value), ((a)->hw_addr + (reg) + ((offset) << 2)))) + if (ixgbe_removed(reg_addr)) + return; + writel(value, reg_addr + reg); +} +#define IXGBE_WRITE_REG(a, reg, value) ixgbe_write_reg((a), (reg), (value)) -#define IXGBE_READ_REG_ARRAY(a, reg, offset) (\ - readl((a)->hw_addr + (reg) + ((offset) << 2))) +#ifndef writeq +#define writeq writeq +static inline void writeq(u64 val, void __iomem *addr) +{ + writel((u32)val, addr); + writel((u32)(val >> 32), addr + 4); +} +#endif -#define IXGBE_WRITE_FLUSH(a) IXGBE_READ_REG(a, IXGBE_STATUS) +static inline void ixgbe_write_reg64(struct ixgbe_hw *hw, u32 reg, u64 value) +{ + u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr); + + if (ixgbe_removed(reg_addr)) + return; + writeq(value, reg_addr + reg); +} +#define IXGBE_WRITE_REG64(a, reg, value) ixgbe_write_reg64((a), (reg), (value)) + +static inline u32 ixgbe_read_reg(struct ixgbe_hw *hw, u32 reg) +{ + u8 __iomem *reg_addr = ACCESS_ONCE(hw->hw_addr); + u32 value; + + if (ixgbe_removed(reg_addr)) + return IXGBE_FAILED_READ_REG; + value = readl(reg_addr + reg); + if (unlikely(value == IXGBE_FAILED_READ_REG)) + ixgbe_check_remove(hw, reg); + return value; +} +#define IXGBE_READ_REG(a, reg) ixgbe_read_reg((a), (reg)) + +#define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) \ + ixgbe_write_reg((a), (reg) + ((offset) << 2), (value)) + +#define IXGBE_READ_REG_ARRAY(a, reg, offset) \ + ixgbe_read_reg((a), (reg) + ((offset) << 2)) + +#define IXGBE_WRITE_FLUSH(a) ixgbe_read_reg((a), IXGBE_STATUS) #define ixgbe_hw_to_netdev(hw) (((struct ixgbe_adapter *)(hw)->back)->netdev) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 4e7c9b098b58..043307024c4a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1342,61 +1342,61 @@ static bool reg_pattern_test(struct ixgbe_adapter *adapter, u64 *data, int reg, static const u32 test_pattern[] = { 0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; + if (ixgbe_removed(adapter->hw.hw_addr)) { + *data = 1; + return 1; + } for (pat = 0; pat < ARRAY_SIZE(test_pattern); pat++) { - before = readl(adapter->hw.hw_addr + reg); - writel((test_pattern[pat] & write), - (adapter->hw.hw_addr + reg)); - val = readl(adapter->hw.hw_addr + reg); + before = ixgbe_read_reg(&adapter->hw, reg); + ixgbe_write_reg(&adapter->hw, reg, test_pattern[pat] & write); + val = ixgbe_read_reg(&adapter->hw, reg); if (val != (test_pattern[pat] & write & mask)) { e_err(drv, "pattern test reg %04X failed: got " "0x%08X expected 0x%08X\n", reg, val, (test_pattern[pat] & write & mask)); *data = reg; - writel(before, adapter->hw.hw_addr + reg); - return 1; + ixgbe_write_reg(&adapter->hw, reg, before); + return true; } - writel(before, adapter->hw.hw_addr + reg); + ixgbe_write_reg(&adapter->hw, reg, before); } - return 0; + return false; } static bool reg_set_and_check(struct ixgbe_adapter *adapter, u64 *data, int reg, u32 mask, u32 write) { u32 val, before; - before = readl(adapter->hw.hw_addr + reg); - writel((write & mask), (adapter->hw.hw_addr + reg)); - val = readl(adapter->hw.hw_addr + reg); + + if (ixgbe_removed(adapter->hw.hw_addr)) { + *data = 1; + return 1; + } + before = ixgbe_read_reg(&adapter->hw, reg); + ixgbe_write_reg(&adapter->hw, reg, write & mask); + val = ixgbe_read_reg(&adapter->hw, reg); if ((write & mask) != (val & mask)) { e_err(drv, "set/check reg %04X test failed: got 0x%08X " "expected 0x%08X\n", reg, (val & mask), (write & mask)); *data = reg; - writel(before, (adapter->hw.hw_addr + reg)); - return 1; + ixgbe_write_reg(&adapter->hw, reg, before); + return true; } - writel(before, (adapter->hw.hw_addr + reg)); - return 0; + ixgbe_write_reg(&adapter->hw, reg, before); + return false; } -#define REG_PATTERN_TEST(reg, mask, write) \ - do { \ - if (reg_pattern_test(adapter, data, reg, mask, write)) \ - return 1; \ - } while (0) \ - - -#define REG_SET_AND_CHECK(reg, mask, write) \ - do { \ - if (reg_set_and_check(adapter, data, reg, mask, write)) \ - return 1; \ - } while (0) \ - static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) { const struct ixgbe_reg_test *test; u32 value, before, after; u32 i, toggle; + if (ixgbe_removed(adapter->hw.hw_addr)) { + e_err(drv, "Adapter removed - register test blocked\n"); + *data = 1; + return 1; + } switch (adapter->hw.mac.type) { case ixgbe_mac_82598EB: toggle = 0x7FFFF3FF; @@ -1419,10 +1419,10 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) * tests. Some bits are read-only, some toggle, and some * are writeable on newer MACs. */ - before = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS); - value = (IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle); - IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, toggle); - after = IXGBE_READ_REG(&adapter->hw, IXGBE_STATUS) & toggle; + before = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS); + value = (ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle); + ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, toggle); + after = ixgbe_read_reg(&adapter->hw, IXGBE_STATUS) & toggle; if (value != after) { e_err(drv, "failed STATUS register test got: 0x%08X " "expected: 0x%08X\n", after, value); @@ -1430,7 +1430,7 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) return 1; } /* restore previous status */ - IXGBE_WRITE_REG(&adapter->hw, IXGBE_STATUS, before); + ixgbe_write_reg(&adapter->hw, IXGBE_STATUS, before); /* * Perform the remainder of the register test, looping through @@ -1438,38 +1438,47 @@ static int ixgbe_reg_test(struct ixgbe_adapter *adapter, u64 *data) */ while (test->reg) { for (i = 0; i < test->array_len; i++) { + bool b = false; + switch (test->test_type) { case PATTERN_TEST: - REG_PATTERN_TEST(test->reg + (i * 0x40), - test->mask, - test->write); + b = reg_pattern_test(adapter, data, + test->reg + (i * 0x40), + test->mask, + test->write); break; case SET_READ_TEST: - REG_SET_AND_CHECK(test->reg + (i * 0x40), - test->mask, - test->write); + b = reg_set_and_check(adapter, data, + test->reg + (i * 0x40), + test->mask, + test->write); break; case WRITE_NO_TEST: - writel(test->write, - (adapter->hw.hw_addr + test->reg) - + (i * 0x40)); + ixgbe_write_reg(&adapter->hw, + test->reg + (i * 0x40), + test->write); break; case TABLE32_TEST: - REG_PATTERN_TEST(test->reg + (i * 4), - test->mask, - test->write); + b = reg_pattern_test(adapter, data, + test->reg + (i * 4), + test->mask, + test->write); break; case TABLE64_TEST_LO: - REG_PATTERN_TEST(test->reg + (i * 8), - test->mask, - test->write); + b = reg_pattern_test(adapter, data, + test->reg + (i * 8), + test->mask, + test->write); break; case TABLE64_TEST_HI: - REG_PATTERN_TEST((test->reg + 4) + (i * 8), - test->mask, - test->write); + b = reg_pattern_test(adapter, data, + (test->reg + 4) + (i * 8), + test->mask, + test->write); break; } + if (b) + return 1; } test++; } @@ -1954,6 +1963,15 @@ static void ixgbe_diag_test(struct net_device *netdev, struct ixgbe_adapter *adapter = netdev_priv(netdev); bool if_running = netif_running(netdev); + if (ixgbe_removed(adapter->hw.hw_addr)) { + e_err(hw, "Adapter removed - test blocked\n"); + data[0] = 1; + data[1] = 1; + data[2] = 1; + data[3] = 1; + eth_test->flags |= ETH_TEST_FL_FAILED; + return; + } set_bit(__IXGBE_TESTING, &adapter->state); if (eth_test->flags == ETH_TEST_FL_OFFLINE) { struct ixgbe_hw *hw = &adapter->hw; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index cc06854296a3..3ca59d21d0b2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -278,10 +278,41 @@ static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter, static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter) { if (!test_bit(__IXGBE_DOWN, &adapter->state) && + !test_bit(__IXGBE_REMOVING, &adapter->state) && !test_and_set_bit(__IXGBE_SERVICE_SCHED, &adapter->state)) schedule_work(&adapter->service_task); } +static void ixgbe_remove_adapter(struct ixgbe_hw *hw) +{ + struct ixgbe_adapter *adapter = hw->back; + + if (!hw->hw_addr) + return; + hw->hw_addr = NULL; + e_dev_err("Adapter removed\n"); + ixgbe_service_event_schedule(adapter); +} + +void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg) +{ + u32 value; + + /* The following check not only optimizes a bit by not + * performing a read on the status register when the + * register just read was a status register read that + * returned IXGBE_FAILED_READ_REG. It also blocks any + * potential recursion. + */ + if (reg == IXGBE_STATUS) { + ixgbe_remove_adapter(hw); + return; + } + value = ixgbe_read_reg(hw, IXGBE_STATUS); + if (value == IXGBE_FAILED_READ_REG) + ixgbe_remove_adapter(hw); +} + static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter) { BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state)); @@ -1314,7 +1345,7 @@ static inline void ixgbe_release_rx_desc(struct ixgbe_ring *rx_ring, u32 val) * such as IA-64). */ wmb(); - writel(val, rx_ring->tail); + ixgbe_write_tail(rx_ring, val); } static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring, @@ -2969,7 +3000,7 @@ void ixgbe_configure_tx_ring(struct ixgbe_adapter *adapter, ring->count * sizeof(union ixgbe_adv_tx_desc)); IXGBE_WRITE_REG(hw, IXGBE_TDH(reg_idx), 0); IXGBE_WRITE_REG(hw, IXGBE_TDT(reg_idx), 0); - ring->tail = hw->hw_addr + IXGBE_TDT(reg_idx); + ring->tail = adapter->io_addr + IXGBE_TDT(reg_idx); /* * set WTHRESH to encourage burst writeback, it should not be set @@ -3308,6 +3339,8 @@ static void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter, u32 rxdctl; u8 reg_idx = ring->reg_idx; + if (ixgbe_removed(hw->hw_addr)) + return; /* RXDCTL.EN will return 0 on 82598 if link is down, so skip it */ if (hw->mac.type == ixgbe_mac_82598EB && !(IXGBE_READ_REG(hw, IXGBE_LINKS) & IXGBE_LINKS_UP)) @@ -3332,6 +3365,8 @@ void ixgbe_disable_rx_queue(struct ixgbe_adapter *adapter, u32 rxdctl; u8 reg_idx = ring->reg_idx; + if (ixgbe_removed(hw->hw_addr)) + return; rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(reg_idx)); rxdctl &= ~IXGBE_RXDCTL_ENABLE; @@ -3372,7 +3407,7 @@ void ixgbe_configure_rx_ring(struct ixgbe_adapter *adapter, ring->count * sizeof(union ixgbe_adv_rx_desc)); IXGBE_WRITE_REG(hw, IXGBE_RDH(reg_idx), 0); IXGBE_WRITE_REG(hw, IXGBE_RDT(reg_idx), 0); - ring->tail = hw->hw_addr + IXGBE_RDT(reg_idx); + ring->tail = adapter->io_addr + IXGBE_RDT(reg_idx); ixgbe_configure_srrctl(adapter, ring); ixgbe_configure_rscctl(adapter, ring); @@ -4572,6 +4607,7 @@ static void ixgbe_up_complete(struct ixgbe_adapter *adapter) if (hw->mac.ops.enable_tx_laser) hw->mac.ops.enable_tx_laser(hw); + smp_mb__before_clear_bit(); clear_bit(__IXGBE_DOWN, &adapter->state); ixgbe_napi_enable_all(adapter); @@ -4656,6 +4692,8 @@ void ixgbe_reset(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; int err; + if (ixgbe_removed(hw->hw_addr)) + return; /* lock SFP init bit to prevent race conditions with the watchdog */ while (test_and_set_bit(__IXGBE_IN_SFP_INIT, &adapter->state)) usleep_range(1000, 2000); @@ -4783,7 +4821,8 @@ void ixgbe_down(struct ixgbe_adapter *adapter) int i; /* signal that we are down to the interrupt handler */ - set_bit(__IXGBE_DOWN, &adapter->state); + if (test_and_set_bit(__IXGBE_DOWN, &adapter->state)) + return; /* do nothing if already down */ /* disable receives */ rxctrl = IXGBE_READ_REG(hw, IXGBE_RXCTRL); @@ -5874,8 +5913,9 @@ static void ixgbe_check_hang_subtask(struct ixgbe_adapter *adapter) u64 eics = 0; int i; - /* If we're down or resetting, just bail */ + /* If we're down, removing or resetting, just bail */ if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_REMOVING, &adapter->state) || test_bit(__IXGBE_RESETTING, &adapter->state)) return; @@ -6122,8 +6162,9 @@ static void ixgbe_spoof_check(struct ixgbe_adapter *adapter) **/ static void ixgbe_watchdog_subtask(struct ixgbe_adapter *adapter) { - /* if interface is down do nothing */ + /* if interface is down, removing or resetting, do nothing */ if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_REMOVING, &adapter->state) || test_bit(__IXGBE_RESETTING, &adapter->state)) return; @@ -6341,8 +6382,9 @@ static void ixgbe_reset_subtask(struct ixgbe_adapter *adapter) adapter->flags2 &= ~IXGBE_FLAG2_RESET_REQUESTED; - /* If we're already down or resetting, just bail */ + /* If we're already down, removing or resetting, just bail */ if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_REMOVING, &adapter->state) || test_bit(__IXGBE_RESETTING, &adapter->state)) return; @@ -6362,6 +6404,15 @@ static void ixgbe_service_task(struct work_struct *work) struct ixgbe_adapter *adapter = container_of(work, struct ixgbe_adapter, service_task); + if (ixgbe_removed(adapter->hw.hw_addr)) { + if (!test_bit(__IXGBE_DOWN, &adapter->state)) { + rtnl_lock(); + ixgbe_down(adapter); + rtnl_unlock(); + } + ixgbe_service_event_complete(adapter); + return; + } ixgbe_reset_subtask(adapter); ixgbe_sfp_detection_subtask(adapter); ixgbe_sfp_link_config_subtask(adapter); @@ -6693,7 +6744,7 @@ static void ixgbe_tx_map(struct ixgbe_ring *tx_ring, tx_ring->next_to_use = i; /* notify HW of packet */ - writel(i, tx_ring->tail); + ixgbe_write_tail(tx_ring, i); return; dma_error: @@ -6827,12 +6878,20 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size) return __ixgbe_maybe_stop_tx(tx_ring, size); } -#ifdef IXGBE_FCOE -static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { + struct ixgbe_fwd_adapter *fwd_adapter = accel_priv; +#ifdef IXGBE_FCOE struct ixgbe_adapter *adapter; struct ixgbe_ring_feature *f; int txq; +#endif + + if (fwd_adapter) + return skb->queue_mapping + fwd_adapter->tx_base_queue; + +#ifdef IXGBE_FCOE /* * only execute the code below if protocol is FCoE @@ -6858,9 +6917,11 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb) txq -= f->indices; return txq + f->offset; +#else + return __netdev_pick_tx(dev, skb); +#endif } -#endif netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring) @@ -7629,27 +7690,11 @@ static void ixgbe_fwd_del(struct net_device *pdev, void *priv) kfree(fwd_adapter); } -static netdev_tx_t ixgbe_fwd_xmit(struct sk_buff *skb, - struct net_device *dev, - void *priv) -{ - struct ixgbe_fwd_adapter *fwd_adapter = priv; - unsigned int queue; - struct ixgbe_ring *tx_ring; - - queue = skb->queue_mapping + fwd_adapter->tx_base_queue; - tx_ring = fwd_adapter->real_adapter->tx_ring[queue]; - - return __ixgbe_xmit_frame(skb, dev, tx_ring); -} - static const struct net_device_ops ixgbe_netdev_ops = { .ndo_open = ixgbe_open, .ndo_stop = ixgbe_close, .ndo_start_xmit = ixgbe_xmit_frame, -#ifdef IXGBE_FCOE .ndo_select_queue = ixgbe_select_queue, -#endif .ndo_set_rx_mode = ixgbe_set_rx_mode, .ndo_validate_addr = eth_validate_addr, .ndo_set_mac_address = ixgbe_set_mac, @@ -7689,7 +7734,6 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_bridge_getlink = ixgbe_ndo_bridge_getlink, .ndo_dfwd_add_station = ixgbe_fwd_add, .ndo_dfwd_del_station = ixgbe_fwd_del, - .ndo_dfwd_start_xmit = ixgbe_fwd_xmit, }; /** @@ -7881,6 +7925,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw->hw_addr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + adapter->io_addr = hw->hw_addr; if (!hw->hw_addr) { err = -EIO; goto err_ioremap; @@ -8189,7 +8234,7 @@ err_register: err_sw_init: ixgbe_disable_sriov(adapter); adapter->flags2 &= ~IXGBE_FLAG2_SEARCH_FOR_SFP; - iounmap(hw->hw_addr); + iounmap(adapter->io_addr); err_ioremap: free_netdev(netdev); err_alloc_etherdev: @@ -8217,7 +8262,7 @@ static void ixgbe_remove(struct pci_dev *pdev) ixgbe_dbg_adapter_exit(adapter); - set_bit(__IXGBE_DOWN, &adapter->state); + set_bit(__IXGBE_REMOVING, &adapter->state); cancel_work_sync(&adapter->service_task); @@ -8256,7 +8301,7 @@ static void ixgbe_remove(struct pci_dev *pdev) kfree(adapter->ixgbe_ieee_ets); #endif - iounmap(adapter->hw.hw_addr); + iounmap(adapter->io_addr); pci_release_selected_regions(pdev, pci_select_bars(pdev, IORESOURCE_MEM)); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c index d4a64e665398..cc3101afd29f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_mbx.c @@ -27,8 +27,7 @@ #include <linux/pci.h> #include <linux/delay.h> -#include "ixgbe_type.h" -#include "ixgbe_common.h" +#include "ixgbe.h" #include "ixgbe_mbx.h" /** diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 39217e5ff7dc..132557c318f8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -29,7 +29,7 @@ #include <linux/delay.h> #include <linux/sched.h> -#include "ixgbe_common.h" +#include "ixgbe.h" #include "ixgbe_phy.h" static void ixgbe_i2c_start(struct ixgbe_hw *hw); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c index 359f6e60320d..0558c7139f38 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c @@ -631,11 +631,14 @@ int ixgbe_vf_configuration(struct pci_dev *pdev, unsigned int event_mask) static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf) { + struct ixgbe_ring_feature *vmdq = &adapter->ring_feature[RING_F_VMDQ]; struct ixgbe_hw *hw = &adapter->hw; unsigned char *vf_mac = adapter->vfinfo[vf].vf_mac_addresses; u32 reg, reg_offset, vf_shift; u32 msgbuf[4] = {0, 0, 0, 0}; u8 *addr = (u8 *)(&msgbuf[1]); + u32 q_per_pool = __ALIGN_MASK(1, ~vmdq->mask); + int i; e_info(probe, "VF Reset msg received from vf %d\n", vf); @@ -654,6 +657,17 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf) reg |= 1 << vf_shift; IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), reg); + /* force drop enable for all VF Rx queues */ + for (i = vf * q_per_pool; i < ((vf + 1) * q_per_pool); i++) { + /* flush previous write */ + IXGBE_WRITE_FLUSH(hw); + + /* indicate to hardware that we want to set drop enable */ + reg = IXGBE_QDE_WRITE | IXGBE_QDE_ENABLE; + reg |= i << IXGBE_QDE_IDX_SHIFT; + IXGBE_WRITE_REG(hw, IXGBE_QDE, reg); + } + /* enable receive for vf */ reg = IXGBE_READ_REG(hw, IXGBE_VFRE(reg_offset)); reg |= 1 << vf_shift; @@ -684,6 +698,15 @@ static int ixgbe_vf_reset_msg(struct ixgbe_adapter *adapter, u32 vf) reg |= (1 << vf_shift); IXGBE_WRITE_REG(hw, IXGBE_VMECM(reg_offset), reg); + /* + * Reset the VFs TDWBAL and TDWBAH registers + * which are not cleared by an FLR + */ + for (i = 0; i < q_per_pool; i++) { + IXGBE_WRITE_REG(hw, IXGBE_PVFTDWBAHn(q_per_pool, vf, i), 0); + IXGBE_WRITE_REG(hw, IXGBE_PVFTDWBALn(q_per_pool, vf, i), 0); + } + /* reply to reset with ack and vf mac address */ msgbuf[0] = IXGBE_VF_RESET; if (!is_zero_ether_addr(vf_mac)) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 7c19e969576f..0d39cfc4a3bf 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -1980,9 +1980,10 @@ enum { #define IXGBE_FWSM_TS_ENABLED 0x1 /* Queue Drop Enable */ -#define IXGBE_QDE_ENABLE 0x00000001 -#define IXGBE_QDE_IDX_MASK 0x00007F00 -#define IXGBE_QDE_IDX_SHIFT 8 +#define IXGBE_QDE_ENABLE 0x00000001 +#define IXGBE_QDE_IDX_MASK 0x00007F00 +#define IXGBE_QDE_IDX_SHIFT 8 +#define IXGBE_QDE_WRITE 0x00010000 #define IXGBE_TXD_POPTS_IXSM 0x01 /* Insert IP checksum */ #define IXGBE_TXD_POPTS_TXSM 0x02 /* Insert TCP/UDP checksum */ @@ -2173,6 +2174,14 @@ enum { #define IXGBE_MBVFICR(_i) (0x00710 + ((_i) * 4)) #define IXGBE_VFLRE(_i) ((((_i) & 1) ? 0x001C0 : 0x00600)) #define IXGBE_VFLREC(_i) (0x00700 + ((_i) * 4)) +/* Translated register #defines */ +#define IXGBE_PVFTDWBAL(P) (0x06038 + (0x40 * (P))) +#define IXGBE_PVFTDWBAH(P) (0x0603C + (0x40 * (P))) + +#define IXGBE_PVFTDWBALn(q_per_pool, vf_number, vf_q_index) \ + (IXGBE_PVFTDWBAL((q_per_pool)*(vf_number) + (vf_q_index))) +#define IXGBE_PVFTDWBAHn(q_per_pool, vf_number, vf_q_index) \ + (IXGBE_PVFTDWBAH((q_per_pool)*(vf_number) + (vf_q_index))) enum ixgbe_fdir_pballoc_type { IXGBE_FDIR_PBALLOC_NONE = 0, diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 974a007c4277..8f9266c64c75 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -618,7 +618,8 @@ ltq_etop_set_multicast_list(struct net_device *dev) } static u16 -ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb) +ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { /* we are currently only using the first queue */ return 0; diff --git a/drivers/net/ethernet/marvell/Kconfig b/drivers/net/ethernet/marvell/Kconfig index a49e81bdf8e8..6300fd27f2db 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -33,6 +33,7 @@ config MV643XX_ETH config MVMDIO tristate "Marvell MDIO interface support" + depends on HAS_IOMEM select PHYLIB ---help--- This driver supports the MDIO interface found in the network diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 3b66f26ba049..890922c1c8ee 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -724,7 +724,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud * - not an IP fragment * - no LLS polling in progress */ - if (!mlx4_en_cq_ll_polling(cq) && + if (!mlx4_en_cq_busy_polling(cq) && (dev->features & NETIF_F_GRO)) { struct sk_buff *gro_skb = napi_get_frags(&cq->napi); if (!gro_skb) @@ -816,8 +816,10 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud skb_mark_napi_id(skb, &cq->napi); - /* Push it up the stack */ - netif_receive_skb(skb); + if (!mlx4_en_cq_busy_polling(cq)) + napi_gro_receive(&cq->napi, skb); + else + netif_receive_skb(skb); next: for (nr = 0; nr < priv->num_frags; nr++) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 160e86d21607..8e8a7eb43a2c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -628,7 +628,8 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk } } -u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb) +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { struct mlx4_en_priv *priv = netdev_priv(dev); u16 rings_p_up = priv->num_tx_rings_p_up; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 2f1e200f2e4c..3af04c3f42ea 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -661,7 +661,7 @@ static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq) } /* true if a socket is polling, even if it did not get the lock */ -static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) +static inline bool mlx4_en_cq_busy_polling(struct mlx4_en_cq *cq) { WARN_ON(!(cq->state & MLX4_CQ_LOCKED)); return cq->state & CQ_USER_PEND; @@ -691,7 +691,7 @@ static inline bool mlx4_en_cq_unlock_poll(struct mlx4_en_cq *cq) return false; } -static inline bool mlx4_en_cq_ll_polling(struct mlx4_en_cq *cq) +static inline bool mlx4_en_cq_busy_polling(struct mlx4_en_cq *cq) { return false; } @@ -722,7 +722,8 @@ int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq); void mlx4_en_tx_irq(struct mlx4_cq *mcq); -u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb); +u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv); netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev); int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c index 8e9dad770900..ce84dc289c8f 100644 --- a/drivers/net/ethernet/micrel/ksz884x.c +++ b/drivers/net/ethernet/micrel/ksz884x.c @@ -5853,15 +5853,12 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct dev_info *hw_priv = priv->adapter; struct ksz_hw *hw = &hw_priv->hw; struct ksz_port *port = &priv->port; - int rc; int result = 0; struct mii_ioctl_data *data = if_mii(ifr); if (down_interruptible(&priv->proc_sem)) return -ERESTARTSYS; - /* assume success */ - rc = 0; switch (cmd) { /* Get address of MII PHY in use. */ case SIOCGMIIPHY: diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index 35d48766d842..1accd9531224 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h @@ -38,8 +38,8 @@ #define _QLCNIC_LINUX_MAJOR 5 #define _QLCNIC_LINUX_MINOR 3 -#define _QLCNIC_LINUX_SUBVERSION 53 -#define QLCNIC_LINUX_VERSIONID "5.3.53" +#define _QLCNIC_LINUX_SUBVERSION 54 +#define QLCNIC_LINUX_VERSIONID "5.3.54" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -970,6 +970,9 @@ struct qlcnic_ipaddr { #define QLCNIC_BEACON_EANBLE 0xC #define QLCNIC_BEACON_DISABLE 0xD +#define QLCNIC_BEACON_ON 2 +#define QLCNIC_BEACON_OFF 0 + #define QLCNIC_MSIX_TBL_SPACE 8192 #define QLCNIC_PCI_REG_MSIX_TBL 0x44 #define QLCNIC_MSIX_TBL_PGSIZE 4096 @@ -1079,6 +1082,7 @@ struct qlcnic_adapter { u64 dev_rst_time; bool drv_mac_learn; bool fdb_mac_learn; + u8 rx_mac_learn; unsigned long vlans[BITS_TO_LONGS(VLAN_N_VID)]; u8 flash_mfg_id; struct qlcnic_npar_info *npars; @@ -1267,7 +1271,7 @@ struct qlcnic_pci_func_cfg { u16 port_num; u8 pci_func; u8 func_state; - u8 def_mac_addr[6]; + u8 def_mac_addr[ETH_ALEN]; }; struct qlcnic_npar_func_cfg { @@ -1640,7 +1644,6 @@ int qlcnic_set_default_offload_settings(struct qlcnic_adapter *); int qlcnic_reset_npar_config(struct qlcnic_adapter *); int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *); void qlcnic_add_lb_filter(struct qlcnic_adapter *, struct sk_buff *, int, u16); -int qlcnic_get_beacon_state(struct qlcnic_adapter *, u8 *); int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); int qlcnic_read_mac_addr(struct qlcnic_adapter *); int qlcnic_setup_netdev(struct qlcnic_adapter *, struct net_device *, int); @@ -1720,6 +1723,7 @@ int qlcnic_83xx_init_mailbox_work(struct qlcnic_adapter *); void qlcnic_83xx_detach_mailbox_work(struct qlcnic_adapter *); void qlcnic_83xx_reinit_mbx_work(struct qlcnic_mailbox *mbx); void qlcnic_83xx_free_mailbox(struct qlcnic_mailbox *mbx); +void qlcnic_update_stats(struct qlcnic_adapter *); /* Adapter hardware abstraction */ struct qlcnic_hardware_ops { @@ -1767,6 +1771,7 @@ struct qlcnic_hardware_ops { pci_channel_state_t); pci_ers_result_t (*io_slot_reset) (struct pci_dev *); void (*io_resume) (struct pci_dev *); + void (*get_beacon_state)(struct qlcnic_adapter *); }; extern struct qlcnic_nic_template qlcnic_vf_ops; @@ -1993,6 +1998,11 @@ static inline void qlcnic_set_mac_filter_count(struct qlcnic_adapter *adapter) adapter->ahw->hw_ops->set_mac_filter_count(adapter); } +static inline void qlcnic_get_beacon_state(struct qlcnic_adapter *adapter) +{ + adapter->ahw->hw_ops->get_beacon_state(adapter); +} + static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter) { if (adapter->ahw->hw_ops->read_phys_port_id) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 03eb2ad9611a..a684d28e37af 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -181,7 +181,7 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { .io_error_detected = qlcnic_83xx_io_error_detected, .io_slot_reset = qlcnic_83xx_io_slot_reset, .io_resume = qlcnic_83xx_io_resume, - + .get_beacon_state = qlcnic_83xx_get_beacon_state, }; static struct qlcnic_nic_template qlcnic_83xx_ops = { @@ -1388,6 +1388,33 @@ out: netif_device_attach(netdev); } +void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *adapter) +{ + struct qlcnic_hardware_context *ahw = adapter->ahw; + struct qlcnic_cmd_args cmd; + u8 beacon_state; + int err = 0; + + err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_CONFIG); + if (!err) { + err = qlcnic_issue_cmd(adapter, &cmd); + if (!err) { + beacon_state = cmd.rsp.arg[4]; + if (beacon_state == QLCNIC_BEACON_DISABLE) + ahw->beacon_state = QLC_83XX_BEACON_OFF; + else if (beacon_state == QLC_83XX_ENABLE_BEACON) + ahw->beacon_state = QLC_83XX_BEACON_ON; + } + } else { + netdev_err(adapter->netdev, "Get beacon state failed, err=%d\n", + err); + } + + qlcnic_free_mbx_args(&cmd); + + return; +} + int qlcnic_83xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 beacon) { @@ -1591,7 +1618,9 @@ static void qlcnic_83xx_set_interface_id_promisc(struct qlcnic_adapter *adapter, u32 *interface_id) { if (qlcnic_sriov_pf_check(adapter)) { + qlcnic_alloc_lb_filters_mem(adapter); qlcnic_pf_set_interface_id_promisc(adapter, interface_id); + adapter->rx_mac_learn = 1; } else { if (!qlcnic_sriov_vf_check(adapter)) *interface_id = adapter->recv_ctx->context_id << 16; @@ -1618,6 +1647,10 @@ int qlcnic_83xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) cmd->type = QLC_83XX_MBX_CMD_NO_WAIT; qlcnic_83xx_set_interface_id_promisc(adapter, &temp); + + if (qlcnic_84xx_check(adapter) && qlcnic_sriov_pf_check(adapter)) + mode = VPORT_MISS_MODE_ACCEPT_ALL; + cmd->req.arg[1] = mode | temp; err = qlcnic_issue_cmd(adapter, cmd); if (!err) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index 34d291168b79..4643b159df86 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -381,6 +381,8 @@ enum qlcnic_83xx_states { /* LED configuration settings */ #define QLC_83XX_ENABLE_BEACON 0xe +#define QLC_83XX_BEACON_ON 1 +#define QLC_83XX_BEACON_OFF 0 #define QLC_83XX_LED_RATE 0xff #define QLC_83XX_LED_ACT (1 << 10) #define QLC_83XX_LED_MOD (0 << 13) @@ -559,6 +561,7 @@ void qlcnic_83xx_napi_del(struct qlcnic_adapter *); void qlcnic_83xx_napi_enable(struct qlcnic_adapter *); void qlcnic_83xx_napi_disable(struct qlcnic_adapter *); int qlcnic_83xx_config_led(struct qlcnic_adapter *, u32, u32); +void qlcnic_83xx_get_beacon_state(struct qlcnic_adapter *); void qlcnic_ind_wr(struct qlcnic_adapter *, u32, u32); int qlcnic_ind_rd(struct qlcnic_adapter *, u32); int qlcnic_83xx_create_rx_ctx(struct qlcnic_adapter *); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c index 22ae884728b8..abe3924c61c5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c @@ -2214,6 +2214,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *adapter, int pci_using_dac) struct qlcnic_hardware_context *ahw = adapter->ahw; int err = 0; + adapter->rx_mac_learn = 0; ahw->msix_supported = !!qlcnic_use_msi_x; qlcnic_83xx_init_rings(adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c index 474320a5f0c1..23c4fd10e505 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_vnic.c @@ -224,10 +224,14 @@ int qlcnic_83xx_config_vnic_opmode(struct qlcnic_adapter *adapter) return -EIO; } - if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) + if (ahw->capabilities & QLC_83XX_ESWITCH_CAPABILITY) { adapter->flags |= QLCNIC_ESWITCH_ENABLED; - else + if (adapter->drv_mac_learn) + adapter->rx_mac_learn = 1; + } else { adapter->flags &= ~QLCNIC_ESWITCH_ENABLED; + adapter->rx_mac_learn = 0; + } ahw->idc.vnic_state = QLCNIC_DEV_NPAR_NON_OPER; ahw->idc.vnic_wait_limit = QLCNIC_DEV_NPAR_OPER_TIMEO; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index 45fa6eff56c9..18ced0fb6cf0 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -167,27 +167,35 @@ static const char qlcnic_gstrings_test[][ETH_GSTRING_LEN] = { #define QLCNIC_TEST_LEN ARRAY_SIZE(qlcnic_gstrings_test) -static inline int qlcnic_82xx_statistics(void) +static inline int qlcnic_82xx_statistics(struct qlcnic_adapter *adapter) { - return ARRAY_SIZE(qlcnic_device_gstrings_stats) + - ARRAY_SIZE(qlcnic_83xx_mac_stats_strings); + return ARRAY_SIZE(qlcnic_gstrings_stats) + + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) + + QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings; } -static inline int qlcnic_83xx_statistics(void) +static inline int qlcnic_83xx_statistics(struct qlcnic_adapter *adapter) { - return ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) + + return ARRAY_SIZE(qlcnic_gstrings_stats) + + ARRAY_SIZE(qlcnic_83xx_tx_stats_strings) + ARRAY_SIZE(qlcnic_83xx_mac_stats_strings) + - ARRAY_SIZE(qlcnic_83xx_rx_stats_strings); + ARRAY_SIZE(qlcnic_83xx_rx_stats_strings) + + QLCNIC_TX_STATS_LEN * adapter->drv_tx_rings; } static int qlcnic_dev_statistics_len(struct qlcnic_adapter *adapter) { - if (qlcnic_82xx_check(adapter)) - return qlcnic_82xx_statistics(); - else if (qlcnic_83xx_check(adapter)) - return qlcnic_83xx_statistics(); - else - return -1; + int len = -1; + + if (qlcnic_82xx_check(adapter)) { + len = qlcnic_82xx_statistics(adapter); + if (adapter->flags & QLCNIC_ESWITCH_ENABLED) + len += ARRAY_SIZE(qlcnic_device_gstrings_stats); + } else if (qlcnic_83xx_check(adapter)) { + len = qlcnic_83xx_statistics(adapter); + } + + return len; } #define QLCNIC_TX_INTR_NOT_CONFIGURED 0X78563412 @@ -923,18 +931,13 @@ static int qlcnic_eeprom_test(struct net_device *dev) static int qlcnic_get_sset_count(struct net_device *dev, int sset) { - int len; struct qlcnic_adapter *adapter = netdev_priv(dev); switch (sset) { case ETH_SS_TEST: return QLCNIC_TEST_LEN; case ETH_SS_STATS: - len = qlcnic_dev_statistics_len(adapter) + QLCNIC_STATS_LEN; - if ((adapter->flags & QLCNIC_ESWITCH_ENABLED) || - qlcnic_83xx_check(adapter)) - return len; - return qlcnic_82xx_statistics(); + return qlcnic_dev_statistics_len(adapter); default: return -EOPNOTSUPP; } @@ -1270,7 +1273,7 @@ static u64 *qlcnic_fill_stats(u64 *data, void *stats, int type) return data; } -static void qlcnic_update_stats(struct qlcnic_adapter *adapter) +void qlcnic_update_stats(struct qlcnic_adapter *adapter) { struct qlcnic_host_tx_ring *tx_ring; int ring; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index a9a149b82375..6ca5e57da3da 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -546,8 +546,11 @@ void __qlcnic_set_multi(struct net_device *netdev, u16 vlan) !adapter->fdb_mac_learn) { qlcnic_alloc_lb_filters_mem(adapter); adapter->drv_mac_learn = 1; + if (adapter->flags & QLCNIC_ESWITCH_ENABLED) + adapter->rx_mac_learn = 1; } else { adapter->drv_mac_learn = 0; + adapter->rx_mac_learn = 0; } qlcnic_nic_set_promisc(adapter, mode); @@ -779,8 +782,8 @@ void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter) "Could not send interrupt coalescing parameters\n"); } -#define QLCNIC_ENABLE_IPV4_LRO 1 -#define QLCNIC_ENABLE_IPV6_LRO 2 +#define QLCNIC_ENABLE_IPV4_LRO BIT_0 +#define QLCNIC_ENABLE_IPV6_LRO (BIT_1 | BIT_9) int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int enable) { @@ -1530,19 +1533,34 @@ int qlcnic_82xx_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) return rv; } -int qlcnic_get_beacon_state(struct qlcnic_adapter *adapter, u8 *h_state) +void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *adapter) { + struct qlcnic_hardware_context *ahw = adapter->ahw; struct qlcnic_cmd_args cmd; - int err; + u8 beacon_state; + int err = 0; - err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_GET_LED_STATUS); - if (!err) { - err = qlcnic_issue_cmd(adapter, &cmd); - if (!err) - *h_state = cmd.rsp.arg[1]; + if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { + err = qlcnic_alloc_mbx_args(&cmd, adapter, + QLCNIC_CMD_GET_LED_STATUS); + if (!err) { + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) { + netdev_err(adapter->netdev, + "Failed to get current beacon state, err=%d\n", + err); + } else { + beacon_state = cmd.rsp.arg[1]; + if (beacon_state == QLCNIC_BEACON_DISABLE) + ahw->beacon_state = QLCNIC_BEACON_OFF; + else if (beacon_state == QLCNIC_BEACON_EANBLE) + ahw->beacon_state = QLCNIC_BEACON_ON; + } + } + qlcnic_free_mbx_args(&cmd); } - qlcnic_free_mbx_args(&cmd); - return err; + + return; } void qlcnic_82xx_get_func_no(struct qlcnic_adapter *adapter) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 13303e7d1ed7..0e739aed1bc6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -169,6 +169,7 @@ int qlcnic_82xx_config_hw_lro(struct qlcnic_adapter *adapter, int); int qlcnic_82xx_nic_set_promisc(struct qlcnic_adapter *adapter, u32); int qlcnic_82xx_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev); +void qlcnic_82xx_get_beacon_state(struct qlcnic_adapter *); void qlcnic_82xx_change_filter(struct qlcnic_adapter *adapter, u64 *uaddr, u16 vlan_id); void qlcnic_82xx_config_intr_coalesce(struct qlcnic_adapter *adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c index 6373f6022486..2f967441e1a8 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c @@ -156,9 +156,9 @@ static inline void qlcnic_83xx_disable_tx_intr(struct qlcnic_adapter *adapter, writel(1, tx_ring->crb_intr_mask); } -static inline u8 qlcnic_mac_hash(u64 mac) +static inline u8 qlcnic_mac_hash(u64 mac, u16 vlan) { - return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff)); + return (u8)((mac & 0xff) ^ ((mac >> 40) & 0xff) ^ (vlan & 0xff)); } static inline u32 qlcnic_get_ref_handle(struct qlcnic_adapter *adapter, @@ -221,8 +221,11 @@ void qlcnic_add_lb_filter(struct qlcnic_adapter *adapter, struct sk_buff *skb, u8 hindex, op; int ret; + if (!qlcnic_sriov_pf_check(adapter) || (vlan_id == 0xffff)) + vlan_id = 0; + memcpy(&src_addr, phdr->h_source, ETH_ALEN); - hindex = qlcnic_mac_hash(src_addr) & + hindex = qlcnic_mac_hash(src_addr, vlan_id) & (adapter->fhash.fbucket_size - 1); if (loopback_pkt) { @@ -322,31 +325,47 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter, struct cmd_desc_type0 *first_desc, struct sk_buff *skb) { + struct vlan_ethhdr *vh = (struct vlan_ethhdr *)(skb->data); + struct ethhdr *phdr = (struct ethhdr *)(skb->data); + struct net_device *netdev = adapter->netdev; + u16 protocol = ntohs(skb->protocol); struct qlcnic_filter *fil, *tmp_fil; - struct hlist_node *n; struct hlist_head *head; - struct net_device *netdev = adapter->netdev; - struct ethhdr *phdr = (struct ethhdr *)(skb->data); + struct hlist_node *n; u64 src_addr = 0; u16 vlan_id = 0; - u8 hindex; + u8 hindex, hval; - if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) - return; + if (!qlcnic_sriov_pf_check(adapter)) { + if (ether_addr_equal(phdr->h_source, adapter->mac_addr)) + return; + } else { + if (protocol == ETH_P_8021Q) { + vh = (struct vlan_ethhdr *)skb->data; + vlan_id = ntohs(vh->h_vlan_TCI); + } else if (vlan_tx_tag_present(skb)) { + vlan_id = vlan_tx_tag_get(skb); + } + + if (ether_addr_equal(phdr->h_source, adapter->mac_addr) && + !vlan_id) + return; + } if (adapter->fhash.fnum >= adapter->fhash.fmax) { adapter->stats.mac_filter_limit_overrun++; - netdev_info(netdev, "Can not add more than %d mac addresses\n", - adapter->fhash.fmax); + netdev_info(netdev, "Can not add more than %d mac-vlan filters, configured %d\n", + adapter->fhash.fmax, adapter->fhash.fnum); return; } memcpy(&src_addr, phdr->h_source, ETH_ALEN); - hindex = qlcnic_mac_hash(src_addr) & (adapter->fhash.fbucket_size - 1); + hval = qlcnic_mac_hash(src_addr, vlan_id); + hindex = hval & (adapter->fhash.fbucket_size - 1); head = &(adapter->fhash.fhead[hindex]); hlist_for_each_entry_safe(tmp_fil, n, head, fnode) { - if (ether_addr_equal(tmp_fil->faddr, &src_addr) && + if (ether_addr_equal(tmp_fil->faddr, (u8 *)&src_addr) && tmp_fil->vlan_id == vlan_id) { if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime)) qlcnic_change_filter(adapter, &src_addr, @@ -1599,7 +1618,8 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, struct sk_buff *skb; struct qlcnic_host_rds_ring *rds_ring; int index, length, cksum, is_lb_pkt; - u16 vid = 0xffff, t_vid; + u16 vid = 0xffff; + int err; if (unlikely(ring >= adapter->max_rds_rings)) return NULL; @@ -1617,19 +1637,19 @@ qlcnic_83xx_process_rcv(struct qlcnic_adapter *adapter, if (!skb) return buffer; - if (adapter->drv_mac_learn && - (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { - t_vid = 0; - is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); - } - if (length > rds_ring->skb_size) skb_put(skb, rds_ring->skb_size); else skb_put(skb, length); - if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { + err = qlcnic_check_rx_tagging(adapter, skb, &vid); + + if (adapter->rx_mac_learn) { + is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 0); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); + } + + if (unlikely(err)) { adapter->stats.rxdropped++; dev_kfree_skb(skb); return buffer; @@ -1664,7 +1684,8 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, int l2_hdr_offset, l4_hdr_offset; int index, is_lb_pkt; u16 lro_length, length, data_offset, gso_size; - u16 vid = 0xffff, t_vid; + u16 vid = 0xffff; + int err; if (unlikely(ring > adapter->max_rds_rings)) return NULL; @@ -1686,12 +1707,6 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, if (!skb) return buffer; - if (adapter->drv_mac_learn && - (adapter->flags & QLCNIC_ESWITCH_ENABLED)) { - t_vid = 0; - is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); - qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, t_vid); - } if (qlcnic_83xx_is_tstamp(sts_data[1])) data_offset = l4_hdr_offset + QLCNIC_TCP_TS_HDR_SIZE; else @@ -1700,7 +1715,14 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter, skb_put(skb, lro_length + data_offset); skb_pull(skb, l2_hdr_offset); - if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) { + err = qlcnic_check_rx_tagging(adapter, skb, &vid); + + if (adapter->rx_mac_learn) { + is_lb_pkt = qlcnic_83xx_is_lb_pkt(sts_data[1], 1); + qlcnic_add_lb_filter(adapter, skb, is_lb_pkt, vid); + } + + if (unlikely(err)) { adapter->stats.rxdropped++; dev_kfree_skb(skb); return buffer; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index eeec83a0e664..eec7b412477c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -546,6 +546,7 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { .io_error_detected = qlcnic_82xx_io_error_detected, .io_slot_reset = qlcnic_82xx_io_slot_reset, .io_resume = qlcnic_82xx_io_resume, + .get_beacon_state = qlcnic_82xx_get_beacon_state, }; static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter) @@ -2779,6 +2780,9 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev) struct qlcnic_adapter *adapter = netdev_priv(netdev); struct net_device_stats *stats = &netdev->stats; + if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) + qlcnic_update_stats(adapter); + stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts; stats->tx_packets = adapter->stats.xmitfinished; stats->rx_bytes = adapter->stats.rxbytes + adapter->stats.lrobytes; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index bf8fca7d874f..f998fdcd7551 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -277,9 +277,7 @@ static void qlcnic_sriov_vf_cleanup(struct qlcnic_adapter *adapter) void qlcnic_sriov_cleanup(struct qlcnic_adapter *adapter) { - struct qlcnic_sriov *sriov = adapter->ahw->sriov; - - if (!sriov) + if (!test_bit(__QLCNIC_SRIOV_ENABLE, &adapter->state)) return; qlcnic_sriov_free_vlans(adapter); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index d14d9a139eef..09acf15c3a56 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -9,9 +9,14 @@ #include "qlcnic.h" #include <linux/types.h> -#define QLCNIC_SRIOV_VF_MAX_MAC 8 +#define QLCNIC_SRIOV_VF_MAX_MAC 7 #define QLC_VF_MIN_TX_RATE 100 #define QLC_VF_MAX_TX_RATE 9999 +#define QLC_MAC_OPCODE_MASK 0x7 +#define QLC_MAC_STAR_ADD 6 +#define QLC_MAC_STAR_DEL 7 +#define QLC_VF_FLOOD_BIT BIT_16 +#define QLC_FLOOD_MODE 0x5 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); @@ -344,6 +349,28 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter, return err; } +/* On configuring VF flood bit, PFD will receive traffic from all VFs */ +static int qlcnic_sriov_pf_cfg_flood(struct qlcnic_adapter *adapter) +{ + struct qlcnic_cmd_args cmd; + int err; + + err = qlcnic_alloc_mbx_args(&cmd, adapter, QLCNIC_CMD_SET_NIC_INFO); + if (err) + return err; + + cmd.req.arg[1] = QLC_FLOOD_MODE | QLC_VF_FLOOD_BIT; + + err = qlcnic_issue_cmd(adapter, &cmd); + if (err) + dev_err(&adapter->pdev->dev, + "Failed to configure VF Flood bit on PF, err=%d\n", + err); + + qlcnic_free_mbx_args(&cmd); + return err; +} + static int qlcnic_sriov_pf_cfg_eswitch(struct qlcnic_adapter *adapter, u8 func, u8 enable) { @@ -471,6 +498,12 @@ static int qlcnic_sriov_pf_init(struct qlcnic_adapter *adapter) if (err) return err; + if (qlcnic_84xx_check(adapter)) { + err = qlcnic_sriov_pf_cfg_flood(adapter); + if (err) + goto disable_vlan_filtering; + } + err = qlcnic_sriov_pf_cfg_eswitch(adapter, func, 1); if (err) goto disable_vlan_filtering; @@ -1173,6 +1206,13 @@ static int qlcnic_sriov_validate_cfg_macvlan(struct qlcnic_adapter *adapter, struct qlcnic_vport *vp = vf->vp; u8 op, new_op; + if (((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_ADD) || + ((cmd->req.arg[1] & QLC_MAC_OPCODE_MASK) == QLC_MAC_STAR_DEL)) { + netdev_err(adapter->netdev, "MAC + any VLAN filter not allowed from VF %d\n", + vf->pci_func); + return -EINVAL; + } + if (!(cmd->req.arg[1] & BIT_8)) return -EINVAL; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c index b5296672c447..1c8552f682d6 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -6,7 +6,6 @@ */ #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/interrupt.h> #include "qlcnic.h" @@ -127,6 +126,8 @@ static int qlcnic_83xx_store_beacon(struct qlcnic_adapter *adapter, if (kstrtoul(buf, 2, &h_beacon)) return -EINVAL; + qlcnic_get_beacon_state(adapter); + if (ahw->beacon_state == h_beacon) return len; @@ -158,7 +159,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter, struct qlcnic_hardware_context *ahw = adapter->ahw; int err, drv_sds_rings = adapter->drv_sds_rings; u16 beacon; - u8 h_beacon_state, b_state, b_rate; + u8 b_state, b_rate; if (len != sizeof(u16)) return QL_STATUS_INVALID_PARAM; @@ -168,18 +169,7 @@ static int qlcnic_82xx_store_beacon(struct qlcnic_adapter *adapter, if (err) return err; - if (ahw->extra_capability[0] & QLCNIC_FW_CAPABILITY_2_BEACON) { - err = qlcnic_get_beacon_state(adapter, &h_beacon_state); - if (err) { - netdev_err(adapter->netdev, - "Failed to get current beacon state\n"); - } else { - if (h_beacon_state == QLCNIC_BEACON_DISABLE) - ahw->beacon_state = 0; - else if (h_beacon_state == QLCNIC_BEACON_EANBLE) - ahw->beacon_state = 2; - } - } + qlcnic_get_beacon_state(adapter); if (ahw->beacon_state == b_state) return len; @@ -927,38 +917,35 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_pci_func_cfg *pci_cfg; struct qlcnic_pci_info *pci_info; - size_t pci_info_sz, pci_cfg_sz; + size_t pci_cfg_sz; int i, ret; pci_cfg_sz = pci_func_count * sizeof(*pci_cfg); if (size != pci_cfg_sz) return QL_STATUS_INVALID_PARAM; - pci_info_sz = pci_func_count * sizeof(*pci_info); - pci_info = vmalloc(pci_info_sz); + pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL); if (!pci_info) return -ENOMEM; - memset(pci_info, 0, pci_info_sz); - memset(buf, 0, pci_cfg_sz); - pci_cfg = (struct qlcnic_pci_func_cfg *)buf; - ret = qlcnic_get_pci_info(adapter, pci_info); if (ret) { - vfree(pci_info); + kfree(pci_info); return ret; } + pci_cfg = (struct qlcnic_pci_func_cfg *)buf; for (i = 0; i < pci_func_count; i++) { pci_cfg[i].pci_func = pci_info[i].id; pci_cfg[i].func_type = pci_info[i].type; + pci_cfg[i].func_state = 0; pci_cfg[i].port_num = pci_info[i].default_port; pci_cfg[i].min_bw = pci_info[i].tx_min_bw; pci_cfg[i].max_bw = pci_info[i].tx_max_bw; memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN); } - vfree(pci_info); + kfree(pci_info); return size; } diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 888410737dbd..ba1f6c928b91 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1513,11 +1513,11 @@ ignore_link: if (intr_status & mask) { /* Tx error */ u32 edtrr = sh_eth_read(ndev, EDTRR); + /* dmesg */ - dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x ", - intr_status, mdp->cur_tx); - dev_err(&ndev->dev, "dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", - mdp->dirty_tx, (u32) ndev->state, edtrr); + dev_err(&ndev->dev, "TX error. status=%8.8x cur_tx=%8.8x dirty_tx=%8.8x state=%8.8x EDTRR=%8.8x.\n", + intr_status, mdp->cur_tx, mdp->dirty_tx, + (u32)ndev->state, edtrr); /* dirty buffer free */ sh_eth_txfree(ndev); diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c index 96f79f7c4395..a6a9e1ebe30c 100644 --- a/drivers/net/ethernet/smsc/smc91x.c +++ b/drivers/net/ethernet/smsc/smc91x.c @@ -1894,7 +1894,7 @@ static int smc_probe(struct net_device *dev, void __iomem *ioaddr, SMC_SELECT_BANK(lp, 1); val = SMC_GET_BASE(lp); val = ((val & 0x1F00) >> 3) << SMC_IO_SHIFT; - if (((unsigned int)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) { + if (((unsigned long)ioaddr & (0x3e0 << SMC_IO_SHIFT)) != val) { netdev_warn(dev, "%s: IOADDR %p doesn't match configuration (%x).\n", CARDNAME, ioaddr, val); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index b8e3a4ce24b0..ecdc8ab50425 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1951,6 +1951,23 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static void stmmac_rx_vlan(struct net_device *dev, struct sk_buff *skb) +{ + struct ethhdr *ehdr; + u16 vlanid; + + if ((dev->features & NETIF_F_HW_VLAN_CTAG_RX) == + NETIF_F_HW_VLAN_CTAG_RX && + !__vlan_get_tag(skb, &vlanid)) { + /* pop the vlan tag */ + ehdr = (struct ethhdr *)skb->data; + memmove(skb->data + VLAN_HLEN, ehdr, ETH_ALEN * 2); + skb_pull(skb, VLAN_HLEN); + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid); + } +} + + /** * stmmac_rx_refill: refill used skb preallocated buffers * @priv: driver private structure @@ -2102,6 +2119,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit) print_pkt(skb->data, frame_len); } + stmmac_rx_vlan(priv->dev, skb); + skb->protocol = eth_type_trans(skb, priv->dev); if (unlikely(!coe)) diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c index 4f1d2549130e..2ead87759ab4 100644 --- a/drivers/net/ethernet/tehuti/tehuti.c +++ b/drivers/net/ethernet/tehuti/tehuti.c @@ -1764,7 +1764,7 @@ static void bdx_tx_cleanup(struct bdx_priv *priv) WRITE_REG(priv, f->m.reg_RPTR, f->m.rptr & TXF_WPTR_WR_PTR); /* We reclaimed resources, so in case the Q is stopped by xmit callback, - * we resume the transmition and use tx_lock to synchronize with xmit.*/ + * we resume the transmission and use tx_lock to synchronize with xmit.*/ spin_lock(&priv->tx_lock); priv->tx_level += tx_level; BDX_ASSERT(priv->tx_level <= 0 || priv->tx_level > BDX_MAX_TX_LEVEL); diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 570495be77f3..023237a65720 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -2070,7 +2070,8 @@ static int tile_net_tx(struct sk_buff *skb, struct net_device *dev) } /* Return subqueue id on this core (one per core). */ -static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 tile_net_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { return smp_processor_id(); } diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 09ababe54a5b..8433de4509c7 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -299,7 +299,7 @@ static netdev_tx_t macvlan_start_xmit(struct sk_buff *skb, if (vlan->fwd_priv) { skb->dev = vlan->lowerdev; - ret = dev_hard_start_xmit(skb, skb->dev, NULL, vlan->fwd_priv); + ret = dev_queue_xmit_accel(skb, vlan->fwd_priv); } else { ret = macvlan_queue_xmit(skb, dev); } @@ -337,6 +337,8 @@ static const struct header_ops macvlan_hard_header_ops = { .cache_update = eth_header_cache_update, }; +static struct rtnl_link_ops macvlan_link_ops; + static int macvlan_open(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); @@ -352,7 +354,8 @@ static int macvlan_open(struct net_device *dev) goto hash_add; } - if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD) { + if (lowerdev->features & NETIF_F_HW_L2FW_DOFFLOAD && + dev->rtnl_link_ops == &macvlan_link_ops) { vlan->fwd_priv = lowerdev->netdev_ops->ndo_dfwd_add_station(lowerdev, dev); @@ -361,10 +364,8 @@ static int macvlan_open(struct net_device *dev) */ if (IS_ERR_OR_NULL(vlan->fwd_priv)) { vlan->fwd_priv = NULL; - } else { - dev->features &= ~NETIF_F_LLTX; + } else return 0; - } } err = -EBUSY; @@ -698,8 +699,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev, features = netdev_increment_features(vlan->lowerdev->features, features, mask); - if (!vlan->fwd_priv) - features |= NETIF_F_LLTX; + features |= NETIF_F_LLTX; return features; } diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 5d81c89ee52b..39794c4d7b21 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -30,6 +30,7 @@ #include <linux/mii.h> #include <linux/ethtool.h> #include <linux/phy.h> +#include <linux/mdio.h> #include <linux/io.h> #include <linux/uaccess.h> @@ -50,14 +51,17 @@ static void phy_device_release(struct device *dev) kfree(to_phy_device(dev)); } -static struct phy_driver genphy_driver; +enum genphy_driver { + GENPHY_DRV_1G, + GENPHY_DRV_10G, + GENPHY_DRV_MAX +}; + +static struct phy_driver genphy_driver[GENPHY_DRV_MAX]; static LIST_HEAD(phy_fixup_list); static DEFINE_MUTEX(phy_fixup_lock); -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface); - /** * phy_register_fixup - creates a new phy_fixup and adds it to the list * @bus_id: A string which matches phydev->dev.bus_id (or PHY_ANY_ID) @@ -560,13 +564,13 @@ EXPORT_SYMBOL(phy_init_hw); * * Description: Called by drivers to attach to a particular PHY * device. The phy_device is found, and properly hooked up - * to the phy_driver. If no driver is attached, then the - * genphy_driver is used. The phy_device is given a ptr to + * to the phy_driver. If no driver is attached, then a + * generic driver is used. The phy_device is given a ptr to * the attaching device, and given a callback for link status * change. The phy_device is returned to the attaching driver. */ -static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface) +int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, + u32 flags, phy_interface_t interface) { struct device *d = &phydev->dev; int err; @@ -575,12 +579,10 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, * exist, and we should use the genphy driver. */ if (NULL == d->driver) { - if (phydev->is_c45) { - pr_err("No driver for phy %x\n", phydev->phy_id); - return -ENODEV; - } - - d->driver = &genphy_driver.driver; + if (phydev->is_c45) + d->driver = &genphy_driver[GENPHY_DRV_10G].driver; + else + d->driver = &genphy_driver[GENPHY_DRV_1G].driver; err = d->driver->probe(d); if (err >= 0) @@ -616,6 +618,7 @@ static int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, return err; } +EXPORT_SYMBOL(phy_attach_direct); /** * phy_attach - attach a network device to a particular PHY device @@ -658,6 +661,7 @@ EXPORT_SYMBOL(phy_attach); */ void phy_detach(struct phy_device *phydev) { + int i; phydev->attached_dev->phydev = NULL; phydev->attached_dev = NULL; phy_suspend(phydev); @@ -667,8 +671,12 @@ void phy_detach(struct phy_device *phydev) * from the generic driver so that there's a chance a * real driver could be loaded */ - if (phydev->dev.driver == &genphy_driver.driver) - device_release_driver(&phydev->dev); + for (i = 0; i < ARRAY_SIZE(genphy_driver); i++) { + if (phydev->dev.driver == &genphy_driver[i].driver) { + device_release_driver(&phydev->dev); + break; + } + } } EXPORT_SYMBOL(phy_detach); @@ -759,6 +767,12 @@ static int genphy_config_advert(struct phy_device *phydev) return changed; } +int gen10g_config_advert(struct phy_device *dev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_config_advert); + /** * genphy_setup_forced - configures/forces speed/duplex from @phydev * @phydev: target phy_device struct @@ -806,6 +820,12 @@ int genphy_restart_aneg(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_restart_aneg); +int gen10g_restart_aneg(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_restart_aneg); + /** * genphy_config_aneg - restart auto-negotiation or write BMCR * @phydev: target phy_device struct @@ -847,6 +867,12 @@ int genphy_config_aneg(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_aneg); +int gen10g_config_aneg(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_config_aneg); + /** * genphy_update_link - update link status in @phydev * @phydev: target phy_device struct @@ -978,6 +1004,34 @@ int genphy_read_status(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_read_status); +int gen10g_read_status(struct phy_device *phydev) +{ + int devad, reg; + u32 mmd_mask = phydev->c45_ids.devices_in_package; + + phydev->link = 1; + + /* For now just lie and say it's 10G all the time */ + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + for (devad = 0; mmd_mask; devad++, mmd_mask = mmd_mask >> 1) { + if (!(mmd_mask & 1)) + continue; + + /* Read twice because link state is latched and a + * read moves the current state into the register + */ + phy_read_mmd(phydev, devad, MDIO_STAT1); + reg = phy_read_mmd(phydev, devad, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} +EXPORT_SYMBOL(gen10g_read_status); + static int genphy_config_init(struct phy_device *phydev) { int val; @@ -1023,6 +1077,16 @@ static int genphy_config_init(struct phy_device *phydev) return 0; } + +static int gen10g_config_init(struct phy_device *phydev) +{ + /* Temporarily just say we support everything */ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + int genphy_suspend(struct phy_device *phydev) { int value; @@ -1038,6 +1102,12 @@ int genphy_suspend(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_suspend); +int gen10g_suspend(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_suspend); + int genphy_resume(struct phy_device *phydev) { int value; @@ -1053,6 +1123,12 @@ int genphy_resume(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_resume); +int gen10g_resume(struct phy_device *phydev) +{ + return 0; +} +EXPORT_SYMBOL(gen10g_resume); + /** * phy_probe - probe and init a PHY device * @dev: device to probe and init @@ -1173,7 +1249,8 @@ void phy_drivers_unregister(struct phy_driver *drv, int n) } EXPORT_SYMBOL(phy_drivers_unregister); -static struct phy_driver genphy_driver = { +static struct phy_driver genphy_driver[] = { +{ .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, .name = "Generic PHY", @@ -1184,7 +1261,18 @@ static struct phy_driver genphy_driver = { .suspend = genphy_suspend, .resume = genphy_resume, .driver = { .owner = THIS_MODULE, }, -}; +}, { + .phy_id = 0xffffffff, + .phy_id_mask = 0xffffffff, + .name = "Generic 10G PHY", + .config_init = gen10g_config_init, + .features = 0, + .config_aneg = gen10g_config_aneg, + .read_status = gen10g_read_status, + .suspend = gen10g_suspend, + .resume = gen10g_resume, + .driver = {.owner = THIS_MODULE, }, +} }; static int __init phy_init(void) { @@ -1194,7 +1282,8 @@ static int __init phy_init(void) if (rc) return rc; - rc = phy_driver_register(&genphy_driver); + rc = phy_drivers_register(genphy_driver, + ARRAY_SIZE(genphy_driver)); if (rc) mdio_bus_exit(); @@ -1203,7 +1292,8 @@ static int __init phy_init(void) static void __exit phy_exit(void) { - phy_driver_unregister(&genphy_driver); + phy_drivers_unregister(genphy_driver, + ARRAY_SIZE(genphy_driver)); mdio_bus_exit(); } diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 736050d6b451..b75ae5bde673 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1647,7 +1647,8 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { /* * This helper function exists to help dev_pick_tx get the correct diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 09f66624eaca..34cca74c99ed 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -364,7 +364,8 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) * different rxq no. here. If we could not get rxhash, then we would * hope the rxq no. may help here. */ -static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { struct tun_struct *tun = netdev_priv(dev); struct tun_flow_entry *e; diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 47b0f732b0b1..6b638a066c1d 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -92,11 +92,12 @@ config USB_RTL8150 module will be called rtl8150. config USB_RTL8152 - tristate "Realtek RTL8152 Based USB 2.0 Ethernet Adapters" + tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" select MII help This option adds support for Realtek RTL8152 based USB 2.0 - 10/100 Ethernet adapters. + 10/100 Ethernet adapters and RTL8153 based USB 3.0 10/100/1000 + Ethernet adapters. To compile this driver as a module, choose M here: the module will be called r8152. diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 640406ac4358..7d32be89e3ca 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -653,15 +653,6 @@ static const struct usb_device_id products[] = { .driver_info = 0, }, -#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE) -/* Samsung USB Ethernet Adapters */ -{ - USB_DEVICE_AND_INTERFACE_INFO(SAMSUNG_VENDOR_ID, 0xa101, USB_CLASS_COMM, - USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), - .driver_info = 0, -}, -#endif - /* WHITELIST!!! * * CDC Ether uses two interfaces, not necessarily consecutive. diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index bf7d549ab511..31d13ca1a39e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Realtek Semiconductor Corp. All rights reserved. + * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -24,9 +24,9 @@ #include <linux/ipv6.h> /* Version Information */ -#define DRIVER_VERSION "v1.03.0 (2013/12/26)" +#define DRIVER_VERSION "v1.04.0 (2014/01/15)" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" -#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters" +#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" #define R8152_PHY_ID 32 @@ -450,6 +450,9 @@ enum rtl8152_flags { #define MCU_TYPE_PLA 0x0100 #define MCU_TYPE_USB 0x0000 +#define REALTEK_USB_DEVICE(vend, prod) \ + USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC) + struct rx_desc { __le32 opts1; #define RX_LEN_MASK 0x7fff @@ -1100,40 +1103,28 @@ static void free_all_mem(struct r8152 *tp) int i; for (i = 0; i < RTL8152_MAX_RX; i++) { - if (tp->rx_info[i].urb) { - usb_free_urb(tp->rx_info[i].urb); - tp->rx_info[i].urb = NULL; - } + usb_free_urb(tp->rx_info[i].urb); + tp->rx_info[i].urb = NULL; - if (tp->rx_info[i].buffer) { - kfree(tp->rx_info[i].buffer); - tp->rx_info[i].buffer = NULL; - tp->rx_info[i].head = NULL; - } + kfree(tp->rx_info[i].buffer); + tp->rx_info[i].buffer = NULL; + tp->rx_info[i].head = NULL; } for (i = 0; i < RTL8152_MAX_TX; i++) { - if (tp->tx_info[i].urb) { - usb_free_urb(tp->tx_info[i].urb); - tp->tx_info[i].urb = NULL; - } + usb_free_urb(tp->tx_info[i].urb); + tp->tx_info[i].urb = NULL; - if (tp->tx_info[i].buffer) { - kfree(tp->tx_info[i].buffer); - tp->tx_info[i].buffer = NULL; - tp->tx_info[i].head = NULL; - } + kfree(tp->tx_info[i].buffer); + tp->tx_info[i].buffer = NULL; + tp->tx_info[i].head = NULL; } - if (tp->intr_urb) { - usb_free_urb(tp->intr_urb); - tp->intr_urb = NULL; - } + usb_free_urb(tp->intr_urb); + tp->intr_urb = NULL; - if (tp->intr_buff) { - kfree(tp->intr_buff); - tp->intr_buff = NULL; - } + kfree(tp->intr_buff); + tp->intr_buff = NULL; } static int alloc_all_mem(struct r8152 *tp) @@ -2048,7 +2039,7 @@ static void r8153_first_init(struct r8152 *tp) /* TX share fifo free credit full threshold */ ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); - // rx aggregation + /* rx aggregation */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); ocp_data &= ~RX_AGG_DISABLE; ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); @@ -2750,11 +2741,6 @@ static int rtl8152_probe(struct usb_interface *intf, struct net_device *netdev; int ret; - if (udev->actconfig->desc.bConfigurationValue != 1) { - usb_driver_set_configuration(udev, 1); - return -ENODEV; - } - netdev = alloc_etherdev(sizeof(struct r8152)); if (!netdev) { dev_err(&intf->dev, "Out of memory\n"); @@ -2835,9 +2821,9 @@ static void rtl8152_disconnect(struct usb_interface *intf) /* table of devices that work with this driver */ static struct usb_device_id rtl8152_table[] = { - {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, - {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)}, - {USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)}, + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)}, + {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)}, {} }; diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c index 5fd2ca61d1e2..f0a8791b7636 100644 --- a/drivers/net/usb/r815x.c +++ b/drivers/net/usb/r815x.c @@ -216,21 +216,13 @@ static const struct usb_device_id products[] = { { USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), -#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE) - .driver_info = 0, -#else .driver_info = (unsigned long) &r8152_info, -#endif }, { USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), -#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE) - .driver_info = 0, -#else .driver_info = (unsigned long) &r8153_info, -#endif }, { }, /* END */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 56c175ebae3c..4671da755e7b 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1244,7 +1244,7 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) return -ENOMEM; urb->num_sgs = num_sgs; - sg_init_table(urb->sg, urb->num_sgs); + sg_init_table(urb->sg, urb->num_sgs + 1); sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); total_len += skb_headlen(skb); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 481f85d604a4..a2dee80e1fb8 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -741,10 +741,9 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, if (nla_len(tb[NDA_IFINDEX]) != sizeof(u32)) return -EINVAL; *ifindex = nla_get_u32(tb[NDA_IFINDEX]); - tdev = dev_get_by_index(net, *ifindex); + tdev = __dev_get_by_index(net, *ifindex); if (!tdev) return -EADDRNOTAVAIL; - dev_put(tdev); } else { *ifindex = 0; } @@ -2656,6 +2655,44 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = { .fill_info = vxlan_fill_info, }; +static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn, + struct net_device *dev) +{ + struct vxlan_dev *vxlan, *next; + LIST_HEAD(list_kill); + + list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) { + struct vxlan_rdst *dst = &vxlan->default_dst; + + /* In case we created vxlan device with carrier + * and we loose the carrier due to module unload + * we also need to remove vxlan device. In other + * cases, it's not necessary and remote_ifindex + * is 0 here, so no matches. + */ + if (dst->remote_ifindex == dev->ifindex) + vxlan_dellink(vxlan->dev, &list_kill); + } + + unregister_netdevice_many(&list_kill); +} + +static int vxlan_lowerdev_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); + + if (event == NETDEV_UNREGISTER) + vxlan_handle_lowerdev_unregister(vn, dev); + + return NOTIFY_DONE; +} + +static struct notifier_block vxlan_notifier_block __read_mostly = { + .notifier_call = vxlan_lowerdev_event, +}; + static __net_init int vxlan_init_net(struct net *net) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); @@ -2673,13 +2710,13 @@ static __net_init int vxlan_init_net(struct net *net) static __net_exit void vxlan_exit_net(struct net *net) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); - struct vxlan_dev *vxlan; - LIST_HEAD(list); + struct vxlan_dev *vxlan, *next; + LIST_HEAD(list_kill); rtnl_lock(); - list_for_each_entry(vxlan, &vn->vxlan_list, next) - unregister_netdevice_queue(vxlan->dev, &list); - unregister_netdevice_many(&list); + list_for_each_entry_safe(vxlan, next, &vn->vxlan_list, next) + vxlan_dellink(vxlan->dev, &list_kill); + unregister_netdevice_many(&list_kill); rtnl_unlock(); } @@ -2704,12 +2741,17 @@ static int __init vxlan_init_module(void) if (rc) goto out1; - rc = rtnl_link_register(&vxlan_link_ops); + rc = register_netdevice_notifier(&vxlan_notifier_block); if (rc) goto out2; - return 0; + rc = rtnl_link_register(&vxlan_link_ops); + if (rc) + goto out3; + return 0; +out3: + unregister_netdevice_notifier(&vxlan_notifier_block); out2: unregister_pernet_device(&vxlan_net_ops); out1: @@ -2721,6 +2763,7 @@ late_initcall(vxlan_init_module); static void __exit vxlan_cleanup_module(void) { rtnl_link_unregister(&vxlan_link_ops); + unregister_netdevice_notifier(&vxlan_notifier_block); destroy_workqueue(vxlan_wq); unregister_pernet_device(&vxlan_net_ops); rcu_barrier(); diff --git a/drivers/net/wan/hd64570.h b/drivers/net/wan/hd64570.h index e4f539ad071b..10963e8f4b39 100644 --- a/drivers/net/wan/hd64570.h +++ b/drivers/net/wan/hd64570.h @@ -159,7 +159,7 @@ typedef struct { /* Packet Descriptor Status bits */ #define ST_TX_EOM 0x80 /* End of frame */ -#define ST_TX_EOT 0x01 /* End of transmition */ +#define ST_TX_EOT 0x01 /* End of transmission */ #define ST_RX_EOM 0x80 /* End of frame */ #define ST_RX_SHORT 0x40 /* Short frame */ @@ -211,7 +211,7 @@ typedef struct { #define CTL_NORTS 0x01 #define CTL_IDLE 0x10 /* Transmit an idle pattern */ -#define CTL_UDRNC 0x20 /* Idle after CRC or FCS+flag transmition */ +#define CTL_UDRNC 0x20 /* Idle after CRC or FCS+flag transmission */ #define ST0_TXRDY 0x02 /* TX ready */ #define ST0_RXRDY 0x01 /* RX ready */ diff --git a/drivers/net/wan/hd64572.h b/drivers/net/wan/hd64572.h index 96567c2dc4db..22137ee669cf 100644 --- a/drivers/net/wan/hd64572.h +++ b/drivers/net/wan/hd64572.h @@ -218,7 +218,7 @@ typedef struct { #define ST_TX_EOM 0x80 /* End of frame */ #define ST_TX_UNDRRUN 0x08 #define ST_TX_OWNRSHP 0x02 -#define ST_TX_EOT 0x01 /* End of transmition */ +#define ST_TX_EOT 0x01 /* End of transmission */ #define ST_RX_EOM 0x80 /* End of frame */ #define ST_RX_SHORT 0x40 /* Short frame */ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index 1d40c69cc4a9..55eda7afc041 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -15,7 +15,6 @@ * more details. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/if.h> #include <linux/skbuff.h> diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c index 14128fd265ac..7e9ede6c5798 100644 --- a/drivers/net/wireless/airo_cs.c +++ b/drivers/net/wireless/airo_cs.c @@ -23,7 +23,6 @@ #ifdef __IN_PCMCIA_PACKAGE__ #include <pcmcia/k_compat.h> #endif -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/ptrace.h> diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c index 34c8a33cac06..031d4ec64779 100644 --- a/drivers/net/wireless/at76c50x-usb.c +++ b/drivers/net/wireless/at76c50x-usb.c @@ -1721,7 +1721,7 @@ static void at76_mac80211_tx(struct ieee80211_hw *hw, * following workaround is necessary. If the TX frame is an * authentication frame extract the bssid and send the CMD_JOIN. */ if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) { - if (!ether_addr_equal(priv->bssid, mgmt->bssid)) { + if (!ether_addr_equal_64bits(priv->bssid, mgmt->bssid)) { memcpy(priv->bssid, mgmt->bssid, ETH_ALEN); ieee80211_queue_work(hw, &priv->work_join_bssid); dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/ath/ar5523/ar5523.c b/drivers/net/wireless/ath/ar5523/ar5523.c index 280fc3d53a36..8aa20df55e50 100644 --- a/drivers/net/wireless/ath/ar5523/ar5523.c +++ b/drivers/net/wireless/ath/ar5523/ar5523.c @@ -25,7 +25,6 @@ * that and only has minimal functionality. */ #include <linux/compiler.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/list.h> diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index 69f58b073e85..6396ad4bce67 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -1245,7 +1245,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb, if (ieee80211_is_beacon(mgmt->frame_control) && le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS && - ether_addr_equal(mgmt->bssid, common->curbssid)) { + ether_addr_equal_64bits(mgmt->bssid, common->curbssid)) { /* * Received an IBSS beacon with the same BSSID. Hardware *must* * have updated the local TSF. We have to work around various @@ -1309,7 +1309,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi) /* only beacons from our BSSID */ if (!ieee80211_is_beacon(mgmt->frame_control) || - !ether_addr_equal(mgmt->bssid, common->curbssid)) + !ether_addr_equal_64bits(mgmt->bssid, common->curbssid)) return; ewma_add(&ah->ah_beacon_rssi_avg, rssi); diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index 149aba3c7298..d480d2f3e185 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -383,6 +383,20 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah) } } +static void ar9002_hw_init_hang_checks(struct ath_hw *ah) +{ + if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) { + ah->config.hw_hang_checks |= HW_BB_RIFS_HANG; + ah->config.hw_hang_checks |= HW_BB_DFS_HANG; + } + + if (AR_SREV_9280(ah)) + ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG; + + if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah)) + ah->config.hw_hang_checks |= HW_MAC_HANG; +} + /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */ int ar9002_hw_attach_ops(struct ath_hw *ah) { @@ -395,6 +409,7 @@ int ar9002_hw_attach_ops(struct ath_hw *ah) return ret; priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs; + priv_ops->init_hang_checks = ar9002_hw_init_hang_checks; ops->config_pci_powersave = ar9002_hw_configpcipowersave; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index 97e09d5f3a42..8c145cd98c1c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -326,6 +326,224 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah) ah->supp_cals = IQ_MISMATCH_CAL; } +#define OFF_UPPER_LT 24 +#define OFF_LOWER_LT 7 + +static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah, + bool txiqcal_done) +{ + struct ath_common *common = ath9k_hw_common(ah); + int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2, + dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3; + int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2, + dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3; + int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2, + dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3; + bool status; + u32 temp, val; + + /* + * Clear offset and IQ calibration, run AGC cal. + */ + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_OFFSET_CAL); + REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); + + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "AGC cal without offset cal failed to complete in 1ms"); + return false; + } + + /* + * Allow only offset calibration and disable the others + * (Carrier Leak calibration, TX Filter calibration and + * Peak Detector offset calibration). + */ + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_OFFSET_CAL); + REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, + AR_PHY_CL_CAL_ENABLE); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_FLTR_CAL); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_PKDET_CAL); + + ch0_done = 0; + ch1_done = 0; + ch2_done = 0; + + while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) { + osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3; + osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3; + osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3; + + REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL); + + status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_CAL, + 0, AH_WAIT_TIMEOUT); + if (!status) { + ath_dbg(common, CALIBRATE, + "DC offset cal failed to complete in 1ms"); + return false; + } + + REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * High gain. + */ + REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8))); + + temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); + dc_off_ch0_i1 = (temp >> 26) & 0x1f; + dc_off_ch0_q1 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); + dc_off_ch1_i1 = (temp >> 26) & 0x1f; + dc_off_ch1_q1 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); + dc_off_ch2_i1 = (temp >> 26) & 0x1f; + dc_off_ch2_q1 = (temp >> 21) & 0x1f; + + /* + * Low gain. + */ + REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8))); + + temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); + dc_off_ch0_i2 = (temp >> 26) & 0x1f; + dc_off_ch0_q2 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); + dc_off_ch1_i2 = (temp >> 26) & 0x1f; + dc_off_ch1_q2 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); + dc_off_ch2_i2 = (temp >> 26) & 0x1f; + dc_off_ch2_q2 = (temp >> 21) & 0x1f; + + /* + * Loopback. + */ + REG_WRITE(ah, AR_PHY_65NM_CH0_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8))); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB3, + ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8))); + + temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3); + dc_off_ch0_i3 = (temp >> 26) & 0x1f; + dc_off_ch0_q3 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3); + dc_off_ch1_i3 = (temp >> 26) & 0x1f; + dc_off_ch1_q3 = (temp >> 21) & 0x1f; + + temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3); + dc_off_ch2_i3 = (temp >> 26) & 0x1f; + dc_off_ch2_q3 = (temp >> 21) & 0x1f; + + if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) || + (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) || + (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) || + (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) || + (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) || + (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) { + if (osdac_ch0 == 3) { + ch0_done = 1; + } else { + osdac_ch0++; + + val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff; + val |= (osdac_ch0 << 30); + REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val); + + ch0_done = 0; + } + } else { + ch0_done = 1; + } + + if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) || + (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) || + (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) || + (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) || + (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) || + (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) { + if (osdac_ch1 == 3) { + ch1_done = 1; + } else { + osdac_ch1++; + + val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff; + val |= (osdac_ch1 << 30); + REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val); + + ch1_done = 0; + } + } else { + ch1_done = 1; + } + + if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) || + (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) || + (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) || + (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) || + (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) || + (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) { + if (osdac_ch2 == 3) { + ch2_done = 1; + } else { + osdac_ch2++; + + val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff; + val |= (osdac_ch2 << 30); + REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val); + + ch2_done = 0; + } + } else { + ch2_done = 1; + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_OFFSET_CAL); + REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + + /* + * We don't need to check txiqcal_done here since it is always + * set for AR9550. + */ + REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0, + AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL); + + return true; +} + /* * solve 4x4 linear equation used in loopback iq cal. */ @@ -1271,6 +1489,11 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah, REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); } + if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) { + if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done)) + return false; + } + skip_tx_iqcal: if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) { if (AR_SREV_9330_11(ah)) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index c8d22eccfef8..25243cbc07f0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3598,7 +3598,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); - } else if (AR_SREV_9550(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9550_ALL, value); } else @@ -3975,7 +3975,7 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah) struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0]; - if (AR_SREV_9340(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9531(ah)) return; if (eep->baseEepHeader.featureEnable & 0x40) { @@ -4030,7 +4030,10 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz) if (!(eep->baseEepHeader.featureEnable & 0x80)) return; - if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah)) + if (!AR_SREV_9300(ah) && + !AR_SREV_9340(ah) && + !AR_SREV_9580(ah) && + !AR_SREV_9531(ah)) return; xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn; @@ -4163,7 +4166,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_xlna_bias_strength_apply(ah, is2ghz); ar9003_hw_atten_apply(ah, chan); ar9003_hw_quick_drop_apply(ah, chan->channel); - if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah)) ar9003_hw_internal_regulator_apply(ah); ar9003_hw_apply_tuning_caps(ah); ar9003_hw_apply_minccapwr_thresh(ah, chan); @@ -4788,7 +4791,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah, } tempslope: - if (AR_SREV_9550(ah)) { + if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { /* * AR955x has tempSlope register for each chain. * Check whether temp_compensation feature is enabled or not. diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 29613ebbc5d7..ec1da0cc25f5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -28,6 +28,7 @@ #include "ar9462_2p1_initvals.h" #include "ar9565_1p0_initvals.h" #include "ar9565_1p1_initvals.h" +#include "ar953x_initvals.h" /* General hardware code for the AR9003 hadware family */ @@ -308,6 +309,31 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, ar955x_1p0_modes_fast_clock); + } else if (AR_SREV_9531(ah)) { + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + qca953x_1p0_mac_core); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + qca953x_1p0_mac_postamble); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + qca953x_1p0_baseband_core); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + qca953x_1p0_baseband_postamble); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + qca953x_1p0_radio_core); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + qca953x_1p0_radio_postamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + qca953x_1p0_soc_preamble); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + qca953x_1p0_soc_postamble); + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_wo_xlna_rx_gain_bounds); + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_no_xpa_tx_gain_table); + INIT_INI_ARRAY(&ah->iniModesFastClock, + qca953x_1p0_modes_fast_clock); } else if (AR_SREV_9580(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], @@ -485,6 +511,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar955x_1p0_modes_xpa_tx_gain_table); + else if (AR_SREV_9531(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_xpa_tx_gain_table); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_lowest_ob_db_tx_gain_table); @@ -525,7 +554,14 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar955x_1p0_modes_no_xpa_tx_gain_table); - else if (AR_SREV_9462_21(ah)) + else if (AR_SREV_9531(ah)) { + if (AR_SREV_9531_11(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p1_modes_no_xpa_tx_gain_table); + else + INIT_INI_ARRAY(&ah->iniModesTxGain, + qca953x_1p0_modes_no_xpa_tx_gain_table); + } else if (AR_SREV_9462_21(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_2p1_modes_high_ob_db_tx_gain); else if (AR_SREV_9462_20(ah)) @@ -699,6 +735,11 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar955x_1p0_common_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, ar955x_1p0_common_rx_gain_bounds); + } else if (AR_SREV_9531(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_rx_gain_table); @@ -744,6 +785,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar955x_1p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, ar955x_1p0_common_wo_xlna_rx_gain_bounds); + } else if (AR_SREV_9531(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + qca953x_1p0_common_wo_xlna_rx_gain_table); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + qca953x_1p0_common_wo_xlna_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table); @@ -872,6 +918,117 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah, } } +static void ar9003_hw_init_hang_checks(struct ath_hw *ah) +{ + /* + * All chips support detection of BB/MAC hangs. + */ + ah->config.hw_hang_checks |= HW_BB_WATCHDOG; + ah->config.hw_hang_checks |= HW_MAC_HANG; + + /* + * This is not required for AR9580 1.0 + */ + if (AR_SREV_9300_22(ah)) + ah->config.hw_hang_checks |= HW_PHYRESTART_CLC_WAR; + + if (AR_SREV_9330(ah)) + ah->bb_watchdog_timeout_ms = 85; + else + ah->bb_watchdog_timeout_ms = 25; +} + +/* + * MAC HW hang check + * ================= + * + * Signature: dcu_chain_state is 0x6 and dcu_complete_state is 0x1. + * + * The state of each DCU chain (mapped to TX queues) is available from these + * DMA debug registers: + * + * Chain 0 state : Bits 4:0 of AR_DMADBG_4 + * Chain 1 state : Bits 9:5 of AR_DMADBG_4 + * Chain 2 state : Bits 14:10 of AR_DMADBG_4 + * Chain 3 state : Bits 19:15 of AR_DMADBG_4 + * Chain 4 state : Bits 24:20 of AR_DMADBG_4 + * Chain 5 state : Bits 29:25 of AR_DMADBG_4 + * Chain 6 state : Bits 4:0 of AR_DMADBG_5 + * Chain 7 state : Bits 9:5 of AR_DMADBG_5 + * Chain 8 state : Bits 14:10 of AR_DMADBG_5 + * Chain 9 state : Bits 19:15 of AR_DMADBG_5 + * + * The DCU chain state "0x6" means "WAIT_FRDONE" - wait for TX frame to be done. + */ + +#define NUM_STATUS_READS 50 + +static bool ath9k_hw_verify_hang(struct ath_hw *ah, unsigned int queue) +{ + u32 dma_dbg_chain, dma_dbg_complete; + u8 dcu_chain_state, dcu_complete_state; + int i; + + for (i = 0; i < NUM_STATUS_READS; i++) { + if (queue < 6) + dma_dbg_chain = REG_READ(ah, AR_DMADBG_4); + else + dma_dbg_chain = REG_READ(ah, AR_DMADBG_5); + + dma_dbg_complete = REG_READ(ah, AR_DMADBG_6); + + dcu_chain_state = (dma_dbg_chain >> (5 * queue)) & 0x1f; + dcu_complete_state = dma_dbg_complete & 0x3; + + if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1)) + return false; + } + + ath_dbg(ath9k_hw_common(ah), RESET, + "MAC Hang signature found for queue: %d\n", queue); + + return true; +} + +static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah) +{ + u32 dma_dbg_4, dma_dbg_5, dma_dbg_6, chk_dbg; + u8 dcu_chain_state, dcu_complete_state; + bool dcu_wait_frdone = false; + unsigned long chk_dcu = 0; + unsigned int i = 0; + + dma_dbg_4 = REG_READ(ah, AR_DMADBG_4); + dma_dbg_5 = REG_READ(ah, AR_DMADBG_5); + dma_dbg_6 = REG_READ(ah, AR_DMADBG_6); + + dcu_complete_state = dma_dbg_6 & 0x3; + if (dcu_complete_state != 0x1) + goto exit; + + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (i < 6) + chk_dbg = dma_dbg_4; + else + chk_dbg = dma_dbg_5; + + dcu_chain_state = (chk_dbg >> (5 * i)) & 0x1f; + if (dcu_chain_state == 0x6) { + dcu_wait_frdone = true; + chk_dcu |= BIT(i); + } + } + + if ((dcu_complete_state == 0x1) && dcu_wait_frdone) { + for_each_set_bit(i, &chk_dcu, ATH9K_NUM_TX_QUEUES) { + if (ath9k_hw_verify_hang(ah, i)) + return true; + } + } +exit: + return false; +} + /* Sets up the AR9003 hardware familiy callbacks */ void ar9003_hw_attach_ops(struct ath_hw *ah) { @@ -880,6 +1037,8 @@ void ar9003_hw_attach_ops(struct ath_hw *ah) ar9003_hw_init_mode_regs(ah); priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs; + priv_ops->init_hang_checks = ar9003_hw_init_hang_checks; + priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang; ops->config_pci_powersave = ar9003_hw_configpcipowersave; diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index 9f051a08e143..09facba1dc6d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -103,7 +103,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) } else { channelSel = CHANSEL_2G(freq) >> 1; } - } else if (AR_SREV_9550(ah)) { + } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { if (ah->is_clk_25mhz) div = 75; else @@ -118,7 +118,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) /* Set to 2G mode */ bMode = 1; } else { - if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && + if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) && ah->is_clk_25mhz) { channelSel = freq / 75; chan_frac = ((freq % 75) * 0x20000) / 75; @@ -810,10 +810,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, /* * TXGAIN initvals. */ - if (AR_SREV_9550(ah)) { - int modes_txgain_index; + if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) { + int modes_txgain_index = 1; + + if (AR_SREV_9550(ah)) + modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); - modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); if (modes_txgain_index < 0) return -EINVAL; @@ -1814,6 +1816,68 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah) memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs)); } +/* + * Baseband Watchdog signatures: + * + * 0x04000539: BB hang when operating in HT40 DFS Channel. + * Full chip reset is not required, but a recovery + * mechanism is needed. + * + * 0x1300000a: Related to CAC deafness. + * Chip reset is not required. + * + * 0x0400000a: Related to CAC deafness. + * Full chip reset is required. + * + * 0x04000b09: RX state machine gets into an illegal state + * when a packet with unsupported rate is received. + * Full chip reset is required and PHY_RESTART has + * to be disabled. + * + * 0x04000409: Packet stuck on receive. + * Full chip reset is required for all chips except AR9340. + */ + +/* + * ar9003_hw_bb_watchdog_check(): Returns true if a chip reset is required. + */ +bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah) +{ + u32 val; + + switch(ah->bb_watchdog_last_status) { + case 0x04000539: + val = REG_READ(ah, AR_PHY_RADAR_0); + val &= (~AR_PHY_RADAR_0_FIRPWR); + val |= SM(0x7f, AR_PHY_RADAR_0_FIRPWR); + REG_WRITE(ah, AR_PHY_RADAR_0, val); + udelay(1); + val = REG_READ(ah, AR_PHY_RADAR_0); + val &= ~AR_PHY_RADAR_0_FIRPWR; + val |= SM(AR9300_DFS_FIRPWR, AR_PHY_RADAR_0_FIRPWR); + REG_WRITE(ah, AR_PHY_RADAR_0, val); + + return false; + case 0x1300000a: + return false; + case 0x0400000a: + case 0x04000b09: + return true; + case 0x04000409: + if (AR_SREV_9340(ah) || AR_SREV_9531(ah)) + return false; + else + return true; + default: + /* + * For any other unknown signatures, do a + * full chip reset. + */ + return true; + } +} +EXPORT_SYMBOL(ar9003_hw_bb_watchdog_check); + void ar9003_hw_bb_watchdog_config(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1930,6 +1994,7 @@ EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info); void ar9003_hw_disable_phy_restart(struct ath_hw *ah) { + u8 result; u32 val; /* While receiving unsupported rate frame rx state machine @@ -1937,15 +2002,13 @@ void ar9003_hw_disable_phy_restart(struct ath_hw *ah) * state, BB would go hang. If RXSM is in 0xb state after * first bb panic, ensure to disable the phy_restart. */ - if (!((MS(ah->bb_watchdog_last_status, - AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) || - ah->bb_hang_rx_ofdm)) - return; - - ah->bb_hang_rx_ofdm = true; - val = REG_READ(ah, AR_PHY_RESTART); - val &= ~AR_PHY_RESTART_ENA; + result = MS(ah->bb_watchdog_last_status, AR_PHY_WATCHDOG_RX_OFDM_SM); - REG_WRITE(ah, AR_PHY_RESTART, val); + if ((result == 0xb) || ah->bb_hang_rx_ofdm) { + ah->bb_hang_rx_ofdm = true; + val = REG_READ(ah, AR_PHY_RESTART); + val &= ~AR_PHY_RESTART_ENA; + REG_WRITE(ah, AR_PHY_RESTART, val); + } } EXPORT_SYMBOL(ar9003_hw_disable_phy_restart); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 1b441715ba39..fd090b1f2d0f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -338,9 +338,8 @@ #define AR_PHY_CCA_NOM_VAL_9300_5GHZ -115 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ -125 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ -125 -#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -95 -#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -100 - +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ -60 +#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ -60 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ -95 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ -100 @@ -670,6 +669,16 @@ #define AR_PHY_65NM_CH1_RXTX4 0x1650c #define AR_PHY_65NM_CH2_RXTX4 0x1690c +#define AR_PHY_65NM_CH0_BB1 0x16140 +#define AR_PHY_65NM_CH0_BB2 0x16144 +#define AR_PHY_65NM_CH0_BB3 0x16148 +#define AR_PHY_65NM_CH1_BB1 0x16540 +#define AR_PHY_65NM_CH1_BB2 0x16544 +#define AR_PHY_65NM_CH1_BB3 0x16548 +#define AR_PHY_65NM_CH2_BB1 0x16940 +#define AR_PHY_65NM_CH2_BB2 0x16944 +#define AR_PHY_65NM_CH2_BB3 0x16948 + #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3 0x00780000 #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S 19 #define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK 0x00000004 @@ -1334,4 +1343,6 @@ #define AR_PHY_65NM_RXRF_AGC_AGC_OUT 0x00000004 #define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S 2 +#define AR9300_DFS_FIRPWR -28 + #endif /* AR9003_PHY_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h new file mode 100644 index 000000000000..3c9113d9b1bc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h @@ -0,0 +1,718 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_953X_H +#define INITVALS_953X_H + +#define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble + +#define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble + +#define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2 + +#define qca953x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 + +#define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 + +static const u32 qca953x_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c22}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008140, 0x000000fe}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f3d7}, + {0x00008248, 0x00000852}, + {0x0000824c, 0x0001e7ae}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00001d40}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x0000001f}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0xffff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48107b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x8c7901ff}, +}; + +static const u32 qca953x_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01884061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b91}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x1f020503}, + {0x0000a39c, 0x29180c03}, + {0x0000a3a0, 0x9a8b6844}, + {0x0000a3a4, 0x000000ff}, + {0x0000a3a8, 0x6a6a6a6a}, + {0x0000a3ac, 0x6a6a6a6a}, + {0x0000a3b0, 0x00c8641a}, + {0x0000a3b4, 0x0000001a}, + {0x0000a3b8, 0x0088642a}, + {0x0000a3bc, 0x000001fa}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce42108}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce73908}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce738e7}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0xbfad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x08000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, +}; + +static const u32 qca953x_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 qca953x_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x3f80fff8}, + {0x0001604c, 0x000f0278}, + {0x00016050, 0x8036db6c}, + {0x00016054, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f080a}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x000160a0, 0xc2108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480080}, + {0x000160c0, 0x006db6d8}, + {0x000160c4, 0x24b6db6c}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x6db6fb7c}, + {0x000160d0, 0x6db6da44}, + {0x00016100, 0x07ff8001}, + {0x00016108, 0x00080010}, + {0x00016144, 0x01884080}, + {0x00016148, 0x000080d8}, + {0x00016280, 0x01000901}, + {0x00016284, 0x15d30000}, + {0x00016288, 0x00318000}, + {0x0001628c, 0x50000000}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00800700}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x3f80fff8}, + {0x0001644c, 0x000f0278}, + {0x00016450, 0x8036db6c}, + {0x00016454, 0x6db60000}, + {0x00016500, 0x07ff8001}, + {0x00016508, 0x00080010}, + {0x00016544, 0x01884080}, + {0x00016548, 0x000080d8}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00800700}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, +}; + +static const u32 qca953x_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46}, + {0x00016104, 0xb7a00001, 0xb7a00001, 0xfff80005, 0xfff80005}, + {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, + {0x00016504, 0xb7a00001, 0xb7a00001, 0xfff80001, 0xfff80001}, + {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000}, + {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000}, +}; + +static const u32 qca953x_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x00007000, 0x00000000}, + {0x00007004, 0x00000000}, + {0x00007008, 0x00000000}, + {0x0000700c, 0x00000000}, + {0x0000701c, 0x00000000}, + {0x00007020, 0x00000000}, + {0x00007024, 0x00000000}, + {0x00007028, 0x00000000}, + {0x0000702c, 0x00000000}, + {0x00007030, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, + {0x00007048, 0x00000000}, +}; + +static const u32 qca953x_1p0_common_rx_gain_bounds[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018}, +}; + +static const u32 qca953x_1p0_common_wo_xlna_rx_gain_bounds[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, +}; + +static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xfffd5aaa}, + {0x0000a2e0, 0xfffe9ccc}, + {0x0000a2e4, 0xffffe0f0}, + {0x0000a2e8, 0xfffcff00}, + {0x0000a410, 0x000050da}, + {0x0000a500, 0x00000000}, + {0x0000a504, 0x04000002}, + {0x0000a508, 0x08000004}, + {0x0000a50c, 0x0c000006}, + {0x0000a510, 0x0f00000a}, + {0x0000a514, 0x1300000c}, + {0x0000a518, 0x1700000e}, + {0x0000a51c, 0x1b000064}, + {0x0000a520, 0x1f000242}, + {0x0000a524, 0x23000229}, + {0x0000a528, 0x270002a2}, + {0x0000a52c, 0x2c001203}, + {0x0000a530, 0x30001803}, + {0x0000a534, 0x33000881}, + {0x0000a538, 0x38001809}, + {0x0000a53c, 0x3a000814}, + {0x0000a540, 0x3f001a0c}, + {0x0000a544, 0x43001a0e}, + {0x0000a548, 0x46001812}, + {0x0000a54c, 0x49001884}, + {0x0000a550, 0x4d001e84}, + {0x0000a554, 0x50001e69}, + {0x0000a558, 0x550006f4}, + {0x0000a55c, 0x59000ad3}, + {0x0000a560, 0x5e000ad5}, + {0x0000a564, 0x61001ced}, + {0x0000a568, 0x660018d4}, + {0x0000a56c, 0x660018d4}, + {0x0000a570, 0x660018d4}, + {0x0000a574, 0x660018d4}, + {0x0000a578, 0x660018d4}, + {0x0000a57c, 0x660018d4}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x03804000}, + {0x0000a610, 0x0300ca02}, + {0x0000a614, 0x00000e04}, + {0x0000a618, 0x03014000}, + {0x0000a61c, 0x00000000}, + {0x0000a620, 0x00000000}, + {0x0000a624, 0x03014000}, + {0x0000a628, 0x03804c05}, + {0x0000a62c, 0x0701de06}, + {0x0000a630, 0x07819c07}, + {0x0000a634, 0x0701dc07}, + {0x0000a638, 0x0701dc07}, + {0x0000a63c, 0x0701dc07}, + {0x0000b2dc, 0xfffd5aaa}, + {0x0000b2e0, 0xfffe9ccc}, + {0x0000b2e4, 0xffffe0f0}, + {0x0000b2e8, 0xfffcff00}, + {0x00016044, 0x010002d4}, + {0x00016048, 0x66482400}, + {0x00016280, 0x01000015}, + {0x00016444, 0x010002d4}, + {0x00016448, 0x66482400}, +}; + +static const u32 qca953x_1p0_modes_no_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xffd5f552}, + {0x0000a2e0, 0xffe60664}, + {0x0000a2e4, 0xfff80780}, + {0x0000a2e8, 0xfffff800}, + {0x0000a410, 0x000050d6}, + {0x0000a500, 0x00060020}, + {0x0000a504, 0x04060060}, + {0x0000a508, 0x080600a0}, + {0x0000a50c, 0x0c068020}, + {0x0000a510, 0x10068060}, + {0x0000a514, 0x140680a0}, + {0x0000a518, 0x18090040}, + {0x0000a51c, 0x1b090080}, + {0x0000a520, 0x1f0900c0}, + {0x0000a524, 0x240c0041}, + {0x0000a528, 0x280d0021}, + {0x0000a52c, 0x2d0f0061}, + {0x0000a530, 0x310f00a1}, + {0x0000a534, 0x350e00a2}, + {0x0000a538, 0x360e80a2}, + {0x0000a53c, 0x380f00a2}, + {0x0000a540, 0x3b0e00a3}, + {0x0000a544, 0x3d110083}, + {0x0000a548, 0x3e1100a3}, + {0x0000a54c, 0x401100e3}, + {0x0000a550, 0x421380e3}, + {0x0000a554, 0x431780e3}, + {0x0000a558, 0x461f80e3}, + {0x0000a55c, 0x461f80e3}, + {0x0000a560, 0x461f80e3}, + {0x0000a564, 0x461f80e3}, + {0x0000a568, 0x461f80e3}, + {0x0000a56c, 0x461f80e3}, + {0x0000a570, 0x461f80e3}, + {0x0000a574, 0x461f80e3}, + {0x0000a578, 0x461f80e3}, + {0x0000a57c, 0x461f80e3}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00804201}, + {0x0000a610, 0x01008201}, + {0x0000a614, 0x0180c402}, + {0x0000a618, 0x0180c603}, + {0x0000a61c, 0x0180c603}, + {0x0000a620, 0x01c10603}, + {0x0000a624, 0x01c10704}, + {0x0000a628, 0x02c18b05}, + {0x0000a62c, 0x0301cc07}, + {0x0000a630, 0x0301cc07}, + {0x0000a634, 0x0301cc07}, + {0x0000a638, 0x0301cc07}, + {0x0000a63c, 0x0301cc07}, + {0x0000b2dc, 0xffd5f552}, + {0x0000b2e0, 0xffe60664}, + {0x0000b2e4, 0xfff80780}, + {0x0000b2e8, 0xfffff800}, + {0x00016044, 0x049242db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x049242db}, + {0x00016448, 0x6c927a70}, +}; + +static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a2dc, 0xffd5f552}, + {0x0000a2e0, 0xffe60664}, + {0x0000a2e4, 0xfff80780}, + {0x0000a2e8, 0xfffff800}, + {0x0000a410, 0x000050de}, + {0x0000a500, 0x00000061}, + {0x0000a504, 0x04000063}, + {0x0000a508, 0x08000065}, + {0x0000a50c, 0x0c000261}, + {0x0000a510, 0x10000263}, + {0x0000a514, 0x14000265}, + {0x0000a518, 0x18000482}, + {0x0000a51c, 0x1b000484}, + {0x0000a520, 0x1f000486}, + {0x0000a524, 0x240008c2}, + {0x0000a528, 0x28000cc1}, + {0x0000a52c, 0x2d000ce3}, + {0x0000a530, 0x31000ce5}, + {0x0000a534, 0x350010e5}, + {0x0000a538, 0x360012e5}, + {0x0000a53c, 0x380014e5}, + {0x0000a540, 0x3b0018e5}, + {0x0000a544, 0x3d001d04}, + {0x0000a548, 0x3e001d05}, + {0x0000a54c, 0x40001d07}, + {0x0000a550, 0x42001f27}, + {0x0000a554, 0x43001f67}, + {0x0000a558, 0x46001fe7}, + {0x0000a55c, 0x47001f2b}, + {0x0000a560, 0x49001f0d}, + {0x0000a564, 0x4b001ed2}, + {0x0000a568, 0x4c001ed4}, + {0x0000a56c, 0x4e001f15}, + {0x0000a570, 0x4f001ff6}, + {0x0000a574, 0x4f001ff6}, + {0x0000a578, 0x4f001ff6}, + {0x0000a57c, 0x4f001ff6}, + {0x0000a600, 0x00000000}, + {0x0000a604, 0x00000000}, + {0x0000a608, 0x00000000}, + {0x0000a60c, 0x00804201}, + {0x0000a610, 0x01008201}, + {0x0000a614, 0x0180c402}, + {0x0000a618, 0x0180c603}, + {0x0000a61c, 0x0180c603}, + {0x0000a620, 0x01c10603}, + {0x0000a624, 0x01c10704}, + {0x0000a628, 0x02c18b05}, + {0x0000a62c, 0x02c14c07}, + {0x0000a630, 0x01008704}, + {0x0000a634, 0x01c10402}, + {0x0000a638, 0x0301cc07}, + {0x0000a63c, 0x0301cc07}, + {0x0000b2dc, 0xffd5f552}, + {0x0000b2e0, 0xffe60664}, + {0x0000b2e4, 0xfff80780}, + {0x0000b2e8, 0xfffff800}, + {0x00016044, 0x049242db}, + {0x00016048, 0x6c927a70}, + {0x00016444, 0x049242db}, + {0x00016448, 0x6c927a70}, +}; + +#endif /* INITVALS_953X_H */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index f2202e78fa7b..f622a986c8cc 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -455,10 +455,8 @@ bool ath9k_csa_is_finished(struct ath_softc *sc); void ath_tx_complete_poll_work(struct work_struct *work); void ath_reset_work(struct work_struct *work); -void ath_hw_check(struct work_struct *work); +bool ath_hw_check(struct ath_softc *sc); void ath_hw_pll_work(struct work_struct *work); -void ath_rx_poll(unsigned long data); -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); void ath_start_ani(struct ath_softc *sc); @@ -722,12 +720,10 @@ struct ath_softc { spinlock_t sc_pcu_lock; struct mutex mutex; struct work_struct paprd_work; - struct work_struct hw_check_work; struct work_struct hw_reset_work; struct completion paprd_complete; wait_queue_head_t tx_wait; - unsigned int hw_busy_count; unsigned long sc_flags; unsigned long driver_data; @@ -761,7 +757,6 @@ struct ath_softc { struct ath_beacon_config cur_beacon_conf; struct delayed_work tx_complete_work; struct delayed_work hw_pll_work; - struct timer_list rx_poll_timer; struct timer_list sleep_timer; #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 112aff720e13..2e8bba0eb361 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -337,8 +337,14 @@ void ath9k_beacon_tasklet(unsigned long data) ath9k_hw_check_nav(ah); - if (!ath9k_hw_check_alive(ah)) - ieee80211_queue_work(sc->hw, &sc->hw_check_work); + /* + * If the previous beacon has not been transmitted + * and a MAC/BB hang has been identified, return + * here because a chip reset would have been + * initiated. + */ + if (!ath_hw_check(sc)) + return; if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { ath_dbg(common, BSTUCK, diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index c028df76b564..b41e008298dc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -1077,7 +1077,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, if (ieee80211_is_beacon(hdr->frame_control) && !is_zero_ether_addr(common->curbssid) && - ether_addr_equal(hdr->addr3, common->curbssid)) { + ether_addr_equal_64bits(hdr->addr3, common->curbssid)) { s8 rssi = rxbuf->rxstatus.rs_rssi; if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h index cc58a8ee1223..a47ea8423f1e 100644 --- a/drivers/net/wireless/ath/ath9k/hw-ops.h +++ b/drivers/net/wireless/ath/ath9k/hw-ops.h @@ -107,6 +107,21 @@ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) /* Private hardware call ops */ +static inline void ath9k_hw_init_hang_checks(struct ath_hw *ah) +{ + ath9k_hw_private_ops(ah)->init_hang_checks(ah); +} + +static inline bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->detect_mac_hang(ah); +} + +static inline bool ath9k_hw_detect_bb_hang(struct ath_hw *ah) +{ + return ath9k_hw_private_ops(ah)->detect_bb_hang(ah); +} + /* PHY ops */ static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah, @@ -232,4 +247,31 @@ static inline void ath9k_hw_set_radar_params(struct ath_hw *ah) ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf); } +static inline void ath9k_hw_init_cal_settings(struct ath_hw *ah) +{ + ath9k_hw_private_ops(ah)->init_cal_settings(ah); +} + +static inline u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); +} + +static inline void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) + return; + + ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); +} + +static inline void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) +{ + if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs) + return; + + ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah); +} + #endif /* ATH9K_HW_OPS_H */ diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index a4b1ae026216..ce41658a6003 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -37,57 +37,6 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards."); MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards"); MODULE_LICENSE("Dual BSD/GPL"); -static int __init ath9k_init(void) -{ - return 0; -} -module_init(ath9k_init); - -static void __exit ath9k_exit(void) -{ - return; -} -module_exit(ath9k_exit); - -/* Private hardware callbacks */ - -static void ath9k_hw_init_cal_settings(struct ath_hw *ah) -{ - ath9k_hw_private_ops(ah)->init_cal_settings(ah); -} - -static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah, - struct ath9k_channel *chan) -{ - return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan); -} - -static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah) -{ - if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs) - return; - - ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah); -} - -static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah) -{ - /* You will not have this callback if using the old ANI */ - if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs) - return; - - ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah); -} - -/********************/ -/* Helper Functions */ -/********************/ - -#ifdef CONFIG_ATH9K_DEBUGFS - -#endif - - static void ath9k_hw_set_clockrate(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -296,6 +245,9 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) case AR9300_DEVID_QCA955X: ah->hw_version.macVersion = AR_SREV_VERSION_9550; return; + case AR9300_DEVID_AR953X: + ah->hw_version.macVersion = AR_SREV_VERSION_9531; + return; } val = REG_READ(ah, AR_SREV) & AR_SREV_ID; @@ -397,9 +349,10 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah) static void ath9k_hw_init_config(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); + ah->config.dma_beacon_response_time = 1; ah->config.sw_beacon_response_time = 6; - ah->config.ack_6mb = 0x0; ah->config.cwm_ignore_extcca = 0; ah->config.analog_shiftreg = 1; @@ -423,6 +376,24 @@ static void ath9k_hw_init_config(struct ath_hw *ah) */ if (num_possible_cpus() > 1) ah->config.serialize_regmode = SER_REG_MODE_AUTO; + + if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || + ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && + !ah->is_pciexpress)) { + ah->config.serialize_regmode = SER_REG_MODE_ON; + } else { + ah->config.serialize_regmode = SER_REG_MODE_OFF; + } + } + + ath_dbg(common, RESET, "serialize_regmode is %d\n", + ah->config.serialize_regmode); + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; + else + ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; } static void ath9k_hw_init_defaults(struct ath_hw *ah) @@ -435,15 +406,24 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah) ah->hw_version.magic = AR5416_MAGIC; ah->hw_version.subvendorid = 0; - ah->sta_id1_defaults = - AR_STA_ID1_CRPT_MIC_ENABLE | - AR_STA_ID1_MCAST_KSRCH; + ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE | + AR_STA_ID1_MCAST_KSRCH; if (AR_SREV_9100(ah)) ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX; + ah->slottime = ATH9K_SLOT_TIME_9; ah->globaltxtimeout = (u32) -1; ah->power_mode = ATH9K_PM_UNDEFINED; ah->htc_reset_init = true; + + ah->ani_function = ATH9K_ANI_ALL; + if (!AR_SREV_9300_20_OR_LATER(ah)) + ah->ani_function &= ~ATH9K_ANI_MRC_CCK; + + if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) + ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); + else + ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); } static int ath9k_hw_init_macaddr(struct ath_hw *ah) @@ -525,6 +505,31 @@ static int __ath9k_hw_init(struct ath_hw *ah) ath9k_hw_read_revisions(ah); + switch (ah->hw_version.macVersion) { + case AR_SREV_VERSION_5416_PCI: + case AR_SREV_VERSION_5416_PCIE: + case AR_SREV_VERSION_9160: + case AR_SREV_VERSION_9100: + case AR_SREV_VERSION_9280: + case AR_SREV_VERSION_9285: + case AR_SREV_VERSION_9287: + case AR_SREV_VERSION_9271: + case AR_SREV_VERSION_9300: + case AR_SREV_VERSION_9330: + case AR_SREV_VERSION_9485: + case AR_SREV_VERSION_9340: + case AR_SREV_VERSION_9462: + case AR_SREV_VERSION_9550: + case AR_SREV_VERSION_9565: + case AR_SREV_VERSION_9531: + break; + default: + ath_err(common, + "Mac Chip Rev 0x%02x.%x is not supported by this driver\n", + ah->hw_version.macVersion, ah->hw_version.macRev); + return -EOPNOTSUPP; + } + /* * Read back AR_WA into a permanent copy and set bits 14 and 17. * We need to do this to avoid RMW of this register. We cannot @@ -558,50 +563,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) return -EIO; } - if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && - !ah->is_pciexpress)) { - ah->config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - - ath_dbg(common, RESET, "serialize_regmode is %d\n", - ah->config.serialize_regmode); - - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1; - else - ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD; - - switch (ah->hw_version.macVersion) { - case AR_SREV_VERSION_5416_PCI: - case AR_SREV_VERSION_5416_PCIE: - case AR_SREV_VERSION_9160: - case AR_SREV_VERSION_9100: - case AR_SREV_VERSION_9280: - case AR_SREV_VERSION_9285: - case AR_SREV_VERSION_9287: - case AR_SREV_VERSION_9271: - case AR_SREV_VERSION_9300: - case AR_SREV_VERSION_9330: - case AR_SREV_VERSION_9485: - case AR_SREV_VERSION_9340: - case AR_SREV_VERSION_9462: - case AR_SREV_VERSION_9550: - case AR_SREV_VERSION_9565: - break; - default: - ath_err(common, - "Mac Chip Rev 0x%02x.%x is not supported by this driver\n", - ah->hw_version.macVersion, ah->hw_version.macRev); - return -EOPNOTSUPP; - } - if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || AR_SREV_9550(ah)) ah->is_pciexpress = false; @@ -609,10 +570,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); ath9k_hw_init_cal_settings(ah); - ah->ani_function = ATH9K_ANI_ALL; - if (!AR_SREV_9300_20_OR_LATER(ah)) - ah->ani_function &= ~ATH9K_ANI_MRC_CCK; - if (!ah->is_pciexpress) ath9k_hw_disablepcie(ah); @@ -631,15 +588,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) return r; } - if (AR_SREV_9285(ah) || AR_SREV_9271(ah)) - ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S); - else - ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S); - - if (AR_SREV_9330(ah)) - ah->bb_watchdog_timeout_ms = 85; - else - ah->bb_watchdog_timeout_ms = 25; + ath9k_hw_init_hang_checks(ah); common->state = ATH_HW_INITIALIZED; @@ -672,6 +621,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9300_DEVID_AR9462: case AR9485_DEVID_AR1111: case AR9300_DEVID_AR9565: + case AR9300_DEVID_AR953X: break; default: if (common->bus_ops->ath_bus_type == ATH_USB) @@ -807,7 +757,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, /* program BB PLL phase_shift */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); - } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) { u32 regval, pll2_divint, pll2_divfrac, refdiv; REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); @@ -817,9 +767,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(100); if (ah->is_clk_25mhz) { - pll2_divint = 0x54; - pll2_divfrac = 0x1eb85; - refdiv = 3; + if (AR_SREV_9531(ah)) { + pll2_divint = 0x1c; + pll2_divfrac = 0xa3d2; + refdiv = 1; + } else { + pll2_divint = 0x54; + pll2_divfrac = 0x1eb85; + refdiv = 3; + } } else { if (AR_SREV_9340(ah)) { pll2_divint = 88; @@ -833,7 +789,10 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, } regval = REG_READ(ah, AR_PHY_PLL_MODE); - regval |= (0x1 << 16); + if (AR_SREV_9531(ah)) + regval |= (0x1 << 22); + else + regval |= (0x1 << 16); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); udelay(100); @@ -843,14 +802,33 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, regval = REG_READ(ah, AR_PHY_PLL_MODE); if (AR_SREV_9340(ah)) - regval = (regval & 0x80071fff) | (0x1 << 30) | - (0x1 << 13) | (0x4 << 26) | (0x18 << 19); + regval = (regval & 0x80071fff) | + (0x1 << 30) | + (0x1 << 13) | + (0x4 << 26) | + (0x18 << 19); + else if (AR_SREV_9531(ah)) + regval = (regval & 0x01c00fff) | + (0x1 << 31) | + (0x2 << 29) | + (0xa << 25) | + (0x1 << 19) | + (0x6 << 12); else - regval = (regval & 0x80071fff) | (0x3 << 30) | - (0x1 << 13) | (0x4 << 26) | (0x60 << 19); + regval = (regval & 0x80071fff) | + (0x3 << 30) | + (0x1 << 13) | + (0x4 << 26) | + (0x60 << 19); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); - REG_WRITE(ah, AR_PHY_PLL_MODE, - REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + + if (AR_SREV_9531(ah)) + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff); + else + REG_WRITE(ah, AR_PHY_PLL_MODE, + REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); + udelay(1000); } @@ -1532,76 +1510,6 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah) } } -static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states, - int *hang_state, int *hang_pos) -{ - static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */ - u32 chain_state, dcs_pos, i; - - for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) { - chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f; - for (i = 0; i < 3; i++) { - if (chain_state == dcu_chain_state[i]) { - *hang_state = chain_state; - *hang_pos = dcs_pos; - return true; - } - } - } - return false; -} - -#define DCU_COMPLETE_STATE 1 -#define DCU_COMPLETE_STATE_MASK 0x3 -#define NUM_STATUS_READS 50 -static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah) -{ - u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4; - u32 i, hang_pos, hang_state, num_state = 6; - - comp_state = REG_READ(ah, AR_DMADBG_6); - - if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) { - ath_dbg(ath9k_hw_common(ah), RESET, - "MAC Hang signature not found at DCU complete\n"); - return false; - } - - chain_state = REG_READ(ah, dcs_reg); - if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) - goto hang_check_iter; - - dcs_reg = AR_DMADBG_5; - num_state = 4; - chain_state = REG_READ(ah, dcs_reg); - if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos)) - goto hang_check_iter; - - ath_dbg(ath9k_hw_common(ah), RESET, - "MAC Hang signature 1 not found\n"); - return false; - -hang_check_iter: - ath_dbg(ath9k_hw_common(ah), RESET, - "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n", - chain_state, comp_state, hang_state, hang_pos); - - for (i = 0; i < NUM_STATUS_READS; i++) { - chain_state = REG_READ(ah, dcs_reg); - chain_state = (chain_state >> (5 * hang_pos)) & 0x1f; - comp_state = REG_READ(ah, AR_DMADBG_6); - - if (((comp_state & DCU_COMPLETE_STATE_MASK) != - DCU_COMPLETE_STATE) || - (chain_state != hang_state)) - return false; - } - - ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n"); - - return true; -} - void ath9k_hw_check_nav(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); @@ -1676,7 +1584,6 @@ static void ath9k_hw_reset_opmode(struct ath_hw *ah, REG_RMW(ah, AR_STA_ID1, macStaId1 | AR_STA_ID1_RTS_USE_DEF - | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0) | ah->sta_id1_defaults, ~AR_STA_ID1_SADH_MASK); ath_hw_setbssidmask(common); @@ -1735,7 +1642,7 @@ static void ath9k_hw_init_desc(struct ath_hw *ah) } #ifdef __BIG_ENDIAN else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || - AR_SREV_9550(ah)) + AR_SREV_9550(ah) || AR_SREV_9531(ah)) REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); @@ -1865,7 +1772,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, /* Save TSF before chip reset, a cold reset clears it */ tsf = ath9k_hw_gettsf64(ah); getrawmonotonic(&ts); - usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000; + usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000; saveLedState = REG_READ(ah, AR_CFG_LED) & (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL | @@ -1899,7 +1806,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, /* Restore TSF */ getrawmonotonic(&ts); - usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec; + usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec; ath9k_hw_settsf64(ah, tsf + usec); if (AR_SREV_9280_20_OR_LATER(ah)) @@ -2008,10 +1915,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_loadnf(ah, chan); ath9k_hw_start_nfcal(ah, true); - if (AR_SREV_9300_20_OR_LATER(ah)) { + if (AR_SREV_9300_20_OR_LATER(ah)) ar9003_hw_bb_watchdog_config(ah); + + if (ah->config.hw_hang_checks & HW_PHYRESTART_CLC_WAR) ar9003_hw_disable_phy_restart(ah); - } ath9k_hw_apply_gpio_override(ah); @@ -2135,7 +2043,11 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN); - udelay(50); + + if (AR_SREV_9100(ah)) + udelay(10000); + else + udelay(50); for (i = POWER_UP_TIME / 50; i > 0; i--) { val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; @@ -2564,13 +2476,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) ah->eep_ops->get_eeprom(ah, EEP_PAPRD)) pCap->hw_caps |= ATH9K_HW_CAP_PAPRD; - /* - * Fast channel change across bands is available - * only for AR9462 and AR9565. - */ - if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) - pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH; - return 0; } @@ -3084,14 +2989,14 @@ void ath_gen_timer_isr(struct ath_hw *ah) trigger_mask &= timer_table->timer_mask; thresh_mask &= timer_table->timer_mask; - trigger_mask &= ~thresh_mask; - for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) { timer = timer_table->timers[index]; if (!timer) continue; if (!timer->overflow) continue; + + trigger_mask &= ~BIT(index); timer->overflow(timer->arg); } diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 6132ffeb3048..e766399bdcda 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -52,6 +52,7 @@ #define AR9300_DEVID_QCA955X 0x0038 #define AR9485_DEVID_AR1111 0x0037 #define AR9300_DEVID_AR9565 0x0036 +#define AR9300_DEVID_AR953X 0x003d #define AR5416_AR9100_DEVID 0x000b @@ -277,10 +278,24 @@ struct ath9k_hw_capabilities { u8 txs_len; }; +#define AR_NO_SPUR 0x8000 +#define AR_BASE_FREQ_2GHZ 2300 +#define AR_BASE_FREQ_5GHZ 4900 +#define AR_SPUR_FEEQ_BOUND_HT40 19 +#define AR_SPUR_FEEQ_BOUND_HT20 10 + +enum ath9k_hw_hang_checks { + HW_BB_WATCHDOG = BIT(0), + HW_PHYRESTART_CLC_WAR = BIT(1), + HW_BB_RIFS_HANG = BIT(2), + HW_BB_DFS_HANG = BIT(3), + HW_BB_RX_CLEAR_STUCK_HANG = BIT(4), + HW_MAC_HANG = BIT(5), +}; + struct ath9k_ops_config { int dma_beacon_response_time; int sw_beacon_response_time; - int ack_6mb; u32 cwm_ignore_extcca; u32 pcie_waen; u8 analog_shiftreg; @@ -292,13 +307,9 @@ struct ath9k_ops_config { int serialize_regmode; bool rx_intr_mitigation; bool tx_intr_mitigation; -#define AR_NO_SPUR 0x8000 -#define AR_BASE_FREQ_2GHZ 2300 -#define AR_BASE_FREQ_5GHZ 4900 -#define AR_SPUR_FEEQ_BOUND_HT40 19 -#define AR_SPUR_FEEQ_BOUND_HT20 10 u8 max_txtrig_level; u16 ani_poll_interval; /* ANI poll interval in ms */ + u16 hw_hang_checks; /* Platform specific config */ u32 aspm_l1_fix; @@ -573,6 +584,10 @@ struct ath_hw_radar_conf { * register settings through the register initialization. */ struct ath_hw_private_ops { + void (*init_hang_checks)(struct ath_hw *ah); + bool (*detect_mac_hang)(struct ath_hw *ah); + bool (*detect_bb_hang)(struct ath_hw *ah); + /* Calibration ops */ void (*init_cal_settings)(struct ath_hw *ah); bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan); @@ -1029,6 +1044,7 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah); * Code specific to AR9003, we stuff these here to avoid callbacks * for older families */ +bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah); void ar9003_hw_bb_watchdog_config(struct ath_hw *ah); void ar9003_hw_bb_watchdog_read(struct ath_hw *ah); void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index e63465b7eab9..f2a17fcf1ae4 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -763,10 +763,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc); INIT_WORK(&sc->hw_reset_work, ath_reset_work); - INIT_WORK(&sc->hw_check_work, ath_hw_check); INIT_WORK(&sc->paprd_work, ath_paprd_calibrate); INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work); - setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc); /* * Cache line size is used to size and align various diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index aed7e29dc50f..30dcef5aba10 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -65,50 +65,26 @@ void ath_tx_complete_poll_work(struct work_struct *work) /* * Checks if the BB/MAC is hung. */ -void ath_hw_check(struct work_struct *work) +bool ath_hw_check(struct ath_softc *sc) { - struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work); struct ath_common *common = ath9k_hw_common(sc->sc_ah); - unsigned long flags; - int busy; - u8 is_alive, nbeacon = 1; enum ath_reset_type type; + bool is_alive; ath9k_ps_wakeup(sc); + is_alive = ath9k_hw_check_alive(sc->sc_ah); - if ((is_alive && !AR_SREV_9300(sc->sc_ah)) || sc->tx99_state) - goto out; - else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { + if (!is_alive) { ath_dbg(common, RESET, - "DCU stuck is detected. Schedule chip reset\n"); + "HW hang detected, schedule chip reset\n"); type = RESET_TYPE_MAC_HANG; - goto sched_reset; - } - - spin_lock_irqsave(&common->cc_lock, flags); - busy = ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); - - ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n", - busy, sc->hw_busy_count + 1); - if (busy >= 99) { - if (++sc->hw_busy_count >= 3) { - type = RESET_TYPE_BB_HANG; - goto sched_reset; - } - } else if (busy >= 0) { - sc->hw_busy_count = 0; - nbeacon = 3; + ath9k_queue_reset(sc, type); } - ath_start_rx_poll(sc, nbeacon); - goto out; - -sched_reset: - ath9k_queue_reset(sc, type); -out: ath9k_ps_restore(sc); + + return is_alive; } /* @@ -162,29 +138,6 @@ void ath_hw_pll_work(struct work_struct *work) } /* - * RX Polling - monitors baseband hangs. - */ -void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon) -{ - if (!AR_SREV_9300(sc->sc_ah)) - return; - - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) - return; - - mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies - (nbeacon * sc->cur_beacon_conf.beacon_interval)); -} - -void ath_rx_poll(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - - if (!test_bit(SC_OP_INVALID, &sc->sc_flags)) - ieee80211_queue_work(sc->hw, &sc->hw_check_work); -} - -/* * PA Pre-distortion. */ static void ath_paprd_activate(struct ath_softc *sc) @@ -409,10 +362,10 @@ void ath_ani_calibrate(unsigned long data) /* Call ANI routine if necessary */ if (aniflag) { - spin_lock_irqsave(&common->cc_lock, flags); + spin_lock(&common->cc_lock); ath9k_hw_ani_monitor(ah, ah->curchan); ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); + spin_unlock(&common->cc_lock); } /* Perform calibration if necessary */ diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 89d7e206992b..5f727588ca27 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -922,11 +922,29 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah) mask2 |= AR_IMR_S2_CST; } + if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { + if (ints & ATH9K_INT_BB_WATCHDOG) { + mask |= AR_IMR_BCNMISC; + mask2 |= AR_IMR_S2_BB_WATCHDOG; + } + } + ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); - ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC | - AR_IMR_S2_CABEND | AR_IMR_S2_CABTO | - AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST); + ah->imrs2_reg &= ~(AR_IMR_S2_TIM | + AR_IMR_S2_DTIM | + AR_IMR_S2_DTIMSYNC | + AR_IMR_S2_CABEND | + AR_IMR_S2_CABTO | + AR_IMR_S2_TSFOOR | + AR_IMR_S2_GTT | + AR_IMR_S2_CST); + + if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) { + if (ints & ATH9K_INT_BB_WATCHDOG) + ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG; + } + ah->imrs2_reg |= mask2; REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 21b764ba6400..d0c3aec7c74e 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -170,7 +170,6 @@ void ath9k_ps_restore(struct ath_softc *sc) static void __ath_cancel_work(struct ath_softc *sc) { cancel_work_sync(&sc->paprd_work); - cancel_work_sync(&sc->hw_check_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->hw_pll_work); @@ -194,7 +193,6 @@ void ath_restart_work(struct ath_softc *sc) ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); - ath_start_rx_poll(sc, 3); ath_start_ani(sc); } @@ -204,11 +202,7 @@ static bool ath_prepare_reset(struct ath_softc *sc) bool ret = true; ieee80211_stop_queues(sc->hw); - - sc->hw_busy_count = 0; ath_stop_ani(sc); - del_timer_sync(&sc->rx_poll_timer); - ath9k_hw_disable_interrupts(ah); if (!ath_drain_all_txq(sc)) @@ -336,7 +330,6 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand struct ieee80211_hw *hw = sc->hw; struct ath9k_channel *hchan; struct ieee80211_channel *chan = chandef->chan; - unsigned long flags; bool offchannel; int pos = chan->hw_value; int old_pos = -1; @@ -354,9 +347,9 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand chan->center_freq, chandef->width); /* update survey stats for the old channel before switching */ - spin_lock_irqsave(&common->cc_lock, flags); + spin_lock_bh(&common->cc_lock); ath_update_survey_stats(sc); - spin_unlock_irqrestore(&common->cc_lock, flags); + spin_unlock_bh(&common->cc_lock); ath9k_cmn_get_channel(hw, ah, chandef); @@ -427,12 +420,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, an->vif = vif; ath_tx_node_init(sc, an); - - if (sta->ht_cap.ht_supported) { - an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + - sta->ht_cap.ampdu_factor); - an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); - } } static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) @@ -454,14 +441,8 @@ void ath9k_tasklet(unsigned long data) ath9k_ps_wakeup(sc); spin_lock(&sc->sc_pcu_lock); - if ((status & ATH9K_INT_FATAL) || - (status & ATH9K_INT_BB_WATCHDOG)) { - - if (status & ATH9K_INT_FATAL) - type = RESET_TYPE_FATAL_INT; - else - type = RESET_TYPE_BB_WATCHDOG; - + if (status & ATH9K_INT_FATAL) { + type = RESET_TYPE_FATAL_INT; ath9k_queue_reset(sc, type); /* @@ -473,6 +454,28 @@ void ath9k_tasklet(unsigned long data) goto out; } + if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && + (status & ATH9K_INT_BB_WATCHDOG)) { + spin_lock(&common->cc_lock); + ath_hw_cycle_counters_update(common); + ar9003_hw_bb_watchdog_dbg_info(ah); + spin_unlock(&common->cc_lock); + + if (ar9003_hw_bb_watchdog_check(ah)) { + type = RESET_TYPE_BB_WATCHDOG; + ath9k_queue_reset(sc, type); + + /* + * Increment the ref. counter here so that + * interrupts are enabled in the reset routine. + */ + atomic_inc(&ah->intr_ref_cnt); + ath_dbg(common, ANY, + "BB_WATCHDOG: Skipping interrupts\n"); + goto out; + } + } + spin_lock_irqsave(&sc->sc_pm_lock, flags); if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) { /* @@ -541,7 +544,7 @@ irqreturn_t ath_isr(int irq, void *dev) struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); enum ath9k_int status; - u32 sync_cause; + u32 sync_cause = 0; bool sched = false; /* @@ -593,16 +596,9 @@ irqreturn_t ath_isr(int irq, void *dev) !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA))) goto chip_reset; - if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) && - (status & ATH9K_INT_BB_WATCHDOG)) { - - spin_lock(&common->cc_lock); - ath_hw_cycle_counters_update(common); - ar9003_hw_bb_watchdog_dbg_info(ah); - spin_unlock(&common->cc_lock); - + if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) && + (status & ATH9K_INT_BB_WATCHDOG)) goto chip_reset; - } #ifdef CONFIG_ATH9K_WOW if (status & ATH9K_INT_BMISS) { @@ -732,11 +728,13 @@ static int ath9k_start(struct ieee80211_hw *hw) if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ah->imask |= ATH9K_INT_RXHP | - ATH9K_INT_RXLP | - ATH9K_INT_BB_WATCHDOG; + ATH9K_INT_RXLP; else ah->imask |= ATH9K_INT_RX; + if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) + ah->imask |= ATH9K_INT_BB_WATCHDOG; + ah->imask |= ATH9K_INT_GTT; if (ah->caps.hw_caps & ATH9K_HW_CAP_HT) @@ -860,7 +858,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) mutex_lock(&sc->mutex); ath_cancel_work(sc); - del_timer_sync(&sc->rx_poll_timer); if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { ath_dbg(common, ANY, "Device not present\n"); @@ -1791,13 +1788,12 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ieee80211_supported_band *sband; struct ieee80211_channel *chan; - unsigned long flags; int pos; if (config_enabled(CONFIG_ATH9K_TX99)) return -EOPNOTSUPP; - spin_lock_irqsave(&common->cc_lock, flags); + spin_lock_bh(&common->cc_lock); if (idx == 0) ath_update_survey_stats(sc); @@ -1811,7 +1807,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ]; if (!sband || idx >= sband->n_channels) { - spin_unlock_irqrestore(&common->cc_lock, flags); + spin_unlock_bh(&common->cc_lock); return -ENOENT; } @@ -1819,7 +1815,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx, pos = chan->hw_value; memcpy(survey, &sc->survey[pos], sizeof(*survey)); survey->channel = chan; - spin_unlock_irqrestore(&common->cc_lock, flags); + spin_unlock_bh(&common->cc_lock); return 0; } diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index e9a585758941..55724b02316b 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -412,6 +412,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x11AD, /* LITEON */ + 0x06B2), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0842), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ 0x6671), .driver_data = ATH9K_PCI_AR9565_1ANT }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, @@ -424,6 +434,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { 0x1B9A, /* XAVI */ 0x2812), .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x1B9A, /* XAVI */ + 0x28A1), + .driver_data = ATH9K_PCI_AR9565_1ANT }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x218A), + .driver_data = ATH9K_PCI_AR9565_1ANT }, /* WB335 1-ANT / Antenna Diversity */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, @@ -469,22 +489,17 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, 0x11AD, /* LITEON */ - 0x0682), + 0x06A2), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, - PCI_VENDOR_ID_AZWAVE, - 0x213A), - .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, - { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, - 0x0036, - PCI_VENDOR_ID_LENOVO, - 0x3026), + 0x11AD, /* LITEON */ + 0x0682), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, - PCI_VENDOR_ID_LENOVO, - 0x4026), + PCI_VENDOR_ID_AZWAVE, + 0x213A), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, @@ -504,37 +519,35 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_DELL, - 0x020E), + 0x020C), .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV }, - /* WB335 2-ANT */ + /* WB335 2-ANT / Antenna-Diversity */ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_SAMSUNG, 0x411A), - .driver_data = ATH9K_PCI_AR9565_2ANT }, + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_SAMSUNG, 0x411B), - .driver_data = ATH9K_PCI_AR9565_2ANT }, + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_SAMSUNG, 0x411C), - .driver_data = ATH9K_PCI_AR9565_2ANT }, + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_SAMSUNG, 0x411D), - .driver_data = ATH9K_PCI_AR9565_2ANT }, + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_SAMSUNG, 0x411E), - .driver_data = ATH9K_PCI_AR9565_2ANT }, - - /* WB335 2-ANT / Antenna-Diversity */ + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, PCI_VENDOR_ID_ATHEROS, @@ -562,11 +575,31 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, + 0x11AD, /* LITEON */ + 0x0832), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + 0x11AD, /* LITEON */ + 0x0692), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, PCI_VENDOR_ID_AZWAVE, 0x2130), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x213B), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_AZWAVE, + 0x2182), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, 0x144F, /* ASKEY */ 0x7202), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, @@ -577,6 +610,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, 0x0036, + 0x1B9A, /* XAVI */ + 0x28A2), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, 0x185F, /* WNC */ 0x3027), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, @@ -590,6 +628,31 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = { PCI_VENDOR_ID_FOXCONN, 0xE07F), .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_FOXCONN, + 0xE081), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x3026), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_LENOVO, + 0x4026), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_ASUSTEK, + 0x85F2), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS, + 0x0036, + PCI_VENDOR_ID_DELL, + 0x020E), + .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV }, /* PCI-E AR9565 (WB335) */ { PCI_VDEVICE(ATHEROS, 0x0036), diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 3692b2a501a2..f7cc5b37a18f 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -419,7 +419,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } - if (AR_SREV_9550(sc->sc_ah)) + if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah)) rfilt |= ATH9K_RX_FILTER_4ADDRESS; return rfilt; @@ -850,20 +850,15 @@ static int ath9k_process_rate(struct ath_common *common, enum ieee80211_band band; unsigned int i = 0; struct ath_softc __maybe_unused *sc = common->priv; + struct ath_hw *ah = sc->sc_ah; - band = hw->conf.chandef.chan->band; + band = ah->curchan->chan->band; sband = hw->wiphy->bands[band]; - switch (hw->conf.chandef.width) { - case NL80211_CHAN_WIDTH_5: + if (IS_CHAN_QUARTER_RATE(ah->curchan)) rxs->flag |= RX_FLAG_5MHZ; - break; - case NL80211_CHAN_WIDTH_10: + else if (IS_CHAN_HALF_RATE(ah->curchan)) rxs->flag |= RX_FLAG_10MHZ; - break; - default: - break; - } if (rx_stats->rs_rate & 0x80) { /* HT rate */ @@ -982,7 +977,7 @@ static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr) if (ieee80211_is_beacon(hdr->frame_control)) { RX_STAT_INC(rx_beacons); if (!is_zero_ether_addr(common->curbssid) && - ether_addr_equal(hdr->addr3, common->curbssid)) + ether_addr_equal_64bits(hdr->addr3, common->curbssid)) return true; } @@ -1077,9 +1072,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, } rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr); - if (rx_stats->is_mybeacon) { - sc->hw_busy_count = 0; - ath_start_rx_poll(sc, 3); + + /* + * This shouldn't happen, but have a safety check anyway. + */ + if (WARN_ON(!ah->curchan)) { + ret = -EINVAL; + goto exit; } if (ath9k_process_rate(common, hw, rx_stats, rx_status)) { @@ -1089,8 +1088,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc, ath9k_process_rssi(common, hw, rx_stats, rx_status); - rx_status->band = hw->conf.chandef.chan->band; - rx_status->freq = hw->conf.chandef.chan->center_freq; + rx_status->band = ah->curchan->chan->band; + rx_status->freq = ah->curchan->chan->center_freq; rx_status->antenna = rx_stats->rs_antenna; rx_status->flag |= RX_FLAG_MACTIME_END; diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 9ad007312c9d..b1fd3fa84983 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -304,6 +304,7 @@ #define AR_IMR_S2 0x00ac #define AR_IMR_S2_QCU_TXURN 0x000003FF #define AR_IMR_S2_QCU_TXURN_S 0 +#define AR_IMR_S2_BB_WATCHDOG 0x00010000 #define AR_IMR_S2_CST 0x00400000 #define AR_IMR_S2_GTT 0x00800000 #define AR_IMR_S2_TIM 0x01000000 @@ -812,6 +813,9 @@ #define AR_SREV_REVISION_9565_101 1 #define AR_SREV_REVISION_9565_11 2 #define AR_SREV_VERSION_9550 0x400 +#define AR_SREV_VERSION_9531 0x500 +#define AR_SREV_REVISION_9531_10 0 +#define AR_SREV_REVISION_9531_11 1 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -945,11 +949,19 @@ #define AR_SREV_9580(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10)) - #define AR_SREV_9580_10(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ ((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10)) +#define AR_SREV_9531(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531)) +#define AR_SREV_9531_10(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_10)) +#define AR_SREV_9531_11(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \ + ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11)) + /* NOTE: When adding chips newer than Peacock, add chip check here */ #define AR_SREV_9580_10_OR_LATER(_ah) \ (AR_SREV_9580(_ah)) diff --git a/drivers/net/wireless/ath/ath9k/spectral.c b/drivers/net/wireless/ath/ath9k/spectral.c index 11adb5eb51cc..99f4de95c264 100644 --- a/drivers/net/wireless/ath/ath9k/spectral.c +++ b/drivers/net/wireless/ath/ath9k/spectral.c @@ -497,7 +497,7 @@ static int remove_buf_file_handler(struct dentry *dentry) return 0; } -struct rchan_callbacks rfs_spec_scan_cb = { +static struct rchan_callbacks rfs_spec_scan_cb = { .create_buf_file = create_buf_file_handler, .remove_buf_file = remove_buf_file_handler, }; diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c index f1cde81bb7a2..1b3230fa3651 100644 --- a/drivers/net/wireless/ath/ath9k/wow.c +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -197,7 +197,6 @@ int ath9k_suspend(struct ieee80211_hw *hw, ath_cancel_work(sc); ath_stop_ani(sc); - del_timer_sync(&sc->rx_poll_timer); if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { ath_dbg(common, ANY, "Device not present\n"); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 9d735c55a0f3..e8d0e7fc77da 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -774,11 +774,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (bt_aggr_limit) aggr_limit = bt_aggr_limit; - /* - * h/w can accept aggregates up to 16 bit lengths (65535). - * The IE, however can hold up to 65536, which shows up here - * as zero. Ignore 65536 since we are constrained by hw. - */ if (tid->an->maxampdu) aggr_limit = min(aggr_limit, tid->an->maxampdu); @@ -1403,8 +1398,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, * has already been added. */ if (sta->ht_cap.ht_supported) { - an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + - sta->ht_cap.ampdu_factor); + an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->ht_cap.ampdu_factor)) - 1; density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); an->mpdudensity = density; } diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c index 3d70cd277fd7..1c0af9cd9a85 100644 --- a/drivers/net/wireless/ath/carl9170/debug.c +++ b/drivers/net/wireless/ath/carl9170/debug.c @@ -37,7 +37,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/seq_file.h> diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 349fa22a921a..4c3f576c3144 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -37,7 +37,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index e935f61c7fad..1b1b20751ead 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -37,7 +37,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/etherdevice.h> @@ -536,7 +535,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (!ether_addr_equal(hdr->addr3, ar->common.curbssid) || + if (!ether_addr_equal_64bits(hdr->addr3, ar->common.curbssid) || !ar->common.curaid) return; @@ -602,8 +601,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) if (bar->start_seq_num == entry_bar->start_seq_num && TID_CHECK(bar->control, entry_bar->control) && - ether_addr_equal(bar->ra, entry_bar->ta) && - ether_addr_equal(bar->ta, entry_bar->ra)) { + ether_addr_equal_64bits(bar->ra, entry_bar->ta) && + ether_addr_equal_64bits(bar->ta, entry_bar->ra)) { struct ieee80211_tx_info *tx_info; tx_info = IEEE80211_SKB_CB(entry_skb); diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index e3f696ee4d23..4cadfd48ffdf 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -37,7 +37,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c index 8205d3e4ab66..10919f95a83c 100644 --- a/drivers/net/wireless/ath/wil6210/interrupt.c +++ b/drivers/net/wireless/ath/wil6210/interrupt.c @@ -156,6 +156,19 @@ void wil6210_enable_irq(struct wil6210_priv *wil) iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) + offsetof(struct RGF_ICR, ICC)); + /* interrupt moderation parameters */ + if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) { + /* disable interrupt moderation for monitor + * to get better timestamp precision + */ + iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); + } else { + iowrite32(WIL6210_ITR_TRSH, + wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH)); + iowrite32(BIT_DMA_ITR_CNT_CRL_EN, + wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL)); + } + wil6210_unmask_irq_pseudo(wil); wil6210_unmask_irq_tx(wil); wil6210_unmask_irq_rx(wil); diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index d505b2676a73..9b88440ef05b 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -21,6 +21,7 @@ #include <linux/ip.h> #include <linux/ipv6.h> #include <net/ipv6.h> +#include <asm/processor.h> #include "wil6210.h" #include "wmi.h" @@ -377,6 +378,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil, } skb_trim(skb, dmalen); + prefetch(skb->data); + wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1, skb->data, skb_headlen(skb), false); @@ -673,9 +676,12 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, if (skb->ip_summed != CHECKSUM_PARTIAL) return 0; + d->dma.b11 = ETH_HLEN; /* MAC header length */ + switch (skb->protocol) { case cpu_to_be16(ETH_P_IP): protocol = ip_hdr(skb)->protocol; + d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS); break; case cpu_to_be16(ETH_P_IPV6): protocol = ipv6_hdr(skb)->nexthdr; @@ -701,8 +707,6 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil, } d->dma.ip_length = skb_network_header_len(skb); - d->dma.b11 = ETH_HLEN; /* MAC header length */ - d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS); /* Enable TCP/UDP checksum */ d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS); /* Calculate pseudo-header */ diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index c4a51638736a..1f91eaf95bbe 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -39,6 +39,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1) #define WIL6210_MAX_TX_RINGS (24) /* HW limit */ #define WIL6210_MAX_CID (8) /* HW limit */ #define WIL6210_NAPI_BUDGET (16) /* arbitrary */ +#define WIL6210_ITR_TRSH (10000) /* arbitrary - about 15 IRQs/msec */ /* Hardware definitions begin */ diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index b73b7e3e2196..bf93ea859f2d 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -39,7 +39,6 @@ ******************************************************************************/ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/kernel.h> diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c index 5e2749dd1124..4cfb4d99ced0 100644 --- a/drivers/net/wireless/atmel_cs.c +++ b/drivers/net/wireless/atmel_cs.c @@ -32,7 +32,6 @@ #ifdef __IN_PCMCIA_PACKAGE__ #include <pcmcia/k_compat.h> #endif -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/ptrace.h> diff --git a/drivers/net/wireless/atmel_pci.c b/drivers/net/wireless/atmel_pci.c index 64d5973ec28b..5cd97e3cbee3 100644 --- a/drivers/net/wireless/atmel_pci.c +++ b/drivers/net/wireless/atmel_pci.c @@ -22,7 +22,6 @@ #include <linux/pci.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include "atmel.h" diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c index 12c27d13df7f..c229210d50ba 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcdc.c @@ -41,9 +41,6 @@ struct brcmf_proto_bcdc_dcmd { __le32 status; /* status code returned from the device */ }; -/* Max valid buffer size that can be sent to the dongle */ -#define BCDC_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) - /* BCDC flag definitions */ #define BCDC_DCMD_ERROR 0x01 /* 1=cmd failed */ #define BCDC_DCMD_SET 0x02 /* 0=get, 1=set cmd */ @@ -133,9 +130,12 @@ brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf, if (buf) memcpy(bcdc->buf, buf, len); + len += sizeof(*msg); + if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE) + len = BRCMF_TX_IOCTL_MAX_MSG_SIZE; + /* Send request */ - return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, - len + sizeof(struct brcmf_proto_bcdc_dcmd)); + return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len); } static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 2b5cde67e728..34c993dd0602 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -47,8 +47,6 @@ #define SDIOH_API_ACCESS_RETRY_LIMIT 2 -#define SDIO_VENDOR_ID_BROADCOM 0x02d0 - #define DMA_ALIGN_MASK 0x03 #define SDIO_FUNC1_BLOCKSIZE 64 @@ -216,94 +214,104 @@ static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func, return err_ret; } -static int brcmf_sdiod_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw, - uint func, uint regaddr, u8 *byte) +static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn, + u32 addr, u8 regsz, void *data, bool write) { - int err_ret; + struct sdio_func *func; + int ret; - brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr); + brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", + write, fn, addr, regsz); - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait); + brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); if (brcmf_sdiod_pm_resume_error(sdiodev)) return -EIO; - if (rw && func == 0) { - /* handle F0 separately */ - err_ret = brcmf_sdiod_f0_writeb(sdiodev->func[func], - regaddr, *byte); - } else { - if (rw) /* CMD52 Write */ - sdio_writeb(sdiodev->func[func], *byte, regaddr, - &err_ret); - else if (func == 0) { - *byte = sdio_f0_readb(sdiodev->func[func], regaddr, - &err_ret); + /* only allow byte access on F0 */ + if (WARN_ON(regsz > 1 && !fn)) + return -EINVAL; + func = sdiodev->func[fn]; + + switch (regsz) { + case sizeof(u8): + if (write) { + if (fn) + sdio_writeb(func, *(u8 *)data, addr, &ret); + else + ret = brcmf_sdiod_f0_writeb(func, addr, + *(u8 *)data); } else { - *byte = sdio_readb(sdiodev->func[func], regaddr, - &err_ret); + if (fn) + *(u8 *)data = sdio_readb(func, addr, &ret); + else + *(u8 *)data = sdio_f0_readb(func, addr, &ret); } + break; + case sizeof(u16): + if (write) + sdio_writew(func, *(u16 *)data, addr, &ret); + else + *(u16 *)data = sdio_readw(func, addr, &ret); + break; + case sizeof(u32): + if (write) + sdio_writel(func, *(u32 *)data, addr, &ret); + else + *(u32 *)data = sdio_readl(func, addr, &ret); + break; + default: + brcmf_err("invalid size: %d\n", regsz); + break; } - if (err_ret) { + if (ret) { /* * SleepCSR register access can fail when * waking up the device so reduce this noise * in the logs. */ - if (regaddr != SBSDIO_FUNC1_SLEEPCSR) - brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "write" : "read", func, regaddr, *byte, - err_ret); + if (addr != SBSDIO_FUNC1_SLEEPCSR) + brcmf_err("failed to %s data F%d@0x%05x, err: %d\n", + write ? "write" : "read", fn, addr, ret); else - brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n", - rw ? "write" : "read", func, regaddr, *byte, - err_ret); + brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n", + write ? "write" : "read", fn, addr, ret); } - return err_ret; + return ret; } -static int brcmf_sdiod_request_word(struct brcmf_sdio_dev *sdiodev, uint rw, - uint func, uint addr, u32 *word, - uint nbytes) +static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, + u8 regsz, void *data, bool write) { - int err_ret = -EIO; - - if (func == 0) { - brcmf_err("Only CMD52 allowed to F0\n"); - return -EINVAL; - } - - brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n", - rw, func, addr, nbytes); + u8 func_num; + s32 retry = 0; + int ret; - brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait); - if (brcmf_sdiod_pm_resume_error(sdiodev)) - return -EIO; + /* + * figure out how to read the register based on address range + * 0x00 ~ 0x7FF: function 0 CCCR and FBR + * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers + * The rest: function 1 silicon backplane core registers + */ + if ((addr & ~REG_F0_REG_MASK) == 0) + func_num = SDIO_FUNC_0; + else + func_num = SDIO_FUNC_1; - if (rw) { /* CMD52 Write */ - if (nbytes == 4) - sdio_writel(sdiodev->func[func], *word, addr, - &err_ret); - else if (nbytes == 2) - sdio_writew(sdiodev->func[func], (*word & 0xFFFF), - addr, &err_ret); - else - brcmf_err("Invalid nbytes: %d\n", nbytes); - } else { /* CMD52 Read */ - if (nbytes == 4) - *word = sdio_readl(sdiodev->func[func], addr, &err_ret); - else if (nbytes == 2) - *word = sdio_readw(sdiodev->func[func], addr, - &err_ret) & 0xFFFF; - else - brcmf_err("Invalid nbytes: %d\n", nbytes); - } + do { + if (!write) + memset(data, 0, regsz); + /* for retry wait for 1 ms till bus get settled down */ + if (retry) + usleep_range(1000, 2000); + ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz, + data, write); + } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); - if (err_ret) - brcmf_err("Failed to %s word, Err: 0x%08x\n", - rw ? "write" : "read", err_ret); + if (ret != 0) + brcmf_err("failed with %d\n", ret); - return err_ret; + return ret; } static int @@ -311,24 +319,17 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) { int err = 0, i; u8 addr[3]; - s32 retry; addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK; addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK; addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK; for (i = 0; i < 3; i++) { - retry = 0; - do { - if (retry) - usleep_range(1000, 2000); - err = brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE, - SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i, - &addr[i]); - } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); - + err = brcmf_sdiod_regrw_helper(sdiodev, + SBSDIO_FUNC1_SBADDRLOW + i, + sizeof(u8), &addr[i], true); if (err) { - brcmf_err("failed at addr:0x%0x\n", + brcmf_err("failed at addr: 0x%0x\n", SBSDIO_FUNC1_SBADDRLOW + i); break; } @@ -359,61 +360,14 @@ brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr) return 0; } -static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, - void *data, bool write) -{ - u8 func_num, reg_size; - s32 retry = 0; - int ret; - - /* - * figure out how to read the register based on address range - * 0x00 ~ 0x7FF: function 0 CCCR and FBR - * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers - * The rest: function 1 silicon backplane core registers - */ - if ((addr & ~REG_F0_REG_MASK) == 0) { - func_num = SDIO_FUNC_0; - reg_size = 1; - } else if ((addr & ~REG_F1_MISC_MASK) == 0) { - func_num = SDIO_FUNC_1; - reg_size = 1; - } else { - func_num = SDIO_FUNC_1; - reg_size = 4; - - ret = brcmf_sdiod_addrprep(sdiodev, reg_size, &addr); - if (ret) - goto done; - } - - do { - if (!write) - memset(data, 0, reg_size); - if (retry) /* wait for 1 ms till bus get settled down */ - usleep_range(1000, 2000); - if (reg_size == 1) - ret = brcmf_sdiod_request_byte(sdiodev, write, - func_num, addr, data); - else - ret = brcmf_sdiod_request_word(sdiodev, write, - func_num, addr, data, 4); - } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); - -done: - if (ret != 0) - brcmf_err("failed with %d\n", ret); - - return ret; -} - u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) { u8 data; int retval; brcmf_dbg(SDIO, "addr:0x%08x\n", addr); - retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false); + retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, + false); brcmf_dbg(SDIO, "data:0x%02x\n", data); if (ret) @@ -428,9 +382,14 @@ u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) int retval; brcmf_dbg(SDIO, "addr:0x%08x\n", addr); - retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false); + retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr); + if (retval) + goto done; + retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, + false); brcmf_dbg(SDIO, "data:0x%08x\n", data); +done: if (ret) *ret = retval; @@ -443,8 +402,8 @@ void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, int retval; brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data); - retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true); - + retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, + true); if (ret) *ret = retval; } @@ -455,8 +414,13 @@ void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, int retval; brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data); - retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true); + retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr); + if (retval) + goto done; + retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data, + true); +done: if (ret) *ret = retval; } @@ -879,8 +843,8 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn) brcmf_dbg(SDIO, "Enter\n"); /* issue abort cmd52 command through F0 */ - brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0, - SDIO_CCCR_ABORT, &t_func); + brcmf_sdiod_request_data(sdiodev, SDIO_FUNC_0, SDIO_CCCR_ABORT, + sizeof(t_func), &t_func, true); brcmf_dbg(SDIO, "Exit\n"); return 0; @@ -981,6 +945,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)}, {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4335_4339)}, { /* end: all zeroes */ }, @@ -1037,7 +1002,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func, sdiodev->pdata = brcmfmac_sdio_pdata; atomic_set(&sdiodev->suspend, false); - init_waitqueue_head(&sdiodev->request_byte_wait); init_waitqueue_head(&sdiodev->request_word_wait); init_waitqueue_head(&sdiodev->request_buffer_wait); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 252024bcbc3b..939d6b132922 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -21,8 +21,6 @@ #ifndef _BRCMF_H_ #define _BRCMF_H_ -#define BRCMF_VERSION_STR "4.218.248.5" - #include "fweh.h" #define TOE_TX_CSUM_OL 0x00000001 @@ -39,6 +37,11 @@ #define BRCMF_DCMD_MEDLEN 1536 #define BRCMF_DCMD_MAXLEN 8192 +/* IOCTL from host to device are limited in lenght. A device can only handle + * ethernet frame size. This limitation is to be applied by protocol layer. + */ +#define BRCMF_TX_IOCTL_MAX_MSG_SIZE (ETH_FRAME_LEN+ETH_FCS_LEN) + #define BRCMF_AMPDU_RX_REORDER_MAXFLOWS 256 /* Length of firmware version string stored for diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 548dbb5542c6..6a8983a1fb9c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -32,15 +32,6 @@ #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME 40 #define BRCMF_DEFAULT_PACKET_FILTER "100 0 0 0 0x01 0x00" -#ifdef DEBUG -static const char brcmf_version[] = - "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on " - __DATE__ " at " __TIME__; -#else -static const char brcmf_version[] = - "Dongle Host Driver, version " BRCMF_VERSION_STR; -#endif - bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt, int prec) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index bce0b8e511fd..af39edae8c62 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -702,7 +702,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); - ndev->destructor = free_netdev; + ndev->destructor = brcmf_cfg80211_free_netdev; return 0; fail: @@ -859,8 +859,6 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx) } /* unregister will take care of freeing it */ unregister_netdev(ifp->ndev); - if (bssidx == 0) - brcmf_cfg80211_detach(drvr->config); } else { kfree(ifp); } @@ -963,8 +961,7 @@ int brcmf_bus_start(struct device *dev) fail: if (ret < 0) { brcmf_err("failed: %d\n", ret); - if (drvr->config) - brcmf_cfg80211_detach(drvr->config); + brcmf_cfg80211_detach(drvr->config); if (drvr->fws) { brcmf_fws_del_interface(ifp); brcmf_fws_deinit(drvr); @@ -1039,6 +1036,8 @@ void brcmf_detach(struct device *dev) brcmf_del_if(drvr, i); } + brcmf_cfg80211_detach(drvr->config); + brcmf_bus_detach(drvr); brcmf_proto_detach(drvr); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index f214510e3bee..9c7f08a13105 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -509,6 +509,8 @@ enum brcmf_sdio_frmtype { #define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt" #define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin" #define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt" +#define BCM43362_FIRMWARE_NAME "brcm/brcmfmac43362-sdio.bin" +#define BCM43362_NVRAM_NAME "brcm/brcmfmac43362-sdio.txt" #define BCM4339_FIRMWARE_NAME "brcm/brcmfmac4339-sdio.bin" #define BCM4339_NVRAM_NAME "brcm/brcmfmac4339-sdio.txt" @@ -526,6 +528,8 @@ MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4334_NVRAM_NAME); MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4335_NVRAM_NAME); +MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME); +MODULE_FIRMWARE(BCM43362_NVRAM_NAME); MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME); MODULE_FIRMWARE(BCM4339_NVRAM_NAME); @@ -552,6 +556,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = { { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) }, { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) }, { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) }, + { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) }, { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) } }; @@ -3384,7 +3389,8 @@ err: static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus) { - u32 addr, reg; + u32 addr, reg, pmu_cc3_mask = ~0; + int err; brcmf_dbg(TRACE, "Enter\n"); @@ -3392,13 +3398,27 @@ static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus) if (bus->ci->pmurev < 17) return false; - /* read PMU chipcontrol register 3*/ - addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr); - brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL); - addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data); - reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL); + switch (bus->ci->chip) { + case BCM43241_CHIP_ID: + case BCM4335_CHIP_ID: + case BCM4339_CHIP_ID: + /* read PMU chipcontrol register 3 */ + addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr); + brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL); + addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data); + reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL); + return (reg & pmu_cc3_mask) != 0; + default: + addr = CORE_CC_REG(bus->ci->c_inf[0].base, pmucapabilities_ext); + reg = brcmf_sdiod_regrl(bus->sdiodev, addr, &err); + if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0) + return false; - return (bool)reg; + addr = CORE_CC_REG(bus->ci->c_inf[0].base, retention_ctl); + reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL); + return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK | + PMU_RCTL_LOGIC_DISABLE_MASK)) == 0; + } } static void brcmf_sdio_sr_init(struct brcmf_sdio *bus) @@ -3615,7 +3635,7 @@ static int brcmf_sdio_bus_init(struct device *dev) } /* If we didn't come up, turn off backplane clock */ - if (bus_if->state != BRCMF_BUS_DATA) + if (ret != 0) brcmf_sdio_clkctl(bus, CLK_NONE, false); exit: @@ -3750,31 +3770,6 @@ static void brcmf_sdio_dataworker(struct work_struct *work) } } -static void brcmf_sdio_release_malloc(struct brcmf_sdio *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - kfree(bus->rxbuf); - bus->rxctl = bus->rxbuf = NULL; - bus->rxlen = 0; -} - -static bool brcmf_sdio_probe_malloc(struct brcmf_sdio *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - if (bus->sdiodev->bus_if->maxctl) { - bus->rxblen = - roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), - ALIGNMENT) + bus->head_align; - bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); - if (!(bus->rxbuf)) - return false; - } - - return true; -} - static bool brcmf_sdio_probe_attach(struct brcmf_sdio *bus) { @@ -3888,39 +3883,6 @@ fail: return false; } -static bool brcmf_sdio_probe_init(struct brcmf_sdio *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - sdio_claim_host(bus->sdiodev->func[1]); - - /* Disable F2 to clear any intermediate frame state on the dongle */ - sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]); - - bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; - bus->rxflow = false; - - /* Done with backplane-dependent accesses, can drop clock... */ - brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); - - sdio_release_host(bus->sdiodev->func[1]); - - /* ...and initialize clock/power states */ - bus->clkstate = CLK_SDONLY; - bus->idletime = BRCMF_IDLE_INTERVAL; - bus->idleclock = BRCMF_IDLE_ACTIVE; - - /* Query the F2 block size, set roundup accordingly */ - bus->blocksize = bus->sdiodev->func[2]->cur_blksize; - bus->roundup = min(max_roundup, bus->blocksize); - - /* SR state */ - bus->sleeping = false; - bus->sr_enabled = false; - - return true; -} - static int brcmf_sdio_watchdog_thread(void *data) { @@ -3955,24 +3917,6 @@ brcmf_sdio_watchdog(unsigned long data) } } -static void brcmf_sdio_release_dongle(struct brcmf_sdio *bus) -{ - brcmf_dbg(TRACE, "Enter\n"); - - if (bus->ci) { - sdio_claim_host(bus->sdiodev->func[1]); - brcmf_sdio_clkctl(bus, CLK_AVAIL, false); - brcmf_sdio_clkctl(bus, CLK_NONE, false); - sdio_release_host(bus->sdiodev->func[1]); - brcmf_sdio_chip_detach(&bus->ci); - if (bus->vars && bus->varsz) - kfree(bus->vars); - bus->vars = NULL; - } - - brcmf_dbg(TRACE, "Disconnected\n"); -} - static struct brcmf_bus_ops brcmf_sdio_bus_ops = { .stop = brcmf_sdio_bus_stop, .preinit = brcmf_sdio_bus_preinit, @@ -4066,15 +4010,42 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev) } /* Allocate buffers */ - if (!(brcmf_sdio_probe_malloc(bus))) { - brcmf_err("brcmf_sdio_probe_malloc failed\n"); - goto fail; + if (bus->sdiodev->bus_if->maxctl) { + bus->rxblen = + roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN), + ALIGNMENT) + bus->head_align; + bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC); + if (!(bus->rxbuf)) { + brcmf_err("rxbuf allocation failed\n"); + goto fail; + } } - if (!(brcmf_sdio_probe_init(bus))) { - brcmf_err("brcmf_sdio_probe_init failed\n"); - goto fail; - } + sdio_claim_host(bus->sdiodev->func[1]); + + /* Disable F2 to clear any intermediate frame state on the dongle */ + sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]); + + bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; + bus->rxflow = false; + + /* Done with backplane-dependent accesses, can drop clock... */ + brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + + sdio_release_host(bus->sdiodev->func[1]); + + /* ...and initialize clock/power states */ + bus->clkstate = CLK_SDONLY; + bus->idletime = BRCMF_IDLE_INTERVAL; + bus->idleclock = BRCMF_IDLE_ACTIVE; + + /* Query the F2 block size, set roundup accordingly */ + bus->blocksize = bus->sdiodev->func[2]->cur_blksize; + bus->roundup = min(max_roundup, bus->blocksize); + + /* SR state */ + bus->sleeping = false; + bus->sr_enabled = false; brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); @@ -4108,12 +4079,20 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus) if (bus->sdiodev->bus_if->drvr) { brcmf_detach(bus->sdiodev->dev); - brcmf_sdio_release_dongle(bus); + } + + if (bus->ci) { + sdio_claim_host(bus->sdiodev->func[1]); + brcmf_sdio_clkctl(bus, CLK_AVAIL, false); + brcmf_sdio_clkctl(bus, CLK_NONE, false); + sdio_release_host(bus->sdiodev->func[1]); + brcmf_sdio_chip_detach(&bus->ci); } brcmu_pkt_buf_free_skb(bus->txglom_sgpad); - brcmf_sdio_release_malloc(bus); + kfree(bus->rxbuf); kfree(bus->hdrbuf); + kfree(bus->vars); kfree(bus); } @@ -4131,7 +4110,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick) } /* don't start the wd until fw is loaded */ - if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) + if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA) return; if (wdtick) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c index 7918c1033662..c3e7d76dbf35 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c @@ -1873,7 +1873,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb) brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto)); /* determine the priority */ if (!skb->priority) - skb->priority = cfg80211_classify8021d(skb); + skb->priority = cfg80211_classify8021d(skb, NULL); drvr->tx_multicast += !!multicast; if (pae) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c index 185af8a84c9a..fc4f98b275d7 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/p2p.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/p2p.c @@ -1955,21 +1955,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg) err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1); if (err < 0) { brcmf_err("set p2p_disc error\n"); - brcmf_free_vif(cfg, p2p_vif); + brcmf_free_vif(p2p_vif); goto exit; } /* obtain bsscfg index for P2P discovery */ err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx); if (err < 0) { brcmf_err("retrieving discover bsscfg index failed\n"); - brcmf_free_vif(cfg, p2p_vif); + brcmf_free_vif(p2p_vif); goto exit; } /* Verify that firmware uses same bssidx as driver !! */ if (p2p_ifp->bssidx != bssidx) { brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n", bssidx, p2p_ifp->bssidx); - brcmf_free_vif(cfg, p2p_vif); + brcmf_free_vif(p2p_vif); goto exit; } @@ -1997,7 +1997,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p) brcmf_p2p_cancel_remain_on_channel(vif->ifp); brcmf_p2p_deinit_discovery(p2p); /* remove discovery interface */ - brcmf_free_vif(p2p->cfg, vif); + brcmf_free_vif(vif); p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; } /* just set it all to zero */ @@ -2222,7 +2222,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p, return &p2p_vif->wdev; fail: - brcmf_free_vif(p2p->cfg, p2p_vif); + brcmf_free_vif(p2p_vif); return ERR_PTR(err); } @@ -2231,31 +2231,12 @@ fail: * * @vif: virtual interface object to delete. */ -static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg, +static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p, struct brcmf_cfg80211_vif *vif) { cfg80211_unregister_wdev(&vif->wdev); - cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; - brcmf_free_vif(cfg, vif); -} - -/** - * brcmf_p2p_free_p2p_if() - free up net device related data. - * - * @ndev: net device that needs to be freed. - */ -static void brcmf_p2p_free_p2p_if(struct net_device *ndev) -{ - struct brcmf_cfg80211_info *cfg; - struct brcmf_cfg80211_vif *vif; - struct brcmf_if *ifp; - - ifp = netdev_priv(ndev); - cfg = ifp->drvr->config; - vif = ifp->vif; - - brcmf_free_vif(cfg, vif); - free_netdev(ifp->ndev); + p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL; + brcmf_free_vif(vif); } /** @@ -2335,8 +2316,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, brcmf_err("Registering netdevice failed\n"); goto fail; } - /* override destructor */ - ifp->ndev->destructor = brcmf_p2p_free_p2p_if; cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif; /* Disable firmware roaming for P2P interface */ @@ -2349,7 +2328,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name, return &ifp->vif->wdev; fail: - brcmf_free_vif(cfg, vif); + brcmf_free_vif(vif); return ERR_PTR(err); } @@ -2358,8 +2337,6 @@ fail: * * @wiphy: wiphy device of interface. * @wdev: wireless device of interface. - * - * TODO: not yet supported. */ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) { @@ -2385,7 +2362,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) break; case NL80211_IFTYPE_P2P_DEVICE: - brcmf_p2p_delete_p2pdev(cfg, vif); + brcmf_p2p_delete_p2pdev(p2p, vif); return 0; default: return -ENOTSUPP; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index 5f39f28e6efb..9fd40675f18e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -19,6 +19,7 @@ #include <linux/netdevice.h> #include <linux/mmc/card.h> #include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> #include <linux/ssb/ssb_regs.h> #include <linux/bcma/bcma.h> @@ -83,6 +84,24 @@ static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = { {0, 0x1} }; +/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */ +static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = { + {6, 0x7}, + {5, 0x6}, + {4, 0x5}, + {3, 0x4}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} +}; + +/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */ +static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = { + {3, 0x3}, + {2, 0x2}, + {1, 0x1}, + {0, 0x0} }; + /* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = { {16, 0x7}, @@ -569,6 +588,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, ci->ramsize = 0xc0000; ci->rambase = 0x180000; break; + case BCM43362_CHIP_ID: + ci->c_inf[0].wrapbase = 0x18100000; + ci->c_inf[0].cib = 0x27004211; + ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; + ci->c_inf[1].base = 0x18002000; + ci->c_inf[1].wrapbase = 0x18102000; + ci->c_inf[1].cib = 0x0a004211; + ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; + ci->c_inf[2].base = 0x18004000; + ci->c_inf[2].wrapbase = 0x18104000; + ci->c_inf[2].cib = 0x08080401; + ci->c_inf[3].id = BCMA_CORE_ARM_CM3; + ci->c_inf[3].base = 0x18003000; + ci->c_inf[3].wrapbase = 0x18103000; + ci->c_inf[3].cib = 0x03004211; + ci->ramsize = 0x3C000; + break; default: brcmf_err("chipid 0x%x is not supported\n", ci->chip); return -ENODEV; @@ -757,6 +793,11 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, str_mask = 0x00003800; str_shift = 11; break; + case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17): + str_tab = sdiod_drvstr_tab6_1v8; + str_mask = 0x00001800; + str_shift = 11; + break; case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17): /* note: 43143 does not support tristate */ i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1; @@ -769,6 +810,11 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, brcmf_sdio_chip_name(ci->chip, chn, 8), drivestrength); break; + case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13): + str_tab = sdiod_drive_strength_tab5_1v8; + str_mask = 0x00003800; + str_shift = 11; + break; default: brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n", brcmf_sdio_chip_name(ci->chip, chn, 8), diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h index d0f4b45b24c7..7ea424e20773 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h @@ -54,14 +54,6 @@ #define BRCMF_MAX_CORENUM 6 -/* SDIO device ID */ -#define SDIO_DEVICE_ID_BROADCOM_43143 43143 -#define SDIO_DEVICE_ID_BROADCOM_43241 0x4324 -#define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 -#define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 -#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 -#define SDIO_DEVICE_ID_BROADCOM_4335_4339 0x4335 - struct chip_core_info { u16 id; u16 rev; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index a0981b32c729..092e9c824992 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -167,7 +167,6 @@ struct brcmf_sdio_dev { u32 sbwad; /* Save backplane window address */ struct brcmf_sdio *bus; atomic_t suspend; /* suspend flag */ - wait_queue_head_t request_byte_wait; wait_queue_head_t request_word_wait; wait_queue_head_t request_buffer_wait; struct device *dev; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index 3966fe0fcfd9..aad83aef7d93 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -1095,10 +1095,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif) BRCMF_C_DISASSOC, NULL, 0); if (err) { brcmf_err("WLC_DISASSOC failed (%d)\n", err); - cfg80211_disconnected(vif->wdev.netdev, 0, - NULL, 0, GFP_KERNEL); } clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state); + cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL); + } clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state); clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status); @@ -1758,6 +1758,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev, return -EIO; clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state); + cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL); memcpy(&scbval.ea, &profile->bssid, ETH_ALEN); scbval.val = cpu_to_le32(reason_code); @@ -4359,9 +4360,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, { struct brcmf_cfg80211_vif *vif; - if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT) - return ERR_PTR(-ENOSPC); - brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", sizeof(*vif)); vif = kzalloc(sizeof(*vif), GFP_KERNEL); @@ -4378,21 +4376,25 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, brcmf_init_prof(&vif->profile); list_add_tail(&vif->list, &cfg->vif_list); - cfg->vif_cnt++; return vif; } -void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, - struct brcmf_cfg80211_vif *vif) +void brcmf_free_vif(struct brcmf_cfg80211_vif *vif) { list_del(&vif->list); - cfg->vif_cnt--; - kfree(vif); - if (!cfg->vif_cnt) { - wiphy_unregister(cfg->wiphy); - wiphy_free(cfg->wiphy); - } +} + +void brcmf_cfg80211_free_netdev(struct net_device *ndev) +{ + struct brcmf_cfg80211_vif *vif; + struct brcmf_if *ifp; + + ifp = netdev_priv(ndev); + vif = ifp->vif; + + brcmf_free_vif(vif); + free_netdev(ndev); } static bool brcmf_is_linkup(const struct brcmf_event_msg *e) @@ -4979,20 +4981,20 @@ cfg80211_p2p_attach_out: wl_deinit_priv(cfg); cfg80211_attach_out: - brcmf_free_vif(cfg, vif); + brcmf_free_vif(vif); return NULL; } void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg) { - struct brcmf_cfg80211_vif *vif; - struct brcmf_cfg80211_vif *tmp; + if (!cfg) + return; - wl_deinit_priv(cfg); + WARN_ON(!list_empty(&cfg->vif_list)); + wiphy_unregister(cfg->wiphy); brcmf_btcoex_detach(cfg); - list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) { - brcmf_free_vif(cfg, vif); - } + wl_deinit_priv(cfg); + wiphy_free(cfg->wiphy); } static s32 @@ -5087,7 +5089,8 @@ dongle_scantime_out: } -static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) +static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, + u32 bw_cap[]) { struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg)); struct ieee80211_channel *band_chan_arr; @@ -5100,7 +5103,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) enum ieee80211_band band; u32 channel; u32 *n_cnt; - bool ht40_allowed; u32 index; u32 ht40_flag; bool update; @@ -5133,18 +5135,17 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) array_size = ARRAY_SIZE(__wl_2ghz_channels); n_cnt = &__wl_band_2ghz.n_channels; band = IEEE80211_BAND_2GHZ; - ht40_allowed = (bw_cap == WLC_N_BW_40ALL); } else if (ch.band == BRCMU_CHAN_BAND_5G) { band_chan_arr = __wl_5ghz_a_channels; array_size = ARRAY_SIZE(__wl_5ghz_a_channels); n_cnt = &__wl_band_5ghz_a.n_channels; band = IEEE80211_BAND_5GHZ; - ht40_allowed = !(bw_cap == WLC_N_BW_20ALL); } else { - brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec); + brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec); continue; } - if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40) + if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) && + ch.bw == BRCMU_CHAN_BW_40) continue; update = false; for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) { @@ -5162,7 +5163,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap) ieee80211_channel_to_frequency(ch.chnum, band); band_chan_arr[index].hw_value = ch.chnum; - if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) { + brcmf_err("channel %d: f=%d bw=%d sb=%d\n", + ch.chnum, band_chan_arr[index].center_freq, + ch.bw, ch.sb); + if (ch.bw == BRCMU_CHAN_BW_40) { /* assuming the order is HT20, HT40 Upper, * HT40 lower from chanspecs */ @@ -5213,6 +5217,46 @@ exit: return err; } +static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[]) +{ + u32 band, mimo_bwcap; + int err; + + band = WLC_BAND_2G; + err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band); + if (!err) { + bw_cap[IEEE80211_BAND_2GHZ] = band; + band = WLC_BAND_5G; + err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band); + if (!err) { + bw_cap[IEEE80211_BAND_5GHZ] = band; + return; + } + WARN_ON(1); + return; + } + brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n"); + mimo_bwcap = 0; + err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap); + if (err) + /* assume 20MHz if firmware does not give a clue */ + mimo_bwcap = WLC_N_BW_20ALL; + + switch (mimo_bwcap) { + case WLC_N_BW_40ALL: + bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT; + /* fall-thru */ + case WLC_N_BW_20IN2G_40IN5G: + bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT; + /* fall-thru */ + case WLC_N_BW_20ALL: + bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT; + bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT; + break; + default: + brcmf_err("invalid mimo_bw_cap value\n"); + } +} static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) { @@ -5221,13 +5265,13 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) s32 phy_list; u32 band_list[3]; u32 nmode; - u32 bw_cap = 0; + u32 bw_cap[2] = { 0, 0 }; s8 phy; s32 err; u32 nband; s32 i; - struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS]; - s32 index; + struct ieee80211_supported_band *bands[2] = { NULL, NULL }; + struct ieee80211_supported_band *band; err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST, &phy_list, sizeof(phy_list)); @@ -5253,11 +5297,10 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) if (err) { brcmf_err("nmode error (%d)\n", err); } else { - err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap); - if (err) - brcmf_err("mimo_bw_cap error (%d)\n", err); + brcmf_get_bwcap(ifp, bw_cap); } - brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap); + brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode, + bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]); err = brcmf_construct_reginfo(cfg, bw_cap); if (err) { @@ -5266,40 +5309,33 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg) } nband = band_list[0]; - memset(bands, 0, sizeof(bands)); for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) { - index = -1; + band = NULL; if ((band_list[i] == WLC_BAND_5G) && - (__wl_band_5ghz_a.n_channels > 0)) { - index = IEEE80211_BAND_5GHZ; - bands[index] = &__wl_band_5ghz_a; - if ((bw_cap == WLC_N_BW_40ALL) || - (bw_cap == WLC_N_BW_20IN2G_40IN5G)) - bands[index]->ht_cap.cap |= - IEEE80211_HT_CAP_SGI_40; - } else if ((band_list[i] == WLC_BAND_2G) && - (__wl_band_2ghz.n_channels > 0)) { - index = IEEE80211_BAND_2GHZ; - bands[index] = &__wl_band_2ghz; - if (bw_cap == WLC_N_BW_40ALL) - bands[index]->ht_cap.cap |= - IEEE80211_HT_CAP_SGI_40; - } + (__wl_band_5ghz_a.n_channels > 0)) + band = &__wl_band_5ghz_a; + else if ((band_list[i] == WLC_BAND_2G) && + (__wl_band_2ghz.n_channels > 0)) + band = &__wl_band_2ghz; + else + continue; - if ((index >= 0) && nmode) { - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; - bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; - bands[index]->ht_cap.ht_supported = true; - bands[index]->ht_cap.ampdu_factor = - IEEE80211_HT_MAX_AMPDU_64K; - bands[index]->ht_cap.ampdu_density = - IEEE80211_HT_MPDU_DENSITY_16; - /* An HT shall support all EQM rates for one spatial - * stream - */ - bands[index]->ht_cap.mcs.rx_mask[0] = 0xff; + if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) { + band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40; + band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; } + band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20; + band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40; + band->ht_cap.ht_supported = true; + band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K; + band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16; + /* An HT shall support all EQM rates for one spatial + * stream + */ + band->ht_cap.mcs.rx_mask[0] = 0xff; + band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; + bands[band->band] = band; } wiphy = cfg_to_wiphy(cfg); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h index d9bdaf9a72d0..2dc6a074e8ed 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h @@ -412,7 +412,6 @@ struct brcmf_cfg80211_info { struct work_struct escan_timeout_work; u8 *escan_ioctl_buf; struct list_head vif_list; - u8 vif_cnt; struct brcmf_cfg80211_vif_event vif_event; struct completion vif_disabled; struct brcmu_d11inf d11inf; @@ -487,8 +486,7 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp); struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, enum nl80211_iftype type, bool pm_block); -void brcmf_free_vif(struct brcmf_cfg80211_info *cfg, - struct brcmf_cfg80211_vif *vif); +void brcmf_free_vif(struct brcmf_cfg80211_vif *vif); s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag, const u8 *vndr_ie_buf, u32 vndr_ie_len); @@ -507,5 +505,6 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg, bool fw_abort); void brcmf_set_mpc(struct brcmf_if *ndev, int mpc); void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg); +void brcmf_cfg80211_free_netdev(struct net_device *ndev); #endif /* _wl_cfg80211_h_ */ diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 84113ea16f84..6fa5d4863782 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -41,6 +41,7 @@ #define BCM4331_CHIP_ID 0x4331 #define BCM4334_CHIP_ID 0x4334 #define BCM4335_CHIP_ID 0x4335 +#define BCM43362_CHIP_ID 43362 #define BCM4339_CHIP_ID 0x4339 #endif /* _BRCM_HW_IDS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h index 0505cc065e0d..7ca2aa1035b2 100644 --- a/drivers/net/wireless/brcm80211/include/brcmu_wifi.h +++ b/drivers/net/wireless/brcm80211/include/brcmu_wifi.h @@ -82,6 +82,20 @@ #define WLC_N_BW_40ALL 1 #define WLC_N_BW_20IN2G_40IN5G 2 +#define WLC_BW_20MHZ_BIT BIT(0) +#define WLC_BW_40MHZ_BIT BIT(1) +#define WLC_BW_80MHZ_BIT BIT(2) +#define WLC_BW_160MHZ_BIT BIT(3) + +/* Bandwidth capabilities */ +#define WLC_BW_CAP_20MHZ (WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_40MHZ (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_80MHZ (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT| \ + WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_160MHZ (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \ + WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT) +#define WLC_BW_CAP_UNRESTRICTED 0xFF + /* band types */ #define WLC_BAND_AUTO 0 /* auto-select */ #define WLC_BAND_5G 1 /* 5 Ghz */ diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c index acdff0f7f952..5a9ffd3a6a6c 100644 --- a/drivers/net/wireless/cw1200/fwio.c +++ b/drivers/net/wireless/cw1200/fwio.c @@ -14,7 +14,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/vmalloc.h> #include <linux/sched.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c index 090f01577dd2..d1270da4dfea 100644 --- a/drivers/net/wireless/cw1200/main.c +++ b/drivers/net/wireless/cw1200/main.c @@ -21,7 +21,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/vmalloc.h> diff --git a/drivers/net/wireless/cw1200/pm.c b/drivers/net/wireless/cw1200/pm.c index b37abb9f0453..6907c8fd4578 100644 --- a/drivers/net/wireless/cw1200/pm.c +++ b/drivers/net/wireless/cw1200/pm.c @@ -225,7 +225,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) cw1200_set_pm(priv, &priv->powersave_mode); if (wait_event_interruptible_timeout(priv->ps_mode_switch_done, !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) { - goto revert3; + goto revert4; } } @@ -254,11 +254,11 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) /* Stop serving thread */ if (cw1200_bh_suspend(priv)) - goto revert4; + goto revert5; ret = timer_pending(&priv->mcast_timeout); if (ret) - goto revert5; + goto revert6; /* Store suspend state */ pm_state->suspend_state = state; @@ -280,9 +280,9 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) return 0; -revert5: +revert6: WARN_ON(cw1200_bh_resume(priv)); -revert4: +revert5: cw1200_resume_work(priv, &priv->bss_loss_work, state->bss_loss_tmo); cw1200_resume_work(priv, &priv->join_timeout, @@ -291,6 +291,7 @@ revert4: state->direct_probe); cw1200_resume_work(priv, &priv->link_id_gc_work, state->link_id_gc); +revert4: kfree(state); revert3: wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off); diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 56cd01ca8ad0..9f825f2620da 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c @@ -1,7 +1,6 @@ #define PRISM2_PCCARD #include <linux/module.h> -#include <linux/init.h> #include <linux/if.h> #include <linux/slab.h> #include <linux/wait.h> diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 2454a740ea50..3e5fa7872b64 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -2567,7 +2567,7 @@ static int prism2_ioctl_priv_prism2_param(struct net_device *dev, local->passive_scan_interval = value; if (timer_pending(&local->passive_scan_timer)) del_timer(&local->passive_scan_timer); - if (value > 0) { + if (value > 0 && value < INT_MAX / HZ) { local->passive_scan_timer.expires = jiffies + local->passive_scan_interval * HZ; add_timer(&local->passive_scan_timer); diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 05ca3402dca7..91158e2e961c 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -5,7 +5,6 @@ * Andy Warner <andyw@pobox.com> */ #include <linux/module.h> -#include <linux/init.h> #include <linux/if.h> #include <linux/skbuff.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index c3d067ee4db9..3bf530d9a40f 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c @@ -8,7 +8,6 @@ #include <linux/module.h> -#include <linux/init.h> #include <linux/if.h> #include <linux/skbuff.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/ipw2x00/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h index 570d6fb88967..aa301d1eee3c 100644 --- a/drivers/net/wireless/ipw2x00/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -29,7 +29,6 @@ #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/mutex.h> diff --git a/drivers/net/wireless/ipw2x00/libipw_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c index 5c6253811c52..a586a85bfcfe 100644 --- a/drivers/net/wireless/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -1468,7 +1468,7 @@ static inline int is_same_network(struct libipw_network *src, * as one network */ return ((src->ssid_len == dst->ssid_len) && (src->channel == dst->channel) && - ether_addr_equal(src->bssid, dst->bssid) && + ether_addr_equal_64bits(src->bssid, dst->bssid) && !memcmp(src->ssid, dst->ssid, src->ssid_len)); } diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index aea667b430c3..9a45f6f626f6 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c @@ -25,7 +25,6 @@ *****************************************************************************/ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlegacy/3945.c b/drivers/net/wireless/iwlegacy/3945.c index f09e257759d5..d37a6fd90d40 100644 --- a/drivers/net/wireless/iwlegacy/3945.c +++ b/drivers/net/wireless/iwlegacy/3945.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/pci.h> #include <linux/dma-mapping.h> @@ -466,10 +465,10 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header) switch (il->iw_mode) { case NL80211_IFTYPE_ADHOC: /* Header: Dest. | Source | BSSID */ /* packets to our IBSS update information */ - return ether_addr_equal(header->addr3, il->bssid); + return ether_addr_equal_64bits(header->addr3, il->bssid); case NL80211_IFTYPE_STATION: /* Header: Dest. | AP{BSSID} | Source */ /* packets to our IBSS update information */ - return ether_addr_equal(header->addr2, il->bssid); + return ether_addr_equal_64bits(header->addr2, il->bssid); default: return 1; } diff --git a/drivers/net/wireless/iwlegacy/4965-rs.c b/drivers/net/wireless/iwlegacy/4965-rs.c index 3ccbaf791b48..4d5e33259ca8 100644 --- a/drivers/net/wireless/iwlegacy/4965-rs.c +++ b/drivers/net/wireless/iwlegacy/4965-rs.c @@ -24,7 +24,6 @@ * *****************************************************************************/ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlegacy/4965.c b/drivers/net/wireless/iwlegacy/4965.c index 777a578294bd..fe47db9c20cd 100644 --- a/drivers/net/wireless/iwlegacy/4965.c +++ b/drivers/net/wireless/iwlegacy/4965.c @@ -26,7 +26,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/delay.h> diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index a27b14cfeaec..02e8233ccf29 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -33,7 +33,6 @@ #include <linux/slab.h> #include <linux/types.h> #include <linux/lockdep.h> -#include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> #include <linux/delay.h> @@ -3746,10 +3745,10 @@ il_full_rxon_required(struct il_priv *il) /* These items are only settable from the full RXON command */ CHK(!il_is_associated(il)); - CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr)); - CHK(!ether_addr_equal(staging->node_addr, active->node_addr)); - CHK(!ether_addr_equal(staging->wlap_bssid_addr, - active->wlap_bssid_addr)); + CHK(!ether_addr_equal_64bits(staging->bssid_addr, active->bssid_addr)); + CHK(!ether_addr_equal_64bits(staging->node_addr, active->node_addr)); + CHK(!ether_addr_equal_64bits(staging->wlap_bssid_addr, + active->wlap_bssid_addr)); CHK_NEQ(staging->dev_type, active->dev_type); CHK_NEQ(staging->channel, active->channel); CHK_NEQ(staging->air_propagation, active->air_propagation); diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index 23d5f0275ce9..562772d85102 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.c b/drivers/net/wireless/iwlwifi/dvm/calib.c index 1b0f0d502568..be1086c87157 100644 --- a/drivers/net/wireless/iwlwifi/dvm/calib.c +++ b/drivers/net/wireless/iwlwifi/dvm/calib.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/dvm/calib.h b/drivers/net/wireless/iwlwifi/dvm/calib.h index cfddde194940..aeae4e80ea40 100644 --- a/drivers/net/wireless/iwlwifi/dvm/calib.h +++ b/drivers/net/wireless/iwlwifi/dvm/calib.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index ebdac909f0cd..751ae1d10b7f 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index f69301e505ee..d2fe2596d54e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 7434d9edf3b7..3441f70d0ff9 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/devices.c b/drivers/net/wireless/iwlwifi/dvm/devices.c index 352c6cb7b4f1..7b140e487deb 100644 --- a/drivers/net/wireless/iwlwifi/dvm/devices.c +++ b/drivers/net/wireless/iwlwifi/dvm/devices.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/led.c b/drivers/net/wireless/iwlwifi/dvm/led.c index 33c7e15d24f5..ca4d6692cc4e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/led.c +++ b/drivers/net/wireless/iwlwifi/dvm/led.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -27,7 +27,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/skbuff.h> #include <linux/netdevice.h> diff --git a/drivers/net/wireless/iwlwifi/dvm/led.h b/drivers/net/wireless/iwlwifi/dvm/led.h index 8749dcfe695f..6a0817d9c4fa 100644 --- a/drivers/net/wireless/iwlwifi/dvm/led.h +++ b/drivers/net/wireless/iwlwifi/dvm/led.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 3d5bdc4217a8..576f7ee38ca5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,6 @@ #include <linux/etherdevice.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/sched.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 9f4239d31c08..40eb5e691475 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -28,7 +28,6 @@ *****************************************************************************/ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/dma-mapping.h> #include <linux/delay.h> diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index fd9f6cf96cfd..ba1b1ea54252 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/dvm/power.c b/drivers/net/wireless/iwlwifi/dvm/power.c index 77cb59712235..b4e61417013a 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.c +++ b/drivers/net/wireless/iwlwifi/dvm/power.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -30,7 +30,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/init.h> #include <net/mac80211.h> #include "iwl-io.h" #include "iwl-debug.h" diff --git a/drivers/net/wireless/iwlwifi/dvm/power.h b/drivers/net/wireless/iwlwifi/dvm/power.h index 7b03e1342d47..570d3a5e4670 100644 --- a/drivers/net/wireless/iwlwifi/dvm/power.h +++ b/drivers/net/wireless/iwlwifi/dvm/power.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.c b/drivers/net/wireless/iwlwifi/dvm/rs.c index b647e506564c..0977d93b529d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.c +++ b/drivers/net/wireless/iwlwifi/dvm/rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -24,7 +24,6 @@ * *****************************************************************************/ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/dvm/rs.h b/drivers/net/wireless/iwlwifi/dvm/rs.h index 41988f4b8a5a..bdd5644a400b 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rs.h +++ b/drivers/net/wireless/iwlwifi/dvm/rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index d71776dd1e6a..b68bb2f4d2c2 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portionhelp of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index d7ce2f12a907..503a81e58185 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 928f8640a0a7..be98b913ed58 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/dvm/sta.c b/drivers/net/wireless/iwlwifi/dvm/sta.c index c3c13ce96eb0..c0d070c5df5e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/sta.c +++ b/drivers/net/wireless/iwlwifi/dvm/sta.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c index fbeee081ee2f..058c5892c427 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.c +++ b/drivers/net/wireless/iwlwifi/dvm/tt.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -30,7 +30,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/init.h> #include <net/mac80211.h> #include "iwl-io.h" #include "iwl-modparams.h" diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.h b/drivers/net/wireless/iwlwifi/dvm/tt.h index 9356c4b908ca..507726534b84 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tt.h +++ b/drivers/net/wireless/iwlwifi/dvm/tt.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c index e12b1a63c484..a6839dfcb82d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/tx.c +++ b/drivers/net/wireless/iwlwifi/dvm/tx.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -29,7 +29,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/sched.h> #include <linux/ieee80211.h> #include "iwl-io.h" diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index 63637949a146..f59709a9b79d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -2,7 +2,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -28,7 +28,6 @@ *****************************************************************************/ #include <linux/kernel.h> -#include <linux/init.h> #include "iwl-io.h" #include "iwl-agn-hw.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c index 0d2afe098afc..854ba84ccb73 100644 --- a/drivers/net/wireless/iwlwifi/iwl-1000.c +++ b/drivers/net/wireless/iwlwifi/iwl-1000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c index c727ec7c90a6..3e63323637f3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-2000.c +++ b/drivers/net/wireless/iwlwifi/iwl-2000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index ecc01e1a61a1..6674f2c4541c 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c index 8ac305be68f4..8048de90233f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-6000.c +++ b/drivers/net/wireless/iwlwifi/iwl-6000.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 5fb37724c096..2a59da2ff87a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h index 6d73f943cefa..7f37fb86837b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index e05440ff5cd4..1ced525157dc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index da4eca8b3007..9d325516c42d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -198,7 +198,8 @@ CSR_INT_BIT_RF_KILL | \ CSR_INT_BIT_SW_RX | \ CSR_INT_BIT_WAKEUP | \ - CSR_INT_BIT_ALIVE) + CSR_INT_BIT_ALIVE | \ + CSR_INT_BIT_RX_PERIODIC) /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */ #define CSR_FH_INT_BIT_ERR (1 << 31) /* Error */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index b2bb32a781dd..a75aac986a23 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.c b/drivers/net/wireless/iwlwifi/iwl-devtrace.c index 8f61c717f619..23e7351e02de 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.c +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 684c416d3493..78bd41bf34b0 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 4bebfb58fc7b..c3728163be46 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h index 429337a2b9a1..592c01e11013 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.h +++ b/drivers/net/wireless/iwlwifi/iwl-drv.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -67,7 +67,7 @@ /* for all modules */ #define DRV_NAME "iwlwifi" #define IWLWIFI_VERSION "in-tree:" -#define DRV_COPYRIGHT "Copyright(c) 2003-2013 Intel Corporation" +#define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation" #define DRV_AUTHOR "<ilw@linux.intel.com>" diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c index 4380c16580eb..c44cf1149648 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h index d73304a23ec2..e3c7deafabe6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c index e5f2e362ab0b..25d0105741db 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h index 8e941f8bd7d6..a6d3bdf82cdd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom-read.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index 484d318245fb..9564ae173d06 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 4f95734b2811..88e2d6eb569f 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h index 8704e3042ca1..5f1493c44097 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c index ad8e19a56eca..f98175a0d35b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.c +++ b/drivers/net/wireless/iwlwifi/iwl-io.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 63d10ec08dbc..c339c1bed080 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project. * diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h index a1f580c0c6c6..0a84ade7edac 100644 --- a/drivers/net/wireless/iwlwifi/iwl-modparams.h +++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c index 940b8a9d5285..b5bc959b1dfe 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h index 2e2f1c8c99f9..95af97a6c2cf 100644 --- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h +++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c index a48decc6c68f..1b61cb529948 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h index 3325059c52d4..0c4399aba8c6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h +++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-op-mode.h b/drivers/net/wireless/iwlwifi/iwl-op-mode.h index f50e6c62ebc5..b5be51f3cd3d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-op-mode.h +++ b/drivers/net/wireless/iwlwifi/iwl-op-mode.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.c b/drivers/net/wireless/iwlwifi/iwl-phy-db.c index 1a405ae6a9c5..fa77d63a277a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.c +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-phy-db.h b/drivers/net/wireless/iwlwifi/iwl-phy-db.h index ce983af79644..9ee18d0d2d01 100644 --- a/drivers/net/wireless/iwlwifi/iwl-phy-db.h +++ b/drivers/net/wireless/iwlwifi/iwl-phy-db.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index f6412dae2659..d69b0fb0a434 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 0c3647858909..8d1b5ed3502a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -622,6 +622,10 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans, { int ret; + if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) && + test_bit(STATUS_RFKILL, &trans->status))) + return -ERFKILL; + if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status))) return -EIO; @@ -684,9 +688,6 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue, static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue) { - if (unlikely(trans->state != IWL_TRANS_FW_ALIVE)) - IWL_ERR(trans, "%s bad state = %d", __func__, trans->state); - trans->ops->txq_disable(trans, queue); } diff --git a/drivers/net/wireless/iwlwifi/mvm/binding.c b/drivers/net/wireless/iwlwifi/mvm/binding.c index 57d3eed86efa..a1376539d2dc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/binding.c +++ b/drivers/net/wireless/iwlwifi/mvm/binding.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c index d126245c48de..76cde6ce6551 100644 --- a/drivers/net/wireless/iwlwifi/mvm/bt-coex.c +++ b/drivers/net/wireless/iwlwifi/mvm/bt-coex.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -294,9 +294,9 @@ static const __le64 iwl_ci_mask[][3] = { cpu_to_le64(0x0) }, { - cpu_to_le64(0xFE00000000ULL), + cpu_to_le64(0xFFC0000000ULL), cpu_to_le64(0x0ULL), - cpu_to_le64(0x0) + cpu_to_le64(0x0ULL) }, }; diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h index 4b6d670c3509..036857698565 100644 --- a/drivers/net/wireless/iwlwifi/mvm/constants.h +++ b/drivers/net/wireless/iwlwifi/mvm/constants.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c index 665f87e788d6..f04d2f4d80cd 100644 --- a/drivers/net/wireless/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/iwlwifi/mvm/d3.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c index b8667575bc10..0e29cd83a06a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index e8f62a6a1b57..76cdce9edf55 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -123,51 +123,31 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, { struct iwl_mvm *mvm = file->private_data; const struct fw_img *img; - int ofs, len, pos = 0; - size_t bufsz, ret; - char *buf; + unsigned int ofs, len; + size_t ret; u8 *ptr; if (!mvm->ucode_loaded) return -EINVAL; /* default is to dump the entire data segment */ + img = &mvm->fw->img[mvm->cur_ucode]; + ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; + len = img->sec[IWL_UCODE_SECTION_DATA].len; + if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) { - img = &mvm->fw->img[mvm->cur_ucode]; - ofs = img->sec[IWL_UCODE_SECTION_DATA].offset; - len = img->sec[IWL_UCODE_SECTION_DATA].len; - } else { ofs = mvm->dbgfs_sram_offset; len = mvm->dbgfs_sram_len; } - bufsz = len * 4 + 256; - buf = kzalloc(bufsz, GFP_KERNEL); - if (!buf) - return -ENOMEM; - ptr = kzalloc(len, GFP_KERNEL); - if (!ptr) { - kfree(buf); + if (!ptr) return -ENOMEM; - } - - pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len); - pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", ofs); iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len); - for (ofs = 0; ofs < len; ofs += 16) { - pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos, - bufsz - pos, false); - pos += strlen(buf + pos); - if (bufsz - pos > 0) - buf[pos++] = '\n'; - } - ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len); - kfree(buf); kfree(ptr); return ret; @@ -176,11 +156,24 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf, static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { + const struct fw_img *img; u32 offset, len; + u32 img_offset, img_len; + + if (!mvm->ucode_loaded) + return -EINVAL; + + img = &mvm->fw->img[mvm->cur_ucode]; + img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset; + img_len = img->sec[IWL_UCODE_SECTION_DATA].len; if (sscanf(buf, "%x,%x", &offset, &len) == 2) { if ((offset & 0x3) || (len & 0x3)) return -EINVAL; + + if (offset + len > img_offset + img_len) + return -EINVAL; + mvm->dbgfs_sram_offset = offset; mvm->dbgfs_sram_len = len; } else { diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.h b/drivers/net/wireless/iwlwifi/mvm/debugfs.h index 85f9f958bfd2..e3a9774af495 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.h +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h index af500996bbf1..1b4e54d416b0 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index 4e7dd8cf87dc..8415ff312d0e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h index 39c3148bdfa8..c405cda1025f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index cb78e5539357..884c08725308 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h index 532312c7b937..85057219cc43 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h index b3ed59237cba..73cbba7424f2 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h index 8c73ba74b6fd..6bbbad453a3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h index 22864671d66c..b674c2a2b51c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h index 1c3079714c2b..989d7dbdca6c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index 27ba104a3540..c03d39541f9e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/led.c b/drivers/net/wireless/iwlwifi/mvm/led.c index 2269a9e5cc67..6b4ea6bf8ffe 100644 --- a/drivers/net/wireless/iwlwifi/mvm/led.c +++ b/drivers/net/wireless/iwlwifi/mvm/led.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -103,7 +103,7 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm) return 0; default: return -EINVAL; - }; + } mvm->led.name = kasprintf(GFP_KERNEL, "%s-led", wiphy_name(mvm->hw->wiphy)); diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index fb93961da750..ba723d50939a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -69,10 +69,10 @@ #include "mvm.h" const u8 iwl_mvm_ac_to_tx_fifo[] = { - IWL_MVM_TX_FIFO_BK, - IWL_MVM_TX_FIFO_BE, - IWL_MVM_TX_FIFO_VI, IWL_MVM_TX_FIFO_VO, + IWL_MVM_TX_FIFO_VI, + IWL_MVM_TX_FIFO_BE, + IWL_MVM_TX_FIFO_BK, }; struct iwl_mvm_mac_iface_iterator_data { @@ -85,35 +85,15 @@ struct iwl_mvm_mac_iface_iterator_data { bool found_vif; }; -static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, - struct ieee80211_vif *vif) +static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac, + struct ieee80211_vif *vif) { struct iwl_mvm_mac_iface_iterator_data *data = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - u32 ac; - /* Iterator may already find the interface being added -- skip it */ - if (vif == data->vif) { - data->found_vif = true; + /* Skip the interface for which we are trying to assign a tsf_id */ + if (vif == data->vif) return; - } - - /* Mark the queues used by the vif */ - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) - if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) - __set_bit(vif->hw_queue[ac], data->used_hw_queues); - - if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) - __set_bit(vif->cab_queue, data->used_hw_queues); - - /* - * Mark MAC IDs as used by clearing the available bit, and - * (below) mark TSFs as used if their existing use is not - * compatible with the new interface type. - * No locking or atomic bit operations are needed since the - * data is on the stack of the caller function. - */ - __clear_bit(mvmvif->id, data->available_mac_ids); /* * The TSF is a hardware/firmware resource, there are 4 and @@ -135,21 +115,26 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, case NL80211_IFTYPE_STATION: /* * The new interface is client, so if the existing one - * we're iterating is an AP, the TSF should be used to + * we're iterating is an AP, and both interfaces have the + * same beacon interval, the same TSF should be used to * avoid drift between the new client and existing AP, * the existing AP will get drift updates from the new * client context in this case */ if (vif->type == NL80211_IFTYPE_AP) { if (data->preferred_tsf == NUM_TSF_IDS && - test_bit(mvmvif->tsf_id, data->available_tsf_ids)) + test_bit(mvmvif->tsf_id, data->available_tsf_ids) && + (vif->bss_conf.beacon_int == + data->vif->bss_conf.beacon_int)) { data->preferred_tsf = mvmvif->tsf_id; - return; + return; + } } break; case NL80211_IFTYPE_AP: /* - * The new interface is AP/GO, so should get drift + * The new interface is AP/GO, so in case both interfaces + * have the same beacon interval, it should get drift * updates from an existing client or use the same * TSF as an existing GO. There's no drift between * TSFs internally but if they used different TSFs @@ -159,9 +144,12 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, if (vif->type == NL80211_IFTYPE_STATION || vif->type == NL80211_IFTYPE_AP) { if (data->preferred_tsf == NUM_TSF_IDS && - test_bit(mvmvif->tsf_id, data->available_tsf_ids)) + test_bit(mvmvif->tsf_id, data->available_tsf_ids) && + (vif->bss_conf.beacon_int == + data->vif->bss_conf.beacon_int)) { data->preferred_tsf = mvmvif->tsf_id; - return; + return; + } } break; default: @@ -187,6 +175,39 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, data->preferred_tsf = NUM_TSF_IDS; } +static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_mac_iface_iterator_data *data = _data; + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + u32 ac; + + /* Iterator may already find the interface being added -- skip it */ + if (vif == data->vif) { + data->found_vif = true; + return; + } + + /* Mark the queues used by the vif */ + for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) + if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE) + __set_bit(vif->hw_queue[ac], data->used_hw_queues); + + if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE) + __set_bit(vif->cab_queue, data->used_hw_queues); + + /* Mark MAC IDs as used by clearing the available bit, and + * (below) mark TSFs as used if their existing use is not + * compatible with the new interface type. + * No locking or atomic bit operations are needed since the + * data is on the stack of the caller function. + */ + __clear_bit(mvmvif->id, data->available_mac_ids); + + /* find a suitable tsf_id */ + iwl_mvm_mac_tsf_id_iter(_data, mac, vif); +} + /* * Get the mask of the queus used by the vif */ @@ -205,6 +226,29 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm, return qmask; } +void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, + struct ieee80211_vif *vif) +{ + struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); + struct iwl_mvm_mac_iface_iterator_data data = { + .mvm = mvm, + .vif = vif, + .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 }, + /* no preference yet */ + .preferred_tsf = NUM_TSF_IDS, + }; + + ieee80211_iterate_active_interfaces_atomic( + mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL, + iwl_mvm_mac_tsf_id_iter, &data); + + if (data.preferred_tsf != NUM_TSF_IDS) + mvmvif->tsf_id = data.preferred_tsf; + else if (!test_bit(mvmvif->tsf_id, data.available_tsf_ids)) + mvmvif->tsf_id = find_first_bit(data.available_tsf_ids, + NUM_TSF_IDS); +} + static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm, struct ieee80211_vif *vif) { @@ -586,18 +630,23 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm, cpu_to_le32(vif->bss_conf.use_short_slot ? MAC_FLG_SHORT_SLOT : 0); - for (i = 0; i < AC_NUM; i++) { - cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min); - cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max); - cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs; - cmd->ac[i].edca_txop = + for (i = 0; i < IEEE80211_NUM_ACS; i++) { + u8 txf = iwl_mvm_ac_to_tx_fifo[i]; + + cmd->ac[txf].cw_min = + cpu_to_le16(mvmvif->queue_params[i].cw_min); + cmd->ac[txf].cw_max = + cpu_to_le16(mvmvif->queue_params[i].cw_max); + cmd->ac[txf].edca_txop = cpu_to_le16(mvmvif->queue_params[i].txop * 32); - cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]); + cmd->ac[txf].aifsn = mvmvif->queue_params[i].aifs; + cmd->ac[txf].fifos_mask = BIT(txf); } /* in AP mode, the MCAST FIFO takes the EDCA params from VO */ if (vif->type == NL80211_IFTYPE_AP) - cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST); + cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |= + BIT(IWL_MVM_TX_FIFO_MCAST); if (vif->bss_conf.qos) cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA); @@ -1007,7 +1056,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm, iwl_mvm_mac_ap_iterator, &data); if (data.beacon_device_ts) { - u32 rand = (prandom_u32() % (80 - 20)) + 20; + u32 rand = (prandom_u32() % (64 - 36)) + 36; mvmvif->ap_beacon_time = data.beacon_device_ts + ieee80211_tu_to_usec(data.beacon_int * rand / 100); @@ -1186,10 +1235,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac, struct ieee80211_vif *vif) { - u16 *id = _data; + struct iwl_missed_beacons_notif *missed_beacons = _data; struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); - if (mvmvif->id == *id) + if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id)) + return; + + /* + * TODO: the threshold should be adjusted based on latency conditions, + * and/or in case of a CS flow on one of the other AP vifs. + */ + if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) > + IWL_MVM_MISSED_BEACONS_THRESHOLD) ieee80211_beacon_loss(vif); } @@ -1198,12 +1255,19 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, struct iwl_device_cmd *cmd) { struct iwl_rx_packet *pkt = rxb_addr(rxb); - struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data; - u16 id = (u16)le32_to_cpu(missed_beacons->mac_id); + struct iwl_missed_beacons_notif *mb = (void *)pkt->data; + + IWL_DEBUG_INFO(mvm, + "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n", + le32_to_cpu(mb->mac_id), + le32_to_cpu(mb->consec_missed_beacons), + le32_to_cpu(mb->consec_missed_beacons_since_last_rx), + le32_to_cpu(mb->num_recvd_beacons), + le32_to_cpu(mb->num_expected_beacons)); ieee80211_iterate_active_interfaces_atomic(mvm->hw, IEEE80211_IFACE_ITER_NORMAL, iwl_mvm_beacon_loss_iterator, - &id); + mb); return 0; } diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 2f5269359dce..b41177eb4888 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -262,7 +262,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm) mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; /* currently FW API supports only one optional cipher scheme */ - if (mvm->fw->cs && mvm->fw->cs->cipher) { + if (mvm->fw->cs->cipher) { mvm->hw->n_cipher_schemes = 1; mvm->hw->cipher_schemes = mvm->fw->cs; } @@ -866,6 +866,14 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); int ret; + /* + * Re-calculate the tsf id, as the master-slave relations depend on the + * beacon interval, which was not known when the station interface was + * added. + */ + if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc) + iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); + ret = iwl_mvm_mac_ctxt_changed(mvm, vif); if (ret) IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr); @@ -979,6 +987,13 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw, if (ret) goto out_unlock; + /* + * Re-calculate the tsf id, as the master-slave relations depend on the + * beacon interval, which was not known when the AP interface was added. + */ + if (vif->type == NL80211_IFTYPE_AP) + iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif); + /* Add the mac context */ ret = iwl_mvm_mac_ctxt_add(mvm, vif); if (ret) @@ -1671,7 +1686,8 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw, if (WARN_ONCE((phy_ctxt->ref > 1) && (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH | IEEE80211_CHANCTX_CHANGE_RX_CHAINS | - IEEE80211_CHANCTX_CHANGE_RADAR)), + IEEE80211_CHANCTX_CHANGE_RADAR | + IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)), "Cannot change PHY. Ref=%d, changed=0x%X\n", phy_ctxt->ref, changed)) return; diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 84edf3649ad2..e4ead86f06d6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -81,6 +81,7 @@ #define IWL_MVM_MAX_ADDRESSES 5 /* RSSI offset for WkP */ #define IWL_RSSI_OFFSET 50 +#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8 enum iwl_mvm_tx_fifo { IWL_MVM_TX_FIFO_BK = 0, @@ -711,6 +712,8 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd); +void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm, + struct ieee80211_vif *vif); /* Bindings */ int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif); diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c index 48089b1625ff..c6beb0f842d5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/nvm.c +++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -367,16 +367,17 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm) break; } + if (WARN(section_id >= NVM_NUM_OF_SECTIONS, + "Invalid NVM section ID %d\n", section_id)) { + ret = -EINVAL; + break; + } + temp = kmemdup(file_sec->data, section_size, GFP_KERNEL); if (!temp) { ret = -ENOMEM; break; } - if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) { - IWL_ERR(mvm, "Invalid NVM section ID\n"); - ret = -EINVAL; - break; - } mvm->nvm_sections[section_id].data = temp; mvm->nvm_sections[section_id].length = section_size; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index a362430477a0..552c76a926ed 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -665,6 +665,8 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state) else clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status); + if (state && mvm->cur_ucode != IWL_UCODE_INIT) + iwl_trans_stop_device(mvm->trans); wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm)); } diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c index a8652ddd6bed..b7268c0b3333 100644 --- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/power.c b/drivers/net/wireless/iwlwifi/mvm/power.c index 483ecc67501f..d9eab3b7bb9f 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power.c +++ b/drivers/net/wireless/iwlwifi/mvm/power.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,7 +64,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> -#include <linux/init.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c index 2ce79bad5845..ef712ae5bc62 100644 --- a/drivers/net/wireless/iwlwifi/mvm/power_legacy.c +++ b/drivers/net/wireless/iwlwifi/mvm/power_legacy.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/quota.c b/drivers/net/wireless/iwlwifi/mvm/quota.c index 38165eba2a17..ce5db6c4ef7e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/quota.c +++ b/drivers/net/wireless/iwlwifi/mvm/quota.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index d6d28d7b442b..ba078a3322b8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -24,7 +24,6 @@ * *****************************************************************************/ #include <linux/kernel.h> -#include <linux/init.h> #include <linux/skbuff.h> #include <linux/slab.h> #include <net/mac80211.h> @@ -700,7 +699,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate, u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate); u8 nss; - memset(rate, 0, sizeof(struct rs_rate)); + memset(rate, 0, sizeof(*rate)); rate->index = iwl_hwrate_to_plcp_idx(ucode_rate); if (rate->index == IWL_RATE_INVALID) { @@ -2121,7 +2120,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, tbl->column = RS_COLUMN_LEGACY_ANT_B; rs_set_expected_tpt_table(lq_sta, tbl); - rs_fill_lq_cmd(NULL, NULL, lq_sta, rate); + rs_fill_lq_cmd(mvm, sta, lq_sta, rate); /* TODO restore station should remember the lq cmd */ iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init); } @@ -2446,10 +2445,9 @@ static void rs_build_rates_table(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq_cmd = &lq_sta->lq; bool toggle_ant = false; - memcpy(&rate, initial_rate, sizeof(struct rs_rate)); + memcpy(&rate, initial_rate, sizeof(rate)); - if (mvm) - valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); + valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw); if (is_siso(&rate)) { num_rates = RS_INITIAL_SISO_NUM_RATES; @@ -2623,7 +2621,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm, struct rs_rate rate; rs_rate_from_ucode_rate(lq_sta->dbg_fixed_rate, lq_sta->band, &rate); - rs_fill_lq_cmd(NULL, NULL, lq_sta, &rate); + rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate); iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false); } } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index c31aa59728ea..7bc6404f6986 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 454341cc3b27..a85b60f7e67e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 4ce9bb581144..0e0007960612 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -473,13 +473,18 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm) if (mvm->scan_status == IWL_MVM_SCAN_NONE) return; + if (iwl_mvm_is_radio_killed(mvm)) { + ieee80211_scan_completed(mvm->hw, true); + mvm->scan_status = IWL_MVM_SCAN_NONE; + return; + } + iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort, scan_abort_notif, ARRAY_SIZE(scan_abort_notif), iwl_mvm_scan_abort_notif, NULL); - ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, - CMD_SYNC | CMD_SEND_IN_RFKILL, 0, NULL); + ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL); if (ret) { IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret); /* mac80211's state will be cleaned in the fw_restart flow */ diff --git a/drivers/net/wireless/iwlwifi/mvm/sf.c b/drivers/net/wireless/iwlwifi/mvm/sf.c index 97bb3c3e75ce..8401627c0030 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sf.c +++ b/drivers/net/wireless/iwlwifi/mvm/sf.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index 0a8af2083ddc..ec1812133235 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h index b34941148a98..4968d0237dc5 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.h +++ b/drivers/net/wireless/iwlwifi/mvm/sta.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/testmode.h b/drivers/net/wireless/iwlwifi/mvm/testmode.h index eb74391d91ca..0241665925f7 100644 --- a/drivers/net/wireless/iwlwifi/mvm/testmode.h +++ b/drivers/net/wireless/iwlwifi/mvm/testmode.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.c b/drivers/net/wireless/iwlwifi/mvm/time-event.c index 95ce4b601fef..50f3d7f560bc 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.c +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/time-event.h b/drivers/net/wireless/iwlwifi/mvm/time-event.h index d9c8d6cfa2db..4a61c8c02372 100644 --- a/drivers/net/wireless/iwlwifi/mvm/time-event.h +++ b/drivers/net/wireless/iwlwifi/mvm/time-event.h @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c index a0ec7b3473bd..3afa6b6bf835 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tt.c +++ b/drivers/net/wireless/iwlwifi/mvm/tt.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c index 735f86da7985..3c575a39987b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/tx.c +++ b/drivers/net/wireless/iwlwifi/mvm/tx.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c index f4aff56a36da..487d61b25359 100644 --- a/drivers/net/wireless/iwlwifi/mvm/utils.c +++ b/drivers/net/wireless/iwlwifi/mvm/utils.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2e97a3995333..3040924f5f3c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -362,21 +362,27 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = { {IWL_PCI_DEVICE(0x095B, 0x5310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5302, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5210, iwl7265_2ac_cfg)}, - {IWL_PCI_DEVICE(0x095B, 0x5012, iwl7265_2ac_cfg)}, - {IWL_PCI_DEVICE(0x095B, 0x500A, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5012, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x500A, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5410, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5400, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x1010, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5000, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5200, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5002, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5202, iwl7265_n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9010, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9110, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9210, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9510, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x9310, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x9410, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5020, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x502A, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5420, iwl7265_2n_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5090, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5190, iwl7265_2ac_cfg)}, + {IWL_PCI_DEVICE(0x095A, 0x5590, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095B, 0x5290, iwl7265_2ac_cfg)}, {IWL_PCI_DEVICE(0x095A, 0x5490, iwl7265_2ac_cfg)}, #endif /* CONFIG_IWLMVM */ diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 674c75b0d002..e851f26fd44c 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -262,6 +262,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @rx_page_order: page order for receive buffer size * @wd_timeout: queue watchdog timeout (jiffies) * @reg_lock: protect hw register access + * @cmd_in_flight: true when we have a host command in flight */ struct iwl_trans_pcie { struct iwl_rxq rxq; @@ -273,7 +274,6 @@ struct iwl_trans_pcie { __le32 *ict_tbl; dma_addr_t ict_tbl_dma; int ict_index; - u32 inta; bool use_ict; struct isr_statistics isr_stats; @@ -311,6 +311,7 @@ struct iwl_trans_pcie { /*protect hw register */ spinlock_t reg_lock; + bool cmd_in_flight; }; #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \ @@ -343,7 +344,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans); /***************************************************** * ICT - interrupt handling ******************************************************/ -irqreturn_t iwl_pcie_isr_ict(int irq, void *data); +irqreturn_t iwl_pcie_isr(int irq, void *data); int iwl_pcie_alloc_ict(struct iwl_trans *trans); void iwl_pcie_free_ict(struct iwl_trans *trans); void iwl_pcie_reset_ict(struct iwl_trans *trans); @@ -397,13 +398,17 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans) IWL_DEBUG_ISR(trans, "Enabling interrupts\n"); set_bit(STATUS_INT_ENABLED, &trans->status); + trans_pcie->inta_mask = CSR_INI_SET_MASK; iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } static inline void iwl_enable_rfkill_int(struct iwl_trans *trans) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n"); - iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL); + trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL; + iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask); } static inline void iwl_wake_queue(struct iwl_trans *trans, @@ -456,4 +461,31 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans) CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW); } +static inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, + u32 reg, u32 mask, u32 value) +{ + u32 v; + +#ifdef CONFIG_IWLWIFI_DEBUG + WARN_ON_ONCE(value & ~mask); +#endif + + v = iwl_read32(trans, reg); + v &= ~mask; + v |= value; + iwl_write32(trans, reg, v); +} + +static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, + u32 reg, u32 mask) +{ + __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); +} + +static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, + u32 reg, u32 mask) +{ + __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); +} + #endif /* __iwl_trans_int_pcie_h__ */ diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index 7aeec5ccefa5..1890ea29c264 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -148,10 +148,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans) static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_rxq *rxq) { - unsigned long flags; u32 reg; - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); if (rxq->need_update == 0) goto exit_unlock; @@ -190,7 +189,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, rxq->need_update = 0; exit_unlock: - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); } /* @@ -209,7 +208,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; - unsigned long flags; /* * If the device isn't enabled - not need to try to add buffers... @@ -222,7 +220,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status)) return; - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) { /* The overwritten rxb must be a used one */ rxb = rxq->queue[rxq->write]; @@ -239,7 +237,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) rxq->write = (rxq->write + 1) & RX_QUEUE_MASK; rxq->free_count--; } - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); /* If the pre-allocated buffer pool is dropping low, schedule to * refill it */ if (rxq->free_count <= RX_LOW_WATERMARK) @@ -248,9 +246,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ if (rxq->write_actual != (rxq->write & ~0x7)) { - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); rxq->need_update = 1; - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); iwl_pcie_rxq_inc_wr_ptr(trans, rxq); } } @@ -270,16 +268,15 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_rx_mem_buffer *rxb; struct page *page; - unsigned long flags; gfp_t gfp_mask = priority; while (1) { - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); if (list_empty(&rxq->rx_used)) { - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); return; } - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); if (rxq->free_count > RX_LOW_WATERMARK) gfp_mask |= __GFP_NOWARN; @@ -308,17 +305,17 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) return; } - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); if (list_empty(&rxq->rx_used)) { - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); __free_pages(page, trans_pcie->rx_page_order); return; } rxb = list_first_entry(&rxq->rx_used, struct iwl_rx_mem_buffer, list); list_del(&rxb->list); - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); BUG_ON(rxb->page); rxb->page = page; @@ -329,9 +326,9 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) DMA_FROM_DEVICE); if (dma_mapping_error(trans->dev, rxb->page_dma)) { rxb->page = NULL; - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); list_add(&rxb->list, &rxq->rx_used); - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); __free_pages(page, trans_pcie->rx_page_order); return; } @@ -340,12 +337,12 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority) /* and also 256 byte aligned! */ BUG_ON(rxb->page_dma & DMA_BIT_MASK(8)); - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); } } @@ -379,13 +376,12 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans) static void iwl_pcie_rx_replenish(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL); - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_pcie_rxq_restock(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); } static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans) @@ -511,7 +507,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; int i, err; - unsigned long flags; if (!rxq->bd) { err = iwl_pcie_rx_alloc(trans); @@ -519,7 +514,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) return err; } - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work); @@ -535,16 +530,16 @@ int iwl_pcie_rx_init(struct iwl_trans *trans) rxq->read = rxq->write = 0; rxq->write_actual = 0; memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts)); - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); iwl_pcie_rx_replenish(trans); iwl_pcie_rx_hw_init(trans, rxq); - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); rxq->need_update = 1; iwl_pcie_rxq_inc_wr_ptr(trans, rxq); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); return 0; } @@ -553,7 +548,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; - unsigned long flags; /*if rxq->bd is NULL, it means that nothing has been allocated, * exit now */ @@ -564,9 +558,9 @@ void iwl_pcie_rx_free(struct iwl_trans *trans) cancel_work_sync(&trans_pcie->rx_replenish); - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); iwl_pcie_rxq_free_rbs(trans); - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE, rxq->bd, rxq->bd_dma); @@ -589,7 +583,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_rxq *rxq = &trans_pcie->rxq; struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; - unsigned long flags; bool page_stolen = false; int max_len = PAGE_SIZE << trans_pcie->rx_page_order; u32 offset = 0; @@ -691,7 +684,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, /* Reuse the page if possible. For notification packets and * SKBs that fail to Rx correctly, add them back into the * rx_free list for reuse later. */ - spin_lock_irqsave(&rxq->lock, flags); + spin_lock(&rxq->lock); if (rxb->page != NULL) { rxb->page_dma = dma_map_page(trans->dev, rxb->page, 0, @@ -712,7 +705,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans, } } else list_add_tail(&rxb->list, &rxq->rx_used); - spin_unlock_irqrestore(&rxq->lock, flags); + spin_unlock(&rxq->lock); } /* @@ -807,6 +800,87 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans) wake_up(&trans_pcie->wait_command_queue); } +static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 inta; + + lockdep_assert_held(&trans_pcie->irq_lock); + + trace_iwlwifi_dev_irq(trans->dev); + + /* Discover which interrupts are active/pending */ + inta = iwl_read32(trans, CSR_INT); + + /* the thread will service interrupts and re-enable them */ + return inta; +} + +/* a device (PCI-E) page is 4096 bytes long */ +#define ICT_SHIFT 12 +#define ICT_SIZE (1 << ICT_SHIFT) +#define ICT_COUNT (ICT_SIZE / sizeof(u32)) + +/* interrupt handler using ict table, with this interrupt driver will + * stop using INTA register to get device's interrupt, reading this register + * is expensive, device will write interrupts in ICT dram table, increment + * index then will fire interrupt to driver, driver will OR all ICT table + * entries from current index up to table entry with 0 value. the result is + * the interrupt we need to service, driver will set the entries back to 0 and + * set index. + */ +static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + u32 inta; + u32 val = 0; + u32 read; + + trace_iwlwifi_dev_irq(trans->dev); + + /* Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. */ + read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); + trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read); + if (!read) + return 0; + + /* + * Collect all entries up to the first 0, starting from ict_index; + * note we already read at ict_index. + */ + do { + val |= read; + IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", + trans_pcie->ict_index, read); + trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; + trans_pcie->ict_index = + iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); + + read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); + trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, + read); + } while (read); + + /* We should not get this value, just ignore it. */ + if (val == 0xffffffff) + val = 0; + + /* + * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit + * (bit 15 before shifting it to 31) to clear when using interrupt + * coalescing. fortunately, bits 18 and 19 stay set when this happens + * so we use them to decide on the real state of the Rx bit. + * In order words, bit 15 is set if bit 18 or bit 19 are set. + */ + if (val & 0xC0000) + val |= 0x8000; + + inta = (0xff & val) | ((0xff00 & val) << 16); + return inta; +} + irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) { struct iwl_trans *trans = dev_id; @@ -814,12 +888,61 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) struct isr_statistics *isr_stats = &trans_pcie->isr_stats; u32 inta = 0; u32 handled = 0; - unsigned long flags; u32 i; lock_map_acquire(&trans->sync_cmd_lockdep_map); - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); + + /* dram interrupt table not set yet, + * use legacy interrupt. + */ + if (likely(trans_pcie->use_ict)) + inta = iwl_pcie_int_cause_ict(trans); + else + inta = iwl_pcie_int_cause_non_ict(trans); + + if (iwl_have_debug_level(IWL_DL_ISR)) { + IWL_DEBUG_ISR(trans, + "ISR inta 0x%08x, enabled 0x%08x(sw), enabled(hw) 0x%08x, fh 0x%08x\n", + inta, trans_pcie->inta_mask, + iwl_read32(trans, CSR_INT_MASK), + iwl_read32(trans, CSR_FH_INT_STATUS)); + if (inta & (~trans_pcie->inta_mask)) + IWL_DEBUG_ISR(trans, + "We got a masked interrupt (0x%08x)\n", + inta & (~trans_pcie->inta_mask)); + } + + inta &= trans_pcie->inta_mask; + + /* + * Ignore interrupt if there's nothing in NIC to service. + * This may be due to IRQ shared with another device, + * or due to sporadic interrupts thrown from our NIC. + */ + if (unlikely(!inta)) { + IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); + /* + * Re-enable interrupts here since we don't + * have anything to service + */ + if (test_bit(STATUS_INT_ENABLED, &trans->status)) + iwl_enable_interrupts(trans); + spin_unlock(&trans_pcie->irq_lock); + lock_map_release(&trans->sync_cmd_lockdep_map); + return IRQ_NONE; + } + + if (unlikely(inta == 0xFFFFFFFF || (inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { + /* + * Hardware disappeared. It might have + * already raised an interrupt. + */ + IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta); + spin_unlock(&trans_pcie->irq_lock); + goto out; + } /* Ack/clear/reset pending uCode interrupts. * Note: Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS, @@ -832,19 +955,13 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) * hardware bugs here by ACKing all the possible interrupts so that * interrupt coalescing can still be achieved. */ - iwl_write32(trans, CSR_INT, - trans_pcie->inta | ~trans_pcie->inta_mask); - - inta = trans_pcie->inta; + iwl_write32(trans, CSR_INT, inta | ~trans_pcie->inta_mask); if (iwl_have_debug_level(IWL_DL_ISR)) IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n", inta, iwl_read32(trans, CSR_INT_MASK)); - /* saved interrupt in inta variable now we can reset trans_pcie->inta */ - trans_pcie->inta = 0; - - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); /* Now service all interrupt bits discovered above. */ if (inta & CSR_INT_BIT_HW_ERR) { @@ -1019,11 +1136,6 @@ out: * ******************************************************************************/ -/* a device (PCI-E) page is 4096 bytes long */ -#define ICT_SHIFT 12 -#define ICT_SIZE (1 << ICT_SHIFT) -#define ICT_COUNT (ICT_SIZE / sizeof(u32)) - /* Free dram table */ void iwl_pcie_free_ict(struct iwl_trans *trans) { @@ -1048,7 +1160,7 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->ict_tbl = - dma_alloc_coherent(trans->dev, ICT_SIZE, + dma_zalloc_coherent(trans->dev, ICT_SIZE, &trans_pcie->ict_tbl_dma, GFP_KERNEL); if (!trans_pcie->ict_tbl) @@ -1060,17 +1172,10 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans) return -EINVAL; } - IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n", - (unsigned long long)trans_pcie->ict_tbl_dma); - - IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl); + IWL_DEBUG_ISR(trans, "ict dma addr %Lx ict vir addr %p\n", + (unsigned long long)trans_pcie->ict_tbl_dma, + trans_pcie->ict_tbl); - /* reset table and index to all 0 */ - memset(trans_pcie->ict_tbl, 0, ICT_SIZE); - trans_pcie->ict_index = 0; - - /* add periodic RX interrupt */ - trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC; return 0; } @@ -1081,12 +1186,11 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 val; - unsigned long flags; if (!trans_pcie->ict_tbl) return; - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); memset(trans_pcie->ict_tbl, 0, ICT_SIZE); @@ -1103,120 +1207,26 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans) trans_pcie->ict_index = 0; iwl_write32(trans, CSR_INT, trans_pcie->inta_mask); iwl_enable_interrupts(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); } /* Device is going down disable ict interrupt usage */ void iwl_pcie_disable_ict(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); trans_pcie->use_ict = false; - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); -} - -/* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */ -static irqreturn_t iwl_pcie_isr(int irq, void *data) -{ - struct iwl_trans *trans = data; - struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - u32 inta, inta_mask; - - lockdep_assert_held(&trans_pcie->irq_lock); - - trace_iwlwifi_dev_irq(trans->dev); - - /* Disable (but don't clear!) interrupts here to avoid - * back-to-back ISRs and sporadic interrupts from our NIC. - * If we have something to service, the irq thread will re-enable ints. - * If we *don't* have something, we'll re-enable before leaving here. */ - inta_mask = iwl_read32(trans, CSR_INT_MASK); - iwl_write32(trans, CSR_INT_MASK, 0x00000000); - - /* Discover which interrupts are active/pending */ - inta = iwl_read32(trans, CSR_INT); - - if (inta & (~inta_mask)) { - IWL_DEBUG_ISR(trans, - "We got a masked interrupt (0x%08x)...Ack and ignore\n", - inta & (~inta_mask)); - iwl_write32(trans, CSR_INT, inta & (~inta_mask)); - inta &= inta_mask; - } - - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - if (!inta) { - IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); - /* - * Re-enable interrupts here since we don't have anything to - * service, but only in case the handler won't run. Note that - * the handler can be scheduled because of a previous - * interrupt. - */ - if (test_bit(STATUS_INT_ENABLED, &trans->status) && - !trans_pcie->inta) - iwl_enable_interrupts(trans); - return IRQ_NONE; - } - - if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { - /* Hardware disappeared. It might have already raised - * an interrupt */ - IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta); - return IRQ_HANDLED; - } - - if (iwl_have_debug_level(IWL_DL_ISR)) - IWL_DEBUG_ISR(trans, - "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n", - inta, inta_mask, - iwl_read32(trans, CSR_FH_INT_STATUS)); - - trans_pcie->inta |= inta; - /* the thread will service interrupts and re-enable them */ - return IRQ_WAKE_THREAD; + spin_unlock(&trans_pcie->irq_lock); } -/* interrupt handler using ict table, with this interrupt driver will - * stop using INTA register to get device's interrupt, reading this register - * is expensive, device will write interrupts in ICT dram table, increment - * index then will fire interrupt to driver, driver will OR all ICT table - * entries from current index up to table entry with 0 value. the result is - * the interrupt we need to service, driver will set the entries back to 0 and - * set index. - */ -irqreturn_t iwl_pcie_isr_ict(int irq, void *data) +irqreturn_t iwl_pcie_isr(int irq, void *data) { struct iwl_trans *trans = data; - struct iwl_trans_pcie *trans_pcie; - u32 inta; - u32 val = 0; - u32 read; - unsigned long flags; - irqreturn_t ret = IRQ_NONE; if (!trans) return IRQ_NONE; - trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - - spin_lock_irqsave(&trans_pcie->irq_lock, flags); - - /* dram interrupt table not set yet, - * use legacy interrupt. - */ - if (unlikely(!trans_pcie->use_ict)) { - ret = iwl_pcie_isr(irq, data); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - return ret; - } - - trace_iwlwifi_dev_irq(trans->dev); - /* Disable (but don't clear!) interrupts here to avoid * back-to-back ISRs and sporadic interrupts from our NIC. * If we have something to service, the tasklet will re-enable ints. @@ -1224,73 +1234,5 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data) */ iwl_write32(trans, CSR_INT_MASK, 0x00000000); - /* Ignore interrupt if there's nothing in NIC to service. - * This may be due to IRQ shared with another device, - * or due to sporadic interrupts thrown from our NIC. */ - read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); - trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read); - if (!read) { - IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n"); - goto none; - } - - /* - * Collect all entries up to the first 0, starting from ict_index; - * note we already read at ict_index. - */ - do { - val |= read; - IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n", - trans_pcie->ict_index, read); - trans_pcie->ict_tbl[trans_pcie->ict_index] = 0; - trans_pcie->ict_index = - iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT); - - read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]); - trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, - read); - } while (read); - - /* We should not get this value, just ignore it. */ - if (val == 0xffffffff) - val = 0; - - /* - * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit - * (bit 15 before shifting it to 31) to clear when using interrupt - * coalescing. fortunately, bits 18 and 19 stay set when this happens - * so we use them to decide on the real state of the Rx bit. - * In order words, bit 15 is set if bit 18 or bit 19 are set. - */ - if (val & 0xC0000) - val |= 0x8000; - - inta = (0xff & val) | ((0xff00 & val) << 16); - IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled(sw) 0x%08x ict 0x%08x\n", - inta, trans_pcie->inta_mask, val); - if (iwl_have_debug_level(IWL_DL_ISR)) - IWL_DEBUG_ISR(trans, "enabled(hw) 0x%08x\n", - iwl_read32(trans, CSR_INT_MASK)); - - inta &= trans_pcie->inta_mask; - trans_pcie->inta |= inta; - - /* iwl_pcie_tasklet() will service interrupts and re-enable them */ - if (likely(inta)) { - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - return IRQ_WAKE_THREAD; - } - - ret = IRQ_HANDLED; - - none: - /* re-enable interrupts here since we don't have anything to service. - * only Re-enable if disabled by irq. - */ - if (test_bit(STATUS_INT_ENABLED, &trans->status) && - !trans_pcie->inta) - iwl_enable_interrupts(trans); - - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); - return ret; + return IRQ_WAKE_THREAD; } diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index eecd38e3f15f..16f66c1a23de 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -5,7 +5,7 @@ * * GPL LICENSE SUMMARY * - * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -30,7 +30,7 @@ * * BSD LICENSE * - * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -75,33 +75,6 @@ #include "iwl-agn-hw.h" #include "internal.h" -static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, - u32 reg, u32 mask, u32 value) -{ - u32 v; - -#ifdef CONFIG_IWLWIFI_DEBUG - WARN_ON_ONCE(value & ~mask); -#endif - - v = iwl_read32(trans, reg); - v &= ~mask; - v |= value; - iwl_write32(trans, reg, v); -} - -static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans, - u32 reg, u32 mask) -{ - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0); -} - -static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans, - u32 reg, u32 mask) -{ - __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask); -} - static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux) { if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold)) @@ -271,13 +244,12 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans) static int iwl_pcie_nic_init(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; /* nic_init */ - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_pcie_apm_init(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); iwl_pcie_set_pwr(trans, false); @@ -635,13 +607,14 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; - bool hw_rfkill; + bool hw_rfkill, was_hw_rfkill; + + was_hw_rfkill = iwl_is_rfkill_set(trans); /* tell the device to stop sending interrupts */ - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); /* device going down, Stop using ICT table */ iwl_pcie_disable_ict(trans); @@ -673,9 +646,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) /* Upon stop, the APM issues an interrupt if HW RF kill is set. * Clean again the interrupt here */ - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); /* stop and reset the on-board processor */ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET); @@ -698,13 +671,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans) * all the interrupts were disabled, in this case we couldn't * receive the RF kill interrupt and update the state in the * op_mode. + * Don't call the op_mode if the rkfill state hasn't changed. + * This allows the op_mode to call stop_device from the rfkill + * notification without endless recursion. Under very rare + * circumstances, we might have a small recursion if the rfkill + * state changed exactly now while we were called from stop_device. + * This is very unlikely but can happen and is supported. */ hw_rfkill = iwl_is_rfkill_set(trans); if (hw_rfkill) set_bit(STATUS_RFKILL, &trans->status); else clear_bit(STATUS_RFKILL, &trans->status); - iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); + if (hw_rfkill != was_hw_rfkill) + iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -799,7 +779,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) } /* Reset the entire device */ - iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); + iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); usleep_range(10, 15); @@ -821,18 +801,17 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); - unsigned long flags; /* disable interrupts - don't enable HW RF kill interrupt */ - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); iwl_pcie_apm_stop(trans); - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); } @@ -932,6 +911,9 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, spin_lock_irqsave(&trans_pcie->reg_lock, *flags); + if (trans_pcie->cmd_in_flight) + goto out; + /* this bit wakes up the NIC */ __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); @@ -971,6 +953,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent, } } +out: /* * Fool sparse by faking we release the lock - sparse will * track nic_access anyway. @@ -992,6 +975,9 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, */ __acquire(&trans_pcie->reg_lock); + if (trans_pcie->cmd_in_flight) + goto out; + __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); /* @@ -1001,6 +987,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans, * scheduled on different CPUs (after we drop reg_lock). */ mmiowb(); +out: spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags); } @@ -1597,7 +1584,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, if (iwl_pcie_alloc_ict(trans)) goto out_free_cmd_pool; - err = request_threaded_irq(pdev->irq, iwl_pcie_isr_ict, + err = request_threaded_irq(pdev->irq, iwl_pcie_isr, iwl_pcie_irq_handler, IRQF_SHARED, DRV_NAME, trans); if (err) { diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index 8df24787c141..3b14fa8abfc7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c @@ -1,6 +1,6 @@ /****************************************************************************** * - * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved. + * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. * * Portions of this file are derived from the ipw3945 project, as well * as portions of the ieee80211 subsystem header files. @@ -737,10 +737,9 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ch, txq_id, ret; - unsigned long flags; /* Turn off all Tx DMA fifos */ - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); iwl_pcie_txq_set_sched(trans, 0); @@ -757,13 +756,19 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans) iwl_read_direct32(trans, FH_TSSR_TX_STATUS_REG)); } - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); - if (!trans_pcie->txq) { - IWL_WARN(trans, - "Stopping tx queues that aren't allocated...\n"); + /* + * This function can be called before the op_mode disabled the + * queues. This happens when we have an rfkill interrupt. + * Since we stop Tx altogether - mark the queues as stopped. + */ + memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped)); + memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used)); + + /* This can happen: start_hw, stop_device */ + if (!trans_pcie->txq) return 0; - } /* Unmap DMA from host system and free skb's */ for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; @@ -865,7 +870,6 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int ret; int txq_id, slots_num; - unsigned long flags; bool alloc = false; if (!trans_pcie->txq) { @@ -875,7 +879,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) alloc = true; } - spin_lock_irqsave(&trans_pcie->irq_lock, flags); + spin_lock(&trans_pcie->irq_lock); /* Turn off all Tx DMA fifos */ iwl_write_prph(trans, SCD_TXFACT, 0); @@ -884,7 +888,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans) iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG, trans_pcie->kw.dma >> 4); - spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); + spin_unlock(&trans_pcie->irq_lock); /* Alloc and init all Tx queues, including the command queue (#4/#9) */ for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues; @@ -1003,6 +1007,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_txq *txq = &trans_pcie->txq[txq_id]; struct iwl_queue *q = &txq->q; + unsigned long flags; int nfreed = 0; lockdep_assert_held(&txq->lock); @@ -1025,6 +1030,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx) } } + if (q->read_ptr == q->write_ptr) { + spin_lock_irqsave(&trans_pcie->reg_lock, flags); + WARN_ON(!trans_pcie->cmd_in_flight); + trans_pcie->cmd_in_flight = false; + __iwl_trans_pcie_clear_bit(trans, + CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); + } + iwl_pcie_txq_progress(trans_pcie, txq); } @@ -1141,8 +1156,15 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id) SCD_TX_STTS_QUEUE_OFFSET(txq_id); static const u32 zero_val[4] = {}; + /* + * Upon HW Rfkill - we stop the device, and then stop the queues + * in the op_mode. Just for the sake of the simplicity of the op_mode, + * allow the op_mode to call txq_disable after it already called + * stop_device. + */ if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) { - WARN_ONCE(1, "queue %d not used", txq_id); + WARN_ONCE(test_bit(STATUS_DEVICE_ENABLED, &trans->status), + "queue %d not used", txq_id); return; } @@ -1176,12 +1198,13 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, struct iwl_queue *q = &txq->q; struct iwl_device_cmd *out_cmd; struct iwl_cmd_meta *out_meta; + unsigned long flags; void *dup_buf = NULL; dma_addr_t phys_addr; int idx; u16 copy_size, cmd_size, scratch_size; bool had_nocopy = false; - int i; + int i, ret; u32 cmd_pos; const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD]; u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD]; @@ -1379,10 +1402,38 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans, if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout) mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout); + spin_lock_irqsave(&trans_pcie->reg_lock, flags); + + /* + * wake up the NIC to make sure that the firmware will see the host + * command - we will let the NIC sleep once all the host commands + * returned. + */ + if (!trans_pcie->cmd_in_flight) { + trans_pcie->cmd_in_flight = true; + __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + ret = iwl_poll_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN, + (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY | + CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), + 15000); + if (ret < 0) { + __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ); + spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); + trans_pcie->cmd_in_flight = false; + idx = -EIO; + goto out; + } + } + /* Increment and update queue's write index */ q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); iwl_pcie_txq_inc_wr_ptr(trans, txq); + spin_unlock_irqrestore(&trans_pcie->reg_lock, flags); + out: spin_unlock_bh(&txq->lock); free_dup_buf: @@ -1464,7 +1515,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans, } #define HOST_COMPLETE_TIMEOUT (2 * HZ) -#define COMMAND_POKE_TIMEOUT (HZ / 10) static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd) @@ -1492,7 +1542,6 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); int cmd_idx; int ret; - int timeout = HOST_COMPLETE_TIMEOUT; IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n", get_cmd_string(trans_pcie, cmd->id)); @@ -1516,29 +1565,10 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans, return ret; } - while (timeout > 0) { - unsigned long flags; - - timeout -= COMMAND_POKE_TIMEOUT; - ret = wait_event_timeout(trans_pcie->wait_command_queue, - !test_bit(STATUS_SYNC_HCMD_ACTIVE, - &trans->status), - COMMAND_POKE_TIMEOUT); - if (ret) - break; - /* poke the device - it may have lost the command */ - if (iwl_trans_grab_nic_access(trans, true, &flags)) { - iwl_trans_release_nic_access(trans, &flags); - IWL_DEBUG_INFO(trans, - "Tried to wake NIC for command %s\n", - get_cmd_string(trans_pcie, cmd->id)); - } else { - IWL_ERR(trans, "Failed to poke NIC for command %s\n", - get_cmd_string(trans_pcie, cmd->id)); - break; - } - } - + ret = wait_event_timeout(trans_pcie->wait_command_queue, + !test_bit(STATUS_SYNC_HCMD_ACTIVE, + &trans->status), + HOST_COMPLETE_TIMEOUT); if (!ret) { struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue]; struct iwl_queue *q = &txq->q; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 9c0cc8ded021..fa41a773b79b 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2018,7 +2018,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, (hwsim_flags & HWSIM_TX_STAT_ACK)) { if (skb->len >= 16) { hdr = (struct ieee80211_hdr *) skb->data; - mac80211_hwsim_monitor_ack(txi->rate_driver_data[0], + mac80211_hwsim_monitor_ack(data2->channel, hdr->addr2); } txi->flags |= IEEE80211_TX_STAT_ACK; diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b994679abce0..e7c81abf108e 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -563,14 +563,7 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy, memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2)); mwifiex_send_domain_info_cmd_fw(wiphy); - - if (adapter->dt_node) { - char txpwr[] = {"marvell,00_txpwrlimit"}; - - memcpy(&txpwr[8], adapter->country_code, 2); - mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node, - txpwr); - } + mwifiex_dnld_txpwr_table(priv); } } diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 6bf58aba51d2..4d79761b9c87 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -747,9 +747,10 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev) } static u16 -mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb) +mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { - skb->priority = cfg80211_classify8021d(skb); + skb->priority = cfg80211_classify8021d(skb, NULL); return mwifiex_1d_to_wmm_queue[skb->priority]; } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ab3416449bfd..d8ad554ce39f 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1155,6 +1155,7 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer, int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv); int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, struct device_node *node, const char *prefix); +void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv); extern const struct ethtool_ops mwifiex_ethtool_ops; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 9c2404cd755f..9208a8816b80 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1170,8 +1170,9 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv, strncmp(prop->name, prefix, len)) continue; - /* property header is 6 bytes */ - if (prop && prop->value && prop->length > 6) { + /* property header is 6 bytes, data must fit in cmd buffer */ + if (prop && prop->value && prop->length > 6 && + prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) { ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA, HostCmd_ACT_GEN_SET, 0, prop); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 3edc92fad319..c5cb2ed19ec2 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -184,6 +184,16 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc); } +void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv) +{ + if (priv->adapter->dt_node) { + char txpwr[] = {"marvell,00_txpwrlimit"}; + + memcpy(&txpwr[8], priv->adapter->country_code, 2); + mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr); + } +} + static int mwifiex_process_country_ie(struct mwifiex_private *priv, struct cfg80211_bss *bss) { @@ -234,12 +244,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv, return -1; } - if (priv->adapter->dt_node) { - char txpwr[] = {"marvell,00_txpwrlimit"}; - - memcpy(&txpwr[8], priv->adapter->country_code, 2); - mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr); - } + mwifiex_dnld_txpwr_table(priv); return 0; } diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index b953ad621e0b..63dbde5c3713 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -9,7 +9,6 @@ * warranty of any kind, whether express or implied. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> #include <linux/kernel.h> @@ -1258,7 +1257,7 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh) { return priv->capture_beacon && ieee80211_is_beacon(wh->frame_control) && - ether_addr_equal(wh->addr3, priv->capture_bssid); + ether_addr_equal_64bits(wh->addr3, priv->capture_bssid); } static inline void mwl8k_save_beacon(struct ieee80211_hw *hw, diff --git a/drivers/net/wireless/orinoco/hermes.c b/drivers/net/wireless/orinoco/hermes.c index 75c15bc7b34c..43790fbea0e0 100644 --- a/drivers/net/wireless/orinoco/hermes.c +++ b/drivers/net/wireless/orinoco/hermes.c @@ -40,7 +40,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/delay.h> #include "hermes.h" diff --git a/drivers/net/wireless/orinoco/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c index d21d95939316..c0a27377d9e2 100644 --- a/drivers/net/wireless/orinoco/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -15,7 +15,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/delay.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c index bdfe637953f4..f9805c9353d2 100644 --- a/drivers/net/wireless/orinoco/orinoco_usb.c +++ b/drivers/net/wireless/orinoco/orinoco_usb.c @@ -52,7 +52,6 @@ #include <linux/signal.h> #include <linux/errno.h> #include <linux/poll.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/fcntl.h> #include <linux/spinlock.h> diff --git a/drivers/net/wireless/orinoco/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c index e2264bc12ebf..b60048c95e0a 100644 --- a/drivers/net/wireless/orinoco/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -23,7 +23,6 @@ #include <linux/module.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/delay.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c index d43e3740e45d..0fe67d2da208 100644 --- a/drivers/net/wireless/p54/eeprom.c +++ b/drivers/net/wireless/p54/eeprom.c @@ -16,7 +16,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <linux/sort.h> diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c index b3879fbf5368..bc065e8e348b 100644 --- a/drivers/net/wireless/p54/fwio.c +++ b/drivers/net/wireless/p54/fwio.c @@ -16,7 +16,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/firmware.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/p54/led.c b/drivers/net/wireless/p54/led.c index 3837e1eec5f4..1f6fd5ff5531 100644 --- a/drivers/net/wireless/p54/led.c +++ b/drivers/net/wireless/p54/led.c @@ -16,7 +16,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/firmware.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c index 067e6f2fd050..80d93cba5150 100644 --- a/drivers/net/wireless/p54/main.c +++ b/drivers/net/wireless/p54/main.c @@ -16,7 +16,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/slab.h> #include <linux/firmware.h> #include <linux/etherdevice.h> diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index f9a07b0d83ac..d411de409050 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -13,7 +13,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/firmware.h> diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index e328d3058c41..6e635cfa24c8 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -12,7 +12,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/usb.h> #include <linux/pci.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index f95de0d16216..9c96831c0b5c 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -17,7 +17,6 @@ */ #include <linux/export.h> -#include <linux/init.h> #include <linux/firmware.h> #include <linux/etherdevice.h> #include <asm/div64.h> @@ -308,7 +307,7 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb) return; /* only consider beacons from the associated BSSID */ - if (!ether_addr_equal(hdr->addr3, priv->bssid)) + if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid)) return; tim = p54_find_ie(skb, WLAN_EID_TIM); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c3cdda1252de..5028557aa18a 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -26,7 +26,6 @@ // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 4ad0de9d1d08..4ccfef5094e0 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -24,7 +24,6 @@ #include <linux/delay.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index 4f61ffbcd2f1..abc5f56f29fe 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -24,7 +24,6 @@ #include <linux/delay.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index 1bb76935da71..9f16824cd1bc 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -24,7 +24,6 @@ #include <linux/delay.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 49ff178a0b46..5c5c4906c6b6 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -29,7 +29,6 @@ #include <linux/delay.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/usb.h> diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 00c3fae6fa3c..2bde6729f5e6 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -565,10 +565,10 @@ static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev, #undef TID_CHECK - if (!ether_addr_equal(ba->ra, entry->ta)) + if (!ether_addr_equal_64bits(ba->ra, entry->ta)) continue; - if (!ether_addr_equal(ba->ta, entry->ra)) + if (!ether_addr_equal_64bits(ba->ta, entry->ra)) continue; /* Mark BAR since we received the according BA */ diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index b76f6049ad9a..24402984ee57 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -25,7 +25,6 @@ #include <linux/crc-itu-t.h> #include <linux/delay.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index ade88d7e089c..a140170b1eb3 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -25,7 +25,6 @@ #include <linux/crc-itu-t.h> #include <linux/delay.h> #include <linux/etherdevice.h> -#include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index a91506b12a62..8ec17aad0e52 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -15,7 +15,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/slab.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/grf5101.c b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c index dc845693f321..b1bfee738937 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/grf5101.c +++ b/drivers/net/wireless/rtl818x/rtl8180/grf5101.c @@ -19,7 +19,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/max2820.c b/drivers/net/wireless/rtl818x/rtl8180/max2820.c index a63c443c3c6f..eebf23976524 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/max2820.c +++ b/drivers/net/wireless/rtl818x/rtl8180/max2820.c @@ -18,7 +18,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c index ee638d0749d6..d60a5f399022 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8180/rtl8225.c @@ -15,7 +15,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/rtl818x/rtl8180/sa2400.c b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c index 7614d9ccc729..959b049827de 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/sa2400.c +++ b/drivers/net/wireless/rtl818x/rtl8180/sa2400.c @@ -19,7 +19,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/pci.h> #include <linux/delay.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/rtl818x/rtl8187/dev.c b/drivers/net/wireless/rtl818x/rtl8187/dev.c index ec9aa5b67381..fd78df813a85 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187/dev.c @@ -20,7 +20,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/usb.h> #include <linux/slab.h> #include <linux/delay.h> diff --git a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c index a26193a04447..5ecf18ed67b8 100644 --- a/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187/rtl8225.c @@ -16,7 +16,6 @@ * published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/usb.h> #include <net/mac80211.h> diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index fcf9b621918c..d63a12cc5de8 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -1293,7 +1293,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb) return; /* and only beacons from the associated BSSID, please */ - if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) return; rtlpriv->link_info.bcn_rx_inperiod++; @@ -1781,7 +1781,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) return; if (rtl_find_221_ie(hw, data, len)) diff --git a/drivers/net/wireless/rtlwifi/ps.c b/drivers/net/wireless/rtlwifi/ps.c index 0d81f766fd0f..deedae3c5449 100644 --- a/drivers/net/wireless/rtlwifi/ps.c +++ b/drivers/net/wireless/rtlwifi/ps.c @@ -478,7 +478,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) return; rtlpriv->psc.last_beacon = jiffies; @@ -923,7 +923,7 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len) return; /* and only beacons from the associated BSSID, please */ - if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid)) + if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid)) return; /* check if this really is a beacon */ diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index 374268d5ac6a..5a4ec56c83d0 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -194,7 +194,7 @@ out: return ret; } -int wl1251_acx_feature_cfg(struct wl1251 *wl) +int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options) { struct acx_feature_config *feature; int ret; @@ -205,8 +205,8 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl) if (!feature) return -ENOMEM; - /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */ - feature->data_flow_options = 0; + /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE can be set */ + feature->data_flow_options = data_flow_options; feature->options = 0; ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG, @@ -381,7 +381,8 @@ out: return ret; } -int wl1251_acx_group_address_tbl(struct wl1251 *wl) +int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, + void *mc_list, u32 mc_list_len) { struct acx_dot11_grp_addr_tbl *acx; int ret; @@ -393,9 +394,9 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl) return -ENOMEM; /* MAC filtering */ - acx->enabled = 0; - acx->num_groups = 0; - memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN); + acx->enabled = enable; + acx->num_groups = mc_list_len; + memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN); ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL, acx, sizeof(*acx)); @@ -846,12 +847,18 @@ int wl1251_acx_rate_policies(struct wl1251 *wl) return -ENOMEM; /* configure one default (one-size-fits-all) rate class */ - acx->rate_class_cnt = 1; + acx->rate_class_cnt = 2; acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT; acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT; acx->rate_class[0].aflags = 0; + /* no-retry rate class */ + acx->rate_class[1].enabled_rates = ACX_RATE_MASK_UNSPECIFIED; + acx->rate_class[1].short_retry_limit = 0; + acx->rate_class[1].long_retry_limit = 0; + acx->rate_class[1].aflags = 0; + ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx)); if (ret < 0) { wl1251_warning("Setting of rate policies failed: %d", ret); @@ -960,6 +967,32 @@ out: return ret; } +int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address) +{ + struct wl1251_acx_arp_filter *acx; + int ret; + + wl1251_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->version = ACX_IPV4_VERSION; + acx->enable = enable; + + if (enable) + memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE); + + ret = wl1251_cmd_configure(wl, ACX_ARP_IP_FILTER, + acx, sizeof(*acx)); + if (ret < 0) + wl1251_warning("failed to set arp ip filter: %d", ret); + + kfree(acx); + return ret; +} + int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifs, u16 txop) { diff --git a/drivers/net/wireless/ti/wl1251/acx.h b/drivers/net/wireless/ti/wl1251/acx.h index c2ba100f9b1a..2bdec38699f4 100644 --- a/drivers/net/wireless/ti/wl1251/acx.h +++ b/drivers/net/wireless/ti/wl1251/acx.h @@ -350,8 +350,8 @@ struct acx_slot { } __packed; -#define ADDRESS_GROUP_MAX (8) -#define ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ADDRESS_GROUP_MAX) +#define ACX_MC_ADDRESS_GROUP_MAX (8) +#define ACX_MC_ADDRESS_GROUP_MAX_LEN (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX) struct acx_dot11_grp_addr_tbl { struct acx_header header; @@ -359,7 +359,7 @@ struct acx_dot11_grp_addr_tbl { u8 enabled; u8 num_groups; u8 pad[2]; - u8 mac_table[ADDRESS_GROUP_MAX_LEN]; + u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN]; } __packed; @@ -1232,6 +1232,20 @@ struct wl1251_acx_bet_enable { u8 padding[2]; } __packed; +#define ACX_IPV4_VERSION 4 +#define ACX_IPV6_VERSION 6 +#define ACX_IPV4_ADDR_SIZE 4 +struct wl1251_acx_arp_filter { + struct acx_header header; + u8 version; /* The IP version: 4 - IPv4, 6 - IPv6.*/ + u8 enable; /* 1 - ARP filtering is enabled, 0 - disabled */ + u8 padding[2]; + u8 address[16]; /* The IP address used to filter ARP packets. + ARP packets that do not match this address are + dropped. When the IP Version is 4, the last 12 + bytes of the the address are ignored. */ +} __attribute__((packed)); + struct wl1251_acx_ac_cfg { struct acx_header header; @@ -1440,7 +1454,7 @@ int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event, int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth); int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len); int wl1251_acx_tx_power(struct wl1251 *wl, int power); -int wl1251_acx_feature_cfg(struct wl1251 *wl); +int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options); int wl1251_acx_mem_map(struct wl1251 *wl, struct acx_header *mem_map, size_t len); int wl1251_acx_data_path_params(struct wl1251 *wl, @@ -1449,7 +1463,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time); int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter); int wl1251_acx_pd_threshold(struct wl1251 *wl); int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time); -int wl1251_acx_group_address_tbl(struct wl1251 *wl); +int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable, + void *mc_list, u32 mc_list_len); int wl1251_acx_service_period_timeout(struct wl1251 *wl); int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold); int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter); @@ -1473,6 +1488,7 @@ int wl1251_acx_mem_cfg(struct wl1251 *wl); int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim); int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode, u8 max_consecutive); +int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address); int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max, u8 aifs, u16 txop); int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue, diff --git a/drivers/net/wireless/ti/wl1251/boot.c b/drivers/net/wireless/ti/wl1251/boot.c index a2e5241382da..2000cd536077 100644 --- a/drivers/net/wireless/ti/wl1251/boot.c +++ b/drivers/net/wireless/ti/wl1251/boot.c @@ -299,7 +299,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl) ROAMING_TRIGGER_LOW_RSSI_EVENT_ID | ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID | REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID | - BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID; + BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID | + PS_REPORT_EVENT_ID; ret = wl1251_event_unmask(wl); if (ret < 0) { diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index 6822b845efc1..223649bcaa5a 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -3,6 +3,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/crc7.h> +#include <linux/etherdevice.h> #include "wl1251.h" #include "reg.h" @@ -203,11 +204,11 @@ out: return ret; } -int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) +int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable) { struct cmd_enabledisable_path *cmd; int ret; - u16 cmd_rx, cmd_tx; + u16 cmd_rx; wl1251_debug(DEBUG_CMD, "cmd data path"); @@ -219,13 +220,10 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) cmd->channel = channel; - if (enable) { + if (enable) cmd_rx = CMD_ENABLE_RX; - cmd_tx = CMD_ENABLE_TX; - } else { + else cmd_rx = CMD_DISABLE_RX; - cmd_tx = CMD_DISABLE_TX; - } ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd)); if (ret < 0) { @@ -237,17 +235,38 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable) wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d", enable ? "start" : "stop", channel); +out: + kfree(cmd); + return ret; +} + +int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable) +{ + struct cmd_enabledisable_path *cmd; + int ret; + u16 cmd_tx; + + wl1251_debug(DEBUG_CMD, "cmd data path"); + + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); + if (!cmd) + return -ENOMEM; + + cmd->channel = channel; + + if (enable) + cmd_tx = CMD_ENABLE_TX; + else + cmd_tx = CMD_DISABLE_TX; + ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd)); - if (ret < 0) { + if (ret < 0) wl1251_error("tx %s cmd for channel %d failed", enable ? "start" : "stop", channel); - goto out; - } - - wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", - enable ? "start" : "stop", channel); + else + wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d", + enable ? "start" : "stop", channel); -out: kfree(cmd); return ret; } @@ -410,7 +429,9 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, struct wl1251_cmd_scan *cmd; int i, ret = 0; - wl1251_debug(DEBUG_CMD, "cmd scan"); + wl1251_debug(DEBUG_CMD, "cmd scan channels %d", n_channels); + + WARN_ON(n_channels > SCAN_MAX_NUM_OF_CHANNELS); cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) @@ -421,6 +442,13 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len, CFG_RX_MGMT_EN | CFG_RX_BCN_EN); cmd->params.scan_options = 0; + /* + * Use high priority scan when not associated to prevent fw issue + * causing never-ending scans (sometimes 20+ minutes). + * Note: This bug may be caused by the fw's DTIM handling. + */ + if (is_zero_ether_addr(wl->bssid)) + cmd->params.scan_options |= WL1251_SCAN_OPT_PRIORITY_HIGH; cmd->params.num_channels = n_channels; cmd->params.num_probe_requests = n_probes; cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */ diff --git a/drivers/net/wireless/ti/wl1251/cmd.h b/drivers/net/wireless/ti/wl1251/cmd.h index ee4f2b391822..d824ff978311 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.h +++ b/drivers/net/wireless/ti/wl1251/cmd.h @@ -35,7 +35,8 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len); int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity, void *bitmap, u16 bitmap_len, u8 bitmap_control); -int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable); +int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable); +int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable); int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, u16 beacon_interval, u8 dtim_interval); int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode); @@ -167,6 +168,11 @@ struct cmd_read_write_memory { #define CMDMBOX_HEADER_LEN 4 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4 +#define WL1251_SCAN_OPT_PASSIVE 1 +#define WL1251_SCAN_OPT_5GHZ_BAND 2 +#define WL1251_SCAN_OPT_TRIGGERD_SCAN 4 +#define WL1251_SCAN_OPT_PRIORITY_HIGH 8 + #define WL1251_SCAN_MIN_DURATION 30000 #define WL1251_SCAN_MAX_DURATION 60000 diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c index 74ae8e1c2e33..db0105313745 100644 --- a/drivers/net/wireless/ti/wl1251/event.c +++ b/drivers/net/wireless/ti/wl1251/event.c @@ -46,6 +46,43 @@ static int wl1251_event_scan_complete(struct wl1251 *wl, return ret; } +#define WL1251_PSM_ENTRY_RETRIES 3 +static int wl1251_event_ps_report(struct wl1251 *wl, + struct event_mailbox *mbox) +{ + int ret = 0; + + wl1251_debug(DEBUG_EVENT, "ps status: %x", mbox->ps_status); + + switch (mbox->ps_status) { + case EVENT_ENTER_POWER_SAVE_FAIL: + wl1251_debug(DEBUG_PSM, "PSM entry failed"); + + if (wl->station_mode != STATION_POWER_SAVE_MODE) { + /* remain in active mode */ + wl->psm_entry_retry = 0; + break; + } + + if (wl->psm_entry_retry < WL1251_PSM_ENTRY_RETRIES) { + wl->psm_entry_retry++; + ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); + } else { + wl1251_error("Power save entry failed, giving up"); + wl->psm_entry_retry = 0; + } + break; + case EVENT_ENTER_POWER_SAVE_SUCCESS: + case EVENT_EXIT_POWER_SAVE_FAIL: + case EVENT_EXIT_POWER_SAVE_SUCCESS: + default: + wl->psm_entry_retry = 0; + break; + } + + return 0; +} + static void wl1251_event_mbox_dump(struct event_mailbox *mbox) { wl1251_debug(DEBUG_EVENT, "MBOX DUMP:"); @@ -80,7 +117,14 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) } } - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) { + if (vector & PS_REPORT_EVENT_ID) { + wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT"); + ret = wl1251_event_ps_report(wl, mbox); + if (ret < 0) + return ret; + } + + if (wl->vif && vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) { wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/ti/wl1251/event.h b/drivers/net/wireless/ti/wl1251/event.h index 30eb5d150bf7..88570a5cd042 100644 --- a/drivers/net/wireless/ti/wl1251/event.h +++ b/drivers/net/wireless/ti/wl1251/event.h @@ -112,6 +112,13 @@ struct event_mailbox { u8 padding[19]; } __packed; +enum { + EVENT_ENTER_POWER_SAVE_FAIL = 0, + EVENT_ENTER_POWER_SAVE_SUCCESS, + EVENT_EXIT_POWER_SAVE_FAIL, + EVENT_EXIT_POWER_SAVE_SUCCESS, +}; + int wl1251_event_unmask(struct wl1251 *wl); void wl1251_event_mbox_config(struct wl1251 *wl); int wl1251_event_handle(struct wl1251 *wl, u8 mbox); diff --git a/drivers/net/wireless/ti/wl1251/init.c b/drivers/net/wireless/ti/wl1251/init.c index 89b43d35473c..1d799bffaa9f 100644 --- a/drivers/net/wireless/ti/wl1251/init.c +++ b/drivers/net/wireless/ti/wl1251/init.c @@ -33,7 +33,7 @@ int wl1251_hw_init_hwenc_config(struct wl1251 *wl) { int ret; - ret = wl1251_acx_feature_cfg(wl); + ret = wl1251_acx_feature_cfg(wl, 0); if (ret < 0) { wl1251_warning("couldn't set feature config"); return ret; @@ -127,7 +127,7 @@ int wl1251_hw_init_phy_config(struct wl1251 *wl) if (ret < 0) return ret; - ret = wl1251_acx_group_address_tbl(wl); + ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0); if (ret < 0) return ret; @@ -394,8 +394,13 @@ int wl1251_hw_init(struct wl1251 *wl) if (ret < 0) goto out_free_data_path; - /* Enable data path */ - ret = wl1251_cmd_data_path(wl, wl->channel, 1); + /* Enable rx data path */ + ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1); + if (ret < 0) + goto out_free_data_path; + + /* Enable tx data path */ + ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1); if (ret < 0) goto out_free_data_path; diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index b8a360b43e76..119c148f7740 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -28,6 +28,7 @@ #include <linux/etherdevice.h> #include <linux/vmalloc.h> #include <linux/slab.h> +#include <linux/netdevice.h> #include "wl1251.h" #include "wl12xx_80211.h" @@ -479,10 +480,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) wl->next_tx_complete = 0; wl->elp = false; wl->station_mode = STATION_ACTIVE_MODE; + wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; wl->channel = WL1251_DEFAULT_CHANNEL; + wl->monitor_present = false; + wl->joined = false; wl1251_debugfs_reset(wl); @@ -542,6 +546,7 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface"); wl->vif = NULL; + memset(wl->bssid, 0, ETH_ALEN); mutex_unlock(&wl->mutex); } @@ -566,6 +571,11 @@ static int wl1251_build_qos_null_data(struct wl1251 *wl) sizeof(template)); } +static bool wl1251_can_do_pm(struct ieee80211_conf *conf, struct wl1251 *wl) +{ + return (conf->flags & IEEE80211_CONF_PS) && !wl->monitor_present; +} + static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) { struct wl1251 *wl = hw->priv; @@ -575,8 +585,10 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) channel = ieee80211_frequency_to_channel( conf->chandef.chan->center_freq); - wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d", + wl1251_debug(DEBUG_MAC80211, + "mac80211 config ch %d monitor %s psm %s power %d", channel, + conf->flags & IEEE80211_CONF_MONITOR ? "on" : "off", conf->flags & IEEE80211_CONF_PS ? "on" : "off", conf->power_level); @@ -586,16 +598,44 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) if (ret < 0) goto out; + if (changed & IEEE80211_CONF_CHANGE_MONITOR) { + u32 mode; + + if (conf->flags & IEEE80211_CONF_MONITOR) { + wl->monitor_present = true; + mode = DF_SNIFF_MODE_ENABLE | DF_ENCRYPTION_DISABLE; + } else { + wl->monitor_present = false; + mode = 0; + } + + ret = wl1251_acx_feature_cfg(wl, mode); + if (ret < 0) + goto out_sleep; + } + if (channel != wl->channel) { wl->channel = channel; - ret = wl1251_join(wl, wl->bss_type, wl->channel, - wl->beacon_int, wl->dtim_period); + /* + * Use ENABLE_RX command for channel switching when no + * interface is present (monitor mode only). + * This leaves the tx path disabled in firmware, whereas + * the usual JOIN command seems to transmit some frames + * at firmware level. + */ + if (wl->vif == NULL) { + wl->joined = false; + ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1); + } else { + ret = wl1251_join(wl, wl->bss_type, wl->channel, + wl->beacon_int, wl->dtim_period); + } if (ret < 0) goto out_sleep; } - if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) { + if (wl1251_can_do_pm(conf, wl) && !wl->psm_requested) { wl1251_debug(DEBUG_PSM, "psm enabled"); wl->psm_requested = true; @@ -611,8 +651,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE); if (ret < 0) goto out_sleep; - } else if (!(conf->flags & IEEE80211_CONF_PS) && - wl->psm_requested) { + } else if (!wl1251_can_do_pm(conf, wl) && wl->psm_requested) { wl1251_debug(DEBUG_PSM, "psm disabled"); wl->psm_requested = false; @@ -648,6 +687,16 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed) wl->power_level = conf->power_level; } + /* + * Tell stack that connection is lost because hw encryption isn't + * supported in monitor mode. + * This requires temporary enabling of the hw connection monitor flag + */ + if ((changed & IEEE80211_CONF_CHANGE_MONITOR) && wl->vif) { + wl->hw->flags |= IEEE80211_HW_CONNECTION_MONITOR; + ieee80211_connection_loss(wl->vif); + } + out_sleep: wl1251_ps_elp_sleep(wl); @@ -657,6 +706,44 @@ out: return ret; } +struct wl1251_filter_params { + bool enabled; + int mc_list_length; + u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN]; +}; + +static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw, + struct netdev_hw_addr_list *mc_list) +{ + struct wl1251_filter_params *fp; + struct netdev_hw_addr *ha; + struct wl1251 *wl = hw->priv; + + if (unlikely(wl->state == WL1251_STATE_OFF)) + return 0; + + fp = kzalloc(sizeof(*fp), GFP_ATOMIC); + if (!fp) { + wl1251_error("Out of memory setting filters."); + return 0; + } + + /* update multicast filtering parameters */ + fp->mc_list_length = 0; + if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) { + fp->enabled = false; + } else { + fp->enabled = true; + netdev_hw_addr_list_for_each(ha, mc_list) { + memcpy(fp->mc_list[fp->mc_list_length], + ha->addr, ETH_ALEN); + fp->mc_list_length++; + } + } + + return (u64)(unsigned long)fp; +} + #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \ FIF_ALLMULTI | \ FIF_FCSFAIL | \ @@ -667,8 +754,9 @@ out: static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, - unsigned int *total,u64 multicast) + unsigned int *total, u64 multicast) { + struct wl1251_filter_params *fp = (void *)(unsigned long)multicast; struct wl1251 *wl = hw->priv; int ret; @@ -677,9 +765,11 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, *total &= WL1251_SUPPORTED_FILTERS; changed &= WL1251_SUPPORTED_FILTERS; - if (changed == 0) + if (changed == 0) { /* no filters which we support changed */ + kfree(fp); return; + } mutex_lock(&wl->mutex); @@ -716,6 +806,15 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, if (ret < 0) goto out; + if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS) + ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0); + else if (fp) + ret = wl1251_acx_group_address_tbl(wl, fp->enabled, + fp->mc_list, + fp->mc_list_length); + if (ret < 0) + goto out; + /* send filters to firmware */ wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); @@ -723,6 +822,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, out: mutex_unlock(&wl->mutex); + kfree(fp); } /* HW encryption */ @@ -802,12 +902,12 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, mutex_lock(&wl->mutex); - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out_unlock; - switch (cmd) { case SET_KEY: + if (wl->monitor_present) { + ret = -EOPNOTSUPP; + goto out_unlock; + } wl_cmd->key_action = KEY_ADD_OR_REPLACE; break; case DISABLE_KEY: @@ -818,6 +918,10 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, break; } + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out_unlock; + ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr); if (ret < 0) { wl1251_error("Set KEY type failed"); @@ -930,6 +1034,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw, ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels, req->n_channels, WL1251_SCAN_NUM_PROBES); if (ret < 0) { + wl1251_debug(DEBUG_SCAN, "scan failed %d", ret); wl->scanning = false; goto out_idle; } @@ -977,6 +1082,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, { struct wl1251 *wl = hw->priv; struct sk_buff *beacon, *skb; + bool enable; int ret; wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed"); @@ -1023,6 +1129,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ASSOC) { + /* Disable temporary enabled hw connection monitor flag */ + wl->hw->flags &= ~IEEE80211_HW_CONNECTION_MONITOR; + if (bss_conf->assoc) { wl->beacon_int = bss_conf->beacon_int; @@ -1075,6 +1184,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & BSS_CHANGED_ARP_FILTER) { + __be32 addr = bss_conf->arp_addr_list[0]; + WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS); + + enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc; + wl1251_acx_arp_ip_filter(wl, enable, addr); + + if (ret < 0) + goto out_sleep; + } + if (changed & BSS_CHANGED_BEACON) { beacon = ieee80211_beacon_get(hw, vif); if (!beacon) @@ -1245,6 +1365,7 @@ static const struct ieee80211_ops wl1251_ops = { .add_interface = wl1251_op_add_interface, .remove_interface = wl1251_op_remove_interface, .config = wl1251_op_config, + .prepare_multicast = wl1251_op_prepare_multicast, .configure_filter = wl1251_op_configure_filter, .tx = wl1251_op_tx, .set_key = wl1251_op_set_key, @@ -1401,7 +1522,10 @@ struct ieee80211_hw *wl1251_alloc_hw(void) INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); wl->channel = WL1251_DEFAULT_CHANNEL; + wl->monitor_present = false; + wl->joined = false; wl->scanning = false; + wl->bss_type = MAX_BSS_TYPE; wl->default_key = 0; wl->listen_int = 1; wl->rx_counter = 0; @@ -1413,6 +1537,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void) wl->elp = false; wl->station_mode = STATION_ACTIVE_MODE; wl->psm_requested = false; + wl->psm_entry_retry = 0; wl->tx_queue_stopped = false; wl->power_level = WL1251_DEFAULT_POWER_LEVEL; wl->rssi_thold = 0; @@ -1478,3 +1603,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>"); MODULE_FIRMWARE(WL1251_FW_NAME); +MODULE_FIRMWARE(WL1251_NVS_NAME); diff --git a/drivers/net/wireless/ti/wl1251/rx.c b/drivers/net/wireless/ti/wl1251/rx.c index 23289d49dd31..123c4bb50e0a 100644 --- a/drivers/net/wireless/ti/wl1251/rx.c +++ b/drivers/net/wireless/ti/wl1251/rx.c @@ -83,7 +83,7 @@ static void wl1251_rx_status(struct wl1251 *wl, status->flag |= RX_FLAG_MACTIME_START; - if (desc->flags & RX_DESC_ENCRYPTION_MASK) { + if (!wl->monitor_present && (desc->flags & RX_DESC_ENCRYPTION_MASK)) { status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED; if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL))) diff --git a/drivers/net/wireless/ti/wl1251/tx.c b/drivers/net/wireless/ti/wl1251/tx.c index 28121c590a2b..81de83c6fcf6 100644 --- a/drivers/net/wireless/ti/wl1251/tx.c +++ b/drivers/net/wireless/ti/wl1251/tx.c @@ -28,6 +28,7 @@ #include "tx.h" #include "ps.h" #include "io.h" +#include "event.h" static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count) { @@ -89,8 +90,12 @@ static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr, /* 802.11 packets */ tx_hdr->control.packet_type = 0; - if (control->flags & IEEE80211_TX_CTL_NO_ACK) + /* Also disable retry and ACK policy for injected packets */ + if ((control->flags & IEEE80211_TX_CTL_NO_ACK) || + (control->flags & IEEE80211_TX_CTL_INJECTED)) { + tx_hdr->control.rate_policy = 1; tx_hdr->control.ack_policy = 1; + } tx_hdr->control.tx_complete = 1; @@ -277,6 +282,26 @@ static void wl1251_tx_trigger(struct wl1251 *wl) TX_STATUS_DATA_OUT_COUNT_MASK; } +static void enable_tx_for_packet_injection(struct wl1251 *wl) +{ + int ret; + + ret = wl1251_cmd_join(wl, BSS_TYPE_STA_BSS, wl->channel, + wl->beacon_int, wl->dtim_period); + if (ret < 0) { + wl1251_warning("join failed"); + return; + } + + ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100); + if (ret < 0) { + wl1251_warning("join timeout"); + return; + } + + wl->joined = true; +} + /* caller must hold wl->mutex */ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) { @@ -287,6 +312,9 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) info = IEEE80211_SKB_CB(skb); if (info->control.hw_key) { + if (unlikely(wl->monitor_present)) + return -EINVAL; + idx = info->control.hw_key->hw_key_idx; if (unlikely(wl->default_key != idx)) { ret = wl1251_acx_default_key(wl, idx); @@ -295,6 +323,10 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb) } } + /* Enable tx path in monitor mode for packet injection */ + if ((wl->vif == NULL) && !wl->joined) + enable_tx_for_packet_injection(wl); + ret = wl1251_tx_path_status(wl); if (ret < 0) return ret; @@ -394,6 +426,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl, info = IEEE80211_SKB_CB(skb); if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + !(info->flags & IEEE80211_TX_CTL_INJECTED) && (result->status == TX_SUCCESS)) info->flags |= IEEE80211_TX_STAT_ACK; diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h index 2c3bd1bff3f6..235617a7716d 100644 --- a/drivers/net/wireless/ti/wl1251/wl1251.h +++ b/drivers/net/wireless/ti/wl1251/wl1251.h @@ -93,6 +93,7 @@ enum { } while (0) #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN | \ + CFG_MC_FILTER_EN | \ CFG_BSSID_FILTER_EN) #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN | \ @@ -303,6 +304,8 @@ struct wl1251 { u8 bss_type; u8 listen_int; int channel; + bool monitor_present; + bool joined; void *target_mem_map; struct acx_data_path_params_resp *data_path; @@ -368,6 +371,9 @@ struct wl1251 { /* PSM mode requested */ bool psm_requested; + /* retry counter for PSM entries */ + u8 psm_entry_retry; + u16 beacon_int; u8 dtim_period; diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 1477d7f05905..d24d4a958c67 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -29,7 +29,6 @@ #include <linux/delay.h> #include <linux/types.h> -#include <linux/init.h> #include <linux/interrupt.h> #include <linux/in.h> #include <linux/kernel.h> diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 27385639b6e5..6b62c3eb8e18 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -39,7 +39,6 @@ #include <linux/udp.h> #include <net/tcp.h> -#include <net/ip6_checksum.h> #include <xen/xen.h> #include <xen/events.h> @@ -1051,257 +1050,9 @@ static int xenvif_set_skb_gso(struct xenvif *vif, return 0; } -static inline int maybe_pull_tail(struct sk_buff *skb, unsigned int len, - unsigned int max) -{ - if (skb_headlen(skb) >= len) - return 0; - - /* If we need to pullup then pullup to the max, so we - * won't need to do it again. - */ - if (max > skb->len) - max = skb->len; - - if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) - return -ENOMEM; - - if (skb_headlen(skb) < len) - return -EPROTO; - - return 0; -} - -/* This value should be large enough to cover a tagged ethernet header plus - * maximally sized IP and TCP or UDP headers. - */ -#define MAX_IP_HDR_LEN 128 - -static int checksum_setup_ip(struct xenvif *vif, struct sk_buff *skb, - int recalculate_partial_csum) -{ - unsigned int off; - bool fragment; - int err; - - fragment = false; - - err = maybe_pull_tail(skb, - sizeof(struct iphdr), - MAX_IP_HDR_LEN); - if (err < 0) - goto out; - - if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) - fragment = true; - - off = ip_hdrlen(skb); - - err = -EPROTO; - - if (fragment) - goto out; - - switch (ip_hdr(skb)->protocol) { - case IPPROTO_TCP: - err = maybe_pull_tail(skb, - off + sizeof(struct tcphdr), - MAX_IP_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct tcphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate_partial_csum) - tcp_hdr(skb)->check = - ~csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - skb->len - off, - IPPROTO_TCP, 0); - break; - case IPPROTO_UDP: - err = maybe_pull_tail(skb, - off + sizeof(struct udphdr), - MAX_IP_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct udphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate_partial_csum) - udp_hdr(skb)->check = - ~csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - skb->len - off, - IPPROTO_UDP, 0); - break; - default: - goto out; - } - - err = 0; - -out: - return err; -} - -/* This value should be large enough to cover a tagged ethernet header plus - * an IPv6 header, all options, and a maximal TCP or UDP header. - */ -#define MAX_IPV6_HDR_LEN 256 - -#define OPT_HDR(type, skb, off) \ - (type *)(skb_network_header(skb) + (off)) - -static int checksum_setup_ipv6(struct xenvif *vif, struct sk_buff *skb, - int recalculate_partial_csum) -{ - int err; - u8 nexthdr; - unsigned int off; - unsigned int len; - bool fragment; - bool done; - - fragment = false; - done = false; - - off = sizeof(struct ipv6hdr); - - err = maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - nexthdr = ipv6_hdr(skb)->nexthdr; - - len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); - while (off <= len && !done) { - switch (nexthdr) { - case IPPROTO_DSTOPTS: - case IPPROTO_HOPOPTS: - case IPPROTO_ROUTING: { - struct ipv6_opt_hdr *hp; - - err = maybe_pull_tail(skb, - off + - sizeof(struct ipv6_opt_hdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); - nexthdr = hp->nexthdr; - off += ipv6_optlen(hp); - break; - } - case IPPROTO_AH: { - struct ip_auth_hdr *hp; - - err = maybe_pull_tail(skb, - off + - sizeof(struct ip_auth_hdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - hp = OPT_HDR(struct ip_auth_hdr, skb, off); - nexthdr = hp->nexthdr; - off += ipv6_authlen(hp); - break; - } - case IPPROTO_FRAGMENT: { - struct frag_hdr *hp; - - err = maybe_pull_tail(skb, - off + - sizeof(struct frag_hdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - hp = OPT_HDR(struct frag_hdr, skb, off); - - if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) - fragment = true; - - nexthdr = hp->nexthdr; - off += sizeof(struct frag_hdr); - break; - } - default: - done = true; - break; - } - } - - err = -EPROTO; - - if (!done || fragment) - goto out; - - switch (nexthdr) { - case IPPROTO_TCP: - err = maybe_pull_tail(skb, - off + sizeof(struct tcphdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct tcphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate_partial_csum) - tcp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len - off, - IPPROTO_TCP, 0); - break; - case IPPROTO_UDP: - err = maybe_pull_tail(skb, - off + sizeof(struct udphdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - if (!skb_partial_csum_set(skb, off, - offsetof(struct udphdr, check))) { - err = -EPROTO; - goto out; - } - - if (recalculate_partial_csum) - udp_hdr(skb)->check = - ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len - off, - IPPROTO_UDP, 0); - break; - default: - goto out; - } - - err = 0; - -out: - return err; -} - static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) { - int err = -EPROTO; - int recalculate_partial_csum = 0; + bool recalculate_partial_csum = false; /* A GSO SKB must be CHECKSUM_PARTIAL. However some buggy * peers can fail to set NETRXF_csum_blank when sending a GSO @@ -1311,19 +1062,14 @@ static int checksum_setup(struct xenvif *vif, struct sk_buff *skb) if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) { vif->rx_gso_checksum_fixup++; skb->ip_summed = CHECKSUM_PARTIAL; - recalculate_partial_csum = 1; + recalculate_partial_csum = true; } /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ if (skb->ip_summed != CHECKSUM_PARTIAL) return 0; - if (skb->protocol == htons(ETH_P_IP)) - err = checksum_setup_ip(vif, skb, recalculate_partial_csum); - else if (skb->protocol == htons(ETH_P_IPV6)) - err = checksum_setup_ipv6(vif, skb, recalculate_partial_csum); - - return err; + return skb_checksum_setup(skb, recalculate_partial_csum); } static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index e59acb1daa23..c41537b577a4 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -859,9 +859,7 @@ static RING_IDX xennet_fill_frags(struct netfront_info *np, static int checksum_setup(struct net_device *dev, struct sk_buff *skb) { - struct iphdr *iph; - int err = -EPROTO; - int recalculate_partial_csum = 0; + bool recalculate_partial_csum = false; /* * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy @@ -873,54 +871,14 @@ static int checksum_setup(struct net_device *dev, struct sk_buff *skb) struct netfront_info *np = netdev_priv(dev); np->rx_gso_checksum_fixup++; skb->ip_summed = CHECKSUM_PARTIAL; - recalculate_partial_csum = 1; + recalculate_partial_csum = true; } /* A non-CHECKSUM_PARTIAL SKB does not require setup. */ if (skb->ip_summed != CHECKSUM_PARTIAL) return 0; - if (skb->protocol != htons(ETH_P_IP)) - goto out; - - iph = (void *)skb->data; - - switch (iph->protocol) { - case IPPROTO_TCP: - if (!skb_partial_csum_set(skb, 4 * iph->ihl, - offsetof(struct tcphdr, check))) - goto out; - - if (recalculate_partial_csum) { - struct tcphdr *tcph = tcp_hdr(skb); - tcph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, - skb->len - iph->ihl*4, - IPPROTO_TCP, 0); - } - break; - case IPPROTO_UDP: - if (!skb_partial_csum_set(skb, 4 * iph->ihl, - offsetof(struct udphdr, check))) - goto out; - - if (recalculate_partial_csum) { - struct udphdr *udph = udp_hdr(skb); - udph->check = ~csum_tcpudp_magic(iph->saddr, iph->daddr, - skb->len - iph->ihl*4, - IPPROTO_UDP, 0); - } - break; - default: - if (net_ratelimit()) - pr_err("Attempting to checksum a non-TCP/UDP packet, dropping a protocol %d packet\n", - iph->protocol); - goto out; - } - - err = 0; - -out: - return err; + return skb_checksum_setup(skb, recalculate_partial_csum); } static int handle_incoming_queue(struct net_device *dev, diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index a43b8523c61e..875b7b6f0d2a 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -254,3 +254,23 @@ struct phy_device *of_phy_connect_fixed_link(struct net_device *dev, return IS_ERR(phy) ? NULL : phy; } EXPORT_SYMBOL(of_phy_connect_fixed_link); + +/** + * of_phy_attach - Attach to a PHY without starting the state machine + * @dev: pointer to net_device claiming the phy + * @phy_np: Node pointer for the PHY + * @flags: flags to pass to the PHY + * @iface: PHY data interface type + */ +struct phy_device *of_phy_attach(struct net_device *dev, + struct device_node *phy_np, u32 flags, + phy_interface_t iface) +{ + struct phy_device *phy = of_phy_find_device(phy_np); + + if (!phy) + return NULL; + + return phy_attach_direct(dev, phy, flags, iface) ? NULL : phy; +} +EXPORT_SYMBOL(of_phy_attach); diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c index 8f9be2e09937..a208a457558c 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -30,6 +30,7 @@ static const char *phy_modes[] = { [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid", [PHY_INTERFACE_MODE_RTBI] = "rtbi", [PHY_INTERFACE_MODE_SMII] = "smii", + [PHY_INTERFACE_MODE_XGMII] = "xgmii", }; /** diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 1cf605f67673..e86439283a5d 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -279,7 +279,9 @@ static acpi_status register_slot(acpi_handle handle, u32 lvl, void *data, status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); if (ACPI_FAILURE(status)) { - acpi_handle_warn(handle, "can't evaluate _ADR (%#x)\n", status); + if (status != AE_NOT_FOUND) + acpi_handle_warn(handle, + "can't evaluate _ADR (%#x)\n", status); return AE_OK; } @@ -643,6 +645,24 @@ static void disable_slot(struct acpiphp_slot *slot) slot->flags &= (~SLOT_ENABLED); } +static bool acpiphp_no_hotplug(acpi_handle handle) +{ + struct acpi_device *adev = NULL; + + acpi_bus_get_device(handle, &adev); + return adev && adev->flags.no_hotplug; +} + +static bool slot_no_hotplug(struct acpiphp_slot *slot) +{ + struct acpiphp_func *func; + + list_for_each_entry(func, &slot->funcs, sibling) + if (acpiphp_no_hotplug(func_to_handle(func))) + return true; + + return false; +} /** * get_slot_status - get ACPI slot status @@ -701,7 +721,8 @@ static void trim_stale_devices(struct pci_dev *dev) unsigned long long sta; status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); - alive = ACPI_SUCCESS(status) && sta == ACPI_STA_ALL; + alive = (ACPI_SUCCESS(status) && sta == ACPI_STA_ALL) + || acpiphp_no_hotplug(handle); } if (!alive) { u32 v; @@ -741,8 +762,9 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) struct pci_dev *dev, *tmp; mutex_lock(&slot->crit_sect); - /* wake up all functions */ - if (get_slot_status(slot) == ACPI_STA_ALL) { + if (slot_no_hotplug(slot)) { + ; /* do nothing */ + } else if (get_slot_status(slot) == ACPI_STA_ALL) { /* remove stale devices if any */ list_for_each_entry_safe(dev, tmp, &bus->devices, bus_list) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 577074efbe62..f7ebdba14bde 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -330,29 +330,32 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) static void pci_acpi_setup(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - acpi_handle handle = ACPI_HANDLE(dev); - struct acpi_device *adev; + struct acpi_device *adev = ACPI_COMPANION(dev); - if (acpi_bus_get_device(handle, &adev) || !adev->wakeup.flags.valid) + if (!adev) + return; + + pci_acpi_add_pm_notifier(adev, pci_dev); + if (!adev->wakeup.flags.valid) return; device_set_wakeup_capable(dev, true); acpi_pci_sleep_wake(pci_dev, false); - - pci_acpi_add_pm_notifier(adev, pci_dev); if (adev->wakeup.flags.run_wake) device_set_run_wake(dev, true); } static void pci_acpi_cleanup(struct device *dev) { - acpi_handle handle = ACPI_HANDLE(dev); - struct acpi_device *adev; + struct acpi_device *adev = ACPI_COMPANION(dev); + + if (!adev) + return; - if (!acpi_bus_get_device(handle, &adev) && adev->wakeup.flags.valid) { + pci_acpi_remove_pm_notifier(adev); + if (adev->wakeup.flags.valid) { device_set_wakeup_capable(dev, false); device_set_run_wake(dev, false); - pci_acpi_remove_pm_notifier(adev); } } diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index 330ef2d06567..a8b17ce16425 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -16,6 +16,7 @@ config GENERIC_PHY framework should select this config. config PHY_EXYNOS_MIPI_VIDEO + depends on HAS_IOMEM tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" help Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 5e2054afe840..32c6294c1668 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -196,6 +196,7 @@ config BATTERY_MAX17040 config BATTERY_MAX17042 tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge" depends on I2C + select REGMAP_I2C help MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries in handheld and portable equipment. The MAX17042 is configured @@ -376,6 +377,7 @@ config AB8500_BM config BATTERY_GOLDFISH tristate "Goldfish battery driver" depends on GOLDFISH || COMPILE_TEST + depends on HAS_IOMEM help Say Y to enable support for the battery and AC power in the Goldfish emulator. diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c index 00e667296360..557af943b2f5 100644 --- a/drivers/power/power_supply_core.c +++ b/drivers/power/power_supply_core.c @@ -511,6 +511,10 @@ int power_supply_register(struct device *parent, struct power_supply *psy) dev_set_drvdata(dev, psy); psy->dev = dev; + rc = dev_set_name(dev, "%s", psy->name); + if (rc) + goto dev_set_name_failed; + INIT_WORK(&psy->changed_work, power_supply_changed_work); rc = power_supply_check_supplies(psy); @@ -524,10 +528,6 @@ int power_supply_register(struct device *parent, struct power_supply *psy) if (rc) goto wakeup_init_failed; - rc = kobject_set_name(&dev->kobj, "%s", psy->name); - if (rc) - goto kobject_set_name_failed; - rc = device_add(dev); if (rc) goto device_add_failed; @@ -553,11 +553,11 @@ create_triggers_failed: register_cooler_failed: psy_unregister_thermal(psy); register_thermal_failed: -wakeup_init_failed: device_del(dev); -kobject_set_name_failed: device_add_failed: +wakeup_init_failed: check_supplies_failed: +dev_set_name_failed: put_device(dev); success: return rc; diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig index 5be73ba0519a..5a7910e61e17 100644 --- a/drivers/ptp/Kconfig +++ b/drivers/ptp/Kconfig @@ -73,6 +73,7 @@ config DP83640_PHY config PTP_1588_CLOCK_PCH tristate "Intel PCH EG20T as PTP clock" depends on X86 || COMPILE_TEST + depends on HAS_IOMEM select PTP_1588_CLOCK help This driver adds support for using the PCH EG20T as a PTP diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 3f4ca4e09a4c..34629ea913d4 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -942,7 +942,7 @@ static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty) return rc; } - tp->screen = tty3270_alloc_screen(tp->view.cols, tp->view.rows); + tp->screen = tty3270_alloc_screen(tp->view.rows, tp->view.cols); if (IS_ERR(tp->screen)) { rc = PTR_ERR(tp->screen); raw3270_put_view(&tp->view); diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 13299f902676..d24b3672908d 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -55,6 +55,7 @@ int chsc_error_from_response(int response) case 0x0004: return -EOPNOTSUPP; case 0x000b: + case 0x0107: /* "Channel busy" for the op 0x003d */ return -EBUSY; case 0x0100: case 0x0102: @@ -1234,3 +1235,35 @@ out: return ret; } EXPORT_SYMBOL_GPL(chsc_scm_info); + +/** + * chsc_pnso_brinfo() - Perform Network-Subchannel Operation, Bridge Info. + * @schid: id of the subchannel on which PNSO is performed + * @brinfo_area: request and response block for the operation + * @resume_token: resume token for multiblock response + * @cnc: Boolean change-notification control + * + * brinfo_area must be allocated by the caller with get_zeroed_page(GFP_KERNEL) + * + * Returns 0 on success. + */ +int chsc_pnso_brinfo(struct subchannel_id schid, + struct chsc_pnso_area *brinfo_area, + struct chsc_brinfo_resume_token resume_token, + int cnc) +{ + memset(brinfo_area, 0, sizeof(*brinfo_area)); + brinfo_area->request.length = 0x0030; + brinfo_area->request.code = 0x003d; /* network-subchannel operation */ + brinfo_area->m = schid.m; + brinfo_area->ssid = schid.ssid; + brinfo_area->sch = schid.sch_no; + brinfo_area->cssid = schid.cssid; + brinfo_area->oc = 0; /* Store-network-bridging-information list */ + brinfo_area->resume_token = resume_token; + brinfo_area->n = (cnc != 0); + if (chsc(brinfo_area)) + return -EIO; + return chsc_error_from_response(brinfo_area->response.code); +} +EXPORT_SYMBOL_GPL(chsc_pnso_brinfo); diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 23d072e70eb2..7e53a9c8b0b9 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -61,7 +61,9 @@ struct css_chsc_char { u32 : 20; u32 scssc : 1; /* bit 107 */ u32 scsscf : 1; /* bit 108 */ - u32 : 19; + u32:7; + u32 pnso:1; /* bit 116 */ + u32:11; }__attribute__((packed)); extern struct css_chsc_char css_chsc_characteristics; @@ -188,6 +190,53 @@ struct chsc_scm_info { int chsc_scm_info(struct chsc_scm_info *scm_area, u64 token); +struct chsc_brinfo_resume_token { + u64 t1; + u64 t2; +} __packed; + +struct chsc_brinfo_naihdr { + struct chsc_brinfo_resume_token resume_token; + u32:32; + u32 instance; + u32:24; + u8 naids; + u32 reserved[3]; +} __packed; + +struct chsc_pnso_area { + struct chsc_header request; + u8:2; + u8 m:1; + u8:5; + u8:2; + u8 ssid:2; + u8 fmt:4; + u16 sch; + u8:8; + u8 cssid; + u16:16; + u8 oc; + u32:24; + struct chsc_brinfo_resume_token resume_token; + u32 n:1; + u32:31; + u32 reserved[3]; + struct chsc_header response; + u32:32; + struct chsc_brinfo_naihdr naihdr; + union { + struct qdio_brinfo_entry_l3_ipv6 l3_ipv6[0]; + struct qdio_brinfo_entry_l3_ipv4 l3_ipv4[0]; + struct qdio_brinfo_entry_l2 l2[0]; + } entries; +} __packed; + +int chsc_pnso_brinfo(struct subchannel_id schid, + struct chsc_pnso_area *brinfo_area, + struct chsc_brinfo_resume_token resume_token, + int cnc); + #ifdef CONFIG_SCM_BUS int scm_update_information(void); int scm_process_availability_information(void); diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index 3e602e8affa7..5f99af4305fc 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -1752,6 +1752,97 @@ int qdio_stop_irq(struct ccw_device *cdev, int nr) } EXPORT_SYMBOL(qdio_stop_irq); +/** + * qdio_pnso_brinfo() - perform network subchannel op #0 - bridge info. + * @schid: Subchannel ID. + * @cnc: Boolean Change-Notification Control + * @response: Response code will be stored at this address + * @cb: Callback function will be executed for each element + * of the address list + * @priv: Pointer passed from the caller to qdio_pnso_brinfo() + * @type: Type of the address entry passed to the callback + * @entry: Entry containg the address of the specified type + * @priv: Pointer to pass to the callback function. + * + * Performs "Store-network-bridging-information list" operation and calls + * the callback function for every entry in the list. If "change- + * notification-control" is set, further changes in the address list + * will be reported via the IPA command. + */ +int qdio_pnso_brinfo(struct subchannel_id schid, + int cnc, u16 *response, + void (*cb)(void *priv, enum qdio_brinfo_entry_type type, + void *entry), + void *priv) +{ + struct chsc_pnso_area *rr; + int rc; + u32 prev_instance = 0; + int isfirstblock = 1; + int i, size, elems; + + rr = (struct chsc_pnso_area *)get_zeroed_page(GFP_KERNEL); + if (rr == NULL) + return -ENOMEM; + do { + /* on the first iteration, naihdr.resume_token will be zero */ + rc = chsc_pnso_brinfo(schid, rr, rr->naihdr.resume_token, cnc); + if (rc != 0 && rc != -EBUSY) + goto out; + if (rr->response.code != 1) { + rc = -EIO; + continue; + } else + rc = 0; + + if (cb == NULL) + continue; + + size = rr->naihdr.naids; + elems = (rr->response.length - + sizeof(struct chsc_header) - + sizeof(struct chsc_brinfo_naihdr)) / + size; + + if (!isfirstblock && (rr->naihdr.instance != prev_instance)) { + /* Inform the caller that they need to scrap */ + /* the data that was already reported via cb */ + rc = -EAGAIN; + break; + } + isfirstblock = 0; + prev_instance = rr->naihdr.instance; + for (i = 0; i < elems; i++) + switch (size) { + case sizeof(struct qdio_brinfo_entry_l3_ipv6): + (*cb)(priv, l3_ipv6_addr, + &rr->entries.l3_ipv6[i]); + break; + case sizeof(struct qdio_brinfo_entry_l3_ipv4): + (*cb)(priv, l3_ipv4_addr, + &rr->entries.l3_ipv4[i]); + break; + case sizeof(struct qdio_brinfo_entry_l2): + (*cb)(priv, l2_addr_lnid, + &rr->entries.l2[i]); + break; + default: + WARN_ON_ONCE(1); + rc = -EIO; + goto out; + } + } while (rr->response.code == 0x0107 || /* channel busy */ + (rr->response.code == 1 && /* list stored */ + /* resume token is non-zero => list incomplete */ + (rr->naihdr.resume_token.t1 || rr->naihdr.resume_token.t2))); + (*response) = rr->response.code; + +out: + free_page((unsigned long)rr); + return rc; +} +EXPORT_SYMBOL_GPL(qdio_pnso_brinfo); + static int __init init_QDIO(void) { int rc; diff --git a/drivers/s390/net/Makefile b/drivers/s390/net/Makefile index 4dfe8c1092da..d28f05d0c75a 100644 --- a/drivers/s390/net/Makefile +++ b/drivers/s390/net/Makefile @@ -11,7 +11,7 @@ obj-$(CONFIG_LCS) += lcs.o obj-$(CONFIG_CLAW) += claw.o qeth-y += qeth_core_sys.o qeth_core_main.o qeth_core_mpc.o obj-$(CONFIG_QETH) += qeth.o -qeth_l2-y += qeth_l2_main.o +qeth_l2-y += qeth_l2_main.o qeth_l2_sys.o obj-$(CONFIG_QETH_L2) += qeth_l2.o qeth_l3-y += qeth_l3_main.o qeth_l3_sys.o obj-$(CONFIG_QETH_L3) += qeth_l3.o diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h index d45427c553b0..ac0bdded060f 100644 --- a/drivers/s390/net/qeth_core.h +++ b/drivers/s390/net/qeth_core.h @@ -156,6 +156,27 @@ struct qeth_ipa_info { __u32 enabled_funcs; }; +/* SETBRIDGEPORT stuff */ +enum qeth_sbp_roles { + QETH_SBP_ROLE_NONE = 0, + QETH_SBP_ROLE_PRIMARY = 1, + QETH_SBP_ROLE_SECONDARY = 2, +}; + +enum qeth_sbp_states { + QETH_SBP_STATE_INACTIVE = 0, + QETH_SBP_STATE_STANDBY = 1, + QETH_SBP_STATE_ACTIVE = 2, +}; + +#define QETH_SBP_HOST_NOTIFICATION 1 + +struct qeth_sbp_info { + __u32 supported_funcs; + enum qeth_sbp_roles role; + __u32 hostnotification:1; +}; + static inline int qeth_is_ipa_supported(struct qeth_ipa_info *ipa, enum qeth_ipa_funcs func) { @@ -672,6 +693,7 @@ struct qeth_card_options { struct qeth_ipa_info adp; /*Adapter parameters*/ struct qeth_routing_info route6; struct qeth_ipa_info ipa6; + struct qeth_sbp_info sbp; /* SETBRIDGEPORT options */ int fake_broadcast; int add_hhlen; int layer2; @@ -857,6 +879,7 @@ extern struct qeth_discipline qeth_l2_discipline; extern struct qeth_discipline qeth_l3_discipline; extern const struct attribute_group *qeth_generic_attr_groups[]; extern const struct attribute_group *qeth_osn_attr_groups[]; +extern struct workqueue_struct *qeth_wq; const char *qeth_get_cardname_short(struct qeth_card *); int qeth_realloc_buffer_pool(struct qeth_card *, int); @@ -925,6 +948,13 @@ int qeth_query_card_info(struct qeth_card *card, int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *, int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long), void *reply_param); +void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd); +void qeth_bridgeport_query_support(struct qeth_card *card); +int qeth_bridgeport_query_ports(struct qeth_card *card, + enum qeth_sbp_roles *role, enum qeth_sbp_states *state); +int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role); +int qeth_bridgeport_an_set(struct qeth_card *card, int enable); +void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd); int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int); int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int); int qeth_get_elements_for_frags(struct sk_buff *); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index f9a85b47e3c3..c05dacbf4e23 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -68,7 +68,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue, enum qeth_qdio_buffer_states newbufstate); static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int); -static struct workqueue_struct *qeth_wq; +struct workqueue_struct *qeth_wq; static void qeth_close_dev_handler(struct work_struct *work) { @@ -615,6 +615,16 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card, card->info.hwtrap = 2; qeth_schedule_recovery(card); return NULL; + case IPA_CMD_SETBRIDGEPORT: + if (cmd->data.sbp.hdr.command_code == + IPA_SBP_BRIDGE_PORT_STATE_CHANGE) { + qeth_bridge_state_change(card, cmd); + return NULL; + } else + return cmd; + case IPA_CMD_ADDRESS_CHANGE_NOTIF: + qeth_bridge_host_event(card, cmd); + return NULL; case IPA_CMD_MODCCID: return cmd; case IPA_CMD_REGISTER_LOCAL_ADDR: @@ -4956,12 +4966,17 @@ retriable: card->options.ipa4.supported_funcs = 0; card->options.adp.supported_funcs = 0; + card->options.sbp.supported_funcs = 0; card->info.diagass_support = 0; qeth_query_ipassists(card, QETH_PROT_IPV4); if (qeth_is_supported(card, IPA_SETADAPTERPARMS)) qeth_query_setadapterparms(card); if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST)) qeth_query_setdiagass(card); + qeth_bridgeport_query_support(card); + if (card->options.sbp.supported_funcs) + dev_info(&card->gdev->dev, + "The device represents a HiperSockets Bridge Capable Port\n"); return 0; out: dev_warn(&card->gdev->dev, "The qeth device driver failed to recover " diff --git a/drivers/s390/net/qeth_core_mpc.c b/drivers/s390/net/qeth_core_mpc.c index 06c55780005e..7b55768a9592 100644 --- a/drivers/s390/net/qeth_core_mpc.c +++ b/drivers/s390/net/qeth_core_mpc.c @@ -249,10 +249,12 @@ static struct ipa_cmd_names qeth_ipa_cmd_names[] = { {IPA_CMD_DELIP, "delip"}, {IPA_CMD_SETADAPTERPARMS, "setadapterparms"}, {IPA_CMD_SET_DIAG_ASS, "set_diag_ass"}, + {IPA_CMD_SETBRIDGEPORT, "set_bridge_port"}, {IPA_CMD_CREATE_ADDR, "create_addr"}, {IPA_CMD_DESTROY_ADDR, "destroy_addr"}, {IPA_CMD_REGISTER_LOCAL_ADDR, "register_local_addr"}, {IPA_CMD_UNREGISTER_LOCAL_ADDR, "unregister_local_addr"}, + {IPA_CMD_ADDRESS_CHANGE_NOTIF, "address_change_notification"}, {IPA_CMD_UNKNOWN, "unknown"}, }; diff --git a/drivers/s390/net/qeth_core_mpc.h b/drivers/s390/net/qeth_core_mpc.h index 0a6e695578cd..cf6a90ed42ae 100644 --- a/drivers/s390/net/qeth_core_mpc.h +++ b/drivers/s390/net/qeth_core_mpc.h @@ -104,10 +104,12 @@ enum qeth_ipa_cmds { IPA_CMD_DELIP = 0xb7, IPA_CMD_SETADAPTERPARMS = 0xb8, IPA_CMD_SET_DIAG_ASS = 0xb9, + IPA_CMD_SETBRIDGEPORT = 0xbe, IPA_CMD_CREATE_ADDR = 0xc3, IPA_CMD_DESTROY_ADDR = 0xc4, IPA_CMD_REGISTER_LOCAL_ADDR = 0xd1, IPA_CMD_UNREGISTER_LOCAL_ADDR = 0xd2, + IPA_CMD_ADDRESS_CHANGE_NOTIF = 0xd3, IPA_CMD_UNKNOWN = 0x00 }; @@ -500,6 +502,124 @@ struct qeth_ipacmd_diagass { __u8 cdata[64]; } __attribute__ ((packed)); +/* SETBRIDGEPORT IPA Command: *********************************************/ +enum qeth_ipa_sbp_cmd { + IPA_SBP_QUERY_COMMANDS_SUPPORTED = 0x00000000L, + IPA_SBP_RESET_BRIDGE_PORT_ROLE = 0x00000001L, + IPA_SBP_SET_PRIMARY_BRIDGE_PORT = 0x00000002L, + IPA_SBP_SET_SECONDARY_BRIDGE_PORT = 0x00000004L, + IPA_SBP_QUERY_BRIDGE_PORTS = 0x00000008L, + IPA_SBP_BRIDGE_PORT_STATE_CHANGE = 0x00000010L, +}; + +struct net_if_token { + __u16 devnum; + __u8 cssid; + __u8 iid; + __u8 ssid; + __u8 chpid; + __u16 chid; +} __packed; + +struct mac_addr_lnid { + __u8 mac[6]; + __u16 lnid; +} __packed; + +struct qeth_ipacmd_sbp_hdr { + __u32 supported_sbp_cmds; + __u32 enabled_sbp_cmds; + __u16 cmdlength; + __u16 reserved1; + __u32 command_code; + __u16 return_code; + __u8 used_total; + __u8 seq_no; + __u32 reserved2; +} __packed; + +struct qeth_sbp_query_cmds_supp { + __u32 supported_cmds; + __u32 reserved; +} __packed; + +struct qeth_sbp_reset_role { +} __packed; + +struct qeth_sbp_set_primary { + struct net_if_token token; +} __packed; + +struct qeth_sbp_set_secondary { +} __packed; + +struct qeth_sbp_port_entry { + __u8 role; + __u8 state; + __u8 reserved1; + __u8 reserved2; + struct net_if_token token; +} __packed; + +struct qeth_sbp_query_ports { + __u8 primary_bp_supported; + __u8 secondary_bp_supported; + __u8 num_entries; + __u8 entry_length; + struct qeth_sbp_port_entry entry[]; +} __packed; + +struct qeth_sbp_state_change { + __u8 primary_bp_supported; + __u8 secondary_bp_supported; + __u8 num_entries; + __u8 entry_length; + struct qeth_sbp_port_entry entry[]; +} __packed; + +struct qeth_ipacmd_setbridgeport { + struct qeth_ipacmd_sbp_hdr hdr; + union { + struct qeth_sbp_query_cmds_supp query_cmds_supp; + struct qeth_sbp_reset_role reset_role; + struct qeth_sbp_set_primary set_primary; + struct qeth_sbp_set_secondary set_secondary; + struct qeth_sbp_query_ports query_ports; + struct qeth_sbp_state_change state_change; + } data; +} __packed; + +/* ADDRESS_CHANGE_NOTIFICATION adapter-initiated "command" *******************/ +/* Bitmask for entry->change_code. Both bits may be raised. */ +enum qeth_ipa_addr_change_code { + IPA_ADDR_CHANGE_CODE_VLANID = 0x01, + IPA_ADDR_CHANGE_CODE_MACADDR = 0x02, + IPA_ADDR_CHANGE_CODE_REMOVAL = 0x80, /* else addition */ +}; +enum qeth_ipa_addr_change_retcode { + IPA_ADDR_CHANGE_RETCODE_OK = 0x0000, + IPA_ADDR_CHANGE_RETCODE_LOSTEVENTS = 0x0010, +}; +enum qeth_ipa_addr_change_lostmask { + IPA_ADDR_CHANGE_MASK_OVERFLOW = 0x01, + IPA_ADDR_CHANGE_MASK_STATECHANGE = 0x02, +}; + +struct qeth_ipacmd_addr_change_entry { + struct net_if_token token; + struct mac_addr_lnid addr_lnid; + __u8 change_code; + __u8 reserved1; + __u16 reserved2; +} __packed; + +struct qeth_ipacmd_addr_change { + __u8 lost_event_mask; + __u8 reserved; + __u16 num_entries; + struct qeth_ipacmd_addr_change_entry entry[]; +} __packed; + /* Header for each IPA command */ struct qeth_ipacmd_hdr { __u8 command; @@ -529,6 +649,8 @@ struct qeth_ipa_cmd { struct qeth_ipacmd_setadpparms setadapterparms; struct qeth_set_routing setrtg; struct qeth_ipacmd_diagass diagass; + struct qeth_ipacmd_setbridgeport sbp; + struct qeth_ipacmd_addr_change addrchange; } data; } __attribute__ ((packed)); diff --git a/drivers/s390/net/qeth_l2.h b/drivers/s390/net/qeth_l2.h new file mode 100644 index 000000000000..0767556404bd --- /dev/null +++ b/drivers/s390/net/qeth_l2.h @@ -0,0 +1,15 @@ +/* + * Copyright IBM Corp. 2013 + * Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com> + */ + +#ifndef __QETH_L2_H__ +#define __QETH_L2_H__ + +#include "qeth_core.h" + +int qeth_l2_create_device_attributes(struct device *); +void qeth_l2_remove_device_attributes(struct device *); +void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card); + +#endif /* __QETH_L2_H__ */ diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index ec8ccdae7aba..914d2c121fd8 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -21,6 +21,7 @@ #include <linux/list.h> #include "qeth_core.h" +#include "qeth_l2.h" static int qeth_l2_set_offline(struct ccwgroup_device *); static int qeth_l2_stop(struct net_device *); @@ -880,6 +881,7 @@ static int qeth_l2_probe_device(struct ccwgroup_device *gdev) { struct qeth_card *card = dev_get_drvdata(&gdev->dev); + qeth_l2_create_device_attributes(&gdev->dev); INIT_LIST_HEAD(&card->vid_list); INIT_LIST_HEAD(&card->mc_list); card->options.layer2 = 1; @@ -891,6 +893,7 @@ static void qeth_l2_remove_device(struct ccwgroup_device *cgdev) { struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + qeth_l2_remove_device_attributes(&cgdev->dev); qeth_set_allowed_threads(card, 0, 1); wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); @@ -1003,6 +1006,8 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode) } else card->info.hwtrap = 0; + qeth_l2_setup_bridgeport_attrs(card); + card->state = CARD_STATE_HARDSETUP; memset(&card->rx, 0, sizeof(struct qeth_rx)); qeth_print_status_message(card); @@ -1347,6 +1352,595 @@ void qeth_osn_deregister(struct net_device *dev) } EXPORT_SYMBOL(qeth_osn_deregister); +/* SETBRIDGEPORT support, async notifications */ + +enum qeth_an_event_type {anev_reg_unreg, anev_abort, anev_reset}; + +/** + * qeth_bridge_emit_host_event() - bridgeport address change notification + * @card: qeth_card structure pointer, for udev events. + * @evtype: "normal" register/unregister, or abort, or reset. For abort + * and reset token and addr_lnid are unused and may be NULL. + * @code: event bitmask: high order bit 0x80 value 1 means removal of an + * object, 0 - addition of an object. + * 0x01 - VLAN, 0x02 - MAC, 0x03 - VLAN and MAC. + * @token: "network token" structure identifying physical address of the port. + * @addr_lnid: pointer to structure with MAC address and VLAN ID. + * + * This function is called when registrations and deregistrations are + * reported by the hardware, and also when notifications are enabled - + * for all currently registered addresses. + */ +static void qeth_bridge_emit_host_event(struct qeth_card *card, + enum qeth_an_event_type evtype, + u8 code, struct net_if_token *token, struct mac_addr_lnid *addr_lnid) +{ + char str[7][32]; + char *env[8]; + int i = 0; + + switch (evtype) { + case anev_reg_unreg: + snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=%s", + (code & IPA_ADDR_CHANGE_CODE_REMOVAL) + ? "deregister" : "register"); + env[i] = str[i]; i++; + if (code & IPA_ADDR_CHANGE_CODE_VLANID) { + snprintf(str[i], sizeof(str[i]), "VLAN=%d", + addr_lnid->lnid); + env[i] = str[i]; i++; + } + if (code & IPA_ADDR_CHANGE_CODE_MACADDR) { + snprintf(str[i], sizeof(str[i]), "MAC=%pM6", + &addr_lnid->mac); + env[i] = str[i]; i++; + } + snprintf(str[i], sizeof(str[i]), "NTOK_BUSID=%x.%x.%04x", + token->cssid, token->ssid, token->devnum); + env[i] = str[i]; i++; + snprintf(str[i], sizeof(str[i]), "NTOK_IID=%02x", token->iid); + env[i] = str[i]; i++; + snprintf(str[i], sizeof(str[i]), "NTOK_CHPID=%02x", + token->chpid); + env[i] = str[i]; i++; + snprintf(str[i], sizeof(str[i]), "NTOK_CHID=%04x", token->chid); + env[i] = str[i]; i++; + break; + case anev_abort: + snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=abort"); + env[i] = str[i]; i++; + break; + case anev_reset: + snprintf(str[i], sizeof(str[i]), "BRIDGEDHOST=reset"); + env[i] = str[i]; i++; + break; + } + env[i] = NULL; + kobject_uevent_env(&card->gdev->dev.kobj, KOBJ_CHANGE, env); +} + +struct qeth_bridge_state_data { + struct work_struct worker; + struct qeth_card *card; + struct qeth_sbp_state_change qports; +}; + +static void qeth_bridge_state_change_worker(struct work_struct *work) +{ + struct qeth_bridge_state_data *data = + container_of(work, struct qeth_bridge_state_data, worker); + /* We are only interested in the first entry - local port */ + struct qeth_sbp_port_entry *entry = &data->qports.entry[0]; + char env_locrem[32]; + char env_role[32]; + char env_state[32]; + char *env[] = { + env_locrem, + env_role, + env_state, + NULL + }; + + /* Role should not change by itself, but if it did, */ + /* information from the hardware is authoritative. */ + mutex_lock(&data->card->conf_mutex); + data->card->options.sbp.role = entry->role; + mutex_unlock(&data->card->conf_mutex); + + snprintf(env_locrem, sizeof(env_locrem), "BRIDGEPORT=statechange"); + snprintf(env_role, sizeof(env_role), "ROLE=%s", + (entry->role == QETH_SBP_ROLE_NONE) ? "none" : + (entry->role == QETH_SBP_ROLE_PRIMARY) ? "primary" : + (entry->role == QETH_SBP_ROLE_SECONDARY) ? "secondary" : + "<INVALID>"); + snprintf(env_state, sizeof(env_state), "STATE=%s", + (entry->state == QETH_SBP_STATE_INACTIVE) ? "inactive" : + (entry->state == QETH_SBP_STATE_STANDBY) ? "standby" : + (entry->state == QETH_SBP_STATE_ACTIVE) ? "active" : + "<INVALID>"); + kobject_uevent_env(&data->card->gdev->dev.kobj, + KOBJ_CHANGE, env); + kfree(data); +} + +void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd) +{ + struct qeth_sbp_state_change *qports = + &cmd->data.sbp.data.state_change; + struct qeth_bridge_state_data *data; + int extrasize; + + QETH_CARD_TEXT(card, 2, "brstchng"); + if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { + QETH_CARD_TEXT_(card, 2, "BPsz%.8d", qports->entry_length); + return; + } + extrasize = sizeof(struct qeth_sbp_port_entry) * qports->num_entries; + data = kzalloc(sizeof(struct qeth_bridge_state_data) + extrasize, + GFP_ATOMIC); + if (!data) { + QETH_CARD_TEXT(card, 2, "BPSalloc"); + return; + } + INIT_WORK(&data->worker, qeth_bridge_state_change_worker); + data->card = card; + memcpy(&data->qports, qports, + sizeof(struct qeth_sbp_state_change) + extrasize); + queue_work(qeth_wq, &data->worker); +} +EXPORT_SYMBOL(qeth_bridge_state_change); + +struct qeth_bridge_host_data { + struct work_struct worker; + struct qeth_card *card; + struct qeth_ipacmd_addr_change hostevs; +}; + +static void qeth_bridge_host_event_worker(struct work_struct *work) +{ + struct qeth_bridge_host_data *data = + container_of(work, struct qeth_bridge_host_data, worker); + int i; + + if (data->hostevs.lost_event_mask) { + dev_info(&data->card->gdev->dev, +"Address notification from the HiperSockets Bridge Port stopped %s (%s)\n", + data->card->dev->name, + (data->hostevs.lost_event_mask == 0x01) + ? "Overflow" + : (data->hostevs.lost_event_mask == 0x02) + ? "Bridge port state change" + : "Unknown reason"); + mutex_lock(&data->card->conf_mutex); + data->card->options.sbp.hostnotification = 0; + mutex_unlock(&data->card->conf_mutex); + qeth_bridge_emit_host_event(data->card, anev_abort, + 0, NULL, NULL); + } else + for (i = 0; i < data->hostevs.num_entries; i++) { + struct qeth_ipacmd_addr_change_entry *entry = + &data->hostevs.entry[i]; + qeth_bridge_emit_host_event(data->card, + anev_reg_unreg, + entry->change_code, + &entry->token, &entry->addr_lnid); + } + kfree(data); +} + +void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd) +{ + struct qeth_ipacmd_addr_change *hostevs = + &cmd->data.addrchange; + struct qeth_bridge_host_data *data; + int extrasize; + + QETH_CARD_TEXT(card, 2, "brhostev"); + if (cmd->hdr.return_code != 0x0000) { + if (cmd->hdr.return_code == 0x0010) { + if (hostevs->lost_event_mask == 0x00) + hostevs->lost_event_mask = 0xff; + } else { + QETH_CARD_TEXT_(card, 2, "BPHe%04x", + cmd->hdr.return_code); + return; + } + } + extrasize = sizeof(struct qeth_ipacmd_addr_change_entry) * + hostevs->num_entries; + data = kzalloc(sizeof(struct qeth_bridge_host_data) + extrasize, + GFP_ATOMIC); + if (!data) { + QETH_CARD_TEXT(card, 2, "BPHalloc"); + return; + } + INIT_WORK(&data->worker, qeth_bridge_host_event_worker); + data->card = card; + memcpy(&data->hostevs, hostevs, + sizeof(struct qeth_ipacmd_addr_change) + extrasize); + queue_work(qeth_wq, &data->worker); +} +EXPORT_SYMBOL(qeth_bridge_host_event); + +/* SETBRIDGEPORT support; sending commands */ + +struct _qeth_sbp_cbctl { + u16 ipa_rc; + u16 cmd_rc; + union { + u32 supported; + struct { + enum qeth_sbp_roles *role; + enum qeth_sbp_states *state; + } qports; + } data; +}; + +/** + * qeth_bridgeport_makerc() - derive "traditional" error from hardware codes. + * @card: qeth_card structure pointer, for debug messages. + * @cbctl: state structure with hardware return codes. + * @setcmd: IPA command code + * + * Returns negative errno-compatible error indication or 0 on success. + */ +static int qeth_bridgeport_makerc(struct qeth_card *card, + struct _qeth_sbp_cbctl *cbctl, enum qeth_ipa_sbp_cmd setcmd) +{ + int rc; + + switch (cbctl->ipa_rc) { + case IPA_RC_SUCCESS: + switch (cbctl->cmd_rc) { + case 0x0000: + rc = 0; + break; + case 0x0004: + rc = -ENOSYS; + break; + case 0x000C: /* Not configured as bridge Port */ + rc = -ENODEV; /* maybe not the best code here? */ + dev_err(&card->gdev->dev, + "The HiperSockets device is not configured as a Bridge Port\n"); + break; + case 0x0014: /* Another device is Primary */ + switch (setcmd) { + case IPA_SBP_SET_PRIMARY_BRIDGE_PORT: + rc = -EEXIST; + dev_err(&card->gdev->dev, + "The HiperSockets LAN already has a primary Bridge Port\n"); + break; + case IPA_SBP_SET_SECONDARY_BRIDGE_PORT: + rc = -EBUSY; + dev_err(&card->gdev->dev, + "The HiperSockets device is already a primary Bridge Port\n"); + break; + default: + rc = -EIO; + } + break; + case 0x0018: /* This device is currently Secondary */ + rc = -EBUSY; + dev_err(&card->gdev->dev, + "The HiperSockets device is already a secondary Bridge Port\n"); + break; + case 0x001C: /* Limit for Secondary devices reached */ + rc = -EEXIST; + dev_err(&card->gdev->dev, + "The HiperSockets LAN cannot have more secondary Bridge Ports\n"); + break; + case 0x0024: /* This device is currently Primary */ + rc = -EBUSY; + dev_err(&card->gdev->dev, + "The HiperSockets device is already a primary Bridge Port\n"); + break; + case 0x0020: /* Not authorized by zManager */ + rc = -EACCES; + dev_err(&card->gdev->dev, + "The HiperSockets device is not authorized to be a Bridge Port\n"); + break; + default: + rc = -EIO; + } + break; + case IPA_RC_NOTSUPP: + rc = -ENOSYS; + break; + case IPA_RC_UNSUPPORTED_COMMAND: + rc = -ENOSYS; + break; + default: + rc = -EIO; + } + if (rc) { + QETH_CARD_TEXT_(card, 2, "SBPi%04x", cbctl->ipa_rc); + QETH_CARD_TEXT_(card, 2, "SBPc%04x", cbctl->cmd_rc); + } + return rc; +} + +static int qeth_bridgeport_query_support_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; + QETH_CARD_TEXT(card, 2, "brqsupcb"); + cbctl->ipa_rc = cmd->hdr.return_code; + cbctl->cmd_rc = cmd->data.sbp.hdr.return_code; + if ((cbctl->ipa_rc == 0) && (cbctl->cmd_rc == 0)) { + cbctl->data.supported = + cmd->data.sbp.data.query_cmds_supp.supported_cmds; + } else { + cbctl->data.supported = 0; + } + return 0; +} + +/** + * qeth_bridgeport_query_support() - store bitmask of supported subfunctions. + * @card: qeth_card structure pointer. + * + * Sets bitmask of supported setbridgeport subfunctions in the qeth_card + * strucutre: card->options.sbp.supported_funcs. + */ +void qeth_bridgeport_query_support(struct qeth_card *card) +{ + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + struct _qeth_sbp_cbctl cbctl; + + QETH_CARD_TEXT(card, 2, "brqsuppo"); + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.sbp.hdr.cmdlength = + sizeof(struct qeth_ipacmd_sbp_hdr) + + sizeof(struct qeth_sbp_query_cmds_supp); + cmd->data.sbp.hdr.command_code = + IPA_SBP_QUERY_COMMANDS_SUPPORTED; + cmd->data.sbp.hdr.used_total = 1; + cmd->data.sbp.hdr.seq_no = 1; + if (qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_support_cb, + (void *)&cbctl) || + qeth_bridgeport_makerc(card, &cbctl, + IPA_SBP_QUERY_COMMANDS_SUPPORTED)) { + /* non-zero makerc signifies failure, and produce messages */ + card->options.sbp.role = QETH_SBP_ROLE_NONE; + return; + } + card->options.sbp.supported_funcs = cbctl.data.supported; +} +EXPORT_SYMBOL_GPL(qeth_bridgeport_query_support); + +static int qeth_bridgeport_query_ports_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *) data; + struct qeth_sbp_query_ports *qports = &cmd->data.sbp.data.query_ports; + struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; + + QETH_CARD_TEXT(card, 2, "brqprtcb"); + cbctl->ipa_rc = cmd->hdr.return_code; + cbctl->cmd_rc = cmd->data.sbp.hdr.return_code; + if ((cbctl->ipa_rc != 0) || (cbctl->cmd_rc != 0)) + return 0; + if (qports->entry_length != sizeof(struct qeth_sbp_port_entry)) { + cbctl->cmd_rc = 0xffff; + QETH_CARD_TEXT_(card, 2, "SBPs%04x", qports->entry_length); + return 0; + } + /* first entry contains the state of the local port */ + if (qports->num_entries > 0) { + if (cbctl->data.qports.role) + *cbctl->data.qports.role = qports->entry[0].role; + if (cbctl->data.qports.state) + *cbctl->data.qports.state = qports->entry[0].state; + } + return 0; +} + +/** + * qeth_bridgeport_query_ports() - query local bridgeport status. + * @card: qeth_card structure pointer. + * @role: Role of the port: 0-none, 1-primary, 2-secondary. + * @state: State of the port: 0-inactive, 1-standby, 2-active. + * + * Returns negative errno-compatible error indication or 0 on success. + * + * 'role' and 'state' are not updated in case of hardware operation failure. + */ +int qeth_bridgeport_query_ports(struct qeth_card *card, + enum qeth_sbp_roles *role, enum qeth_sbp_states *state) +{ + int rc = 0; + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + struct _qeth_sbp_cbctl cbctl = { + .data = { + .qports = { + .role = role, + .state = state, + }, + }, + }; + + QETH_CARD_TEXT(card, 2, "brqports"); + if (!(card->options.sbp.supported_funcs & IPA_SBP_QUERY_BRIDGE_PORTS)) + return -EOPNOTSUPP; + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.sbp.hdr.cmdlength = + sizeof(struct qeth_ipacmd_sbp_hdr); + cmd->data.sbp.hdr.command_code = + IPA_SBP_QUERY_BRIDGE_PORTS; + cmd->data.sbp.hdr.used_total = 1; + cmd->data.sbp.hdr.seq_no = 1; + rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_query_ports_cb, + (void *)&cbctl); + if (rc) + return rc; + rc = qeth_bridgeport_makerc(card, &cbctl, IPA_SBP_QUERY_BRIDGE_PORTS); + if (rc) + return rc; + return 0; +} +EXPORT_SYMBOL_GPL(qeth_bridgeport_query_ports); + +static int qeth_bridgeport_set_cb(struct qeth_card *card, + struct qeth_reply *reply, unsigned long data) +{ + struct qeth_ipa_cmd *cmd = (struct qeth_ipa_cmd *)data; + struct _qeth_sbp_cbctl *cbctl = (struct _qeth_sbp_cbctl *)reply->param; + QETH_CARD_TEXT(card, 2, "brsetrcb"); + cbctl->ipa_rc = cmd->hdr.return_code; + cbctl->cmd_rc = cmd->data.sbp.hdr.return_code; + return 0; +} + +/** + * qeth_bridgeport_setrole() - Assign primary role to the port. + * @card: qeth_card structure pointer. + * @role: Role to assign. + * + * Returns negative errno-compatible error indication or 0 on success. + */ +int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role) +{ + int rc = 0; + int cmdlength; + struct qeth_cmd_buffer *iob; + struct qeth_ipa_cmd *cmd; + struct _qeth_sbp_cbctl cbctl; + enum qeth_ipa_sbp_cmd setcmd; + + QETH_CARD_TEXT(card, 2, "brsetrol"); + switch (role) { + case QETH_SBP_ROLE_NONE: + setcmd = IPA_SBP_RESET_BRIDGE_PORT_ROLE; + cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) + + sizeof(struct qeth_sbp_reset_role); + break; + case QETH_SBP_ROLE_PRIMARY: + setcmd = IPA_SBP_SET_PRIMARY_BRIDGE_PORT; + cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) + + sizeof(struct qeth_sbp_set_primary); + break; + case QETH_SBP_ROLE_SECONDARY: + setcmd = IPA_SBP_SET_SECONDARY_BRIDGE_PORT; + cmdlength = sizeof(struct qeth_ipacmd_sbp_hdr) + + sizeof(struct qeth_sbp_set_secondary); + break; + default: + return -EINVAL; + } + if (!(card->options.sbp.supported_funcs & setcmd)) + return -EOPNOTSUPP; + iob = qeth_get_ipacmd_buffer(card, IPA_CMD_SETBRIDGEPORT, 0); + cmd = (struct qeth_ipa_cmd *)(iob->data+IPA_PDU_HEADER_SIZE); + cmd->data.sbp.hdr.cmdlength = cmdlength; + cmd->data.sbp.hdr.command_code = setcmd; + cmd->data.sbp.hdr.used_total = 1; + cmd->data.sbp.hdr.seq_no = 1; + rc = qeth_send_ipa_cmd(card, iob, qeth_bridgeport_set_cb, + (void *)&cbctl); + if (rc) + return rc; + rc = qeth_bridgeport_makerc(card, &cbctl, setcmd); + return rc; +} + +/** + * qeth_anset_makerc() - derive "traditional" error from hardware codes. + * @card: qeth_card structure pointer, for debug messages. + * + * Returns negative errno-compatible error indication or 0 on success. + */ +static int qeth_anset_makerc(struct qeth_card *card, int pnso_rc, u16 response) +{ + int rc; + + if (pnso_rc == 0) + switch (response) { + case 0x0001: + rc = 0; + break; + case 0x0004: + case 0x0100: + case 0x0106: + rc = -ENOSYS; + dev_err(&card->gdev->dev, + "Setting address notification failed\n"); + break; + case 0x0107: + rc = -EAGAIN; + break; + default: + rc = -EIO; + } + else + rc = -EIO; + + if (rc) { + QETH_CARD_TEXT_(card, 2, "SBPp%04x", pnso_rc); + QETH_CARD_TEXT_(card, 2, "SBPr%04x", response); + } + return rc; +} + +static void qeth_bridgeport_an_set_cb(void *priv, + enum qdio_brinfo_entry_type type, void *entry) +{ + struct qeth_card *card = (struct qeth_card *)priv; + struct qdio_brinfo_entry_l2 *l2entry; + u8 code; + + if (type != l2_addr_lnid) { + WARN_ON_ONCE(1); + return; + } + + l2entry = (struct qdio_brinfo_entry_l2 *)entry; + code = IPA_ADDR_CHANGE_CODE_MACADDR; + if (l2entry->addr_lnid.lnid) + code |= IPA_ADDR_CHANGE_CODE_VLANID; + qeth_bridge_emit_host_event(card, anev_reg_unreg, code, + (struct net_if_token *)&l2entry->nit, + (struct mac_addr_lnid *)&l2entry->addr_lnid); +} + +/** + * qeth_bridgeport_an_set() - Enable or disable bridgeport address notification + * @card: qeth_card structure pointer. + * @enable: 0 - disable, non-zero - enable notifications + * + * Returns negative errno-compatible error indication or 0 on success. + * + * On enable, emits a series of address notifications udev events for all + * currently registered hosts. + */ +int qeth_bridgeport_an_set(struct qeth_card *card, int enable) +{ + int rc; + u16 response; + struct ccw_device *ddev; + struct subchannel_id schid; + + if (!card) + return -EINVAL; + if (!card->options.sbp.supported_funcs) + return -EOPNOTSUPP; + ddev = CARD_DDEV(card); + ccw_device_get_schid(ddev, &schid); + + if (enable) { + qeth_bridge_emit_host_event(card, anev_reset, 0, NULL, NULL); + rc = qdio_pnso_brinfo(schid, 1, &response, + qeth_bridgeport_an_set_cb, card); + } else + rc = qdio_pnso_brinfo(schid, 0, &response, NULL, NULL); + return qeth_anset_makerc(card, rc, response); +} +EXPORT_SYMBOL_GPL(qeth_bridgeport_an_set); + module_init(qeth_l2_init); module_exit(qeth_l2_exit); MODULE_AUTHOR("Frank Blaschka <frank.blaschka@de.ibm.com>"); diff --git a/drivers/s390/net/qeth_l2_sys.c b/drivers/s390/net/qeth_l2_sys.c new file mode 100644 index 000000000000..ae1bc04b8653 --- /dev/null +++ b/drivers/s390/net/qeth_l2_sys.c @@ -0,0 +1,223 @@ +/* + * Copyright IBM Corp. 2013 + * Author(s): Eugene Crosser <eugene.crosser@ru.ibm.com> + */ + +#include <linux/slab.h> +#include <asm/ebcdic.h> +#include "qeth_l2.h" + +#define QETH_DEVICE_ATTR(_id, _name, _mode, _show, _store) \ +struct device_attribute dev_attr_##_id = __ATTR(_name, _mode, _show, _store) + +static int qeth_card_hw_is_reachable(struct qeth_card *card) +{ + return (card->state == CARD_STATE_SOFTSETUP) || + (card->state == CARD_STATE_UP); +} + +static ssize_t qeth_bridge_port_role_state_show(struct device *dev, + struct device_attribute *attr, char *buf, + int show_state) +{ + struct qeth_card *card = dev_get_drvdata(dev); + enum qeth_sbp_states state = QETH_SBP_STATE_INACTIVE; + int rc = 0; + char *word; + + if (!card) + return -EINVAL; + + mutex_lock(&card->conf_mutex); + + if (qeth_card_hw_is_reachable(card) && + card->options.sbp.supported_funcs) + rc = qeth_bridgeport_query_ports(card, + &card->options.sbp.role, &state); + if (!rc) { + if (show_state) + switch (state) { + case QETH_SBP_STATE_INACTIVE: + word = "inactive"; break; + case QETH_SBP_STATE_STANDBY: + word = "standby"; break; + case QETH_SBP_STATE_ACTIVE: + word = "active"; break; + default: + rc = -EIO; + } + else + switch (card->options.sbp.role) { + case QETH_SBP_ROLE_NONE: + word = "none"; break; + case QETH_SBP_ROLE_PRIMARY: + word = "primary"; break; + case QETH_SBP_ROLE_SECONDARY: + word = "secondary"; break; + default: + rc = -EIO; + } + if (rc) + QETH_CARD_TEXT_(card, 2, "SBP%02x:%02x", + card->options.sbp.role, state); + else + rc = sprintf(buf, "%s\n", word); + } + + mutex_unlock(&card->conf_mutex); + + return rc; +} + +static ssize_t qeth_bridge_port_role_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return qeth_bridge_port_role_state_show(dev, attr, buf, 0); +} + +static ssize_t qeth_bridge_port_role_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int rc = 0; + enum qeth_sbp_roles role; + + if (!card) + return -EINVAL; + if (sysfs_streq(buf, "primary")) + role = QETH_SBP_ROLE_PRIMARY; + else if (sysfs_streq(buf, "secondary")) + role = QETH_SBP_ROLE_SECONDARY; + else if (sysfs_streq(buf, "none")) + role = QETH_SBP_ROLE_NONE; + else + return -EINVAL; + + mutex_lock(&card->conf_mutex); + + if (qeth_card_hw_is_reachable(card)) { + rc = qeth_bridgeport_setrole(card, role); + if (!rc) + card->options.sbp.role = role; + } else + card->options.sbp.role = role; + + mutex_unlock(&card->conf_mutex); + + return rc ? rc : count; +} + +static DEVICE_ATTR(bridge_role, 0644, qeth_bridge_port_role_show, + qeth_bridge_port_role_store); + +static ssize_t qeth_bridge_port_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return qeth_bridge_port_role_state_show(dev, attr, buf, 1); +} + +static DEVICE_ATTR(bridge_state, 0644, qeth_bridge_port_state_show, + NULL); + +static ssize_t qeth_bridgeport_hostnotification_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int enabled; + + if (!card) + return -EINVAL; + + mutex_lock(&card->conf_mutex); + + enabled = card->options.sbp.hostnotification; + + mutex_unlock(&card->conf_mutex); + + return sprintf(buf, "%d\n", enabled); +} + +static ssize_t qeth_bridgeport_hostnotification_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct qeth_card *card = dev_get_drvdata(dev); + int rc = 0; + int enable; + + if (!card) + return -EINVAL; + + if (sysfs_streq(buf, "0")) + enable = 0; + else if (sysfs_streq(buf, "1")) + enable = 1; + else + return -EINVAL; + + mutex_lock(&card->conf_mutex); + + if (qeth_card_hw_is_reachable(card)) { + rc = qeth_bridgeport_an_set(card, enable); + if (!rc) + card->options.sbp.hostnotification = enable; + } else + card->options.sbp.hostnotification = enable; + + mutex_unlock(&card->conf_mutex); + + return rc ? rc : count; +} + +static DEVICE_ATTR(bridge_hostnotify, 0644, + qeth_bridgeport_hostnotification_show, + qeth_bridgeport_hostnotification_store); + +static struct attribute *qeth_l2_bridgeport_attrs[] = { + &dev_attr_bridge_role.attr, + &dev_attr_bridge_state.attr, + &dev_attr_bridge_hostnotify.attr, + NULL, +}; + +static struct attribute_group qeth_l2_bridgeport_attr_group = { + .attrs = qeth_l2_bridgeport_attrs, +}; + +int qeth_l2_create_device_attributes(struct device *dev) +{ + return sysfs_create_group(&dev->kobj, &qeth_l2_bridgeport_attr_group); +} + +void qeth_l2_remove_device_attributes(struct device *dev) +{ + sysfs_remove_group(&dev->kobj, &qeth_l2_bridgeport_attr_group); +} + +/** + * qeth_l2_setup_bridgeport_attrs() - set/restore attrs when turning online. + * @card: qeth_card structure pointer + * + * Note: this function is called with conf_mutex held by the caller + */ +void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card) +{ + int rc; + + if (!card) + return; + if (!card->options.sbp.supported_funcs) + return; + if (card->options.sbp.role != QETH_SBP_ROLE_NONE) { + /* Conditional to avoid spurious error messages */ + qeth_bridgeport_setrole(card, card->options.sbp.role); + /* Let the callback function refresh the stored role value. */ + qeth_bridgeport_query_ports(card, + &card->options.sbp.role, NULL); + } + if (card->options.sbp.hostnotification) { + rc = qeth_bridgeport_an_set(card, 1); + if (rc) + card->options.sbp.hostnotification = 0; + } else + qeth_bridgeport_an_set(card, 0); +} diff --git a/drivers/ssb/driver_chipcommon_sflash.c b/drivers/ssb/driver_chipcommon_sflash.c index 50328de712fa..937fc31971a7 100644 --- a/drivers/ssb/driver_chipcommon_sflash.c +++ b/drivers/ssb/driver_chipcommon_sflash.c @@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = { { "M25P32", 0x15, 0x10000, 64, }, { "M25P64", 0x16, 0x10000, 128, }, { "M25FL128", 0x17, 0x10000, 256, }, - { 0 }, + { NULL }, }; static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { @@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = { { "SST25VF016", 0x41, 0x1000, 512, }, { "SST25VF032", 0x4a, 0x1000, 1024, }, { "SST25VF064", 0x4b, 0x1000, 2048, }, - { 0 }, + { NULL }, }; static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { @@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = { { "AT45DB161", 0x2c, 512, 4096, }, { "AT45DB321", 0x34, 512, 8192, }, { "AT45DB642", 0x3c, 1024, 8192, }, - { 0 }, + { NULL }, }; static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode) diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 53fee2f9a498..8dfdd2732bdc 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -39,7 +39,8 @@ static INT bcm_close(struct net_device *dev) return 0; } -static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { return ClassifyPacket(netdev_priv(dev), skb); } diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 9b483739881a..4a08e16e42f7 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -770,9 +770,9 @@ do_del_chan (struct net_device *musycc_dev, void *data) if (cp.channum > 999) return -EINVAL; snprintf (buf, sizeof(buf), CHANNAME "%d", cp.channum); - if (!(dev = dev_get_by_name (&init_net, buf))) - return -ENOENT; - dev_put (dev); + dev = __dev_get_by_name(&init_net, buf); + if (!dev) + return -ENODEV; ret = do_deluser (dev, 1); if (ret) return ret; @@ -792,19 +792,18 @@ do_reset (struct net_device *musycc_dev, void *data) char buf[sizeof (CHANNAME) + 3]; sprintf (buf, CHANNAME "%d", i); - if (!(ndev = dev_get_by_name(&init_net, buf))) - continue; + ndev = __dev_get_by_name(&init_net, buf); + if (!ndev) + continue; priv = dev_to_hdlc (ndev)->priv; if ((unsigned long) (priv->ci) == (unsigned long) (netdev_priv(musycc_dev))) { ndev->flags &= ~IFF_UP; - dev_put (ndev); netif_stop_queue (ndev); do_deluser (ndev, 1); - } else - dev_put (ndev); + } } return 0; } diff --git a/drivers/staging/dgap/Kconfig b/drivers/staging/dgap/Kconfig index 31f1d7533eec..3bbe9e122365 100644 --- a/drivers/staging/dgap/Kconfig +++ b/drivers/staging/dgap/Kconfig @@ -1,6 +1,6 @@ config DGAP tristate "Digi EPCA PCI products" default n - depends on TTY + depends on TTY && HAS_IOMEM ---help--- Driver for the Digi International EPCA PCI based product line diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index e3d643001952..363329808a4f 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -103,6 +103,7 @@ config AD7280 config LPC32XX_ADC tristate "NXP LPC32XX ADC" depends on ARCH_LPC32XX || COMPILE_TEST + depends on HAS_IOMEM help Say yes here to build support for the integrated ADC inside the LPC32XX SoC. Note that this feature uses the same hardware as the @@ -128,6 +129,7 @@ config MXS_LRADC config SPEAR_ADC tristate "ST SPEAr ADC" depends on PLAT_SPEAR || COMPILE_TEST + depends on HAS_IOMEM help Say yes here to build support for the integrated ADC inside the ST SPEAr SoC. Provides direct access via sysfs. diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index 235d2b1ec593..eedffed17e39 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -306,7 +306,8 @@ static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } -static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb) +static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb, + void *accel_priv) { return (u16)smp_processor_id(); } diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index 17659bb04bef..dd69e344e409 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -652,7 +652,8 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb) return dscp >> 5; } -static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb) +static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, + void *accel_priv) { struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; |