diff options
Diffstat (limited to 'drivers')
701 files changed, 21302 insertions, 9999 deletions
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index e7515aa43d6b..6f190bc2b8b7 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -243,6 +243,8 @@ static int acpi_ac_resume(struct device *dev) kobject_uevent(&ac->charger.dev->kobj, KOBJ_CHANGE); return 0; } +#else +#define acpi_ac_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_ac_pm_ops, NULL, acpi_ac_resume); diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 018a42883706..797a6938d051 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -841,6 +841,8 @@ static int acpi_battery_resume(struct device *dev) acpi_battery_update(battery); return 0; } +#else +#define acpi_battery_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_battery_pm, NULL, acpi_battery_resume); diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 10e4964d051a..afec4526c48a 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -260,14 +260,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { }, { .callback = dmi_disable_osi_win8, - .ident = "Dell Inspiron 15R SE", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 7520"), - }, - }, - { - .callback = dmi_disable_osi_win8, .ident = "ThinkPad Edge E530", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), @@ -322,56 +314,6 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_VERSION, "2349D15"), }, }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ProBook 2013 models", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "), - DMI_MATCH(DMI_PRODUCT_NAME, " G1"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP EliteBook 2013 models", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "), - DMI_MATCH(DMI_PRODUCT_NAME, " G1"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ZBook 14", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ZBook 15", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP ZBook 17", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"), - }, - }, - { - .callback = dmi_disable_osi_win8, - .ident = "HP EliteBook 8780w", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"), - }, - }, /* * BIOS invocation of _OSI(Linux) is almost always a BIOS bug. diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 11c11f6b8fa1..714e957a871a 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -80,6 +80,8 @@ static void acpi_button_notify(struct acpi_device *device, u32 event); #ifdef CONFIG_PM_SLEEP static int acpi_button_resume(struct device *dev); +#else +#define acpi_button_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_button_pm, NULL, acpi_button_resume); diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index 0b6ae6eb5c4a..368f9ddb8480 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -79,9 +79,10 @@ static int container_device_attach(struct acpi_device *adev, ACPI_COMPANION_SET(dev, adev); dev->release = acpi_container_release; ret = device_register(dev); - if (ret) + if (ret) { + put_device(dev); return ret; - + } adev->driver_data = dev; return 1; } diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index c431c88faaff..5bfd769fc91f 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -609,7 +609,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event) static void dock_notify(struct dock_station *ds, u32 event) { acpi_handle handle = ds->handle; - struct acpi_device *ad; + struct acpi_device *adev = NULL; int surprise_removal = 0; /* @@ -632,7 +632,8 @@ static void dock_notify(struct dock_station *ds, u32 event) switch (event) { case ACPI_NOTIFY_BUS_CHECK: case ACPI_NOTIFY_DEVICE_CHECK: - if (!dock_in_progress(ds) && acpi_bus_get_device(handle, &ad)) { + acpi_bus_get_device(handle, &adev); + if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) { begin_dock(ds); dock(ds); if (!dock_present(ds)) { @@ -712,13 +713,11 @@ static acpi_status __init find_dock_devices(acpi_handle handle, u32 lvl, static ssize_t show_docked(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *tmp; - struct dock_station *dock_station = dev->platform_data; + struct acpi_device *adev = NULL; - if (!acpi_bus_get_device(dock_station->handle, &tmp)) - return snprintf(buf, PAGE_SIZE, "1\n"); - return snprintf(buf, PAGE_SIZE, "0\n"); + acpi_bus_get_device(dock_station->handle, &adev); + return snprintf(buf, PAGE_SIZE, "%u\n", acpi_device_enumerated(adev)); } static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 1fb62900f32a..09e423f3d8ad 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -55,6 +55,9 @@ MODULE_DEVICE_TABLE(acpi, fan_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_fan_suspend(struct device *dev); static int acpi_fan_resume(struct device *dev); +#else +#define acpi_fan_suspend NULL +#define acpi_fan_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_fan_pm, acpi_fan_suspend, acpi_fan_resume); diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 52d45ea2bc4f..361b40c10c3f 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -430,6 +430,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev) pin_name(pin)); } + kfree(entry); return 0; } diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 28baa05b8018..84243c32e29c 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -56,6 +56,12 @@ struct throttling_tstate { int target_state; /* target T-state */ }; +struct acpi_processor_throttling_arg { + struct acpi_processor *pr; + int target_state; + bool force; +}; + #define THROTTLING_PRECHANGE (1) #define THROTTLING_POSTCHANGE (2) @@ -1060,16 +1066,24 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr, return 0; } +static long acpi_processor_throttling_fn(void *data) +{ + struct acpi_processor_throttling_arg *arg = data; + struct acpi_processor *pr = arg->pr; + + return pr->throttling.acpi_processor_set_throttling(pr, + arg->target_state, arg->force); +} + int acpi_processor_set_throttling(struct acpi_processor *pr, int state, bool force) { - cpumask_var_t saved_mask; int ret = 0; unsigned int i; struct acpi_processor *match_pr; struct acpi_processor_throttling *p_throttling; + struct acpi_processor_throttling_arg arg; struct throttling_tstate t_state; - cpumask_var_t online_throttling_cpus; if (!pr) return -EINVAL; @@ -1080,14 +1094,6 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, if ((state < 0) || (state > (pr->throttling.state_count - 1))) return -EINVAL; - if (!alloc_cpumask_var(&saved_mask, GFP_KERNEL)) - return -ENOMEM; - - if (!alloc_cpumask_var(&online_throttling_cpus, GFP_KERNEL)) { - free_cpumask_var(saved_mask); - return -ENOMEM; - } - if (cpu_is_offline(pr->id)) { /* * the cpu pointed by pr->id is offline. Unnecessary to change @@ -1096,17 +1102,15 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, return -ENODEV; } - cpumask_copy(saved_mask, ¤t->cpus_allowed); t_state.target_state = state; p_throttling = &(pr->throttling); - cpumask_and(online_throttling_cpus, cpu_online_mask, - p_throttling->shared_cpu_map); + /* * The throttling notifier will be called for every * affected cpu in order to get one proper T-state. * The notifier event is THROTTLING_PRECHANGE. */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { t_state.cpu = i; acpi_processor_throttling_notifier(THROTTLING_PRECHANGE, &t_state); @@ -1118,21 +1122,18 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, * it can be called only for the cpu pointed by pr. */ if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) { - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(pr->id))) { - /* Can't migrate to the pr->id CPU. Exit */ - ret = -ENODEV; - goto exit; - } - ret = p_throttling->acpi_processor_set_throttling(pr, - t_state.target_state, force); + arg.pr = pr; + arg.target_state = state; + arg.force = force; + ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, &arg); } else { /* * When the T-state coordination is SW_ALL or HW_ALL, * it is necessary to set T-state for every affected * cpus. */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, + p_throttling->shared_cpu_map) { match_pr = per_cpu(processors, i); /* * If the pointer is invalid, we will report the @@ -1153,13 +1154,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, "on CPU %d\n", i)); continue; } - t_state.cpu = i; - /* FIXME: use work_on_cpu() */ - if (set_cpus_allowed_ptr(current, cpumask_of(i))) - continue; - ret = match_pr->throttling. - acpi_processor_set_throttling( - match_pr, t_state.target_state, force); + + arg.pr = match_pr; + arg.target_state = state; + arg.force = force; + ret = work_on_cpu(pr->id, acpi_processor_throttling_fn, + &arg); } } /* @@ -1168,17 +1168,12 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, * affected cpu to update the T-states. * The notifier event is THROTTLING_POSTCHANGE */ - for_each_cpu(i, online_throttling_cpus) { + for_each_cpu_and(i, cpu_online_mask, p_throttling->shared_cpu_map) { t_state.cpu = i; acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE, &t_state); } - /* restore the previous state */ - /* FIXME: use work_on_cpu() */ - set_cpus_allowed_ptr(current, saved_mask); -exit: - free_cpumask_var(online_throttling_cpus); - free_cpumask_var(saved_mask); + return ret; } diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index d465ae6cdd00..dbd48498b938 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -450,7 +450,7 @@ static ssize_t acpi_battery_alarm_store(struct device *dev, { unsigned long x; struct acpi_battery *battery = to_acpi_battery(dev_get_drvdata(dev)); - if (sscanf(buf, "%ld\n", &x) == 1) + if (sscanf(buf, "%lu\n", &x) == 1) battery->alarm_capacity = x / (1000 * acpi_battery_scale(battery)); if (battery->present) @@ -668,6 +668,8 @@ static int acpi_sbs_resume(struct device *dev) acpi_sbs_callback(sbs); return 0; } +#else +#define acpi_sbs_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_sbs_pm, NULL, acpi_sbs_resume); diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 8349a555b92b..08626c851be7 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -102,6 +102,8 @@ MODULE_DEVICE_TABLE(acpi, thermal_device_ids); #ifdef CONFIG_PM_SLEEP static int acpi_thermal_resume(struct device *dev); +#else +#define acpi_thermal_resume NULL #endif static SIMPLE_DEV_PM_OPS(acpi_thermal_pm, NULL, acpi_thermal_resume); diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c index b727d105046d..b6ba88ed31ae 100644 --- a/drivers/acpi/video.c +++ b/drivers/acpi/video.c @@ -81,11 +81,12 @@ static bool allow_duplicates; module_param(allow_duplicates, bool, 0644); /* - * For Windows 8 systems: if set ture and the GPU driver has - * registered a backlight interface, skip registering ACPI video's. + * For Windows 8 systems: used to decide if video module + * should skip registering backlight interface of its own. */ -static bool use_native_backlight = false; -module_param(use_native_backlight, bool, 0644); +static int use_native_backlight_param = -1; +module_param_named(use_native_backlight, use_native_backlight_param, int, 0444); +static bool use_native_backlight_dmi = false; static int register_count; static struct mutex video_list_lock; @@ -231,9 +232,17 @@ static int acpi_video_get_next_level(struct acpi_video_device *device, static int acpi_video_switch_brightness(struct acpi_video_device *device, int event); +static bool acpi_video_use_native_backlight(void) +{ + if (use_native_backlight_param != -1) + return use_native_backlight_param; + else + return use_native_backlight_dmi; +} + static bool acpi_video_verify_backlight_support(void) { - if (acpi_osi_is_win8() && use_native_backlight && + if (acpi_osi_is_win8() && acpi_video_use_native_backlight() && backlight_device_registered(BACKLIGHT_RAW)) return false; return acpi_video_backlight_support(); @@ -398,6 +407,12 @@ static int __init video_set_bqc_offset(const struct dmi_system_id *d) return 0; } +static int __init video_set_use_native_backlight(const struct dmi_system_id *d) +{ + use_native_backlight_dmi = true; + return 0; +} + static struct dmi_system_id video_dmi_table[] __initdata = { /* * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121 @@ -442,6 +457,120 @@ static struct dmi_system_id video_dmi_table[] __initdata = { DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"), }, }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad T430s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T430s"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad X230", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X230"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "ThinkPad X1 Carbon", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X1 Carbon"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Lenovo Yoga 13", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Dell Inspiron 7520", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), + DMI_MATCH(DMI_PRODUCT_VERSION, "Inspiron 7520"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire 5733Z", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5733Z"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "Acer Aspire V5-431", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-431"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ProBook 4340s", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_VERSION, "HP ProBook 4340s"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ProBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 2013 models", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook "), + DMI_MATCH(DMI_PRODUCT_NAME, " G1"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 14", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 14"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 15", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 15"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP ZBook 17", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP ZBook 17"), + }, + }, + { + .callback = video_set_use_native_backlight, + .ident = "HP EliteBook 8780w", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"), + }, + }, {} }; @@ -685,6 +814,7 @@ acpi_video_init_brightness(struct acpi_video_device *device) union acpi_object *o; struct acpi_video_device_brightness *br = NULL; int result = -EINVAL; + u32 value; if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available " @@ -715,7 +845,12 @@ acpi_video_init_brightness(struct acpi_video_device *device) printk(KERN_ERR PREFIX "Invalid data\n"); continue; } - br->levels[count] = (u32) o->integer.value; + value = (u32) o->integer.value; + /* Skip duplicate entries */ + if (count > 2 && br->levels[count - 1] == value) + continue; + + br->levels[count] = value; if (br->levels[count] > max_level) max_level = br->levels[count]; diff --git a/drivers/acpi/video_detect.c b/drivers/acpi/video_detect.c index a697b77b8865..19080c8e2f2a 100644 --- a/drivers/acpi/video_detect.c +++ b/drivers/acpi/video_detect.c @@ -168,22 +168,6 @@ static struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "UL30A"), }, }, - { - .callback = video_detect_force_vendor, - .ident = "HP EliteBook Revolve 810", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook Revolve 810 G1"), - }, - }, - { - .callback = video_detect_force_vendor, - .ident = "Lenovo Yoga 13", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo IdeaPad Yoga 13"), - }, - }, { }, }; diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig index 4e737728aee2..868429a47be4 100644 --- a/drivers/ata/Kconfig +++ b/drivers/ata/Kconfig @@ -247,6 +247,7 @@ config SATA_HIGHBANK config SATA_MV tristate "Marvell SATA support" + select GENERIC_PHY help This option enables support for the Marvell Serial ATA family. Currently supports 88SX[56]0[48][01] PCI(-X) chips, diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c index dc2756fb6f33..c81d809c111b 100644 --- a/drivers/ata/ahci.c +++ b/drivers/ata/ahci.c @@ -61,6 +61,7 @@ enum board_ids { /* board IDs by feature in alphabetical order */ board_ahci, board_ahci_ign_iferr, + board_ahci_noncq, board_ahci_nosntf, board_ahci_yes_fbs, @@ -121,6 +122,13 @@ static const struct ata_port_info ahci_port_info[] = { .udma_mask = ATA_UDMA6, .port_ops = &ahci_ops, }, + [board_ahci_noncq] = { + AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ), + .flags = AHCI_FLAG_COMMON, + .pio_mask = ATA_PIO4, + .udma_mask = ATA_UDMA6, + .port_ops = &ahci_ops, + }, [board_ahci_nosntf] = { AHCI_HFLAGS (AHCI_HFLAG_NO_SNTF), .flags = AHCI_FLAG_COMMON, @@ -452,6 +460,12 @@ static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VDEVICE(ASMEDIA, 0x0611), board_ahci }, /* ASM1061 */ { PCI_VDEVICE(ASMEDIA, 0x0612), board_ahci }, /* ASM1062 */ + /* + * Samsung SSDs found on some macbooks. NCQ times out. + * https://bugzilla.kernel.org/show_bug.cgi?id=60731 + */ + { PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_noncq }, + /* Enmotus */ { PCI_DEVICE(0x1c44, 0x8000), board_ahci }, @@ -1170,8 +1184,10 @@ static int ahci_init_interrupts(struct pci_dev *pdev, unsigned int n_ports, nvec = rc; rc = pci_enable_msi_block(pdev, nvec); - if (rc) + if (rc < 0) goto intx; + else if (rc > 0) + goto single_msi; return nvec; diff --git a/drivers/ata/libata-pmp.c b/drivers/ata/libata-pmp.c index 20fd337a5731..7ccc084bf1df 100644 --- a/drivers/ata/libata-pmp.c +++ b/drivers/ata/libata-pmp.c @@ -447,8 +447,11 @@ static void sata_pmp_quirks(struct ata_port *ap) * otherwise. Don't try hard to recover it. */ ap->pmp_link[ap->nr_pmp_links - 1].flags |= ATA_LFLAG_NO_RETRY; - } else if (vendor == 0x197b && devid == 0x2352) { - /* chip found in Thermaltake BlackX Duet, jmicron JMB350? */ + } else if (vendor == 0x197b && (devid == 0x2352 || devid == 0x0325)) { + /* + * 0x2352: found in Thermaltake BlackX Duet, jmicron JMB350? + * 0x0325: jmicron JMB394. + */ ata_for_each_link(link, ap, EDGE) { /* SRST breaks detection and disks get misclassified * LPM disabled to avoid potential problems diff --git a/drivers/ata/pata_imx.c b/drivers/ata/pata_imx.c index 26386f0b89a8..b0b18ec5465f 100644 --- a/drivers/ata/pata_imx.c +++ b/drivers/ata/pata_imx.c @@ -119,7 +119,9 @@ static int pata_imx_probe(struct platform_device *pdev) return PTR_ERR(priv->clk); } - clk_prepare_enable(priv->clk); + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; host = ata_host_alloc(&pdev->dev, 1); if (!host) { @@ -212,7 +214,9 @@ static int pata_imx_resume(struct device *dev) struct ata_host *host = dev_get_drvdata(dev); struct pata_imx_priv *priv = host->private_data; - clk_prepare_enable(priv->clk); + int ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; __raw_writel(priv->ata_ctl, priv->host_regs + PATA_IMX_ATA_CONTROL); diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c index 20a7517bd339..05c8a44adf8e 100644 --- a/drivers/ata/sata_mv.c +++ b/drivers/ata/sata_mv.c @@ -4104,7 +4104,6 @@ static int mv_platform_probe(struct platform_device *pdev) if (!hpriv->port_phys) return -ENOMEM; host->private_data = hpriv; - hpriv->n_ports = n_ports; hpriv->board_idx = chip_soc; host->iomap = NULL; @@ -4126,17 +4125,24 @@ static int mv_platform_probe(struct platform_device *pdev) clk_prepare_enable(hpriv->port_clks[port]); sprintf(port_number, "port%d", port); - hpriv->port_phys[port] = devm_phy_get(&pdev->dev, port_number); + hpriv->port_phys[port] = devm_phy_optional_get(&pdev->dev, + port_number); if (IS_ERR(hpriv->port_phys[port])) { rc = PTR_ERR(hpriv->port_phys[port]); hpriv->port_phys[port] = NULL; - if ((rc != -EPROBE_DEFER) && (rc != -ENODEV)) - dev_warn(&pdev->dev, "error getting phy"); + if (rc != -EPROBE_DEFER) + dev_warn(&pdev->dev, "error getting phy %d", rc); + + /* Cleanup only the initialized ports */ + hpriv->n_ports = port; goto err; } else phy_power_on(hpriv->port_phys[port]); } + /* All the ports have been initialized */ + hpriv->n_ports = n_ports; + /* * (Re-)program MBUS remapping windows if we are asked to. */ @@ -4174,7 +4180,7 @@ err: clk_disable_unprepare(hpriv->clk); clk_put(hpriv->clk); } - for (port = 0; port < n_ports; port++) { + for (port = 0; port < hpriv->n_ports; port++) { if (!IS_ERR(hpriv->port_clks[port])) { clk_disable_unprepare(hpriv->port_clks[port]); clk_put(hpriv->port_clks[port]); diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c index d67fc351343c..b7695e804635 100644 --- a/drivers/ata/sata_sil.c +++ b/drivers/ata/sata_sil.c @@ -157,6 +157,7 @@ static const struct sil_drivelist { { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, { "ST3120022ASL", SIL_QUIRK_MOD15WRITE }, { "ST3160021ASL", SIL_QUIRK_MOD15WRITE }, + { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE }, { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX }, { } }; diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c index 62a76076b548..f1a9198dfe5a 100644 --- a/drivers/atm/ambassador.c +++ b/drivers/atm/ambassador.c @@ -1925,7 +1925,7 @@ static int ucode_init(loader_block *lb, amb_dev *dev) const struct firmware *fw; unsigned long start_address; const struct ihex_binrec *rec; - const char *errmsg = 0; + const char *errmsg = NULL; int res; res = request_ihex_firmware(&fw, "atmsar11.fw", &dev->pci_dev->dev); diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index b41c9481b67b..f43e1c13b300 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -736,8 +736,8 @@ static void process_txdone_queue (struct fs_dev *dev, struct queue *q) skb = td->skb; if (skb == FS_VCC (ATM_SKB(skb)->vcc)->last_skb) { - wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait); FS_VCC (ATM_SKB(skb)->vcc)->last_skb = NULL; + wake_up_interruptible (& FS_VCC (ATM_SKB(skb)->vcc)->close_wait); } td->dev->ntxpckts--; @@ -1123,7 +1123,7 @@ static void fs_close(struct atm_vcc *atm_vcc) this sleep_on, we'll lose any reference to these packets. Memory leak! On the other hand, it's awfully convenient that we can abort a "close" that is taking too long. Maybe just use non-interruptible sleep on? -- REW */ - interruptible_sleep_on (& vcc->close_wait); + wait_event_interruptible(vcc->close_wait, !vcc->last_skb); } txtp = &atm_vcc->qos.txtp; diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index 9587e959ce1a..9988ac98b6d8 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -639,9 +639,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev) card->hbnr.init = NUM_HB; card->hbnr.max = MAX_HB; - card->sm_handle = 0x00000000; + card->sm_handle = NULL; card->sm_addr = 0x00000000; - card->lg_handle = 0x00000000; + card->lg_handle = NULL; card->lg_addr = 0x00000000; card->efbie = 1; /* To prevent push_rxbufs from enabling the interrupt */ @@ -979,7 +979,7 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb) addr2 = card->sm_addr; handle2 = card->sm_handle; card->sm_addr = 0x00000000; - card->sm_handle = 0x00000000; + card->sm_handle = NULL; } else { /* (!sm_addr) */ card->sm_addr = addr1; @@ -993,7 +993,7 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb) addr2 = card->lg_addr; handle2 = card->lg_handle; card->lg_addr = 0x00000000; - card->lg_handle = 0x00000000; + card->lg_handle = NULL; } else { /* (!lg_addr) */ card->lg_addr = addr1; @@ -1739,10 +1739,10 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, } scq->full = 1; - spin_unlock_irqrestore(&scq->lock, flags); - interruptible_sleep_on_timeout(&scq->scqfull_waitq, - SCQFULL_TIMEOUT); - spin_lock_irqsave(&scq->lock, flags); + wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, + scq->tail != scq->next, + scq->lock, + SCQFULL_TIMEOUT); if (scq->full) { spin_unlock_irqrestore(&scq->lock, flags); @@ -1789,10 +1789,10 @@ static int push_scqe(ns_dev * card, vc_map * vc, scq_info * scq, ns_scqe * tbd, scq->full = 1; if (has_run++) break; - spin_unlock_irqrestore(&scq->lock, flags); - interruptible_sleep_on_timeout(&scq->scqfull_waitq, - SCQFULL_TIMEOUT); - spin_lock_irqsave(&scq->lock, flags); + wait_event_interruptible_lock_irq_timeout(scq->scqfull_waitq, + scq->tail != scq->next, + scq->lock, + SCQFULL_TIMEOUT); } if (!scq->full) { diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c index e3fb496c7163..943cf0d6abaf 100644 --- a/drivers/atm/solos-pci.c +++ b/drivers/atm/solos-pci.c @@ -760,7 +760,7 @@ static irqreturn_t solos_irq(int irq, void *dev_id) return IRQ_RETVAL(handled); } -void solos_bh(unsigned long card_arg) +static void solos_bh(unsigned long card_arg) { struct solos_card *card = (void *)card_arg; uint32_t card_flags; diff --git a/drivers/base/component.c b/drivers/base/component.c index c53efe6c6d8e..c4778995cd72 100644 --- a/drivers/base/component.c +++ b/drivers/base/component.c @@ -133,9 +133,16 @@ static int try_to_bring_up_master(struct master *master, goto out; } + if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) { + ret = -ENOMEM; + goto out; + } + /* Found all components */ ret = master->ops->bind(master->dev); if (ret < 0) { + devres_release_group(master->dev, NULL); + dev_info(master->dev, "master bind failed: %d\n", ret); master_remove_components(master); goto out; } @@ -166,6 +173,7 @@ static void take_down_master(struct master *master) { if (master->bound) { master->ops->unbind(master->dev); + devres_release_group(master->dev, NULL); master->bound = false; } diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c index 1e16cbd61da2..61d6d62cc0d3 100644 --- a/drivers/base/dma-buf.c +++ b/drivers/base/dma-buf.c @@ -616,36 +616,35 @@ static int dma_buf_describe(struct seq_file *s) if (ret) return ret; - seq_printf(s, "\nDma-buf Objects:\n"); - seq_printf(s, "\texp_name\tsize\tflags\tmode\tcount\n"); + seq_puts(s, "\nDma-buf Objects:\n"); + seq_puts(s, "size\tflags\tmode\tcount\texp_name\n"); list_for_each_entry(buf_obj, &db_list.head, list_node) { ret = mutex_lock_interruptible(&buf_obj->lock); if (ret) { - seq_printf(s, - "\tERROR locking buffer object: skipping\n"); + seq_puts(s, + "\tERROR locking buffer object: skipping\n"); continue; } - seq_printf(s, "\t"); - - seq_printf(s, "\t%s\t%08zu\t%08x\t%08x\t%08ld\n", - buf_obj->exp_name, buf_obj->size, + seq_printf(s, "%08zu\t%08x\t%08x\t%08ld\t%s\n", + buf_obj->size, buf_obj->file->f_flags, buf_obj->file->f_mode, - (long)(buf_obj->file->f_count.counter)); + (long)(buf_obj->file->f_count.counter), + buf_obj->exp_name); - seq_printf(s, "\t\tAttached Devices:\n"); + seq_puts(s, "\tAttached Devices:\n"); attach_count = 0; list_for_each_entry(attach_obj, &buf_obj->attachments, node) { - seq_printf(s, "\t\t"); + seq_puts(s, "\t"); - seq_printf(s, "%s\n", attach_obj->dev->init_name); + seq_printf(s, "%s\n", dev_name(attach_obj->dev)); attach_count++; } - seq_printf(s, "\n\t\tTotal %d devices attached\n", + seq_printf(s, "Total %d devices attached\n\n", attach_count); count++; diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 8a97ddfa6122..c30df50e4440 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -1580,6 +1580,7 @@ static int fw_pm_notify(struct notifier_block *notify_block, switch (mode) { case PM_HIBERNATION_PREPARE: case PM_SUSPEND_PREPARE: + case PM_RESTORE_PREPARE: kill_requests_without_uevent(); device_cache_fw_images(); break; diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 8184451b57c0..422b7d84f686 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -874,7 +874,7 @@ bio_pageinc(struct bio *bio) /* Non-zero page count for non-head members of * compound pages is no longer allowed by the kernel. */ - page = compound_trans_head(bv.bv_page); + page = compound_head(bv.bv_page); atomic_inc(&page->_count); } } @@ -887,7 +887,7 @@ bio_pagedec(struct bio *bio) struct bvec_iter iter; bio_for_each_segment(bv, bio, iter) { - page = compound_trans_head(bv.bv_page); + page = compound_head(bv.bv_page); atomic_dec(&page->_count); } } diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c index 3107282a9741..091b9ea14feb 100644 --- a/drivers/block/null_blk.c +++ b/drivers/block/null_blk.c @@ -60,7 +60,9 @@ enum { NULL_IRQ_NONE = 0, NULL_IRQ_SOFTIRQ = 1, NULL_IRQ_TIMER = 2, +}; +enum { NULL_Q_BIO = 0, NULL_Q_RQ = 1, NULL_Q_MQ = 2, @@ -172,18 +174,20 @@ static struct nullb_cmd *alloc_cmd(struct nullb_queue *nq, int can_wait) static void end_cmd(struct nullb_cmd *cmd) { - if (cmd->rq) { - if (queue_mode == NULL_Q_MQ) - blk_mq_end_io(cmd->rq, 0); - else { - INIT_LIST_HEAD(&cmd->rq->queuelist); - blk_end_request_all(cmd->rq, 0); - } - } else if (cmd->bio) + switch (queue_mode) { + case NULL_Q_MQ: + blk_mq_end_io(cmd->rq, 0); + return; + case NULL_Q_RQ: + INIT_LIST_HEAD(&cmd->rq->queuelist); + blk_end_request_all(cmd->rq, 0); + break; + case NULL_Q_BIO: bio_endio(cmd->bio, 0); + break; + } - if (queue_mode != NULL_Q_MQ) - free_cmd(cmd); + free_cmd(cmd); } static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) @@ -195,6 +199,7 @@ static enum hrtimer_restart null_cmd_timer_expired(struct hrtimer *timer) cq = &per_cpu(completion_queues, smp_processor_id()); while ((entry = llist_del_all(&cq->list)) != NULL) { + entry = llist_reverse_order(entry); do { cmd = container_of(entry, struct nullb_cmd, ll_list); end_cmd(cmd); @@ -221,61 +226,31 @@ static void null_cmd_end_timer(struct nullb_cmd *cmd) static void null_softirq_done_fn(struct request *rq) { - blk_end_request_all(rq, 0); -} - -#ifdef CONFIG_SMP - -static void null_ipi_cmd_end_io(void *data) -{ - struct completion_queue *cq; - struct llist_node *entry, *next; - struct nullb_cmd *cmd; - - cq = &per_cpu(completion_queues, smp_processor_id()); - - entry = llist_del_all(&cq->list); - - while (entry) { - next = entry->next; - cmd = llist_entry(entry, struct nullb_cmd, ll_list); - end_cmd(cmd); - entry = next; - } -} - -static void null_cmd_end_ipi(struct nullb_cmd *cmd) -{ - struct call_single_data *data = &cmd->csd; - int cpu = get_cpu(); - struct completion_queue *cq = &per_cpu(completion_queues, cpu); - - cmd->ll_list.next = NULL; - - if (llist_add(&cmd->ll_list, &cq->list)) { - data->func = null_ipi_cmd_end_io; - data->flags = 0; - __smp_call_function_single(cpu, data, 0); - } - - put_cpu(); + end_cmd(rq->special); } -#endif /* CONFIG_SMP */ - static inline void null_handle_cmd(struct nullb_cmd *cmd) { /* Complete IO by inline, softirq or timer */ switch (irqmode) { - case NULL_IRQ_NONE: - end_cmd(cmd); - break; case NULL_IRQ_SOFTIRQ: -#ifdef CONFIG_SMP - null_cmd_end_ipi(cmd); -#else + switch (queue_mode) { + case NULL_Q_MQ: + blk_mq_complete_request(cmd->rq); + break; + case NULL_Q_RQ: + blk_complete_request(cmd->rq); + break; + case NULL_Q_BIO: + /* + * XXX: no proper submitting cpu information available. + */ + end_cmd(cmd); + break; + } + break; + case NULL_IRQ_NONE: end_cmd(cmd); -#endif break; case NULL_IRQ_TIMER: null_cmd_end_timer(cmd); @@ -411,6 +386,7 @@ static struct blk_mq_ops null_mq_ops = { .queue_rq = null_queue_rq, .map_queue = blk_mq_map_queue, .init_hctx = null_init_hctx, + .complete = null_softirq_done_fn, }; static struct blk_mq_reg null_mq_reg = { @@ -609,13 +585,6 @@ static int __init null_init(void) { unsigned int i; -#if !defined(CONFIG_SMP) - if (irqmode == NULL_IRQ_SOFTIRQ) { - pr_warn("null_blk: softirq completions not available.\n"); - pr_warn("null_blk: using direct completions.\n"); - irqmode = NULL_IRQ_NONE; - } -#endif if (bs > PAGE_SIZE) { pr_warn("null_blk: invalid block size\n"); pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 6a680d4de7f1..b1cb3f4c4db4 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -110,9 +110,9 @@ static int __virtblk_add_req(struct virtqueue *vq, return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); } -static inline void virtblk_request_done(struct virtblk_req *vbr) +static inline void virtblk_request_done(struct request *req) { - struct request *req = vbr->req; + struct virtblk_req *vbr = req->special; int error = virtblk_result(vbr); if (req->cmd_type == REQ_TYPE_BLOCK_PC) { @@ -138,7 +138,7 @@ static void virtblk_done(struct virtqueue *vq) do { virtqueue_disable_cb(vq); while ((vbr = virtqueue_get_buf(vblk->vq, &len)) != NULL) { - virtblk_request_done(vbr); + blk_mq_complete_request(vbr->req); req_done = true; } if (unlikely(virtqueue_is_broken(vq))) @@ -479,6 +479,7 @@ static struct blk_mq_ops virtio_mq_ops = { .map_queue = blk_mq_map_queue, .alloc_hctx = blk_mq_alloc_single_hw_queue, .free_hctx = blk_mq_free_single_hw_queue, + .complete = virtblk_request_done, }; static struct blk_mq_reg virtio_mq_reg = { diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index 4b97b86da926..64c60edcdfbc 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -299,7 +299,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root, BUG_ON(num != 0); } -static void unmap_purged_grants(struct work_struct *work) +void xen_blkbk_unmap_purged_grants(struct work_struct *work) { struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST]; struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST]; @@ -375,7 +375,7 @@ static void purge_persistent_gnt(struct xen_blkif *blkif) pr_debug(DRV_PFX "Going to purge %u persistent grants\n", num_clean); - INIT_LIST_HEAD(&blkif->persistent_purge_list); + BUG_ON(!list_empty(&blkif->persistent_purge_list)); root = &blkif->persistent_gnts; purge_list: foreach_grant_safe(persistent_gnt, n, root, node) { @@ -420,7 +420,6 @@ finished: blkif->vbd.overflow_max_grants = 0; /* We can defer this work */ - INIT_WORK(&blkif->persistent_purge_work, unmap_purged_grants); schedule_work(&blkif->persistent_purge_work); pr_debug(DRV_PFX "Purged %u/%u\n", (total - num_clean), total); return; @@ -625,9 +624,23 @@ purge_gnt_list: print_stats(blkif); } - /* Since we are shutting down remove all pages from the buffer */ - shrink_free_pagepool(blkif, 0 /* All */); + /* Drain pending purge work */ + flush_work(&blkif->persistent_purge_work); + if (log_stats) + print_stats(blkif); + + blkif->xenblkd = NULL; + xen_blkif_put(blkif); + + return 0; +} + +/* + * Remove persistent grants and empty the pool of free pages + */ +void xen_blkbk_free_caches(struct xen_blkif *blkif) +{ /* Free all persistent grant pages */ if (!RB_EMPTY_ROOT(&blkif->persistent_gnts)) free_persistent_gnts(blkif, &blkif->persistent_gnts, @@ -636,13 +649,8 @@ purge_gnt_list: BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts)); blkif->persistent_gnt_c = 0; - if (log_stats) - print_stats(blkif); - - blkif->xenblkd = NULL; - xen_blkif_put(blkif); - - return 0; + /* Since we are shutting down remove all pages from the buffer */ + shrink_free_pagepool(blkif, 0 /* All */); } /* @@ -838,7 +846,7 @@ static int xen_blkbk_parse_indirect(struct blkif_request *req, struct grant_page **pages = pending_req->indirect_pages; struct xen_blkif *blkif = pending_req->blkif; int indirect_grefs, rc, n, nseg, i; - struct blkif_request_segment_aligned *segments = NULL; + struct blkif_request_segment *segments = NULL; nseg = pending_req->nr_pages; indirect_grefs = INDIRECT_PAGES(nseg); @@ -934,9 +942,7 @@ static void xen_blk_drain_io(struct xen_blkif *blkif) { atomic_set(&blkif->drain, 1); do { - /* The initial value is one, and one refcnt taken at the - * start of the xen_blkif_schedule thread. */ - if (atomic_read(&blkif->refcnt) <= 2) + if (atomic_read(&blkif->inflight) == 0) break; wait_for_completion_interruptible_timeout( &blkif->drain_complete, HZ); @@ -976,17 +982,30 @@ static void __end_block_io_op(struct pending_req *pending_req, int error) * the proper response on the ring. */ if (atomic_dec_and_test(&pending_req->pendcnt)) { - xen_blkbk_unmap(pending_req->blkif, + struct xen_blkif *blkif = pending_req->blkif; + + xen_blkbk_unmap(blkif, pending_req->segments, pending_req->nr_pages); - make_response(pending_req->blkif, pending_req->id, + make_response(blkif, pending_req->id, pending_req->operation, pending_req->status); - xen_blkif_put(pending_req->blkif); - if (atomic_read(&pending_req->blkif->refcnt) <= 2) { - if (atomic_read(&pending_req->blkif->drain)) - complete(&pending_req->blkif->drain_complete); + free_req(blkif, pending_req); + /* + * Make sure the request is freed before releasing blkif, + * or there could be a race between free_req and the + * cleanup done in xen_blkif_free during shutdown. + * + * NB: The fact that we might try to wake up pending_free_wq + * before drain_complete (in case there's a drain going on) + * it's not a problem with our current implementation + * because we can assure there's no thread waiting on + * pending_free_wq if there's a drain going on, but it has + * to be taken into account if the current model is changed. + */ + if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) { + complete(&blkif->drain_complete); } - free_req(pending_req->blkif, pending_req); + xen_blkif_put(blkif); } } @@ -1240,6 +1259,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif, * below (in "!bio") if we are handling a BLKIF_OP_DISCARD. */ xen_blkif_get(blkif); + atomic_inc(&blkif->inflight); for (i = 0; i < nseg; i++) { while ((bio == NULL) || diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h index 8d8807563d99..be052773ad03 100644 --- a/drivers/block/xen-blkback/common.h +++ b/drivers/block/xen-blkback/common.h @@ -57,7 +57,7 @@ #define MAX_INDIRECT_SEGMENTS 256 #define SEGS_PER_INDIRECT_FRAME \ - (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned)) + (PAGE_SIZE/sizeof(struct blkif_request_segment)) #define MAX_INDIRECT_PAGES \ ((MAX_INDIRECT_SEGMENTS + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) #define INDIRECT_PAGES(_segs) \ @@ -278,6 +278,7 @@ struct xen_blkif { /* for barrier (drain) requests */ struct completion drain_complete; atomic_t drain; + atomic_t inflight; /* One thread per one blkif. */ struct task_struct *xenblkd; unsigned int waiting_reqs; @@ -376,6 +377,7 @@ int xen_blkif_xenbus_init(void); irqreturn_t xen_blkif_be_int(int irq, void *dev_id); int xen_blkif_schedule(void *arg); int xen_blkif_purge_persistent(void *arg); +void xen_blkbk_free_caches(struct xen_blkif *blkif); int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, struct backend_info *be, int state); @@ -383,6 +385,7 @@ int xen_blkbk_flush_diskcache(struct xenbus_transaction xbt, int xen_blkbk_barrier(struct xenbus_transaction xbt, struct backend_info *be, int state); struct xenbus_device *xen_blkbk_xenbus(struct backend_info *be); +void xen_blkbk_unmap_purged_grants(struct work_struct *work); static inline void blkif_get_x86_32_req(struct blkif_request *dst, struct blkif_x86_32_request *src) diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index c2014a0aa206..9a547e6b6ebf 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -125,8 +125,11 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) blkif->persistent_gnts.rb_node = NULL; spin_lock_init(&blkif->free_pages_lock); INIT_LIST_HEAD(&blkif->free_pages); + INIT_LIST_HEAD(&blkif->persistent_purge_list); blkif->free_pages_num = 0; atomic_set(&blkif->persistent_gnt_in_use, 0); + atomic_set(&blkif->inflight, 0); + INIT_WORK(&blkif->persistent_purge_work, xen_blkbk_unmap_purged_grants); INIT_LIST_HEAD(&blkif->pending_free); @@ -259,6 +262,17 @@ static void xen_blkif_free(struct xen_blkif *blkif) if (!atomic_dec_and_test(&blkif->refcnt)) BUG(); + /* Remove all persistent grants and the cache of ballooned pages. */ + xen_blkbk_free_caches(blkif); + + /* Make sure everything is drained before shutting down */ + BUG_ON(blkif->persistent_gnt_c != 0); + BUG_ON(atomic_read(&blkif->persistent_gnt_in_use) != 0); + BUG_ON(blkif->free_pages_num != 0); + BUG_ON(!list_empty(&blkif->persistent_purge_list)); + BUG_ON(!list_empty(&blkif->free_pages)); + BUG_ON(!RB_EMPTY_ROOT(&blkif->persistent_gnts)); + /* Check that there is no request in use */ list_for_each_entry_safe(req, n, &blkif->pending_free, free_list) { list_del(&req->free_list); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 8dcfb54f1603..efe1b4761735 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -162,7 +162,7 @@ static DEFINE_SPINLOCK(minor_lock); #define DEV_NAME "xvd" /* name in /dev */ #define SEGS_PER_INDIRECT_FRAME \ - (PAGE_SIZE/sizeof(struct blkif_request_segment_aligned)) + (PAGE_SIZE/sizeof(struct blkif_request_segment)) #define INDIRECT_GREFS(_segs) \ ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) @@ -393,7 +393,7 @@ static int blkif_queue_request(struct request *req) unsigned long id; unsigned int fsect, lsect; int i, ref, n; - struct blkif_request_segment_aligned *segments = NULL; + struct blkif_request_segment *segments = NULL; /* * Used to store if we are able to queue the request by just using @@ -550,7 +550,7 @@ static int blkif_queue_request(struct request *req) } else { n = i % SEGS_PER_INDIRECT_FRAME; segments[n] = - (struct blkif_request_segment_aligned) { + (struct blkif_request_segment) { .gref = ref, .first_sect = fsect, .last_sect = lsect }; @@ -1904,13 +1904,16 @@ static void blkback_changed(struct xenbus_device *dev, case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateConnected: blkfront_connect(info); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's Closing state -- fallthrough */ case XenbusStateClosing: blkfront_closing(info); break; diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 011e55d820b1..51c557cfd92b 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -612,6 +612,8 @@ static ssize_t disksize_store(struct device *dev, disksize = PAGE_ALIGN(disksize); meta = zram_meta_alloc(disksize); + if (!meta) + return -ENOMEM; down_write(&zram->init_lock); if (zram->init_done) { up_write(&zram->init_lock); diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index fa3243d71c76..1386749b48ff 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -499,6 +499,7 @@ config RAW_DRIVER config MAX_RAW_DEVS int "Maximum number of RAW devices to support (1-65536)" depends on RAW_DRIVER + range 1 65536 default "256" help The maximum number of RAW devices that are supported. diff --git a/drivers/char/raw.c b/drivers/char/raw.c index f3223aac4df1..6e8d65e9b1d3 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -190,7 +190,7 @@ static int bind_get(int number, dev_t *dev) struct raw_device_data *rawdev; struct block_device *bdev; - if (number <= 0 || number >= MAX_RAW_MINORS) + if (number <= 0 || number >= max_raw_minors) return -EINVAL; rawdev = &raw_devices[number]; diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c index bd313f7816a8..c1af80bcdf20 100644 --- a/drivers/clk/at91/clk-master.c +++ b/drivers/clk/at91/clk-master.c @@ -242,7 +242,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, irq = irq_of_parse_and_map(np, 0); if (!irq) - return; + goto out_free_characteristics; clk = at91_clk_register_master(pmc, irq, name, num_parents, parent_names, layout, diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c index 6a934a5296bd..05e04ce0f148 100644 --- a/drivers/clk/clk-nomadik.c +++ b/drivers/clk/clk-nomadik.c @@ -494,6 +494,9 @@ static const struct file_operations nomadik_src_clk_debugfs_ops = { static int __init nomadik_src_clk_init_debugfs(void) { + /* Vital for multiplatform */ + if (!src_base) + return -ENODEV; src_pcksr0_boot = readl(src_base + SRC_PCKSR0); src_pcksr1_boot = readl(src_base + SRC_PCKSR1); debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO, diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 5517944495d8..c42e608af6bb 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2226,24 +2226,25 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister); */ int __clk_get(struct clk *clk) { - if (clk && !try_module_get(clk->owner)) - return 0; + if (clk) { + if (!try_module_get(clk->owner)) + return 0; - kref_get(&clk->ref); + kref_get(&clk->ref); + } return 1; } void __clk_put(struct clk *clk) { - if (WARN_ON_ONCE(IS_ERR(clk))) + if (!clk || WARN_ON_ONCE(IS_ERR(clk))) return; clk_prepare_lock(); kref_put(&clk->ref, __clk_release); clk_prepare_unlock(); - if (clk) - module_put(clk->owner); + module_put(clk->owner); } /*** clk rate change notifiers ***/ diff --git a/drivers/clk/keystone/gate.c b/drivers/clk/keystone/gate.c index 17a598398a53..86f1e362eafb 100644 --- a/drivers/clk/keystone/gate.c +++ b/drivers/clk/keystone/gate.c @@ -179,6 +179,7 @@ static struct clk *clk_register_psc(struct device *dev, init.name = name; init.ops = &clk_psc_ops; + init.flags = 0; init.parent_names = (parent_name ? &parent_name : NULL); init.num_parents = (parent_name ? 1 : 0); diff --git a/drivers/clk/mvebu/armada-370.c b/drivers/clk/mvebu/armada-370.c index 81a202d12a7a..bef198a83863 100644 --- a/drivers/clk/mvebu/armada-370.c +++ b/drivers/clk/mvebu/armada-370.c @@ -141,13 +141,6 @@ static const struct coreclk_soc_desc a370_coreclks = { .num_ratios = ARRAY_SIZE(a370_coreclk_ratios), }; -static void __init a370_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &a370_coreclks); -} -CLK_OF_DECLARE(a370_core_clk, "marvell,armada-370-core-clock", - a370_coreclk_init); - /* * Clock Gating Control */ @@ -168,9 +161,15 @@ static const struct clk_gating_soc_desc a370_gating_desc[] __initconst = { { } }; -static void __init a370_clk_gating_init(struct device_node *np) +static void __init a370_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, a370_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,armada-370-gating-clock"); + + mvebu_coreclk_setup(np, &a370_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, a370_gating_desc); } -CLK_OF_DECLARE(a370_clk_gating, "marvell,armada-370-gating-clock", - a370_clk_gating_init); +CLK_OF_DECLARE(a370_clk, "marvell,armada-370-core-clock", a370_clk_init); + diff --git a/drivers/clk/mvebu/armada-xp.c b/drivers/clk/mvebu/armada-xp.c index 9922c4475aa8..b3094315a3c0 100644 --- a/drivers/clk/mvebu/armada-xp.c +++ b/drivers/clk/mvebu/armada-xp.c @@ -158,13 +158,6 @@ static const struct coreclk_soc_desc axp_coreclks = { .num_ratios = ARRAY_SIZE(axp_coreclk_ratios), }; -static void __init axp_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &axp_coreclks); -} -CLK_OF_DECLARE(axp_core_clk, "marvell,armada-xp-core-clock", - axp_coreclk_init); - /* * Clock Gating Control */ @@ -202,9 +195,14 @@ static const struct clk_gating_soc_desc axp_gating_desc[] __initconst = { { } }; -static void __init axp_clk_gating_init(struct device_node *np) +static void __init axp_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, axp_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,armada-xp-gating-clock"); + + mvebu_coreclk_setup(np, &axp_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, axp_gating_desc); } -CLK_OF_DECLARE(axp_clk_gating, "marvell,armada-xp-gating-clock", - axp_clk_gating_init); +CLK_OF_DECLARE(axp_clk, "marvell,armada-xp-core-clock", axp_clk_init); diff --git a/drivers/clk/mvebu/dove.c b/drivers/clk/mvebu/dove.c index 38aee1e3f242..b8c2424ac926 100644 --- a/drivers/clk/mvebu/dove.c +++ b/drivers/clk/mvebu/dove.c @@ -154,12 +154,6 @@ static const struct coreclk_soc_desc dove_coreclks = { .num_ratios = ARRAY_SIZE(dove_coreclk_ratios), }; -static void __init dove_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &dove_coreclks); -} -CLK_OF_DECLARE(dove_core_clk, "marvell,dove-core-clock", dove_coreclk_init); - /* * Clock Gating Control */ @@ -186,9 +180,14 @@ static const struct clk_gating_soc_desc dove_gating_desc[] __initconst = { { } }; -static void __init dove_clk_gating_init(struct device_node *np) +static void __init dove_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, dove_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,dove-gating-clock"); + + mvebu_coreclk_setup(np, &dove_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, dove_gating_desc); } -CLK_OF_DECLARE(dove_clk_gating, "marvell,dove-gating-clock", - dove_clk_gating_init); +CLK_OF_DECLARE(dove_clk, "marvell,dove-core-clock", dove_clk_init); diff --git a/drivers/clk/mvebu/kirkwood.c b/drivers/clk/mvebu/kirkwood.c index 2636a55f29f9..ddb666a86500 100644 --- a/drivers/clk/mvebu/kirkwood.c +++ b/drivers/clk/mvebu/kirkwood.c @@ -193,13 +193,6 @@ static const struct coreclk_soc_desc kirkwood_coreclks = { .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), }; -static void __init kirkwood_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &kirkwood_coreclks); -} -CLK_OF_DECLARE(kirkwood_core_clk, "marvell,kirkwood-core-clock", - kirkwood_coreclk_init); - static const struct coreclk_soc_desc mv88f6180_coreclks = { .get_tclk_freq = kirkwood_get_tclk_freq, .get_cpu_freq = mv88f6180_get_cpu_freq, @@ -208,13 +201,6 @@ static const struct coreclk_soc_desc mv88f6180_coreclks = { .num_ratios = ARRAY_SIZE(kirkwood_coreclk_ratios), }; -static void __init mv88f6180_coreclk_init(struct device_node *np) -{ - mvebu_coreclk_setup(np, &mv88f6180_coreclks); -} -CLK_OF_DECLARE(mv88f6180_core_clk, "marvell,mv88f6180-core-clock", - mv88f6180_coreclk_init); - /* * Clock Gating Control */ @@ -239,9 +225,21 @@ static const struct clk_gating_soc_desc kirkwood_gating_desc[] __initconst = { { } }; -static void __init kirkwood_clk_gating_init(struct device_node *np) +static void __init kirkwood_clk_init(struct device_node *np) { - mvebu_clk_gating_setup(np, kirkwood_gating_desc); + struct device_node *cgnp = + of_find_compatible_node(NULL, NULL, "marvell,kirkwood-gating-clock"); + + + if (of_device_is_compatible(np, "marvell,mv88f6180-core-clock")) + mvebu_coreclk_setup(np, &mv88f6180_coreclks); + else + mvebu_coreclk_setup(np, &kirkwood_coreclks); + + if (cgnp) + mvebu_clk_gating_setup(cgnp, kirkwood_gating_desc); } -CLK_OF_DECLARE(kirkwood_clk_gating, "marvell,kirkwood-gating-clock", - kirkwood_clk_gating_init); +CLK_OF_DECLARE(kirkwood_clk, "marvell,kirkwood-core-clock", + kirkwood_clk_init); +CLK_OF_DECLARE(mv88f6180_clk, "marvell,mv88f6180-core-clock", + kirkwood_clk_init); diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c index a59ec217a124..dd272a0d1446 100644 --- a/drivers/clk/shmobile/clk-rcar-gen2.c +++ b/drivers/clk/shmobile/clk-rcar-gen2.c @@ -186,7 +186,7 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, const char *name) { const struct clk_div_table *table = NULL; - const char *parent_name = "main"; + const char *parent_name; unsigned int shift; unsigned int mult = 1; unsigned int div = 1; @@ -201,23 +201,31 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg, * the multiplier value. */ u32 value = clk_readl(cpg->reg + CPG_PLL0CR); + parent_name = "main"; mult = ((value >> 24) & ((1 << 7) - 1)) + 1; } else if (!strcmp(name, "pll1")) { + parent_name = "main"; mult = config->pll1_mult / 2; } else if (!strcmp(name, "pll3")) { + parent_name = "main"; mult = config->pll3_mult; } else if (!strcmp(name, "lb")) { + parent_name = "pll1_div2"; div = cpg_mode & BIT(18) ? 36 : 24; } else if (!strcmp(name, "qspi")) { + parent_name = "pll1_div2"; div = (cpg_mode & (BIT(3) | BIT(2) | BIT(1))) == BIT(2) - ? 16 : 20; + ? 8 : 10; } else if (!strcmp(name, "sdh")) { + parent_name = "pll1_div2"; table = cpg_sdh_div_table; shift = 8; } else if (!strcmp(name, "sd0")) { + parent_name = "pll1_div2"; table = cpg_sd01_div_table; shift = 4; } else if (!strcmp(name, "sd1")) { + parent_name = "pll1_div2"; table = cpg_sd01_div_table; shift = 0; } else if (!strcmp(name, "z")) { diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c index 4d75b1f37e3a..290f9c1a3749 100644 --- a/drivers/clk/tegra/clk-divider.c +++ b/drivers/clk/tegra/clk-divider.c @@ -59,7 +59,7 @@ static int get_div(struct tegra_clk_frac_div *divider, unsigned long rate, return 0; if (divider_ux1 > get_max_div(divider)) - return -EINVAL; + return get_max_div(divider); return divider_ux1; } diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index cf0c323f2c36..c39613c519af 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -180,9 +180,13 @@ enum clk_id { tegra_clk_sbc6_8, tegra_clk_sclk, tegra_clk_sdmmc1, + tegra_clk_sdmmc1_8, tegra_clk_sdmmc2, + tegra_clk_sdmmc2_8, tegra_clk_sdmmc3, + tegra_clk_sdmmc3_8, tegra_clk_sdmmc4, + tegra_clk_sdmmc4_8, tegra_clk_se, tegra_clk_soc_therm, tegra_clk_sor0, diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 5c35885f4a7c..1fa5c3f33b20 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -371,9 +371,7 @@ static const char *mux_pllp3_pllc_clkm[] = { static const char *mux_pllm_pllc_pllp_plla_pllc2_c3_clkm[] = { "pll_m", "pll_c", "pll_p", "pll_a", "pll_c2", "pll_c3", "clk_m" }; -static u32 mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx[] = { - [0] = 0, [1] = 1, [2] = 2, [3] = 3, [4] = 4, [5] = 6, -}; +#define mux_pllm_pllc_pllp_plla_pllc2_c3_clkm_idx NULL static const char *mux_pllm_pllc2_c_c3_pllp_plla_pllc4[] = { "pll_m", "pll_c2", "pll_c", "pll_c3", "pll_p", "pll_a_out0", "pll_c4", @@ -465,6 +463,10 @@ static struct tegra_periph_init_data periph_clks[] = { MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1), MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1), MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 20, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2), + MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8), + MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8), + MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8), + MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8), MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8), MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8), MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8), @@ -492,7 +494,7 @@ static struct tegra_periph_init_data periph_clks[] = { UART("uartb", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTB, 7, tegra_clk_uartb), UART("uartc", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTC, 55, tegra_clk_uartc), UART("uartd", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTD, 65, tegra_clk_uartd), - UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 65, tegra_clk_uarte), + UART("uarte", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_UARTE, 66, tegra_clk_uarte), XUSB("xusb_host_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_host_src), XUSB("xusb_falcon_src", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_falcon_src), XUSB("xusb_fs_src", mux_clkm_48M_pllp_480M, CLK_SOURCE_XUSB_FS_SRC, 143, TEGRA_PERIPH_NO_RESET, tegra_clk_xusb_fs_src), diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 05dce4aa2c11..feb3201c85ce 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -120,7 +120,7 @@ void __init tegra_super_clk_gen4_init(void __iomem *clk_base, ARRAY_SIZE(cclk_lp_parents), CLK_SET_RATE_PARENT, clk_base + CCLKLP_BURST_POLICY, - 0, 4, 8, 9, NULL); + TEGRA_DIVIDER_2, 4, 8, 9, NULL); *dt_clk = clk; } diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index 90d9d25f2228..80431f0fb268 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -682,12 +682,12 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_timer] = { .dt_id = TEGRA114_CLK_TIMER, .present = true }, [tegra_clk_uarta] = { .dt_id = TEGRA114_CLK_UARTA, .present = true }, [tegra_clk_uartd] = { .dt_id = TEGRA114_CLK_UARTD, .present = true }, - [tegra_clk_sdmmc2] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true }, + [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA114_CLK_SDMMC2, .present = true }, [tegra_clk_i2s1] = { .dt_id = TEGRA114_CLK_I2S1, .present = true }, [tegra_clk_i2c1] = { .dt_id = TEGRA114_CLK_I2C1, .present = true }, [tegra_clk_ndflash] = { .dt_id = TEGRA114_CLK_NDFLASH, .present = true }, - [tegra_clk_sdmmc1] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true }, - [tegra_clk_sdmmc4] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true }, + [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA114_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA114_CLK_SDMMC4, .present = true }, [tegra_clk_pwm] = { .dt_id = TEGRA114_CLK_PWM, .present = true }, [tegra_clk_i2s0] = { .dt_id = TEGRA114_CLK_I2S0, .present = true }, [tegra_clk_i2s2] = { .dt_id = TEGRA114_CLK_I2S2, .present = true }, @@ -723,7 +723,7 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = { [tegra_clk_bsev] = { .dt_id = TEGRA114_CLK_BSEV, .present = true }, [tegra_clk_i2c3] = { .dt_id = TEGRA114_CLK_I2C3, .present = true }, [tegra_clk_sbc4_8] = { .dt_id = TEGRA114_CLK_SBC4, .present = true }, - [tegra_clk_sdmmc3] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true }, + [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA114_CLK_SDMMC3, .present = true }, [tegra_clk_owr] = { .dt_id = TEGRA114_CLK_OWR, .present = true }, [tegra_clk_csite] = { .dt_id = TEGRA114_CLK_CSITE, .present = true }, [tegra_clk_la] = { .dt_id = TEGRA114_CLK_LA, .present = true }, diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index aff86b5bc745..166e02f16c8a 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -516,11 +516,11 @@ static struct div_nmp pllp_nmp = { }; static struct tegra_clk_pll_freq_table pll_p_freq_table[] = { - {12000000, 216000000, 432, 12, 1, 8}, - {13000000, 216000000, 432, 13, 1, 8}, - {16800000, 216000000, 360, 14, 1, 8}, - {19200000, 216000000, 360, 16, 1, 8}, - {26000000, 216000000, 432, 26, 1, 8}, + {12000000, 408000000, 408, 12, 0, 8}, + {13000000, 408000000, 408, 13, 0, 8}, + {16800000, 408000000, 340, 14, 0, 8}, + {19200000, 408000000, 340, 16, 0, 8}, + {26000000, 408000000, 408, 26, 0, 8}, {0, 0, 0, 0, 0, 0}, }; @@ -570,6 +570,15 @@ static struct tegra_clk_pll_params pll_a_params = { .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_USE_LOCK, }; +static struct div_nmp plld_nmp = { + .divm_shift = 0, + .divm_width = 5, + .divn_shift = 8, + .divn_width = 11, + .divp_shift = 20, + .divp_width = 3, +}; + static struct tegra_clk_pll_freq_table pll_d_freq_table[] = { {12000000, 216000000, 864, 12, 4, 12}, {13000000, 216000000, 864, 13, 4, 12}, @@ -603,19 +612,18 @@ static struct tegra_clk_pll_params pll_d_params = { .lock_mask = PLL_BASE_LOCK, .lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE, .lock_delay = 1000, - .div_nmp = &pllp_nmp, + .div_nmp = &plld_nmp, .freq_table = pll_d_freq_table, .flags = TEGRA_PLL_HAS_CPCON | TEGRA_PLL_SET_LFCON | TEGRA_PLL_USE_LOCK, }; static struct tegra_clk_pll_freq_table tegra124_pll_d2_freq_table[] = { - { 12000000, 148500000, 99, 1, 8}, - { 12000000, 594000000, 99, 1, 1}, - { 13000000, 594000000, 91, 1, 1}, /* actual: 591.5 MHz */ - { 16800000, 594000000, 71, 1, 1}, /* actual: 596.4 MHz */ - { 19200000, 594000000, 62, 1, 1}, /* actual: 595.2 MHz */ - { 26000000, 594000000, 91, 2, 1}, /* actual: 591.5 MHz */ + { 12000000, 594000000, 99, 1, 2}, + { 13000000, 594000000, 91, 1, 2}, /* actual: 591.5 MHz */ + { 16800000, 594000000, 71, 1, 2}, /* actual: 596.4 MHz */ + { 19200000, 594000000, 62, 1, 2}, /* actual: 595.2 MHz */ + { 26000000, 594000000, 91, 2, 2}, /* actual: 591.5 MHz */ { 0, 0, 0, 0, 0, 0 }, }; @@ -753,21 +761,19 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_rtc] = { .dt_id = TEGRA124_CLK_RTC, .present = true }, [tegra_clk_timer] = { .dt_id = TEGRA124_CLK_TIMER, .present = true }, [tegra_clk_uarta] = { .dt_id = TEGRA124_CLK_UARTA, .present = true }, - [tegra_clk_sdmmc2] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true }, + [tegra_clk_sdmmc2_8] = { .dt_id = TEGRA124_CLK_SDMMC2, .present = true }, [tegra_clk_i2s1] = { .dt_id = TEGRA124_CLK_I2S1, .present = true }, [tegra_clk_i2c1] = { .dt_id = TEGRA124_CLK_I2C1, .present = true }, [tegra_clk_ndflash] = { .dt_id = TEGRA124_CLK_NDFLASH, .present = true }, - [tegra_clk_sdmmc1] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true }, - [tegra_clk_sdmmc4] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true }, + [tegra_clk_sdmmc1_8] = { .dt_id = TEGRA124_CLK_SDMMC1, .present = true }, + [tegra_clk_sdmmc4_8] = { .dt_id = TEGRA124_CLK_SDMMC4, .present = true }, [tegra_clk_pwm] = { .dt_id = TEGRA124_CLK_PWM, .present = true }, [tegra_clk_i2s2] = { .dt_id = TEGRA124_CLK_I2S2, .present = true }, - [tegra_clk_gr2d] = { .dt_id = TEGRA124_CLK_GR_2D, .present = true }, [tegra_clk_usbd] = { .dt_id = TEGRA124_CLK_USBD, .present = true }, [tegra_clk_isp_8] = { .dt_id = TEGRA124_CLK_ISP, .present = true }, - [tegra_clk_gr3d] = { .dt_id = TEGRA124_CLK_GR_3D, .present = true }, [tegra_clk_disp2] = { .dt_id = TEGRA124_CLK_DISP2, .present = true }, [tegra_clk_disp1] = { .dt_id = TEGRA124_CLK_DISP1, .present = true }, - [tegra_clk_host1x] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true }, + [tegra_clk_host1x_8] = { .dt_id = TEGRA124_CLK_HOST1X, .present = true }, [tegra_clk_vcp] = { .dt_id = TEGRA124_CLK_VCP, .present = true }, [tegra_clk_i2s0] = { .dt_id = TEGRA124_CLK_I2S0, .present = true }, [tegra_clk_apbdma] = { .dt_id = TEGRA124_CLK_APBDMA, .present = true }, @@ -794,7 +800,7 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_uartd] = { .dt_id = TEGRA124_CLK_UARTD, .present = true }, [tegra_clk_i2c3] = { .dt_id = TEGRA124_CLK_I2C3, .present = true }, [tegra_clk_sbc4] = { .dt_id = TEGRA124_CLK_SBC4, .present = true }, - [tegra_clk_sdmmc3] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true }, + [tegra_clk_sdmmc3_8] = { .dt_id = TEGRA124_CLK_SDMMC3, .present = true }, [tegra_clk_pcie] = { .dt_id = TEGRA124_CLK_PCIE, .present = true }, [tegra_clk_owr] = { .dt_id = TEGRA124_CLK_OWR, .present = true }, [tegra_clk_afi] = { .dt_id = TEGRA124_CLK_AFI, .present = true }, @@ -1286,9 +1292,9 @@ static void __init tegra124_pll_init(void __iomem *clk_base, clk_register_clkdev(clk, "pll_d2", NULL); clks[TEGRA124_CLK_PLL_D2] = clk; - /* PLLD2_OUT0 ?? */ + /* PLLD2_OUT0 */ clk = clk_register_fixed_factor(NULL, "pll_d2_out0", "pll_d2", - CLK_SET_RATE_PARENT, 1, 2); + CLK_SET_RATE_PARENT, 1, 1); clk_register_clkdev(clk, "pll_d2_out0", NULL); clks[TEGRA124_CLK_PLL_D2_OUT0] = clk; diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index dbace152b2fa..dace2b1b5ae6 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -574,6 +574,8 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { [tegra_clk_tvdac] = { .dt_id = TEGRA20_CLK_TVDAC, .present = true }, [tegra_clk_vi_sensor] = { .dt_id = TEGRA20_CLK_VI_SENSOR, .present = true }, [tegra_clk_afi] = { .dt_id = TEGRA20_CLK_AFI, .present = true }, + [tegra_clk_fuse] = { .dt_id = TEGRA20_CLK_FUSE, .present = true }, + [tegra_clk_kfuse] = { .dt_id = TEGRA20_CLK_KFUSE, .present = true }, }; static unsigned long tegra20_clk_measure_input_freq(void) diff --git a/drivers/clocksource/bcm_kona_timer.c b/drivers/clocksource/bcm_kona_timer.c index 974b2db2fe10..0595dc6c453e 100644 --- a/drivers/clocksource/bcm_kona_timer.c +++ b/drivers/clocksource/bcm_kona_timer.c @@ -99,31 +99,6 @@ kona_timer_get_counter(void *timer_base, uint32_t *msw, uint32_t *lsw) return; } -static void __init kona_timers_init(struct device_node *node) -{ - u32 freq; - struct clk *external_clk; - - external_clk = of_clk_get_by_name(node, NULL); - - if (!IS_ERR(external_clk)) { - arch_timer_rate = clk_get_rate(external_clk); - clk_prepare_enable(external_clk); - } else if (!of_property_read_u32(node, "clock-frequency", &freq)) { - arch_timer_rate = freq; - } else { - panic("unable to determine clock-frequency"); - } - - /* Setup IRQ numbers */ - timers.tmr_irq = irq_of_parse_and_map(node, 0); - - /* Setup IO addresses */ - timers.tmr_regs = of_iomap(node, 0); - - kona_timer_disable_and_clear(timers.tmr_regs); -} - static int kona_timer_set_next_event(unsigned long clc, struct clock_event_device *unused) { @@ -198,7 +173,34 @@ static struct irqaction kona_timer_irq = { static void __init kona_timer_init(struct device_node *node) { - kona_timers_init(node); + u32 freq; + struct clk *external_clk; + + if (!of_device_is_available(node)) { + pr_info("Kona Timer v1 marked as disabled in device tree\n"); + return; + } + + external_clk = of_clk_get_by_name(node, NULL); + + if (!IS_ERR(external_clk)) { + arch_timer_rate = clk_get_rate(external_clk); + clk_prepare_enable(external_clk); + } else if (!of_property_read_u32(node, "clock-frequency", &freq)) { + arch_timer_rate = freq; + } else { + pr_err("Kona Timer v1 unable to determine clock-frequency"); + return; + } + + /* Setup IRQ numbers */ + timers.tmr_irq = irq_of_parse_and_map(node, 0); + + /* Setup IO addresses */ + timers.tmr_regs = of_iomap(node, 0); + + kona_timer_disable_and_clear(timers.tmr_regs); + kona_timer_clockevents_init(); setup_irq(timers.tmr_irq, &kona_timer_irq); kona_timer_set_next_event((arch_timer_rate / HZ), NULL); diff --git a/drivers/connector/connector.c b/drivers/connector/connector.c index a36749f1e44a..9b0ea0a6e26e 100644 --- a/drivers/connector/connector.c +++ b/drivers/connector/connector.c @@ -139,7 +139,6 @@ static int cn_call_callback(struct sk_buff *skb) spin_unlock_bh(&dev->cbdev->queue_lock); if (cbq != NULL) { - err = 0; cbq->callback(msg, nsp); kfree_skb(skb); cn_queue_release_callback(cbq); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 08ca8c9f41cd..cb003a6b72c8 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1323,8 +1323,7 @@ static int __cpufreq_remove_dev_prepare(struct device *dev, up_read(&policy->rwsem); if (cpu != policy->cpu) { - if (!frozen) - sysfs_remove_link(&dev->kobj, "cpufreq"); + sysfs_remove_link(&dev->kobj, "cpufreq"); } else if (cpus > 1) { new_cpu = cpufreq_nominate_new_policy_cpu(policy, cpu); if (new_cpu >= 0) { diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 79606f473f48..2cd36b9297f3 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -34,12 +34,15 @@ #define SAMPLE_COUNT 3 -#define BYT_RATIOS 0x66a -#define BYT_VIDS 0x66b +#define BYT_RATIOS 0x66a +#define BYT_VIDS 0x66b +#define BYT_TURBO_RATIOS 0x66c -#define FRAC_BITS 8 + +#define FRAC_BITS 6 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) #define fp_toint(X) ((X) >> FRAC_BITS) +#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS) static inline int32_t mul_fp(int32_t x, int32_t y) { @@ -51,8 +54,6 @@ static inline int32_t div_fp(int32_t x, int32_t y) return div_s64((int64_t)x << FRAC_BITS, (int64_t)y); } -static u64 energy_divisor; - struct sample { int32_t core_pct_busy; u64 aperf; @@ -359,7 +360,7 @@ static int byt_get_min_pstate(void) { u64 value; rdmsrl(BYT_RATIOS, value); - return value & 0xFF; + return (value >> 8) & 0xFF; } static int byt_get_max_pstate(void) @@ -369,6 +370,13 @@ static int byt_get_max_pstate(void) return (value >> 16) & 0xFF; } +static int byt_get_turbo_pstate(void) +{ + u64 value; + rdmsrl(BYT_TURBO_RATIOS, value); + return value & 0x3F; +} + static void byt_set_pstate(struct cpudata *cpudata, int pstate) { u64 val; @@ -471,7 +479,7 @@ static struct cpu_defaults byt_params = { .funcs = { .get_max = byt_get_max_pstate, .get_min = byt_get_min_pstate, - .get_turbo = byt_get_max_pstate, + .get_turbo = byt_get_turbo_pstate, .set = byt_set_pstate, .get_vid = byt_get_vid, }, @@ -549,18 +557,20 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu) static inline void intel_pstate_calc_busy(struct cpudata *cpu, struct sample *sample) { - u64 core_pct; - u64 c0_pct; + int32_t core_pct; + int32_t c0_pct; + + core_pct = div_fp(int_tofp((sample->aperf)), + int_tofp((sample->mperf))); + core_pct = mul_fp(core_pct, int_tofp(100)); + FP_ROUNDUP(core_pct); - core_pct = div64_u64(sample->aperf * 100, sample->mperf); + c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc)); - c0_pct = div64_u64(sample->mperf * 100, sample->tsc); sample->freq = fp_toint( - mul_fp(int_tofp(cpu->pstate.max_pstate), - int_tofp(core_pct * 1000))); + mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); - sample->core_pct_busy = mul_fp(int_tofp(core_pct), - div_fp(int_tofp(c0_pct + 1), int_tofp(100))); + sample->core_pct_busy = mul_fp(core_pct, c0_pct); } static inline void intel_pstate_sample(struct cpudata *cpu) @@ -572,6 +582,10 @@ static inline void intel_pstate_sample(struct cpudata *cpu) rdmsrl(MSR_IA32_MPERF, mperf); tsc = native_read_tsc(); + aperf = aperf >> FRAC_BITS; + mperf = mperf >> FRAC_BITS; + tsc = tsc >> FRAC_BITS; + cpu->sample_ptr = (cpu->sample_ptr + 1) % SAMPLE_COUNT; cpu->samples[cpu->sample_ptr].aperf = aperf; cpu->samples[cpu->sample_ptr].mperf = mperf; @@ -603,7 +617,8 @@ static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) core_busy = cpu->samples[cpu->sample_ptr].core_pct_busy; max_pstate = int_tofp(cpu->pstate.max_pstate); current_pstate = int_tofp(cpu->pstate.current_pstate); - return mul_fp(core_busy, div_fp(max_pstate, current_pstate)); + core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); + return FP_ROUNDUP(core_busy); } static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu) @@ -630,12 +645,10 @@ static void intel_pstate_timer_func(unsigned long __data) { struct cpudata *cpu = (struct cpudata *) __data; struct sample *sample; - u64 energy; intel_pstate_sample(cpu); sample = &cpu->samples[cpu->sample_ptr]; - rdmsrl(MSR_PKG_ENERGY_STATUS, energy); intel_pstate_adjust_busy_pstate(cpu); @@ -644,7 +657,6 @@ static void intel_pstate_timer_func(unsigned long __data) cpu->pstate.current_pstate, sample->mperf, sample->aperf, - div64_u64(energy, energy_divisor), sample->freq); intel_pstate_set_sample_time(cpu); @@ -926,7 +938,6 @@ static int __init intel_pstate_init(void) int cpu, rc = 0; const struct x86_cpu_id *id; struct cpu_defaults *cpu_info; - u64 units; if (no_load) return -ENODEV; @@ -960,9 +971,6 @@ static int __init intel_pstate_init(void) if (rc) goto out; - rdmsrl(MSR_RAPL_POWER_UNIT, units); - energy_divisor = 1 << ((units >> 8) & 0x1f); /* bits{12:8} */ - intel_pstate_debug_expose_params(); intel_pstate_sysfs_expose_params(); diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index e10b646634d7..6684e0342792 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -1076,7 +1076,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) { struct powernow_k8_data *data; struct init_on_cpu init_on_cpu; - int rc; + int rc, cpu; smp_call_function_single(pol->cpu, check_supported_cpu, &rc, 1); if (rc) @@ -1140,7 +1140,9 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol) pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n", data->currfid, data->currvid); - per_cpu(powernow_data, pol->cpu) = data; + /* Point all the CPUs in this policy to the same data */ + for_each_cpu(cpu, pol->cpus) + per_cpu(powernow_data, cpu) = data; return 0; @@ -1155,6 +1157,7 @@ err_out: static int powernowk8_cpu_exit(struct cpufreq_policy *pol) { struct powernow_k8_data *data = per_cpu(powernow_data, pol->cpu); + int cpu; if (!data) return -EINVAL; @@ -1165,7 +1168,8 @@ static int powernowk8_cpu_exit(struct cpufreq_policy *pol) kfree(data->powernow_table); kfree(data); - per_cpu(powernow_data, pol->cpu) = NULL; + for_each_cpu(cpu, pol->cpus) + per_cpu(powernow_data, cpu) = NULL; return 0; } diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 6c4c000671c5..1e5481d88a26 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c @@ -158,6 +158,15 @@ static inline unsigned long nx842_get_scatterlist_size( return sl->entry_nr * sizeof(struct nx842_slentry); } +static inline unsigned long nx842_get_pa(void *addr) +{ + if (is_vmalloc_addr(addr)) + return page_to_phys(vmalloc_to_page(addr)) + + offset_in_page(addr); + else + return __pa(addr); +} + static int nx842_build_scatterlist(unsigned long buf, int len, struct nx842_scatterlist *sl) { @@ -168,7 +177,7 @@ static int nx842_build_scatterlist(unsigned long buf, int len, entry = sl->entries; while (len) { - entry->ptr = __pa(buf); + entry->ptr = nx842_get_pa((void *)buf); nextpage = ALIGN(buf + 1, NX842_HW_PAGE_SIZE); if (nextpage < buf + len) { /* we aren't at the end yet */ @@ -370,8 +379,8 @@ int nx842_compress(const unsigned char *in, unsigned int inlen, op.flags = NX842_OP_COMPRESS; csbcpb = &workmem->csbcpb; memset(csbcpb, 0, sizeof(*csbcpb)); - op.csbcpb = __pa(csbcpb); - op.out = __pa(slout.entries); + op.csbcpb = nx842_get_pa(csbcpb); + op.out = nx842_get_pa(slout.entries); for (i = 0; i < hdr->blocks_nr; i++) { /* @@ -401,13 +410,13 @@ int nx842_compress(const unsigned char *in, unsigned int inlen, */ if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { /* Create direct DDE */ - op.in = __pa(inbuf); + op.in = nx842_get_pa((void *)inbuf); op.inlen = max_sync_size; } else { /* Create indirect DDE (scatterlist) */ nx842_build_scatterlist(inbuf, max_sync_size, &slin); - op.in = __pa(slin.entries); + op.in = nx842_get_pa(slin.entries); op.inlen = -nx842_get_scatterlist_size(&slin); } @@ -565,7 +574,7 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen, op.flags = NX842_OP_DECOMPRESS; csbcpb = &workmem->csbcpb; memset(csbcpb, 0, sizeof(*csbcpb)); - op.csbcpb = __pa(csbcpb); + op.csbcpb = nx842_get_pa(csbcpb); /* * max_sync_size may have changed since compression, @@ -597,12 +606,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen, if (likely((inbuf & NX842_HW_PAGE_MASK) == ((inbuf + hdr->sizes[i] - 1) & NX842_HW_PAGE_MASK))) { /* Create direct DDE */ - op.in = __pa(inbuf); + op.in = nx842_get_pa((void *)inbuf); op.inlen = hdr->sizes[i]; } else { /* Create indirect DDE (scatterlist) */ nx842_build_scatterlist(inbuf, hdr->sizes[i] , &slin); - op.in = __pa(slin.entries); + op.in = nx842_get_pa(slin.entries); op.inlen = -nx842_get_scatterlist_size(&slin); } @@ -613,12 +622,12 @@ int nx842_decompress(const unsigned char *in, unsigned int inlen, */ if (likely(max_sync_size == NX842_HW_PAGE_SIZE)) { /* Create direct DDE */ - op.out = __pa(outbuf); + op.out = nx842_get_pa((void *)outbuf); op.outlen = max_sync_size; } else { /* Create indirect DDE (scatterlist) */ nx842_build_scatterlist(outbuf, max_sync_size, &slout); - op.out = __pa(slout.entries); + op.out = nx842_get_pa(slout.entries); op.outlen = -nx842_get_scatterlist_size(&slout); } diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 9bed1a2a67a1..605b016bcea4 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -346,6 +346,7 @@ config MOXART_DMA tristate "MOXART DMA support" depends on ARCH_MOXART select DMA_ENGINE + select DMA_OF select DMA_VIRTUAL_CHANNELS help Enable support for the MOXA ART SoC DMA controller. diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index 4e7918339b12..19041cefabb1 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -449,6 +449,7 @@ static const struct of_device_id sdma_dt_ids[] = { { .compatible = "fsl,imx51-sdma", .data = &sdma_imx51, }, { .compatible = "fsl,imx35-sdma", .data = &sdma_imx35, }, { .compatible = "fsl,imx31-sdma", .data = &sdma_imx31, }, + { .compatible = "fsl,imx25-sdma", .data = &sdma_imx25, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, sdma_dt_ids); diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 87529181efcc..4e3549a16132 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -77,7 +77,8 @@ static irqreturn_t ioat_dma_do_interrupt(int irq, void *data) attnstatus = readl(instance->reg_base + IOAT_ATTNSTATUS_OFFSET); for_each_set_bit(bit, &attnstatus, BITS_PER_LONG) { chan = ioat_chan_by_index(instance, bit); - tasklet_schedule(&chan->cleanup_task); + if (test_bit(IOAT_RUN, &chan->state)) + tasklet_schedule(&chan->cleanup_task); } writeb(intrctrl, instance->reg_base + IOAT_INTRCTRL_OFFSET); @@ -93,7 +94,8 @@ static irqreturn_t ioat_dma_do_interrupt_msix(int irq, void *data) { struct ioat_chan_common *chan = data; - tasklet_schedule(&chan->cleanup_task); + if (test_bit(IOAT_RUN, &chan->state)) + tasklet_schedule(&chan->cleanup_task); return IRQ_HANDLED; } @@ -116,7 +118,6 @@ void ioat_init_channel(struct ioatdma_device *device, struct ioat_chan_common *c chan->timer.function = device->timer_fn; chan->timer.data = data; tasklet_init(&chan->cleanup_task, device->cleanup_fn, data); - tasklet_disable(&chan->cleanup_task); } /** @@ -354,13 +355,49 @@ static int ioat1_dma_alloc_chan_resources(struct dma_chan *c) writel(((u64) chan->completion_dma) >> 32, chan->reg_base + IOAT_CHANCMP_OFFSET_HIGH); - tasklet_enable(&chan->cleanup_task); + set_bit(IOAT_RUN, &chan->state); ioat1_dma_start_null_desc(ioat); /* give chain to dma device */ dev_dbg(to_dev(chan), "%s: allocated %d descriptors\n", __func__, ioat->desccount); return ioat->desccount; } +void ioat_stop(struct ioat_chan_common *chan) +{ + struct ioatdma_device *device = chan->device; + struct pci_dev *pdev = device->pdev; + int chan_id = chan_num(chan); + struct msix_entry *msix; + + /* 1/ stop irq from firing tasklets + * 2/ stop the tasklet from re-arming irqs + */ + clear_bit(IOAT_RUN, &chan->state); + + /* flush inflight interrupts */ + switch (device->irq_mode) { + case IOAT_MSIX: + msix = &device->msix_entries[chan_id]; + synchronize_irq(msix->vector); + break; + case IOAT_MSI: + case IOAT_INTX: + synchronize_irq(pdev->irq); + break; + default: + break; + } + + /* flush inflight timers */ + del_timer_sync(&chan->timer); + + /* flush inflight tasklet runs */ + tasklet_kill(&chan->cleanup_task); + + /* final cleanup now that everything is quiesced and can't re-arm */ + device->cleanup_fn((unsigned long) &chan->common); +} + /** * ioat1_dma_free_chan_resources - release all the descriptors * @chan: the channel to be cleaned @@ -379,9 +416,7 @@ static void ioat1_dma_free_chan_resources(struct dma_chan *c) if (ioat->desccount == 0) return; - tasklet_disable(&chan->cleanup_task); - del_timer_sync(&chan->timer); - ioat1_cleanup(ioat); + ioat_stop(chan); /* Delay 100ms after reset to allow internal DMA logic to quiesce * before removing DMA descriptor resources. @@ -526,8 +561,11 @@ ioat1_dma_prep_memcpy(struct dma_chan *c, dma_addr_t dma_dest, static void ioat1_cleanup_event(unsigned long data) { struct ioat_dma_chan *ioat = to_ioat_chan((void *) data); + struct ioat_chan_common *chan = &ioat->base; ioat1_cleanup(ioat); + if (!test_bit(IOAT_RUN, &chan->state)) + return; writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); } diff --git a/drivers/dma/ioat/dma.h b/drivers/dma/ioat/dma.h index 11fb877ddca9..e982f00a9843 100644 --- a/drivers/dma/ioat/dma.h +++ b/drivers/dma/ioat/dma.h @@ -356,6 +356,7 @@ bool ioat_cleanup_preamble(struct ioat_chan_common *chan, void ioat_kobject_add(struct ioatdma_device *device, struct kobj_type *type); void ioat_kobject_del(struct ioatdma_device *device); int ioat_dma_setup_interrupts(struct ioatdma_device *device); +void ioat_stop(struct ioat_chan_common *chan); extern const struct sysfs_ops ioat_sysfs_ops; extern struct ioat_sysfs_entry ioat_version_attr; extern struct ioat_sysfs_entry ioat_cap_attr; diff --git a/drivers/dma/ioat/dma_v2.c b/drivers/dma/ioat/dma_v2.c index 5d3affe7e976..8d1058085eeb 100644 --- a/drivers/dma/ioat/dma_v2.c +++ b/drivers/dma/ioat/dma_v2.c @@ -190,8 +190,11 @@ static void ioat2_cleanup(struct ioat2_dma_chan *ioat) void ioat2_cleanup_event(unsigned long data) { struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data); + struct ioat_chan_common *chan = &ioat->base; ioat2_cleanup(ioat); + if (!test_bit(IOAT_RUN, &chan->state)) + return; writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); } @@ -553,10 +556,10 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) ioat->issued = 0; ioat->tail = 0; ioat->alloc_order = order; + set_bit(IOAT_RUN, &chan->state); spin_unlock_bh(&ioat->prep_lock); spin_unlock_bh(&chan->cleanup_lock); - tasklet_enable(&chan->cleanup_task); ioat2_start_null_desc(ioat); /* check that we got off the ground */ @@ -566,7 +569,6 @@ int ioat2_alloc_chan_resources(struct dma_chan *c) } while (i++ < 20 && !is_ioat_active(status) && !is_ioat_idle(status)); if (is_ioat_active(status) || is_ioat_idle(status)) { - set_bit(IOAT_RUN, &chan->state); return 1 << ioat->alloc_order; } else { u32 chanerr = readl(chan->reg_base + IOAT_CHANERR_OFFSET); @@ -809,11 +811,8 @@ void ioat2_free_chan_resources(struct dma_chan *c) if (!ioat->ring) return; - tasklet_disable(&chan->cleanup_task); - del_timer_sync(&chan->timer); - device->cleanup_fn((unsigned long) c); + ioat_stop(chan); device->reset_hw(chan); - clear_bit(IOAT_RUN, &chan->state); spin_lock_bh(&chan->cleanup_lock); spin_lock_bh(&ioat->prep_lock); diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index 820817e97e62..b9b38a1cf92f 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -464,8 +464,11 @@ static void ioat3_cleanup(struct ioat2_dma_chan *ioat) static void ioat3_cleanup_event(unsigned long data) { struct ioat2_dma_chan *ioat = to_ioat2_chan((void *) data); + struct ioat_chan_common *chan = &ioat->base; ioat3_cleanup(ioat); + if (!test_bit(IOAT_RUN, &chan->state)) + return; writew(IOAT_CHANCTRL_RUN, ioat->base.reg_base + IOAT_CHANCTRL_OFFSET); } diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 53fb0c8365b0..766b68ed505c 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -497,8 +497,8 @@ mv_xor_tx_submit(struct dma_async_tx_descriptor *tx) if (!mv_can_chain(grp_start)) goto submit_done; - dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %x\n", - old_chain_tail->async_tx.phys); + dev_dbg(mv_chan_to_devp(mv_chan), "Append to last desc %pa\n", + &old_chain_tail->async_tx.phys); /* fix up the hardware chain */ mv_desc_set_next_desc(old_chain_tail, grp_start->async_tx.phys); @@ -527,7 +527,8 @@ submit_done: /* returns the number of allocated descriptors */ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) { - char *hw_desc; + void *virt_desc; + dma_addr_t dma_desc; int idx; struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); struct mv_xor_desc_slot *slot = NULL; @@ -542,17 +543,16 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) " %d descriptor slots", idx); break; } - hw_desc = (char *) mv_chan->dma_desc_pool_virt; - slot->hw_desc = (void *) &hw_desc[idx * MV_XOR_SLOT_SIZE]; + virt_desc = mv_chan->dma_desc_pool_virt; + slot->hw_desc = virt_desc + idx * MV_XOR_SLOT_SIZE; dma_async_tx_descriptor_init(&slot->async_tx, chan); slot->async_tx.tx_submit = mv_xor_tx_submit; INIT_LIST_HEAD(&slot->chain_node); INIT_LIST_HEAD(&slot->slot_node); INIT_LIST_HEAD(&slot->tx_list); - hw_desc = (char *) mv_chan->dma_desc_pool; - slot->async_tx.phys = - (dma_addr_t) &hw_desc[idx * MV_XOR_SLOT_SIZE]; + dma_desc = mv_chan->dma_desc_pool; + slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE; slot->idx = idx++; spin_lock_bh(&mv_chan->lock); @@ -582,8 +582,8 @@ mv_xor_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, int slot_cnt; dev_dbg(mv_chan_to_devp(mv_chan), - "%s dest: %x src %x len: %u flags: %ld\n", - __func__, dest, src, len, flags); + "%s dest: %pad src %pad len: %u flags: %ld\n", + __func__, &dest, &src, len, flags); if (unlikely(len < MV_XOR_MIN_BYTE_COUNT)) return NULL; @@ -626,8 +626,8 @@ mv_xor_prep_dma_xor(struct dma_chan *chan, dma_addr_t dest, dma_addr_t *src, BUG_ON(len > MV_XOR_MAX_BYTE_COUNT); dev_dbg(mv_chan_to_devp(mv_chan), - "%s src_cnt: %d len: dest %x %u flags: %ld\n", - __func__, src_cnt, len, dest, flags); + "%s src_cnt: %d len: %u dest %pad flags: %ld\n", + __func__, src_cnt, len, &dest, flags); spin_lock_bh(&mv_chan->lock); slot_cnt = mv_chan_xor_slot_count(len, src_cnt); diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 00a2de957b23..bf18c786ed40 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1641,6 +1641,7 @@ static void dma_tasklet(unsigned long data) struct d40_chan *d40c = (struct d40_chan *) data; struct d40_desc *d40d; unsigned long flags; + bool callback_active; dma_async_tx_callback callback; void *callback_param; @@ -1668,6 +1669,7 @@ static void dma_tasklet(unsigned long data) } /* Callback to client */ + callback_active = !!(d40d->txd.flags & DMA_PREP_INTERRUPT); callback = d40d->txd.callback; callback_param = d40d->txd.callback_param; @@ -1690,7 +1692,7 @@ static void dma_tasklet(unsigned long data) spin_unlock_irqrestore(&d40c->lock, flags); - if (callback && (d40d->txd.flags & DMA_PREP_INTERRUPT)) + if (callback_active && callback) callback(callback_param); return; diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index e8c9ef03495b..33edd6766344 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -559,7 +559,8 @@ static void edac_mc_workq_function(struct work_struct *work_req) * * called with the mem_ctls_mutex held */ -static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) +static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec, + bool init) { edac_dbg(0, "\n"); @@ -567,7 +568,9 @@ static void edac_mc_workq_setup(struct mem_ctl_info *mci, unsigned msec) if (mci->op_state != OP_RUNNING_POLL) return; - INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); + if (init) + INIT_DELAYED_WORK(&mci->work, edac_mc_workq_function); + mod_delayed_work(edac_workqueue, &mci->work, msecs_to_jiffies(msec)); } @@ -601,7 +604,7 @@ static void edac_mc_workq_teardown(struct mem_ctl_info *mci) * user space has updated our poll period value, need to * reset our workq delays */ -void edac_mc_reset_delay_period(int value) +void edac_mc_reset_delay_period(unsigned long value) { struct mem_ctl_info *mci; struct list_head *item; @@ -611,7 +614,7 @@ void edac_mc_reset_delay_period(int value) list_for_each(item, &mc_devices) { mci = list_entry(item, struct mem_ctl_info, link); - edac_mc_workq_setup(mci, (unsigned long) value); + edac_mc_workq_setup(mci, value, false); } mutex_unlock(&mem_ctls_mutex); @@ -782,7 +785,7 @@ int edac_mc_add_mc(struct mem_ctl_info *mci) /* This instance is NOW RUNNING */ mci->op_state = OP_RUNNING_POLL; - edac_mc_workq_setup(mci, edac_mc_get_poll_msec()); + edac_mc_workq_setup(mci, edac_mc_get_poll_msec(), true); } else { mci->op_state = OP_RUNNING_INTERRUPT; } diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 51c0362acf5c..b335c6ab5efe 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -52,18 +52,20 @@ int edac_mc_get_poll_msec(void) static int edac_set_poll_msec(const char *val, struct kernel_param *kp) { - long l; + unsigned long l; int ret; if (!val) return -EINVAL; - ret = kstrtol(val, 0, &l); + ret = kstrtoul(val, 0, &l); if (ret) return ret; - if ((int)l != l) + + if (l < 1000) return -EINVAL; - *((int *)kp->arg) = l; + + *((unsigned long *)kp->arg) = l; /* notify edac_mc engine to reset the poll period */ edac_mc_reset_delay_period(l); diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 3d139c6e7fe3..f2118bfcf8df 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -52,7 +52,7 @@ extern void edac_device_workq_setup(struct edac_device_ctl_info *edac_dev, extern void edac_device_workq_teardown(struct edac_device_ctl_info *edac_dev); extern void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, unsigned long value); -extern void edac_mc_reset_delay_period(int value); +extern void edac_mc_reset_delay_period(unsigned long value); extern void *edac_align_ptr(void **p, unsigned size, int n_elems); diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index d63f4798f7d0..57e96a3350f0 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -943,33 +943,35 @@ static int i7300_get_devices(struct mem_ctl_info *mci) /* Attempt to 'get' the MCH register we want */ pdev = NULL; - while (!pvt->pci_dev_16_1_fsb_addr_map || - !pvt->pci_dev_16_2_fsb_err_regs) { - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, pdev); - if (!pdev) { - /* End of list, leave */ - i7300_printk(KERN_ERR, - "'system address,Process Bus' " - "device not found:" - "vendor 0x%x device 0x%x ERR funcs " - "(broken BIOS?)\n", - PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); - goto error; - } - + while ((pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7300_MCH_ERR, + pdev))) { /* Store device 16 funcs 1 and 2 */ switch (PCI_FUNC(pdev->devfn)) { case 1: - pvt->pci_dev_16_1_fsb_addr_map = pdev; + if (!pvt->pci_dev_16_1_fsb_addr_map) + pvt->pci_dev_16_1_fsb_addr_map = + pci_dev_get(pdev); break; case 2: - pvt->pci_dev_16_2_fsb_err_regs = pdev; + if (!pvt->pci_dev_16_2_fsb_err_regs) + pvt->pci_dev_16_2_fsb_err_regs = + pci_dev_get(pdev); break; } } + if (!pvt->pci_dev_16_1_fsb_addr_map || + !pvt->pci_dev_16_2_fsb_err_regs) { + /* At least one device was not found */ + i7300_printk(KERN_ERR, + "'system address,Process Bus' device not found:" + "vendor 0x%x device 0x%x ERR funcs (broken BIOS?)\n", + PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_I7300_MCH_ERR); + goto error; + } + edac_dbg(1, "System Address, processor bus- PCI Bus ID: %s %x:%x\n", pci_name(pvt->pci_dev_16_0_fsb_ctlr), pvt->pci_dev_16_0_fsb_ctlr->vendor, diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 87533ca7752e..d871275196f6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1334,14 +1334,19 @@ static int i7core_get_onedevice(struct pci_dev **prev, * is at addr 8086:2c40, instead of 8086:2c41. So, we need * to probe for the alternate address in case of failure */ - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) { + pci_dev_get(*prev); /* pci_get_device will put it */ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); + } - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) + if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && + !pdev) { + pci_dev_get(*prev); /* pci_get_device will put it */ pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, *prev); + } if (!pdev) { if (*prev) { diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index c20602f601ee..98a14f6143a7 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -222,27 +222,19 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) struct snd_soc_dapm_context *dapm = arizona->dapm; int ret; - mutex_lock(&dapm->card->dapm_mutex); - ret = snd_soc_dapm_force_enable_pin(dapm, widget); if (ret != 0) dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret); - mutex_unlock(&dapm->card->dapm_mutex); - snd_soc_dapm_sync(dapm); if (!arizona->pdata.micd_force_micbias) { - mutex_lock(&dapm->card->dapm_mutex); - ret = snd_soc_dapm_disable_pin(arizona->dapm, widget); if (ret != 0) dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); - mutex_unlock(&dapm->card->dapm_mutex); - snd_soc_dapm_sync(dapm); } } @@ -304,16 +296,12 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) ARIZONA_MICD_ENA, 0, &change); - mutex_lock(&dapm->card->dapm_mutex); - ret = snd_soc_dapm_disable_pin(dapm, widget); if (ret != 0) dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); - mutex_unlock(&dapm->card->dapm_mutex); - snd_soc_dapm_sync(dapm); if (info->micd_reva) { diff --git a/drivers/fmc/fmc-write-eeprom.c b/drivers/fmc/fmc-write-eeprom.c index ee5b47904130..9bb2cbd5c9f2 100644 --- a/drivers/fmc/fmc-write-eeprom.c +++ b/drivers/fmc/fmc-write-eeprom.c @@ -27,7 +27,7 @@ FMC_PARAM_BUSID(fwe_drv); /* The "file=" is like the generic "gateware=" used elsewhere */ static char *fwe_file[FMC_MAX_CARDS]; static int fwe_file_n; -module_param_array_named(file, fwe_file, charp, &fwe_file_n, 444); +module_param_array_named(file, fwe_file, charp, &fwe_file_n, 0444); static int fwe_run_tlv(struct fmc_device *fmc, const struct firmware *fw, int write) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 697338772b64..903f24d28ba0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -403,6 +403,7 @@ config GPIO_GRGPIO config GPIO_TB10X bool + select GENERIC_IRQ_CHIP select OF_GPIO comment "I2C GPIO expanders:" diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 233d088ac59f..f32357e2d78d 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2013 Broadcom Corporation + * Copyright (C) 2012-2014 Broadcom Corporation * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -657,6 +657,6 @@ static struct platform_driver bcm_kona_gpio_driver = { module_platform_driver(bcm_kona_gpio_driver); -MODULE_AUTHOR("Broadcom"); +MODULE_AUTHOR("Broadcom Corporation <bcm-kernel-feedback-list@broadcom.com>"); MODULE_DESCRIPTION("Broadcom Kona GPIO Driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/gpio/gpio-clps711x.c b/drivers/gpio/gpio-clps711x.c index d3550274b8f7..3c2ba2ad0ada 100644 --- a/drivers/gpio/gpio-clps711x.c +++ b/drivers/gpio/gpio-clps711x.c @@ -97,3 +97,4 @@ module_platform_driver(clps711x_gpio_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>"); MODULE_DESCRIPTION("CLPS711X GPIO driver"); +MODULE_ALIAS("platform:clps711x-gpio"); diff --git a/drivers/gpio/gpio-intel-mid.c b/drivers/gpio/gpio-intel-mid.c index d1b50ef5fab8..e585163f1ad5 100644 --- a/drivers/gpio/gpio-intel-mid.c +++ b/drivers/gpio/gpio-intel-mid.c @@ -394,8 +394,8 @@ static const struct irq_domain_ops intel_gpio_irq_ops = { static int intel_gpio_runtime_idle(struct device *dev) { - pm_schedule_suspend(dev, 500); - return -EBUSY; + int err = pm_schedule_suspend(dev, 500); + return err ?: -EBUSY; } static const struct dev_pm_ops intel_gpio_pm_ops = { diff --git a/drivers/gpio/gpio-xtensa.c b/drivers/gpio/gpio-xtensa.c index 1d136eceda62..7081304d6797 100644 --- a/drivers/gpio/gpio-xtensa.c +++ b/drivers/gpio/gpio-xtensa.c @@ -40,6 +40,8 @@ #error GPIO32 option is not enabled for your xtensa core variant #endif +#if XCHAL_HAVE_CP + static inline unsigned long enable_cp(unsigned long *cpenable) { unsigned long flags; @@ -57,6 +59,20 @@ static inline void disable_cp(unsigned long flags, unsigned long cpenable) local_irq_restore(flags); } +#else + +static inline unsigned long enable_cp(unsigned long *cpenable) +{ + *cpenable = 0; /* avoid uninitialized value warning */ + return 0; +} + +static inline void disable_cp(unsigned long flags, unsigned long cpenable) +{ +} + +#endif /* XCHAL_HAVE_CP */ + static int xtensa_impwire_get_direction(struct gpio_chip *gc, unsigned offset) { return 1; /* input only */ diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c index dffc836144cc..f4dc9b7a3831 100644 --- a/drivers/gpu/drm/drm_ioctl.c +++ b/drivers/gpu/drm/drm_ioctl.c @@ -296,6 +296,18 @@ int drm_getcap(struct drm_device *dev, void *data, struct drm_file *file_priv) case DRM_CAP_ASYNC_PAGE_FLIP: req->value = dev->mode_config.async_page_flip; break; + case DRM_CAP_CURSOR_WIDTH: + if (dev->mode_config.cursor_width) + req->value = dev->mode_config.cursor_width; + else + req->value = 64; + break; + case DRM_CAP_CURSOR_HEIGHT: + if (dev->mode_config.cursor_height) + req->value = dev->mode_config.cursor_height; + else + req->value = 64; + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig index f227f544aa36..6e1a1a20cf6b 100644 --- a/drivers/gpu/drm/exynos/Kconfig +++ b/drivers/gpu/drm/exynos/Kconfig @@ -51,7 +51,7 @@ config DRM_EXYNOS_G2D config DRM_EXYNOS_IPP bool "Exynos DRM IPP" - depends on DRM_EXYNOS && !ARCH_MULTIPLATFORM + depends on DRM_EXYNOS help Choose this option if you want to use IPP feature for DRM. @@ -69,6 +69,6 @@ config DRM_EXYNOS_ROTATOR config DRM_EXYNOS_GSC bool "Exynos DRM GSC" - depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 + depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !ARCH_MULTIPLATFORM help Choose this option if you want to use Exynos GSC for DRM. diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 9d096a0c5f8d..215131ab1dd2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -171,22 +171,24 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) file->driver_priv = file_priv; ret = exynos_drm_subdrv_open(dev, file); - if (ret) { - kfree(file_priv); - file->driver_priv = NULL; - } + if (ret) + goto out; anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops, NULL, 0); if (IS_ERR(anon_filp)) { - kfree(file_priv); - return PTR_ERR(anon_filp); + ret = PTR_ERR(anon_filp); + goto out; } anon_filp->f_mode = FMODE_READ | FMODE_WRITE; file_priv->anon_filp = anon_filp; return ret; +out: + kfree(file_priv); + file->driver_priv = NULL; + return ret; } static void exynos_drm_preclose(struct drm_device *dev, diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 380aec28840b..6c1885eedfdf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -607,7 +607,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset) reg_type = REG_TYPE_NONE; DRM_ERROR("Unknown register offset![%d]\n", reg_offset); break; - }; + } return reg_type; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index d519a4e5fe40..09312b877470 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -16,7 +16,6 @@ #include <linux/types.h> #include <linux/clk.h> #include <linux/pm_runtime.h> -#include <plat/map-base.h> #include <drm/drmP.h> #include <drm/exynos_drm.h> @@ -826,7 +825,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e); /* - * quf == NULL condition means all event deletion. + * qbuf == NULL condition means all event deletion. * stop operations want to delete all event list. * another case delete only same buf id. */ diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index a0e10aeb0e67..c021ddc1ffb4 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c @@ -34,6 +34,7 @@ #include <linux/io.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/hdmi.h> #include <drm/exynos_drm.h> @@ -59,19 +60,6 @@ #define HDMI_AUI_VERSION 0x01 #define HDMI_AUI_LENGTH 0x0A -/* HDMI infoframe to configure HDMI out packet header, AUI and AVI */ -enum HDMI_PACKET_TYPE { - /* refer to Table 5-8 Packet Type in HDMI specification v1.4a */ - /* InfoFrame packet type */ - HDMI_PACKET_TYPE_INFOFRAME = 0x80, - /* Vendor-Specific InfoFrame */ - HDMI_PACKET_TYPE_VSI = HDMI_PACKET_TYPE_INFOFRAME + 1, - /* Auxiliary Video information InfoFrame */ - HDMI_PACKET_TYPE_AVI = HDMI_PACKET_TYPE_INFOFRAME + 2, - /* Audio information InfoFrame */ - HDMI_PACKET_TYPE_AUI = HDMI_PACKET_TYPE_INFOFRAME + 4 -}; - enum hdmi_type { HDMI_TYPE13, HDMI_TYPE14, @@ -379,12 +367,6 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = { }, }; -struct hdmi_infoframe { - enum HDMI_PACKET_TYPE type; - u8 ver; - u8 len; -}; - static inline u32 hdmi_reg_read(struct hdmi_context *hdata, u32 reg_id) { return readl(hdata->regs + reg_id); @@ -682,7 +664,7 @@ static u8 hdmi_chksum(struct hdmi_context *hdata, } static void hdmi_reg_infoframe(struct hdmi_context *hdata, - struct hdmi_infoframe *infoframe) + union hdmi_infoframe *infoframe) { u32 hdr_sum; u8 chksum; @@ -700,13 +682,15 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, return; } - switch (infoframe->type) { - case HDMI_PACKET_TYPE_AVI: + switch (infoframe->any.type) { + case HDMI_INFOFRAME_TYPE_AVI: hdmi_reg_writeb(hdata, HDMI_AVI_CON, HDMI_AVI_CON_EVERY_VSYNC); - hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->type); - hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, infoframe->ver); - hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->len); - hdr_sum = infoframe->type + infoframe->ver + infoframe->len; + hdmi_reg_writeb(hdata, HDMI_AVI_HEADER0, infoframe->any.type); + hdmi_reg_writeb(hdata, HDMI_AVI_HEADER1, + infoframe->any.version); + hdmi_reg_writeb(hdata, HDMI_AVI_HEADER2, infoframe->any.length); + hdr_sum = infoframe->any.type + infoframe->any.version + + infoframe->any.length; /* Output format zero hardcoded ,RGB YBCR selection */ hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(1), 0 << 5 | @@ -722,18 +706,20 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata, hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic); chksum = hdmi_chksum(hdata, HDMI_AVI_BYTE(1), - infoframe->len, hdr_sum); + infoframe->any.length, hdr_sum); DRM_DEBUG_KMS("AVI checksum = 0x%x\n", chksum); hdmi_reg_writeb(hdata, HDMI_AVI_CHECK_SUM, chksum); break; - case HDMI_PACKET_TYPE_AUI: + case HDMI_INFOFRAME_TYPE_AUDIO: hdmi_reg_writeb(hdata, HDMI_AUI_CON, 0x02); - hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->type); - hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, infoframe->ver); - hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->len); - hdr_sum = infoframe->type + infoframe->ver + infoframe->len; + hdmi_reg_writeb(hdata, HDMI_AUI_HEADER0, infoframe->any.type); + hdmi_reg_writeb(hdata, HDMI_AUI_HEADER1, + infoframe->any.version); + hdmi_reg_writeb(hdata, HDMI_AUI_HEADER2, infoframe->any.length); + hdr_sum = infoframe->any.type + infoframe->any.version + + infoframe->any.length; chksum = hdmi_chksum(hdata, HDMI_AUI_BYTE(1), - infoframe->len, hdr_sum); + infoframe->any.length, hdr_sum); DRM_DEBUG_KMS("AUI checksum = 0x%x\n", chksum); hdmi_reg_writeb(hdata, HDMI_AUI_CHECK_SUM, chksum); break; @@ -985,7 +971,7 @@ static void hdmi_conf_reset(struct hdmi_context *hdata) static void hdmi_conf_init(struct hdmi_context *hdata) { - struct hdmi_infoframe infoframe; + union hdmi_infoframe infoframe; /* disable HPD interrupts from HDMI IP block, use GPIO instead */ hdmi_reg_writemask(hdata, HDMI_INTC_CON, 0, HDMI_INTC_EN_GLOBAL | @@ -1021,14 +1007,14 @@ static void hdmi_conf_init(struct hdmi_context *hdata) hdmi_reg_writeb(hdata, HDMI_V13_AUI_CON, 0x02); hdmi_reg_writeb(hdata, HDMI_V13_ACR_CON, 0x04); } else { - infoframe.type = HDMI_PACKET_TYPE_AVI; - infoframe.ver = HDMI_AVI_VERSION; - infoframe.len = HDMI_AVI_LENGTH; + infoframe.any.type = HDMI_INFOFRAME_TYPE_AVI; + infoframe.any.version = HDMI_AVI_VERSION; + infoframe.any.length = HDMI_AVI_LENGTH; hdmi_reg_infoframe(hdata, &infoframe); - infoframe.type = HDMI_PACKET_TYPE_AUI; - infoframe.ver = HDMI_AUI_VERSION; - infoframe.len = HDMI_AUI_LENGTH; + infoframe.any.type = HDMI_INFOFRAME_TYPE_AUDIO; + infoframe.any.version = HDMI_AUI_VERSION; + infoframe.any.length = HDMI_AUI_LENGTH; hdmi_reg_infoframe(hdata, &infoframe); /* enable AVI packet every vsync, fixes purple line problem */ diff --git a/drivers/gpu/drm/i2c/tda998x_drv.c b/drivers/gpu/drm/i2c/tda998x_drv.c index 400b0c4a10fb..faa77f543a07 100644 --- a/drivers/gpu/drm/i2c/tda998x_drv.c +++ b/drivers/gpu/drm/i2c/tda998x_drv.c @@ -208,7 +208,7 @@ struct tda998x_priv { # define PLL_SERIAL_1_SRL_IZ(x) (((x) & 3) << 1) # define PLL_SERIAL_1_SRL_MAN_IZ (1 << 6) #define REG_PLL_SERIAL_2 REG(0x02, 0x01) /* read/write */ -# define PLL_SERIAL_2_SRL_NOSC(x) (((x) & 3) << 0) +# define PLL_SERIAL_2_SRL_NOSC(x) ((x) << 0) # define PLL_SERIAL_2_SRL_PR(x) (((x) & 0xf) << 4) #define REG_PLL_SERIAL_3 REG(0x02, 0x02) /* read/write */ # define PLL_SERIAL_3_SRL_CCIR (1 << 0) @@ -528,10 +528,10 @@ tda998x_write_aif(struct drm_encoder *encoder, struct tda998x_encoder_params *p) { uint8_t buf[PB(5) + 1]; + memset(buf, 0, sizeof(buf)); buf[HB(0)] = 0x84; buf[HB(1)] = 0x01; buf[HB(2)] = 10; - buf[PB(0)] = 0; buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */ buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */ buf[PB(4)] = p->audio_frame[4]; @@ -824,6 +824,11 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, } div = 148500 / mode->clock; + if (div != 0) { + div--; + if (div > 3) + div = 3; + } /* mute the audio FIFO: */ reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO); @@ -913,7 +918,7 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder, if (priv->rev == TDA19988) { /* let incoming pixels fill the active space (if any) */ - reg_write(encoder, REG_ENABLE_SPACE, 0x01); + reg_write(encoder, REG_ENABLE_SPACE, 0x00); } /* must be last register set: */ @@ -1094,6 +1099,8 @@ tda998x_encoder_destroy(struct drm_encoder *encoder) { struct tda998x_priv *priv = to_tda998x_priv(encoder); drm_i2c_encoder_destroy(encoder); + if (priv->cec) + i2c_unregister_device(priv->cec); kfree(priv); } @@ -1142,8 +1149,12 @@ tda998x_encoder_init(struct i2c_client *client, priv->vip_cntrl_1 = VIP_CNTRL_1_SWAP_C(0) | VIP_CNTRL_1_SWAP_D(1); priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5); - priv->current_page = 0; + priv->current_page = 0xff; priv->cec = i2c_new_dummy(client->adapter, 0x34); + if (!priv->cec) { + kfree(priv); + return -ENODEV; + } priv->dpms = DRM_MODE_DPMS_OFF; encoder_slave->slave_priv = priv; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4a2bf8e3f739..df77e20e3c3d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1831,6 +1831,14 @@ struct drm_i915_file_private { /* Early gen2 have a totally busted CS tlb and require pinned batches. */ #define HAS_BROKEN_CS_TLB(dev) (IS_I830(dev) || IS_845G(dev)) +/* + * dp aux and gmbus irq on gen4 seems to be able to generate legacy interrupts + * even when in MSI mode. This results in spurious interrupt warnings if the + * legacy irq no. is shared with another device. The kernel then disables that + * interrupt source and so prevents the other device from working properly. + */ +#define HAS_AUX_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) +#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) /* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c index d7fd2fd2f0a5..990cf8f43efd 100644 --- a/drivers/gpu/drm/i915/i915_gpu_error.c +++ b/drivers/gpu/drm/i915/i915_gpu_error.c @@ -146,7 +146,10 @@ static void i915_error_vprintf(struct drm_i915_error_state_buf *e, va_list tmp; va_copy(tmp, args); - if (!__i915_error_seek(e, vsnprintf(NULL, 0, f, tmp))) + len = vsnprintf(NULL, 0, f, tmp); + va_end(tmp); + + if (!__i915_error_seek(e, len)) return; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 17d8fcb1b6f7..9fec71175571 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -567,8 +567,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) vbl_start = mode->crtc_vblank_start * mode->crtc_htotal; } else { - enum transcoder cpu_transcoder = - intel_pipe_to_cpu_transcoder(dev_priv, pipe); + enum transcoder cpu_transcoder = (enum transcoder) pipe; u32 htotal; htotal = ((I915_READ(HTOTAL(cpu_transcoder)) >> 16) & 0x1fff) + 1; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9fa24347963a..4c1672809493 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -8586,6 +8586,20 @@ static int intel_gen7_queue_flip(struct drm_device *dev, if (ring->id == RCS) len += 6; + /* + * BSpec MI_DISPLAY_FLIP for IVB: + * "The full packet must be contained within the same cache line." + * + * Currently the LRI+SRM+MI_DISPLAY_FLIP all fit within the same + * cacheline, if we ever start emitting more commands before + * the MI_DISPLAY_FLIP we may need to first emit everything else, + * then do the cacheline alignment, and finally emit the + * MI_DISPLAY_FLIP. + */ + ret = intel_ring_cacheline_align(ring); + if (ret) + goto err_unpin; + ret = intel_ring_begin(ring, len); if (ret) goto err_unpin; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ede4e8e290d..57552eb386b0 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp, int i, ret, recv_bytes; uint32_t status; int try, precharge, clock = 0; - bool has_aux_irq = true; + bool has_aux_irq = HAS_AUX_IRQ(dev); uint32_t timeout; /* dp aux is extremely sensitive to irq latency, hence request the @@ -537,6 +537,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp, uint8_t msg[20]; int msg_bytes; uint8_t ack; + int retry; if (WARN_ON(send_bytes > 16)) return -E2BIG; @@ -548,19 +549,21 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp, msg[3] = send_bytes - 1; memcpy(&msg[4], send, send_bytes); msg_bytes = send_bytes + 4; - for (;;) { + for (retry = 0; retry < 7; retry++) { ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1); if (ret < 0) return ret; ack >>= 4; if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) - break; + return send_bytes; else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) - udelay(100); + usleep_range(400, 500); else return -EIO; } - return send_bytes; + + DRM_ERROR("too many retries, giving up\n"); + return -EIO; } /* Write a single byte to the aux channel in native mode */ @@ -582,6 +585,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp, int reply_bytes; uint8_t ack; int ret; + int retry; if (WARN_ON(recv_bytes > 19)) return -E2BIG; @@ -595,7 +599,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp, msg_bytes = 4; reply_bytes = recv_bytes + 1; - for (;;) { + for (retry = 0; retry < 7; retry++) { ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, reply, reply_bytes); if (ret == 0) @@ -608,10 +612,13 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp, return ret - 1; } else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) - udelay(100); + usleep_range(400, 500); else return -EIO; } + + DRM_ERROR("too many retries, giving up\n"); + return -EIO; } static int @@ -1869,10 +1876,12 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder) mutex_unlock(&dev_priv->dpio_lock); - /* init power sequencer on this pipe and port */ - intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); - intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, - &power_seq); + if (is_edp(intel_dp)) { + /* init power sequencer on this pipe and port */ + intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); + intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, + &power_seq); + } intel_enable_dp(encoder); diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index b1dc33f47899..d33b61d0dd33 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -258,13 +258,6 @@ intel_gpio_setup(struct intel_gmbus *bus, u32 pin) algo->data = bus; } -/* - * gmbus on gen4 seems to be able to generate legacy interrupts even when in MSI - * mode. This results in spurious interrupt warnings if the legacy irq no. is - * shared with another device. The kernel then disables that interrupt source - * and so prevents the other device from working properly. - */ -#define HAS_GMBUS_IRQ(dev) (INTEL_INFO(dev)->gen >= 5) static int gmbus_wait_hw_status(struct drm_i915_private *dev_priv, u32 gmbus2_status, diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 4e960ec7419f..acde2945eb8a 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -226,6 +226,8 @@ struct opregion_asle { #define ACPI_DIGITAL_OUTPUT (3<<8) #define ACPI_LVDS_OUTPUT (4<<8) +#define MAX_DSLP 1500 + #ifdef CONFIG_ACPI static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) { @@ -260,10 +262,11 @@ static int swsci(struct drm_device *dev, u32 function, u32 parm, u32 *parm_out) /* The spec says 2ms should be the default, but it's too small * for some machines. */ dslp = 50; - } else if (dslp > 500) { + } else if (dslp > MAX_DSLP) { /* Hey bios, trust must be earned. */ - WARN_ONCE(1, "excessive driver sleep timeout (DSPL) %u\n", dslp); - dslp = 500; + DRM_INFO_ONCE("ACPI BIOS requests an excessive sleep of %u ms, " + "using %u ms instead\n", dslp, MAX_DSLP); + dslp = MAX_DSLP; } /* The spec tells us to do this, but we are the only user... */ diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b7f1742caf87..31b36c5ac894 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1653,6 +1653,27 @@ int intel_ring_begin(struct intel_ring_buffer *ring, return 0; } +/* Align the ring tail to a cacheline boundary */ +int intel_ring_cacheline_align(struct intel_ring_buffer *ring) +{ + int num_dwords = (64 - (ring->tail & 63)) / sizeof(uint32_t); + int ret; + + if (num_dwords == 0) + return 0; + + ret = intel_ring_begin(ring, num_dwords); + if (ret) + return ret; + + while (num_dwords--) + intel_ring_emit(ring, MI_NOOP); + + intel_ring_advance(ring); + + return 0; +} + void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno) { struct drm_i915_private *dev_priv = ring->dev->dev_private; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 71a73f4fe252..0b243ce33714 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -233,6 +233,7 @@ intel_write_status_page(struct intel_ring_buffer *ring, void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring); int __must_check intel_ring_begin(struct intel_ring_buffer *ring, int n); +int __must_check intel_ring_cacheline_align(struct intel_ring_buffer *ring); static inline void intel_ring_emit(struct intel_ring_buffer *ring, u32 data) { diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index 1964f4f0d452..84c5b13b33c9 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -39,6 +39,7 @@ struct mdp4_crtc { spinlock_t lock; bool stale; uint32_t width, height; + uint32_t x, y; /* next cursor to scan-out: */ uint32_t next_iova; @@ -57,9 +58,16 @@ struct mdp4_crtc { #define PENDING_FLIP 0x2 atomic_t pending; - /* the fb that we currently hold a scanout ref to: */ + /* the fb that we logically (from PoV of KMS API) hold a ref + * to. Which we may not yet be scanning out (we may still + * be scanning out previous in case of page_flip while waiting + * for gpu rendering to complete: + */ struct drm_framebuffer *fb; + /* the fb that we currently hold a scanout ref to: */ + struct drm_framebuffer *scanout_fb; + /* for unref'ing framebuffers after scanout completes: */ struct drm_flip_work unref_fb_work; @@ -77,24 +85,73 @@ static struct mdp4_kms *get_kms(struct drm_crtc *crtc) return to_mdp4_kms(to_mdp_kms(priv->kms)); } -static void update_fb(struct drm_crtc *crtc, bool async, - struct drm_framebuffer *new_fb) +static void request_pending(struct drm_crtc *crtc, uint32_t pending) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct drm_framebuffer *old_fb = mdp4_crtc->fb; - if (old_fb) - drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb); + atomic_or(pending, &mdp4_crtc->pending); + mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); +} + +static void crtc_flush(struct drm_crtc *crtc) +{ + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); + uint32_t i, flush = 0; + + for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { + struct drm_plane *plane = mdp4_crtc->planes[i]; + if (plane) { + enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); + flush |= pipe2flush(pipe_id); + } + } + flush |= ovlp2flush(mdp4_crtc->ovlp); + + DBG("%s: flush=%08x", mdp4_crtc->name, flush); + + mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); +} + +static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb) +{ + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct drm_framebuffer *old_fb = mdp4_crtc->fb; /* grab reference to incoming scanout fb: */ drm_framebuffer_reference(new_fb); mdp4_crtc->base.fb = new_fb; mdp4_crtc->fb = new_fb; - if (!async) { - /* enable vblank to pick up the old_fb */ - mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); - } + if (old_fb) + drm_flip_work_queue(&mdp4_crtc->unref_fb_work, old_fb); +} + +/* unlike update_fb(), take a ref to the new scanout fb *before* updating + * plane, then call this. Needed to ensure we don't unref the buffer that + * is actually still being scanned out. + * + * Note that this whole thing goes away with atomic.. since we can defer + * calling into driver until rendering is done. + */ +static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb) +{ + struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + + /* flush updates, to make sure hw is updated to new scanout fb, + * so that we can safely queue unref to current fb (ie. next + * vblank we know hw is done w/ previous scanout_fb). + */ + crtc_flush(crtc); + + if (mdp4_crtc->scanout_fb) + drm_flip_work_queue(&mdp4_crtc->unref_fb_work, + mdp4_crtc->scanout_fb); + + mdp4_crtc->scanout_fb = fb; + + /* enable vblank to complete flip: */ + request_pending(crtc, PENDING_FLIP); } /* if file!=NULL, this is preclose potential cancel-flip path */ @@ -120,34 +177,6 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file) spin_unlock_irqrestore(&dev->event_lock, flags); } -static void crtc_flush(struct drm_crtc *crtc) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct mdp4_kms *mdp4_kms = get_kms(crtc); - uint32_t i, flush = 0; - - for (i = 0; i < ARRAY_SIZE(mdp4_crtc->planes); i++) { - struct drm_plane *plane = mdp4_crtc->planes[i]; - if (plane) { - enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane); - flush |= pipe2flush(pipe_id); - } - } - flush |= ovlp2flush(mdp4_crtc->ovlp); - - DBG("%s: flush=%08x", mdp4_crtc->name, flush); - - mdp4_write(mdp4_kms, REG_MDP4_OVERLAY_FLUSH, flush); -} - -static void request_pending(struct drm_crtc *crtc, uint32_t pending) -{ - struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - - atomic_or(pending, &mdp4_crtc->pending); - mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank); -} - static void pageflip_cb(struct msm_fence_cb *cb) { struct mdp4_crtc *mdp4_crtc = @@ -158,11 +187,9 @@ static void pageflip_cb(struct msm_fence_cb *cb) if (!fb) return; + drm_framebuffer_reference(fb); mdp4_plane_set_scanout(mdp4_crtc->plane, fb); - crtc_flush(crtc); - - /* enable vblank to complete flip: */ - request_pending(crtc, PENDING_FLIP); + update_scanout(crtc, fb); } static void unref_fb_worker(struct drm_flip_work *work, void *val) @@ -320,6 +347,20 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, mode->vsync_end, mode->vtotal, mode->type, mode->flags); + /* grab extra ref for update_scanout() */ + drm_framebuffer_reference(crtc->fb); + + ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb, + 0, 0, mode->hdisplay, mode->vdisplay, + x << 16, y << 16, + mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + drm_framebuffer_unreference(crtc->fb); + dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", + mdp4_crtc->name, ret); + return ret; + } + mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_SIZE(dma), MDP4_DMA_SRC_SIZE_WIDTH(mode->hdisplay) | MDP4_DMA_SRC_SIZE_HEIGHT(mode->vdisplay)); @@ -341,24 +382,15 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc, mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1); - update_fb(crtc, false, crtc->fb); - - ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb, - 0, 0, mode->hdisplay, mode->vdisplay, - x << 16, y << 16, - mode->hdisplay << 16, mode->vdisplay << 16); - if (ret) { - dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", - mdp4_crtc->name, ret); - return ret; - } - if (dma == DMA_E) { mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(0), 0x00ff0000); mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(1), 0x00ff0000); mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000); } + update_fb(crtc, crtc->fb); + update_scanout(crtc, crtc->fb); + return 0; } @@ -385,13 +417,24 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct drm_plane *plane = mdp4_crtc->plane; struct drm_display_mode *mode = &crtc->mode; + int ret; - update_fb(crtc, false, crtc->fb); + /* grab extra ref for update_scanout() */ + drm_framebuffer_reference(crtc->fb); - return mdp4_plane_mode_set(plane, crtc, crtc->fb, + ret = mdp4_plane_mode_set(plane, crtc, crtc->fb, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + drm_framebuffer_unreference(crtc->fb); + return ret; + } + + update_fb(crtc, crtc->fb); + update_scanout(crtc, crtc->fb); + + return 0; } static void mdp4_crtc_load_lut(struct drm_crtc *crtc) @@ -419,7 +462,7 @@ static int mdp4_crtc_page_flip(struct drm_crtc *crtc, mdp4_crtc->event = event; spin_unlock_irqrestore(&dev->event_lock, flags); - update_fb(crtc, true, new_fb); + update_fb(crtc, new_fb); return msm_gem_queue_inactive_cb(obj, &mdp4_crtc->pageflip_cb); } @@ -442,12 +485,12 @@ static int mdp4_crtc_set_property(struct drm_crtc *crtc, static void update_cursor(struct drm_crtc *crtc) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); + struct mdp4_kms *mdp4_kms = get_kms(crtc); enum mdp4_dma dma = mdp4_crtc->dma; unsigned long flags; spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); if (mdp4_crtc->cursor.stale) { - struct mdp4_kms *mdp4_kms = get_kms(crtc); struct drm_gem_object *next_bo = mdp4_crtc->cursor.next_bo; struct drm_gem_object *prev_bo = mdp4_crtc->cursor.scanout_bo; uint32_t iova = mdp4_crtc->cursor.next_iova; @@ -479,6 +522,11 @@ static void update_cursor(struct drm_crtc *crtc) mdp4_crtc->cursor.scanout_bo = next_bo; mdp4_crtc->cursor.stale = false; } + + mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma), + MDP4_DMA_CURSOR_POS_X(mdp4_crtc->cursor.x) | + MDP4_DMA_CURSOR_POS_Y(mdp4_crtc->cursor.y)); + spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); } @@ -530,6 +578,7 @@ static int mdp4_crtc_cursor_set(struct drm_crtc *crtc, drm_gem_object_unreference_unlocked(old_bo); } + crtc_flush(crtc); request_pending(crtc, PENDING_CURSOR); return 0; @@ -542,12 +591,15 @@ fail: static int mdp4_crtc_cursor_move(struct drm_crtc *crtc, int x, int y) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); - struct mdp4_kms *mdp4_kms = get_kms(crtc); - enum mdp4_dma dma = mdp4_crtc->dma; + unsigned long flags; - mdp4_write(mdp4_kms, REG_MDP4_DMA_CURSOR_POS(dma), - MDP4_DMA_CURSOR_POS_X(x) | - MDP4_DMA_CURSOR_POS_Y(y)); + spin_lock_irqsave(&mdp4_crtc->cursor.lock, flags); + mdp4_crtc->cursor.x = x; + mdp4_crtc->cursor.y = y; + spin_unlock_irqrestore(&mdp4_crtc->cursor.lock, flags); + + crtc_flush(crtc); + request_pending(crtc, PENDING_CURSOR); return 0; } @@ -713,6 +765,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev, crtc = &mdp4_crtc->base; mdp4_crtc->plane = plane; + mdp4_crtc->id = id; mdp4_crtc->ovlp = ovlp_id; mdp4_crtc->dma = dma_id; diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c index 2406027200ec..1e893dd13859 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c @@ -170,8 +170,8 @@ int mdp4_plane_mode_set(struct drm_plane *plane, MDP4_PIPE_DST_SIZE_HEIGHT(crtc_h)); mdp4_write(mdp4_kms, REG_MDP4_PIPE_DST_XY(pipe), - MDP4_PIPE_SRC_XY_X(crtc_x) | - MDP4_PIPE_SRC_XY_Y(crtc_y)); + MDP4_PIPE_DST_XY_X(crtc_x) | + MDP4_PIPE_DST_XY_Y(crtc_y)); mdp4_plane_set_scanout(plane, fb); diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index 71a3b2345eb3..f2794021f086 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -296,6 +296,7 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); if (ret) { + drm_framebuffer_unreference(crtc->fb); dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n", mdp5_crtc->name, ret); return ret; @@ -343,11 +344,15 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y, 0, 0, mode->hdisplay, mode->vdisplay, x << 16, y << 16, mode->hdisplay << 16, mode->vdisplay << 16); + if (ret) { + drm_framebuffer_unreference(crtc->fb); + return ret; + } update_fb(crtc, crtc->fb); update_scanout(crtc, crtc->fb); - return ret; + return 0; } static void mdp5_crtc_load_lut(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index d8d60c969ac7..3da8264d3039 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -644,7 +644,7 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev, fail: if (obj) - drm_gem_object_unreference_unlocked(obj); + drm_gem_object_unreference(obj); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/msm/msm_gem_submit.c b/drivers/gpu/drm/msm/msm_gem_submit.c index 5281d4bc37f7..5423e914e491 100644 --- a/drivers/gpu/drm/msm/msm_gem_submit.c +++ b/drivers/gpu/drm/msm/msm_gem_submit.c @@ -163,7 +163,7 @@ retry: /* if locking succeeded, pin bo: */ - ret = msm_gem_get_iova(&msm_obj->base, + ret = msm_gem_get_iova_locked(&msm_obj->base, submit->gpu->id, &iova); /* this would break the logic in the fail path.. there is no @@ -247,7 +247,7 @@ static int submit_reloc(struct msm_gem_submit *submit, struct msm_gem_object *ob /* For now, just map the entire thing. Eventually we probably * to do it page-by-page, w/ kmap() if not vmap()d.. */ - ptr = msm_gem_vaddr(&obj->base); + ptr = msm_gem_vaddr_locked(&obj->base); if (IS_ERR(ptr)) { ret = PTR_ERR(ptr); @@ -307,14 +307,12 @@ static void submit_cleanup(struct msm_gem_submit *submit, bool fail) { unsigned i; - mutex_lock(&submit->dev->struct_mutex); for (i = 0; i < submit->nr_bos; i++) { struct msm_gem_object *msm_obj = submit->bos[i].obj; submit_unlock_unpin_bo(submit, i); list_del_init(&msm_obj->submit_entry); drm_gem_object_unreference(&msm_obj->base); } - mutex_unlock(&submit->dev->struct_mutex); ww_acquire_fini(&submit->ticket); kfree(submit); @@ -342,6 +340,8 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, if (args->nr_cmds > MAX_CMDS) return -EINVAL; + mutex_lock(&dev->struct_mutex); + submit = submit_create(dev, gpu, args->nr_bos); if (!submit) { ret = -ENOMEM; @@ -410,5 +410,6 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data, out: if (submit) submit_cleanup(submit, !!ret); + mutex_unlock(&dev->struct_mutex); return ret; } diff --git a/drivers/gpu/drm/msm/msm_gpu.c b/drivers/gpu/drm/msm/msm_gpu.c index 4ebce8be489d..0cfe3f426ee4 100644 --- a/drivers/gpu/drm/msm/msm_gpu.c +++ b/drivers/gpu/drm/msm/msm_gpu.c @@ -298,8 +298,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, struct msm_drm_private *priv = dev->dev_private; int i, ret; - mutex_lock(&dev->struct_mutex); - submit->fence = ++priv->next_fence; gpu->submitted_fence = submit->fence; @@ -331,7 +329,6 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit, msm_gem_move_to_active(&msm_obj->base, gpu, true, submit->fence); } hangcheck_timer_reset(gpu); - mutex_unlock(&dev->struct_mutex); return ret; } diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile index e88145ba1bf5..d310c195bdfe 100644 --- a/drivers/gpu/drm/nouveau/Makefile +++ b/drivers/gpu/drm/nouveau/Makefile @@ -141,6 +141,7 @@ nouveau-y += core/subdev/mc/base.o nouveau-y += core/subdev/mc/nv04.o nouveau-y += core/subdev/mc/nv40.o nouveau-y += core/subdev/mc/nv44.o +nouveau-y += core/subdev/mc/nv4c.o nouveau-y += core/subdev/mc/nv50.o nouveau-y += core/subdev/mc/nv94.o nouveau-y += core/subdev/mc/nv98.o diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c index 1b653dd74a70..08b88591ed60 100644 --- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c @@ -311,7 +311,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -334,7 +334,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass; @@ -357,7 +357,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -380,7 +380,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -403,7 +403,7 @@ nv40_identify(struct nouveau_device *device) device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 940eaa5d8b9a..9ad722e4e087 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -1142,7 +1142,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) if (conf != ~0) { if (outp.location == 0 && outp.type == DCB_OUTPUT_DP) { u32 soff = (ffs(outp.or) - 1) * 0x08; - u32 ctrl = nv_rd32(priv, 0x610798 + soff); + u32 ctrl = nv_rd32(priv, 0x610794 + soff); u32 datarate; switch ((ctrl & 0x000f0000) >> 16) { diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c index 9a850fe19515..54c1b5b471cd 100644 --- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c +++ b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c @@ -112,7 +112,7 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine) nv_wr32(priv, 0x002270, cur->addr >> 12); nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); - if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000)) + if (!nv_wait(priv, 0x002284 + (engine * 8), 0x00100000, 0x00000000)) nv_error(priv, "runlist %d update timeout\n", engine); mutex_unlock(&nv_subdev(priv)->mutex); } diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c index 30ed19c52e05..7a367c402978 100644 --- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c @@ -539,7 +539,7 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old, ustatus &= ~0x04030000; } if (ustatus && display) { - nv_error("%s - TP%d:", name, i); + nv_error(priv, "%s - TP%d:", name, i); nouveau_bitfield_print(nv50_mpc_traps, ustatus); pr_cont("\n"); ustatus = 0; diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h index adc88b73d911..3c6738edd127 100644 --- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h @@ -47,6 +47,7 @@ struct nouveau_mc_oclass { extern struct nouveau_oclass *nv04_mc_oclass; extern struct nouveau_oclass *nv40_mc_oclass; extern struct nouveau_oclass *nv44_mc_oclass; +extern struct nouveau_oclass *nv4c_mc_oclass; extern struct nouveau_oclass *nv50_mc_oclass; extern struct nouveau_oclass *nv94_mc_oclass; extern struct nouveau_oclass *nv98_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c index aa0fbbec7f08..ef0c9c4a8cc3 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c @@ -130,6 +130,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios) u16 pcir; int i; + /* there is no prom on nv4x IGP's */ + if (device->card_type == NV_40 && device->chipset >= 0x4c) + return; + /* enable access to rom */ if (device->card_type >= NV_50) pcireg = 0x088050; diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c index 9159a5ccee93..265d1253624a 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c +++ b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c @@ -36,7 +36,7 @@ nv1a_fb_oclass = &(struct nv04_fb_impl) { .fini = _nouveau_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv10_ram_oclass, + .base.ram = &nv1a_ram_oclass, .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h index b0d5c31606c1..81a408e7d034 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h @@ -14,6 +14,7 @@ int nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *, extern const struct nouveau_mc_intr nv04_mc_intr[]; int nv04_mc_init(struct nouveau_object *); void nv40_mc_msi_rearm(struct nouveau_mc *); +int nv44_mc_init(struct nouveau_object *object); int nv50_mc_init(struct nouveau_object *); extern const struct nouveau_mc_intr nv50_mc_intr[]; extern const struct nouveau_mc_intr nvc0_mc_intr[]; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c index 3bfee5c6c4f2..cc4d0d2d886e 100644 --- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c @@ -24,7 +24,7 @@ #include "nv04.h" -static int +int nv44_mc_init(struct nouveau_object *object) { struct nv04_mc_priv *priv = (void *)object; diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c new file mode 100644 index 000000000000..a75c35ccf25c --- /dev/null +++ b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c @@ -0,0 +1,45 @@ +/* + * Copyright 2014 Ilia Mirkin + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: Ilia Mirkin + */ + +#include "nv04.h" + +static void +nv4c_mc_msi_rearm(struct nouveau_mc *pmc) +{ + struct nv04_mc_priv *priv = (void *)pmc; + nv_wr08(priv, 0x088050, 0xff); +} + +struct nouveau_oclass * +nv4c_mc_oclass = &(struct nouveau_mc_oclass) { + .base.handle = NV_SUBDEV(MC, 0x4c), + .base.ofuncs = &(struct nouveau_ofuncs) { + .ctor = nv04_mc_ctor, + .dtor = _nouveau_mc_dtor, + .init = nv44_mc_init, + .fini = _nouveau_mc_fini, + }, + .intr = nv04_mc_intr, + .msi_rearm = nv4c_mc_msi_rearm, +}.base; diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 4ef83df2b246..83face3f608f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -106,6 +106,29 @@ static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t * return 0; } +/* + * On some platforms, _DSM(nouveau_op_dsm_muid, func0) has special + * requirements on the fourth parameter, so a private implementation + * instead of using acpi_check_dsm(). + */ +static int nouveau_check_optimus_dsm(acpi_handle handle) +{ + int result; + + /* + * Function 0 returns a Buffer containing available functions. + * The args parameter is ignored for function 0, so just put 0 in it + */ + if (nouveau_optimus_dsm(handle, 0, 0, &result)) + return 0; + + /* + * ACPI Spec v4 9.14.1: if bit 0 is zero, no function is supported. + * If the n-th bit is enabled, function n is supported + */ + return result & 1 && result & (1 << NOUVEAU_DSM_OPTIMUS_CAPS); +} + static int nouveau_dsm(acpi_handle handle, int func, int arg) { int ret = 0; @@ -207,8 +230,7 @@ static int nouveau_dsm_pci_probe(struct pci_dev *pdev) 1 << NOUVEAU_DSM_POWER)) retval |= NOUVEAU_DSM_HAS_MUX; - if (acpi_check_dsm(dhandle, nouveau_op_dsm_muid, 0x00000100, - 1 << NOUVEAU_DSM_OPTIMUS_CAPS)) + if (nouveau_check_optimus_dsm(dhandle)) retval |= NOUVEAU_DSM_HAS_OPT; if (retval & NOUVEAU_DSM_HAS_OPT) { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 488686d490c0..4aed1714b9ab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1249,7 +1249,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) mem->bus.is_iomem = !dev->agp->cant_use_aperture; } #endif - if (!node->memtype) + if (nv_device(drm->device)->card_type < NV_50 || !node->memtype) /* untiled */ break; /* fallthrough, tiled memory */ diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 78c8e7146d56..89c484d8ac26 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -376,6 +376,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) if (ret) goto fail_device; + dev->irq_enabled = true; + /* workaround an odd issue on nvc1 by disabling the device's * nosnoop capability. hopefully won't cause issues until a * better fix is found - assuming there is one... @@ -475,6 +477,7 @@ nouveau_drm_remove(struct pci_dev *pdev) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_object *device; + dev->irq_enabled = false; device = drm->client.base.device; drm_put_dev(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index 81638d7f2eff..471347edc27e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -14,7 +14,9 @@ nouveau_vga_set_decode(void *priv, bool state) { struct nouveau_device *device = nouveau_dev(priv); - if (device->chipset >= 0x40) + if (device->card_type == NV_40 && device->chipset >= 0x4c) + nv_wr32(device, 0x088060, state); + else if (device->chipset >= 0x40) nv_wr32(device, 0x088054, state); else nv_wr32(device, 0x001854, state); diff --git a/drivers/gpu/drm/radeon/atombios_crtc.c b/drivers/gpu/drm/radeon/atombios_crtc.c index a9338c85630f..daa4dd375ab1 100644 --- a/drivers/gpu/drm/radeon/atombios_crtc.c +++ b/drivers/gpu/drm/radeon/atombios_crtc.c @@ -559,7 +559,7 @@ static u32 atombios_adjust_pll(struct drm_crtc *crtc, u32 adjusted_clock = mode->clock; int encoder_mode = atombios_get_encoder_mode(encoder); u32 dp_clock = mode->clock; - int bpc = radeon_get_monitor_bpc(connector); + int bpc = radeon_crtc->bpc; bool is_duallink = radeon_dig_monitor_is_duallink(encoder, mode->clock); /* reset the pll flags */ @@ -1176,7 +1176,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, evergreen_tiling_fields(tiling_flags, &bankw, &bankh, &mtaspect, &tile_split); /* Set NUM_BANKS. */ - if (rdev->family >= CHIP_BONAIRE) { + if (rdev->family >= CHIP_TAHITI) { unsigned tileb, index, num_banks, tile_split_bytes; /* Calculate the macrotile mode index. */ @@ -1194,13 +1194,14 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc, return -EINVAL; } - num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; + if (rdev->family >= CHIP_BONAIRE) + num_banks = (rdev->config.cik.macrotile_mode_array[index] >> 6) & 0x3; + else + num_banks = (rdev->config.si.tile_mode_array[index] >> 20) & 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) + /* NI and older. */ + if (rdev->family >= CHIP_CAYMAN) tmp = rdev->config.cayman.tile_config; else tmp = rdev->config.evergreen.tile_config; @@ -1773,6 +1774,20 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) return ATOM_PPLL1; DRM_ERROR("unable to allocate a PPLL\n"); return ATOM_PPLL_INVALID; + } else if (ASIC_IS_DCE41(rdev)) { + /* Don't share PLLs on DCE4.1 chips */ + if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(radeon_crtc->encoder))) { + if (rdev->clock.dp_extclk) + /* skip PPLL programming if using ext clock */ + return ATOM_PPLL_INVALID; + } + pll_in_use = radeon_get_pll_use_mask(crtc); + if (!(pll_in_use & (1 << ATOM_PPLL1))) + return ATOM_PPLL1; + if (!(pll_in_use & (1 << ATOM_PPLL2))) + return ATOM_PPLL2; + DRM_ERROR("unable to allocate a PPLL\n"); + return ATOM_PPLL_INVALID; } else if (ASIC_IS_DCE4(rdev)) { /* in DP mode, the DP ref clock can come from PPLL, DCPLL, or ext clock, * depending on the asic: @@ -1800,7 +1815,7 @@ static int radeon_atom_pick_pll(struct drm_crtc *crtc) if (pll != ATOM_PPLL_INVALID) return pll; } - } else if (!ASIC_IS_DCE41(rdev)) { /* Don't share PLLs on DCE4.1 chips */ + } else { /* use the same PPLL for all monitors with the same clock */ pll = radeon_get_shared_nondp_ppll(crtc); if (pll != ATOM_PPLL_INVALID) diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c index a42d61571f49..2cec2ab02f80 100644 --- a/drivers/gpu/drm/radeon/atombios_encoders.c +++ b/drivers/gpu/drm/radeon/atombios_encoders.c @@ -464,11 +464,12 @@ atombios_tv_setup(struct drm_encoder *encoder, int action) static u8 radeon_atom_get_bpc(struct drm_encoder *encoder) { - struct drm_connector *connector = radeon_get_connector_for_encoder(encoder); int bpc = 8; - if (connector) - bpc = radeon_get_monitor_bpc(connector); + if (encoder->crtc) { + struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc); + bpc = radeon_crtc->bpc; + } switch (bpc) { case 0: diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c index 0fbd36f3d4e9..ea103ccdf4bd 100644 --- a/drivers/gpu/drm/radeon/btc_dpm.c +++ b/drivers/gpu/drm/radeon/btc_dpm.c @@ -29,6 +29,7 @@ #include "cypress_dpm.h" #include "btc_dpm.h" #include "atom.h" +#include <linux/seq_file.h> #define MC_CG_ARB_FREQ_F0 0x0a #define MC_CG_ARB_FREQ_F1 0x0b @@ -2756,6 +2757,37 @@ void btc_dpm_fini(struct radeon_device *rdev) r600_free_extended_power_table(rdev); } +void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m) +{ + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; + struct rv7xx_ps *ps = rv770_get_ps(rps); + struct rv7xx_pl *pl; + u32 current_index = + (RREG32(TARGET_AND_CURRENT_PROFILE_INDEX) & CURRENT_PROFILE_INDEX_MASK) >> + CURRENT_PROFILE_INDEX_SHIFT; + + if (current_index > 2) { + seq_printf(m, "invalid dpm profile %d\n", current_index); + } else { + if (current_index == 0) + pl = &ps->low; + else if (current_index == 1) + pl = &ps->medium; + else /* current_index == 2 */ + pl = &ps->high; + seq_printf(m, "uvd vclk: %d dclk: %d\n", rps->vclk, rps->dclk); + if (rdev->family >= CHIP_CEDAR) { + seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u vddci: %u\n", + current_index, pl->sclk, pl->mclk, pl->vddc, pl->vddci); + } else { + seq_printf(m, "power level %d sclk: %u mclk: %u vddc: %u\n", + current_index, pl->sclk, pl->mclk, pl->vddc); + } + } +} + u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low) { struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); diff --git a/drivers/gpu/drm/radeon/btcd.h b/drivers/gpu/drm/radeon/btcd.h index 29e32de7e025..9c65be2d55a9 100644 --- a/drivers/gpu/drm/radeon/btcd.h +++ b/drivers/gpu/drm/radeon/btcd.h @@ -44,6 +44,10 @@ # define DYN_SPREAD_SPECTRUM_EN (1 << 23) # define AC_DC_SW (1 << 24) +#define TARGET_AND_CURRENT_PROFILE_INDEX 0x66c +# define CURRENT_PROFILE_INDEX_MASK (0xf << 4) +# define CURRENT_PROFILE_INDEX_SHIFT 4 + #define CG_BIF_REQ_AND_RSP 0x7f4 #define CG_CLIENT_REQ(x) ((x) << 0) #define CG_CLIENT_REQ_MASK (0xff << 0) diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c index 713a5d359901..94e858751994 100644 --- a/drivers/gpu/drm/radeon/dce6_afmt.c +++ b/drivers/gpu/drm/radeon/dce6_afmt.c @@ -278,13 +278,15 @@ static int dce6_audio_chipset_supported(struct radeon_device *rdev) return !ASIC_IS_NODCE(rdev); } -static void dce6_audio_enable(struct radeon_device *rdev, - struct r600_audio_pin *pin, - bool enable) +void dce6_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, + bool enable) { + if (!pin) + return; + WREG32_ENDPOINT(pin->offset, AZ_F0_CODEC_PIN_CONTROL_HOTPLUG_CONTROL, - AUDIO_ENABLED); - DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id); + enable ? AUDIO_ENABLED : 0); } static const u32 pin_offsets[7] = @@ -323,7 +325,8 @@ int dce6_audio_init(struct radeon_device *rdev) rdev->audio.pin[i].connected = false; rdev->audio.pin[i].offset = pin_offsets[i]; rdev->audio.pin[i].id = i; - dce6_audio_enable(rdev, &rdev->audio.pin[i], true); + /* disable audio. it will be set up later */ + dce6_audio_enable(rdev, &rdev->audio.pin[i], false); } return 0; diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c index f2b9e21ce4da..8a2c010b7dc5 100644 --- a/drivers/gpu/drm/radeon/evergreen.c +++ b/drivers/gpu/drm/radeon/evergreen.c @@ -1680,7 +1680,7 @@ bool evergreen_hpd_sense(struct radeon_device *rdev, enum radeon_hpd_id hpd) case RADEON_HPD_6: if (RREG32(DC_HPD6_INT_STATUS) & DC_HPDx_SENSE) connected = true; - break; + break; default: break; } @@ -5475,9 +5475,9 @@ void evergreen_fini(struct radeon_device *rdev) radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); - evergreen_pcie_gart_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); + evergreen_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c index 0c6d5cef4cf1..05b0c95813fd 100644 --- a/drivers/gpu/drm/radeon/evergreen_hdmi.c +++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c @@ -306,6 +306,15 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode return; offset = dig->afmt->offset; + /* disable audio prior to setting up hw */ + if (ASIC_IS_DCE6(rdev)) { + dig->afmt->pin = dce6_audio_get_pin(rdev); + dce6_audio_enable(rdev, dig->afmt->pin, false); + } else { + dig->afmt->pin = r600_audio_get_pin(rdev); + r600_audio_enable(rdev, dig->afmt->pin, false); + } + evergreen_audio_set_dto(encoder, mode->clock); WREG32(HDMI_VBI_PACKET_CONTROL + offset, @@ -409,12 +418,16 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF); WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001); WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001); + + /* enable audio after to setting up hw */ + if (ASIC_IS_DCE6(rdev)) + dce6_audio_enable(rdev, dig->afmt->pin, true); + else + r600_audio_enable(rdev, dig->afmt->pin, true); } void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) { - struct drm_device *dev = encoder->dev; - struct radeon_device *rdev = dev->dev_private; struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder); struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv; @@ -427,15 +440,6 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable) if (!enable && !dig->afmt->enabled) return; - if (enable) { - if (ASIC_IS_DCE6(rdev)) - dig->afmt->pin = dce6_audio_get_pin(rdev); - else - dig->afmt->pin = r600_audio_get_pin(rdev); - } else { - dig->afmt->pin = NULL; - } - dig->afmt->enabled = enable; DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n", diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c index b6e01d5d2cce..351db361239d 100644 --- a/drivers/gpu/drm/radeon/kv_dpm.c +++ b/drivers/gpu/drm/radeon/kv_dpm.c @@ -1223,7 +1223,7 @@ int kv_dpm_enable(struct radeon_device *rdev) int kv_dpm_late_enable(struct radeon_device *rdev) { - int ret; + int ret = 0; if (rdev->irq.installed && r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) { diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c index c351226ecb31..ca814276b075 100644 --- a/drivers/gpu/drm/radeon/ni_dpm.c +++ b/drivers/gpu/drm/radeon/ni_dpm.c @@ -2588,7 +2588,7 @@ static int ni_populate_sq_ramping_values(struct radeon_device *rdev, if (NISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT)) enable_sq_ramping = false; - if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) + if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) enable_sq_ramping = false; for (i = 0; i < state->performance_level_count; i++) { @@ -3945,7 +3945,6 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev, struct rv7xx_power_info *pi = rv770_get_pi(rdev); struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); struct ni_ps *ps = ni_get_ps(rps); - u16 vddc; struct rv7xx_pl *pl = &ps->performance_levels[index]; ps->performance_level_count = index + 1; @@ -3961,8 +3960,8 @@ static void ni_parse_pplib_clock_info(struct radeon_device *rdev, /* patch up vddc if necessary */ if (pl->vddc == 0xff01) { - if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) - pl->vddc = vddc; + if (pi->max_vddc) + pl->vddc = pi->max_vddc; } if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { @@ -4322,7 +4321,8 @@ void ni_dpm_print_power_state(struct radeon_device *rdev, void ni_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; struct ni_ps *ps = ni_get_ps(rps); struct rv7xx_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c index 56140b4e5bb2..cdbc4171fe73 100644 --- a/drivers/gpu/drm/radeon/r600.c +++ b/drivers/gpu/drm/radeon/r600.c @@ -3991,6 +3991,10 @@ restart_ih: break; } break; + case 124: /* UVD */ + DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); + radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); + break; case 176: /* CP_INT in ring buffer */ case 177: /* CP_INT in IB1 */ case 178: /* CP_INT in IB2 */ diff --git a/drivers/gpu/drm/radeon/r600_audio.c b/drivers/gpu/drm/radeon/r600_audio.c index 47fc2b886979..bffac10c4296 100644 --- a/drivers/gpu/drm/radeon/r600_audio.c +++ b/drivers/gpu/drm/radeon/r600_audio.c @@ -142,12 +142,15 @@ void r600_audio_update_hdmi(struct work_struct *work) } /* enable the audio stream */ -static void r600_audio_enable(struct radeon_device *rdev, - struct r600_audio_pin *pin, - bool enable) +void r600_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, + bool enable) { u32 value = 0; + if (!pin) + return; + if (ASIC_IS_DCE4(rdev)) { if (enable) { value |= 0x81000000; /* Required to enable audio */ @@ -158,7 +161,6 @@ static void r600_audio_enable(struct radeon_device *rdev, WREG32_P(R600_AUDIO_ENABLE, enable ? 0x81000000 : 0x0, ~0x81000000); } - DRM_INFO("%s audio %d support\n", enable ? "Enabling" : "Disabling", pin->id); } /* @@ -178,8 +180,8 @@ int r600_audio_init(struct radeon_device *rdev) rdev->audio.pin[0].status_bits = 0; rdev->audio.pin[0].category_code = 0; rdev->audio.pin[0].id = 0; - - r600_audio_enable(rdev, &rdev->audio.pin[0], true); + /* disable audio. it will be set up later */ + r600_audio_enable(rdev, &rdev->audio.pin[0], false); return 0; } diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c index 3016fc14f502..85a2bb28aed2 100644 --- a/drivers/gpu/drm/radeon/r600_hdmi.c +++ b/drivers/gpu/drm/radeon/r600_hdmi.c @@ -329,9 +329,6 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder) u8 *sadb; int sad_count; - /* XXX: setting this register causes hangs on some asics */ - return; - list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) { if (connector->encoder == encoder) { radeon_connector = to_radeon_connector(connector); @@ -460,6 +457,10 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod return; offset = dig->afmt->offset; + /* disable audio prior to setting up hw */ + dig->afmt->pin = r600_audio_get_pin(rdev); + r600_audio_enable(rdev, dig->afmt->pin, false); + r600_audio_set_dto(encoder, mode->clock); WREG32(HDMI0_VBI_PACKET_CONTROL + offset, @@ -531,6 +532,9 @@ void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mod WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001); r600_hdmi_audio_workaround(encoder); + + /* enable audio after to setting up hw */ + r600_audio_enable(rdev, dig->afmt->pin, true); } /* @@ -651,11 +655,6 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable) if (!enable && !dig->afmt->enabled) return; - if (enable) - dig->afmt->pin = r600_audio_get_pin(rdev); - else - dig->afmt->pin = NULL; - /* Older chipsets require setting HDMI and routing manually */ if (!ASIC_IS_DCE3(rdev)) { if (enable) diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h index 4a8ac1cd6b4c..e887d027b6d0 100644 --- a/drivers/gpu/drm/radeon/radeon.h +++ b/drivers/gpu/drm/radeon/radeon.h @@ -135,6 +135,9 @@ extern int radeon_hard_reset; /* R600+ */ #define R600_RING_TYPE_UVD_INDEX 5 +/* number of hw syncs before falling back on blocking */ +#define RADEON_NUM_SYNCS 4 + /* hardcode those limit for now */ #define RADEON_VA_IB_OFFSET (1 << 20) #define RADEON_VA_RESERVED_SIZE (8 << 20) @@ -554,7 +557,6 @@ int radeon_mode_dumb_mmap(struct drm_file *filp, /* * Semaphores. */ -/* everything here is constant */ struct radeon_semaphore { struct radeon_sa_bo *sa_bo; signed waiters; @@ -2745,6 +2747,12 @@ int radeon_vm_bo_rmv(struct radeon_device *rdev, void r600_audio_update_hdmi(struct work_struct *work); struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev); struct r600_audio_pin *dce6_audio_get_pin(struct radeon_device *rdev); +void r600_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, + bool enable); +void dce6_audio_enable(struct radeon_device *rdev, + struct r600_audio_pin *pin, + bool enable); /* * R600 vram scratch functions diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c index f74db43346fd..dda02bfc10a4 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.c +++ b/drivers/gpu/drm/radeon/radeon_asic.c @@ -1555,7 +1555,7 @@ static struct radeon_asic btc_asic = { .get_sclk = &btc_dpm_get_sclk, .get_mclk = &btc_dpm_get_mclk, .print_power_state = &rv770_dpm_print_power_state, - .debugfs_print_current_performance_level = &rv770_dpm_debugfs_print_current_performance_level, + .debugfs_print_current_performance_level = &btc_dpm_debugfs_print_current_performance_level, .force_performance_level = &rv770_dpm_force_performance_level, .vblank_too_short = &btc_dpm_vblank_too_short, }, diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h index b3bc433eed4c..ae637cfda783 100644 --- a/drivers/gpu/drm/radeon/radeon_asic.h +++ b/drivers/gpu/drm/radeon/radeon_asic.h @@ -551,6 +551,8 @@ void btc_dpm_fini(struct radeon_device *rdev); u32 btc_dpm_get_sclk(struct radeon_device *rdev, bool low); u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low); bool btc_dpm_vblank_too_short(struct radeon_device *rdev); +void btc_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, + struct seq_file *m); int sumo_dpm_init(struct radeon_device *rdev); int sumo_dpm_enable(struct radeon_device *rdev); int sumo_dpm_late_enable(struct radeon_device *rdev); diff --git a/drivers/gpu/drm/radeon/radeon_atpx_handler.c b/drivers/gpu/drm/radeon/radeon_atpx_handler.c index 485848f889f5..fa9a9c02751e 100644 --- a/drivers/gpu/drm/radeon/radeon_atpx_handler.c +++ b/drivers/gpu/drm/radeon/radeon_atpx_handler.c @@ -219,7 +219,8 @@ static int radeon_atpx_verify_interface(struct radeon_atpx *atpx) memcpy(&output, info->buffer.pointer, size); /* TODO: check version? */ - printk("ATPX version %u\n", output.version); + printk("ATPX version %u, functions 0x%08x\n", + output.version, output.function_bits); radeon_atpx_parse_functions(&atpx->functions, output.function_bits); diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c index d680608f6f5b..fbd8b930f2be 100644 --- a/drivers/gpu/drm/radeon/radeon_display.c +++ b/drivers/gpu/drm/radeon/radeon_display.c @@ -571,6 +571,8 @@ static void radeon_crtc_init(struct drm_device *dev, int index) radeon_crtc->max_cursor_width = CURSOR_WIDTH; radeon_crtc->max_cursor_height = CURSOR_HEIGHT; } + dev->mode_config.cursor_width = radeon_crtc->max_cursor_width; + dev->mode_config.cursor_height = radeon_crtc->max_cursor_height; #if 0 radeon_crtc->mode_set.crtc = &radeon_crtc->base; diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c index 114d1672d616..2aecd6dc2610 100644 --- a/drivers/gpu/drm/radeon/radeon_kms.c +++ b/drivers/gpu/drm/radeon/radeon_kms.c @@ -537,6 +537,10 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) radeon_vm_init(rdev, &fpriv->vm); + r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false); + if (r) + return r; + /* map the ib pool buffer read only into * virtual address space */ bo_va = radeon_vm_bo_add(rdev, &fpriv->vm, @@ -544,6 +548,8 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv) r = radeon_vm_bo_set_addr(rdev, bo_va, RADEON_VA_IB_OFFSET, RADEON_VM_PAGE_READABLE | RADEON_VM_PAGE_SNOOPED); + + radeon_bo_unreserve(rdev->ring_tmp_bo.bo); if (r) { radeon_vm_fini(rdev, &fpriv->vm); kfree(fpriv); diff --git a/drivers/gpu/drm/radeon/radeon_ring.c b/drivers/gpu/drm/radeon/radeon_ring.c index 1b783f0e6d3a..15e44a7281ab 100644 --- a/drivers/gpu/drm/radeon/radeon_ring.c +++ b/drivers/gpu/drm/radeon/radeon_ring.c @@ -139,7 +139,7 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib, } /* 64 dwords should be enough for fence too */ - r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_RINGS * 8); + r = radeon_ring_lock(rdev, ring, 64 + RADEON_NUM_SYNCS * 8); if (r) { dev_err(rdev->dev, "scheduling IB failed (%d).\n", r); return r; diff --git a/drivers/gpu/drm/radeon/radeon_semaphore.c b/drivers/gpu/drm/radeon/radeon_semaphore.c index 2b42aa1914f2..9006b32d5eed 100644 --- a/drivers/gpu/drm/radeon/radeon_semaphore.c +++ b/drivers/gpu/drm/radeon/radeon_semaphore.c @@ -34,14 +34,15 @@ int radeon_semaphore_create(struct radeon_device *rdev, struct radeon_semaphore **semaphore) { + uint32_t *cpu_addr; int i, r; *semaphore = kmalloc(sizeof(struct radeon_semaphore), GFP_KERNEL); if (*semaphore == NULL) { return -ENOMEM; } - r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, - &(*semaphore)->sa_bo, 8, 8, true); + r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo, + 8 * RADEON_NUM_SYNCS, 8, true); if (r) { kfree(*semaphore); *semaphore = NULL; @@ -49,7 +50,10 @@ int radeon_semaphore_create(struct radeon_device *rdev, } (*semaphore)->waiters = 0; (*semaphore)->gpu_addr = radeon_sa_bo_gpu_addr((*semaphore)->sa_bo); - *((uint64_t*)radeon_sa_bo_cpu_addr((*semaphore)->sa_bo)) = 0; + + cpu_addr = radeon_sa_bo_cpu_addr((*semaphore)->sa_bo); + for (i = 0; i < RADEON_NUM_SYNCS; ++i) + cpu_addr[i] = 0; for (i = 0; i < RADEON_NUM_RINGS; ++i) (*semaphore)->sync_to[i] = NULL; @@ -125,6 +129,7 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev, struct radeon_semaphore *semaphore, int ring) { + unsigned count = 0; int i, r; for (i = 0; i < RADEON_NUM_RINGS; ++i) { @@ -140,6 +145,12 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev, return -EINVAL; } + if (++count > RADEON_NUM_SYNCS) { + /* not enough room, wait manually */ + radeon_fence_wait_locked(fence); + continue; + } + /* allocate enough space for sync command */ r = radeon_ring_alloc(rdev, &rdev->ring[i], 16); if (r) { @@ -164,6 +175,8 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev, radeon_ring_commit(rdev, &rdev->ring[i]); radeon_fence_note_sync(fence, ring); + + semaphore->gpu_addr += 8; } return 0; diff --git a/drivers/gpu/drm/radeon/radeon_uvd.c b/drivers/gpu/drm/radeon/radeon_uvd.c index 6781fee1eaad..3e6804b2b2ef 100644 --- a/drivers/gpu/drm/radeon/radeon_uvd.c +++ b/drivers/gpu/drm/radeon/radeon_uvd.c @@ -171,6 +171,8 @@ void radeon_uvd_fini(struct radeon_device *rdev) radeon_bo_unref(&rdev->uvd.vcpu_bo); + radeon_ring_fini(rdev, &rdev->ring[R600_RING_TYPE_UVD_INDEX]); + release_firmware(rdev->uvd_fw); } diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c index 6c772e58c784..4e37a42305d8 100644 --- a/drivers/gpu/drm/radeon/rv770.c +++ b/drivers/gpu/drm/radeon/rv770.c @@ -1955,9 +1955,9 @@ void rv770_fini(struct radeon_device *rdev) radeon_wb_fini(rdev); radeon_ib_pool_fini(rdev); radeon_irq_kms_fini(rdev); - rv770_pcie_gart_fini(rdev); uvd_v1_0_fini(rdev); radeon_uvd_fini(rdev); + rv770_pcie_gart_fini(rdev); r600_vram_scratch_fini(rdev); radeon_gem_fini(rdev); radeon_fence_driver_fini(rdev); diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c index 80c595aba359..b5f63f5e22a3 100644 --- a/drivers/gpu/drm/radeon/rv770_dpm.c +++ b/drivers/gpu/drm/radeon/rv770_dpm.c @@ -2174,7 +2174,6 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev, struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); struct rv7xx_ps *ps = rv770_get_ps(rps); u32 sclk, mclk; - u16 vddc; struct rv7xx_pl *pl; switch (index) { @@ -2214,8 +2213,8 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev, /* patch up vddc if necessary */ if (pl->vddc == 0xff01) { - if (radeon_atom_get_max_vddc(rdev, 0, 0, &vddc) == 0) - pl->vddc = vddc; + if (pi->max_vddc) + pl->vddc = pi->max_vddc; } if (rps->class & ATOM_PPLIB_CLASSIFICATION_ACPI) { @@ -2527,14 +2526,7 @@ u32 rv770_dpm_get_mclk(struct radeon_device *rdev, bool low) bool rv770_dpm_vblank_too_short(struct radeon_device *rdev) { u32 vblank_time = r600_dpm_get_vblank_time(rdev); - u32 switch_limit = 300; - - /* quirks */ - /* ASUS K70AF */ - if ((rdev->pdev->device == 0x9553) && - (rdev->pdev->subsystem_vendor == 0x1043) && - (rdev->pdev->subsystem_device == 0x1c42)) - switch_limit = 200; + u32 switch_limit = 200; /* 300 */ /* RV770 */ /* mclk switching doesn't seem to work reliably on desktop RV770s */ diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c index 09ec4f6c53bb..83578324e5d1 100644 --- a/drivers/gpu/drm/radeon/si.c +++ b/drivers/gpu/drm/radeon/si.c @@ -6338,6 +6338,10 @@ restart_ih: break; } break; + case 124: /* UVD */ + DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data); + radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX); + break; case 146: case 147: addr = RREG32(VM_CONTEXT1_PROTECTION_FAULT_ADDR); diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c index 0471501338fb..0a2f5b4bca43 100644 --- a/drivers/gpu/drm/radeon/si_dpm.c +++ b/drivers/gpu/drm/radeon/si_dpm.c @@ -2395,7 +2395,7 @@ static int si_populate_sq_ramping_values(struct radeon_device *rdev, if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT)) enable_sq_ramping = false; - if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) + if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO > (LTI_RATIO_MASK >> LTI_RATIO_SHIFT)) enable_sq_ramping = false; for (i = 0; i < state->performance_level_count; i++) { @@ -6472,7 +6472,8 @@ void si_dpm_fini(struct radeon_device *rdev) void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev); + struct radeon_ps *rps = &eg_pi->current_rps; struct ni_ps *ps = ni_get_ps(rps); struct rv7xx_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c index f121efe12dc5..8b47b3cd0357 100644 --- a/drivers/gpu/drm/radeon/sumo_dpm.c +++ b/drivers/gpu/drm/radeon/sumo_dpm.c @@ -1807,7 +1807,7 @@ void sumo_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev struct seq_file *m) { struct sumo_power_info *pi = sumo_get_pi(rdev); - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct radeon_ps *rps = &pi->current_rps; struct sumo_ps *ps = sumo_get_ps(rps); struct sumo_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c index 2d447192d6f7..2da0e17eb960 100644 --- a/drivers/gpu/drm/radeon/trinity_dpm.c +++ b/drivers/gpu/drm/radeon/trinity_dpm.c @@ -1926,7 +1926,8 @@ void trinity_dpm_print_power_state(struct radeon_device *rdev, void trinity_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev, struct seq_file *m) { - struct radeon_ps *rps = rdev->pm.dpm.current_ps; + struct trinity_power_info *pi = trinity_get_pi(rdev); + struct radeon_ps *rps = &pi->current_rps; struct trinity_ps *ps = trinity_get_ps(rps); struct trinity_pl *pl; u32 current_index = diff --git a/drivers/gpu/drm/radeon/uvd_v2_2.c b/drivers/gpu/drm/radeon/uvd_v2_2.c index 824550db3fed..d1771004cb52 100644 --- a/drivers/gpu/drm/radeon/uvd_v2_2.c +++ b/drivers/gpu/drm/radeon/uvd_v2_2.c @@ -57,7 +57,6 @@ void uvd_v2_2_fence_emit(struct radeon_device *rdev, radeon_ring_write(ring, 0); radeon_ring_write(ring, PACKET0(UVD_GPCOM_VCPU_CMD, 0)); radeon_ring_write(ring, 2); - return; } /** diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c index 88a529008ce0..c71594754f46 100644 --- a/drivers/gpu/drm/tegra/drm.c +++ b/drivers/gpu/drm/tegra/drm.c @@ -104,7 +104,7 @@ static void tegra_drm_context_free(struct tegra_drm_context *context) static void tegra_drm_lastclose(struct drm_device *drm) { -#ifdef CONFIG_TEGRA_DRM_FBDEV +#ifdef CONFIG_DRM_TEGRA_FBDEV struct tegra_drm *tegra = drm->dev_private; tegra_fbdev_restore_mode(tegra->fbdev); diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 338f7f6561d7..0266fb40479e 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -15,6 +15,7 @@ struct tegra_rgb { struct tegra_output output; struct tegra_dc *dc; + bool enabled; struct clk *clk_parent; struct clk *clk; @@ -89,6 +90,9 @@ static int tegra_output_rgb_enable(struct tegra_output *output) struct tegra_rgb *rgb = to_rgb(output); unsigned long value; + if (rgb->enabled) + return 0; + tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable)); value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL; @@ -122,6 +126,8 @@ static int tegra_output_rgb_enable(struct tegra_output *output) tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL); tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL); + rgb->enabled = true; + return 0; } @@ -130,6 +136,9 @@ static int tegra_output_rgb_disable(struct tegra_output *output) struct tegra_rgb *rgb = to_rgb(output); unsigned long value; + if (!rgb->enabled) + return 0; + value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL); value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE | PW4_ENABLE | PM0_ENABLE | PM1_ENABLE); @@ -144,6 +153,8 @@ static int tegra_output_rgb_disable(struct tegra_output *output) tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable)); + rgb->enabled = false; + return 0; } diff --git a/drivers/gpu/drm/ttm/ttm_agp_backend.c b/drivers/gpu/drm/ttm/ttm_agp_backend.c index 3302f99e7497..764be36397fd 100644 --- a/drivers/gpu/drm/ttm/ttm_agp_backend.c +++ b/drivers/gpu/drm/ttm/ttm_agp_backend.c @@ -126,6 +126,7 @@ struct ttm_tt *ttm_agp_tt_create(struct ttm_bo_device *bdev, agp_be->ttm.func = &ttm_agp_func; if (ttm_tt_init(&agp_be->ttm, bdev, size, page_flags, dummy_read_page)) { + kfree(agp_be); return NULL; } diff --git a/drivers/gpu/drm/vmwgfx/svga3d_reg.h b/drivers/gpu/drm/vmwgfx/svga3d_reg.h index b645647b7776..f58dc7dd15c5 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_reg.h @@ -261,12 +261,7 @@ typedef enum SVGA3dSurfaceFormat { /* Planar video formats. */ SVGA3D_YV12 = 121, - /* Shader constant formats. */ - SVGA3D_SURFACE_SHADERCONST_FLOAT = 122, - SVGA3D_SURFACE_SHADERCONST_INT = 123, - SVGA3D_SURFACE_SHADERCONST_BOOL = 124, - - SVGA3D_FORMAT_MAX = 125, + SVGA3D_FORMAT_MAX = 122, } SVGA3dSurfaceFormat; typedef uint32 SVGA3dColor; /* a, r, g, b */ @@ -1223,9 +1218,19 @@ typedef enum { #define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129 #define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE 1130 - +#define SVGA_3D_CMD_GB_SCREEN_DMA 1131 +#define SVGA_3D_CMD_BIND_GB_SURFACE_WITH_PITCH 1132 +#define SVGA_3D_CMD_GB_MOB_FENCE 1133 +#define SVGA_3D_CMD_DEFINE_GB_SURFACE_V2 1134 #define SVGA_3D_CMD_DEFINE_GB_MOB64 1135 #define SVGA_3D_CMD_REDEFINE_GB_MOB64 1136 +#define SVGA_3D_CMD_NOP_ERROR 1137 + +#define SVGA_3D_CMD_RESERVED1 1138 +#define SVGA_3D_CMD_RESERVED2 1139 +#define SVGA_3D_CMD_RESERVED3 1140 +#define SVGA_3D_CMD_RESERVED4 1141 +#define SVGA_3D_CMD_RESERVED5 1142 #define SVGA_3D_CMD_MAX 1142 #define SVGA_3D_CMD_FUTURE_MAX 3000 @@ -1973,8 +1978,7 @@ struct { uint32 sizeInBytes; uint32 validSizeInBytes; SVGAMobFormat ptDepth; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdSetOTableBase; /* SVGA_3D_CMD_SET_OTABLE_BASE */ typedef @@ -1984,15 +1988,13 @@ struct { uint32 sizeInBytes; uint32 validSizeInBytes; SVGAMobFormat ptDepth; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdSetOTableBase64; /* SVGA_3D_CMD_SET_OTABLE_BASE64 */ typedef struct { SVGAOTableType type; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdReadbackOTable; /* SVGA_3D_CMD_READBACK_OTABLE */ /* @@ -2005,8 +2007,7 @@ struct SVGA3dCmdDefineGBMob { SVGAMobFormat ptDepth; PPN base; uint32 sizeInBytes; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */ @@ -2017,8 +2018,7 @@ SVGA3dCmdDefineGBMob; /* SVGA_3D_CMD_DEFINE_GB_MOB */ typedef struct SVGA3dCmdDestroyGBMob { SVGAMobId mobid; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdDestroyGBMob; /* SVGA_3D_CMD_DESTROY_GB_MOB */ /* @@ -2031,8 +2031,7 @@ struct SVGA3dCmdRedefineGBMob { SVGAMobFormat ptDepth; PPN base; uint32 sizeInBytes; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdRedefineGBMob; /* SVGA_3D_CMD_REDEFINE_GB_MOB */ /* @@ -2045,8 +2044,7 @@ struct SVGA3dCmdDefineGBMob64 { SVGAMobFormat ptDepth; PPN64 base; uint32 sizeInBytes; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdDefineGBMob64; /* SVGA_3D_CMD_DEFINE_GB_MOB64 */ /* @@ -2059,8 +2057,7 @@ struct SVGA3dCmdRedefineGBMob64 { SVGAMobFormat ptDepth; PPN64 base; uint32 sizeInBytes; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */ /* @@ -2070,8 +2067,7 @@ SVGA3dCmdRedefineGBMob64; /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */ typedef struct SVGA3dCmdUpdateGBMobMapping { SVGAMobId mobid; -} -__attribute__((__packed__)) +} __packed SVGA3dCmdUpdateGBMobMapping; /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */ /* @@ -2087,7 +2083,8 @@ struct SVGA3dCmdDefineGBSurface { uint32 multisampleCount; SVGA3dTextureFilter autogenFilter; SVGA3dSize size; -} SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ +} __packed +SVGA3dCmdDefineGBSurface; /* SVGA_3D_CMD_DEFINE_GB_SURFACE */ /* * Destroy a guest-backed surface. @@ -2096,7 +2093,8 @@ struct SVGA3dCmdDefineGBSurface { typedef struct SVGA3dCmdDestroyGBSurface { uint32 sid; -} SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */ +} __packed +SVGA3dCmdDestroyGBSurface; /* SVGA_3D_CMD_DESTROY_GB_SURFACE */ /* * Bind a guest-backed surface to an object. @@ -2106,7 +2104,8 @@ typedef struct SVGA3dCmdBindGBSurface { uint32 sid; SVGAMobId mobid; -} SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */ +} __packed +SVGA3dCmdBindGBSurface; /* SVGA_3D_CMD_BIND_GB_SURFACE */ /* * Conditionally bind a mob to a guest backed surface if testMobid @@ -2123,7 +2122,7 @@ struct{ SVGAMobId testMobid; SVGAMobId mobid; uint32 flags; -} +} __packed SVGA3dCmdCondBindGBSurface; /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */ /* @@ -2135,7 +2134,8 @@ typedef struct SVGA3dCmdUpdateGBImage { SVGA3dSurfaceImageId image; SVGA3dBox box; -} SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */ +} __packed +SVGA3dCmdUpdateGBImage; /* SVGA_3D_CMD_UPDATE_GB_IMAGE */ /* * Update an entire guest-backed surface. @@ -2145,7 +2145,8 @@ struct SVGA3dCmdUpdateGBImage { typedef struct SVGA3dCmdUpdateGBSurface { uint32 sid; -} SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */ +} __packed +SVGA3dCmdUpdateGBSurface; /* SVGA_3D_CMD_UPDATE_GB_SURFACE */ /* * Readback an image in a guest-backed surface. @@ -2155,7 +2156,8 @@ struct SVGA3dCmdUpdateGBSurface { typedef struct SVGA3dCmdReadbackGBImage { SVGA3dSurfaceImageId image; -} SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/ +} __packed +SVGA3dCmdReadbackGBImage; /* SVGA_3D_CMD_READBACK_GB_IMAGE*/ /* * Readback an entire guest-backed surface. @@ -2165,7 +2167,8 @@ struct SVGA3dCmdReadbackGBImage { typedef struct SVGA3dCmdReadbackGBSurface { uint32 sid; -} SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */ +} __packed +SVGA3dCmdReadbackGBSurface; /* SVGA_3D_CMD_READBACK_GB_SURFACE */ /* * Readback a sub rect of an image in a guest-backed surface. After @@ -2179,7 +2182,7 @@ struct SVGA3dCmdReadbackGBImagePartial { SVGA3dSurfaceImageId image; SVGA3dBox box; uint32 invertBox; -} +} __packed SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */ /* @@ -2190,7 +2193,8 @@ SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */ typedef struct SVGA3dCmdInvalidateGBImage { SVGA3dSurfaceImageId image; -} SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */ +} __packed +SVGA3dCmdInvalidateGBImage; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */ /* * Invalidate an entire guest-backed surface. @@ -2200,7 +2204,8 @@ struct SVGA3dCmdInvalidateGBImage { typedef struct SVGA3dCmdInvalidateGBSurface { uint32 sid; -} SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */ +} __packed +SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */ /* * Invalidate a sub rect of an image in a guest-backed surface. After @@ -2214,7 +2219,7 @@ struct SVGA3dCmdInvalidateGBImagePartial { SVGA3dSurfaceImageId image; SVGA3dBox box; uint32 invertBox; -} +} __packed SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */ /* @@ -2224,7 +2229,8 @@ SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */ typedef struct SVGA3dCmdDefineGBContext { uint32 cid; -} SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */ +} __packed +SVGA3dCmdDefineGBContext; /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */ /* * Destroy a guest-backed context. @@ -2233,7 +2239,8 @@ struct SVGA3dCmdDefineGBContext { typedef struct SVGA3dCmdDestroyGBContext { uint32 cid; -} SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */ +} __packed +SVGA3dCmdDestroyGBContext; /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */ /* * Bind a guest-backed context. @@ -2252,7 +2259,8 @@ struct SVGA3dCmdBindGBContext { uint32 cid; SVGAMobId mobid; uint32 validContents; -} SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */ +} __packed +SVGA3dCmdBindGBContext; /* SVGA_3D_CMD_BIND_GB_CONTEXT */ /* * Readback a guest-backed context. @@ -2262,7 +2270,8 @@ struct SVGA3dCmdBindGBContext { typedef struct SVGA3dCmdReadbackGBContext { uint32 cid; -} SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */ +} __packed +SVGA3dCmdReadbackGBContext; /* SVGA_3D_CMD_READBACK_GB_CONTEXT */ /* * Invalidate a guest-backed context. @@ -2270,7 +2279,8 @@ struct SVGA3dCmdReadbackGBContext { typedef struct SVGA3dCmdInvalidateGBContext { uint32 cid; -} SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */ +} __packed +SVGA3dCmdInvalidateGBContext; /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */ /* * Define a guest-backed shader. @@ -2281,7 +2291,8 @@ struct SVGA3dCmdDefineGBShader { uint32 shid; SVGA3dShaderType type; uint32 sizeInBytes; -} SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */ +} __packed +SVGA3dCmdDefineGBShader; /* SVGA_3D_CMD_DEFINE_GB_SHADER */ /* * Bind a guest-backed shader. @@ -2291,7 +2302,8 @@ typedef struct SVGA3dCmdBindGBShader { uint32 shid; SVGAMobId mobid; uint32 offsetInBytes; -} SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */ +} __packed +SVGA3dCmdBindGBShader; /* SVGA_3D_CMD_BIND_GB_SHADER */ /* * Destroy a guest-backed shader. @@ -2299,7 +2311,8 @@ typedef struct SVGA3dCmdBindGBShader { typedef struct SVGA3dCmdDestroyGBShader { uint32 shid; -} SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */ +} __packed +SVGA3dCmdDestroyGBShader; /* SVGA_3D_CMD_DESTROY_GB_SHADER */ typedef struct { @@ -2314,14 +2327,16 @@ struct { * Note that FLOAT and INT constants are 4-dwords in length, while * BOOL constants are 1-dword in length. */ -} SVGA3dCmdSetGBShaderConstInline; +} __packed +SVGA3dCmdSetGBShaderConstInline; /* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */ typedef struct { uint32 cid; SVGA3dQueryType type; -} SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */ +} __packed +SVGA3dCmdBeginGBQuery; /* SVGA_3D_CMD_BEGIN_GB_QUERY */ typedef struct { @@ -2329,7 +2344,8 @@ struct { SVGA3dQueryType type; SVGAMobId mobid; uint32 offset; -} SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */ +} __packed +SVGA3dCmdEndGBQuery; /* SVGA_3D_CMD_END_GB_QUERY */ /* @@ -2346,21 +2362,22 @@ struct { SVGA3dQueryType type; SVGAMobId mobid; uint32 offset; -} SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */ +} __packed +SVGA3dCmdWaitForGBQuery; /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */ typedef struct { SVGAMobId mobid; uint32 fbOffset; uint32 initalized; -} +} __packed SVGA3dCmdEnableGart; /* SVGA_3D_CMD_ENABLE_GART */ typedef struct { SVGAMobId mobid; uint32 gartOffset; -} +} __packed SVGA3dCmdMapMobIntoGart; /* SVGA_3D_CMD_MAP_MOB_INTO_GART */ @@ -2368,7 +2385,7 @@ typedef struct { uint32 gartOffset; uint32 numPages; -} +} __packed SVGA3dCmdUnmapGartRange; /* SVGA_3D_CMD_UNMAP_GART_RANGE */ @@ -2385,27 +2402,27 @@ struct { int32 xRoot; int32 yRoot; uint32 flags; -} +} __packed SVGA3dCmdDefineGBScreenTarget; /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */ typedef struct { uint32 stid; -} +} __packed SVGA3dCmdDestroyGBScreenTarget; /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */ typedef struct { uint32 stid; SVGA3dSurfaceImageId image; -} +} __packed SVGA3dCmdBindGBScreenTarget; /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */ typedef struct { uint32 stid; SVGA3dBox box; -} +} __packed SVGA3dCmdUpdateGBScreenTarget; /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */ /* diff --git a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h index 8369c3ba10fe..ef3385096145 100644 --- a/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h +++ b/drivers/gpu/drm/vmwgfx/svga3d_surfacedefs.h @@ -38,8 +38,11 @@ #define DIV_ROUND_UP(x, y) (((x) + (y) - 1) / (y)) #define max_t(type, x, y) ((x) > (y) ? (x) : (y)) +#define min_t(type, x, y) ((x) < (y) ? (x) : (y)) #define surf_size_struct SVGA3dSize #define u32 uint32 +#define u64 uint64_t +#define U32_MAX ((u32)~0U) #endif /* __KERNEL__ */ @@ -704,8 +707,8 @@ static const struct svga3d_surface_desc svga3d_surface_descs[] = { static inline u32 clamped_umul32(u32 a, u32 b) { - uint64_t tmp = (uint64_t) a*b; - return (tmp > (uint64_t) ((u32) -1)) ? (u32) -1 : tmp; + u64 tmp = (u64) a*b; + return (tmp > (u64) U32_MAX) ? U32_MAX : tmp; } static inline const struct svga3d_surface_desc * @@ -834,7 +837,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format, bool cubemap) { const struct svga3d_surface_desc *desc = svga3dsurface_get_desc(format); - u32 total_size = 0; + u64 total_size = 0; u32 mip; for (mip = 0; mip < num_mip_levels; mip++) { @@ -847,7 +850,7 @@ svga3dsurface_get_serialized_size(SVGA3dSurfaceFormat format, if (cubemap) total_size *= SVGA3D_MAX_SURFACE_FACES; - return total_size; + return (u32) min_t(u64, total_size, (u64) U32_MAX); } diff --git a/drivers/gpu/drm/vmwgfx/svga_reg.h b/drivers/gpu/drm/vmwgfx/svga_reg.h index 71defa4d2d75..11323dd5196f 100644 --- a/drivers/gpu/drm/vmwgfx/svga_reg.h +++ b/drivers/gpu/drm/vmwgfx/svga_reg.h @@ -169,10 +169,17 @@ enum { SVGA_REG_TRACES = 45, /* Enable trace-based updates even when FIFO is on */ SVGA_REG_GMRS_MAX_PAGES = 46, /* Maximum number of 4KB pages for all GMRs */ SVGA_REG_MEMORY_SIZE = 47, /* Total dedicated device memory excluding FIFO */ + SVGA_REG_COMMAND_LOW = 48, /* Lower 32 bits and submits commands */ + SVGA_REG_COMMAND_HIGH = 49, /* Upper 32 bits of command buffer PA */ SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50, /* Max primary memory */ SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */ SVGA_REG_DEV_CAP = 52, /* Write dev cap index, read value */ - SVGA_REG_TOP = 53, /* Must be 1 more than the last register */ + SVGA_REG_CMD_PREPEND_LOW = 53, + SVGA_REG_CMD_PREPEND_HIGH = 54, + SVGA_REG_SCREENTARGET_MAX_WIDTH = 55, + SVGA_REG_SCREENTARGET_MAX_HEIGHT = 56, + SVGA_REG_MOB_MAX_SIZE = 57, + SVGA_REG_TOP = 58, /* Must be 1 more than the last register */ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */ /* Next 768 (== 256*3) registers exist for colormap */ diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c index 9426c53fb483..1e80152674b5 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_context.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_context.c @@ -551,8 +551,7 @@ static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi, bool rebind) cmd->header.size = sizeof(cmd->body); cmd->body.cid = bi->ctx->id; cmd->body.type = bi->i1.shader_type; - cmd->body.shid = - cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID); + cmd->body.shid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); vmw_fifo_commit(dev_priv, sizeof(*cmd)); return 0; @@ -585,8 +584,7 @@ static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi, cmd->header.size = sizeof(cmd->body); cmd->body.cid = bi->ctx->id; cmd->body.type = bi->i1.rt_type; - cmd->body.target.sid = - cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID); + cmd->body.target.sid = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); cmd->body.target.face = 0; cmd->body.target.mipmap = 0; vmw_fifo_commit(dev_priv, sizeof(*cmd)); @@ -628,8 +626,7 @@ static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi, cmd->body.c.cid = bi->ctx->id; cmd->body.s1.stage = bi->i1.texture_stage; cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE; - cmd->body.s1.value = - cpu_to_le32((rebind) ? bi->res->id : SVGA3D_INVALID_ID); + cmd->body.s1.value = ((rebind) ? bi->res->id : SVGA3D_INVALID_ID); vmw_fifo_commit(dev_priv, sizeof(*cmd)); return 0; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 3bdc0adc656d..0083cbf99edf 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -667,6 +667,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->memory_size = 512*1024*1024; } dev_priv->max_mob_pages = 0; + dev_priv->max_mob_size = 0; if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) { uint64_t mem_size = vmw_read(dev_priv, @@ -676,6 +677,8 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset) dev_priv->prim_bb_mem = vmw_read(dev_priv, SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM); + dev_priv->max_mob_size = + vmw_read(dev_priv, SVGA_REG_MOB_MAX_SIZE); } else dev_priv->prim_bb_mem = dev_priv->vram_size; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h index ecaa302a6154..07831554dad7 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.h @@ -40,7 +40,7 @@ #include <drm/ttm/ttm_module.h> #include "vmwgfx_fence.h" -#define VMWGFX_DRIVER_DATE "20121114" +#define VMWGFX_DRIVER_DATE "20140228" #define VMWGFX_DRIVER_MAJOR 2 #define VMWGFX_DRIVER_MINOR 5 #define VMWGFX_DRIVER_PATCHLEVEL 0 @@ -386,6 +386,7 @@ struct vmw_private { uint32_t max_gmr_ids; uint32_t max_gmr_pages; uint32_t max_mob_pages; + uint32_t max_mob_size; uint32_t memory_size; bool has_gmr; bool has_mob; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c index 269b85cc875a..efb575a7996c 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c @@ -602,7 +602,7 @@ static int vmw_cmd_cid_check(struct vmw_private *dev_priv, { struct vmw_cid_cmd { SVGA3dCmdHeader header; - __le32 cid; + uint32_t cid; } *cmd; cmd = container_of(header, struct vmw_cid_cmd, header); @@ -1835,7 +1835,7 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv, return 0; } -static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = { +static const struct vmw_cmd_entry vmw_cmd_entries[SVGA_3D_CMD_MAX] = { VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid, false, false, false), VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid, @@ -2032,6 +2032,9 @@ static int vmw_cmd_check(struct vmw_private *dev_priv, goto out_invalid; entry = &vmw_cmd_entries[cmd_id]; + if (unlikely(!entry->func)) + goto out_invalid; + if (unlikely(!entry->user_allow && !sw_context->kernel)) goto out_privileged; @@ -2469,7 +2472,7 @@ int vmw_execbuf_process(struct drm_file *file_priv, if (dev_priv->has_mob) { ret = vmw_rebind_contexts(sw_context); if (unlikely(ret != 0)) - goto out_err; + goto out_unlock_binding; } cmd = vmw_fifo_reserve(dev_priv, command_size); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c index f9881f9e62bd..47b70949bf3a 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c @@ -102,6 +102,9 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data, vmw_fp->gb_aware = true; param->value = dev_priv->max_mob_pages * PAGE_SIZE; break; + case DRM_VMW_PARAM_MAX_MOB_SIZE: + param->value = dev_priv->max_mob_size; + break; default: DRM_ERROR("Illegal vmwgfx get param request: %d\n", param->param); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c index d4a5a19cb8c3..04a64b8cd3cd 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c @@ -188,18 +188,20 @@ static void vmw_takedown_otable_base(struct vmw_private *dev_priv, bo = otable->page_table->pt_bo; cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd)); - if (unlikely(cmd == NULL)) - DRM_ERROR("Failed reserving FIFO space for OTable setup.\n"); - - memset(cmd, 0, sizeof(*cmd)); - cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; - cmd->header.size = sizeof(cmd->body); - cmd->body.type = type; - cmd->body.baseAddress = 0; - cmd->body.sizeInBytes = 0; - cmd->body.validSizeInBytes = 0; - cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID; - vmw_fifo_commit(dev_priv, sizeof(*cmd)); + if (unlikely(cmd == NULL)) { + DRM_ERROR("Failed reserving FIFO space for OTable " + "takedown.\n"); + } else { + memset(cmd, 0, sizeof(*cmd)); + cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE; + cmd->header.size = sizeof(cmd->body); + cmd->body.type = type; + cmd->body.baseAddress = 0; + cmd->body.sizeInBytes = 0; + cmd->body.validSizeInBytes = 0; + cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); + } if (bo) { int ret; @@ -562,11 +564,12 @@ void vmw_mob_unbind(struct vmw_private *dev_priv, if (unlikely(cmd == NULL)) { DRM_ERROR("Failed reserving FIFO space for Memory " "Object unbinding.\n"); + } else { + cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB; + cmd->header.size = sizeof(cmd->body); + cmd->body.mobid = mob->id; + vmw_fifo_commit(dev_priv, sizeof(*cmd)); } - cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB; - cmd->header.size = sizeof(cmd->body); - cmd->body.mobid = mob->id; - vmw_fifo_commit(dev_priv, sizeof(*cmd)); if (bo) { vmw_fence_single_bo(bo, NULL); ttm_bo_unreserve(bo); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c index 2aa4bc6a4d60..9757b57f8388 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_resource.c @@ -427,8 +427,7 @@ int vmw_dmabuf_init(struct vmw_private *dev_priv, INIT_LIST_HEAD(&vmw_bo->res_list); ret = ttm_bo_init(bdev, &vmw_bo->base, size, - (user) ? ttm_bo_type_device : - ttm_bo_type_kernel, placement, + ttm_bo_type_device, placement, 0, interruptible, NULL, acc_size, NULL, bo_free); return ret; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c index 217d941b8176..ee3856578a12 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c @@ -371,13 +371,13 @@ int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data, TTM_REF_USAGE); } -int vmw_shader_alloc(struct vmw_private *dev_priv, - struct vmw_dma_buffer *buffer, - size_t shader_size, - size_t offset, - SVGA3dShaderType shader_type, - struct ttm_object_file *tfile, - u32 *handle) +static int vmw_shader_alloc(struct vmw_private *dev_priv, + struct vmw_dma_buffer *buffer, + size_t shader_size, + size_t offset, + SVGA3dShaderType shader_type, + struct ttm_object_file *tfile, + u32 *handle) { struct vmw_user_shader *ushader; struct vmw_resource *res, *tmp; @@ -779,6 +779,8 @@ vmw_compat_shader_man_create(struct vmw_private *dev_priv) int ret; man = kzalloc(sizeof(*man), GFP_KERNEL); + if (man == NULL) + return ERR_PTR(-ENOMEM); man->dev_priv = dev_priv; INIT_LIST_HEAD(&man->list); diff --git a/drivers/gpu/host1x/job.c b/drivers/gpu/host1x/job.c index 1146e3bba6e1..112f27e51bc7 100644 --- a/drivers/gpu/host1x/job.c +++ b/drivers/gpu/host1x/job.c @@ -538,7 +538,7 @@ int host1x_job_pin(struct host1x_job *job, struct device *dev) g->base = job->gather_addr_phys[i]; - for (j = 0; j < job->num_gathers; j++) + for (j = i + 1; j < job->num_gathers; j++) if (job->gathers[j].bo == g->bo) job->gathers[j].handled = true; diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 497558127bb3..f822fd2a1ada 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -469,6 +469,9 @@ static const struct hid_device_id apple_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, + USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS), + .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS), .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI), diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 3bfac3accd22..cc32a6f96c64 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1679,6 +1679,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, @@ -1779,6 +1780,8 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 8fae6d1414cc..c24908f14934 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -157,6 +157,7 @@ struct mousevsc_dev { u32 report_desc_size; struct hv_input_dev_info hid_dev_info; struct hid_device *hid_device; + u8 input_buf[HID_MAX_BUFFER_SIZE]; }; @@ -256,6 +257,7 @@ static void mousevsc_on_receive(struct hv_device *device, struct synthhid_msg *hid_msg; struct mousevsc_dev *input_dev = hv_get_drvdata(device); struct synthhid_input_report *input_report; + size_t len; pipe_msg = (struct pipe_prt_msg *)((unsigned long)packet + (packet->offset8 << 3)); @@ -300,9 +302,12 @@ static void mousevsc_on_receive(struct hv_device *device, (struct synthhid_input_report *)pipe_msg->data; if (!input_dev->init_complete) break; - hid_input_report(input_dev->hid_device, - HID_INPUT_REPORT, input_report->buffer, - input_report->header.size, 1); + + len = min(input_report->header.size, + (u32)sizeof(input_dev->input_buf)); + memcpy(input_dev->input_buf, input_report->buffer, len); + hid_input_report(input_dev->hid_device, HID_INPUT_REPORT, + input_dev->input_buf, len, 1); break; default: pr_err("unsupported hid msg type - type %d len %d", diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 5a5248f2cc07..22f28d6b33a8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -135,6 +135,7 @@ #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255 #define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290 #define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291 #define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292 @@ -240,6 +241,7 @@ #define USB_VENDOR_ID_CYGNAL 0x10c4 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a +#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9 #define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244 @@ -451,6 +453,9 @@ #define USB_VENDOR_ID_INTEL_1 0x8087 #define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa +#define USB_VENDOR_ID_STM_0 0x0483 +#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1 + #define USB_VENDOR_ID_ION 0x15e4 #define USB_DEVICE_ID_ICADE 0x0132 @@ -619,6 +624,8 @@ #define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 #define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730 #define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c +#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 +#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 @@ -644,6 +651,7 @@ #define USB_VENDOR_ID_NEXIO 0x1870 #define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d +#define USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750 0x0110 #define USB_VENDOR_ID_NEXTWINDOW 0x1926 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index d50e7313b171..a713e6211419 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1178,7 +1178,7 @@ static void hidinput_led_worker(struct work_struct *work) /* fall back to generic raw-output-report */ len = ((report->size - 1) >> 3) + 1 + (report->id > 0); - buf = kmalloc(len, GFP_KERNEL); + buf = hid_alloc_report_buf(report, GFP_KERNEL); if (!buf) return; diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index c6ef6eed3091..404a3a8a82f1 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -208,6 +208,10 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_2), + .driver_data = 0 }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TOUCH_COVER_2), + .driver_data = 0 }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index f134d73beca1..221d503f1c24 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1166,6 +1166,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, USB_DEVICE_ID_MULTITOUCH_3200) }, + /* FocalTech Panels */ + { .driver_data = MT_CLS_SERIAL, + MT_USB_DEVICE(USB_VENDOR_ID_CYGNAL, + USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH) }, + /* GeneralTouch panel */ { .driver_data = MT_CLS_GENERALTOUCH_TWOFINGERS, MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 46f4480035bc..9c22e14c57f0 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -665,6 +665,9 @@ static const struct hid_device_id sensor_hub_devices[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1, USB_DEVICE_ID_INTEL_HID_SENSOR), .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0, + USB_DEVICE_ID_STM_HID_SENSOR), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, { } diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index d1f81f52481a..42eebd14de1f 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -582,7 +582,7 @@ static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep, int ret; int len = i2c_hid_get_report_length(rep) - 2; - buf = kzalloc(len, GFP_KERNEL); + buf = hid_alloc_report_buf(rep, GFP_KERNEL); if (!buf) return; diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 175ec0afb70c..dbd83878ff99 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -74,6 +74,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS }, diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c index af6edf9b1936..f2d7bf90c9fe 100644 --- a/drivers/hv/connection.c +++ b/drivers/hv/connection.c @@ -67,7 +67,6 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, int ret = 0; struct vmbus_channel_initiate_contact *msg; unsigned long flags; - int t; init_completion(&msginfo->waitevent); @@ -78,6 +77,8 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, msg->interrupt_page = virt_to_phys(vmbus_connection.int_page); msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]); msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]); + if (version == VERSION_WIN8) + msg->target_vcpu = hv_context.vp_index[smp_processor_id()]; /* * Add to list before we send the request since we may @@ -100,15 +101,7 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo, } /* Wait for the connection response */ - t = wait_for_completion_timeout(&msginfo->waitevent, 5*HZ); - if (t == 0) { - spin_lock_irqsave(&vmbus_connection.channelmsg_lock, - flags); - list_del(&msginfo->msglistentry); - spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, - flags); - return -ETIMEDOUT; - } + wait_for_completion(&msginfo->waitevent); spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); list_del(&msginfo->msglistentry); diff --git a/drivers/hwmon/max1668.c b/drivers/hwmon/max1668.c index a7626358c95d..029b65e6c589 100644 --- a/drivers/hwmon/max1668.c +++ b/drivers/hwmon/max1668.c @@ -243,7 +243,7 @@ static ssize_t set_temp_min(struct device *dev, data->temp_min[index] = clamp_val(temp/1000, -128, 127); if (i2c_smbus_write_byte_data(client, MAX1668_REG_LIML_WR(index), - data->temp_max[index])) + data->temp_min[index])) count = -EIO; mutex_unlock(&data->update_lock); diff --git a/drivers/hwmon/ntc_thermistor.c b/drivers/hwmon/ntc_thermistor.c index 8c23203915af..8a17f01e8672 100644 --- a/drivers/hwmon/ntc_thermistor.c +++ b/drivers/hwmon/ntc_thermistor.c @@ -145,7 +145,7 @@ struct ntc_data { static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) { struct iio_channel *channel = pdata->chan; - unsigned int result; + s64 result; int val, ret; ret = iio_read_channel_raw(channel, &val); @@ -155,10 +155,10 @@ static int ntc_adc_iio_read(struct ntc_thermistor_platform_data *pdata) } /* unit: mV */ - result = pdata->pullup_uv * val; + result = pdata->pullup_uv * (s64) val; result >>= 12; - return result; + return (int)result; } static const struct of_device_id ntc_match[] = { diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index b8c5187b9ee0..d52d84937ad3 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -97,7 +97,6 @@ enum { enum { MV64XXX_I2C_ACTION_INVALID, MV64XXX_I2C_ACTION_CONTINUE, - MV64XXX_I2C_ACTION_OFFLOAD_SEND_START, MV64XXX_I2C_ACTION_SEND_START, MV64XXX_I2C_ACTION_SEND_RESTART, MV64XXX_I2C_ACTION_OFFLOAD_RESTART, @@ -204,6 +203,9 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data) unsigned long ctrl_reg; struct i2c_msg *msg = drv_data->msgs; + if (!drv_data->offload_enabled) + return -EOPNOTSUPP; + drv_data->msg = msg; drv_data->byte_posn = 0; drv_data->bytes_left = msg->len; @@ -433,8 +435,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->msgs++; drv_data->num_msgs--; - if (!(drv_data->offload_enabled && - mv64xxx_i2c_offload_msg(drv_data))) { + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; writel(drv_data->cntl_bits, drv_data->reg_base + drv_data->reg_offsets.control); @@ -458,15 +459,14 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->reg_base + drv_data->reg_offsets.control); break; - case MV64XXX_I2C_ACTION_OFFLOAD_SEND_START: - if (!mv64xxx_i2c_offload_msg(drv_data)) - break; - else - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - /* FALLTHRU */ case MV64XXX_I2C_ACTION_SEND_START: - writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, - drv_data->reg_base + drv_data->reg_offsets.control); + /* Can we offload this msg ? */ + if (mv64xxx_i2c_offload_msg(drv_data) < 0) { + /* No, switch to standard path */ + mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); + writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, + drv_data->reg_base + drv_data->reg_offsets.control); + } break; case MV64XXX_I2C_ACTION_SEND_ADDR_1: @@ -625,15 +625,10 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); - if (drv_data->offload_enabled) { - drv_data->action = MV64XXX_I2C_ACTION_OFFLOAD_SEND_START; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; - } else { - mv64xxx_i2c_prepare_for_io(drv_data, msg); - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; - } + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; + drv_data->send_stop = is_last; drv_data->block = 1; mv64xxx_i2c_do_action(drv_data); diff --git a/drivers/iio/accel/bma180.c b/drivers/iio/accel/bma180.c index 3bec9220df04..bfec313492b3 100644 --- a/drivers/iio/accel/bma180.c +++ b/drivers/iio/accel/bma180.c @@ -447,14 +447,14 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { { }, }; -#define BMA180_CHANNEL(_index) { \ +#define BMA180_CHANNEL(_axis) { \ .type = IIO_ACCEL, \ - .indexed = 1, \ - .channel = (_index), \ + .modified = 1, \ + .channel2 = IIO_MOD_##_axis, \ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ - .scan_index = (_index), \ + .scan_index = AXIS_##_axis, \ .scan_type = { \ .sign = 's', \ .realbits = 14, \ @@ -465,10 +465,10 @@ static const struct iio_chan_spec_ext_info bma180_ext_info[] = { } static const struct iio_chan_spec bma180_channels[] = { - BMA180_CHANNEL(AXIS_X), - BMA180_CHANNEL(AXIS_Y), - BMA180_CHANNEL(AXIS_Z), - IIO_CHAN_SOFT_TIMESTAMP(4), + BMA180_CHANNEL(X), + BMA180_CHANNEL(Y), + BMA180_CHANNEL(Z), + IIO_CHAN_SOFT_TIMESTAMP(3), }; static irqreturn_t bma180_trigger_handler(int irq, void *p) diff --git a/drivers/iio/adc/max1363.c b/drivers/iio/adc/max1363.c index e283f2f2ee2f..360259266d4f 100644 --- a/drivers/iio/adc/max1363.c +++ b/drivers/iio/adc/max1363.c @@ -1560,7 +1560,7 @@ static int max1363_probe(struct i2c_client *client, st->client = client; st->vref_uv = st->chip_info->int_vref_mv * 1000; - vref = devm_regulator_get(&client->dev, "vref"); + vref = devm_regulator_get_optional(&client->dev, "vref"); if (!IS_ERR(vref)) { int vref_uv; diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig index 41c64a43bcab..ac2d69e34c8c 100644 --- a/drivers/iio/gyro/Kconfig +++ b/drivers/iio/gyro/Kconfig @@ -70,7 +70,7 @@ config IIO_ST_GYRO_3AXIS select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics gyroscopes: - L3G4200D, LSM330DL, L3GD20, L3GD20H, LSM330DLC, L3G4IS, LSM330. + L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330. This driver can also be built as a module. If so, these modules will be created: diff --git a/drivers/iio/gyro/st_gyro.h b/drivers/iio/gyro/st_gyro.h index f8f2bf84a5a2..c197360c450b 100644 --- a/drivers/iio/gyro/st_gyro.h +++ b/drivers/iio/gyro/st_gyro.h @@ -19,7 +19,6 @@ #define LSM330DL_GYRO_DEV_NAME "lsm330dl_gyro" #define LSM330DLC_GYRO_DEV_NAME "lsm330dlc_gyro" #define L3GD20_GYRO_DEV_NAME "l3gd20" -#define L3GD20H_GYRO_DEV_NAME "l3gd20h" #define L3G4IS_GYRO_DEV_NAME "l3g4is_ui" #define LSM330_GYRO_DEV_NAME "lsm330_gyro" diff --git a/drivers/iio/gyro/st_gyro_core.c b/drivers/iio/gyro/st_gyro_core.c index d53d91adfb55..a8e174a47bc4 100644 --- a/drivers/iio/gyro/st_gyro_core.c +++ b/drivers/iio/gyro/st_gyro_core.c @@ -167,11 +167,10 @@ static const struct st_sensors st_gyro_sensors[] = { .wai = ST_GYRO_2_WAI_EXP, .sensors_supported = { [0] = L3GD20_GYRO_DEV_NAME, - [1] = L3GD20H_GYRO_DEV_NAME, - [2] = LSM330D_GYRO_DEV_NAME, - [3] = LSM330DLC_GYRO_DEV_NAME, - [4] = L3G4IS_GYRO_DEV_NAME, - [5] = LSM330_GYRO_DEV_NAME, + [1] = LSM330D_GYRO_DEV_NAME, + [2] = LSM330DLC_GYRO_DEV_NAME, + [3] = L3G4IS_GYRO_DEV_NAME, + [4] = LSM330_GYRO_DEV_NAME, }, .ch = (struct iio_chan_spec *)st_gyro_16bit_channels, .odr = { diff --git a/drivers/iio/gyro/st_gyro_i2c.c b/drivers/iio/gyro/st_gyro_i2c.c index 16b8b8d70bf1..23c12f361b05 100644 --- a/drivers/iio/gyro/st_gyro_i2c.c +++ b/drivers/iio/gyro/st_gyro_i2c.c @@ -55,7 +55,6 @@ static const struct i2c_device_id st_gyro_id_table[] = { { LSM330DL_GYRO_DEV_NAME }, { LSM330DLC_GYRO_DEV_NAME }, { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, { L3G4IS_GYRO_DEV_NAME }, { LSM330_GYRO_DEV_NAME }, {}, diff --git a/drivers/iio/gyro/st_gyro_spi.c b/drivers/iio/gyro/st_gyro_spi.c index 94763e25caf9..b4ad3be26687 100644 --- a/drivers/iio/gyro/st_gyro_spi.c +++ b/drivers/iio/gyro/st_gyro_spi.c @@ -54,7 +54,6 @@ static const struct spi_device_id st_gyro_id_table[] = { { LSM330DL_GYRO_DEV_NAME }, { LSM330DLC_GYRO_DEV_NAME }, { L3GD20_GYRO_DEV_NAME }, - { L3GD20H_GYRO_DEV_NAME }, { L3G4IS_GYRO_DEV_NAME }, { LSM330_GYRO_DEV_NAME }, {}, diff --git a/drivers/iio/imu/adis16400.h b/drivers/iio/imu/adis16400.h index 2f8f9d632386..0916bf6b6c31 100644 --- a/drivers/iio/imu/adis16400.h +++ b/drivers/iio/imu/adis16400.h @@ -189,6 +189,7 @@ enum { ADIS16300_SCAN_INCLI_X, ADIS16300_SCAN_INCLI_Y, ADIS16400_SCAN_ADC, + ADIS16400_SCAN_TIMESTAMP, }; #ifdef CONFIG_IIO_BUFFER diff --git a/drivers/iio/imu/adis16400_core.c b/drivers/iio/imu/adis16400_core.c index 368660dfe135..7c582f7ae34e 100644 --- a/drivers/iio/imu/adis16400_core.c +++ b/drivers/iio/imu/adis16400_core.c @@ -632,7 +632,7 @@ static const struct iio_chan_spec adis16400_channels[] = { ADIS16400_MAGN_CHAN(Z, ADIS16400_ZMAGN_OUT, 14), ADIS16400_TEMP_CHAN(ADIS16400_TEMP_OUT, 12), ADIS16400_AUX_ADC_CHAN(ADIS16400_AUX_ADC, 12), - IIO_CHAN_SOFT_TIMESTAMP(12) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16448_channels[] = { @@ -659,7 +659,7 @@ static const struct iio_chan_spec adis16448_channels[] = { }, }, ADIS16400_TEMP_CHAN(ADIS16448_TEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16350_channels[] = { @@ -677,7 +677,7 @@ static const struct iio_chan_spec adis16350_channels[] = { ADIS16400_MOD_TEMP_CHAN(X, ADIS16350_XTEMP_OUT, 12), ADIS16400_MOD_TEMP_CHAN(Y, ADIS16350_YTEMP_OUT, 12), ADIS16400_MOD_TEMP_CHAN(Z, ADIS16350_ZTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(11) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16300_channels[] = { @@ -690,7 +690,7 @@ static const struct iio_chan_spec adis16300_channels[] = { ADIS16400_AUX_ADC_CHAN(ADIS16300_AUX_ADC, 12), ADIS16400_INCLI_CHAN(X, ADIS16300_PITCH_OUT, 13), ADIS16400_INCLI_CHAN(Y, ADIS16300_ROLL_OUT, 13), - IIO_CHAN_SOFT_TIMESTAMP(14) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static const struct iio_chan_spec adis16334_channels[] = { @@ -701,7 +701,7 @@ static const struct iio_chan_spec adis16334_channels[] = { ADIS16400_ACCEL_CHAN(Y, ADIS16400_YACCL_OUT, 14), ADIS16400_ACCEL_CHAN(Z, ADIS16400_ZACCL_OUT, 14), ADIS16400_TEMP_CHAN(ADIS16350_XTEMP_OUT, 12), - IIO_CHAN_SOFT_TIMESTAMP(8) + IIO_CHAN_SOFT_TIMESTAMP(ADIS16400_SCAN_TIMESTAMP), }; static struct attribute *adis16400_attributes[] = { diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c index f17b4e6183c6..47a6dbac2d0c 100644 --- a/drivers/iio/light/cm32181.c +++ b/drivers/iio/light/cm32181.c @@ -103,13 +103,13 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181) /** * cm32181_read_als_it() - Get sensor integration time (ms) * @cm32181: pointer of struct cm32181 - * @val: pointer of int to load the als_it value. + * @val2: pointer of int to load the als_it value. * * Report the current integartion time by millisecond. * - * Return: IIO_VAL_INT for success, otherwise -EINVAL. + * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL. */ -static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val) +static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2) { u16 als_it; int i; @@ -119,8 +119,8 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val) als_it >>= CM32181_CMD_ALS_IT_SHIFT; for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) { if (als_it == als_it_bits[i]) { - *val = als_it_value[i]; - return IIO_VAL_INT; + *val2 = als_it_value[i]; + return IIO_VAL_INT_PLUS_MICRO; } } @@ -221,7 +221,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev, *val = cm32181->calibscale; return IIO_VAL_INT; case IIO_CHAN_INFO_INT_TIME: - ret = cm32181_read_als_it(cm32181, val); + ret = cm32181_read_als_it(cm32181, val2); return ret; } @@ -240,7 +240,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev, cm32181->calibscale = val; return val; case IIO_CHAN_INFO_INT_TIME: - ret = cm32181_write_als_it(cm32181, val); + ret = cm32181_write_als_it(cm32181, val2); return ret; } @@ -264,7 +264,7 @@ static ssize_t cm32181_get_it_available(struct device *dev, n = ARRAY_SIZE(als_it_value); for (i = 0, len = 0; i < n; i++) - len += sprintf(buf + len, "%d ", als_it_value[i]); + len += sprintf(buf + len, "0.%06u ", als_it_value[i]); return len + sprintf(buf + len, "\n"); } diff --git a/drivers/iio/light/cm36651.c b/drivers/iio/light/cm36651.c index 0a142af83e25..a45e07492db3 100644 --- a/drivers/iio/light/cm36651.c +++ b/drivers/iio/light/cm36651.c @@ -50,10 +50,10 @@ #define CM36651_CS_CONF2_DEFAULT_BIT 0x08 /* CS_CONF3 channel integration time */ -#define CM36651_CS_IT1 0x00 /* Integration time 80000 usec */ -#define CM36651_CS_IT2 0x40 /* Integration time 160000 usec */ -#define CM36651_CS_IT3 0x80 /* Integration time 320000 usec */ -#define CM36651_CS_IT4 0xC0 /* Integration time 640000 usec */ +#define CM36651_CS_IT1 0x00 /* Integration time 80 msec */ +#define CM36651_CS_IT2 0x40 /* Integration time 160 msec */ +#define CM36651_CS_IT3 0x80 /* Integration time 320 msec */ +#define CM36651_CS_IT4 0xC0 /* Integration time 640 msec */ /* PS_CONF1 command code */ #define CM36651_PS_ENABLE 0x00 @@ -64,10 +64,10 @@ #define CM36651_PS_PERS4 0x0C /* PS_CONF1 command code: integration time */ -#define CM36651_PS_IT1 0x00 /* Integration time 320 usec */ -#define CM36651_PS_IT2 0x10 /* Integration time 420 usec */ -#define CM36651_PS_IT3 0x20 /* Integration time 520 usec */ -#define CM36651_PS_IT4 0x30 /* Integration time 640 usec */ +#define CM36651_PS_IT1 0x00 /* Integration time 0.32 msec */ +#define CM36651_PS_IT2 0x10 /* Integration time 0.42 msec */ +#define CM36651_PS_IT3 0x20 /* Integration time 0.52 msec */ +#define CM36651_PS_IT4 0x30 /* Integration time 0.64 msec */ /* PS_CONF1 command code: duty ratio */ #define CM36651_PS_DR1 0x00 /* Duty ratio 1/80 */ @@ -93,8 +93,8 @@ #define CM36651_CLOSE_PROXIMITY 0x32 #define CM36651_FAR_PROXIMITY 0x33 -#define CM36651_CS_INT_TIME_AVAIL "80000 160000 320000 640000" -#define CM36651_PS_INT_TIME_AVAIL "320 420 520 640" +#define CM36651_CS_INT_TIME_AVAIL "0.08 0.16 0.32 0.64" +#define CM36651_PS_INT_TIME_AVAIL "0.000320 0.000420 0.000520 0.000640" enum cm36651_operation_mode { CM36651_LIGHT_EN, @@ -356,30 +356,30 @@ static int cm36651_read_channel(struct cm36651_data *cm36651, } static int cm36651_read_int_time(struct cm36651_data *cm36651, - struct iio_chan_spec const *chan, int *val) + struct iio_chan_spec const *chan, int *val2) { switch (chan->type) { case IIO_LIGHT: if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1) - *val = 80000; + *val2 = 80000; else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2) - *val = 160000; + *val2 = 160000; else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3) - *val = 320000; + *val2 = 320000; else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4) - *val = 640000; + *val2 = 640000; else return -EINVAL; break; case IIO_PROXIMITY: if (cm36651->ps_int_time == CM36651_PS_IT1) - *val = 320; + *val2 = 320; else if (cm36651->ps_int_time == CM36651_PS_IT2) - *val = 420; + *val2 = 420; else if (cm36651->ps_int_time == CM36651_PS_IT3) - *val = 520; + *val2 = 520; else if (cm36651->ps_int_time == CM36651_PS_IT4) - *val = 640; + *val2 = 640; else return -EINVAL; break; @@ -387,7 +387,7 @@ static int cm36651_read_int_time(struct cm36651_data *cm36651, return -EINVAL; } - return IIO_VAL_INT; + return IIO_VAL_INT_PLUS_MICRO; } static int cm36651_write_int_time(struct cm36651_data *cm36651, @@ -459,7 +459,8 @@ static int cm36651_read_raw(struct iio_dev *indio_dev, ret = cm36651_read_channel(cm36651, chan, val); break; case IIO_CHAN_INFO_INT_TIME: - ret = cm36651_read_int_time(cm36651, chan, val); + *val = 0; + ret = cm36651_read_int_time(cm36651, chan, val2); break; default: ret = -EINVAL; @@ -479,7 +480,7 @@ static int cm36651_write_raw(struct iio_dev *indio_dev, int ret = -EINVAL; if (mask == IIO_CHAN_INFO_INT_TIME) { - ret = cm36651_write_int_time(cm36651, chan, val); + ret = cm36651_write_int_time(cm36651, chan, val2); if (ret < 0) dev_err(&client->dev, "Integration time write failed\n"); } diff --git a/drivers/iio/light/tsl2563.c b/drivers/iio/light/tsl2563.c index 3d8110157f2d..94daa9fc1247 100644 --- a/drivers/iio/light/tsl2563.c +++ b/drivers/iio/light/tsl2563.c @@ -460,10 +460,14 @@ static int tsl2563_write_raw(struct iio_dev *indio_dev, { struct tsl2563_chip *chip = iio_priv(indio_dev); - if (chan->channel == IIO_MOD_LIGHT_BOTH) + if (mask != IIO_CHAN_INFO_CALIBSCALE) + return -EINVAL; + if (chan->channel2 == IIO_MOD_LIGHT_BOTH) chip->calib0 = calib_from_sysfs(val); - else + else if (chan->channel2 == IIO_MOD_LIGHT_IR) chip->calib1 = calib_from_sysfs(val); + else + return -EINVAL; return 0; } @@ -472,14 +476,14 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, - long m) + long mask) { int ret = -EINVAL; u32 calib0, calib1; struct tsl2563_chip *chip = iio_priv(indio_dev); mutex_lock(&chip->lock); - switch (m) { + switch (mask) { case IIO_CHAN_INFO_RAW: case IIO_CHAN_INFO_PROCESSED: switch (chan->type) { @@ -498,7 +502,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev, ret = tsl2563_get_adc(chip); if (ret) goto error_ret; - if (chan->channel == 0) + if (chan->channel2 == IIO_MOD_LIGHT_BOTH) *val = chip->data0; else *val = chip->data1; @@ -510,7 +514,7 @@ static int tsl2563_read_raw(struct iio_dev *indio_dev, break; case IIO_CHAN_INFO_CALIBSCALE: - if (chan->channel == 0) + if (chan->channel2 == IIO_MOD_LIGHT_BOTH) *val = calib_to_sysfs(chip->calib0); else *val = calib_to_sysfs(chip->calib1); diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c index ff284e5afd95..05423543f89d 100644 --- a/drivers/iio/magnetometer/ak8975.c +++ b/drivers/iio/magnetometer/ak8975.c @@ -85,6 +85,7 @@ #define AK8975_MAX_CONVERSION_TIMEOUT 500 #define AK8975_CONVERSION_DONE_POLL_TIME 10 #define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000) +#define RAW_TO_GAUSS(asa) ((((asa) + 128) * 3000) / 256) /* * Per-instance context data for the device. @@ -265,15 +266,15 @@ static int ak8975_setup(struct i2c_client *client) * * Since 1uT = 0.01 gauss, our final scale factor becomes: * - * Hadj = H * ((ASA + 128) / 256) * 3/10 * 100 - * Hadj = H * ((ASA + 128) * 30 / 256 + * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100 + * Hadj = H * ((ASA + 128) * 0.003) / 256 * * Since ASA doesn't change, we cache the resultant scale factor into the * device context in ak8975_setup(). */ - data->raw_to_gauss[0] = ((data->asa[0] + 128) * 30) >> 8; - data->raw_to_gauss[1] = ((data->asa[1] + 128) * 30) >> 8; - data->raw_to_gauss[2] = ((data->asa[2] + 128) * 30) >> 8; + data->raw_to_gauss[0] = RAW_TO_GAUSS(data->asa[0]); + data->raw_to_gauss[1] = RAW_TO_GAUSS(data->asa[1]); + data->raw_to_gauss[2] = RAW_TO_GAUSS(data->asa[2]); return 0; } @@ -428,8 +429,9 @@ static int ak8975_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_RAW: return ak8975_read_axis(indio_dev, chan->address, val); case IIO_CHAN_INFO_SCALE: - *val = data->raw_to_gauss[chan->address]; - return IIO_VAL_INT; + *val = 0; + *val2 = data->raw_to_gauss[chan->address]; + return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } diff --git a/drivers/iio/magnetometer/mag3110.c b/drivers/iio/magnetometer/mag3110.c index 4b65b6d3bdb1..f66955fb3509 100644 --- a/drivers/iio/magnetometer/mag3110.c +++ b/drivers/iio/magnetometer/mag3110.c @@ -106,7 +106,7 @@ static ssize_t mag3110_show_int_plus_micros(char *buf, while (n-- > 0) len += scnprintf(buf + len, PAGE_SIZE - len, - "%d.%d ", vals[n][0], vals[n][1]); + "%d.%06d ", vals[n][0], vals[n][1]); /* replace trailing space by newline */ buf[len - 1] = '\n'; @@ -154,6 +154,9 @@ static int mag3110_read_raw(struct iio_dev *indio_dev, switch (mask) { case IIO_CHAN_INFO_RAW: + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + switch (chan->type) { case IIO_MAGN: /* in 0.1 uT / LSB */ ret = mag3110_read(data, buffer); @@ -199,6 +202,9 @@ static int mag3110_write_raw(struct iio_dev *indio_dev, struct mag3110_data *data = iio_priv(indio_dev); int rate; + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: rate = mag3110_get_samp_freq_index(data, val, val2); diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c index d53cf519f42a..00400c352c1a 100644 --- a/drivers/infiniband/hw/amso1100/c2.c +++ b/drivers/infiniband/hw/amso1100/c2.c @@ -1082,6 +1082,7 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) /* Initialize network device */ if ((netdev = c2_devinit(c2dev, mmio_regs)) == NULL) { + ret = -ENOMEM; iounmap(mmio_regs); goto bail4; } @@ -1151,7 +1152,8 @@ static int c2_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) goto bail10; } - if (c2_register_device(c2dev)) + ret = c2_register_device(c2dev); + if (ret) goto bail10; return 0; diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c index b7c986990053..d2a6d961344b 100644 --- a/drivers/infiniband/hw/amso1100/c2_rnic.c +++ b/drivers/infiniband/hw/amso1100/c2_rnic.c @@ -576,7 +576,8 @@ int c2_rnic_init(struct c2_dev *c2dev) goto bail4; /* Initialize cached the adapter limits */ - if (c2_rnic_query(c2dev, &c2dev->props)) + err = c2_rnic_query(c2dev, &c2dev->props); + if (err) goto bail5; /* Initialize the PD pool */ diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 45126879ad28..d286bdebe2ab 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -3352,6 +3352,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb) goto free_dst; } + neigh_release(neigh); step = dev->rdev.lldi.nrxq / dev->rdev.lldi.nchan; rss_qid = dev->rdev.lldi.rxq_ids[pi->port_id * step]; window = (__force u16) htons((__force u16)tcph->window); diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c index d1f5f1dd77b0..56a593e0ae5d 100644 --- a/drivers/infiniband/hw/mlx4/cm.c +++ b/drivers/infiniband/hw/mlx4/cm.c @@ -61,6 +61,11 @@ struct cm_generic_msg { __be32 remote_comm_id; }; +struct cm_sidr_generic_msg { + struct ib_mad_hdr hdr; + __be32 request_id; +}; + struct cm_req_msg { unsigned char unused[0x60]; union ib_gid primary_path_sgid; @@ -69,28 +74,62 @@ struct cm_req_msg { static void set_local_comm_id(struct ib_mad *mad, u32 cm_id) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - msg->local_comm_id = cpu_to_be32(cm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + msg->request_id = cpu_to_be32(cm_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + pr_err("trying to set local_comm_id in SIDR_REP\n"); + return; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + msg->local_comm_id = cpu_to_be32(cm_id); + } } static u32 get_local_comm_id(struct ib_mad *mad) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - - return be32_to_cpu(msg->local_comm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + return be32_to_cpu(msg->request_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + pr_err("trying to set local_comm_id in SIDR_REP\n"); + return -1; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + return be32_to_cpu(msg->local_comm_id); + } } static void set_remote_comm_id(struct ib_mad *mad, u32 cm_id) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - msg->remote_comm_id = cpu_to_be32(cm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + msg->request_id = cpu_to_be32(cm_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + pr_err("trying to set remote_comm_id in SIDR_REQ\n"); + return; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + msg->remote_comm_id = cpu_to_be32(cm_id); + } } static u32 get_remote_comm_id(struct ib_mad *mad) { - struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; - - return be32_to_cpu(msg->remote_comm_id); + if (mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { + struct cm_sidr_generic_msg *msg = + (struct cm_sidr_generic_msg *)mad; + return be32_to_cpu(msg->request_id); + } else if (mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + pr_err("trying to set remote_comm_id in SIDR_REQ\n"); + return -1; + } else { + struct cm_generic_msg *msg = (struct cm_generic_msg *)mad; + return be32_to_cpu(msg->remote_comm_id); + } } static union ib_gid gid_from_req_msg(struct ib_device *ibdev, struct ib_mad *mad) @@ -282,19 +321,21 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id u32 sl_cm_id; int pv_cm_id = -1; - sl_cm_id = get_local_comm_id(mad); - if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID || - mad->mad_hdr.attr_id == CM_REP_ATTR_ID) { + mad->mad_hdr.attr_id == CM_REP_ATTR_ID || + mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { + sl_cm_id = get_local_comm_id(mad); id = id_map_alloc(ibdev, slave_id, sl_cm_id); if (IS_ERR(id)) { mlx4_ib_warn(ibdev, "%s: id{slave: %d, sl_cm_id: 0x%x} Failed to id_map_alloc\n", __func__, slave_id, sl_cm_id); return PTR_ERR(id); } - } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID) { + } else if (mad->mad_hdr.attr_id == CM_REJ_ATTR_ID || + mad->mad_hdr.attr_id == CM_SIDR_REP_ATTR_ID) { return 0; } else { + sl_cm_id = get_local_comm_id(mad); id = id_map_get(ibdev, &pv_cm_id, slave_id, sl_cm_id); } @@ -315,14 +356,18 @@ int mlx4_ib_multiplex_cm_handler(struct ib_device *ibdev, int port, int slave_id } int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, - struct ib_mad *mad) + struct ib_mad *mad) { u32 pv_cm_id; struct id_map_entry *id; - if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID) { + if (mad->mad_hdr.attr_id == CM_REQ_ATTR_ID || + mad->mad_hdr.attr_id == CM_SIDR_REQ_ATTR_ID) { union ib_gid gid; + if (!slave) + return 0; + gid = gid_from_req_msg(ibdev, mad); *slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id); if (*slave < 0) { @@ -341,7 +386,8 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, return -ENOENT; } - *slave = id->slave_id; + if (slave) + *slave = id->slave_id; set_remote_comm_id(mad, id->sl_cm_id); if (mad->mad_hdr.attr_id == CM_DREQ_ATTR_ID) diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index cc40f08ca8f1..5f640814cc81 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -564,7 +564,7 @@ static int mlx4_ib_ipoib_csum_ok(__be16 status, __be16 checksum) } static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct ib_wc *wc, - unsigned tail, struct mlx4_cqe *cqe) + unsigned tail, struct mlx4_cqe *cqe, int is_eth) { struct mlx4_ib_proxy_sqp_hdr *hdr; @@ -574,12 +574,20 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct DMA_FROM_DEVICE); hdr = (struct mlx4_ib_proxy_sqp_hdr *) (qp->sqp_proxy_rcv[tail].addr); wc->pkey_index = be16_to_cpu(hdr->tun.pkey_index); - wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32); - wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12); wc->src_qp = be32_to_cpu(hdr->tun.flags_src_qp) & 0xFFFFFF; wc->wc_flags |= (hdr->tun.g_ml_path & 0x80) ? (IB_WC_GRH) : 0; wc->dlid_path_bits = 0; + if (is_eth) { + wc->vlan_id = be16_to_cpu(hdr->tun.sl_vid); + memcpy(&(wc->smac[0]), (char *)&hdr->tun.mac_31_0, 4); + memcpy(&(wc->smac[4]), (char *)&hdr->tun.slid_mac_47_32, 2); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); + } else { + wc->slid = be16_to_cpu(hdr->tun.slid_mac_47_32); + wc->sl = (u8) (be16_to_cpu(hdr->tun.sl_vid) >> 12); + } + return 0; } @@ -594,6 +602,7 @@ static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq, struct mlx4_srq *msrq = NULL; int is_send; int is_error; + int is_eth; u32 g_mlpath_rqpn; u16 wqe_ctr; unsigned tail = 0; @@ -778,11 +787,15 @@ repoll: break; } + is_eth = (rdma_port_get_link_layer(wc->qp->device, + (*cur_qp)->port) == + IB_LINK_LAYER_ETHERNET); if (mlx4_is_mfunc(to_mdev(cq->ibcq.device)->dev)) { if ((*cur_qp)->mlx4_ib_qp_type & (MLX4_IB_QPT_PROXY_SMI_OWNER | MLX4_IB_QPT_PROXY_SMI | MLX4_IB_QPT_PROXY_GSI)) - return use_tunnel_data(*cur_qp, cq, wc, tail, cqe); + return use_tunnel_data(*cur_qp, cq, wc, tail, + cqe, is_eth); } wc->slid = be16_to_cpu(cqe->rlid); @@ -793,20 +806,21 @@ repoll: wc->pkey_index = be32_to_cpu(cqe->immed_rss_invalid) & 0x7f; wc->wc_flags |= mlx4_ib_ipoib_csum_ok(cqe->status, cqe->checksum) ? IB_WC_IP_CSUM_OK : 0; - if (rdma_port_get_link_layer(wc->qp->device, - (*cur_qp)->port) == IB_LINK_LAYER_ETHERNET) + if (is_eth) { wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; - else - wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; - if (be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) { - wc->vlan_id = be16_to_cpu(cqe->sl_vid) & - MLX4_CQE_VID_MASK; + if (be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_VLAN_PRESENT_MASK) { + wc->vlan_id = be16_to_cpu(cqe->sl_vid) & + MLX4_CQE_VID_MASK; + } else { + wc->vlan_id = 0xffff; + } + memcpy(wc->smac, cqe->smac, ETH_ALEN); + wc->wc_flags |= (IB_WC_WITH_VLAN | IB_WC_WITH_SMAC); } else { + wc->sl = be16_to_cpu(cqe->sl_vid) >> 12; wc->vlan_id = 0xffff; } - wc->wc_flags |= IB_WC_WITH_VLAN; - memcpy(wc->smac, cqe->smac, ETH_ALEN); - wc->wc_flags |= IB_WC_WITH_SMAC; } return 0; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index f2a3f48107e7..2c572aed3f6f 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -467,6 +467,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, int ret = 0; u16 tun_pkey_ix; u16 cached_pkey; + u8 is_eth = dev->dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH; if (dest_qpt > IB_QPT_GSI) return -EINVAL; @@ -509,6 +510,10 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, * The driver will set the force loopback bit in post_send */ memset(&attr, 0, sizeof attr); attr.port_num = port; + if (is_eth) { + memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16); + attr.ah_flags = IB_AH_GRH; + } ah = ib_create_ah(tun_ctx->pd, &attr); if (IS_ERR(ah)) return -ENOMEM; @@ -540,11 +545,36 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, /* adjust tunnel data */ tun_mad->hdr.pkey_index = cpu_to_be16(tun_pkey_ix); - tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); - tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid); tun_mad->hdr.flags_src_qp = cpu_to_be32(wc->src_qp & 0xFFFFFF); tun_mad->hdr.g_ml_path = (grh && (wc->wc_flags & IB_WC_GRH)) ? 0x80 : 0; + if (is_eth) { + u16 vlan = 0; + if (mlx4_get_slave_default_vlan(dev->dev, port, slave, &vlan, + NULL)) { + /* VST mode */ + if (vlan != wc->vlan_id) + /* Packet vlan is not the VST-assigned vlan. + * Drop the packet. + */ + goto out; + else + /* Remove the vlan tag before forwarding + * the packet to the VF. + */ + vlan = 0xffff; + } else { + vlan = wc->vlan_id; + } + + tun_mad->hdr.sl_vid = cpu_to_be16(vlan); + memcpy((char *)&tun_mad->hdr.mac_31_0, &(wc->smac[0]), 4); + memcpy((char *)&tun_mad->hdr.slid_mac_47_32, &(wc->smac[4]), 2); + } else { + tun_mad->hdr.sl_vid = cpu_to_be16(((u16)(wc->sl)) << 12); + tun_mad->hdr.slid_mac_47_32 = cpu_to_be16(wc->slid); + } + ib_dma_sync_single_for_device(&dev->ib_dev, tun_qp->tx_ring[tun_tx_ix].buf.map, sizeof (struct mlx4_rcv_tunnel_mad), @@ -580,6 +610,41 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, int err; int slave; u8 *slave_id; + int is_eth = 0; + + if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) + is_eth = 0; + else + is_eth = 1; + + if (is_eth) { + if (!(wc->wc_flags & IB_WC_GRH)) { + mlx4_ib_warn(ibdev, "RoCE grh not present.\n"); + return -EINVAL; + } + if (mad->mad_hdr.mgmt_class != IB_MGMT_CLASS_CM) { + mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n"); + return -EINVAL; + } + if (mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave)) { + mlx4_ib_warn(ibdev, "failed matching grh\n"); + return -ENOENT; + } + if (slave >= dev->dev->caps.sqp_demux) { + mlx4_ib_warn(ibdev, "slave id: %d is bigger than allowed:%d\n", + slave, dev->dev->caps.sqp_demux); + return -ENOENT; + } + + if (mlx4_ib_demux_cm_handler(ibdev, port, NULL, mad)) + return 0; + + err = mlx4_ib_send_to_slave(dev, slave, port, wc->qp->qp_type, wc, grh, mad); + if (err) + pr_debug("failed sending to slave %d via tunnel qp (%d)\n", + slave, err); + return 0; + } /* Initially assume that this mad is for us */ slave = mlx4_master_func_num(dev->dev); @@ -1076,8 +1141,9 @@ static int is_proxy_qp0(struct mlx4_ib_dev *dev, int qpn, int slave) int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, - enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn, - u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad) + enum ib_qp_type dest_qpt, u16 pkey_index, + u32 remote_qpn, u32 qkey, struct ib_ah_attr *attr, + u8 *s_mac, struct ib_mad *mad) { struct ib_sge list; struct ib_send_wr wr, *bad_wr; @@ -1166,6 +1232,9 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, wr.num_sge = 1; wr.opcode = IB_WR_SEND; wr.send_flags = IB_SEND_SIGNALED; + if (s_mac) + memcpy(to_mah(ah)->av.eth.s_mac, s_mac, 6); + ret = ib_post_send(send_qp, &wr, &bad_wr); out: @@ -1174,6 +1243,34 @@ out: return ret; } +static int get_slave_base_gid_ix(struct mlx4_ib_dev *dev, int slave, int port) +{ + int gids; + int vfs; + + if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) + return slave; + + gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; + vfs = dev->dev->num_vfs; + + if (slave == 0) + return 0; + if (slave <= gids % vfs) + return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); + + return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); +} + +static void fill_in_real_sgid_index(struct mlx4_ib_dev *dev, int slave, int port, + struct ib_ah_attr *ah_attr) +{ + if (rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_INFINIBAND) + ah_attr->grh.sgid_index = slave; + else + ah_attr->grh.sgid_index += get_slave_base_gid_ix(dev, slave, port); +} + static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc *wc) { struct mlx4_ib_dev *dev = to_mdev(ctx->ib_dev); @@ -1260,12 +1357,14 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc memcpy(&ah.av, &tunnel->hdr.av, sizeof (struct mlx4_av)); ah.ibah.device = ctx->ib_dev; mlx4_ib_query_ah(&ah.ibah, &ah_attr); - if ((ah_attr.ah_flags & IB_AH_GRH) && - (ah_attr.grh.sgid_index != slave)) { - mlx4_ib_warn(ctx->ib_dev, "slave:%d accessed invalid sgid_index:%d\n", - slave, ah_attr.grh.sgid_index); - return; - } + if (ah_attr.ah_flags & IB_AH_GRH) + fill_in_real_sgid_index(dev, slave, ctx->port, &ah_attr); + + memcpy(ah_attr.dmac, tunnel->hdr.mac, 6); + ah_attr.vlan_id = be16_to_cpu(tunnel->hdr.vlan); + /* if slave have default vlan use it */ + mlx4_get_slave_default_vlan(dev->dev, ctx->port, slave, + &ah_attr.vlan_id, &ah_attr.sl); mlx4_ib_send_to_wire(dev, slave, ctx->port, is_proxy_qp0(dev, wc->src_qp, slave) ? @@ -1273,7 +1372,7 @@ static void mlx4_ib_multiplex_mad(struct mlx4_ib_demux_pv_ctx *ctx, struct ib_wc be16_to_cpu(tunnel->hdr.pkey_index), be32_to_cpu(tunnel->hdr.remote_qpn), be32_to_cpu(tunnel->hdr.qkey), - &ah_attr, &tunnel->mad); + &ah_attr, wc->smac, &tunnel->mad); } static int mlx4_ib_alloc_pv_bufs(struct mlx4_ib_demux_pv_ctx *ctx, diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index c2702f549f10..1d1750ef000a 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -53,8 +53,8 @@ #include "user.h" #define DRV_NAME MLX4_IB_DRV_NAME -#define DRV_VERSION "1.0" -#define DRV_RELDATE "April 4, 2008" +#define DRV_VERSION "2.2-1" +#define DRV_RELDATE "Feb 2014" #define MLX4_IB_FLOW_MAX_PRIO 0xFFF #define MLX4_IB_FLOW_QPN_MASK 0xFFFFFF @@ -347,7 +347,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ? IB_WIDTH_4X : IB_WIDTH_1X; props->active_speed = IB_SPEED_QDR; - props->port_cap_flags = IB_PORT_CM_SUP; + props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_IP_BASED_GIDS; props->gid_tbl_len = mdev->dev->caps.gid_table_len[port]; props->max_msg_sz = mdev->dev->caps.max_msg_sz; props->pkey_tbl_len = 1; @@ -1357,6 +1357,21 @@ static struct device_attribute *mlx4_class_attributes[] = { &dev_attr_board_id }; +static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, + struct net_device *dev) +{ + memcpy(eui, dev->dev_addr, 3); + memcpy(eui + 5, dev->dev_addr + 3, 3); + if (vlan_id < 0x1000) { + eui[3] = vlan_id >> 8; + eui[4] = vlan_id & 0xff; + } else { + eui[3] = 0xff; + eui[4] = 0xfe; + } + eui[0] ^= 2; +} + static void update_gids_task(struct work_struct *work) { struct update_gid_work *gw = container_of(work, struct update_gid_work, work); @@ -1393,7 +1408,6 @@ static void reset_gids_task(struct work_struct *work) struct mlx4_cmd_mailbox *mailbox; union ib_gid *gids; int err; - int i; struct mlx4_dev *dev = gw->dev->dev; mailbox = mlx4_alloc_cmd_mailbox(dev); @@ -1405,18 +1419,16 @@ static void reset_gids_task(struct work_struct *work) gids = mailbox->buf; memcpy(gids, gw->gids, sizeof(gw->gids)); - for (i = 1; i < gw->dev->num_ports + 1; i++) { - if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, i) == - IB_LINK_LAYER_ETHERNET) { - err = mlx4_cmd(dev, mailbox->dma, - MLX4_SET_PORT_GID_TABLE << 8 | i, - 1, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - pr_warn(KERN_WARNING - "set port %d command failed\n", i); - } + if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, gw->port) == + IB_LINK_LAYER_ETHERNET) { + err = mlx4_cmd(dev, mailbox->dma, + MLX4_SET_PORT_GID_TABLE << 8 | gw->port, + 1, MLX4_CMD_SET_PORT, + MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); + if (err) + pr_warn(KERN_WARNING + "set port %d command failed\n", gw->port); } mlx4_free_cmd_mailbox(dev, mailbox); @@ -1425,7 +1437,8 @@ free: } static int update_gid_table(struct mlx4_ib_dev *dev, int port, - union ib_gid *gid, int clear) + union ib_gid *gid, int clear, + int default_gid) { struct update_gid_work *work; int i; @@ -1434,26 +1447,31 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port, int found = -1; int max_gids; - max_gids = dev->dev->caps.gid_table_len[port]; - for (i = 0; i < max_gids; ++i) { - if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid, - sizeof(*gid))) - found = i; - - if (clear) { - if (found >= 0) { - need_update = 1; - dev->iboe.gid_table[port - 1][found] = zgid; - break; - } - } else { - if (found >= 0) - break; - - if (free < 0 && - !memcmp(&dev->iboe.gid_table[port - 1][i], &zgid, + if (default_gid) { + free = 0; + } else { + max_gids = dev->dev->caps.gid_table_len[port]; + for (i = 1; i < max_gids; ++i) { + if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid, sizeof(*gid))) - free = i; + found = i; + + if (clear) { + if (found >= 0) { + need_update = 1; + dev->iboe.gid_table[port - 1][found] = + zgid; + break; + } + } else { + if (found >= 0) + break; + + if (free < 0 && + !memcmp(&dev->iboe.gid_table[port - 1][i], + &zgid, sizeof(*gid))) + free = i; + } } } @@ -1478,18 +1496,26 @@ static int update_gid_table(struct mlx4_ib_dev *dev, int port, return 0; } -static int reset_gid_table(struct mlx4_ib_dev *dev) +static void mlx4_make_default_gid(struct net_device *dev, union ib_gid *gid) { - struct update_gid_work *work; + gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); + mlx4_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev); +} + +static int reset_gid_table(struct mlx4_ib_dev *dev, u8 port) +{ + struct update_gid_work *work; work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) return -ENOMEM; - memset(dev->iboe.gid_table, 0, sizeof(dev->iboe.gid_table)); + + memset(dev->iboe.gid_table[port - 1], 0, sizeof(work->gids)); memset(work->gids, 0, sizeof(work->gids)); INIT_WORK(&work->work, reset_gids_task); work->dev = dev; + work->port = port; queue_work(wq, &work->work); return 0; } @@ -1502,6 +1528,12 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev, struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ? rdma_vlan_dev_real_dev(event_netdev) : event_netdev; + union ib_gid default_gid; + + mlx4_make_default_gid(real_dev, &default_gid); + + if (!memcmp(gid, &default_gid, sizeof(*gid))) + return 0; if (event != NETDEV_DOWN && event != NETDEV_UP) return 0; @@ -1520,7 +1552,7 @@ static int mlx4_ib_addr_event(int event, struct net_device *event_netdev, (!netif_is_bond_master(real_dev) && (real_dev == iboe->netdevs[port - 1]))) update_gid_table(ibdev, port, gid, - event == NETDEV_DOWN); + event == NETDEV_DOWN, 0); spin_unlock(&iboe->lock); return 0; @@ -1536,7 +1568,6 @@ static u8 mlx4_ib_get_dev_port(struct net_device *dev, rdma_vlan_dev_real_dev(dev) : dev; iboe = &ibdev->iboe; - spin_lock(&iboe->lock); for (port = 1; port <= MLX4_MAX_PORTS; ++port) if ((netif_is_bond_master(real_dev) && @@ -1545,8 +1576,6 @@ static u8 mlx4_ib_get_dev_port(struct net_device *dev, (real_dev == iboe->netdevs[port - 1]))) break; - spin_unlock(&iboe->lock); - if ((port == 0) || (port > MLX4_MAX_PORTS)) return 0; else @@ -1607,7 +1636,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev, /*ifa->ifa_address;*/ ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid); - update_gid_table(ibdev, port, &gid, 0); + update_gid_table(ibdev, port, &gid, 0, 0); } endfor_ifa(in_dev); in_dev_put(in_dev); @@ -1619,7 +1648,7 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev, read_lock_bh(&in6_dev->lock); list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { pgid = (union ib_gid *)&ifp->addr; - update_gid_table(ibdev, port, pgid, 0); + update_gid_table(ibdev, port, pgid, 0, 0); } read_unlock_bh(&in6_dev->lock); in6_dev_put(in6_dev); @@ -1627,14 +1656,26 @@ static void mlx4_ib_get_dev_addr(struct net_device *dev, #endif } +static void mlx4_ib_set_default_gid(struct mlx4_ib_dev *ibdev, + struct net_device *dev, u8 port) +{ + union ib_gid gid; + mlx4_make_default_gid(dev, &gid); + update_gid_table(ibdev, port, &gid, 0, 1); +} + static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev) { struct net_device *dev; + struct mlx4_ib_iboe *iboe = &ibdev->iboe; + int i; - if (reset_gid_table(ibdev)) - return -1; + for (i = 1; i <= ibdev->num_ports; ++i) + if (reset_gid_table(ibdev, i)) + return -1; read_lock(&dev_base_lock); + spin_lock(&iboe->lock); for_each_netdev(&init_net, dev) { u8 port = mlx4_ib_get_dev_port(dev, ibdev); @@ -1642,6 +1683,7 @@ static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev) mlx4_ib_get_dev_addr(dev, ibdev, port); } + spin_unlock(&iboe->lock); read_unlock(&dev_base_lock); return 0; @@ -1656,25 +1698,57 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev) spin_lock(&iboe->lock); mlx4_foreach_ib_transport_port(port, ibdev->dev) { + enum ib_port_state port_state = IB_PORT_NOP; struct net_device *old_master = iboe->masters[port - 1]; + struct net_device *curr_netdev; struct net_device *curr_master; + iboe->netdevs[port - 1] = mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port); + if (iboe->netdevs[port - 1]) + mlx4_ib_set_default_gid(ibdev, + iboe->netdevs[port - 1], port); + curr_netdev = iboe->netdevs[port - 1]; if (iboe->netdevs[port - 1] && netif_is_bond_slave(iboe->netdevs[port - 1])) { - rtnl_lock(); iboe->masters[port - 1] = netdev_master_upper_dev_get( iboe->netdevs[port - 1]); - rtnl_unlock(); + } else { + iboe->masters[port - 1] = NULL; } curr_master = iboe->masters[port - 1]; + if (curr_netdev) { + port_state = (netif_running(curr_netdev) && netif_carrier_ok(curr_netdev)) ? + IB_PORT_ACTIVE : IB_PORT_DOWN; + mlx4_ib_set_default_gid(ibdev, curr_netdev, port); + } else { + reset_gid_table(ibdev, port); + } + /* if using bonding/team and a slave port is down, we don't the bond IP + * based gids in the table since flows that select port by gid may get + * the down port. + */ + if (curr_master && (port_state == IB_PORT_DOWN)) { + reset_gid_table(ibdev, port); + mlx4_ib_set_default_gid(ibdev, curr_netdev, port); + } /* if bonding is used it is possible that we add it to masters - only after IP address is assigned to the net bonding - interface */ - if (curr_master && (old_master != curr_master)) + * only after IP address is assigned to the net bonding + * interface. + */ + if (curr_master && (old_master != curr_master)) { + reset_gid_table(ibdev, port); + mlx4_ib_set_default_gid(ibdev, curr_netdev, port); mlx4_ib_get_dev_addr(curr_master, ibdev, port); + } + + if (!curr_master && (old_master != curr_master)) { + reset_gid_table(ibdev, port); + mlx4_ib_set_default_gid(ibdev, curr_netdev, port); + mlx4_ib_get_dev_addr(curr_netdev, ibdev, port); + } } spin_unlock(&iboe->lock); @@ -1810,17 +1884,10 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) int i, j; int err; struct mlx4_ib_iboe *iboe; + int ib_num_ports = 0; pr_info_once("%s", mlx4_ib_version); - mlx4_foreach_non_ib_transport_port(i, dev) - num_ports++; - - if (mlx4_is_mfunc(dev) && num_ports) { - dev_err(&dev->pdev->dev, "RoCE is not supported over SRIOV as yet\n"); - return NULL; - } - num_ports = 0; mlx4_foreach_ib_transport_port(i, dev) num_ports++; @@ -1985,10 +2052,14 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->counters[i] = -1; } + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) + ib_num_ports++; + spin_lock_init(&ibdev->sm_lock); mutex_init(&ibdev->cap_mask_mutex); - if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED) { + if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED && + ib_num_ports) { ibdev->steer_qpn_count = MLX4_IB_UC_MAX_NUM_QPS; err = mlx4_qp_reserve_range(dev, ibdev->steer_qpn_count, MLX4_IB_UC_STEER_QPN_ALIGN, @@ -2051,7 +2122,11 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) } } #endif + for (i = 1 ; i <= ibdev->num_ports ; ++i) + reset_gid_table(ibdev, i); + rtnl_lock(); mlx4_ib_scan_netdevs(ibdev); + rtnl_unlock(); mlx4_ib_init_gid_table(ibdev); } diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index 25b2cdff00f8..ed327e6c8fdc 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -215,8 +215,9 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad) } mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr); spin_unlock(&dev->sm_lock); - return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port, - IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, mad); + return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), + ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY, + &ah_attr, NULL, mad); } static int send_mad_to_slave(int slave, struct mlx4_ib_demux_ctx *ctx, diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index a230683af940..f589522fddfd 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -241,6 +241,22 @@ struct mlx4_ib_proxy_sqp_hdr { struct mlx4_rcv_tunnel_hdr tun; } __packed; +struct mlx4_roce_smac_vlan_info { + u64 smac; + int smac_index; + int smac_port; + u64 candidate_smac; + int candidate_smac_index; + int candidate_smac_port; + u16 vid; + int vlan_index; + int vlan_port; + u16 candidate_vid; + int candidate_vlan_index; + int candidate_vlan_port; + int update_vid; +}; + struct mlx4_ib_qp { struct ib_qp ibqp; struct mlx4_qp mqp; @@ -273,8 +289,9 @@ struct mlx4_ib_qp { struct list_head gid_list; struct list_head steering_rules; struct mlx4_ib_buf *sqp_proxy_rcv; + struct mlx4_roce_smac_vlan_info pri; + struct mlx4_roce_smac_vlan_info alt; u64 reg_id; - }; struct mlx4_ib_srq { @@ -720,9 +737,12 @@ void mlx4_ib_tunnels_update_work(struct work_struct *work); int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, enum ib_qp_type qpt, struct ib_wc *wc, struct ib_grh *grh, struct ib_mad *mad); + int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, enum ib_qp_type dest_qpt, u16 pkey_index, u32 remote_qpn, - u32 qkey, struct ib_ah_attr *attr, struct ib_mad *mad); + u32 qkey, struct ib_ah_attr *attr, u8 *s_mac, + struct ib_mad *mad); + __be64 mlx4_ib_get_new_demux_tid(struct mlx4_ib_demux_ctx *ctx); int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave, diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index d8f4d1fe8494..aadf7f82e1f3 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -662,10 +662,14 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, if (!sqp) return -ENOMEM; qp = &sqp->qp; + qp->pri.vid = 0xFFFF; + qp->alt.vid = 0xFFFF; } else { qp = kzalloc(sizeof (struct mlx4_ib_qp), GFP_KERNEL); if (!qp) return -ENOMEM; + qp->pri.vid = 0xFFFF; + qp->alt.vid = 0xFFFF; } } else qp = *caller_qp; @@ -940,11 +944,32 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, { struct mlx4_ib_cq *send_cq, *recv_cq; - if (qp->state != IB_QPS_RESET) + if (qp->state != IB_QPS_RESET) { if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state), MLX4_QP_STATE_RST, NULL, 0, 0, &qp->mqp)) pr_warn("modify QP %06x to RESET failed.\n", qp->mqp.qpn); + if (qp->pri.smac) { + mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); + qp->pri.smac = 0; + } + if (qp->alt.smac) { + mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); + qp->alt.smac = 0; + } + if (qp->pri.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid); + qp->pri.vid = 0xFFFF; + qp->pri.candidate_vid = 0xFFFF; + qp->pri.update_vid = 0; + } + if (qp->alt.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid); + qp->alt.vid = 0xFFFF; + qp->alt.candidate_vid = 0xFFFF; + qp->alt.update_vid = 0; + } + } get_cqs(qp, &send_cq, &recv_cq); @@ -1057,6 +1082,8 @@ struct ib_qp *mlx4_ib_create_qp(struct ib_pd *pd, qp = kzalloc(sizeof *qp, GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); + qp->pri.vid = 0xFFFF; + qp->alt.vid = 0xFFFF; /* fall through */ case IB_QPT_UD: { @@ -1188,12 +1215,13 @@ static void mlx4_set_sched(struct mlx4_qp_path *path, u8 port) static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, u64 smac, u16 vlan_tag, struct mlx4_qp_path *path, - u8 port) + struct mlx4_roce_smac_vlan_info *smac_info, u8 port) { int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port) == IB_LINK_LAYER_ETHERNET; int vidx; int smac_index; + int err; path->grh_mylmc = ah->src_path_bits & 0x7f; @@ -1223,61 +1251,103 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, } if (is_eth) { - path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | - ((port - 1) << 6) | ((ah->sl & 7) << 3); - if (!(ah->ah_flags & IB_AH_GRH)) return -1; - memcpy(path->dmac, ah->dmac, ETH_ALEN); - path->ackto = MLX4_IB_LINK_TYPE_ETH; - /* find the index into MAC table for IBoE */ - if (!is_zero_ether_addr((const u8 *)&smac)) { - if (mlx4_find_cached_mac(dev->dev, port, smac, - &smac_index)) - return -ENOENT; - } else { - smac_index = 0; - } - - path->grh_mylmc &= 0x80 | smac_index; + path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | + ((port - 1) << 6) | ((ah->sl & 7) << 3); path->feup |= MLX4_FEUP_FORCE_ETH_UP; if (vlan_tag < 0x1000) { - if (mlx4_find_cached_vlan(dev->dev, port, vlan_tag, &vidx)) - return -ENOENT; - - path->vlan_index = vidx; - path->fl = 1 << 6; + if (smac_info->vid < 0x1000) { + /* both valid vlan ids */ + if (smac_info->vid != vlan_tag) { + /* different VIDs. unreg old and reg new */ + err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx); + if (err) + return err; + smac_info->candidate_vid = vlan_tag; + smac_info->candidate_vlan_index = vidx; + smac_info->candidate_vlan_port = port; + smac_info->update_vid = 1; + path->vlan_index = vidx; + } else { + path->vlan_index = smac_info->vlan_index; + } + } else { + /* no current vlan tag in qp */ + err = mlx4_register_vlan(dev->dev, port, vlan_tag, &vidx); + if (err) + return err; + smac_info->candidate_vid = vlan_tag; + smac_info->candidate_vlan_index = vidx; + smac_info->candidate_vlan_port = port; + smac_info->update_vid = 1; + path->vlan_index = vidx; + } path->feup |= MLX4_FVL_FORCE_ETH_VLAN; + path->fl = 1 << 6; + } else { + /* have current vlan tag. unregister it at modify-qp success */ + if (smac_info->vid < 0x1000) { + smac_info->candidate_vid = 0xFFFF; + smac_info->update_vid = 1; + } } - } else + + /* get smac_index for RoCE use. + * If no smac was yet assigned, register one. + * If one was already assigned, but the new mac differs, + * unregister the old one and register the new one. + */ + if (!smac_info->smac || smac_info->smac != smac) { + /* register candidate now, unreg if needed, after success */ + smac_index = mlx4_register_mac(dev->dev, port, smac); + if (smac_index >= 0) { + smac_info->candidate_smac_index = smac_index; + smac_info->candidate_smac = smac; + smac_info->candidate_smac_port = port; + } else { + return -EINVAL; + } + } else { + smac_index = smac_info->smac_index; + } + + memcpy(path->dmac, ah->dmac, 6); + path->ackto = MLX4_IB_LINK_TYPE_ETH; + /* put MAC table smac index for IBoE */ + path->grh_mylmc = (u8) (smac_index) | 0x80; + } else { path->sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((port - 1) << 6) | ((ah->sl & 0xf) << 2); + } return 0; } static int mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp, enum ib_qp_attr_mask qp_attr_mask, + struct mlx4_ib_qp *mqp, struct mlx4_qp_path *path, u8 port) { return _mlx4_set_path(dev, &qp->ah_attr, mlx4_mac_to_u64((u8 *)qp->smac), (qp_attr_mask & IB_QP_VID) ? qp->vlan_id : 0xffff, - path, port); + path, &mqp->pri, port); } static int mlx4_set_alt_path(struct mlx4_ib_dev *dev, const struct ib_qp_attr *qp, enum ib_qp_attr_mask qp_attr_mask, + struct mlx4_ib_qp *mqp, struct mlx4_qp_path *path, u8 port) { return _mlx4_set_path(dev, &qp->alt_ah_attr, mlx4_mac_to_u64((u8 *)qp->alt_smac), (qp_attr_mask & IB_QP_ALT_VID) ? qp->alt_vlan_id : 0xffff, - path, port); + path, &mqp->alt, port); } static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) @@ -1292,6 +1362,37 @@ static void update_mcg_macs(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp) } } +static int handle_eth_ud_smac_index(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp, u8 *smac, + struct mlx4_qp_context *context) +{ + struct net_device *ndev; + u64 u64_mac; + int smac_index; + + + ndev = dev->iboe.netdevs[qp->port - 1]; + if (ndev) { + smac = ndev->dev_addr; + u64_mac = mlx4_mac_to_u64(smac); + } else { + u64_mac = dev->dev->caps.def_mac[qp->port]; + } + + context->pri_path.sched_queue = MLX4_IB_DEFAULT_SCHED_QUEUE | ((qp->port - 1) << 6); + if (!qp->pri.smac) { + smac_index = mlx4_register_mac(dev->dev, qp->port, u64_mac); + if (smac_index >= 0) { + qp->pri.candidate_smac_index = smac_index; + qp->pri.candidate_smac = u64_mac; + qp->pri.candidate_smac_port = qp->port; + context->pri_path.grh_mylmc = 0x80 | (u8) smac_index; + } else { + return -ENOENT; + } + } + return 0; +} + static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, int attr_mask, enum ib_qp_state cur_state, enum ib_qp_state new_state) @@ -1403,7 +1504,7 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, } if (attr_mask & IB_QP_AV) { - if (mlx4_set_path(dev, attr, attr_mask, &context->pri_path, + if (mlx4_set_path(dev, attr, attr_mask, qp, &context->pri_path, attr_mask & IB_QP_PORT ? attr->port_num : qp->port)) goto out; @@ -1426,7 +1527,8 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, dev->dev->caps.pkey_table_len[attr->alt_port_num]) goto out; - if (mlx4_set_alt_path(dev, attr, attr_mask, &context->alt_path, + if (mlx4_set_alt_path(dev, attr, attr_mask, qp, + &context->alt_path, attr->alt_port_num)) goto out; @@ -1532,6 +1634,20 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, context->pri_path.fl = 0x80; context->pri_path.sched_queue |= MLX4_IB_DEFAULT_SCHED_QUEUE; } + if (rdma_port_get_link_layer(&dev->ib_dev, qp->port) == + IB_LINK_LAYER_ETHERNET) { + if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI || + qp->mlx4_ib_qp_type == MLX4_IB_QPT_GSI) + context->pri_path.feup = 1 << 7; /* don't fsm */ + /* handle smac_index */ + if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_UD || + qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI || + qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) { + err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context); + if (err) + return -EINVAL; + } + } } if (qp->ibqp.qp_type == IB_QPT_RAW_PACKET) @@ -1619,28 +1735,113 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, * If we moved a kernel QP to RESET, clean up all old CQ * entries and reinitialize the QP. */ - if (new_state == IB_QPS_RESET && !ibqp->uobject) { - mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, - ibqp->srq ? to_msrq(ibqp->srq): NULL); - if (send_cq != recv_cq) - mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); + if (new_state == IB_QPS_RESET) { + if (!ibqp->uobject) { + mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn, + ibqp->srq ? to_msrq(ibqp->srq) : NULL); + if (send_cq != recv_cq) + mlx4_ib_cq_clean(send_cq, qp->mqp.qpn, NULL); + + qp->rq.head = 0; + qp->rq.tail = 0; + qp->sq.head = 0; + qp->sq.tail = 0; + qp->sq_next_wqe = 0; + if (qp->rq.wqe_cnt) + *qp->db.db = 0; - qp->rq.head = 0; - qp->rq.tail = 0; - qp->sq.head = 0; - qp->sq.tail = 0; - qp->sq_next_wqe = 0; - if (qp->rq.wqe_cnt) - *qp->db.db = 0; + if (qp->flags & MLX4_IB_QP_NETIF) + mlx4_ib_steer_qp_reg(dev, qp, 0); + } + if (qp->pri.smac) { + mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); + qp->pri.smac = 0; + } + if (qp->alt.smac) { + mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); + qp->alt.smac = 0; + } + if (qp->pri.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, qp->pri.vid); + qp->pri.vid = 0xFFFF; + qp->pri.candidate_vid = 0xFFFF; + qp->pri.update_vid = 0; + } - if (qp->flags & MLX4_IB_QP_NETIF) - mlx4_ib_steer_qp_reg(dev, qp, 0); + if (qp->alt.vid < 0x1000) { + mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, qp->alt.vid); + qp->alt.vid = 0xFFFF; + qp->alt.candidate_vid = 0xFFFF; + qp->alt.update_vid = 0; + } } - out: if (err && steer_qp) mlx4_ib_steer_qp_reg(dev, qp, 0); kfree(context); + if (qp->pri.candidate_smac) { + if (err) { + mlx4_unregister_mac(dev->dev, qp->pri.candidate_smac_port, qp->pri.candidate_smac); + } else { + if (qp->pri.smac) + mlx4_unregister_mac(dev->dev, qp->pri.smac_port, qp->pri.smac); + qp->pri.smac = qp->pri.candidate_smac; + qp->pri.smac_index = qp->pri.candidate_smac_index; + qp->pri.smac_port = qp->pri.candidate_smac_port; + } + qp->pri.candidate_smac = 0; + qp->pri.candidate_smac_index = 0; + qp->pri.candidate_smac_port = 0; + } + if (qp->alt.candidate_smac) { + if (err) { + mlx4_unregister_mac(dev->dev, qp->alt.candidate_smac_port, qp->alt.candidate_smac); + } else { + if (qp->alt.smac) + mlx4_unregister_mac(dev->dev, qp->alt.smac_port, qp->alt.smac); + qp->alt.smac = qp->alt.candidate_smac; + qp->alt.smac_index = qp->alt.candidate_smac_index; + qp->alt.smac_port = qp->alt.candidate_smac_port; + } + qp->alt.candidate_smac = 0; + qp->alt.candidate_smac_index = 0; + qp->alt.candidate_smac_port = 0; + } + + if (qp->pri.update_vid) { + if (err) { + if (qp->pri.candidate_vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->pri.candidate_vlan_port, + qp->pri.candidate_vid); + } else { + if (qp->pri.vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->pri.vlan_port, + qp->pri.vid); + qp->pri.vid = qp->pri.candidate_vid; + qp->pri.vlan_port = qp->pri.candidate_vlan_port; + qp->pri.vlan_index = qp->pri.candidate_vlan_index; + } + qp->pri.candidate_vid = 0xFFFF; + qp->pri.update_vid = 0; + } + + if (qp->alt.update_vid) { + if (err) { + if (qp->alt.candidate_vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->alt.candidate_vlan_port, + qp->alt.candidate_vid); + } else { + if (qp->alt.vid < 0x1000) + mlx4_unregister_vlan(dev->dev, qp->alt.vlan_port, + qp->alt.vid); + qp->alt.vid = qp->alt.candidate_vid; + qp->alt.vlan_port = qp->alt.candidate_vlan_port; + qp->alt.vlan_index = qp->alt.candidate_vlan_index; + } + qp->alt.candidate_vid = 0xFFFF; + qp->alt.update_vid = 0; + } + return err; } @@ -1842,9 +2043,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, { struct ib_device *ib_dev = sqp->qp.ibqp.device; struct mlx4_wqe_mlx_seg *mlx = wqe; + struct mlx4_wqe_ctrl_seg *ctrl = wqe; struct mlx4_wqe_inline_seg *inl = wqe + sizeof *mlx; struct mlx4_ib_ah *ah = to_mah(wr->wr.ud.ah); - struct net_device *ndev; union ib_gid sgid; u16 pkey; int send_size; @@ -1868,12 +2069,11 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, /* When multi-function is enabled, the ib_core gid * indexes don't necessarily match the hw ones, so * we must use our own cache */ - sgid.global.subnet_prefix = - to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1]. - subnet_prefix; - sgid.global.interface_id = - to_mdev(ib_dev)->sriov.demux[sqp->qp.port - 1]. - guid_cache[ah->av.ib.gid_index]; + err = mlx4_get_roce_gid_from_slave(to_mdev(ib_dev)->dev, + be32_to_cpu(ah->av.ib.port_pd) >> 24, + ah->av.ib.gid_index, &sgid.raw[0]); + if (err) + return err; } else { err = ib_get_cached_gid(ib_dev, be32_to_cpu(ah->av.ib.port_pd) >> 24, @@ -1902,6 +2102,9 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, sqp->ud_header.grh.flow_label = ah->av.ib.sl_tclass_flowlabel & cpu_to_be32(0xfffff); sqp->ud_header.grh.hop_limit = ah->av.ib.hop_limit; + if (is_eth) + memcpy(sqp->ud_header.grh.source_gid.raw, sgid.raw, 16); + else { if (mlx4_is_mfunc(to_mdev(ib_dev)->dev)) { /* When multi-function is enabled, the ib_core gid * indexes don't necessarily match the hw ones, so @@ -1917,6 +2120,7 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, be32_to_cpu(ah->av.ib.port_pd) >> 24, ah->av.ib.gid_index, &sqp->ud_header.grh.source_gid); + } memcpy(sqp->ud_header.grh.destination_gid.raw, ah->av.ib.dgid, 16); } @@ -1949,16 +2153,23 @@ static int build_mlx_header(struct mlx4_ib_sqp *sqp, struct ib_send_wr *wr, if (is_eth) { u8 *smac; + struct in6_addr in6; + u16 pcp = (be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 29) << 13; mlx->sched_prio = cpu_to_be16(pcp); memcpy(sqp->ud_header.eth.dmac_h, ah->av.eth.mac, 6); /* FIXME: cache smac value? */ - ndev = to_mdev(sqp->qp.ibqp.device)->iboe.netdevs[sqp->qp.port - 1]; - if (!ndev) - return -ENODEV; - smac = ndev->dev_addr; + memcpy(&ctrl->srcrb_flags16[0], ah->av.eth.mac, 2); + memcpy(&ctrl->imm, ah->av.eth.mac + 2, 4); + memcpy(&in6, sgid.raw, sizeof(in6)); + + if (!mlx4_is_mfunc(to_mdev(ib_dev)->dev)) + smac = to_mdev(sqp->qp.ibqp.device)-> + iboe.netdevs[sqp->qp.port - 1]->dev_addr; + else /* use the src mac of the tunnel */ + smac = ah->av.eth.s_mac; memcpy(sqp->ud_header.eth.smac_h, smac, 6); if (!memcmp(sqp->ud_header.eth.smac_h, sqp->ud_header.eth.dmac_h, 6)) mlx->flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK); @@ -2190,6 +2401,8 @@ static void build_tunnel_header(struct ib_send_wr *wr, void *wqe, unsigned *mlx_ hdr.remote_qpn = cpu_to_be32(wr->wr.ud.remote_qpn); hdr.pkey_index = cpu_to_be16(wr->wr.ud.pkey_index); hdr.qkey = cpu_to_be32(wr->wr.ud.remote_qkey); + memcpy(hdr.mac, ah->av.eth.mac, 6); + hdr.vlan = ah->av.eth.vlan; spc = MLX4_INLINE_ALIGN - ((unsigned long) (inl + 1) & (MLX4_INLINE_ALIGN - 1)); diff --git a/drivers/infiniband/hw/mlx5/Kconfig b/drivers/infiniband/hw/mlx5/Kconfig index 8e6aebfaf8a4..10df386c6344 100644 --- a/drivers/infiniband/hw/mlx5/Kconfig +++ b/drivers/infiniband/hw/mlx5/Kconfig @@ -1,6 +1,6 @@ config MLX5_INFINIBAND tristate "Mellanox Connect-IB HCA support" - depends on NETDEVICES && ETHERNET && PCI && X86 + depends on NETDEVICES && ETHERNET && PCI select NET_VENDOR_MELLANOX select MLX5_CORE ---help--- diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 9660d093f8cf..bf900579ac08 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -46,8 +46,8 @@ #include "mlx5_ib.h" #define DRIVER_NAME "mlx5_ib" -#define DRIVER_VERSION "1.0" -#define DRIVER_RELDATE "June 2013" +#define DRIVER_VERSION "2.2-1" +#define DRIVER_RELDATE "Feb 2014" MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); MODULE_DESCRIPTION("Mellanox Connect-IB HCA IB driver"); @@ -261,8 +261,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->device_cap_flags = IB_DEVICE_CHANGE_PHY_PORT | IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SYS_IMAGE_GUID | - IB_DEVICE_RC_RNR_NAK_GEN | - IB_DEVICE_BLOCK_MULTICAST_LOOPBACK; + IB_DEVICE_RC_RNR_NAK_GEN; flags = dev->mdev.caps.flags; if (flags & MLX5_DEV_CAP_FLAG_BAD_PKEY_CNTR) props->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR; @@ -536,24 +535,38 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, struct ib_udata *udata) { struct mlx5_ib_dev *dev = to_mdev(ibdev); - struct mlx5_ib_alloc_ucontext_req req; + struct mlx5_ib_alloc_ucontext_req_v2 req; struct mlx5_ib_alloc_ucontext_resp resp; struct mlx5_ib_ucontext *context; struct mlx5_uuar_info *uuari; struct mlx5_uar *uars; int gross_uuars; int num_uars; + int ver; int uuarn; int err; int i; + int reqlen; if (!dev->ib_active) return ERR_PTR(-EAGAIN); - err = ib_copy_from_udata(&req, udata, sizeof(req)); + memset(&req, 0, sizeof(req)); + reqlen = udata->inlen - sizeof(struct ib_uverbs_cmd_hdr); + if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req)) + ver = 0; + else if (reqlen == sizeof(struct mlx5_ib_alloc_ucontext_req_v2)) + ver = 2; + else + return ERR_PTR(-EINVAL); + + err = ib_copy_from_udata(&req, udata, reqlen); if (err) return ERR_PTR(err); + if (req.flags || req.reserved) + return ERR_PTR(-EINVAL); + if (req.total_num_uuars > MLX5_MAX_UUARS) return ERR_PTR(-ENOMEM); @@ -626,6 +639,7 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, if (err) goto out_uars; + uuari->ver = ver; uuari->num_low_latency_uuars = req.num_low_latency_uuars; uuari->uars = uars; uuari->num_uars = num_uars; diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index ae37fb9bf262..7dfe8a1c84cf 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -216,7 +216,9 @@ static int sq_overhead(enum ib_qp_type qp_type) case IB_QPT_UC: size += sizeof(struct mlx5_wqe_ctrl_seg) + - sizeof(struct mlx5_wqe_raddr_seg); + sizeof(struct mlx5_wqe_raddr_seg) + + sizeof(struct mlx5_wqe_umr_ctrl_seg) + + sizeof(struct mlx5_mkey_seg); break; case IB_QPT_UD: @@ -428,11 +430,17 @@ static int alloc_uuar(struct mlx5_uuar_info *uuari, break; case MLX5_IB_LATENCY_CLASS_MEDIUM: - uuarn = alloc_med_class_uuar(uuari); + if (uuari->ver < 2) + uuarn = -ENOMEM; + else + uuarn = alloc_med_class_uuar(uuari); break; case MLX5_IB_LATENCY_CLASS_HIGH: - uuarn = alloc_high_class_uuar(uuari); + if (uuari->ver < 2) + uuarn = -ENOMEM; + else + uuarn = alloc_high_class_uuar(uuari); break; case MLX5_IB_LATENCY_CLASS_FAST_PATH: @@ -657,8 +665,8 @@ static int create_kernel_qp(struct mlx5_ib_dev *dev, int err; uuari = &dev->mdev.priv.uuari; - if (init_attr->create_flags & IB_QP_CREATE_BLOCK_MULTICAST_LOOPBACK) - qp->flags |= MLX5_IB_QP_BLOCK_MULTICAST_LOOPBACK; + if (init_attr->create_flags) + return -EINVAL; if (init_attr->qp_type == MLX5_IB_QPT_REG_UMR) lc = MLX5_IB_LATENCY_CLASS_FAST_PATH; diff --git a/drivers/infiniband/hw/mlx5/user.h b/drivers/infiniband/hw/mlx5/user.h index 32a2a5dfc523..0f4f8e42a17f 100644 --- a/drivers/infiniband/hw/mlx5/user.h +++ b/drivers/infiniband/hw/mlx5/user.h @@ -62,6 +62,13 @@ struct mlx5_ib_alloc_ucontext_req { __u32 num_low_latency_uuars; }; +struct mlx5_ib_alloc_ucontext_req_v2 { + __u32 total_num_uuars; + __u32 num_low_latency_uuars; + __u32 flags; + __u32 reserved; +}; + struct mlx5_ib_alloc_ucontext_resp { __u32 qp_tab_size; __u32 bf_reg_size; diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 429141078eec..353c7b05a90a 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -675,8 +675,11 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) INIT_DELAYED_WORK(&nesdev->work, nes_recheck_link_status); /* Initialize network devices */ - if ((netdev = nes_netdev_init(nesdev, mmio_regs)) == NULL) + netdev = nes_netdev_init(nesdev, mmio_regs); + if (netdev == NULL) { + ret = -ENOMEM; goto bail7; + } /* Register network device */ ret = register_netdev(netdev); diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index 2ca86ca818bd..1a8a945efa60 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -127,7 +127,7 @@ static int ocrdma_addr_event(unsigned long event, struct net_device *netdev, is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN; if (is_vlan) - netdev = vlan_dev_real_dev(netdev); + netdev = rdma_vlan_dev_real_dev(netdev); rcu_read_lock(); list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) { diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index aa92f40c9d50..e0cc201be41a 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -176,7 +176,7 @@ int ocrdma_query_port(struct ib_device *ibdev, props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP | - IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP; + IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_IP_BASED_GIDS; props->gid_tbl_len = OCRDMA_MAX_SGID; props->pkey_tbl_len = 1; props->bad_pkey_cntr = 0; @@ -1416,7 +1416,7 @@ int ocrdma_query_qp(struct ib_qp *ibqp, OCRDMA_QP_PARAMS_HOP_LMT_MASK) >> OCRDMA_QP_PARAMS_HOP_LMT_SHIFT; qp_attr->ah_attr.grh.traffic_class = (params.tclass_sq_psn & - OCRDMA_QP_PARAMS_SQ_PSN_MASK) >> + OCRDMA_QP_PARAMS_TCLASS_MASK) >> OCRDMA_QP_PARAMS_TCLASS_SHIFT; qp_attr->ah_attr.ah_flags = IB_AH_GRH; diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index 5bfc02f450e6..d1bd21319d7d 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -2395,6 +2395,11 @@ static int qib_7322_bringup_serdes(struct qib_pportdata *ppd) qib_write_kreg_port(ppd, krp_ibcctrl_a, ppd->cpspec->ibcctrl_a); qib_write_kreg(dd, kr_scratch, 0ULL); + /* ensure previous Tx parameters are not still forced */ + qib_write_kreg_port(ppd, krp_tx_deemph_override, + SYM_MASK(IBSD_TX_DEEMPHASIS_OVERRIDE_0, + reset_tx_deemphasis_override)); + if (qib_compat_ddr_negotiate) { ppd->cpspec->ibdeltainprog = 1; ppd->cpspec->ibsymsnap = read_7322_creg32_port(ppd, diff --git a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c index 7ecc6061f1f4..f8dfd76be89f 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c @@ -629,6 +629,7 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow, { enum usnic_transport_type trans_type = qp_flow->trans_type; int err; + uint16_t port_num = 0; switch (trans_type) { case USNIC_TRANSPORT_ROCE_CUSTOM: @@ -637,9 +638,15 @@ static int qp_grp_id_from_flow(struct usnic_ib_qp_grp_flow *qp_flow, case USNIC_TRANSPORT_IPV4_UDP: err = usnic_transport_sock_get_addr(qp_flow->udp.sock, NULL, NULL, - (uint16_t *) id); + &port_num); if (err) return err; + /* + * Copy port_num to stack first and then to *id, + * so that the short to int cast works for little + * and big endian systems. + */ + *id = port_num; break; default: usnic_err("Unsupported transport %u\n", trans_type); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 538822684d5b..334f34b1cd46 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -610,11 +610,12 @@ void iser_snd_completion(struct iser_tx_desc *tx_desc, ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); kmem_cache_free(ig.desc_cache, tx_desc); + tx_desc = NULL; } atomic_dec(&ib_conn->post_send_buf_count); - if (tx_desc->type == ISCSI_TX_CONTROL) { + if (tx_desc && tx_desc->type == ISCSI_TX_CONTROL) { /* this arithmetic is legal by libiscsi dd_data allocation */ task = (void *) ((long)(void *)tx_desc - sizeof(struct iscsi_task)); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index afe95674008b..ca37edef2791 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -652,9 +652,13 @@ static int iser_disconnected_handler(struct rdma_cm_id *cma_id) /* getting here when the state is UP means that the conn is being * * terminated asynchronously from the iSCSI layer's perspective. */ if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP, - ISER_CONN_TERMINATING)) - iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn, - ISCSI_ERR_CONN_FAILED); + ISER_CONN_TERMINATING)){ + if (ib_conn->iser_conn) + iscsi_conn_failure(ib_conn->iser_conn->iscsi_conn, + ISCSI_ERR_CONN_FAILED); + else + iser_err("iscsi_iser connection isn't bound\n"); + } /* Complete the termination process if no posts are pending */ if (ib_conn->post_recv_buf_count == 0 && diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 2b161be3c1a3..d18d08a076e8 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -453,6 +453,7 @@ isert_conn_create_fastreg_pool(struct isert_conn *isert_conn) if (ret) { pr_err("Failed to create fastreg descriptor err=%d\n", ret); + kfree(fr_desc); goto err; } diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 520a7e5a490b..0e537d8d0e47 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3666,9 +3666,9 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rdma_size( unsigned long val; int ret; - ret = strict_strtoul(page, 0, &val); + ret = kstrtoul(page, 0, &val); if (ret < 0) { - pr_err("strict_strtoul() failed with ret: %d\n", ret); + pr_err("kstrtoul() failed with ret: %d\n", ret); return -EINVAL; } if (val > MAX_SRPT_RDMA_SIZE) { @@ -3706,9 +3706,9 @@ static ssize_t srpt_tpg_attrib_store_srp_max_rsp_size( unsigned long val; int ret; - ret = strict_strtoul(page, 0, &val); + ret = kstrtoul(page, 0, &val); if (ret < 0) { - pr_err("strict_strtoul() failed with ret: %d\n", ret); + pr_err("kstrtoul() failed with ret: %d\n", ret); return -EINVAL; } if (val > MAX_SRPT_RSP_SIZE) { @@ -3746,9 +3746,9 @@ static ssize_t srpt_tpg_attrib_store_srp_sq_size( unsigned long val; int ret; - ret = strict_strtoul(page, 0, &val); + ret = kstrtoul(page, 0, &val); if (ret < 0) { - pr_err("strict_strtoul() failed with ret: %d\n", ret); + pr_err("kstrtoul() failed with ret: %d\n", ret); return -EINVAL; } if (val > MAX_SRPT_SRQ_SIZE) { @@ -3793,7 +3793,7 @@ static ssize_t srpt_tpg_store_enable( unsigned long tmp; int ret; - ret = strict_strtoul(page, 0, &tmp); + ret = kstrtoul(page, 0, &tmp); if (ret < 0) { printk(KERN_ERR "Unable to extract srpt_tpg_store_enable\n"); return -EINVAL; diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 7a04f54ef961..ef2e281b0a43 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -37,7 +37,6 @@ static void arizona_haptics_work(struct work_struct *work) struct arizona_haptics, work); struct arizona *arizona = haptics->arizona; - struct mutex *dapm_mutex = &arizona->dapm->card->dapm_mutex; int ret; if (!haptics->arizona->dapm) { @@ -67,13 +66,10 @@ static void arizona_haptics_work(struct work_struct *work) return; } - mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS"); if (ret != 0) { dev_err(arizona->dev, "Failed to start HAPTICS: %d\n", ret); - mutex_unlock(dapm_mutex); return; } @@ -81,21 +77,14 @@ static void arizona_haptics_work(struct work_struct *work) if (ret != 0) { dev_err(arizona->dev, "Failed to sync DAPM: %d\n", ret); - mutex_unlock(dapm_mutex); return; } - - mutex_unlock(dapm_mutex); - } else { /* This disable sequence will be a noop if already enabled */ - mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS"); if (ret != 0) { dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n", ret); - mutex_unlock(dapm_mutex); return; } @@ -103,12 +92,9 @@ static void arizona_haptics_work(struct work_struct *work) if (ret != 0) { dev_err(arizona->dev, "Failed to sync DAPM: %d\n", ret); - mutex_unlock(dapm_mutex); return; } - mutex_unlock(dapm_mutex); - ret = regmap_update_bits(arizona->regmap, ARIZONA_HAPTICS_CONTROL_1, ARIZONA_HAP_CTRL_MASK, @@ -155,16 +141,11 @@ static int arizona_haptics_play(struct input_dev *input, void *data, static void arizona_haptics_close(struct input_dev *input) { struct arizona_haptics *haptics = input_get_drvdata(input); - struct mutex *dapm_mutex = &haptics->arizona->dapm->card->dapm_mutex; cancel_work_sync(&haptics->work); - mutex_lock_nested(dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); - if (haptics->arizona->dapm) snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS"); - - mutex_unlock(dapm_mutex); } static int arizona_haptics_probe(struct platform_device *pdev) diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8911850c9444..1d9ab39af29f 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -79,7 +79,6 @@ #define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES) #define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1)) -#define ARM_SMMU_PTE_HWTABLE_SIZE (PTRS_PER_PTE * sizeof(pte_t)) /* Stage-1 PTE */ #define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6) @@ -191,6 +190,9 @@ #define ARM_SMMU_GR1_CBAR(n) (0x0 + ((n) << 2)) #define CBAR_VMID_SHIFT 0 #define CBAR_VMID_MASK 0xff +#define CBAR_S1_BPSHCFG_SHIFT 8 +#define CBAR_S1_BPSHCFG_MASK 3 +#define CBAR_S1_BPSHCFG_NSH 3 #define CBAR_S1_MEMATTR_SHIFT 12 #define CBAR_S1_MEMATTR_MASK 0xf #define CBAR_S1_MEMATTR_WB 0xf @@ -393,7 +395,7 @@ struct arm_smmu_domain { struct arm_smmu_cfg root_cfg; phys_addr_t output_mask; - struct mutex lock; + spinlock_t lock; }; static DEFINE_SPINLOCK(arm_smmu_devices_lock); @@ -632,6 +634,28 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev) return IRQ_HANDLED; } +static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr, + size_t size) +{ + unsigned long offset = (unsigned long)addr & ~PAGE_MASK; + + + /* Ensure new page tables are visible to the hardware walker */ + if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) { + dsb(); + } else { + /* + * If the SMMU can't walk tables in the CPU caches, treat them + * like non-coherent DMA since we need to flush the new entries + * all the way out to memory. There's no possibility of + * recursion here as the SMMU table walker will not be wired + * through another SMMU. + */ + dma_map_page(smmu->dev, virt_to_page(addr), offset, size, + DMA_TO_DEVICE); + } +} + static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) { u32 reg; @@ -650,11 +674,16 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) if (smmu->version == 1) reg |= root_cfg->irptndx << CBAR_IRPTNDX_SHIFT; - /* Use the weakest memory type, so it is overridden by the pte */ - if (stage1) - reg |= (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); - else + /* + * Use the weakest shareability/memory types, so they are + * overridden by the ttbcr/pte. + */ + if (stage1) { + reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) | + (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); + } else { reg |= ARM_SMMU_CB_VMID(root_cfg) << CBAR_VMID_SHIFT; + } writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBAR(root_cfg->cbndx)); if (smmu->version > 1) { @@ -715,6 +744,8 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain) } /* TTBR0 */ + arm_smmu_flush_pgtable(smmu, root_cfg->pgd, + PTRS_PER_PGD * sizeof(pgd_t)); reg = __pa(root_cfg->pgd); writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO); reg = (phys_addr_t)__pa(root_cfg->pgd) >> 32; @@ -901,7 +932,7 @@ static int arm_smmu_domain_init(struct iommu_domain *domain) goto out_free_domain; smmu_domain->root_cfg.pgd = pgd; - mutex_init(&smmu_domain->lock); + spin_lock_init(&smmu_domain->lock); domain->priv = smmu_domain; return 0; @@ -1128,6 +1159,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) struct arm_smmu_domain *smmu_domain = domain->priv; struct arm_smmu_device *device_smmu = dev->archdata.iommu; struct arm_smmu_master *master; + unsigned long flags; if (!device_smmu) { dev_err(dev, "cannot attach to SMMU, is it on the same bus?\n"); @@ -1138,7 +1170,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) * Sanity check the domain. We don't currently support domains * that cross between different SMMU chains. */ - mutex_lock(&smmu_domain->lock); + spin_lock_irqsave(&smmu_domain->lock, flags); if (!smmu_domain->leaf_smmu) { /* Now that we have a master, we can finalise the domain */ ret = arm_smmu_init_domain_context(domain, dev); @@ -1153,7 +1185,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) dev_name(device_smmu->dev)); goto err_unlock; } - mutex_unlock(&smmu_domain->lock); + spin_unlock_irqrestore(&smmu_domain->lock, flags); /* Looks ok, so add the device to the domain */ master = find_smmu_master(smmu_domain->leaf_smmu, dev->of_node); @@ -1163,7 +1195,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) return arm_smmu_domain_add_master(smmu_domain, master); err_unlock: - mutex_unlock(&smmu_domain->lock); + spin_unlock_irqrestore(&smmu_domain->lock, flags); return ret; } @@ -1177,23 +1209,6 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev) arm_smmu_domain_remove_master(smmu_domain, master); } -static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr, - size_t size) -{ - unsigned long offset = (unsigned long)addr & ~PAGE_MASK; - - /* - * If the SMMU can't walk tables in the CPU caches, treat them - * like non-coherent DMA since we need to flush the new entries - * all the way out to memory. There's no possibility of recursion - * here as the SMMU table walker will not be wired through another - * SMMU. - */ - if (!(smmu->features & ARM_SMMU_FEAT_COHERENT_WALK)) - dma_map_page(smmu->dev, virt_to_page(addr), offset, size, - DMA_TO_DEVICE); -} - static bool arm_smmu_pte_is_contiguous_range(unsigned long addr, unsigned long end) { @@ -1210,12 +1225,11 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd, if (pmd_none(*pmd)) { /* Allocate a new set of tables */ - pgtable_t table = alloc_page(PGALLOC_GFP); + pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO); if (!table) return -ENOMEM; - arm_smmu_flush_pgtable(smmu, page_address(table), - ARM_SMMU_PTE_HWTABLE_SIZE); + arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE); if (!pgtable_page_ctor(table)) { __free_page(table); return -ENOMEM; @@ -1317,9 +1331,15 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud, #ifndef __PAGETABLE_PMD_FOLDED if (pud_none(*pud)) { - pmd = pmd_alloc_one(NULL, addr); + pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC); if (!pmd) return -ENOMEM; + + arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE); + pud_populate(NULL, pud, pmd); + arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); + + pmd += pmd_index(addr); } else #endif pmd = pmd_offset(pud, addr); @@ -1328,8 +1348,6 @@ static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud, next = pmd_addr_end(addr, end); ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, end, pfn, flags, stage); - pud_populate(NULL, pud, pmd); - arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud)); phys += next - addr; } while (pmd++, addr = next, addr < end); @@ -1346,9 +1364,15 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd, #ifndef __PAGETABLE_PUD_FOLDED if (pgd_none(*pgd)) { - pud = pud_alloc_one(NULL, addr); + pud = (pud_t *)get_zeroed_page(GFP_ATOMIC); if (!pud) return -ENOMEM; + + arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE); + pgd_populate(NULL, pgd, pud); + arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); + + pud += pud_index(addr); } else #endif pud = pud_offset(pgd, addr); @@ -1357,8 +1381,6 @@ static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd, next = pud_addr_end(addr, end); ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys, flags, stage); - pgd_populate(NULL, pud, pgd); - arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd)); phys += next - addr; } while (pud++, addr = next, addr < end); @@ -1375,6 +1397,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain, struct arm_smmu_cfg *root_cfg = &smmu_domain->root_cfg; pgd_t *pgd = root_cfg->pgd; struct arm_smmu_device *smmu = root_cfg->smmu; + unsigned long irqflags; if (root_cfg->cbar == CBAR_TYPE_S2_TRANS) { stage = 2; @@ -1397,7 +1420,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain, if (paddr & ~output_mask) return -ERANGE; - mutex_lock(&smmu_domain->lock); + spin_lock_irqsave(&smmu_domain->lock, irqflags); pgd += pgd_index(iova); end = iova + size; do { @@ -1413,11 +1436,7 @@ static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain, } while (pgd++, iova != end); out_unlock: - mutex_unlock(&smmu_domain->lock); - - /* Ensure new page tables are visible to the hardware walker */ - if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) - dsb(); + spin_unlock_irqrestore(&smmu_domain->lock, irqflags); return ret; } @@ -1987,8 +2006,10 @@ static int __init arm_smmu_init(void) if (!iommu_present(&platform_bus_type)) bus_set_iommu(&platform_bus_type, &arm_smmu_ops); +#ifdef CONFIG_ARM_AMBA if (!iommu_present(&amba_bustype)) bus_set_iommu(&amba_bustype, &arm_smmu_ops); +#endif return 0; } diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index d97fbe4fb9b1..80fffba7f12d 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -354,8 +354,8 @@ DEBUG_FOPS(mem); return -ENOMEM; \ } -#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600) -#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400) +#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 0600) +#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 0400) static int iommu_debug_register(struct device *dev, void *data) { diff --git a/drivers/irqchip/irq-metag-ext.c b/drivers/irqchip/irq-metag-ext.c index 92c41ab4dbfd..2cb474ad8809 100644 --- a/drivers/irqchip/irq-metag-ext.c +++ b/drivers/irqchip/irq-metag-ext.c @@ -515,7 +515,7 @@ static int meta_intc_set_affinity(struct irq_data *data, * one cpu (the interrupt code doesn't support it), so we just * pick the first cpu we find in 'cpumask'. */ - cpu = cpumask_any(cpumask); + cpu = cpumask_any_and(cpumask, cpu_online_mask); thread = cpu_2_hwthread_id[cpu]; metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR2(thread)), vec_addr); diff --git a/drivers/irqchip/irq-metag.c b/drivers/irqchip/irq-metag.c index 8e94d7a3b20d..c16c186d97d3 100644 --- a/drivers/irqchip/irq-metag.c +++ b/drivers/irqchip/irq-metag.c @@ -201,7 +201,7 @@ static int metag_internal_irq_set_affinity(struct irq_data *data, * one cpu (the interrupt code doesn't support it), so we just * pick the first cpu we find in 'cpumask'. */ - cpu = cpumask_any(cpumask); + cpu = cpumask_any_and(cpumask, cpu_online_mask); thread = cpu_2_hwthread_id[cpu]; metag_out32(TBI_TRIG_VEC(TBID_SIGNUM_TR1(thread)), diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c index e51d40031884..8e41be62812e 100644 --- a/drivers/irqchip/irq-orion.c +++ b/drivers/irqchip/irq-orion.c @@ -111,7 +111,8 @@ IRQCHIP_DECLARE(orion_intc, "marvell,orion-intc", orion_irq_init); static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) { struct irq_domain *d = irq_get_handler_data(irq); - struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, irq); + + struct irq_chip_generic *gc = irq_get_domain_generic_chip(d, 0); u32 stat = readl_relaxed(gc->reg_base + ORION_BRIDGE_IRQ_CAUSE) & gc->mask_cache; @@ -123,6 +124,19 @@ static void orion_bridge_irq_handler(unsigned int irq, struct irq_desc *desc) } } +/* + * Bridge IRQ_CAUSE is asserted regardless of IRQ_MASK register. + * To avoid interrupt events on stale irqs, we clear them before unmask. + */ +static unsigned int orion_bridge_irq_startup(struct irq_data *d) +{ + struct irq_chip_type *ct = irq_data_get_chip_type(d); + + ct->chip.irq_ack(d); + ct->chip.irq_unmask(d); + return 0; +} + static int __init orion_bridge_irq_init(struct device_node *np, struct device_node *parent) { @@ -143,7 +157,7 @@ static int __init orion_bridge_irq_init(struct device_node *np, } ret = irq_alloc_domain_generic_chips(domain, nrirqs, 1, np->name, - handle_level_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); + handle_edge_irq, clr, 0, IRQ_GC_INIT_MASK_CACHE); if (ret) { pr_err("%s: unable to alloc irq domain gc\n", np->name); return ret; @@ -176,12 +190,14 @@ static int __init orion_bridge_irq_init(struct device_node *np, gc->chip_types[0].regs.ack = ORION_BRIDGE_IRQ_CAUSE; gc->chip_types[0].regs.mask = ORION_BRIDGE_IRQ_MASK; + gc->chip_types[0].chip.irq_startup = orion_bridge_irq_startup; gc->chip_types[0].chip.irq_ack = irq_gc_ack_clr_bit; gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit; gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit; - /* mask all interrupts */ + /* mask and clear all interrupts */ writel(0, gc->reg_base + ORION_BRIDGE_IRQ_MASK); + writel(0, gc->reg_base + ORION_BRIDGE_IRQ_CAUSE); irq_set_handler_data(irq, domain); irq_set_chained_handler(irq, orion_bridge_irq_handler); diff --git a/drivers/isdn/divert/divert_procfs.c b/drivers/isdn/divert/divert_procfs.c index fb4f1bac0133..1c5dc345e7c5 100644 --- a/drivers/isdn/divert/divert_procfs.c +++ b/drivers/isdn/divert/divert_procfs.c @@ -86,12 +86,13 @@ isdn_divert_read(struct file *file, char __user *buf, size_t count, loff_t *off) struct divert_info *inf; int len; - if (!*((struct divert_info **) file->private_data)) { + if (!(inf = *((struct divert_info **) file->private_data))) { if (file->f_flags & O_NONBLOCK) return -EAGAIN; - interruptible_sleep_on(&(rd_queue)); + wait_event_interruptible(rd_queue, (inf = + *((struct divert_info **) file->private_data))); } - if (!(inf = *((struct divert_info **) file->private_data))) + if (!inf) return (0); inf->usage_cnt--; /* new usage count */ diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 2be1c8a3bb5f..d8ef64da26f1 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -509,7 +509,8 @@ static void set_arcofi(struct IsdnCardState *cs, int bc) { cs->dc.isac.arcofi_bc = bc; arcofi_fsm(cs, ARCOFI_START, &ARCOFI_COP_5); - interruptible_sleep_on(&cs->dc.isac.arcofi_wait); + wait_event_interruptible(cs->dc.isac.arcofi_wait, + cs->dc.isac.arcofi_state == ARCOFI_NOP); } static int @@ -528,7 +529,8 @@ check_arcofi(struct IsdnCardState *cs) } cs->dc.isac.arcofi_bc = 0; arcofi_fsm(cs, ARCOFI_START, &ARCOFI_VERSION); - interruptible_sleep_on(&cs->dc.isac.arcofi_wait); + wait_event_interruptible(cs->dc.isac.arcofi_wait, + cs->dc.isac.arcofi_state == ARCOFI_NOP); if (!test_and_clear_bit(FLG_ARCOFI_ERROR, &cs->HW_Flags)) { debugl1(cs, "Arcofi response received %d bytes", cs->dc.isac.mon_rxp); p = cs->dc.isac.mon_rx; @@ -595,7 +597,8 @@ check_arcofi(struct IsdnCardState *cs) Elsa_Types[cs->subtyp], cs->hw.elsa.base + 8); arcofi_fsm(cs, ARCOFI_START, &ARCOFI_XOP_0); - interruptible_sleep_on(&cs->dc.isac.arcofi_wait); + wait_event_interruptible(cs->dc.isac.arcofi_wait, + cs->dc.isac.arcofi_state == ARCOFI_NOP); return (1); } return (0); diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c index 3f84dd8f1757..a2a358c1dc8e 100644 --- a/drivers/isdn/hisax/elsa_ser.c +++ b/drivers/isdn/hisax/elsa_ser.c @@ -573,7 +573,8 @@ modem_l2l1(struct PStack *st, int pr, void *arg) test_and_clear_bit(BC_FLG_ACTIV, &bcs->Flag); bcs->cs->dc.isac.arcofi_bc = st->l1.bc; arcofi_fsm(bcs->cs, ARCOFI_START, &ARCOFI_XOP_0); - interruptible_sleep_on(&bcs->cs->dc.isac.arcofi_wait); + wait_event_interruptible(bcs->cs->dc.isac.arcofi_wait, + bcs->cs->dc.isac.arcofi_state == ARCOFI_NOP); bcs->cs->hw.elsa.MFlag = 1; } else { printk(KERN_WARNING "ElsaSer: unknown pr %x\n", pr); diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index af1b020a81f1..b420f8bd862e 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -810,7 +810,7 @@ prfeatureind(char *dest, u_char *p) dp += sprintf(dp, " octet 3 "); dp += prbits(dp, *p, 8, 8); *dp++ = '\n'; - if (!(*p++ & 80)) { + if (!(*p++ & 0x80)) { dp += sprintf(dp, " octet 4 "); dp += prbits(dp, *p++, 8, 8); *dp++ = '\n'; diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c index b61e8d5e84ad..7b5fd8fb1761 100644 --- a/drivers/isdn/hysdn/hysdn_proclog.c +++ b/drivers/isdn/hysdn/hysdn_proclog.c @@ -175,14 +175,15 @@ hysdn_log_read(struct file *file, char __user *buf, size_t count, loff_t *off) int len; hysdn_card *card = PDE_DATA(file_inode(file)); - if (!*((struct log_data **) file->private_data)) { + if (!(inf = *((struct log_data **) file->private_data))) { struct procdata *pd = card->proclog; if (file->f_flags & O_NONBLOCK) return (-EAGAIN); - interruptible_sleep_on(&(pd->rd_queue)); + wait_event_interruptible(pd->rd_queue, (inf = + *((struct log_data **) file->private_data))); } - if (!(inf = *((struct log_data **) file->private_data))) + if (!inf) return (0); inf->usage_cnt--; /* new usage count */ diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c index 9bb12ba3191f..130f21643154 100644 --- a/drivers/isdn/i4l/isdn_common.c +++ b/drivers/isdn/i4l/isdn_common.c @@ -777,7 +777,8 @@ isdn_readbchan(int di, int channel, u_char *buf, u_char *fp, int len, wait_queue return 0; if (skb_queue_empty(&dev->drv[di]->rpqueue[channel])) { if (sleep) - interruptible_sleep_on(sleep); + wait_event_interruptible(*sleep, + !skb_queue_empty(&dev->drv[di]->rpqueue[channel])); else return 0; } @@ -1072,7 +1073,8 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off) retval = -EAGAIN; goto out; } - interruptible_sleep_on(&(dev->info_waitq)); + wait_event_interruptible(dev->info_waitq, + file->private_data); } p = isdn_statstr(); file->private_data = NULL; @@ -1128,7 +1130,8 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t *off) retval = -EAGAIN; goto out; } - interruptible_sleep_on(&(dev->drv[drvidx]->st_waitq)); + wait_event_interruptible(dev->drv[drvidx]->st_waitq, + dev->drv[drvidx]->stavail); } if (dev->drv[drvidx]->interface->readstat) { if (count > dev->drv[drvidx]->stavail) @@ -1188,8 +1191,8 @@ isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off) goto out; } chidx = isdn_minor2chan(minor); - while ((retval = isdn_writebuf_stub(drvidx, chidx, buf, count)) == 0) - interruptible_sleep_on(&dev->drv[drvidx]->snd_waitq[chidx]); + wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx], + (retval = isdn_writebuf_stub(drvidx, chidx, buf, count))); goto out; } if (minor <= ISDN_MINOR_CTRLMAX) { diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c index 1eaf62273903..f02cc506fbfa 100644 --- a/drivers/isdn/pcbit/drv.c +++ b/drivers/isdn/pcbit/drv.c @@ -796,6 +796,7 @@ static void set_running_timeout(unsigned long ptr) #endif dev = (struct pcbit_dev *) ptr; + dev->l2_state = L2_DOWN; wake_up_interruptible(&dev->set_running_wq); } @@ -818,7 +819,8 @@ static int set_protocol_running(struct pcbit_dev *dev) add_timer(&dev->set_running_timer); - interruptible_sleep_on(&dev->set_running_wq); + wait_event(dev->set_running_wq, dev->l2_state == L2_RUNNING || + dev->l2_state == L2_DOWN); del_timer(&dev->set_running_timer); @@ -842,8 +844,6 @@ static int set_protocol_running(struct pcbit_dev *dev) printk(KERN_DEBUG "pcbit: initialization failed\n"); printk(KERN_DEBUG "pcbit: firmware not loaded\n"); - dev->l2_state = L2_DOWN; - #ifdef DEBUG printk(KERN_DEBUG "Bank3 = %02x\n", readb(dev->sh_mem + BANK3)); diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 0c707e4f4eaf..a4c7306ff43d 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -210,7 +210,9 @@ BITMASK(GC_MARK, struct bucket, gc_mark, 0, 2); #define GC_MARK_RECLAIMABLE 0 #define GC_MARK_DIRTY 1 #define GC_MARK_METADATA 2 -BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, 13); +#define GC_SECTORS_USED_SIZE 13 +#define MAX_GC_SECTORS_USED (~(~0ULL << GC_SECTORS_USED_SIZE)) +BITMASK(GC_SECTORS_USED, struct bucket, gc_mark, 2, GC_SECTORS_USED_SIZE); BITMASK(GC_MOVE, struct bucket, gc_mark, 15, 1); #include "journal.h" diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index 4f6b5940e609..3f74b4b0747b 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c @@ -23,7 +23,7 @@ void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set) for (k = i->start; k < bset_bkey_last(i); k = next) { next = bkey_next(k); - printk(KERN_ERR "block %u key %zi/%u: ", set, + printk(KERN_ERR "block %u key %li/%u: ", set, (uint64_t *) k - i->d, i->keys); if (b->ops->key_dump) @@ -1185,9 +1185,12 @@ static void __btree_sort(struct btree_keys *b, struct btree_iter *iter, struct bset *out = (void *) __get_free_pages(__GFP_NOWARN|GFP_NOIO, order); if (!out) { + struct page *outp; + BUG_ON(order > state->page_order); - out = page_address(mempool_alloc(state->pool, GFP_NOIO)); + outp = mempool_alloc(state->pool, GFP_NOIO); + out = page_address(outp); used_mempool = true; order = state->page_order; } diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 98cc0a810a36..5f9c2a665ca5 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -1167,7 +1167,7 @@ uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k) /* guard against overflow */ SET_GC_SECTORS_USED(g, min_t(unsigned, GC_SECTORS_USED(g) + KEY_SIZE(k), - (1 << 14) - 1)); + MAX_GC_SECTORS_USED)); BUG_ON(!GC_SECTORS_USED(g)); } @@ -1805,7 +1805,7 @@ static bool btree_insert_key(struct btree *b, struct bkey *k, static size_t insert_u64s_remaining(struct btree *b) { - ssize_t ret = bch_btree_keys_u64s_remaining(&b->keys); + long ret = bch_btree_keys_u64s_remaining(&b->keys); /* * Might land in the middle of an existing extent and have to split it diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index c3ead586dc27..416d1a3e028e 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -194,7 +194,7 @@ err: mutex_unlock(&b->c->bucket_lock); bch_extent_to_text(buf, sizeof(buf), k); btree_bug(b, -"inconsistent btree pointer %s: bucket %li pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i", +"inconsistent btree pointer %s: bucket %zi pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i", buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin), g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen); return true; diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index 72cd213f213f..5d5d031cf381 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -353,14 +353,14 @@ static void bch_data_insert_start(struct closure *cl) struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); struct bio *bio = op->bio, *n; - if (op->bypass) - return bch_data_invalidate(cl); - if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) { set_gc_sectors(op->c); wake_up_gc(op->c); } + if (op->bypass) + return bch_data_invalidate(cl); + /* * Journal writes are marked REQ_FLUSH; if the original write was a * flush, it'll wait on the journal write. diff --git a/drivers/md/bcache/sysfs.c b/drivers/md/bcache/sysfs.c index c6ab69333a6d..d8458d477a12 100644 --- a/drivers/md/bcache/sysfs.c +++ b/drivers/md/bcache/sysfs.c @@ -416,7 +416,7 @@ static int btree_bset_stats(struct btree_op *b_op, struct btree *b) return MAP_CONTINUE; } -int bch_bset_print_stats(struct cache_set *c, char *buf) +static int bch_bset_print_stats(struct cache_set *c, char *buf) { struct bset_stats_op op; int ret; diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index ffd472e015ca..1af70145fab9 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -289,6 +289,7 @@ struct per_bio_data { bool tick:1; unsigned req_nr:2; struct dm_deferred_entry *all_io_entry; + struct dm_hook_info hook_info; /* * writethrough fields. These MUST remain at the end of this @@ -297,7 +298,6 @@ struct per_bio_data { */ struct cache *cache; dm_cblock_t cblock; - struct dm_hook_info hook_info; struct dm_bio_details bio_details; }; @@ -671,15 +671,16 @@ static void remap_to_cache(struct cache *cache, struct bio *bio, dm_cblock_t cblock) { sector_t bi_sector = bio->bi_iter.bi_sector; + sector_t block = from_cblock(cblock); bio->bi_bdev = cache->cache_dev->bdev; if (!block_size_is_power_of_two(cache)) bio->bi_iter.bi_sector = - (from_cblock(cblock) * cache->sectors_per_block) + + (block * cache->sectors_per_block) + sector_div(bi_sector, cache->sectors_per_block); else bio->bi_iter.bi_sector = - (from_cblock(cblock) << cache->sectors_per_block_shift) | + (block << cache->sectors_per_block_shift) | (bi_sector & (cache->sectors_per_block - 1)); } @@ -1010,13 +1011,15 @@ static void overwrite_endio(struct bio *bio, int err) struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size); unsigned long flags; + dm_unhook_bio(&pb->hook_info, bio); + if (err) mg->err = true; + mg->requeue_holder = false; + spin_lock_irqsave(&cache->lock, flags); list_add_tail(&mg->list, &cache->completed_migrations); - dm_unhook_bio(&pb->hook_info, bio); - mg->requeue_holder = false; spin_unlock_irqrestore(&cache->lock, flags); wake_worker(cache); diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c index b2b8a10e8427..3842ac738f98 100644 --- a/drivers/md/dm-io.c +++ b/drivers/md/dm-io.c @@ -201,29 +201,28 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse /* * Functions for getting the pages from a bvec. */ -static void bio_get_page(struct dpages *dp, - struct page **p, unsigned long *len, unsigned *offset) +static void bio_get_page(struct dpages *dp, struct page **p, + unsigned long *len, unsigned *offset) { - struct bio *bio = dp->context_ptr; - struct bio_vec bvec = bio_iovec(bio); - *p = bvec.bv_page; - *len = bvec.bv_len; - *offset = bvec.bv_offset; + struct bio_vec *bvec = dp->context_ptr; + *p = bvec->bv_page; + *len = bvec->bv_len - dp->context_u; + *offset = bvec->bv_offset + dp->context_u; } static void bio_next_page(struct dpages *dp) { - struct bio *bio = dp->context_ptr; - struct bio_vec bvec = bio_iovec(bio); - - bio_advance(bio, bvec.bv_len); + struct bio_vec *bvec = dp->context_ptr; + dp->context_ptr = bvec + 1; + dp->context_u = 0; } static void bio_dp_init(struct dpages *dp, struct bio *bio) { dp->get_page = bio_get_page; dp->next_page = bio_next_page; - dp->context_ptr = bio; + dp->context_ptr = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); + dp->context_u = bio->bi_iter.bi_bvec_done; } /* diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index 6eb9dc9ef8f3..422a9fdeb53e 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -1626,8 +1626,11 @@ static int multipath_ioctl(struct dm_target *ti, unsigned int cmd, /* * Only pass ioctls through if the device sizes match exactly. */ - if (!r && ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) - r = scsi_verify_blk_ioctl(NULL, cmd); + if (!bdev || ti->len != i_size_read(bdev->bd_inode) >> SECTOR_SHIFT) { + int err = scsi_verify_blk_ioctl(NULL, cmd); + if (err) + r = err; + } if (r == -ENOTCONN && !fatal_signal_pending(current)) queue_work(kmultipathd, &m->process_queued_ios); diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index f284e0bfb25f..7dfdb5c746d6 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -1244,6 +1244,9 @@ static int mirror_end_io(struct dm_target *ti, struct bio *bio, int error) dm_bio_restore(bd, bio); bio_record->details.bi_bdev = NULL; + + atomic_inc(&bio->bi_remaining); + queue_bio(ms, bio, rw); return DM_ENDIO_INCOMPLETE; } diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c index 7da347665552..baa87ff12816 100644 --- a/drivers/md/dm-thin-metadata.c +++ b/drivers/md/dm-thin-metadata.c @@ -483,7 +483,7 @@ static int __write_initial_superblock(struct dm_pool_metadata *pmd) disk_super->data_mapping_root = cpu_to_le64(pmd->root); disk_super->device_details_root = cpu_to_le64(pmd->details_root); - disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); + disk_super->metadata_block_size = cpu_to_le32(THIN_METADATA_BLOCK_SIZE); disk_super->metadata_nr_blocks = cpu_to_le64(bdev_size >> SECTOR_TO_BLOCK_SHIFT); disk_super->data_block_size = cpu_to_le32(pmd->data_block_size); @@ -651,7 +651,7 @@ static int __create_persistent_data_objects(struct dm_pool_metadata *pmd, bool f { int r; - pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE, + pmd->bm = dm_block_manager_create(pmd->bdev, THIN_METADATA_BLOCK_SIZE << SECTOR_SHIFT, THIN_METADATA_CACHE_SIZE, THIN_MAX_CONCURRENT_LOCKS); if (IS_ERR(pmd->bm)) { @@ -1489,6 +1489,23 @@ bool dm_thin_changed_this_transaction(struct dm_thin_device *td) return r; } +bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd) +{ + bool r = false; + struct dm_thin_device *td, *tmp; + + down_read(&pmd->root_lock); + list_for_each_entry_safe(td, tmp, &pmd->thin_devices, list) { + if (td->changed) { + r = td->changed; + break; + } + } + up_read(&pmd->root_lock); + + return r; +} + bool dm_thin_aborted_changes(struct dm_thin_device *td) { bool r; diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h index 9a368567632f..82ea384d36ff 100644 --- a/drivers/md/dm-thin-metadata.h +++ b/drivers/md/dm-thin-metadata.h @@ -9,16 +9,14 @@ #include "persistent-data/dm-block-manager.h" #include "persistent-data/dm-space-map.h" +#include "persistent-data/dm-space-map-metadata.h" -#define THIN_METADATA_BLOCK_SIZE 4096 +#define THIN_METADATA_BLOCK_SIZE DM_SM_METADATA_BLOCK_SIZE /* * The metadata device is currently limited in size. - * - * We have one block of index, which can hold 255 index entries. Each - * index entry contains allocation info about 16k metadata blocks. */ -#define THIN_METADATA_MAX_SECTORS (255 * (1 << 14) * (THIN_METADATA_BLOCK_SIZE / (1 << SECTOR_SHIFT))) +#define THIN_METADATA_MAX_SECTORS DM_SM_METADATA_MAX_SECTORS /* * A metadata device larger than 16GB triggers a warning. @@ -161,6 +159,8 @@ int dm_thin_remove_block(struct dm_thin_device *td, dm_block_t block); */ bool dm_thin_changed_this_transaction(struct dm_thin_device *td); +bool dm_pool_changed_this_transaction(struct dm_pool_metadata *pmd); + bool dm_thin_aborted_changes(struct dm_thin_device *td); int dm_thin_get_highest_mapped_block(struct dm_thin_device *td, diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index faaf944597ab..7e84baccf0ad 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -1357,7 +1357,8 @@ static void process_deferred_bios(struct pool *pool) bio_list_init(&pool->deferred_flush_bios); spin_unlock_irqrestore(&pool->lock, flags); - if (bio_list_empty(&bios) && !need_commit_due_to_time(pool)) + if (bio_list_empty(&bios) && + !(dm_pool_changed_this_transaction(pool->pmd) && need_commit_due_to_time(pool))) return; if (commit(pool)) { @@ -1999,16 +2000,27 @@ static void metadata_low_callback(void *context) dm_table_event(pool->ti->table); } -static sector_t get_metadata_dev_size(struct block_device *bdev) +static sector_t get_dev_size(struct block_device *bdev) +{ + return i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; +} + +static void warn_if_metadata_device_too_big(struct block_device *bdev) { - sector_t metadata_dev_size = i_size_read(bdev->bd_inode) >> SECTOR_SHIFT; + sector_t metadata_dev_size = get_dev_size(bdev); char buffer[BDEVNAME_SIZE]; - if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) { + if (metadata_dev_size > THIN_METADATA_MAX_SECTORS_WARNING) DMWARN("Metadata device %s is larger than %u sectors: excess space will not be used.", bdevname(bdev, buffer), THIN_METADATA_MAX_SECTORS); - metadata_dev_size = THIN_METADATA_MAX_SECTORS_WARNING; - } +} + +static sector_t get_metadata_dev_size(struct block_device *bdev) +{ + sector_t metadata_dev_size = get_dev_size(bdev); + + if (metadata_dev_size > THIN_METADATA_MAX_SECTORS) + metadata_dev_size = THIN_METADATA_MAX_SECTORS; return metadata_dev_size; } @@ -2017,7 +2029,7 @@ static dm_block_t get_metadata_dev_size_in_blocks(struct block_device *bdev) { sector_t metadata_dev_size = get_metadata_dev_size(bdev); - sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE >> SECTOR_SHIFT); + sector_div(metadata_dev_size, THIN_METADATA_BLOCK_SIZE); return metadata_dev_size; } @@ -2095,12 +2107,7 @@ static int pool_ctr(struct dm_target *ti, unsigned argc, char **argv) ti->error = "Error opening metadata block device"; goto out_unlock; } - - /* - * Run for the side-effect of possibly issuing a warning if the - * device is too big. - */ - (void) get_metadata_dev_size(metadata_dev->bdev); + warn_if_metadata_device_too_big(metadata_dev->bdev); r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev); if (r) { @@ -2287,6 +2294,7 @@ static int maybe_resize_metadata_dev(struct dm_target *ti, bool *need_commit) return -EINVAL; } else if (metadata_dev_size > sb_metadata_dev_size) { + warn_if_metadata_device_too_big(pool->md_dev); DMINFO("%s: growing the metadata device from %llu to %llu blocks", dm_device_name(pool->pool_md), sb_metadata_dev_size, metadata_dev_size); @@ -2894,6 +2902,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) if (get_pool_mode(tc->pool) == PM_FAIL) { ti->error = "Couldn't open thin device, Pool is in fail mode"; + r = -EINVAL; goto bad_thin_open; } @@ -2905,7 +2914,7 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block); if (r) - goto bad_thin_open; + goto bad_target_max_io_len; ti->num_flush_bios = 1; ti->flush_supported = true; @@ -2926,6 +2935,8 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv) return 0; +bad_target_max_io_len: + dm_pool_close_thin_device(tc->td); bad_thin_open: __pool_dec(tc->pool); bad_pool_lookup: diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c index 536782e3bcb7..e9bdd462f4f5 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.c +++ b/drivers/md/persistent-data/dm-space-map-metadata.c @@ -680,6 +680,8 @@ int dm_sm_metadata_create(struct dm_space_map *sm, if (r) return r; + if (nr_blocks > DM_SM_METADATA_MAX_BLOCKS) + nr_blocks = DM_SM_METADATA_MAX_BLOCKS; r = sm_ll_extend(&smm->ll, nr_blocks); if (r) return r; diff --git a/drivers/md/persistent-data/dm-space-map-metadata.h b/drivers/md/persistent-data/dm-space-map-metadata.h index 39bba0801cf2..64df923974d8 100644 --- a/drivers/md/persistent-data/dm-space-map-metadata.h +++ b/drivers/md/persistent-data/dm-space-map-metadata.h @@ -9,6 +9,17 @@ #include "dm-transaction-manager.h" +#define DM_SM_METADATA_BLOCK_SIZE (4096 >> SECTOR_SHIFT) + +/* + * The metadata device is currently limited in size. + * + * We have one block of index, which can hold 255 index entries. Each + * index entry contains allocation info about ~16k metadata blocks. + */ +#define DM_SM_METADATA_MAX_BLOCKS (255 * ((1 << 14) - 64)) +#define DM_SM_METADATA_MAX_SECTORS (DM_SM_METADATA_MAX_BLOCKS * DM_SM_METADATA_BLOCK_SIZE) + /* * Unfortunately we have to use two-phase construction due to the cycle * between the tm and sm. diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index fd3a2a14b587..4a6ca1cb2e78 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1953,11 +1953,15 @@ static int process_checks(struct r1bio *r1_bio) for (i = 0; i < conf->raid_disks * 2; i++) { int j; int size; + int uptodate; struct bio *b = r1_bio->bios[i]; if (b->bi_end_io != end_sync_read) continue; - /* fixup the bio for reuse */ + /* fixup the bio for reuse, but preserve BIO_UPTODATE */ + uptodate = test_bit(BIO_UPTODATE, &b->bi_flags); bio_reset(b); + if (!uptodate) + clear_bit(BIO_UPTODATE, &b->bi_flags); b->bi_vcnt = vcnt; b->bi_iter.bi_size = r1_bio->sectors << 9; b->bi_iter.bi_sector = r1_bio->sector + @@ -1990,11 +1994,14 @@ static int process_checks(struct r1bio *r1_bio) int j; struct bio *pbio = r1_bio->bios[primary]; struct bio *sbio = r1_bio->bios[i]; + int uptodate = test_bit(BIO_UPTODATE, &sbio->bi_flags); if (sbio->bi_end_io != end_sync_read) continue; + /* Now we can 'fixup' the BIO_UPTODATE flag */ + set_bit(BIO_UPTODATE, &sbio->bi_flags); - if (test_bit(BIO_UPTODATE, &sbio->bi_flags)) { + if (uptodate) { for (j = vcnt; j-- ; ) { struct page *p, *s; p = pbio->bi_io_vec[j].bv_page; @@ -2009,7 +2016,7 @@ static int process_checks(struct r1bio *r1_bio) if (j >= 0) atomic64_add(r1_bio->sectors, &mddev->resync_mismatches); if (j < 0 || (test_bit(MD_RECOVERY_CHECK, &mddev->recovery) - && test_bit(BIO_UPTODATE, &sbio->bi_flags))) { + && uptodate)) { /* No need to write to this device. */ sbio->bi_end_io = NULL; rdev_dec_pending(conf->mirrors[i].rdev, mddev); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f1feadeb7bb2..16f5c21963db 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5514,23 +5514,43 @@ raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks) return sectors * (raid_disks - conf->max_degraded); } +static void free_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu) +{ + safe_put_page(percpu->spare_page); + kfree(percpu->scribble); + percpu->spare_page = NULL; + percpu->scribble = NULL; +} + +static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu) +{ + if (conf->level == 6 && !percpu->spare_page) + percpu->spare_page = alloc_page(GFP_KERNEL); + if (!percpu->scribble) + percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); + + if (!percpu->scribble || (conf->level == 6 && !percpu->spare_page)) { + free_scratch_buffer(conf, percpu); + return -ENOMEM; + } + + return 0; +} + static void raid5_free_percpu(struct r5conf *conf) { - struct raid5_percpu *percpu; unsigned long cpu; if (!conf->percpu) return; - get_online_cpus(); - for_each_possible_cpu(cpu) { - percpu = per_cpu_ptr(conf->percpu, cpu); - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); - } #ifdef CONFIG_HOTPLUG_CPU unregister_cpu_notifier(&conf->cpu_notify); #endif + + get_online_cpus(); + for_each_possible_cpu(cpu) + free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); put_online_cpus(); free_percpu(conf->percpu); @@ -5557,15 +5577,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - if (conf->level == 6 && !percpu->spare_page) - percpu->spare_page = alloc_page(GFP_KERNEL); - if (!percpu->scribble) - percpu->scribble = kmalloc(conf->scribble_len, GFP_KERNEL); - - if (!percpu->scribble || - (conf->level == 6 && !percpu->spare_page)) { - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); + if (alloc_scratch_buffer(conf, percpu)) { pr_err("%s: failed memory allocation for cpu%ld\n", __func__, cpu); return notifier_from_errno(-ENOMEM); @@ -5573,10 +5585,7 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, break; case CPU_DEAD: case CPU_DEAD_FROZEN: - safe_put_page(percpu->spare_page); - kfree(percpu->scribble); - percpu->spare_page = NULL; - percpu->scribble = NULL; + free_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); break; default: break; @@ -5588,40 +5597,29 @@ static int raid456_cpu_notify(struct notifier_block *nfb, unsigned long action, static int raid5_alloc_percpu(struct r5conf *conf) { unsigned long cpu; - struct page *spare_page; - struct raid5_percpu __percpu *allcpus; - void *scribble; - int err; + int err = 0; - allcpus = alloc_percpu(struct raid5_percpu); - if (!allcpus) + conf->percpu = alloc_percpu(struct raid5_percpu); + if (!conf->percpu) return -ENOMEM; - conf->percpu = allcpus; + +#ifdef CONFIG_HOTPLUG_CPU + conf->cpu_notify.notifier_call = raid456_cpu_notify; + conf->cpu_notify.priority = 0; + err = register_cpu_notifier(&conf->cpu_notify); + if (err) + return err; +#endif get_online_cpus(); - err = 0; for_each_present_cpu(cpu) { - if (conf->level == 6) { - spare_page = alloc_page(GFP_KERNEL); - if (!spare_page) { - err = -ENOMEM; - break; - } - per_cpu_ptr(conf->percpu, cpu)->spare_page = spare_page; - } - scribble = kmalloc(conf->scribble_len, GFP_KERNEL); - if (!scribble) { - err = -ENOMEM; + err = alloc_scratch_buffer(conf, per_cpu_ptr(conf->percpu, cpu)); + if (err) { + pr_err("%s: failed memory allocation for cpu%ld\n", + __func__, cpu); break; } - per_cpu_ptr(conf->percpu, cpu)->scribble = scribble; } -#ifdef CONFIG_HOTPLUG_CPU - conf->cpu_notify.notifier_call = raid456_cpu_notify; - conf->cpu_notify.priority = 0; - if (err == 0) - err = register_cpu_notifier(&conf->cpu_notify); -#endif put_online_cpus(); return err; diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c index a60c188c2bd9..04bd3b6de401 100644 --- a/drivers/message/i2o/i2o_config.c +++ b/drivers/message/i2o/i2o_config.c @@ -754,19 +754,19 @@ static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret; - mutex_lock(&i2o_cfg_mutex); switch (cmd) { case I2OGETIOPS: ret = i2o_cfg_ioctl(file, cmd, arg); break; case I2OPASSTHRU32: + mutex_lock(&i2o_cfg_mutex); ret = i2o_cfg_passthru32(file, cmd, arg); + mutex_unlock(&i2o_cfg_mutex); break; default: ret = -ENOIOCTLCMD; break; } - mutex_unlock(&i2o_cfg_mutex); return ret; } diff --git a/drivers/mfd/da9055-i2c.c b/drivers/mfd/da9055-i2c.c index 13af7e50021e..8103e4362132 100644 --- a/drivers/mfd/da9055-i2c.c +++ b/drivers/mfd/da9055-i2c.c @@ -53,17 +53,25 @@ static int da9055_i2c_remove(struct i2c_client *i2c) return 0; } +/* + * DO NOT change the device Ids. The naming is intentionally specific as both + * the PMIC and CODEC parts of this chip are instantiated separately as I2C + * devices (both have configurable I2C addresses, and are to all intents and + * purposes separate). As a result there are specific DA9055 ids for PMIC + * and CODEC, which must be different to operate together. + */ static struct i2c_device_id da9055_i2c_id[] = { - {"da9055", 0}, + {"da9055-pmic", 0}, { } }; +MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); static struct i2c_driver da9055_i2c_driver = { .probe = da9055_i2c_probe, .remove = da9055_i2c_remove, .id_table = da9055_i2c_id, .driver = { - .name = "da9055", + .name = "da9055-pmic", .owner = THIS_MODULE, }, }; diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c index ac514fb2b877..71aa14a6bfbb 100644 --- a/drivers/mfd/max14577.c +++ b/drivers/mfd/max14577.c @@ -173,6 +173,7 @@ static const struct i2c_device_id max14577_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, max14577_i2c_id); +#ifdef CONFIG_PM_SLEEP static int max14577_suspend(struct device *dev) { struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); @@ -208,6 +209,7 @@ static int max14577_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_SLEEP */ static struct of_device_id max14577_dt_match[] = { { .compatible = "maxim,max14577", }, diff --git a/drivers/mfd/max8997.c b/drivers/mfd/max8997.c index be88a3bf7b85..5adede0fb04c 100644 --- a/drivers/mfd/max8997.c +++ b/drivers/mfd/max8997.c @@ -164,15 +164,15 @@ static struct max8997_platform_data *max8997_i2c_parse_dt_pdata( return pd; } -static inline int max8997_i2c_get_driver_data(struct i2c_client *i2c, +static inline unsigned long max8997_i2c_get_driver_data(struct i2c_client *i2c, const struct i2c_device_id *id) { if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) { const struct of_device_id *match; match = of_match_node(max8997_pmic_dt_match, i2c->dev.of_node); - return (int)match->data; + return (unsigned long)match->data; } - return (int)id->driver_data; + return id->driver_data; } static int max8997_i2c_probe(struct i2c_client *i2c, diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index 612ca404e150..5d5e186b5d8b 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -169,16 +169,16 @@ static struct max8998_platform_data *max8998_i2c_parse_dt_pdata( return pd; } -static inline int max8998_i2c_get_driver_data(struct i2c_client *i2c, +static inline unsigned long max8998_i2c_get_driver_data(struct i2c_client *i2c, const struct i2c_device_id *id) { if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node) { const struct of_device_id *match; match = of_match_node(max8998_dt_match, i2c->dev.of_node); - return (int)(long)match->data; + return (unsigned long)match->data; } - return (int)id->driver_data; + return id->driver_data; } static int max8998_i2c_probe(struct i2c_client *i2c, diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c index a139798b8065..714e2135210e 100644 --- a/drivers/mfd/sec-core.c +++ b/drivers/mfd/sec-core.c @@ -315,6 +315,7 @@ static int sec_pmic_remove(struct i2c_client *i2c) return 0; } +#ifdef CONFIG_PM_SLEEP static int sec_pmic_suspend(struct device *dev) { struct i2c_client *i2c = container_of(dev, struct i2c_client, dev); @@ -349,6 +350,7 @@ static int sec_pmic_resume(struct device *dev) return 0; } +#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 966cf65c5c36..3cc4c7084b92 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -158,7 +158,7 @@ static int tps65217_probe(struct i2c_client *client, { struct tps65217 *tps; unsigned int version; - unsigned int chip_id = ids->driver_data; + unsigned long chip_id = ids->driver_data; const struct of_device_id *match; bool status_off = false; int ret; @@ -170,7 +170,7 @@ static int tps65217_probe(struct i2c_client *client, "Failed to find matching dt id\n"); return -EINVAL; } - chip_id = (unsigned int)(unsigned long)match->data; + chip_id = (unsigned long)match->data; status_off = of_property_read_bool(client->dev.of_node, "ti,pmic-shutdown-controller"); } diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index ba04f1bc70eb..e6fab94e2c8a 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -636,7 +636,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c, if (i2c->dev.of_node) { of_id = of_match_device(wm8994_of_match, &i2c->dev); if (of_id) - wm8994->type = (int)of_id->data; + wm8994->type = (enum wm8994_type)of_id->data; } else { wm8994->type = id->driver_data; } diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index 8f8a6b327cdb..2c2c9cc75231 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -787,6 +787,7 @@ static int genwqe_pin_mem(struct genwqe_file *cfile, struct genwqe_mem *m) if (rc != 0) { dev_err(&pci_dev->dev, "[%s] genwqe_user_vmap rc=%d\n", __func__, rc); + kfree(dma_map); return rc; } diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c index 1ee2b9492a82..89a557972d1b 100644 --- a/drivers/misc/mei/client.c +++ b/drivers/misc/mei/client.c @@ -666,7 +666,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) goto err; cb->fop_type = MEI_FOP_READ; - cl->read_cb = cb; if (dev->hbuf_is_ready) { dev->hbuf_is_ready = false; if (mei_hbm_cl_flow_control_req(dev, cl)) { @@ -678,6 +677,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length) } else { list_add_tail(&cb->list, &dev->ctrl_wr_list.list); } + + cl->read_cb = cb; + return rets; err: mei_io_cb_free(cb); @@ -908,7 +910,6 @@ void mei_cl_all_disconnect(struct mei_device *dev) list_for_each_entry_safe(cl, next, &dev->file_list, link) { cl->state = MEI_FILE_DISCONNECTED; cl->mei_flow_ctrl_creds = 0; - cl->read_cb = NULL; cl->timer_count = 0; } } @@ -942,8 +943,16 @@ void mei_cl_all_wakeup(struct mei_device *dev) void mei_cl_all_write_clear(struct mei_device *dev) { struct mei_cl_cb *cb, *next; + struct list_head *list; + + list = &dev->write_list.list; + list_for_each_entry_safe(cb, next, list, list) { + list_del(&cb->list); + mei_io_cb_free(cb); + } - list_for_each_entry_safe(cb, next, &dev->write_list.list, list) { + list = &dev->write_waiting_list.list; + list_for_each_entry_safe(cb, next, list, list) { list_del(&cb->list); mei_io_cb_free(cb); } diff --git a/drivers/misc/mic/host/mic_virtio.c b/drivers/misc/mic/host/mic_virtio.c index 752ff873f891..7e1ef0ebbb80 100644 --- a/drivers/misc/mic/host/mic_virtio.c +++ b/drivers/misc/mic/host/mic_virtio.c @@ -156,7 +156,8 @@ static int mic_vringh_copy(struct mic_vdev *mvdev, struct vringh_kiov *iov, static int _mic_virtio_copy(struct mic_vdev *mvdev, struct mic_copy_desc *copy) { - int ret = 0, iovcnt = copy->iovcnt; + int ret = 0; + u32 iovcnt = copy->iovcnt; struct iovec iov; struct iovec __user *u_iov = copy->iov; void __user *ubuf = NULL; diff --git a/drivers/misc/sgi-gru/grukdump.c b/drivers/misc/sgi-gru/grukdump.c index 9b2062d17327..2bef3f76032a 100644 --- a/drivers/misc/sgi-gru/grukdump.c +++ b/drivers/misc/sgi-gru/grukdump.c @@ -139,8 +139,11 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum, ubuf += sizeof(hdr); ubufcch = ubuf; - if (gru_user_copy_handle(&ubuf, cch)) - goto fail; + if (gru_user_copy_handle(&ubuf, cch)) { + if (cch_locked) + unlock_cch_handle(cch); + return -EFAULT; + } if (cch_locked) ubufcch->delresp = 0; bytes = sizeof(hdr) + GRU_CACHE_LINE_BYTES; @@ -179,10 +182,6 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum, ret = -EFAULT; return ret ? ret : bytes; - -fail: - unlock_cch_handle(cch); - return -EFAULT; } int gru_dump_chiplet_request(unsigned long arg) diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 357bbc54fe4b..3e049c13429c 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -197,7 +197,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, struct mmc_queue_req *mqrq_prev = &mq->mqrq[1]; if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask) - limit = dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; + limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT; mq->card = card; mq->queue = blk_init_queue(mmc_request_fn, lock); diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 59eba5d2c685..9715a7ba164a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1584,7 +1584,7 @@ read_retry: } if (mtd->ecc_stats.failed - ecc_failures) { - if (retry_mode + 1 <= chip->read_retries) { + if (retry_mode + 1 < chip->read_retries) { retry_mode++; ret = nand_setup_read_retry(mtd, retry_mode); diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index ef4190a02b7b..bf642ceef681 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1633,6 +1633,7 @@ static int omap_nand_probe(struct platform_device *pdev) int i; dma_cap_mask_t mask; unsigned sig; + unsigned oob_index; struct resource *res; struct mtd_part_parser_data ppdata = {}; @@ -1826,11 +1827,14 @@ static int omap_nand_probe(struct platform_device *pdev) (mtd->writesize / nand_chip->ecc.size); if (nand_chip->options & NAND_BUSWIDTH_16) - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; + oob_index = BADBLOCK_MARKER_LENGTH; else - ecclayout->eccpos[0] = 1; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = 1; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* no reserved-marker in ecclayout for this ecc-scheme */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW: @@ -1847,9 +1851,15 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) { + ecclayout->eccpos[i] = oob_index; + if (((i + 1) % nand_chip->ecc.bytes) == 0) + oob_index++; + } + /* include reserved-marker in ecclayout->oobfree calculation */ + ecclayout->oobfree->offset = 1 + + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; /* software bch library is used for locating errors */ nand_chip->ecc.priv = nand_bch_init(mtd, nand_chip->ecc.size, @@ -1883,9 +1893,12 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* reserved marker already included in ecclayout->eccbytes */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; /* This ECC scheme requires ELM H/W block */ if (is_elm_present(info, pdata->elm_of_node, BCH4_ECC) < 0) { pr_err("nand: error: could not initialize ELM\n"); @@ -1913,9 +1926,15 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) { + ecclayout->eccpos[i] = oob_index; + if (((i + 1) % nand_chip->ecc.bytes) == 0) + oob_index++; + } + /* include reserved-marker in ecclayout->oobfree calculation */ + ecclayout->oobfree->offset = 1 + + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; /* software bch library is used for locating errors */ nand_chip->ecc.priv = nand_bch_init(mtd, nand_chip->ecc.size, @@ -1956,9 +1975,12 @@ static int omap_nand_probe(struct platform_device *pdev) ecclayout->eccbytes = nand_chip->ecc.bytes * (mtd->writesize / nand_chip->ecc.size); - ecclayout->eccpos[0] = BADBLOCK_MARKER_LENGTH; - ecclayout->oobfree->offset = ecclayout->eccpos[0] + - ecclayout->eccbytes; + oob_index = BADBLOCK_MARKER_LENGTH; + for (i = 0; i < ecclayout->eccbytes; i++, oob_index++) + ecclayout->eccpos[i] = oob_index; + /* reserved marker already included in ecclayout->eccbytes */ + ecclayout->oobfree->offset = + ecclayout->eccpos[ecclayout->eccbytes - 1] + 1; break; #else pr_err("nand: error: CONFIG_MTD_NAND_OMAP_BCH not enabled\n"); @@ -1972,11 +1994,8 @@ static int omap_nand_probe(struct platform_device *pdev) goto return_error; } - /* populate remaining ECC layout data */ - ecclayout->oobfree->length = mtd->oobsize - (BADBLOCK_MARKER_LENGTH + - ecclayout->eccbytes); - for (i = 1; i < ecclayout->eccbytes; i++) - ecclayout->eccpos[i] = ecclayout->eccpos[0] + i; + /* all OOB bytes from oobfree->offset till end off OOB are free */ + ecclayout->oobfree->length = mtd->oobsize - ecclayout->oobfree->offset; /* check if NAND device's OOB is enough to store ECC signatures */ if (mtd->oobsize < (ecclayout->eccbytes + BADBLOCK_MARKER_LENGTH)) { pr_err("not enough OOB bytes required = %d, available=%d\n", diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c index ead861307b3c..c5dad652614d 100644 --- a/drivers/mtd/ubi/fastmap.c +++ b/drivers/mtd/ubi/fastmap.c @@ -463,8 +463,8 @@ static int scan_pool(struct ubi_device *ubi, struct ubi_attach_info *ai, } } if (found_orphan) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); list_del(&tmp_aeb->u.list); + kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); } new_aeb = kmem_cache_alloc(ai->aeb_slab_cache, @@ -846,16 +846,16 @@ fail_bad: ret = UBI_BAD_FASTMAP; fail: list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &used, u.list) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); list_del(&tmp_aeb->u.list); + kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); } list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &eba_orphans, u.list) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); list_del(&tmp_aeb->u.list); + kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); } list_for_each_entry_safe(tmp_aeb, _tmp_aeb, &free, u.list) { - kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); list_del(&tmp_aeb->u.list); + kmem_cache_free(ai->aeb_slab_cache, tmp_aeb); } return ret; diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f342278539d5..494b888a6568 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -139,7 +139,7 @@ config MACVTAP This adds a specialized tap character device driver that is based on the MAC-VLAN network interface, called macvtap. A macvtap device can be added in the same way as a macvlan device, using 'type - macvlan', and then be accessed through the tap user space interface. + macvtap', and then be accessed through the tap user space interface. To compile this driver as a module, choose M here: the module will be called macvtap. diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index cce1f1bf90b4..dee2a84a2929 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -181,7 +181,7 @@ static inline int __agg_has_partner(struct aggregator *agg) */ static inline void __disable_port(struct port *port) { - bond_set_slave_inactive_flags(port->slave); + bond_set_slave_inactive_flags(port->slave, BOND_SLAVE_NOTIFY_LATER); } /** @@ -193,7 +193,7 @@ static inline void __enable_port(struct port *port) struct slave *slave = port->slave; if ((slave->link == BOND_LINK_UP) && IS_UP(slave->dev)) - bond_set_slave_active_flags(slave); + bond_set_slave_active_flags(slave, BOND_SLAVE_NOTIFY_LATER); } /** @@ -768,11 +768,11 @@ static int ad_lacpdu_send(struct port *port) lacpdu_header = (struct lacpdu_header *)skb_put(skb, length); - memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); + ether_addr_copy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr); /* Note: source address is set to be the member's PERMANENT address, * because we use it to identify loopback lacpdus in receive. */ - memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); + ether_addr_copy(lacpdu_header->hdr.h_source, slave->perm_hwaddr); lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU; lacpdu_header->lacpdu = port->lacpdu; @@ -810,11 +810,11 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) marker_header = (struct bond_marker_header *)skb_put(skb, length); - memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); + ether_addr_copy(marker_header->hdr.h_dest, lacpdu_mcast_addr); /* Note: source address is set to be the member's PERMANENT address, * because we use it to identify loopback MARKERs in receive. */ - memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); + ether_addr_copy(marker_header->hdr.h_source, slave->perm_hwaddr); marker_header->hdr.h_proto = PKT_TYPE_LACPDU; marker_header->marker = *marker; @@ -1079,7 +1079,8 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) /* detect loopback situation */ 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", + 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); return; @@ -1796,8 +1797,6 @@ void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout) BOND_AD_INFO(bond).agg_select_timer = timeout; } -static u16 aggregator_identifier; - /** * bond_3ad_initialize - initialize a bond's 802.3ad parameters and structures * @bond: bonding struct to work on @@ -1811,7 +1810,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution) if (!MAC_ADDRESS_EQUAL(&(BOND_AD_INFO(bond).system.sys_mac_addr), bond->dev->dev_addr)) { - aggregator_identifier = 0; + BOND_AD_INFO(bond).aggregator_identifier = 0; BOND_AD_INFO(bond).system.sys_priority = 0xFFFF; BOND_AD_INFO(bond).system.sys_mac_addr = *((struct mac_addr *)bond->dev->dev_addr); @@ -1880,7 +1879,7 @@ void bond_3ad_bind_slave(struct slave *slave) ad_initialize_agg(aggregator); aggregator->aggregator_mac_address = *((struct mac_addr *)bond->dev->dev_addr); - aggregator->aggregator_identifier = (++aggregator_identifier); + aggregator->aggregator_identifier = ++BOND_AD_INFO(bond).aggregator_identifier; aggregator->slave = slave; aggregator->is_active = 0; aggregator->num_of_ports = 0; @@ -1950,7 +1949,7 @@ void bond_3ad_unbind_slave(struct slave *slave) * 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", + pr_debug("Some port(s) related to LAG %d - replacing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); @@ -2064,6 +2063,7 @@ void bond_3ad_state_machine_handler(struct work_struct *work) struct list_head *iter; struct slave *slave; struct port *port; + bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER; read_lock(&bond->lock); rcu_read_lock(); @@ -2121,8 +2121,19 @@ void bond_3ad_state_machine_handler(struct work_struct *work) } re_arm: + bond_for_each_slave_rcu(bond, slave, iter) { + if (slave->should_notify) { + should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW; + break; + } + } rcu_read_unlock(); read_unlock(&bond->lock); + + if (should_notify_rtnl && rtnl_trylock()) { + bond_slave_state_notify(bond); + rtnl_unlock(); + } queue_delayed_work(bond->wq, &bond->ad_work, ad_delta_in_ticks); } @@ -2300,9 +2311,9 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) port->actor_oper_port_key = (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS); } - pr_debug("Port %d changed link status to %s", - port->actor_port_number, - (link == BOND_LINK_UP) ? "UP" : "DOWN"); + pr_debug("Port %d changed link status to %s\n", + port->actor_port_number, + link == BOND_LINK_UP ? "UP" : "DOWN"); /* there is no need to reselect a new aggregator, just signal the * state machines to reinitialize */ @@ -2380,17 +2391,16 @@ int __bond_3ad_get_active_agg_info(struct bonding *bond, } } - if (aggregator) { - ad_info->aggregator_id = aggregator->aggregator_identifier; - 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); - return 0; - } + if (!aggregator) + return -1; - return -1; + ad_info->aggregator_id = aggregator->aggregator_identifier; + 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; + ether_addr_copy(ad_info->partner_system, + aggregator->partner_system.mac_addr_value); + return 0; } /* Wrapper used to hold bond->lock so no slave manipulation can occur */ @@ -2469,7 +2479,7 @@ out: return NETDEV_TX_OK; err_free: /* no suitable interface, frame not sent */ - kfree_skb(skb); + dev_kfree_skb_any(skb); goto out; } diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index 13dc9d3c5e34..bb03b1df2f3e 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -28,7 +28,7 @@ #include <linux/netdevice.h> #include <linux/if_ether.h> -// General definitions +/* General definitions */ #define PKT_TYPE_LACPDU cpu_to_be16(ETH_P_SLOW) #define AD_TIMER_INTERVAL 100 /*msec*/ @@ -47,54 +47,54 @@ enum { BOND_AD_COUNT = 2, }; -// rx machine states(43.4.11 in the 802.3ad standard) +/* rx machine states(43.4.11 in the 802.3ad standard) */ typedef enum { AD_RX_DUMMY, - AD_RX_INITIALIZE, // rx Machine - AD_RX_PORT_DISABLED, // rx Machine - AD_RX_LACP_DISABLED, // rx Machine - AD_RX_EXPIRED, // rx Machine - AD_RX_DEFAULTED, // rx Machine - AD_RX_CURRENT // rx Machine + AD_RX_INITIALIZE, /* rx Machine */ + AD_RX_PORT_DISABLED, /* rx Machine */ + AD_RX_LACP_DISABLED, /* rx Machine */ + AD_RX_EXPIRED, /* rx Machine */ + AD_RX_DEFAULTED, /* rx Machine */ + AD_RX_CURRENT /* rx Machine */ } rx_states_t; -// periodic machine states(43.4.12 in the 802.3ad standard) +/* periodic machine states(43.4.12 in the 802.3ad standard) */ typedef enum { AD_PERIODIC_DUMMY, - AD_NO_PERIODIC, // periodic machine - AD_FAST_PERIODIC, // periodic machine - AD_SLOW_PERIODIC, // periodic machine - AD_PERIODIC_TX // periodic machine + AD_NO_PERIODIC, /* periodic machine */ + AD_FAST_PERIODIC, /* periodic machine */ + AD_SLOW_PERIODIC, /* periodic machine */ + AD_PERIODIC_TX /* periodic machine */ } periodic_states_t; -// mux machine states(43.4.13 in the 802.3ad standard) +/* mux machine states(43.4.13 in the 802.3ad standard) */ typedef enum { AD_MUX_DUMMY, - AD_MUX_DETACHED, // mux machine - AD_MUX_WAITING, // mux machine - AD_MUX_ATTACHED, // mux machine - AD_MUX_COLLECTING_DISTRIBUTING // mux machine + AD_MUX_DETACHED, /* mux machine */ + AD_MUX_WAITING, /* mux machine */ + AD_MUX_ATTACHED, /* mux machine */ + AD_MUX_COLLECTING_DISTRIBUTING /* mux machine */ } mux_states_t; -// tx machine states(43.4.15 in the 802.3ad standard) +/* tx machine states(43.4.15 in the 802.3ad standard) */ typedef enum { AD_TX_DUMMY, - AD_TRANSMIT // tx Machine + AD_TRANSMIT /* tx Machine */ } tx_states_t; -// rx indication types +/* rx indication types */ typedef enum { - AD_TYPE_LACPDU = 1, // type lacpdu - AD_TYPE_MARKER // type marker + AD_TYPE_LACPDU = 1, /* type lacpdu */ + AD_TYPE_MARKER /* type marker */ } pdu_type_t; -// rx marker indication types +/* rx marker indication types */ typedef enum { - AD_MARKER_INFORMATION_SUBTYPE = 1, // marker imformation subtype - AD_MARKER_RESPONSE_SUBTYPE // marker response subtype + AD_MARKER_INFORMATION_SUBTYPE = 1, /* marker imformation subtype */ + AD_MARKER_RESPONSE_SUBTYPE /* marker response subtype */ } bond_marker_subtype_t; -// timers types(43.4.9 in the 802.3ad standard) +/* timers types(43.4.9 in the 802.3ad standard) */ typedef enum { AD_CURRENT_WHILE_TIMER, AD_ACTOR_CHURN_TIMER, @@ -105,35 +105,35 @@ typedef enum { #pragma pack(1) -// Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) +/* Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) */ typedef struct lacpdu { - u8 subtype; // = LACP(= 0x01) + u8 subtype; /* = LACP(= 0x01) */ u8 version_number; - u8 tlv_type_actor_info; // = actor information(type/length/value) - u8 actor_information_length; // = 20 + u8 tlv_type_actor_info; /* = actor information(type/length/value) */ + u8 actor_information_length; /* = 20 */ __be16 actor_system_priority; struct mac_addr actor_system; __be16 actor_key; __be16 actor_port_priority; __be16 actor_port; u8 actor_state; - u8 reserved_3_1[3]; // = 0 - u8 tlv_type_partner_info; // = partner information - u8 partner_information_length; // = 20 + u8 reserved_3_1[3]; /* = 0 */ + u8 tlv_type_partner_info; /* = partner information */ + u8 partner_information_length; /* = 20 */ __be16 partner_system_priority; struct mac_addr partner_system; __be16 partner_key; __be16 partner_port_priority; __be16 partner_port; u8 partner_state; - u8 reserved_3_2[3]; // = 0 - u8 tlv_type_collector_info; // = collector information - u8 collector_information_length; // = 16 + u8 reserved_3_2[3]; /* = 0 */ + u8 tlv_type_collector_info; /* = collector information */ + u8 collector_information_length;/* = 16 */ __be16 collector_max_delay; u8 reserved_12[12]; - u8 tlv_type_terminator; // = terminator - u8 terminator_length; // = 0 - u8 reserved_50[50]; // = 0 + u8 tlv_type_terminator; /* = terminator */ + u8 terminator_length; /* = 0 */ + u8 reserved_50[50]; /* = 0 */ } __packed lacpdu_t; typedef struct lacpdu_header { @@ -141,20 +141,20 @@ typedef struct lacpdu_header { struct lacpdu lacpdu; } __packed lacpdu_header_t; -// Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) +/* Marker Protocol Data Unit(PDU) structure(43.5.3.2 in the 802.3ad standard) */ typedef struct bond_marker { - u8 subtype; // = 0x02 (marker PDU) - u8 version_number; // = 0x01 - u8 tlv_type; // = 0x01 (marker information) - // = 0x02 (marker response information) - u8 marker_length; // = 0x16 - u16 requester_port; // The number assigned to the port by the requester - struct mac_addr requester_system; // The requester's system id - u32 requester_transaction_id; // The transaction id allocated by the requester, - u16 pad; // = 0 - u8 tlv_type_terminator; // = 0x00 - u8 terminator_length; // = 0x00 - u8 reserved_90[90]; // = 0 + u8 subtype; /* = 0x02 (marker PDU) */ + u8 version_number; /* = 0x01 */ + u8 tlv_type; /* = 0x01 (marker information) */ + /* = 0x02 (marker response information) */ + u8 marker_length; /* = 0x16 */ + u16 requester_port; /* The number assigned to the port by the requester */ + struct mac_addr requester_system; /* The requester's system id */ + u32 requester_transaction_id; /* The transaction id allocated by the requester, */ + u16 pad; /* = 0 */ + u8 tlv_type_terminator; /* = 0x00 */ + u8 terminator_length; /* = 0x00 */ + u8 reserved_90[90]; /* = 0 */ } __packed bond_marker_t; typedef struct bond_marker_header { @@ -173,7 +173,7 @@ struct port; #pragma pack(8) #endif -// aggregator structure(43.4.5 in the 802.3ad standard) +/* aggregator structure(43.4.5 in the 802.3ad standard) */ typedef struct aggregator { struct mac_addr aggregator_mac_address; u16 aggregator_identifier; @@ -183,12 +183,12 @@ typedef struct aggregator { struct mac_addr partner_system; u16 partner_system_priority; u16 partner_oper_aggregator_key; - u16 receive_state; // BOOLEAN - u16 transmit_state; // BOOLEAN + u16 receive_state; /* BOOLEAN */ + u16 transmit_state; /* BOOLEAN */ struct port *lag_ports; - // ****** PRIVATE PARAMETERS ****** - struct slave *slave; // pointer to the bond slave that this aggregator belongs to - u16 is_active; // BOOLEAN. Indicates if this aggregator is active + /* ****** PRIVATE PARAMETERS ****** */ + struct slave *slave; /* pointer to the bond slave that this aggregator belongs to */ + u16 is_active; /* BOOLEAN. Indicates if this aggregator is active */ u16 num_of_ports; } aggregator_t; @@ -201,12 +201,12 @@ struct port_params { u16 port_state; }; -// port structure(43.4.6 in the 802.3ad standard) +/* port structure(43.4.6 in the 802.3ad standard) */ typedef struct port { u16 actor_port_number; u16 actor_port_priority; - struct mac_addr actor_system; // This parameter is added here although it is not specified in the standard, just for simplification - u16 actor_system_priority; // This parameter is added here although it is not specified in the standard, just for simplification + struct mac_addr actor_system; /* This parameter is added here although it is not specified in the standard, just for simplification */ + u16 actor_system_priority; /* This parameter is added here although it is not specified in the standard, just for simplification */ u16 actor_port_aggregator_identifier; bool ntt; u16 actor_admin_port_key; @@ -219,24 +219,24 @@ typedef struct port { bool is_enabled; - // ****** PRIVATE PARAMETERS ****** - u16 sm_vars; // all state machines variables for this port - rx_states_t sm_rx_state; // state machine rx state - u16 sm_rx_timer_counter; // state machine rx timer counter - periodic_states_t sm_periodic_state;// state machine periodic state - u16 sm_periodic_timer_counter; // state machine periodic timer counter - mux_states_t sm_mux_state; // state machine mux state - u16 sm_mux_timer_counter; // state machine mux timer counter - tx_states_t sm_tx_state; // state machine tx state - u16 sm_tx_timer_counter; // state machine tx timer counter(allways on - enter to transmit state 3 time per second) - struct slave *slave; // pointer to the bond slave that this port belongs to - struct aggregator *aggregator; // pointer to an aggregator that this port related to - struct port *next_port_in_aggregator; // Next port on the linked list of the parent aggregator - u32 transaction_id; // continuous number for identification of Marker PDU's; - struct lacpdu lacpdu; // the lacpdu that will be sent for this port + /* ****** PRIVATE PARAMETERS ****** */ + u16 sm_vars; /* all state machines variables for this port */ + rx_states_t sm_rx_state; /* state machine rx state */ + u16 sm_rx_timer_counter; /* state machine rx timer counter */ + periodic_states_t sm_periodic_state; /* state machine periodic state */ + u16 sm_periodic_timer_counter; /* state machine periodic timer counter */ + mux_states_t sm_mux_state; /* state machine mux state */ + u16 sm_mux_timer_counter; /* state machine mux timer counter */ + tx_states_t sm_tx_state; /* state machine tx state */ + u16 sm_tx_timer_counter; /* state machine tx timer counter(allways on - enter to transmit state 3 time per second) */ + struct slave *slave; /* pointer to the bond slave that this port belongs to */ + struct aggregator *aggregator; /* pointer to an aggregator that this port related to */ + struct port *next_port_in_aggregator; /* Next port on the linked list of the parent aggregator */ + u32 transaction_id; /* continuous number for identification of Marker PDU's; */ + struct lacpdu lacpdu; /* the lacpdu that will be sent for this port */ } port_t; -// system structure +/* system structure */ struct ad_system { u16 sys_priority; struct mac_addr sys_mac_addr; @@ -246,26 +246,26 @@ struct ad_system { #pragma pack() #endif -// ================= AD Exported structures to the main bonding code ================== +/* ========== AD Exported structures to the main bonding code ========== */ #define BOND_AD_INFO(bond) ((bond)->ad_info) #define SLAVE_AD_INFO(slave) ((slave)->ad_info) struct ad_bond_info { - struct ad_system system; /* 802.3ad system structure */ - u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes + struct ad_system system; /* 802.3ad system structure */ + u32 agg_select_timer; /* Timer to select aggregator after all adapter's hand shakes */ + u16 aggregator_identifier; }; struct ad_slave_info { - struct aggregator aggregator; // 802.3ad aggregator structure - struct port port; // 802.3ad port structure - spinlock_t state_machine_lock; /* mutex state machines vs. - incoming LACPDU */ + struct aggregator aggregator; /* 802.3ad aggregator structure */ + struct port port; /* 802.3ad port structure */ + spinlock_t state_machine_lock; /* mutex state machines vs. incoming LACPDU */ u16 id; }; -// ================= AD Exported functions to the main bonding code ================== +/* ========== AD Exported functions to the main bonding code ========== */ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution); -void bond_3ad_bind_slave(struct slave *slave); +void bond_3ad_bind_slave(struct slave *slave); void bond_3ad_unbind_slave(struct slave *slave); void bond_3ad_state_machine_handler(struct work_struct *); void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout); @@ -280,5 +280,5 @@ int bond_3ad_lacpdu_recv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave); int bond_3ad_set_carrier(struct bonding *bond); void bond_3ad_update_lacp_rate(struct bonding *bond); -#endif //__BOND_3AD_H__ +#endif /* __BOND_3AD_H__ */ diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index a2c47476804d..9cf836b67b15 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -93,9 +93,8 @@ static inline u8 _simple_hash(const u8 *hash_start, int hash_size) int i; u8 hash = 0; - for (i = 0; i < hash_size; i++) { + for (i = 0; i < hash_size; i++) hash ^= hash_start[i]; - } return hash; } @@ -190,9 +189,8 @@ static int tlb_initialize(struct bonding *bond) bond_info->tx_hashtbl = new_hashtbl; - for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) { + for (i = 0; i < TLB_HASH_TABLE_SIZE; i++) tlb_init_table_entry(&bond_info->tx_hashtbl[i], 0); - } _unlock_tx_hashtbl_bh(bond); @@ -264,9 +262,8 @@ static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index, hash_table[hash_index].next = next_index; hash_table[hash_index].prev = TLB_NULL_INDEX; - if (next_index != TLB_NULL_INDEX) { + if (next_index != TLB_NULL_INDEX) hash_table[next_index].prev = hash_index; - } slave_info->head = hash_index; slave_info->load += @@ -274,9 +271,8 @@ static struct slave *__tlb_choose_channel(struct bonding *bond, u32 hash_index, } } - if (assigned_slave) { + if (assigned_slave) hash_table[hash_index].tx_bytes += skb_len; - } return assigned_slave; } @@ -329,7 +325,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) _lock_rx_hashtbl_bh(bond); - hash_index = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); + hash_index = _simple_hash((u8 *)&(arp->ip_src), sizeof(arp->ip_src)); client_info = &(bond_info->rx_hashtbl[hash_index]); if ((client_info->assigned) && @@ -337,7 +333,7 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) (client_info->ip_dst == arp->ip_src) && (!ether_addr_equal_64bits(client_info->mac_dst, arp->mac_src))) { /* update the clients MAC address */ - memcpy(client_info->mac_dst, arp->mac_src, ETH_ALEN); + ether_addr_copy(client_info->mac_dst, arp->mac_src); client_info->ntt = 1; bond_info->rx_ntt = 1; } @@ -451,9 +447,8 @@ static struct slave *__rlb_next_rx_slave(struct bonding *bond) */ static void rlb_teach_disabled_mac_on_primary(struct bonding *bond, u8 addr[]) { - if (!bond->curr_active_slave) { + if (!bond->curr_active_slave) return; - } if (!bond->alb_info.primary_is_promisc) { if (!dev_set_promiscuity(bond->curr_active_slave->dev, 1)) @@ -513,9 +508,8 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave) write_lock_bh(&bond->curr_slave_lock); - if (slave != bond->curr_active_slave) { + if (slave != bond->curr_active_slave) rlb_teach_disabled_mac_on_primary(bond, slave->dev->dev_addr); - } write_unlock_bh(&bond->curr_slave_lock); } @@ -524,9 +518,8 @@ static void rlb_update_client(struct rlb_client_info *client_info) { int i; - if (!client_info->slave) { + if (!client_info->slave) return; - } for (i = 0; i < RLB_ARP_BURST_SIZE; i++) { struct sk_buff *skb; @@ -574,9 +567,8 @@ static void rlb_update_rx_clients(struct bonding *bond) client_info = &(bond_info->rx_hashtbl[hash_index]); if (client_info->ntt) { rlb_update_client(client_info); - if (bond_info->rlb_update_retry_counter == 0) { + if (bond_info->rlb_update_retry_counter == 0) client_info->ntt = 0; - } } } @@ -610,10 +602,10 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla } } - // update the team's flag only after the whole iteration + /* update the team's flag only after the whole iteration */ if (ntt) { bond_info->rx_ntt = 1; - //fasten the change + /* fasten the change */ bond_info->rlb_update_retry_counter = RLB_UPDATE_RETRY; } @@ -677,9 +669,9 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon /* the entry is already assigned to this client */ if (!ether_addr_equal_64bits(arp->mac_dst, mac_bcast)) { /* update mac address from arp */ - memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); + ether_addr_copy(client_info->mac_dst, arp->mac_dst); } - memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN); + ether_addr_copy(client_info->mac_src, arp->mac_src); assigned_slave = client_info->slave; if (assigned_slave) { @@ -719,8 +711,8 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon * will be updated with clients actual unicast mac address * upon receiving an arp reply. */ - memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN); - memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN); + ether_addr_copy(client_info->mac_dst, arp->mac_dst); + ether_addr_copy(client_info->mac_src, arp->mac_src); client_info->slave = assigned_slave; if (!ether_addr_equal_64bits(client_info->mac_dst, mac_bcast)) { @@ -770,9 +762,8 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) * rx channel */ tx_slave = rlb_choose_channel(skb, bond); - if (tx_slave) { - memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); - } + if (tx_slave) + ether_addr_copy(arp->mac_src, tx_slave->dev->dev_addr); pr_debug("Server sent ARP Reply packet\n"); } else if (arp->op_code == htons(ARPOP_REQUEST)) { /* Create an entry in the rx_hashtbl for this client as a @@ -824,9 +815,8 @@ static void rlb_rebalance(struct bonding *bond) } /* update the team's flag only after the whole iteration */ - if (ntt) { + if (ntt) bond_info->rx_ntt = 1; - } _unlock_rx_hashtbl_bh(bond); } @@ -923,7 +913,7 @@ static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash) static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp) { struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); - u32 ip_src_hash = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src)); + u32 ip_src_hash = _simple_hash((u8 *)&(arp->ip_src), sizeof(arp->ip_src)); u32 index; _lock_rx_hashtbl_bh(bond); @@ -957,9 +947,8 @@ static int rlb_initialize(struct bonding *bond) bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX; - for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) { + for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) rlb_init_table_entry(bond_info->rx_hashtbl + i); - } _unlock_rx_hashtbl_bh(bond); @@ -1014,8 +1003,8 @@ static void alb_send_lp_vid(struct slave *slave, u8 mac_addr[], char *data; memset(&pkt, 0, size); - memcpy(pkt.mac_dst, mac_addr, ETH_ALEN); - memcpy(pkt.mac_src, mac_addr, ETH_ALEN); + ether_addr_copy(pkt.mac_dst, mac_addr); + ether_addr_copy(pkt.mac_src, mac_addr); pkt.type = cpu_to_be16(ETH_P_LOOP); skb = dev_alloc_skb(size); @@ -1097,7 +1086,7 @@ static void alb_swap_mac_addr(struct slave *slave1, struct slave *slave2) { u8 tmp_mac_addr[ETH_ALEN]; - memcpy(tmp_mac_addr, slave1->dev->dev_addr, ETH_ALEN); + ether_addr_copy(tmp_mac_addr, slave1->dev->dev_addr); alb_set_slave_mac_addr(slave1, slave2->dev->dev_addr); alb_set_slave_mac_addr(slave2, tmp_mac_addr); @@ -1254,9 +1243,9 @@ static int alb_handle_addr_collision_on_attach(struct bonding *bond, struct slav if (free_mac_slave) { alb_set_slave_mac_addr(slave, free_mac_slave->perm_hwaddr); - pr_warning("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", - bond->dev->name, slave->dev->name, - free_mac_slave->dev->name); + pr_warn("%s: Warning: the hw address of slave %s is in use by the bond; giving it the hw address of %s\n", + bond->dev->name, slave->dev->name, + free_mac_slave->dev->name); } else if (has_bond_addr) { pr_err("%s: Error: the hw address of slave %s is in use by the bond; couldn't find a slave with a free hw address to give it (this should not have happened)\n", @@ -1294,12 +1283,12 @@ static int alb_set_mac_address(struct bonding *bond, void *addr) bond_for_each_slave(bond, slave, iter) { /* save net_device's current hw address */ - memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); + ether_addr_copy(tmp_addr, slave->dev->dev_addr); res = dev_set_mac_address(slave->dev, addr); /* restore net_device's hw address */ - memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); + ether_addr_copy(slave->dev->dev_addr, tmp_addr); if (res) goto unwind; @@ -1315,9 +1304,9 @@ unwind: bond_for_each_slave(bond, rollback_slave, iter) { if (rollback_slave == slave) break; - memcpy(tmp_addr, rollback_slave->dev->dev_addr, ETH_ALEN); + ether_addr_copy(tmp_addr, rollback_slave->dev->dev_addr); dev_set_mac_address(rollback_slave->dev, &sa); - memcpy(rollback_slave->dev->dev_addr, tmp_addr, ETH_ALEN); + ether_addr_copy(rollback_slave->dev->dev_addr, tmp_addr); } return res; @@ -1330,9 +1319,8 @@ int bond_alb_initialize(struct bonding *bond, int rlb_enabled) int res; res = tlb_initialize(bond); - if (res) { + if (res) return res; - } if (rlb_enabled) { bond->alb_info.rlb_enabled = 1; @@ -1355,9 +1343,8 @@ void bond_alb_deinitialize(struct bonding *bond) tlb_deinitialize(bond); - if (bond_info->rlb_enabled) { + if (bond_info->rlb_enabled) rlb_deinitialize(bond); - } } int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) @@ -1436,14 +1423,13 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) break; } - hash_start = (char*)eth_data->h_dest; + hash_start = (char *)eth_data->h_dest; hash_size = ETH_ALEN; break; case ETH_P_ARP: do_tx_balance = 0; - if (bond_info->rlb_enabled) { + if (bond_info->rlb_enabled) tx_slave = rlb_arp_xmit(skb, bond); - } break; default: do_tx_balance = 0; @@ -1463,23 +1449,22 @@ int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) if (tx_slave && SLAVE_IS_OK(tx_slave)) { if (tx_slave != rcu_dereference(bond->curr_active_slave)) { - memcpy(eth_data->h_source, - tx_slave->dev->dev_addr, - ETH_ALEN); + ether_addr_copy(eth_data->h_source, + tx_slave->dev->dev_addr); } bond_dev_queue_xmit(bond, skb, tx_slave->dev); goto out; - } else { - if (tx_slave) { - _lock_tx_hashtbl(bond); - __tlb_clear_slave(bond, tx_slave, 0); - _unlock_tx_hashtbl(bond); - } + } + + if (tx_slave) { + _lock_tx_hashtbl(bond); + __tlb_clear_slave(bond, tx_slave, 0); + _unlock_tx_hashtbl(bond); } /* no suitable interface, frame not sent */ - kfree_skb(skb); + dev_kfree_skb_any(skb); out: return NETDEV_TX_OK; } @@ -1577,11 +1562,10 @@ void bond_alb_monitor(struct work_struct *work) --bond_info->rlb_update_delay_counter; } else { rlb_update_rx_clients(bond); - if (bond_info->rlb_update_retry_counter) { + if (bond_info->rlb_update_retry_counter) --bond_info->rlb_update_retry_counter; - } else { + else bond_info->rx_ntt = 0; - } } } } @@ -1598,23 +1582,20 @@ int bond_alb_init_slave(struct bonding *bond, struct slave *slave) int res; res = alb_set_slave_mac_addr(slave, slave->perm_hwaddr); - if (res) { + if (res) return res; - } res = alb_handle_addr_collision_on_attach(bond, slave); - if (res) { + if (res) return res; - } tlb_init_slave(slave); /* order a rebalance ASAP */ bond->alb_info.tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS; - if (bond->alb_info.rlb_enabled) { + if (bond->alb_info.rlb_enabled) bond->alb_info.rlb_rebalance = 1; - } return 0; } @@ -1645,9 +1626,8 @@ void bond_alb_handle_link_change(struct bonding *bond, struct slave *slave, char if (link == BOND_LINK_DOWN) { tlb_clear_slave(bond, slave, 0); - if (bond->alb_info.rlb_enabled) { + if (bond->alb_info.rlb_enabled) rlb_clear_slave(bond, slave); - } } else if (link == BOND_LINK_UP) { /* order a rebalance ASAP */ bond_info->tx_rebalance_counter = BOND_TLB_REBALANCE_TICKS; @@ -1723,14 +1703,14 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave struct sockaddr sa; u8 tmp_addr[ETH_ALEN]; - memcpy(tmp_addr, new_slave->dev->dev_addr, ETH_ALEN); + ether_addr_copy(tmp_addr, new_slave->dev->dev_addr); memcpy(sa.sa_data, bond->dev->dev_addr, bond->dev->addr_len); sa.sa_family = bond->dev->type; /* we don't care if it can't change its mac, best effort */ dev_set_mac_address(new_slave->dev, &sa); - memcpy(new_slave->dev->dev_addr, tmp_addr, ETH_ALEN); + ether_addr_copy(new_slave->dev->dev_addr, tmp_addr); } /* curr_active_slave must be set before calling alb_swap_mac_addr */ @@ -1759,14 +1739,12 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) struct slave *swap_slave; int res; - if (!is_valid_ether_addr(sa->sa_data)) { + if (!is_valid_ether_addr(sa->sa_data)) return -EADDRNOTAVAIL; - } res = alb_set_mac_address(bond, addr); - if (res) { + if (res) return res; - } memcpy(bond_dev->dev_addr, sa->sa_data, bond_dev->addr_len); @@ -1774,9 +1752,8 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) * Otherwise we'll need to pass the new address to it and handle * duplications. */ - if (!bond->curr_active_slave) { + if (!bond->curr_active_slave) return 0; - } swap_slave = bond_slave_has_mac(bond, bond_dev->dev_addr); @@ -1800,8 +1777,7 @@ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) void bond_alb_clear_vlan(struct bonding *bond, unsigned short vlan_id) { - if (bond->alb_info.rlb_enabled) { + if (bond->alb_info.rlb_enabled) rlb_clear_vlan(bond, vlan_id); - } } diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c index 5fc4c2351478..2d3f7fa541ff 100644 --- a/drivers/net/bonding/bond_debugfs.c +++ b/drivers/net/bonding/bond_debugfs.c @@ -69,7 +69,7 @@ void bond_debug_register(struct bonding *bond) debugfs_create_dir(bond->dev->name, bonding_debug_root); if (!bond->debug_dir) { - pr_warning("%s: Warning: failed to register to debugfs\n", + pr_warn("%s: Warning: failed to register to debugfs\n", bond->dev->name); return; } @@ -98,9 +98,8 @@ void bond_debug_reregister(struct bonding *bond) if (d) { bond->debug_dir = d; } else { - pr_warning("%s: Warning: failed to reregister, " - "so just unregister old one\n", - bond->dev->name); + pr_warn("%s: Warning: failed to reregister, so just unregister old one\n", + bond->dev->name); bond_debug_unregister(bond); } } @@ -110,8 +109,7 @@ void bond_create_debugfs(void) bonding_debug_root = debugfs_create_dir("bonding", NULL); if (!bonding_debug_root) { - pr_warning("Warning: Cannot create bonding directory" - " in debugfs\n"); + pr_warn("Warning: Cannot create bonding directory in debugfs\n"); } } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 4c08018d7333..e717db301d46 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -673,12 +673,12 @@ static void bond_do_fail_over_mac(struct bonding *bond, write_unlock_bh(&bond->curr_slave_lock); if (old_active) { - memcpy(tmp_mac, new_active->dev->dev_addr, ETH_ALEN); - memcpy(saddr.sa_data, old_active->dev->dev_addr, - ETH_ALEN); + ether_addr_copy(tmp_mac, new_active->dev->dev_addr); + ether_addr_copy(saddr.sa_data, + old_active->dev->dev_addr); saddr.sa_family = new_active->dev->type; } else { - memcpy(saddr.sa_data, bond->dev->dev_addr, ETH_ALEN); + ether_addr_copy(saddr.sa_data, bond->dev->dev_addr); saddr.sa_family = bond->dev->type; } @@ -692,7 +692,7 @@ static void bond_do_fail_over_mac(struct bonding *bond, if (!old_active) goto out; - memcpy(saddr.sa_data, tmp_mac, ETH_ALEN); + ether_addr_copy(saddr.sa_data, tmp_mac); saddr.sa_family = old_active->dev->type; rv = dev_set_mac_address(old_active->dev, &saddr); @@ -798,11 +798,11 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) return; if (new_active) { - new_active->jiffies = jiffies; + new_active->last_link_up = jiffies; if (new_active->link == BOND_LINK_BACK) { if (USES_PRIMARY(bond->params.mode)) { - pr_info("%s: making interface %s the new active one %d ms earlier.\n", + pr_info("%s: making interface %s the new active one %d ms earlier\n", bond->dev->name, new_active->dev->name, (bond->params.updelay - new_active->delay) * bond->params.miimon); } @@ -817,7 +817,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); } else { if (USES_PRIMARY(bond->params.mode)) { - pr_info("%s: making interface %s the new active one.\n", + pr_info("%s: making interface %s the new active one\n", bond->dev->name, new_active->dev->name); } } @@ -829,21 +829,25 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) if (bond_is_lb(bond)) { bond_alb_handle_active_change(bond, new_active); if (old_active) - bond_set_slave_inactive_flags(old_active); + bond_set_slave_inactive_flags(old_active, + BOND_SLAVE_NOTIFY_NOW); if (new_active) - bond_set_slave_active_flags(new_active); + bond_set_slave_active_flags(new_active, + BOND_SLAVE_NOTIFY_NOW); } else { rcu_assign_pointer(bond->curr_active_slave, new_active); } if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { if (old_active) - bond_set_slave_inactive_flags(old_active); + bond_set_slave_inactive_flags(old_active, + BOND_SLAVE_NOTIFY_NOW); if (new_active) { bool should_notify_peers = false; - bond_set_slave_active_flags(new_active); + bond_set_slave_active_flags(new_active, + BOND_SLAVE_NOTIFY_NOW); if (bond->params.fail_over_mac) bond_do_fail_over_mac(bond, new_active, @@ -906,7 +910,7 @@ void bond_select_active_slave(struct bonding *bond) pr_info("%s: first active interface up!\n", bond->dev->name); } else { - pr_info("%s: now running without any active interface !\n", + pr_info("%s: now running without any active interface!\n", bond->dev->name); } } @@ -942,14 +946,6 @@ static inline void slave_disable_netpoll(struct slave *slave) slave->np = NULL; __netpoll_free_async(np); } -static inline bool slave_dev_support_netpoll(struct net_device *slave_dev) -{ - if (slave_dev->priv_flags & IFF_DISABLE_NETPOLL) - return false; - if (!slave_dev->netdev_ops->ndo_poll_controller) - return false; - return true; -} static void bond_poll_controller(struct net_device *bond_dev) { @@ -1115,9 +1111,6 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) slave = bond_slave_get_rcu(skb->dev); bond = slave->bond; - if (bond->params.arp_interval) - slave->dev->last_rx = jiffies; - recv_probe = ACCESS_ONCE(bond->recv_probe); if (recv_probe) { ret = recv_probe(skb, bond, slave); @@ -1142,7 +1135,7 @@ static rx_handler_result_t bond_handle_frame(struct sk_buff **pskb) kfree_skb(skb); return RX_HANDLER_CONSUMED; } - memcpy(eth_hdr(skb)->h_dest, bond->dev->dev_addr, ETH_ALEN); + ether_addr_copy(eth_hdr(skb)->h_dest, bond->dev->dev_addr); } return ret; @@ -1183,16 +1176,21 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!bond->params.use_carrier && slave_dev->ethtool_ops->get_link == NULL && slave_ops->ndo_do_ioctl == NULL) { - pr_warning("%s: Warning: no link monitoring support for %s\n", - bond_dev->name, slave_dev->name); + pr_warn("%s: Warning: no link monitoring support for %s\n", + bond_dev->name, slave_dev->name); } /* already enslaved */ if (slave_dev->flags & IFF_SLAVE) { - pr_debug("Error, Device was already enslaved\n"); + pr_debug("Error: Device was already enslaved\n"); return -EBUSY; } + if (bond_dev == slave_dev) { + pr_err("%s: cannot enslave bond to itself.\n", bond_dev->name); + return -EPERM; + } + /* vlan challenged mutual exclusion */ /* no need to lock since we're protected by rtnl_lock */ if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { @@ -1202,9 +1200,9 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev->name, slave_dev->name, bond_dev->name); return -EPERM; } else { - pr_warning("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n", - bond_dev->name, slave_dev->name, - slave_dev->name, bond_dev->name); + pr_warn("%s: Warning: enslaved VLAN challenged slave %s. Adding VLANs will be blocked as long as %s is part of bond %s\n", + bond_dev->name, slave_dev->name, + slave_dev->name, bond_dev->name); } } else { pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); @@ -1217,7 +1215,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * enslaving it; the old ifenslave will not. */ if ((slave_dev->flags & IFF_UP)) { - pr_err("%s is up. This may be due to an out of date ifenslave.\n", + pr_err("%s is up - this may be due to an out of date ifenslave\n", slave_dev->name); res = -EPERM; goto err_undo_flags; @@ -1261,20 +1259,23 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev); } } else if (bond_dev->type != slave_dev->type) { - pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it.\n", - slave_dev->name, - slave_dev->type, bond_dev->type); + pr_err("%s ether type (%d) is different from other slaves (%d), can not enslave it\n", + slave_dev->name, slave_dev->type, bond_dev->type); res = -EINVAL; goto err_undo_flags; } if (slave_ops->ndo_set_mac_address == NULL) { if (!bond_has_slaves(bond)) { - pr_warning("%s: Warning: The first slave device specified does not support setting the MAC address. Setting fail_over_mac to active.", - bond_dev->name); - bond->params.fail_over_mac = BOND_FOM_ACTIVE; + pr_warn("%s: Warning: The first slave device specified does not support setting the MAC address\n", + bond_dev->name); + if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) { + bond->params.fail_over_mac = BOND_FOM_ACTIVE; + pr_warn("%s: Setting fail_over_mac to active for active-backup mode\n", + bond_dev->name); + } } else if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { - pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active.\n", + pr_err("%s: Error: The slave device specified does not support setting the MAC address, but fail_over_mac is not set to active\n", bond_dev->name); res = -EOPNOTSUPP; goto err_undo_flags; @@ -1313,9 +1314,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * that need it, and for restoring it upon release, and then * set it to the master's address */ - memcpy(new_slave->perm_hwaddr, slave_dev->dev_addr, ETH_ALEN); + ether_addr_copy(new_slave->perm_hwaddr, slave_dev->dev_addr); - if (!bond->params.fail_over_mac) { + if (!bond->params.fail_over_mac || + bond->params.mode != BOND_MODE_ACTIVEBACKUP) { /* * Set slave to master's mac address. The application already * set the master's mac address to that of the first slave @@ -1396,10 +1398,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_update_speed_duplex(new_slave); - new_slave->last_arp_rx = jiffies - + new_slave->last_rx = jiffies - (msecs_to_jiffies(bond->params.arp_interval) + 1); for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) - new_slave->target_last_arp_rx[i] = new_slave->last_arp_rx; + new_slave->target_last_arp_rx[i] = new_slave->last_rx; if (bond->params.miimon && !bond->params.use_carrier) { link_reporting = bond_check_dev_link(bond, slave_dev, 1); @@ -1414,12 +1416,12 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) * supported); thus, we don't need to change * the messages for netif_carrier. */ - pr_warning("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details.\n", - bond_dev->name, slave_dev->name); + pr_warn("%s: Warning: MII and ETHTOOL support not available for interface %s, and arp_interval/arp_ip_target module parameters not specified, thus bonding will not detect link failures! see bonding.txt for details\n", + bond_dev->name, slave_dev->name); } else if (link_reporting == -1) { /* unable get link status using mii/ethtool */ - pr_warning("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface.\n", - bond_dev->name, slave_dev->name); + pr_warn("%s: Warning: can't get link status from interface %s; the network driver associated with this interface does not support MII or ETHTOOL link status reporting, thus miimon has no effect on this interface\n", + bond_dev->name, slave_dev->name); } } @@ -1443,10 +1445,10 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) } if (new_slave->link != BOND_LINK_DOWN) - new_slave->jiffies = jiffies; + new_slave->last_link_up = jiffies; pr_debug("Initial state of slave_dev is BOND_LINK_%s\n", - new_slave->link == BOND_LINK_DOWN ? "DOWN" : - (new_slave->link == BOND_LINK_UP ? "UP" : "BACK")); + new_slave->link == BOND_LINK_DOWN ? "DOWN" : + (new_slave->link == BOND_LINK_UP ? "UP" : "BACK")); if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { /* if there is a primary slave, remember it */ @@ -1458,14 +1460,15 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) switch (bond->params.mode) { case BOND_MODE_ACTIVEBACKUP: - bond_set_slave_inactive_flags(new_slave); + bond_set_slave_inactive_flags(new_slave, + BOND_SLAVE_NOTIFY_NOW); break; case BOND_MODE_8023AD: /* in 802.3ad mode, the internal mechanism * will activate the slaves in the selected * aggregator */ - bond_set_slave_inactive_flags(new_slave); + bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW); /* if this is the first slave */ if (!prev_slave) { SLAVE_AD_INFO(new_slave).id = 1; @@ -1483,7 +1486,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) case BOND_MODE_TLB: case BOND_MODE_ALB: bond_set_active_slave(new_slave); - bond_set_slave_inactive_flags(new_slave); + bond_set_slave_inactive_flags(new_slave, BOND_SLAVE_NOTIFY_NOW); break; default: pr_debug("This slave is always active in trunk mode\n"); @@ -1505,10 +1508,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) slave_dev->npinfo = bond->dev->npinfo; if (slave_dev->npinfo) { if (slave_enable_netpoll(new_slave)) { - read_unlock(&bond->lock); - pr_info("Error, %s: master_dev is using netpoll, " - "but new slave device does not support netpoll.\n", - bond_dev->name); + pr_info("Error, %s: master_dev is using netpoll, but new slave device does not support netpoll\n", + bond_dev->name); res = -EBUSY; goto err_detach; } @@ -1539,15 +1540,17 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_carrier(bond); if (USES_PRIMARY(bond->params.mode)) { + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); } - pr_info("%s: enslaving %s as a%s interface with a%s link.\n", + pr_info("%s: Enslaving %s as %s interface with %s link\n", bond_dev->name, slave_dev->name, - bond_is_active_slave(new_slave) ? "n active" : " backup", - new_slave->link != BOND_LINK_DOWN ? "n up" : " down"); + bond_is_active_slave(new_slave) ? "an active" : "a backup", + new_slave->link != BOND_LINK_DOWN ? "an up" : "a down"); /* enslave is successful */ return 0; @@ -1567,10 +1570,12 @@ err_detach: if (bond->primary_slave == new_slave) bond->primary_slave = NULL; if (bond->curr_active_slave == new_slave) { + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_change_active_slave(bond, NULL); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); } slave_disable_netpoll(new_slave); @@ -1579,12 +1584,13 @@ err_close: dev_close(slave_dev); err_restore_mac: - if (!bond->params.fail_over_mac) { + if (!bond->params.fail_over_mac || + bond->params.mode != BOND_MODE_ACTIVEBACKUP) { /* XXX TODO - fom follow mode needs to change master's * MAC if this slave's MAC is in use by the bond, or at * least print a warning. */ - memcpy(addr.sa_data, new_slave->perm_hwaddr, ETH_ALEN); + ether_addr_copy(addr.sa_data, new_slave->perm_hwaddr); addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); } @@ -1629,7 +1635,7 @@ static int __bond_release_one(struct net_device *bond_dev, /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || !netdev_has_upper_dev(slave_dev, bond_dev)) { - pr_err("%s: Error: cannot release %s.\n", + pr_err("%s: Error: cannot release %s\n", bond_dev->name, slave_dev->name); return -EINVAL; } @@ -1645,9 +1651,6 @@ static int __bond_release_one(struct net_device *bond_dev, return -EINVAL; } - /* release the slave from its bond */ - bond->slave_cnt--; - bond_sysfs_slave_del(slave); bond_upper_dev_unlink(bond_dev, slave_dev); @@ -1663,7 +1666,7 @@ static int __bond_release_one(struct net_device *bond_dev, write_unlock_bh(&bond->lock); - pr_info("%s: releasing %s interface %s\n", + pr_info("%s: Releasing %s interface %s\n", bond_dev->name, bond_is_active_slave(slave) ? "active" : "backup", slave_dev->name); @@ -1672,13 +1675,14 @@ static int __bond_release_one(struct net_device *bond_dev, bond->current_arp_slave = NULL; - if (!all && !bond->params.fail_over_mac) { + if (!all && (!bond->params.fail_over_mac || + bond->params.mode != BOND_MODE_ACTIVEBACKUP)) { if (ether_addr_equal_64bits(bond_dev->dev_addr, slave->perm_hwaddr) && bond_has_slaves(bond)) - pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s. Set the HWaddr of %s to a different address to avoid conflicts.\n", - bond_dev->name, slave_dev->name, - slave->perm_hwaddr, - bond_dev->name, slave_dev->name); + pr_warn("%s: Warning: the permanent HWaddr of %s - %pM - is still in use by %s - set the HWaddr of %s to a different address to avoid conflicts\n", + bond_dev->name, slave_dev->name, + slave->perm_hwaddr, + bond_dev->name, slave_dev->name); } if (bond->primary_slave == slave) @@ -1719,15 +1723,16 @@ static int __bond_release_one(struct net_device *bond_dev, eth_hw_addr_random(bond_dev); if (vlan_uses_dev(bond_dev)) { - pr_warning("%s: Warning: clearing HW address of %s while it still has VLANs.\n", - bond_dev->name, bond_dev->name); - pr_warning("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs'.\n", - bond_dev->name); + pr_warn("%s: Warning: clearing HW address of %s while it still has VLANs\n", + bond_dev->name, bond_dev->name); + pr_warn("%s: When re-adding slaves, make sure the bond's HW address matches its VLANs\n", + bond_dev->name); } } unblock_netpoll_tx(); synchronize_rcu(); + bond->slave_cnt--; if (!bond_has_slaves(bond)) { call_netdevice_notifiers(NETDEV_CHANGEADDR, bond->dev); @@ -1737,7 +1742,7 @@ static int __bond_release_one(struct net_device *bond_dev, bond_compute_features(bond); if (!(bond_dev->features & NETIF_F_VLAN_CHALLENGED) && (old_features & NETIF_F_VLAN_CHALLENGED)) - pr_info("%s: last VLAN challenged slave %s left bond %s. VLAN blocking is removed\n", + pr_info("%s: last VLAN challenged slave %s left bond %s - VLAN blocking is removed\n", bond_dev->name, slave_dev->name, bond_dev->name); /* must do this from outside any spinlocks */ @@ -1769,9 +1774,10 @@ static int __bond_release_one(struct net_device *bond_dev, /* close slave before restoring its mac address */ dev_close(slave_dev); - if (bond->params.fail_over_mac != BOND_FOM_ACTIVE) { + if (bond->params.fail_over_mac != BOND_FOM_ACTIVE || + bond->params.mode != BOND_MODE_ACTIVEBACKUP) { /* restore original ("permanent") mac address */ - memcpy(addr.sa_data, slave->perm_hwaddr, ETH_ALEN); + ether_addr_copy(addr.sa_data, slave->perm_hwaddr); addr.sa_family = slave_dev->type; dev_set_mac_address(slave_dev, &addr); } @@ -1804,7 +1810,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev, ret = bond_release(bond_dev, slave_dev); if (ret == 0 && !bond_has_slaves(bond)) { bond_dev->priv_flags |= IFF_DISABLE_NETPOLL; - pr_info("%s: destroying bond %s.\n", + pr_info("%s: Destroying bond %s\n", bond_dev->name, bond_dev->name); unregister_netdevice(bond_dev); } @@ -1818,9 +1824,7 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) info->bond_mode = bond->params.mode; info->miimon = bond->params.miimon; - read_lock(&bond->lock); info->num_slaves = bond->slave_cnt; - read_unlock(&bond->lock); return 0; } @@ -1832,7 +1836,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in int i = 0, res = -ENODEV; struct slave *slave; - read_lock(&bond->lock); bond_for_each_slave(bond, slave, iter) { if (i++ == (int)info->slave_id) { res = 0; @@ -1843,7 +1846,6 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in break; } } - read_unlock(&bond->lock); return res; } @@ -1873,7 +1875,7 @@ static int bond_miimon_inspect(struct bonding *bond) slave->link = BOND_LINK_FAIL; slave->delay = bond->params.downdelay; if (slave->delay) { - pr_info("%s: link status down for %sinterface %s, disabling it in %d ms.\n", + pr_info("%s: link status down for %sinterface %s, disabling it in %d ms\n", bond->dev->name, (bond->params.mode == BOND_MODE_ACTIVEBACKUP) ? @@ -1889,8 +1891,8 @@ static int bond_miimon_inspect(struct bonding *bond) * recovered before downdelay expired */ slave->link = BOND_LINK_UP; - slave->jiffies = jiffies; - pr_info("%s: link status up again after %d ms for interface %s.\n", + slave->last_link_up = jiffies; + pr_info("%s: link status up again after %d ms for interface %s\n", bond->dev->name, (bond->params.downdelay - slave->delay) * bond->params.miimon, @@ -1915,7 +1917,7 @@ static int bond_miimon_inspect(struct bonding *bond) slave->delay = bond->params.updelay; if (slave->delay) { - pr_info("%s: link status up for interface %s, enabling it in %d ms.\n", + pr_info("%s: link status up for interface %s, enabling it in %d ms\n", bond->dev->name, slave->dev->name, ignore_updelay ? 0 : bond->params.updelay * @@ -1925,7 +1927,7 @@ static int bond_miimon_inspect(struct bonding *bond) case BOND_LINK_BACK: if (!link_state) { slave->link = BOND_LINK_DOWN; - pr_info("%s: link status down again after %d ms for interface %s.\n", + pr_info("%s: link status down again after %d ms for interface %s\n", bond->dev->name, (bond->params.updelay - slave->delay) * bond->params.miimon, @@ -1964,7 +1966,7 @@ static void bond_miimon_commit(struct bonding *bond) case BOND_LINK_UP: slave->link = BOND_LINK_UP; - slave->jiffies = jiffies; + slave->last_link_up = jiffies; if (bond->params.mode == BOND_MODE_8023AD) { /* prevent it from being the active one */ @@ -1977,7 +1979,7 @@ static void bond_miimon_commit(struct bonding *bond) bond_set_backup_slave(slave); } - pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex.\n", + pr_info("%s: link status definitely up for interface %s, %u Mbps %s duplex\n", bond->dev->name, slave->dev->name, slave->speed == SPEED_UNKNOWN ? 0 : slave->speed, slave->duplex ? "full" : "half"); @@ -2004,7 +2006,8 @@ static void bond_miimon_commit(struct bonding *bond) if (bond->params.mode == BOND_MODE_ACTIVEBACKUP || bond->params.mode == BOND_MODE_8023AD) - bond_set_slave_inactive_flags(slave); + bond_set_slave_inactive_flags(slave, + BOND_SLAVE_NOTIFY_NOW); pr_info("%s: link status definitely down for interface %s, disabling it\n", bond->dev->name, slave->dev->name); @@ -2125,8 +2128,8 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ { struct sk_buff *skb; - pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", arp_op, - slave_dev->name, &dest_ip, &src_ip, vlan_id); + pr_debug("arp %d on slave %s: dst %pI4 src %pI4 vid %d\n", + arp_op, slave_dev->name, &dest_ip, &src_ip, vlan_id); skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, NULL, slave_dev->dev_addr, NULL); @@ -2161,8 +2164,13 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) rt = ip_route_output(dev_net(bond->dev), targets[i], 0, RTO_ONLINK, 0); if (IS_ERR(rt)) { - pr_debug("%s: no route to arp_ip_target %pI4\n", - bond->dev->name, &targets[i]); + /* there's no route to target - try to send arp + * probe to generate any traffic (arp_validate=0) + */ + if (bond->params.arp_validate && net_ratelimit()) + pr_warn("%s: no route to arp_ip_target %pI4 and arp_validate is set\n", + bond->dev->name, &targets[i]); + bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], 0, 0); continue; } @@ -2240,7 +2248,7 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 pr_debug("bva: sip %pI4 not found in targets\n", &sip); return; } - slave->last_arp_rx = jiffies; + slave->last_rx = jiffies; slave->target_last_arp_rx[i] = jiffies; } @@ -2248,17 +2256,19 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, struct slave *slave) { struct arphdr *arp = (struct arphdr *)skb->data; + struct slave *curr_active_slave; unsigned char *arp_ptr; __be32 sip, tip; - int alen; + int alen, is_arp = skb->protocol == __cpu_to_be16(ETH_P_ARP); - if (skb->protocol != __cpu_to_be16(ETH_P_ARP)) + if (!slave_do_arp_validate(bond, slave)) { + if ((slave_do_arp_validate_only(bond, slave) && is_arp) || + !slave_do_arp_validate_only(bond, slave)) + slave->last_rx = jiffies; return RX_HANDLER_ANOTHER; - - read_lock(&bond->lock); - - if (!slave_do_arp_validate(bond, slave)) - goto out_unlock; + } else if (!is_arp) { + return RX_HANDLER_ANOTHER; + } alen = arp_hdr_len(bond->dev); @@ -2292,6 +2302,8 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, bond->params.arp_validate, slave_do_arp_validate(bond, slave), &sip, &tip); + curr_active_slave = rcu_dereference(bond->curr_active_slave); + /* * Backup slaves won't see the ARP reply, but do come through * here for each ARP probe (so we swap the sip/tip to validate @@ -2305,15 +2317,15 @@ int bond_arp_rcv(const struct sk_buff *skb, struct bonding *bond, * is done to avoid endless looping when we can't reach the * arp_ip_target and fool ourselves with our own arp requests. */ + if (bond_is_active_slave(slave)) bond_validate_arp(bond, slave, sip, tip); - else if (bond->curr_active_slave && - time_after(slave_last_rx(bond, bond->curr_active_slave), - bond->curr_active_slave->jiffies)) + else if (curr_active_slave && + time_after(slave_last_rx(bond, curr_active_slave), + curr_active_slave->last_link_up)) bond_validate_arp(bond, slave, tip, sip); out_unlock: - read_unlock(&bond->lock); if (arp != (struct arphdr *)skb->data) kfree(arp); return RX_HANDLER_ANOTHER; @@ -2356,9 +2368,9 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) oldcurrent = ACCESS_ONCE(bond->curr_active_slave); /* see if any of the previous devices are up now (i.e. they have * xmt and rcv traffic). the curr_active_slave does not come into - * the picture unless it is null. also, slave->jiffies is not needed - * here because we send an arp on each slave and give a slave as - * long as it needs to get the tx/rx within the delta. + * the picture unless it is null. also, slave->last_link_up is not + * needed here because we send an arp on each slave and give a slave + * as long as it needs to get the tx/rx within the delta. * TODO: what about up/down delay in arp mode? it wasn't here before * so it can wait */ @@ -2367,7 +2379,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (slave->link != BOND_LINK_UP) { if (bond_time_in_interval(bond, trans_start, 1) && - bond_time_in_interval(bond, slave->dev->last_rx, 1)) { + bond_time_in_interval(bond, slave->last_rx, 1)) { slave->link = BOND_LINK_UP; slave_state_changed = 1; @@ -2378,7 +2390,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) * is closed. */ if (!oldcurrent) { - pr_info("%s: link status definitely up for interface %s, ", + pr_info("%s: link status definitely up for interface %s\n", bond->dev->name, slave->dev->name); do_failover = 1; @@ -2396,7 +2408,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) * if we don't know our ip yet */ if (!bond_time_in_interval(bond, trans_start, 2) || - !bond_time_in_interval(bond, slave->dev->last_rx, 2)) { + !bond_time_in_interval(bond, slave->last_rx, 2)) { slave->link = BOND_LINK_DOWN; slave_state_changed = 1; @@ -2404,9 +2416,8 @@ static void bond_loadbalance_arp_mon(struct work_struct *work) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - pr_info("%s: interface %s is now down.\n", - bond->dev->name, - slave->dev->name); + pr_info("%s: interface %s is now down\n", + bond->dev->name, slave->dev->name); if (slave == oldcurrent) do_failover = 1; @@ -2485,7 +2496,7 @@ static int bond_ab_arp_inspect(struct bonding *bond) * active. This avoids bouncing, as the last receive * times need a full ARP monitor cycle to be updated. */ - if (bond_time_in_interval(bond, slave->jiffies, 2)) + if (bond_time_in_interval(bond, slave->last_link_up, 2)) continue; /* @@ -2551,11 +2562,12 @@ static void bond_ab_arp_commit(struct bonding *bond) slave->link = BOND_LINK_UP; if (bond->current_arp_slave) { bond_set_slave_inactive_flags( - bond->current_arp_slave); + bond->current_arp_slave, + BOND_SLAVE_NOTIFY_NOW); bond->current_arp_slave = NULL; } - pr_info("%s: link status definitely up for interface %s.\n", + pr_info("%s: link status definitely up for interface %s\n", bond->dev->name, slave->dev->name); if (!bond->curr_active_slave || @@ -2571,7 +2583,8 @@ static void bond_ab_arp_commit(struct bonding *bond) slave->link_failure_count++; slave->link = BOND_LINK_DOWN; - bond_set_slave_inactive_flags(slave); + bond_set_slave_inactive_flags(slave, + BOND_SLAVE_NOTIFY_NOW); pr_info("%s: link status definitely down for interface %s, disabling it\n", bond->dev->name, slave->dev->name); @@ -2604,17 +2617,17 @@ do_failover: /* * Send ARP probes for active-backup mode ARP monitor. + * + * Called with rcu_read_lock hold. */ static bool bond_ab_arp_probe(struct bonding *bond) { struct slave *slave, *before = NULL, *new_slave = NULL, - *curr_arp_slave, *curr_active_slave; + *curr_arp_slave = rcu_dereference(bond->current_arp_slave), + *curr_active_slave = rcu_dereference(bond->curr_active_slave); struct list_head *iter; bool found = false; - - rcu_read_lock(); - curr_arp_slave = rcu_dereference(bond->current_arp_slave); - curr_active_slave = rcu_dereference(bond->curr_active_slave); + bool should_notify_rtnl = BOND_SLAVE_NOTIFY_LATER; if (curr_arp_slave && curr_active_slave) pr_info("PROBE: c_arp %s && cas %s BAD\n", @@ -2623,32 +2636,23 @@ static bool bond_ab_arp_probe(struct bonding *bond) if (curr_active_slave) { bond_arp_send_all(bond, curr_active_slave); - rcu_read_unlock(); - return true; + return should_notify_rtnl; } - rcu_read_unlock(); /* if we don't have a curr_active_slave, search for the next available * backup slave from the current_arp_slave and make it the candidate * for becoming the curr_active_slave */ - if (!rtnl_trylock()) - return false; - /* curr_arp_slave might have gone away */ - curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave); - if (!curr_arp_slave) { - curr_arp_slave = bond_first_slave(bond); - if (!curr_arp_slave) { - rtnl_unlock(); - return true; - } + curr_arp_slave = bond_first_slave_rcu(bond); + if (!curr_arp_slave) + return should_notify_rtnl; } - bond_set_slave_inactive_flags(curr_arp_slave); + bond_set_slave_inactive_flags(curr_arp_slave, BOND_SLAVE_NOTIFY_LATER); - bond_for_each_slave(bond, slave, iter) { + bond_for_each_slave_rcu(bond, slave, iter) { if (!found && !before && IS_UP(slave->dev)) before = slave; @@ -2666,9 +2670,10 @@ static bool bond_ab_arp_probe(struct bonding *bond) if (slave->link_failure_count < UINT_MAX) slave->link_failure_count++; - bond_set_slave_inactive_flags(slave); + bond_set_slave_inactive_flags(slave, + BOND_SLAVE_NOTIFY_LATER); - pr_info("%s: backup interface %s is now down.\n", + pr_info("%s: backup interface %s is now down\n", bond->dev->name, slave->dev->name); } if (slave == curr_arp_slave) @@ -2678,26 +2683,31 @@ static bool bond_ab_arp_probe(struct bonding *bond) if (!new_slave && before) new_slave = before; - if (!new_slave) { - rtnl_unlock(); - return true; - } + if (!new_slave) + goto check_state; new_slave->link = BOND_LINK_BACK; - bond_set_slave_active_flags(new_slave); + bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER); bond_arp_send_all(bond, new_slave); - new_slave->jiffies = jiffies; + new_slave->last_link_up = jiffies; rcu_assign_pointer(bond->current_arp_slave, new_slave); - rtnl_unlock(); - return true; +check_state: + bond_for_each_slave_rcu(bond, slave, iter) { + if (slave->should_notify) { + should_notify_rtnl = BOND_SLAVE_NOTIFY_NOW; + break; + } + } + return should_notify_rtnl; } static void bond_activebackup_arp_mon(struct work_struct *work) { struct bonding *bond = container_of(work, struct bonding, arp_work.work); - bool should_notify_peers = false, should_commit = false; + bool should_notify_peers = false; + bool should_notify_rtnl = false; int delta_in_ticks; delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval); @@ -2706,11 +2716,12 @@ static void bond_activebackup_arp_mon(struct work_struct *work) goto re_arm; rcu_read_lock(); + should_notify_peers = bond_should_notify_peers(bond); - should_commit = bond_ab_arp_inspect(bond); - rcu_read_unlock(); - if (should_commit) { + if (bond_ab_arp_inspect(bond)) { + rcu_read_unlock(); + /* Race avoidance with bond_close flush of workqueue */ if (!rtnl_trylock()) { delta_in_ticks = 1; @@ -2719,23 +2730,28 @@ static void bond_activebackup_arp_mon(struct work_struct *work) } bond_ab_arp_commit(bond); + rtnl_unlock(); + rcu_read_lock(); } - if (!bond_ab_arp_probe(bond)) { - /* rtnl locking failed, re-arm */ - delta_in_ticks = 1; - should_notify_peers = false; - } + should_notify_rtnl = bond_ab_arp_probe(bond); + rcu_read_unlock(); re_arm: if (bond->params.arp_interval) queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks); - if (should_notify_peers) { + if (should_notify_peers || should_notify_rtnl) { if (!rtnl_trylock()) return; - call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, bond->dev); + + if (should_notify_peers) + call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, + bond->dev); + if (should_notify_rtnl) + bond_slave_state_notify(bond); + rtnl_unlock(); } } @@ -2854,12 +2870,15 @@ static int bond_slave_netdev_event(unsigned long event, break; } - pr_info("%s: Primary slave changed to %s, reselecting active slave.\n", - bond->dev->name, bond->primary_slave ? slave_dev->name : - "none"); + pr_info("%s: Primary slave changed to %s, reselecting active slave\n", + bond->dev->name, + bond->primary_slave ? slave_dev->name : "none"); + + block_netpoll_tx(); write_lock_bh(&bond->curr_slave_lock); bond_select_active_slave(bond); write_unlock_bh(&bond->curr_slave_lock); + unblock_netpoll_tx(); break; case NETDEV_FEAT_CHANGE: bond_compute_features(bond); @@ -2889,8 +2908,7 @@ static int bond_netdev_event(struct notifier_block *this, struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); pr_debug("event_dev: %s, event: %lx\n", - event_dev ? event_dev->name : "None", - event); + event_dev ? event_dev->name : "None", event); if (!(event_dev->priv_flags & IFF_BONDING)) return NOTIFY_DONE; @@ -3032,9 +3050,11 @@ static int bond_open(struct net_device *bond_dev) bond_for_each_slave(bond, slave, iter) { if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP) && (slave != bond->curr_active_slave)) { - bond_set_slave_inactive_flags(slave); + bond_set_slave_inactive_flags(slave, + BOND_SLAVE_NOTIFY_NOW); } else { - bond_set_slave_active_flags(slave); + bond_set_slave_active_flags(slave, + BOND_SLAVE_NOTIFY_NOW); } } read_unlock(&bond->curr_slave_lock); @@ -3057,8 +3077,7 @@ static int bond_open(struct net_device *bond_dev) if (bond->params.arp_interval) { /* arp interval, in milliseconds. */ queue_delayed_work(bond->wq, &bond->arp_work, 0); - if (bond->params.arp_validate) - bond->recv_probe = bond_arp_rcv; + bond->recv_probe = bond_arp_rcv; } if (bond->params.mode == BOND_MODE_8023AD) { @@ -3345,8 +3364,8 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) struct list_head *iter; int res = 0; - pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond, - (bond_dev ? bond_dev->name : "None"), new_mtu); + pr_debug("bond=%p, name=%s, new_mtu=%d\n", + bond, bond_dev ? bond_dev->name : "None", new_mtu); /* Can't hold bond->lock with bh disabled here since * some base drivers panic. On the other hand we can't @@ -3365,8 +3384,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) bond_for_each_slave(bond, slave, iter) { pr_debug("s %p c_m %p\n", - slave, - slave->dev->netdev_ops->ndo_change_mtu); + slave, slave->dev->netdev_ops->ndo_change_mtu); res = dev_set_mtu(slave->dev, new_mtu); @@ -3431,7 +3449,8 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) /* If fail_over_mac is enabled, do nothing and return success. * Returning an error causes ifenslave to fail. */ - if (bond->params.fail_over_mac) + if (bond->params.fail_over_mac && + bond->params.mode == BOND_MODE_ACTIVEBACKUP) return 0; if (!is_valid_ether_addr(sa->sa_data)) @@ -3453,15 +3472,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) */ bond_for_each_slave(bond, slave, iter) { - const struct net_device_ops *slave_ops = slave->dev->netdev_ops; pr_debug("slave %p %s\n", slave, slave->dev->name); - - if (slave_ops->ndo_set_mac_address == NULL) { - res = -EOPNOTSUPP; - pr_debug("EOPNOTSUPP %s\n", slave->dev->name); - goto unwind; - } - res = dev_set_mac_address(slave->dev, addr); if (res) { /* TODO: consider downing the slave @@ -3537,7 +3548,7 @@ static void bond_xmit_slave_id(struct bonding *bond, struct sk_buff *skb, int sl } } /* no slave that can tx has been found */ - kfree_skb(skb); + dev_kfree_skb_any(skb); } /** @@ -3613,7 +3624,7 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d if (slave) bond_dev_queue_xmit(bond, skb, slave->dev); else - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3656,7 +3667,7 @@ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) if (slave && IS_UP(slave->dev) && slave->link == BOND_LINK_UP) bond_dev_queue_xmit(bond, skb, slave->dev); else - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -3692,7 +3703,7 @@ static inline int bond_slave_override(struct bonding *bond, static u16 bond_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { /* * This helper function exists to help dev_pick_tx get the correct @@ -3743,7 +3754,7 @@ static netdev_tx_t __bond_start_xmit(struct sk_buff *skb, struct net_device *dev pr_err("%s: Error: Unknown bonding mode %d\n", dev->name, bond->params.mode); WARN_ON_ONCE(1); - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } } @@ -3764,7 +3775,7 @@ static netdev_tx_t bond_start_xmit(struct sk_buff *skb, struct net_device *dev) if (bond_has_slaves(bond)) ret = __bond_start_xmit(skb, dev); else - kfree_skb(skb); + dev_kfree_skb_any(skb); rcu_read_unlock(); return ret; @@ -3927,7 +3938,7 @@ static void bond_uninit(struct net_device *bond_dev) /* Release the bonded slaves */ bond_for_each_slave(bond, slave, iter) __bond_release_one(bond_dev, slave->dev, true); - pr_info("%s: released all slaves\n", bond_dev->name); + pr_info("%s: Released all slaves\n", bond_dev->name); list_del(&bond->bond_list); @@ -3936,56 +3947,11 @@ static void bond_uninit(struct net_device *bond_dev) /*------------------------- Module initialization ---------------------------*/ -int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl) -{ - int i; - - for (i = 0; tbl[i].modename; i++) - if (mode == tbl[i].mode) - return tbl[i].mode; - - return -1; -} - -static int bond_parm_tbl_lookup_name(const char *modename, - const struct bond_parm_tbl *tbl) -{ - int i; - - for (i = 0; tbl[i].modename; i++) - if (strcmp(modename, tbl[i].modename) == 0) - return tbl[i].mode; - - return -1; -} - -/* - * Convert string input module parms. Accept either the - * number of the mode or its string name. A bit complicated because - * some mode names are substrings of other names, and calls from sysfs - * may have whitespace in the name (trailing newlines, for example). - */ -int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) -{ - int modeint; - char *p, modestr[BOND_MAX_MODENAME_LEN + 1]; - - for (p = (char *)buf; *p; p++) - if (!(isdigit(*p) || isspace(*p))) - break; - - if (*p && sscanf(buf, "%20s", modestr) != 0) - return bond_parm_tbl_lookup_name(modestr, tbl); - else if (sscanf(buf, "%d", &modeint) != 0) - return bond_parm_tbl_lookup(modeint, tbl); - - return -1; -} - static int bond_check_params(struct bond_params *params) { int arp_validate_value, fail_over_mac_value, primary_reselect_value, i; - struct bond_opt_value newval, *valptr; + struct bond_opt_value newval; + const struct bond_opt_value *valptr; int arp_all_targets_value; /* @@ -4005,7 +3971,7 @@ static int bond_check_params(struct bond_params *params) if ((bond_mode != BOND_MODE_XOR) && (bond_mode != BOND_MODE_8023AD)) { pr_info("xmit_hash_policy param is irrelevant in mode %s\n", - bond_mode_name(bond_mode)); + bond_mode_name(bond_mode)); } else { bond_opt_initstr(&newval, xmit_hash_policy); valptr = bond_opt_parse(bond_opt_get(BOND_OPT_XMIT_HASH), @@ -4046,74 +4012,71 @@ static int bond_check_params(struct bond_params *params) } params->ad_select = valptr->value; if (bond_mode != BOND_MODE_8023AD) - pr_warning("ad_select param only affects 802.3ad mode\n"); + pr_warn("ad_select param only affects 802.3ad mode\n"); } else { params->ad_select = BOND_AD_STABLE; } if (max_bonds < 0) { - pr_warning("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", - max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS); + pr_warn("Warning: max_bonds (%d) not in range %d-%d, so it was reset to BOND_DEFAULT_MAX_BONDS (%d)\n", + max_bonds, 0, INT_MAX, BOND_DEFAULT_MAX_BONDS); max_bonds = BOND_DEFAULT_MAX_BONDS; } if (miimon < 0) { - pr_warning("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n", - miimon, INT_MAX); + pr_warn("Warning: miimon module parameter (%d), not in range 0-%d, so it was reset to 0\n", + miimon, INT_MAX); miimon = 0; } if (updelay < 0) { - pr_warning("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n", - updelay, INT_MAX); + pr_warn("Warning: updelay module parameter (%d), not in range 0-%d, so it was reset to 0\n", + updelay, INT_MAX); updelay = 0; } if (downdelay < 0) { - pr_warning("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n", - downdelay, INT_MAX); + pr_warn("Warning: downdelay module parameter (%d), not in range 0-%d, so it was reset to 0\n", + downdelay, INT_MAX); downdelay = 0; } if ((use_carrier != 0) && (use_carrier != 1)) { - pr_warning("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n", - use_carrier); + pr_warn("Warning: use_carrier module parameter (%d), not of valid value (0/1), so it was set to 1\n", + use_carrier); use_carrier = 1; } if (num_peer_notif < 0 || num_peer_notif > 255) { - pr_warning("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", - num_peer_notif); + pr_warn("Warning: num_grat_arp/num_unsol_na (%d) not in range 0-255 so it was reset to 1\n", + num_peer_notif); num_peer_notif = 1; } /* reset values for 802.3ad/TLB/ALB */ if (BOND_NO_USES_ARP(bond_mode)) { if (!miimon) { - pr_warning("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n"); - pr_warning("Forcing miimon to 100msec\n"); + pr_warn("Warning: miimon must be specified, otherwise bonding will not detect link failure, speed and duplex which are essential for 802.3ad operation\n"); + pr_warn("Forcing miimon to 100msec\n"); miimon = BOND_DEFAULT_MIIMON; } } if (tx_queues < 1 || tx_queues > 255) { - pr_warning("Warning: tx_queues (%d) should be between " - "1 and 255, resetting to %d\n", - tx_queues, BOND_DEFAULT_TX_QUEUES); + pr_warn("Warning: tx_queues (%d) should be between 1 and 255, resetting to %d\n", + tx_queues, BOND_DEFAULT_TX_QUEUES); tx_queues = BOND_DEFAULT_TX_QUEUES; } if ((all_slaves_active != 0) && (all_slaves_active != 1)) { - pr_warning("Warning: all_slaves_active module parameter (%d), " - "not of valid value (0/1), so it was set to " - "0\n", all_slaves_active); + pr_warn("Warning: all_slaves_active module parameter (%d), not of valid value (0/1), so it was set to 0\n", + all_slaves_active); all_slaves_active = 0; } if (resend_igmp < 0 || resend_igmp > 255) { - pr_warning("Warning: resend_igmp (%d) should be between " - "0 and 255, resetting to %d\n", - resend_igmp, BOND_DEFAULT_RESEND_IGMP); + pr_warn("Warning: resend_igmp (%d) should be between 0 and 255, resetting to %d\n", + resend_igmp, BOND_DEFAULT_RESEND_IGMP); resend_igmp = BOND_DEFAULT_RESEND_IGMP; } @@ -4134,37 +4097,36 @@ static int bond_check_params(struct bond_params *params) /* just warn the user the up/down delay will have * no effect since miimon is zero... */ - pr_warning("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n", - updelay, downdelay); + pr_warn("Warning: miimon module parameter not set and updelay (%d) or downdelay (%d) module parameter is set; updelay and downdelay have no effect unless miimon is set\n", + updelay, downdelay); } } else { /* don't allow arp monitoring */ if (arp_interval) { - pr_warning("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n", - miimon, arp_interval); + pr_warn("Warning: miimon (%d) and arp_interval (%d) can't be used simultaneously, disabling ARP monitoring\n", + miimon, arp_interval); arp_interval = 0; } if ((updelay % miimon) != 0) { - pr_warning("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", - updelay, miimon, - (updelay / miimon) * miimon); + pr_warn("Warning: updelay (%d) is not a multiple of miimon (%d), updelay rounded to %d ms\n", + updelay, miimon, (updelay / miimon) * miimon); } updelay /= miimon; if ((downdelay % miimon) != 0) { - pr_warning("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n", - downdelay, miimon, - (downdelay / miimon) * miimon); + pr_warn("Warning: downdelay (%d) is not a multiple of miimon (%d), downdelay rounded to %d ms\n", + downdelay, miimon, + (downdelay / miimon) * miimon); } downdelay /= miimon; } if (arp_interval < 0) { - pr_warning("Warning: arp_interval module parameter (%d) , not in range 0-%d, so it was reset to 0\n", - arp_interval, INT_MAX); + pr_warn("Warning: arp_interval module parameter (%d), not in range 0-%d, so it was reset to 0\n", + arp_interval, INT_MAX); arp_interval = 0; } @@ -4175,30 +4137,26 @@ static int bond_check_params(struct bond_params *params) __be32 ip; if (!in4_pton(arp_ip_target[i], -1, (u8 *)&ip, -1, NULL) || IS_IP_TARGET_UNUSABLE_ADDRESS(ip)) { - pr_warning("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", - arp_ip_target[i]); + pr_warn("Warning: bad arp_ip_target module parameter (%s), ARP monitoring will not be performed\n", + arp_ip_target[i]); arp_interval = 0; } else { if (bond_get_targets_ip(arp_target, ip) == -1) arp_target[arp_ip_count++] = ip; else - pr_warning("Warning: duplicate address %pI4 in arp_ip_target, skipping\n", - &ip); + pr_warn("Warning: duplicate address %pI4 in arp_ip_target, skipping\n", + &ip); } } if (arp_interval && !arp_ip_count) { /* don't allow arping if no arp_ip_target given... */ - pr_warning("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n", - arp_interval); + pr_warn("Warning: arp_interval module parameter (%d) specified without providing an arp_ip_target parameter, arp_interval was reset to 0\n", + arp_interval); arp_interval = 0; } if (arp_validate) { - if (bond_mode != BOND_MODE_ACTIVEBACKUP) { - pr_err("arp_validate only supported in active-backup mode\n"); - return -EINVAL; - } if (!arp_interval) { pr_err("arp_validate requires arp_interval\n"); return -EINVAL; @@ -4240,23 +4198,23 @@ static int bond_check_params(struct bond_params *params) arp_interval, valptr->string, arp_ip_count); for (i = 0; i < arp_ip_count; i++) - pr_info(" %s", arp_ip_target[i]); + pr_cont(" %s", arp_ip_target[i]); - pr_info("\n"); + pr_cont("\n"); } else if (max_bonds) { /* miimon and arp_interval not set, we need one so things * work as expected, see bonding.txt for details */ - pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details.\n"); + pr_debug("Warning: either miimon or arp_interval and arp_ip_target module parameters must be specified, otherwise bonding will not detect link failures! see bonding.txt for details\n"); } if (primary && !USES_PRIMARY(bond_mode)) { /* currently, using a primary only makes sense * in active backup, TLB or ALB modes */ - pr_warning("Warning: %s primary device specified but has no effect in %s mode\n", - primary, bond_mode_name(bond_mode)); + pr_warn("Warning: %s primary device specified but has no effect in %s mode\n", + primary, bond_mode_name(bond_mode)); primary = NULL; } @@ -4285,14 +4243,14 @@ static int bond_check_params(struct bond_params *params) } fail_over_mac_value = valptr->value; if (bond_mode != BOND_MODE_ACTIVEBACKUP) - pr_warning("Warning: fail_over_mac only affects active-backup mode.\n"); + pr_warn("Warning: fail_over_mac only affects active-backup mode\n"); } else { fail_over_mac_value = BOND_FOM_NONE; } if (lp_interval == 0) { - pr_warning("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n", - INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL); + pr_warn("Warning: ip_interval must be between 1 and %d, so it was reset to %d\n", + INT_MAX, BOND_ALB_DEFAULT_LP_INTERVAL); lp_interval = BOND_ALB_DEFAULT_LP_INTERVAL; } diff --git a/drivers/net/bonding/bond_netlink.c b/drivers/net/bonding/bond_netlink.c index 70651f8e8e3b..f847e165d252 100644 --- a/drivers/net/bonding/bond_netlink.c +++ b/drivers/net/bonding/bond_netlink.c @@ -181,7 +181,7 @@ static int bond_changelink(struct net_device *bond_dev, int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]); if (arp_interval && miimon) { - pr_err("%s: ARP monitoring cannot be used with MII monitoring.\n", + pr_err("%s: ARP monitoring cannot be used with MII monitoring\n", bond->dev->name); return -EINVAL; } @@ -199,7 +199,7 @@ static int bond_changelink(struct net_device *bond_dev, nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) { __be32 target = nla_get_be32(attr); - bond_opt_initval(&newval, target); + bond_opt_initval(&newval, (__force u64)target); err = __bond_opt_set(bond, BOND_OPT_ARP_TARGETS, &newval); if (err) @@ -207,7 +207,7 @@ static int bond_changelink(struct net_device *bond_dev, i++; } if (i == 0 && bond->params.arp_interval) - pr_warn("%s: removing last arp target with arp_interval on\n", + pr_warn("%s: Removing last arp target with arp_interval on\n", bond->dev->name); if (err) return err; @@ -216,7 +216,7 @@ static int bond_changelink(struct net_device *bond_dev, int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]); if (arp_validate && miimon) { - pr_err("%s: ARP validating cannot be used with MII monitoring.\n", + pr_err("%s: ARP validating cannot be used with MII monitoring\n", bond->dev->name); return -EINVAL; } diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index 11cb943222d5..22800bde9752 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -14,13 +14,65 @@ #include <linux/errno.h> #include <linux/if.h> #include <linux/netdevice.h> -#include <linux/rwlock.h> +#include <linux/spinlock.h> #include <linux/rcupdate.h> #include <linux/ctype.h> #include <linux/inet.h> #include "bonding.h" -static struct bond_opt_value bond_mode_tbl[] = { +static int bond_option_active_slave_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_miimon_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_updelay_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_downdelay_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_use_carrier_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_arp_interval_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); +static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); +static int bond_option_arp_ip_targets_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_arp_validate_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_arp_all_targets_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_primary_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_primary_reselect_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_fail_over_mac_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_xmit_hash_policy_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_resend_igmp_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_num_peer_notif_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_all_slaves_active_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_min_links_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_lp_interval_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_pps_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_lacp_rate_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_ad_select_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_queue_id_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_mode_set(struct bonding *bond, + const struct bond_opt_value *newval); +static int bond_option_slaves_set(struct bonding *bond, + const struct bond_opt_value *newval); + + +static const struct bond_opt_value bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN, BOND_VALFLAG_DEFAULT}, { "active-backup", BOND_MODE_ACTIVEBACKUP, 0}, { "balance-xor", BOND_MODE_XOR, 0}, @@ -31,13 +83,13 @@ static struct bond_opt_value bond_mode_tbl[] = { { NULL, -1, 0}, }; -static struct bond_opt_value bond_pps_tbl[] = { +static const struct bond_opt_value bond_pps_tbl[] = { { "default", 1, BOND_VALFLAG_DEFAULT}, { "maxval", USHRT_MAX, BOND_VALFLAG_MAX}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_xmit_hashtype_tbl[] = { +static const struct bond_opt_value bond_xmit_hashtype_tbl[] = { { "layer2", BOND_XMIT_POLICY_LAYER2, BOND_VALFLAG_DEFAULT}, { "layer3+4", BOND_XMIT_POLICY_LAYER34, 0}, { "layer2+3", BOND_XMIT_POLICY_LAYER23, 0}, @@ -46,84 +98,87 @@ static struct bond_opt_value bond_xmit_hashtype_tbl[] = { { NULL, -1, 0}, }; -static struct bond_opt_value bond_arp_validate_tbl[] = { - { "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT}, - { "active", BOND_ARP_VALIDATE_ACTIVE, 0}, - { "backup", BOND_ARP_VALIDATE_BACKUP, 0}, - { "all", BOND_ARP_VALIDATE_ALL, 0}, - { NULL, -1, 0}, +static const struct bond_opt_value bond_arp_validate_tbl[] = { + { "none", BOND_ARP_VALIDATE_NONE, BOND_VALFLAG_DEFAULT}, + { "active", BOND_ARP_VALIDATE_ACTIVE, 0}, + { "backup", BOND_ARP_VALIDATE_BACKUP, 0}, + { "all", BOND_ARP_VALIDATE_ALL, 0}, + { "filter", BOND_ARP_FILTER, 0}, + { "filter_active", BOND_ARP_FILTER_ACTIVE, 0}, + { "filter_backup", BOND_ARP_FILTER_BACKUP, 0}, + { NULL, -1, 0}, }; -static struct bond_opt_value bond_arp_all_targets_tbl[] = { +static const struct bond_opt_value bond_arp_all_targets_tbl[] = { { "any", BOND_ARP_TARGETS_ANY, BOND_VALFLAG_DEFAULT}, { "all", BOND_ARP_TARGETS_ALL, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_fail_over_mac_tbl[] = { +static const struct bond_opt_value bond_fail_over_mac_tbl[] = { { "none", BOND_FOM_NONE, BOND_VALFLAG_DEFAULT}, { "active", BOND_FOM_ACTIVE, 0}, { "follow", BOND_FOM_FOLLOW, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_intmax_tbl[] = { +static const struct bond_opt_value bond_intmax_tbl[] = { { "off", 0, BOND_VALFLAG_DEFAULT}, { "maxval", INT_MAX, BOND_VALFLAG_MAX}, }; -static struct bond_opt_value bond_lacp_rate_tbl[] = { +static const struct bond_opt_value bond_lacp_rate_tbl[] = { { "slow", AD_LACP_SLOW, 0}, { "fast", AD_LACP_FAST, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_ad_select_tbl[] = { +static const struct bond_opt_value bond_ad_select_tbl[] = { { "stable", BOND_AD_STABLE, BOND_VALFLAG_DEFAULT}, { "bandwidth", BOND_AD_BANDWIDTH, 0}, { "count", BOND_AD_COUNT, 0}, { NULL, -1, 0}, }; -static struct bond_opt_value bond_num_peer_notif_tbl[] = { +static const struct bond_opt_value bond_num_peer_notif_tbl[] = { { "off", 0, 0}, { "maxval", 255, BOND_VALFLAG_MAX}, { "default", 1, BOND_VALFLAG_DEFAULT}, { NULL, -1, 0} }; -static struct bond_opt_value bond_primary_reselect_tbl[] = { +static const struct bond_opt_value bond_primary_reselect_tbl[] = { { "always", BOND_PRI_RESELECT_ALWAYS, BOND_VALFLAG_DEFAULT}, { "better", BOND_PRI_RESELECT_BETTER, 0}, { "failure", BOND_PRI_RESELECT_FAILURE, 0}, { NULL, -1}, }; -static struct bond_opt_value bond_use_carrier_tbl[] = { +static const struct bond_opt_value bond_use_carrier_tbl[] = { { "off", 0, 0}, { "on", 1, BOND_VALFLAG_DEFAULT}, { NULL, -1, 0} }; -static struct bond_opt_value bond_all_slaves_active_tbl[] = { +static const struct bond_opt_value bond_all_slaves_active_tbl[] = { { "off", 0, BOND_VALFLAG_DEFAULT}, { "on", 1, 0}, { NULL, -1, 0} }; -static struct bond_opt_value bond_resend_igmp_tbl[] = { +static const struct bond_opt_value bond_resend_igmp_tbl[] = { { "off", 0, 0}, { "maxval", 255, BOND_VALFLAG_MAX}, { "default", 1, BOND_VALFLAG_DEFAULT}, { NULL, -1, 0} }; -static struct bond_opt_value bond_lp_interval_tbl[] = { +static const struct bond_opt_value bond_lp_interval_tbl[] = { { "minval", 1, BOND_VALFLAG_MIN | BOND_VALFLAG_DEFAULT}, { "maxval", INT_MAX, BOND_VALFLAG_MAX}, }; -static struct bond_option bond_opts[] = { +static const struct bond_option bond_opts[] = { [BOND_OPT_MODE] = { .id = BOND_OPT_MODE, .name = "mode", @@ -151,7 +206,8 @@ static struct bond_option bond_opts[] = { .id = BOND_OPT_ARP_VALIDATE, .name = "arp_validate", .desc = "validate src/dst of ARP probes", - .unsuppmodes = BOND_MODE_ALL_EX(BIT(BOND_MODE_ACTIVEBACKUP)), + .unsuppmodes = BIT(BOND_MODE_8023AD) | BIT(BOND_MODE_TLB) | + BIT(BOND_MODE_ALB), .values = bond_arp_validate_tbl, .set = bond_option_arp_validate_set }, @@ -311,9 +367,9 @@ static struct bond_option bond_opts[] = { }; /* Searches for a value in opt's values[] table */ -struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) +const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) { - struct bond_option *opt; + const struct bond_option *opt; int i; opt = bond_opt_get(option); @@ -327,7 +383,7 @@ struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val) } /* Searches for a value in opt's values[] table which matches the flagmask */ -static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, +static const struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, u32 flagmask) { int i; @@ -344,7 +400,7 @@ static struct bond_opt_value *bond_opt_get_flags(const struct bond_option *opt, */ static bool bond_opt_check_range(const struct bond_option *opt, u64 val) { - struct bond_opt_value *minval, *maxval; + const struct bond_opt_value *minval, *maxval; minval = bond_opt_get_flags(opt, BOND_VALFLAG_MIN); maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX); @@ -364,11 +420,12 @@ static bool bond_opt_check_range(const struct bond_option *opt, u64 val) * or the struct_opt_value that matched. It also strips the new line from * @val->string if it's present. */ -struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, - struct bond_opt_value *val) +const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, + struct bond_opt_value *val) { char *p, valstr[BOND_OPT_MAX_NAMELEN + 1] = { 0, }; - struct bond_opt_value *tbl, *ret = NULL; + const struct bond_opt_value *tbl; + const struct bond_opt_value *ret = NULL; bool checkval; int i, rv; @@ -447,7 +504,7 @@ static int bond_opt_check_deps(struct bonding *bond, static void bond_opt_dep_print(struct bonding *bond, const struct bond_option *opt) { - struct bond_opt_value *modeval; + const struct bond_opt_value *modeval; struct bond_params *params; params = &bond->params; @@ -460,9 +517,9 @@ static void bond_opt_dep_print(struct bonding *bond, static void bond_opt_error_interpret(struct bonding *bond, const struct bond_option *opt, - int error, struct bond_opt_value *val) + int error, const struct bond_opt_value *val) { - struct bond_opt_value *minval, *maxval; + const struct bond_opt_value *minval, *maxval; char *p; switch (error) { @@ -473,10 +530,10 @@ static void bond_opt_error_interpret(struct bonding *bond, p = strchr(val->string, '\n'); if (p) *p = '\0'; - pr_err("%s: option %s: invalid value (%s).\n", + pr_err("%s: option %s: invalid value (%s)\n", bond->dev->name, opt->name, val->string); } else { - pr_err("%s: option %s: invalid value (%llu).\n", + pr_err("%s: option %s: invalid value (%llu)\n", bond->dev->name, opt->name, val->value); } } @@ -484,7 +541,7 @@ static void bond_opt_error_interpret(struct bonding *bond, maxval = bond_opt_get_flags(opt, BOND_VALFLAG_MAX); if (!maxval) break; - pr_err("%s: option %s: allowed values %llu - %llu.\n", + pr_err("%s: option %s: allowed values %llu - %llu\n", bond->dev->name, opt->name, minval ? minval->value : 0, maxval->value); break; @@ -492,11 +549,11 @@ static void bond_opt_error_interpret(struct bonding *bond, bond_opt_dep_print(bond, opt); break; case -ENOTEMPTY: - pr_err("%s: option %s: unable to set because the bond device has slaves.\n", + pr_err("%s: option %s: unable to set because the bond device has slaves\n", bond->dev->name, opt->name); break; case -EBUSY: - pr_err("%s: option %s: unable to set because the bond device is up.\n", + pr_err("%s: option %s: unable to set because the bond device is up\n", bond->dev->name, opt->name); break; default: @@ -517,7 +574,7 @@ static void bond_opt_error_interpret(struct bonding *bond, int __bond_opt_set(struct bonding *bond, unsigned int option, struct bond_opt_value *val) { - struct bond_opt_value *retval = NULL; + const struct bond_opt_value *retval = NULL; const struct bond_option *opt; int ret = -ENOENT; @@ -572,7 +629,7 @@ int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf) * This function checks if option is valid and if so returns a pointer * to its entry in the bond_opts[] option array. */ -struct bond_option *bond_opt_get(unsigned int option) +const struct bond_option *bond_opt_get(unsigned int option) { if (!BOND_OPT_VALID(option)) return NULL; @@ -580,7 +637,7 @@ struct bond_option *bond_opt_get(unsigned int option) return &bond_opts[option]; } -int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval) +int bond_option_mode_set(struct bonding *bond, const struct bond_opt_value *newval) { if (BOND_NO_USES_ARP(newval->value) && bond->params.arp_interval) { pr_info("%s: %s mode is incompatible with arp monitoring, start mii monitoring\n", @@ -589,7 +646,7 @@ int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval) bond->params.arp_interval = 0; /* set miimon to default value */ bond->params.miimon = BOND_DEFAULT_MIIMON; - pr_info("%s: Setting MII monitoring interval to %d.\n", + pr_info("%s: Setting MII monitoring interval to %d\n", bond->dev->name, bond->params.miimon); } @@ -618,8 +675,8 @@ struct net_device *bond_option_active_slave_get(struct bonding *bond) return __bond_option_active_slave_get(bond, bond->curr_active_slave); } -int bond_option_active_slave_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_active_slave_set(struct bonding *bond, + const struct bond_opt_value *newval) { char ifname[IFNAMSIZ] = { 0, }; struct net_device *slave_dev; @@ -636,13 +693,13 @@ int bond_option_active_slave_set(struct bonding *bond, if (slave_dev) { if (!netif_is_bond_slave(slave_dev)) { - pr_err("Device %s is not bonding slave.\n", + pr_err("Device %s is not bonding slave\n", slave_dev->name); return -EINVAL; } if (bond->dev != netdev_master_upper_dev_get(slave_dev)) { - pr_err("%s: Device %s is not our slave.\n", + pr_err("%s: Device %s is not our slave\n", bond->dev->name, slave_dev->name); return -EINVAL; } @@ -653,8 +710,7 @@ int bond_option_active_slave_set(struct bonding *bond, /* check to see if we are clearing active */ if (!slave_dev) { - pr_info("%s: Clearing current active slave.\n", - bond->dev->name); + pr_info("%s: Clearing current active slave\n", bond->dev->name); rcu_assign_pointer(bond->curr_active_slave, NULL); bond_select_active_slave(bond); } else { @@ -665,16 +721,16 @@ int bond_option_active_slave_set(struct bonding *bond, if (new_active == old_active) { /* do nothing */ - pr_info("%s: %s is already the current active slave.\n", + pr_info("%s: %s is already the current active slave\n", bond->dev->name, new_active->dev->name); } else { if (old_active && (new_active->link == BOND_LINK_UP) && IS_UP(new_active->dev)) { - pr_info("%s: Setting %s as active slave.\n", + pr_info("%s: Setting %s as active slave\n", bond->dev->name, new_active->dev->name); bond_change_active_slave(bond, new_active); } else { - pr_err("%s: Could not set %s as active slave; either %s is down or the link is down.\n", + pr_err("%s: Could not set %s as active slave; either %s is down or the link is down\n", bond->dev->name, new_active->dev->name, new_active->dev->name); ret = -EINVAL; @@ -688,21 +744,22 @@ int bond_option_active_slave_set(struct bonding *bond, return ret; } -int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_miimon_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting MII monitoring interval to %llu.\n", + pr_info("%s: Setting MII monitoring interval to %llu\n", bond->dev->name, newval->value); bond->params.miimon = newval->value; if (bond->params.updelay) - pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value.\n", + pr_info("%s: Note: Updating updelay (to %d) since it is a multiple of the miimon value\n", bond->dev->name, bond->params.updelay * bond->params.miimon); if (bond->params.downdelay) - pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value.\n", + pr_info("%s: Note: Updating downdelay (to %d) since it is a multiple of the miimon value\n", bond->dev->name, bond->params.downdelay * bond->params.miimon); if (newval->value && bond->params.arp_interval) { - pr_info("%s: MII monitoring cannot be used with ARP monitoring. Disabling ARP monitoring...\n", + pr_info("%s: MII monitoring cannot be used with ARP monitoring - disabling ARP monitoring...\n", bond->dev->name); bond->params.arp_interval = 0; if (bond->params.arp_validate) @@ -725,7 +782,8 @@ int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval) return 0; } -int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_updelay_set(struct bonding *bond, + const struct bond_opt_value *newval) { int value = newval->value; @@ -742,15 +800,14 @@ int bond_option_updelay_set(struct bonding *bond, struct bond_opt_value *newval) bond->params.miimon); } bond->params.updelay = value / bond->params.miimon; - pr_info("%s: Setting up delay to %d.\n", - bond->dev->name, - bond->params.updelay * bond->params.miimon); + pr_info("%s: Setting up delay to %d\n", + bond->dev->name, bond->params.updelay * bond->params.miimon); return 0; } -int bond_option_downdelay_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_downdelay_set(struct bonding *bond, + const struct bond_opt_value *newval) { int value = newval->value; @@ -767,37 +824,36 @@ int bond_option_downdelay_set(struct bonding *bond, bond->params.miimon); } bond->params.downdelay = value / bond->params.miimon; - pr_info("%s: Setting down delay to %d.\n", - bond->dev->name, - bond->params.downdelay * bond->params.miimon); + pr_info("%s: Setting down delay to %d\n", + bond->dev->name, bond->params.downdelay * bond->params.miimon); return 0; } -int bond_option_use_carrier_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_use_carrier_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting use_carrier to %llu.\n", + pr_info("%s: Setting use_carrier to %llu\n", bond->dev->name, newval->value); bond->params.use_carrier = newval->value; return 0; } -int bond_option_arp_interval_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_interval_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting ARP monitoring interval to %llu.\n", + pr_info("%s: Setting ARP monitoring interval to %llu\n", bond->dev->name, newval->value); bond->params.arp_interval = newval->value; if (newval->value) { if (bond->params.miimon) { - pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring.\n", + pr_info("%s: ARP monitoring cannot be used with MII monitoring. %s Disabling MII monitoring\n", bond->dev->name, bond->dev->name); bond->params.miimon = 0; } if (!bond->params.arp_targets[0]) - pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified.\n", + pr_info("%s: ARP monitoring has been set up, but no ARP targets have been specified\n", bond->dev->name); } if (bond->dev->flags & IFF_UP) { @@ -812,8 +868,7 @@ int bond_option_arp_interval_set(struct bonding *bond, cancel_delayed_work_sync(&bond->arp_work); } else { /* arp_validate can be set only in active-backup mode */ - if (bond->params.arp_validate) - bond->recv_probe = bond_arp_rcv; + bond->recv_probe = bond_arp_rcv; cancel_delayed_work_sync(&bond->mii_work); queue_delayed_work(bond->wq, &bond->arp_work, 0); } @@ -856,19 +911,18 @@ static int _bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) ind = bond_get_targets_ip(targets, 0); /* first free slot */ if (ind == -1) { - pr_err("%s: ARP target table is full!\n", - bond->dev->name); + pr_err("%s: ARP target table is full!\n", bond->dev->name); return -EINVAL; } - pr_info("%s: adding ARP target %pI4.\n", bond->dev->name, &target); + pr_info("%s: Adding ARP target %pI4\n", bond->dev->name, &target); _bond_options_arp_ip_target_set(bond, ind, target, jiffies); return 0; } -int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) +static int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) { int ret; @@ -880,7 +934,7 @@ int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target) return ret; } -int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) +static int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) { __be32 *targets = bond->params.arp_targets; struct list_head *iter; @@ -896,17 +950,16 @@ int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target) ind = bond_get_targets_ip(targets, target); if (ind == -1) { - pr_err("%s: unable to remove nonexistent ARP target %pI4.\n", + pr_err("%s: unable to remove nonexistent ARP target %pI4\n", bond->dev->name, &target); return -EINVAL; } if (ind == 0 && !targets[1] && bond->params.arp_interval) - pr_warn("%s: removing last arp target with arp_interval on\n", + pr_warn("%s: Removing last arp target with arp_interval on\n", bond->dev->name); - pr_info("%s: removing ARP target %pI4.\n", bond->dev->name, - &target); + pr_info("%s: Removing ARP target %pI4\n", bond->dev->name, &target); /* not to race with bond_arp_rcv */ write_lock_bh(&bond->lock); @@ -937,8 +990,8 @@ void bond_option_arp_ip_targets_clear(struct bonding *bond) write_unlock_bh(&bond->lock); } -int bond_option_arp_ip_targets_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_ip_targets_set(struct bonding *bond, + const struct bond_opt_value *newval) { int ret = -EPERM; __be32 target; @@ -954,7 +1007,7 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, else if (newval->string[0] == '-') ret = bond_option_arp_ip_target_rem(bond, target); else - pr_err("no command found in arp_ip_targets file for bond %s. Use +<addr> or -<addr>.\n", + pr_err("no command found in arp_ip_targets file for bond %s - use +<addr> or -<addr>\n", bond->dev->name); } else { target = newval->value; @@ -964,10 +1017,10 @@ int bond_option_arp_ip_targets_set(struct bonding *bond, return ret; } -int bond_option_arp_validate_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_validate_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: setting arp_validate to %s (%llu).\n", + pr_info("%s: Setting arp_validate to %s (%llu)\n", bond->dev->name, newval->string, newval->value); if (bond->dev->flags & IFF_UP) { @@ -981,17 +1034,18 @@ int bond_option_arp_validate_set(struct bonding *bond, return 0; } -int bond_option_arp_all_targets_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_arp_all_targets_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: setting arp_all_targets to %s (%llu).\n", + pr_info("%s: Setting arp_all_targets to %s (%llu)\n", bond->dev->name, newval->string, newval->value); bond->params.arp_all_targets = newval->value; return 0; } -int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_primary_set(struct bonding *bond, + const struct bond_opt_value *newval) { char *p, *primary = newval->string; struct list_head *iter; @@ -1006,8 +1060,7 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval) *p = '\0'; /* check to see if we are clearing primary */ if (!strlen(primary)) { - pr_info("%s: Setting primary slave to None.\n", - bond->dev->name); + pr_info("%s: Setting primary slave to None\n", bond->dev->name); bond->primary_slave = NULL; memset(bond->params.primary, 0, sizeof(bond->params.primary)); bond_select_active_slave(bond); @@ -1016,7 +1069,7 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval) bond_for_each_slave(bond, slave, iter) { if (strncmp(slave->dev->name, primary, IFNAMSIZ) == 0) { - pr_info("%s: Setting %s as primary slave.\n", + pr_info("%s: Setting %s as primary slave\n", bond->dev->name, slave->dev->name); bond->primary_slave = slave; strcpy(bond->params.primary, slave->dev->name); @@ -1026,15 +1079,14 @@ int bond_option_primary_set(struct bonding *bond, struct bond_opt_value *newval) } if (bond->primary_slave) { - pr_info("%s: Setting primary slave to None.\n", - bond->dev->name); + pr_info("%s: Setting primary slave to None\n", bond->dev->name); bond->primary_slave = NULL; bond_select_active_slave(bond); } strncpy(bond->params.primary, primary, IFNAMSIZ); bond->params.primary[IFNAMSIZ - 1] = 0; - pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet.\n", + pr_info("%s: Recording %s as primary, but it has not been enslaved to %s yet\n", bond->dev->name, primary, bond->dev->name); out: @@ -1045,10 +1097,10 @@ out: return 0; } -int bond_option_primary_reselect_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_primary_reselect_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: setting primary_reselect to %s (%llu).\n", + pr_info("%s: Setting primary_reselect to %s (%llu)\n", bond->dev->name, newval->string, newval->value); bond->params.primary_reselect = newval->value; @@ -1061,46 +1113,46 @@ int bond_option_primary_reselect_set(struct bonding *bond, return 0; } -int bond_option_fail_over_mac_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_fail_over_mac_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting fail_over_mac to %s (%llu).\n", + pr_info("%s: Setting fail_over_mac to %s (%llu)\n", bond->dev->name, newval->string, newval->value); bond->params.fail_over_mac = newval->value; return 0; } -int bond_option_xmit_hash_policy_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_xmit_hash_policy_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: setting xmit hash policy to %s (%llu).\n", + pr_info("%s: Setting xmit hash policy to %s (%llu)\n", bond->dev->name, newval->string, newval->value); bond->params.xmit_policy = newval->value; return 0; } -int bond_option_resend_igmp_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_resend_igmp_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting resend_igmp to %llu.\n", + pr_info("%s: Setting resend_igmp to %llu\n", bond->dev->name, newval->value); bond->params.resend_igmp = newval->value; return 0; } -int bond_option_num_peer_notif_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_num_peer_notif_set(struct bonding *bond, + const struct bond_opt_value *newval) { bond->params.num_peer_notif = newval->value; return 0; } -int bond_option_all_slaves_active_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_all_slaves_active_set(struct bonding *bond, + const struct bond_opt_value *newval) { struct list_head *iter; struct slave *slave; @@ -1120,8 +1172,8 @@ int bond_option_all_slaves_active_set(struct bonding *bond, return 0; } -int bond_option_min_links_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_min_links_set(struct bonding *bond, + const struct bond_opt_value *newval) { pr_info("%s: Setting min links value to %llu\n", bond->dev->name, newval->value); @@ -1130,15 +1182,16 @@ int bond_option_min_links_set(struct bonding *bond, return 0; } -int bond_option_lp_interval_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_lp_interval_set(struct bonding *bond, + const struct bond_opt_value *newval) { bond->params.lp_interval = newval->value; return 0; } -int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_pps_set(struct bonding *bond, + const struct bond_opt_value *newval) { bond->params.packets_per_slave = newval->value; if (newval->value > 0) { @@ -1155,10 +1208,10 @@ int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval) return 0; } -int bond_option_lacp_rate_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_lacp_rate_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting LACP rate to %s (%llu).\n", + pr_info("%s: Setting LACP rate to %s (%llu)\n", bond->dev->name, newval->string, newval->value); bond->params.lacp_fast = newval->value; bond_3ad_update_lacp_rate(bond); @@ -1166,18 +1219,18 @@ int bond_option_lacp_rate_set(struct bonding *bond, return 0; } -int bond_option_ad_select_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_ad_select_set(struct bonding *bond, + const struct bond_opt_value *newval) { - pr_info("%s: Setting ad_select to %s (%llu).\n", + pr_info("%s: Setting ad_select to %s (%llu)\n", bond->dev->name, newval->string, newval->value); bond->params.ad_select = newval->value; return 0; } -int bond_option_queue_id_set(struct bonding *bond, - struct bond_opt_value *newval) +static int bond_option_queue_id_set(struct bonding *bond, + const struct bond_opt_value *newval) { struct slave *slave, *update_slave; struct net_device *sdev; @@ -1199,8 +1252,7 @@ int bond_option_queue_id_set(struct bonding *bond, goto err_no_cmd; /* Check buffer length, valid ifname and queue id */ - if (strlen(newval->string) > IFNAMSIZ || - !dev_valid_name(newval->string) || + if (!dev_valid_name(newval->string) || qid > bond->dev->real_num_tx_queues) goto err_no_cmd; @@ -1232,14 +1284,14 @@ out: return ret; err_no_cmd: - pr_info("invalid input for queue_id set for %s.\n", - bond->dev->name); + pr_info("invalid input for queue_id set for %s\n", bond->dev->name); ret = -EPERM; goto out; } -int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval) +static int bond_option_slaves_set(struct bonding *bond, + const struct bond_opt_value *newval) { char command[IFNAMSIZ + 1] = { 0, }; struct net_device *dev; @@ -1254,7 +1306,7 @@ int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval) dev = __dev_get_by_name(dev_net(bond->dev), ifname); if (!dev) { - pr_info("%s: Interface %s does not exist!\n", + pr_info("%s: interface %s does not exist!\n", bond->dev->name, ifname); ret = -ENODEV; goto out; @@ -1262,12 +1314,12 @@ int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval) switch (command[0]) { case '+': - pr_info("%s: Adding slave %s.\n", bond->dev->name, dev->name); + pr_info("%s: Adding slave %s\n", bond->dev->name, dev->name); ret = bond_enslave(bond->dev, dev); break; case '-': - pr_info("%s: Removing slave %s.\n", bond->dev->name, dev->name); + pr_info("%s: Removing slave %s\n", bond->dev->name, dev->name); ret = bond_release(bond->dev, dev); break; @@ -1279,7 +1331,7 @@ out: return ret; err_no_cmd: - pr_err("no command found in slaves file for bond %s. Use +ifname or -ifname.\n", + pr_err("no command found in slaves file for bond %s - use +ifname or -ifname\n", bond->dev->name); ret = -EPERM; goto out; diff --git a/drivers/net/bonding/bond_options.h b/drivers/net/bonding/bond_options.h index 433d37f6940b..12be9e1bfb0c 100644 --- a/drivers/net/bonding/bond_options.h +++ b/drivers/net/bonding/bond_options.h @@ -81,8 +81,8 @@ struct bonding; struct bond_option { int id; - char *name; - char *desc; + const char *name; + const char *desc; u32 flags; /* unsuppmodes is used to denote modes in which the option isn't @@ -92,18 +92,19 @@ struct bond_option { /* supported values which this option can have, can be a subset of * BOND_OPTVAL_RANGE's value range */ - struct bond_opt_value *values; + const struct bond_opt_value *values; - int (*set)(struct bonding *bond, struct bond_opt_value *val); + int (*set)(struct bonding *bond, const struct bond_opt_value *val); }; int __bond_opt_set(struct bonding *bond, unsigned int option, struct bond_opt_value *val); int bond_opt_tryset_rtnl(struct bonding *bond, unsigned int option, char *buf); -struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, - struct bond_opt_value *val); -struct bond_option *bond_opt_get(unsigned int option); -struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val); + +const struct bond_opt_value *bond_opt_parse(const struct bond_option *opt, + struct bond_opt_value *val); +const struct bond_option *bond_opt_get(unsigned int option); +const struct bond_opt_value *bond_opt_get_val(unsigned int option, u64 val); /* This helper is used to initialize a bond_opt_value structure for parameter * passing. There should be either a valid string or value, but not both. @@ -122,49 +123,6 @@ static inline void __bond_opt_init(struct bond_opt_value *optval, #define bond_opt_initval(optval, value) __bond_opt_init(optval, NULL, value) #define bond_opt_initstr(optval, str) __bond_opt_init(optval, str, ULLONG_MAX) -int bond_option_mode_set(struct bonding *bond, struct bond_opt_value *newval); -int bond_option_pps_set(struct bonding *bond, struct bond_opt_value *newval); -int bond_option_xmit_hash_policy_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_validate_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_all_targets_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_fail_over_mac_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_interval_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_arp_ip_targets_set(struct bonding *bond, - struct bond_opt_value *newval); void bond_option_arp_ip_targets_clear(struct bonding *bond); -int bond_option_downdelay_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_updelay_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_lacp_rate_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_min_links_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_ad_select_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_num_peer_notif_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_miimon_set(struct bonding *bond, struct bond_opt_value *newval); -int bond_option_primary_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_primary_reselect_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_use_carrier_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_active_slave_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_queue_id_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_all_slaves_active_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_resend_igmp_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_lp_interval_set(struct bonding *bond, - struct bond_opt_value *newval); -int bond_option_slaves_set(struct bonding *bond, struct bond_opt_value *newval); + #endif /* _BOND_OPTIONS_H */ diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 3ac20e78eafc..013fdd0f45e9 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -65,13 +65,11 @@ static void bond_info_seq_stop(struct seq_file *seq, void *v) static void bond_info_show_master(struct seq_file *seq) { struct bonding *bond = seq->private; - struct bond_opt_value *optval; + const struct bond_opt_value *optval; struct slave *curr; int i; - read_lock(&bond->curr_slave_lock); - curr = bond->curr_active_slave; - read_unlock(&bond->curr_slave_lock); + curr = rcu_dereference(bond->curr_active_slave); seq_printf(seq, "Bonding Mode: %s", bond_mode_name(bond->params.mode)); @@ -254,8 +252,8 @@ void bond_create_proc_entry(struct bonding *bond) S_IRUGO, bn->proc_dir, &bond_info_fops, bond); if (bond->proc_entry == NULL) - pr_warning("Warning: Cannot create /proc/net/%s/%s\n", - DRV_NAME, bond_dev->name); + pr_warn("Warning: Cannot create /proc/net/%s/%s\n", + DRV_NAME, bond_dev->name); else memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ); } @@ -281,8 +279,8 @@ void __net_init bond_create_proc_dir(struct bond_net *bn) if (!bn->proc_dir) { bn->proc_dir = proc_mkdir(DRV_NAME, bn->net->proc_net); if (!bn->proc_dir) - pr_warning("Warning: cannot create /proc/net/%s\n", - DRV_NAME); + pr_warn("Warning: Cannot create /proc/net/%s\n", + DRV_NAME); } } diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 643fcc110299..0e8b268da0a0 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -117,9 +117,9 @@ static ssize_t bonding_store_bonds(struct class *cls, rv = bond_create(bn->net, ifname); if (rv) { if (rv == -EEXIST) - pr_info("%s already exists.\n", ifname); + pr_info("%s already exists\n", ifname); else - pr_info("%s creation failed.\n", ifname); + pr_info("%s creation failed\n", ifname); res = rv; } } else if (command[0] == '-') { @@ -144,7 +144,7 @@ static ssize_t bonding_store_bonds(struct class *cls, return res; err_no_cmd: - pr_err("no command found in bonding_masters. Use +ifname or -ifname.\n"); + pr_err("no command found in bonding_masters - use +ifname or -ifname\n"); return -EPERM; } @@ -220,7 +220,7 @@ static ssize_t bonding_show_mode(struct device *d, struct device_attribute *attr, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_MODE, bond->params.mode); @@ -251,7 +251,7 @@ static ssize_t bonding_show_xmit_hash(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_XMIT_HASH, bond->params.xmit_policy); @@ -282,7 +282,7 @@ static ssize_t bonding_show_arp_validate(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_ARP_VALIDATE, bond->params.arp_validate); @@ -314,7 +314,7 @@ static ssize_t bonding_show_arp_all_targets(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_ARP_ALL_TARGETS, bond->params.arp_all_targets); @@ -348,7 +348,7 @@ static ssize_t bonding_show_fail_over_mac(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_FAIL_OVER_MAC, bond->params.fail_over_mac); @@ -505,7 +505,7 @@ static ssize_t bonding_show_lacp(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_LACP_RATE, bond->params.lacp_fast); @@ -558,7 +558,7 @@ static ssize_t bonding_show_ad_select(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_AD_SELECT, bond->params.ad_select); @@ -686,7 +686,7 @@ static ssize_t bonding_show_primary_reselect(struct device *d, char *buf) { struct bonding *bond = to_bond(d); - struct bond_opt_value *val; + const struct bond_opt_value *val; val = bond_opt_get_val(BOND_OPT_PRIMARY_RESELECT, bond->params.primary_reselect); @@ -1135,7 +1135,7 @@ int bond_create_sysfs(struct bond_net *bn) /* Is someone being kinky and naming a device bonding_master? */ if (__dev_get_by_name(bn->net, class_attr_bonding_masters.attr.name)) - pr_err("network device named %s already exists in sysfs", + pr_err("network device named %s already exists in sysfs\n", class_attr_bonding_masters.attr.name); ret = 0; } diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index 86ccfb9f71cc..0896f1db24db 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -188,14 +188,16 @@ struct slave { struct net_device *dev; /* first - useful for panic debug */ struct bonding *bond; /* our master */ int delay; - unsigned long jiffies; - unsigned long last_arp_rx; + /* all three in jiffies */ + unsigned long last_link_up; + unsigned long last_rx; unsigned long target_last_arp_rx[BOND_MAX_ARP_TARGETS]; s8 link; /* one of BOND_LINK_XXXX */ s8 new_link; u8 backup:1, /* indicates backup slave. Value corresponds with BOND_STATE_ACTIVE and BOND_STATE_BACKUP */ - inactive:1; /* indicates inactive slave */ + inactive:1, /* indicates inactive slave */ + should_notify:1; /* indicateds whether the state changed */ u8 duplex; u32 original_mtu; u32 link_failure_count; @@ -291,7 +293,7 @@ static inline void bond_set_active_slave(struct slave *slave) { if (slave->backup) { slave->backup = 0; - rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC); } } @@ -299,7 +301,25 @@ static inline void bond_set_backup_slave(struct slave *slave) { if (!slave->backup) { slave->backup = 1; - rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_KERNEL); + rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC); + } +} + +static inline void bond_set_slave_state(struct slave *slave, + int slave_state, bool notify) +{ + if (slave->backup == slave_state) + return; + + slave->backup = slave_state; + if (notify) { + rtmsg_ifinfo(RTM_NEWLINK, slave->dev, 0, GFP_ATOMIC); + slave->should_notify = 0; + } else { + if (slave->should_notify) + slave->should_notify = 0; + else + slave->should_notify = 1; } } @@ -316,6 +336,19 @@ static inline void bond_slave_state_change(struct bonding *bond) } } +static inline void bond_slave_state_notify(struct bonding *bond) +{ + struct list_head *iter; + struct slave *tmp; + + bond_for_each_slave(bond, tmp, iter) { + if (tmp->should_notify) { + rtmsg_ifinfo(RTM_NEWLINK, tmp->dev, 0, GFP_ATOMIC); + tmp->should_notify = 0; + } + } +} + static inline int bond_slave_state(struct slave *slave) { return slave->backup; @@ -342,6 +375,14 @@ static inline bool bond_is_active_slave(struct slave *slave) #define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP) #define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \ BOND_ARP_VALIDATE_BACKUP) +#define BOND_ARP_FILTER (BOND_ARP_VALIDATE_ALL + 1) +#define BOND_ARP_FILTER_ACTIVE (BOND_ARP_VALIDATE_ACTIVE | \ + BOND_ARP_FILTER) +#define BOND_ARP_FILTER_BACKUP (BOND_ARP_VALIDATE_BACKUP | \ + BOND_ARP_FILTER) + +#define BOND_SLAVE_NOTIFY_NOW true +#define BOND_SLAVE_NOTIFY_LATER false static inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave) @@ -349,6 +390,12 @@ static inline int slave_do_arp_validate(struct bonding *bond, return bond->params.arp_validate & (1 << bond_slave_state(slave)); } +static inline int slave_do_arp_validate_only(struct bonding *bond, + struct slave *slave) +{ + return bond->params.arp_validate & BOND_ARP_FILTER; +} + /* Get the oldest arp which we've received on this slave for bond's * arp_targets. */ @@ -368,14 +415,10 @@ static inline unsigned long slave_oldest_target_arp_rx(struct bonding *bond, static inline unsigned long slave_last_rx(struct bonding *bond, struct slave *slave) { - if (slave_do_arp_validate(bond, slave)) { - if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL) - return slave_oldest_target_arp_rx(bond, slave); - else - return slave->last_arp_rx; - } + if (bond->params.arp_all_targets == BOND_ARP_TARGETS_ALL) + return slave_oldest_target_arp_rx(bond, slave); - return slave->dev->last_rx; + return slave->last_rx; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -394,17 +437,19 @@ static inline void bond_netpoll_send_skb(const struct slave *slave, } #endif -static inline void bond_set_slave_inactive_flags(struct slave *slave) +static inline void bond_set_slave_inactive_flags(struct slave *slave, + bool notify) { if (!bond_is_lb(slave->bond)) - bond_set_backup_slave(slave); + bond_set_slave_state(slave, BOND_STATE_BACKUP, notify); if (!slave->bond->params.all_slaves_active) slave->inactive = 1; } -static inline void bond_set_slave_active_flags(struct slave *slave) +static inline void bond_set_slave_active_flags(struct slave *slave, + bool notify) { - bond_set_active_slave(slave); + bond_set_slave_state(slave, BOND_STATE_ACTIVE, notify); slave->inactive = 0; } @@ -450,8 +495,6 @@ void bond_sysfs_slave_del(struct slave *slave); int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev); int bond_release(struct net_device *bond_dev, struct net_device *slave_dev); int bond_xmit_hash(struct bonding *bond, struct sk_buff *skb, int count); -int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); -int bond_parm_tbl_lookup(int mode, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_create_debugfs(void); @@ -464,8 +507,6 @@ void bond_setup(struct net_device *bond_dev); unsigned int bond_get_num_tx_queues(void); int bond_netlink_init(void); void bond_netlink_fini(void); -int bond_option_arp_ip_target_add(struct bonding *bond, __be32 target); -int bond_option_arp_ip_target_rem(struct bonding *bond, __be32 target); struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond); struct net_device *bond_option_active_slave_get(struct bonding *bond); const char *bond_slave_link_status(s8 link); diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 88a6a5810ec6..fc73865bb83a 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -204,7 +204,6 @@ static void ldisc_receive(struct tty_struct *tty, const u8 *data, skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); - skb->dev = ser->dev; debugfs_rx(ser, data, count); /* Push received packet up the stack. */ ret = netif_rx_ni(skb); diff --git a/drivers/net/caif/caif_spi.c b/drivers/net/caif/caif_spi.c index 155db68e13ba..ff54c0eb2052 100644 --- a/drivers/net/caif/caif_spi.c +++ b/drivers/net/caif/caif_spi.c @@ -554,7 +554,6 @@ int cfspi_rxfrm(struct cfspi *cfspi, u8 *buf, size_t len) skb->protocol = htons(ETH_P_CAIF); skb_reset_mac_header(skb); - skb->dev = cfspi->ndev; /* * Push received packet up the stack. diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig index d447b881bbde..9e7d95dae2c7 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 && CPU_LITTLE_ENDIAN) || PPC + depends on ARM || PPC ---help--- Say Y here if you want to support for Freescale FlexCAN. diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c index 6efe27458116..1d00b95f8983 100644 --- a/drivers/net/can/at91_can.c +++ b/drivers/net/can/at91_can.c @@ -420,7 +420,11 @@ static void at91_chip_start(struct net_device *dev) at91_transceiver_switch(priv, 1); /* enable chip */ - at91_write(priv, AT91_MR, AT91_MR_CANEN); + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) + reg_mr = AT91_MR_CANEN | AT91_MR_ABM; + else + reg_mr = AT91_MR_CANEN; + at91_write(priv, AT91_MR, reg_mr); priv->can.state = CAN_STATE_ERROR_ACTIVE; @@ -1341,7 +1345,8 @@ static int at91_can_probe(struct platform_device *pdev) priv->can.bittiming_const = &at91_bittiming_const; priv->can.do_set_mode = at91_set_mode; priv->can.do_get_berr_counter = at91_get_berr_counter; - priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES; + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | + CAN_CTRLMODE_LISTENONLY; priv->dev = dev; priv->reg_base = addr; priv->devtype_data = *devtype_data; diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c index 13a909822e25..c7a260478749 100644 --- a/drivers/net/can/dev.c +++ b/drivers/net/can/dev.c @@ -99,10 +99,10 @@ static int can_update_spt(const struct can_bittiming_const *btc, return 1000 * (tseg + 1 - *tseg2) / (tseg + 1); } -static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { struct can_priv *priv = netdev_priv(dev); - const struct can_bittiming_const *btc = priv->bittiming_const; long rate, best_rate = 0; long best_error = 1000000000, error = 0; int best_tseg = 0, best_brp = 0, brp = 0; @@ -110,9 +110,6 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) int spt_error = 1000, spt = 0, sampl_pt; u64 v64; - if (!priv->bittiming_const) - return -ENOTSUPP; - /* Use CIA recommended sample points */ if (bt->sample_point) { sampl_pt = bt->sample_point; @@ -204,7 +201,8 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } #else /* !CONFIG_CAN_CALC_BITTIMING */ -static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { netdev_err(dev, "bit-timing calculation not available\n"); return -EINVAL; @@ -217,16 +215,13 @@ static int can_calc_bittiming(struct net_device *dev, struct can_bittiming *bt) * prescaler value brp. You can find more information in the header * file linux/can/netlink.h. */ -static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { struct can_priv *priv = netdev_priv(dev); - const struct can_bittiming_const *btc = priv->bittiming_const; int tseg1, alltseg; u64 brp64; - if (!priv->bittiming_const) - return -ENOTSUPP; - tseg1 = bt->prop_seg + bt->phase_seg1; if (!bt->sjw) bt->sjw = 1; @@ -254,26 +249,29 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt) return 0; } -static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt) +static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt, + const struct can_bittiming_const *btc) { - struct can_priv *priv = netdev_priv(dev); int err; /* Check if the CAN device has bit-timing parameters */ - if (priv->bittiming_const) { + if (!btc) + return -ENOTSUPP; - /* Non-expert mode? Check if the bitrate has been pre-defined */ - if (!bt->tq) - /* Determine bit-timing parameters */ - err = can_calc_bittiming(dev, bt); - else - /* Check bit-timing params and calculate proper brp */ - err = can_fixup_bittiming(dev, bt); - if (err) - return err; - } + /* + * Depending on the given can_bittiming parameter structure the CAN + * timing parameters are calculated based on the provided bitrate OR + * alternatively the CAN timing parameters (tq, prop_seg, etc.) are + * provided directly which are then checked and fixed up. + */ + if (!bt->tq && bt->bitrate) + err = can_calc_bittiming(dev, bt, btc); + else if (bt->tq && !bt->bitrate) + err = can_fixup_bittiming(dev, bt, btc); + else + err = -EINVAL; - return 0; + return err; } /* @@ -317,28 +315,20 @@ void can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, BUG_ON(idx >= priv->echo_skb_max); /* check flag whether this packet has to be looped back */ - if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK) { + if (!(dev->flags & IFF_ECHO) || skb->pkt_type != PACKET_LOOPBACK || + (skb->protocol != htons(ETH_P_CAN) && + skb->protocol != htons(ETH_P_CANFD))) { kfree_skb(skb); return; } if (!priv->echo_skb[idx]) { - struct sock *srcsk = skb->sk; - if (atomic_read(&skb->users) != 1) { - struct sk_buff *old_skb = skb; - - skb = skb_clone(old_skb, GFP_ATOMIC); - kfree_skb(old_skb); - if (!skb) - return; - } else - skb_orphan(skb); - - skb->sk = srcsk; + skb = can_create_echo_skb(skb); + if (!skb) + return; /* make settings for echo to reduce code in irq context */ - skb->protocol = htons(ETH_P_CAN); skb->pkt_type = PACKET_BROADCAST; skb->ip_summed = CHECKSUM_UNNECESSARY; skb->dev = dev; @@ -521,6 +511,30 @@ struct sk_buff *alloc_can_skb(struct net_device *dev, struct can_frame **cf) } EXPORT_SYMBOL_GPL(alloc_can_skb); +struct sk_buff *alloc_canfd_skb(struct net_device *dev, + struct canfd_frame **cfd) +{ + struct sk_buff *skb; + + skb = netdev_alloc_skb(dev, sizeof(struct can_skb_priv) + + sizeof(struct canfd_frame)); + if (unlikely(!skb)) + return NULL; + + skb->protocol = htons(ETH_P_CANFD); + skb->pkt_type = PACKET_BROADCAST; + skb->ip_summed = CHECKSUM_UNNECESSARY; + + can_skb_reserve(skb); + can_skb_prv(skb)->ifindex = dev->ifindex; + + *cfd = (struct canfd_frame *)skb_put(skb, sizeof(struct canfd_frame)); + memset(*cfd, 0, sizeof(struct canfd_frame)); + + return skb; +} +EXPORT_SYMBOL_GPL(alloc_canfd_skb); + struct sk_buff *alloc_can_err_skb(struct net_device *dev, struct can_frame **cf) { struct sk_buff *skb; @@ -581,6 +595,39 @@ void free_candev(struct net_device *dev) EXPORT_SYMBOL_GPL(free_candev); /* + * changing MTU and control mode for CAN/CANFD devices + */ +int can_change_mtu(struct net_device *dev, int new_mtu) +{ + struct can_priv *priv = netdev_priv(dev); + + /* Do not allow changing the MTU while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + + /* allow change of MTU according to the CANFD ability of the device */ + switch (new_mtu) { + case CAN_MTU: + priv->ctrlmode &= ~CAN_CTRLMODE_FD; + break; + + case CANFD_MTU: + if (!(priv->ctrlmode_supported & CAN_CTRLMODE_FD)) + return -EINVAL; + + priv->ctrlmode |= CAN_CTRLMODE_FD; + break; + + default: + return -EINVAL; + } + + dev->mtu = new_mtu; + return 0; +} +EXPORT_SYMBOL_GPL(can_change_mtu); + +/* * Common open function when the device gets opened. * * This function should be called in the open function of the device @@ -590,11 +637,19 @@ int open_candev(struct net_device *dev) { struct can_priv *priv = netdev_priv(dev); - if (!priv->bittiming.tq && !priv->bittiming.bitrate) { + if (!priv->bittiming.bitrate) { netdev_err(dev, "bit-timing not yet defined\n"); return -EINVAL; } + /* For CAN FD the data bitrate has to be >= the arbitration bitrate */ + if ((priv->ctrlmode & CAN_CTRLMODE_FD) && + (!priv->data_bittiming.bitrate || + (priv->data_bittiming.bitrate < priv->bittiming.bitrate))) { + netdev_err(dev, "incorrect/missing data bit-timing\n"); + return -EINVAL; + } + /* Switch carrier on if device was stopped while in bus-off state */ if (!netif_carrier_ok(dev)) netif_carrier_on(dev); @@ -633,6 +688,10 @@ static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = { = { .len = sizeof(struct can_bittiming_const) }, [IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) }, [IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) }, + [IFLA_CAN_DATA_BITTIMING] + = { .len = sizeof(struct can_bittiming) }, + [IFLA_CAN_DATA_BITTIMING_CONST] + = { .len = sizeof(struct can_bittiming_const) }, }; static int can_changelink(struct net_device *dev, @@ -651,9 +710,7 @@ static int can_changelink(struct net_device *dev, if (dev->flags & IFF_UP) return -EBUSY; memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt)); - if ((!bt.bitrate && !bt.tq) || (bt.bitrate && bt.tq)) - return -EINVAL; - err = can_get_bittiming(dev, &bt); + err = can_get_bittiming(dev, &bt, priv->bittiming_const); if (err) return err; memcpy(&priv->bittiming, &bt, sizeof(bt)); @@ -677,6 +734,12 @@ static int can_changelink(struct net_device *dev, return -EOPNOTSUPP; priv->ctrlmode &= ~cm->mask; priv->ctrlmode |= cm->flags; + + /* CAN_CTRLMODE_FD can only be set when driver supports FD */ + if (priv->ctrlmode & CAN_CTRLMODE_FD) + dev->mtu = CANFD_MTU; + else + dev->mtu = CAN_MTU; } if (data[IFLA_CAN_RESTART_MS]) { @@ -695,6 +758,27 @@ static int can_changelink(struct net_device *dev, return err; } + if (data[IFLA_CAN_DATA_BITTIMING]) { + struct can_bittiming dbt; + + /* Do not allow changing bittiming while running */ + if (dev->flags & IFF_UP) + return -EBUSY; + memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), + sizeof(dbt)); + err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const); + if (err) + return err; + memcpy(&priv->data_bittiming, &dbt, sizeof(dbt)); + + if (priv->do_set_data_bittiming) { + /* Finally, set the bit-timing registers */ + err = priv->do_set_data_bittiming(dev); + if (err) + return err; + } + } + return 0; } @@ -703,7 +787,8 @@ static size_t can_get_size(const struct net_device *dev) struct can_priv *priv = netdev_priv(dev); size_t size = 0; - size += nla_total_size(sizeof(struct can_bittiming)); /* IFLA_CAN_BITTIMING */ + if (priv->bittiming.bitrate) /* IFLA_CAN_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); if (priv->bittiming_const) /* IFLA_CAN_BITTIMING_CONST */ size += nla_total_size(sizeof(struct can_bittiming_const)); size += nla_total_size(sizeof(struct can_clock)); /* IFLA_CAN_CLOCK */ @@ -712,6 +797,10 @@ static size_t can_get_size(const struct net_device *dev) size += nla_total_size(sizeof(u32)); /* IFLA_CAN_RESTART_MS */ if (priv->do_get_berr_counter) /* IFLA_CAN_BERR_COUNTER */ size += nla_total_size(sizeof(struct can_berr_counter)); + if (priv->data_bittiming.bitrate) /* IFLA_CAN_DATA_BITTIMING */ + size += nla_total_size(sizeof(struct can_bittiming)); + if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */ + size += nla_total_size(sizeof(struct can_bittiming_const)); return size; } @@ -725,19 +814,34 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev) if (priv->do_get_state) priv->do_get_state(dev, &state); - if (nla_put(skb, IFLA_CAN_BITTIMING, - sizeof(priv->bittiming), &priv->bittiming) || + + if ((priv->bittiming.bitrate && + nla_put(skb, IFLA_CAN_BITTIMING, + sizeof(priv->bittiming), &priv->bittiming)) || + (priv->bittiming_const && nla_put(skb, IFLA_CAN_BITTIMING_CONST, sizeof(*priv->bittiming_const), priv->bittiming_const)) || + nla_put(skb, IFLA_CAN_CLOCK, sizeof(cm), &priv->clock) || nla_put_u32(skb, IFLA_CAN_STATE, state) || nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) || nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) || + (priv->do_get_berr_counter && !priv->do_get_berr_counter(dev, &bec) && - nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec))) + nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) || + + (priv->data_bittiming.bitrate && + nla_put(skb, IFLA_CAN_DATA_BITTIMING, + sizeof(priv->data_bittiming), &priv->data_bittiming)) || + + (priv->data_bittiming_const && + nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST, + sizeof(*priv->data_bittiming_const), + priv->data_bittiming_const))) return -EMSGSIZE; + return 0; } diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index aaed97bee471..c94d698b73c2 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -144,6 +144,8 @@ #define FLEXCAN_MB_CODE_MASK (0xf0ffffff) +#define FLEXCAN_TIMEOUT_US (50) + /* * FLEXCAN hardware feature flags * @@ -235,9 +237,12 @@ static const struct can_bittiming_const flexcan_bittiming_const = { }; /* - * Abstract off the read/write for arm versus ppc. + * Abstract off the read/write for arm versus ppc. This + * assumes that PPC uses big-endian registers and everything + * else uses little-endian registers, independent of CPU + * endianess. */ -#if defined(__BIG_ENDIAN) +#if defined(CONFIG_PPC) static inline u32 flexcan_read(void __iomem *addr) { return in_be32(addr); @@ -259,6 +264,22 @@ static inline void flexcan_write(u32 val, void __iomem *addr) } #endif +static inline int flexcan_transceiver_enable(const struct flexcan_priv *priv) +{ + if (!priv->reg_xceiver) + return 0; + + return regulator_enable(priv->reg_xceiver); +} + +static inline int flexcan_transceiver_disable(const struct flexcan_priv *priv) +{ + if (!priv->reg_xceiver) + return 0; + + return regulator_disable(priv->reg_xceiver); +} + static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, u32 reg_esr) { @@ -266,26 +287,95 @@ static inline int flexcan_has_and_handle_berr(const struct flexcan_priv *priv, (reg_esr & FLEXCAN_ESR_ERR_BUS); } -static inline void flexcan_chip_enable(struct flexcan_priv *priv) +static int flexcan_chip_enable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = flexcan_read(®s->mcr); reg &= ~FLEXCAN_MCR_MDIS; flexcan_write(reg, ®s->mcr); - udelay(10); + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK) + return -ETIMEDOUT; + + return 0; } -static inline void flexcan_chip_disable(struct flexcan_priv *priv) +static int flexcan_chip_disable(struct flexcan_priv *priv) { struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; u32 reg; reg = flexcan_read(®s->mcr); reg |= FLEXCAN_MCR_MDIS; flexcan_write(reg, ®s->mcr); + + while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + usleep_range(10, 20); + + if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_LPM_ACK)) + return -ETIMEDOUT; + + return 0; +} + +static int flexcan_chip_freeze(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = 1000 * 1000 * 10 / priv->can.bittiming.bitrate; + u32 reg; + + reg = flexcan_read(®s->mcr); + reg |= FLEXCAN_MCR_HALT; + flexcan_write(reg, ®s->mcr); + + while (timeout-- && !(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) + usleep_range(100, 200); + + if (!(flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) + return -ETIMEDOUT; + + return 0; +} + +static int flexcan_chip_unfreeze(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; + u32 reg; + + reg = flexcan_read(®s->mcr); + reg &= ~FLEXCAN_MCR_HALT; + flexcan_write(reg, ®s->mcr); + + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_FRZ_ACK) + return -ETIMEDOUT; + + return 0; +} + +static int flexcan_chip_softreset(struct flexcan_priv *priv) +{ + struct flexcan_regs __iomem *regs = priv->base; + unsigned int timeout = FLEXCAN_TIMEOUT_US / 10; + + flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); + while (timeout-- && (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST)) + usleep_range(10, 20); + + if (flexcan_read(®s->mcr) & FLEXCAN_MCR_SOFTRST) + return -ETIMEDOUT; + + return 0; } static int flexcan_get_berr_counter(const struct net_device *dev, @@ -706,19 +796,14 @@ static int flexcan_chip_start(struct net_device *dev) u32 reg_mcr, reg_ctrl; /* enable module */ - flexcan_chip_enable(priv); + err = flexcan_chip_enable(priv); + if (err) + return err; /* soft reset */ - flexcan_write(FLEXCAN_MCR_SOFTRST, ®s->mcr); - udelay(10); - - reg_mcr = flexcan_read(®s->mcr); - if (reg_mcr & FLEXCAN_MCR_SOFTRST) { - netdev_err(dev, "Failed to softreset can module (mcr=0x%08x)\n", - reg_mcr); - err = -ENODEV; - goto out; - } + err = flexcan_chip_softreset(priv); + if (err) + goto out_chip_disable; flexcan_set_bittiming(dev); @@ -785,16 +870,14 @@ static int flexcan_chip_start(struct net_device *dev) if (priv->devtype_data->features & FLEXCAN_HAS_V10_FEATURES) flexcan_write(0x0, ®s->rxfgmask); - if (priv->reg_xceiver) { - err = regulator_enable(priv->reg_xceiver); - if (err) - goto out; - } + err = flexcan_transceiver_enable(priv); + if (err) + goto out_chip_disable; /* synchronize with the can bus */ - reg_mcr = flexcan_read(®s->mcr); - reg_mcr &= ~FLEXCAN_MCR_HALT; - flexcan_write(reg_mcr, ®s->mcr); + err = flexcan_chip_unfreeze(priv); + if (err) + goto out_transceiver_disable; priv->can.state = CAN_STATE_ERROR_ACTIVE; @@ -807,7 +890,9 @@ static int flexcan_chip_start(struct net_device *dev) return 0; - out: + out_transceiver_disable: + flexcan_transceiver_disable(priv); + out_chip_disable: flexcan_chip_disable(priv); return err; } @@ -822,18 +907,17 @@ static void flexcan_chip_stop(struct net_device *dev) { struct flexcan_priv *priv = netdev_priv(dev); struct flexcan_regs __iomem *regs = priv->base; - u32 reg; + + /* freeze + disable module */ + flexcan_chip_freeze(priv); + flexcan_chip_disable(priv); /* Disable all interrupts */ flexcan_write(0, ®s->imask1); + flexcan_write(priv->reg_ctrl_default & ~FLEXCAN_CTRL_ERR_ALL, + ®s->ctrl); - /* Disable + halt module */ - reg = flexcan_read(®s->mcr); - reg |= FLEXCAN_MCR_MDIS | FLEXCAN_MCR_HALT; - flexcan_write(reg, ®s->mcr); - - if (priv->reg_xceiver) - regulator_disable(priv->reg_xceiver); + flexcan_transceiver_disable(priv); priv->can.state = CAN_STATE_STOPPED; return; @@ -863,7 +947,7 @@ static int flexcan_open(struct net_device *dev) /* start chip and queuing */ err = flexcan_chip_start(dev); if (err) - goto out_close; + goto out_free_irq; can_led_event(dev, CAN_LED_EVENT_OPEN); @@ -872,6 +956,8 @@ static int flexcan_open(struct net_device *dev) return 0; + out_free_irq: + free_irq(dev->irq, dev); out_close: close_candev(dev); out_disable_per: @@ -942,12 +1028,16 @@ static int register_flexcandev(struct net_device *dev) goto out_disable_ipg; /* select "bus clock", chip must be disabled */ - flexcan_chip_disable(priv); + err = flexcan_chip_disable(priv); + if (err) + goto out_disable_per; reg = flexcan_read(®s->ctrl); reg |= FLEXCAN_CTRL_CLK_SRC; flexcan_write(reg, ®s->ctrl); - flexcan_chip_enable(priv); + err = flexcan_chip_enable(priv); + if (err) + goto out_chip_disable; /* set freeze, halt and activate FIFO, restrict register access */ reg = flexcan_read(®s->mcr); @@ -964,14 +1054,15 @@ static int register_flexcandev(struct net_device *dev) if (!(reg & FLEXCAN_MCR_FEN)) { netdev_err(dev, "Could not enable RX FIFO, unsupported core\n"); err = -ENODEV; - goto out_disable_per; + goto out_chip_disable; } err = register_candev(dev); - out_disable_per: /* disable core and turn off clocks */ + out_chip_disable: flexcan_chip_disable(priv); + out_disable_per: clk_disable_unprepare(priv->clk_per); out_disable_ipg: clk_disable_unprepare(priv->clk_ipg); @@ -1041,9 +1132,9 @@ static int flexcan_probe(struct platform_device *pdev) of_id = of_match_device(flexcan_of_match, &pdev->dev); if (of_id) { devtype_data = of_id->data; - } else if (pdev->id_entry->driver_data) { + } else if (platform_get_device_id(pdev)->driver_data) { devtype_data = (struct flexcan_devtype_data *) - pdev->id_entry->driver_data; + platform_get_device_id(pdev)->driver_data; } else { return -ENODEV; } @@ -1101,21 +1192,24 @@ static int flexcan_probe(struct platform_device *pdev) static int flexcan_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); + struct flexcan_priv *priv = netdev_priv(dev); unregister_flexcandev(dev); - + netif_napi_del(&priv->napi); free_candev(dev); return 0; } -#ifdef CONFIG_PM_SLEEP -static int flexcan_suspend(struct device *device) +static int __maybe_unused flexcan_suspend(struct device *device) { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); + int err; - flexcan_chip_disable(priv); + err = flexcan_chip_disable(priv); + if (err) + return err; if (netif_running(dev)) { netif_stop_queue(dev); @@ -1126,7 +1220,7 @@ static int flexcan_suspend(struct device *device) return 0; } -static int flexcan_resume(struct device *device) +static int __maybe_unused flexcan_resume(struct device *device) { struct net_device *dev = dev_get_drvdata(device); struct flexcan_priv *priv = netdev_priv(dev); @@ -1136,11 +1230,8 @@ static int flexcan_resume(struct device *device) netif_device_attach(dev); netif_start_queue(dev); } - flexcan_chip_enable(priv); - - return 0; + return flexcan_chip_enable(priv); } -#endif /* CONFIG_PM_SLEEP */ static SIMPLE_DEV_PM_OPS(flexcan_pm_ops, flexcan_suspend, flexcan_resume); diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c index e24e6690d672..b47df5e482fa 100644 --- a/drivers/net/can/janz-ican3.c +++ b/drivers/net/can/janz-ican3.c @@ -18,6 +18,7 @@ #include <linux/netdevice.h> #include <linux/can.h> #include <linux/can/dev.h> +#include <linux/can/skb.h> #include <linux/can/error.h> #include <linux/mfd/janz.h> @@ -197,9 +198,6 @@ struct ican3_dev { struct net_device *ndev; struct napi_struct napi; - /* Device for printing */ - struct device *dev; - /* module number */ unsigned int num; @@ -294,7 +292,7 @@ static int ican3_old_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) xord = locl ^ peer; if ((xord & MSYNC_RB_MASK) == 0x00) { - dev_dbg(mod->dev, "no mbox for reading\n"); + netdev_dbg(mod->ndev, "no mbox for reading\n"); return -ENOMEM; } @@ -339,7 +337,7 @@ static int ican3_old_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) xord = locl ^ peer; if ((xord & MSYNC_WB_MASK) == MSYNC_WB_MASK) { - dev_err(mod->dev, "no mbox for writing\n"); + netdev_err(mod->ndev, "no mbox for writing\n"); return -ENOMEM; } @@ -541,7 +539,7 @@ static int ican3_new_send_msg(struct ican3_dev *mod, struct ican3_msg *msg) memcpy_fromio(&desc, desc_addr, sizeof(desc)); if (!(desc.control & DESC_VALID)) { - dev_dbg(mod->dev, "%s: no free buffers\n", __func__); + netdev_dbg(mod->ndev, "%s: no free buffers\n", __func__); return -ENOMEM; } @@ -572,7 +570,7 @@ static int ican3_new_recv_msg(struct ican3_dev *mod, struct ican3_msg *msg) memcpy_fromio(&desc, desc_addr, sizeof(desc)); if (!(desc.control & DESC_VALID)) { - dev_dbg(mod->dev, "%s: no buffers to recv\n", __func__); + netdev_dbg(mod->ndev, "%s: no buffers to recv\n", __func__); return -ENOMEM; } @@ -882,7 +880,7 @@ static void can_frame_to_ican3(struct ican3_dev *mod, */ static void ican3_handle_idvers(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_dbg(mod->dev, "IDVERS response: %s\n", msg->data); + netdev_dbg(mod->ndev, "IDVERS response: %s\n", msg->data); } static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg) @@ -898,7 +896,7 @@ static void ican3_handle_msglost(struct ican3_dev *mod, struct ican3_msg *msg) * error frame for userspace */ if (msg->spec == MSG_MSGLOST) { - dev_err(mod->dev, "lost %d control messages\n", msg->data[0]); + netdev_err(mod->ndev, "lost %d control messages\n", msg->data[0]); return; } @@ -938,13 +936,13 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* we can only handle the SJA1000 part */ if (msg->data[1] != CEVTIND_CHIP_SJA1000) { - dev_err(mod->dev, "unable to handle errors on non-SJA1000\n"); + netdev_err(mod->ndev, "unable to handle errors on non-SJA1000\n"); return -ENODEV; } /* check the message length for sanity */ if (le16_to_cpu(msg->len) < 6) { - dev_err(mod->dev, "error message too short\n"); + netdev_err(mod->ndev, "error message too short\n"); return -EINVAL; } @@ -966,7 +964,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) */ if (isrc == CEVTIND_BEI) { int ret; - dev_dbg(mod->dev, "bus error interrupt\n"); + netdev_dbg(mod->ndev, "bus error interrupt\n"); /* TX error */ if (!(ecc & ECC_DIR)) { @@ -982,7 +980,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) */ ret = ican3_set_buserror(mod, 1); if (ret) { - dev_err(mod->dev, "unable to re-enable bus-error\n"); + netdev_err(mod->ndev, "unable to re-enable bus-error\n"); return ret; } @@ -997,7 +995,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* data overrun interrupt */ if (isrc == CEVTIND_DOI || isrc == CEVTIND_LOST) { - dev_dbg(mod->dev, "data overrun interrupt\n"); + netdev_dbg(mod->ndev, "data overrun interrupt\n"); cf->can_id |= CAN_ERR_CRTL; cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW; stats->rx_over_errors++; @@ -1006,7 +1004,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg) /* error warning + passive interrupt */ if (isrc == CEVTIND_EI) { - dev_dbg(mod->dev, "error warning + passive interrupt\n"); + netdev_dbg(mod->ndev, "error warning + passive interrupt\n"); if (status & SR_BS) { state = CAN_STATE_BUS_OFF; cf->can_id |= CAN_ERR_BUSOFF; @@ -1087,7 +1085,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) complete(&mod->termination_comp); break; default: - dev_err(mod->dev, "received an unknown inquiry response\n"); + netdev_err(mod->ndev, "received an unknown inquiry response\n"); break; } } @@ -1095,7 +1093,7 @@ static void ican3_handle_inquiry(struct ican3_dev *mod, struct ican3_msg *msg) static void ican3_handle_unknown_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_warn(mod->dev, "received unknown message: spec 0x%.2x length %d\n", + netdev_warn(mod->ndev, "received unknown message: spec 0x%.2x length %d\n", msg->spec, le16_to_cpu(msg->len)); } @@ -1104,7 +1102,7 @@ static void ican3_handle_unknown_message(struct ican3_dev *mod, */ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) { - dev_dbg(mod->dev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__, + netdev_dbg(mod->ndev, "%s: modno %d spec 0x%.2x len %d bytes\n", __func__, mod->num, msg->spec, le16_to_cpu(msg->len)); switch (msg->spec) { @@ -1133,20 +1131,9 @@ static void ican3_handle_message(struct ican3_dev *mod, struct ican3_msg *msg) */ static void ican3_put_echo_skb(struct ican3_dev *mod, struct sk_buff *skb) { - struct sock *srcsk = skb->sk; - - if (atomic_read(&skb->users) != 1) { - struct sk_buff *old_skb = skb; - - skb = skb_clone(old_skb, GFP_ATOMIC); - kfree_skb(old_skb); - if (!skb) - return; - } else { - skb_orphan(skb); - } - - skb->sk = srcsk; + skb = can_create_echo_skb(skb); + if (!skb) + return; /* save this skb for tx interrupt echo handling */ skb_queue_tail(&mod->echoq, skb); @@ -1322,7 +1309,7 @@ static int ican3_napi(struct napi_struct *napi, int budget) /* process all communication messages */ while (true) { - struct ican3_msg msg; + struct ican3_msg uninitialized_var(msg); ret = ican3_recv_msg(mod, &msg); if (ret) break; @@ -1416,7 +1403,7 @@ static int ican3_reset_module(struct ican3_dev *mod) msleep(10); } while (time_before(jiffies, start + HZ / 4)); - dev_err(mod->dev, "failed to reset CAN module\n"); + netdev_err(mod->ndev, "failed to reset CAN module\n"); return -ETIMEDOUT; } @@ -1435,7 +1422,7 @@ static int ican3_startup_module(struct ican3_dev *mod) ret = ican3_reset_module(mod); if (ret) { - dev_err(mod->dev, "unable to reset module\n"); + netdev_err(mod->ndev, "unable to reset module\n"); return ret; } @@ -1444,41 +1431,41 @@ static int ican3_startup_module(struct ican3_dev *mod) ret = ican3_msg_connect(mod); if (ret) { - dev_err(mod->dev, "unable to connect to module\n"); + netdev_err(mod->ndev, "unable to connect to module\n"); return ret; } ican3_init_new_host_interface(mod); ret = ican3_msg_newhostif(mod); if (ret) { - dev_err(mod->dev, "unable to switch to new-style interface\n"); + netdev_err(mod->ndev, "unable to switch to new-style interface\n"); return ret; } /* default to "termination on" */ ret = ican3_set_termination(mod, true); if (ret) { - dev_err(mod->dev, "unable to enable termination\n"); + netdev_err(mod->ndev, "unable to enable termination\n"); return ret; } /* default to "bus errors enabled" */ ret = ican3_set_buserror(mod, 1); if (ret) { - dev_err(mod->dev, "unable to set bus-error\n"); + netdev_err(mod->ndev, "unable to set bus-error\n"); return ret; } ican3_init_fast_host_interface(mod); ret = ican3_msg_fasthostif(mod); if (ret) { - dev_err(mod->dev, "unable to switch to fast host interface\n"); + netdev_err(mod->ndev, "unable to switch to fast host interface\n"); return ret; } ret = ican3_set_id_filter(mod, true); if (ret) { - dev_err(mod->dev, "unable to set acceptance filter\n"); + netdev_err(mod->ndev, "unable to set acceptance filter\n"); return ret; } @@ -1497,14 +1484,14 @@ static int ican3_open(struct net_device *ndev) /* open the CAN layer */ ret = open_candev(ndev); if (ret) { - dev_err(mod->dev, "unable to start CAN layer\n"); + netdev_err(mod->ndev, "unable to start CAN layer\n"); return ret; } /* bring the bus online */ ret = ican3_set_bus_state(mod, true); if (ret) { - dev_err(mod->dev, "unable to set bus-on\n"); + netdev_err(mod->ndev, "unable to set bus-on\n"); close_candev(ndev); return ret; } @@ -1528,7 +1515,7 @@ static int ican3_stop(struct net_device *ndev) /* bring the bus offline, stop receiving packets */ ret = ican3_set_bus_state(mod, false); if (ret) { - dev_err(mod->dev, "unable to set bus-off\n"); + netdev_err(mod->ndev, "unable to set bus-off\n"); return ret; } @@ -1555,7 +1542,7 @@ static int ican3_xmit(struct sk_buff *skb, struct net_device *ndev) /* check that we can actually transmit */ if (!ican3_txok(mod)) { - dev_err(mod->dev, "BUG: no free descriptors\n"); + netdev_err(mod->ndev, "BUG: no free descriptors\n"); spin_unlock_irqrestore(&mod->lock, flags); return NETDEV_TX_BUSY; } @@ -1667,7 +1654,7 @@ static int ican3_set_mode(struct net_device *ndev, enum can_mode mode) /* bring the bus online */ ret = ican3_set_bus_state(mod, true); if (ret) { - dev_err(mod->dev, "unable to set bus-on\n"); + netdev_err(ndev, "unable to set bus-on\n"); return ret; } @@ -1692,7 +1679,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev, ret = wait_for_completion_timeout(&mod->buserror_comp, HZ); if (ret == 0) { - dev_info(mod->dev, "%s timed out\n", __func__); + netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1718,7 +1705,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev, ret = wait_for_completion_timeout(&mod->termination_comp, HZ); if (ret == 0) { - dev_info(mod->dev, "%s timed out\n", __func__); + netdev_info(mod->ndev, "%s timed out\n", __func__); return -ETIMEDOUT; } @@ -1788,7 +1775,6 @@ static int ican3_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); mod = netdev_priv(ndev); mod->ndev = ndev; - mod->dev = &pdev->dev; mod->num = pdata->modno; netif_napi_add(ndev, &mod->napi, ican3_napi, ICAN3_RX_BUFFERS); skb_queue_head_init(&mod->echoq); diff --git a/drivers/net/can/mcp251x.c b/drivers/net/can/mcp251x.c index cdb9808d12db..50aa630c7dd4 100644 --- a/drivers/net/can/mcp251x.c +++ b/drivers/net/can/mcp251x.c @@ -601,10 +601,10 @@ static int mcp251x_do_set_bittiming(struct net_device *net) (bt->prop_seg - 1)); mcp251x_write_bits(spi, CNF3, CNF3_PHSEG2_MASK, (bt->phase_seg2 - 1)); - dev_info(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n", - mcp251x_read_reg(spi, CNF1), - mcp251x_read_reg(spi, CNF2), - mcp251x_read_reg(spi, CNF3)); + dev_dbg(&spi->dev, "CNF: 0x%02x 0x%02x 0x%02x\n", + mcp251x_read_reg(spi, CNF1), + mcp251x_read_reg(spi, CNF2), + mcp251x_read_reg(spi, CNF3)); return 0; } @@ -1155,8 +1155,6 @@ static int mcp251x_can_probe(struct spi_device *spi) devm_can_led_init(net); - dev_info(&spi->dev, "probed\n"); - return ret; error_probe: @@ -1197,9 +1195,7 @@ static int mcp251x_can_remove(struct spi_device *spi) return 0; } -#ifdef CONFIG_PM_SLEEP - -static int mcp251x_can_suspend(struct device *dev) +static int __maybe_unused mcp251x_can_suspend(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct mcp251x_priv *priv = spi_get_drvdata(spi); @@ -1229,7 +1225,7 @@ static int mcp251x_can_suspend(struct device *dev) return 0; } -static int mcp251x_can_resume(struct device *dev) +static int __maybe_unused mcp251x_can_resume(struct device *dev) { struct spi_device *spi = to_spi_device(dev); struct mcp251x_priv *priv = spi_get_drvdata(spi); @@ -1249,7 +1245,6 @@ static int mcp251x_can_resume(struct device *dev) enable_irq(spi->irq); return 0; } -#endif static SIMPLE_DEV_PM_OPS(mcp251x_can_pm_ops, mcp251x_can_suspend, mcp251x_can_resume); diff --git a/drivers/net/can/sja1000/Kconfig b/drivers/net/can/sja1000/Kconfig index ff2ba86cd4a4..4b18b8765523 100644 --- a/drivers/net/can/sja1000/Kconfig +++ b/drivers/net/can/sja1000/Kconfig @@ -17,16 +17,9 @@ config CAN_SJA1000_PLATFORM the "platform bus" (Linux abstraction for directly to the processor attached devices). Which can be found on various boards from Phytec (http://www.phytec.de) like the PCM027, - PCM038. - -config CAN_SJA1000_OF_PLATFORM - tristate "Generic OF Platform Bus based SJA1000 driver" - depends on OF - ---help--- - This driver adds support for the SJA1000 chips connected to - the OpenFirmware "platform bus" found on embedded systems with - OpenFirmware bindings, e.g. if you have a PowerPC based system - you may want to enable this option. + PCM038. It also provides the OpenFirmware "platform bus" found + on embedded systems with OpenFirmware bindings, e.g. if you + have a PowerPC based system you may want to enable this option. config CAN_EMS_PCMCIA tristate "EMS CPC-CARD Card" diff --git a/drivers/net/can/sja1000/Makefile b/drivers/net/can/sja1000/Makefile index b3d05cbfec36..531d5fcc97e5 100644 --- a/drivers/net/can/sja1000/Makefile +++ b/drivers/net/can/sja1000/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_CAN_SJA1000) += sja1000.o obj-$(CONFIG_CAN_SJA1000_ISA) += sja1000_isa.o obj-$(CONFIG_CAN_SJA1000_PLATFORM) += sja1000_platform.o -obj-$(CONFIG_CAN_SJA1000_OF_PLATFORM) += sja1000_of_platform.o obj-$(CONFIG_CAN_EMS_PCMCIA) += ems_pcmcia.o obj-$(CONFIG_CAN_EMS_PCI) += ems_pci.o obj-$(CONFIG_CAN_KVASER_PCI) += kvaser_pci.o diff --git a/drivers/net/can/sja1000/sja1000.c b/drivers/net/can/sja1000/sja1000.c index f17c3018b7c7..55cce4737518 100644 --- a/drivers/net/can/sja1000/sja1000.c +++ b/drivers/net/can/sja1000/sja1000.c @@ -106,8 +106,7 @@ static int sja1000_probe_chip(struct net_device *dev) struct sja1000_priv *priv = netdev_priv(dev); if (priv->reg_base && sja1000_is_absent(priv)) { - printk(KERN_INFO "%s: probing @0x%lX failed\n", - DRV_NAME, dev->base_addr); + netdev_err(dev, "probing failed\n"); return 0; } return -1; diff --git a/drivers/net/can/sja1000/sja1000_of_platform.c b/drivers/net/can/sja1000/sja1000_of_platform.c deleted file mode 100644 index 2f6e24534231..000000000000 --- a/drivers/net/can/sja1000/sja1000_of_platform.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Driver for SJA1000 CAN controllers on the OpenFirmware platform bus - * - * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the version 2 of the GNU General Public License - * as published by the Free Software Foundation - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see <http://www.gnu.org/licenses/>. - */ - -/* This is a generic driver for SJA1000 chips on the OpenFirmware platform - * bus found on embedded PowerPC systems. You need a SJA1000 CAN node - * definition in your flattened device tree source (DTS) file similar to: - * - * can@3,100 { - * compatible = "nxp,sja1000"; - * reg = <3 0x100 0x80>; - * interrupts = <2 0>; - * interrupt-parent = <&mpic>; - * nxp,external-clock-frequency = <16000000>; - * }; - * - * See "Documentation/devicetree/bindings/net/can/sja1000.txt" for further - * information. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/netdevice.h> -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/can/dev.h> - -#include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> - -#include "sja1000.h" - -#define DRV_NAME "sja1000_of_platform" - -MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); -MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the OF platform bus"); -MODULE_LICENSE("GPL v2"); - -#define SJA1000_OFP_CAN_CLOCK (16000000 / 2) - -#define SJA1000_OFP_OCR OCR_TX0_PULLDOWN -#define SJA1000_OFP_CDR (CDR_CBP | CDR_CLK_OFF) - -static u8 sja1000_ofp_read_reg(const struct sja1000_priv *priv, int reg) -{ - return ioread8(priv->reg_base + reg); -} - -static void sja1000_ofp_write_reg(const struct sja1000_priv *priv, - int reg, u8 val) -{ - iowrite8(val, priv->reg_base + reg); -} - -static int sja1000_ofp_remove(struct platform_device *ofdev) -{ - struct net_device *dev = platform_get_drvdata(ofdev); - struct sja1000_priv *priv = netdev_priv(dev); - struct device_node *np = ofdev->dev.of_node; - struct resource res; - - unregister_sja1000dev(dev); - free_sja1000dev(dev); - iounmap(priv->reg_base); - irq_dispose_mapping(dev->irq); - - of_address_to_resource(np, 0, &res); - release_mem_region(res.start, resource_size(&res)); - - return 0; -} - -static int sja1000_ofp_probe(struct platform_device *ofdev) -{ - struct device_node *np = ofdev->dev.of_node; - struct net_device *dev; - struct sja1000_priv *priv; - struct resource res; - u32 prop; - int err, irq, res_size; - void __iomem *base; - - err = of_address_to_resource(np, 0, &res); - if (err) { - dev_err(&ofdev->dev, "invalid address\n"); - return err; - } - - res_size = resource_size(&res); - - if (!request_mem_region(res.start, res_size, DRV_NAME)) { - dev_err(&ofdev->dev, "couldn't request %pR\n", &res); - return -EBUSY; - } - - base = ioremap_nocache(res.start, res_size); - if (!base) { - dev_err(&ofdev->dev, "couldn't ioremap %pR\n", &res); - err = -ENOMEM; - goto exit_release_mem; - } - - irq = irq_of_parse_and_map(np, 0); - if (irq == 0) { - dev_err(&ofdev->dev, "no irq found\n"); - err = -ENODEV; - goto exit_unmap_mem; - } - - dev = alloc_sja1000dev(0); - if (!dev) { - err = -ENOMEM; - goto exit_dispose_irq; - } - - priv = netdev_priv(dev); - - priv->read_reg = sja1000_ofp_read_reg; - priv->write_reg = sja1000_ofp_write_reg; - - err = of_property_read_u32(np, "nxp,external-clock-frequency", &prop); - if (!err) - priv->can.clock.freq = prop / 2; - else - priv->can.clock.freq = SJA1000_OFP_CAN_CLOCK; /* default */ - - err = of_property_read_u32(np, "nxp,tx-output-mode", &prop); - if (!err) - priv->ocr |= prop & OCR_MODE_MASK; - else - priv->ocr |= OCR_MODE_NORMAL; /* default */ - - err = of_property_read_u32(np, "nxp,tx-output-config", &prop); - if (!err) - priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; - else - priv->ocr |= OCR_TX0_PULLDOWN; /* default */ - - err = of_property_read_u32(np, "nxp,clock-out-frequency", &prop); - if (!err && prop) { - u32 divider = priv->can.clock.freq * 2 / prop; - - if (divider > 1) - priv->cdr |= divider / 2 - 1; - else - priv->cdr |= CDR_CLKOUT_MASK; - } else { - priv->cdr |= CDR_CLK_OFF; /* default */ - } - - if (!of_property_read_bool(np, "nxp,no-comparator-bypass")) - priv->cdr |= CDR_CBP; /* default */ - - priv->irq_flags = IRQF_SHARED; - priv->reg_base = base; - - dev->irq = irq; - - dev_info(&ofdev->dev, - "reg_base=0x%p irq=%d clock=%d ocr=0x%02x cdr=0x%02x\n", - priv->reg_base, dev->irq, priv->can.clock.freq, - priv->ocr, priv->cdr); - - platform_set_drvdata(ofdev, dev); - SET_NETDEV_DEV(dev, &ofdev->dev); - - err = register_sja1000dev(dev); - if (err) { - dev_err(&ofdev->dev, "registering %s failed (err=%d)\n", - DRV_NAME, err); - goto exit_free_sja1000; - } - - return 0; - -exit_free_sja1000: - free_sja1000dev(dev); -exit_dispose_irq: - irq_dispose_mapping(irq); -exit_unmap_mem: - iounmap(base); -exit_release_mem: - release_mem_region(res.start, res_size); - - return err; -} - -static struct of_device_id sja1000_ofp_table[] = { - {.compatible = "nxp,sja1000"}, - {}, -}; -MODULE_DEVICE_TABLE(of, sja1000_ofp_table); - -static struct platform_driver sja1000_ofp_driver = { - .driver = { - .owner = THIS_MODULE, - .name = DRV_NAME, - .of_match_table = sja1000_ofp_table, - }, - .probe = sja1000_ofp_probe, - .remove = sja1000_ofp_remove, -}; - -module_platform_driver(sja1000_ofp_driver); diff --git a/drivers/net/can/sja1000/sja1000_platform.c b/drivers/net/can/sja1000/sja1000_platform.c index 943df645b459..95a844a7ee7b 100644 --- a/drivers/net/can/sja1000/sja1000_platform.c +++ b/drivers/net/can/sja1000/sja1000_platform.c @@ -26,12 +26,16 @@ #include <linux/can/dev.h> #include <linux/can/platform/sja1000.h> #include <linux/io.h> +#include <linux/of.h> +#include <linux/of_irq.h> #include "sja1000.h" #define DRV_NAME "sja1000_platform" +#define SP_CAN_CLOCK (16000000 / 2) MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); MODULE_DESCRIPTION("Socket-CAN driver for SJA1000 on the platform bus"); MODULE_ALIAS("platform:" DRV_NAME); MODULE_LICENSE("GPL v2"); @@ -66,59 +70,16 @@ static void sp_write_reg32(const struct sja1000_priv *priv, int reg, u8 val) iowrite8(val, priv->reg_base + reg * 4); } -static int sp_probe(struct platform_device *pdev) +static void sp_populate(struct sja1000_priv *priv, + struct sja1000_platform_data *pdata, + unsigned long resource_mem_flags) { - int err; - void __iomem *addr; - struct net_device *dev; - struct sja1000_priv *priv; - struct resource *res_mem, *res_irq; - struct sja1000_platform_data *pdata; - - pdata = dev_get_platdata(&pdev->dev); - if (!pdata) { - dev_err(&pdev->dev, "No platform data provided!\n"); - err = -ENODEV; - goto exit; - } - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!res_mem || !res_irq) { - err = -ENODEV; - goto exit; - } - - if (!request_mem_region(res_mem->start, resource_size(res_mem), - DRV_NAME)) { - err = -EBUSY; - goto exit; - } - - addr = ioremap_nocache(res_mem->start, resource_size(res_mem)); - if (!addr) { - err = -ENOMEM; - goto exit_release; - } - - dev = alloc_sja1000dev(0); - if (!dev) { - err = -ENOMEM; - goto exit_iounmap; - } - priv = netdev_priv(dev); - - dev->irq = res_irq->start; - priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; - if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) - priv->irq_flags |= IRQF_SHARED; - priv->reg_base = addr; /* The CAN clock frequency is half the oscillator clock frequency */ priv->can.clock.freq = pdata->osc_freq / 2; priv->ocr = pdata->ocr; priv->cdr = pdata->cdr; - switch (res_mem->flags & IORESOURCE_MEM_TYPE_MASK) { + switch (resource_mem_flags & IORESOURCE_MEM_TYPE_MASK) { case IORESOURCE_MEM_32BIT: priv->read_reg = sp_read_reg32; priv->write_reg = sp_write_reg32; @@ -133,6 +94,124 @@ static int sp_probe(struct platform_device *pdev) priv->write_reg = sp_write_reg8; break; } +} + +static void sp_populate_of(struct sja1000_priv *priv, struct device_node *of) +{ + int err; + u32 prop; + + err = of_property_read_u32(of, "reg-io-width", &prop); + if (err) + prop = 1; /* 8 bit is default */ + + switch (prop) { + case 4: + priv->read_reg = sp_read_reg32; + priv->write_reg = sp_write_reg32; + break; + case 2: + priv->read_reg = sp_read_reg16; + priv->write_reg = sp_write_reg16; + break; + case 1: /* fallthrough */ + default: + priv->read_reg = sp_read_reg8; + priv->write_reg = sp_write_reg8; + } + + err = of_property_read_u32(of, "nxp,external-clock-frequency", &prop); + if (!err) + priv->can.clock.freq = prop / 2; + else + priv->can.clock.freq = SP_CAN_CLOCK; /* default */ + + err = of_property_read_u32(of, "nxp,tx-output-mode", &prop); + if (!err) + priv->ocr |= prop & OCR_MODE_MASK; + else + priv->ocr |= OCR_MODE_NORMAL; /* default */ + + err = of_property_read_u32(of, "nxp,tx-output-config", &prop); + if (!err) + priv->ocr |= (prop << OCR_TX_SHIFT) & OCR_TX_MASK; + else + priv->ocr |= OCR_TX0_PULLDOWN; /* default */ + + err = of_property_read_u32(of, "nxp,clock-out-frequency", &prop); + if (!err && prop) { + u32 divider = priv->can.clock.freq * 2 / prop; + + if (divider > 1) + priv->cdr |= divider / 2 - 1; + else + priv->cdr |= CDR_CLKOUT_MASK; + } else { + priv->cdr |= CDR_CLK_OFF; /* default */ + } + + if (!of_property_read_bool(of, "nxp,no-comparator-bypass")) + priv->cdr |= CDR_CBP; /* default */ +} + +static int sp_probe(struct platform_device *pdev) +{ + int err, irq = 0; + void __iomem *addr; + struct net_device *dev; + struct sja1000_priv *priv; + struct resource *res_mem, *res_irq = NULL; + struct sja1000_platform_data *pdata; + struct device_node *of = pdev->dev.of_node; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata && !of) { + dev_err(&pdev->dev, "No platform data provided!\n"); + return -ENODEV; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) + return -ENODEV; + + if (!devm_request_mem_region(&pdev->dev, res_mem->start, + resource_size(res_mem), DRV_NAME)) + return -EBUSY; + + addr = devm_ioremap_nocache(&pdev->dev, res_mem->start, + resource_size(res_mem)); + if (!addr) + return -ENOMEM; + + if (of) + irq = irq_of_parse_and_map(of, 0); + else + res_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + + if (!irq && !res_irq) + return -ENODEV; + + dev = alloc_sja1000dev(0); + if (!dev) + return -ENOMEM; + priv = netdev_priv(dev); + + if (res_irq) { + irq = res_irq->start; + priv->irq_flags = res_irq->flags & IRQF_TRIGGER_MASK; + if (res_irq->flags & IORESOURCE_IRQ_SHAREABLE) + priv->irq_flags |= IRQF_SHARED; + } else { + priv->irq_flags = IRQF_SHARED; + } + + dev->irq = irq; + priv->reg_base = addr; + + if (of) + sp_populate_of(priv, of); + else + sp_populate(priv, pdata, res_mem->flags); platform_set_drvdata(pdev, dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -150,39 +229,32 @@ static int sp_probe(struct platform_device *pdev) exit_free: free_sja1000dev(dev); - exit_iounmap: - iounmap(addr); - exit_release: - release_mem_region(res_mem->start, resource_size(res_mem)); - exit: return err; } static int sp_remove(struct platform_device *pdev) { struct net_device *dev = platform_get_drvdata(pdev); - struct sja1000_priv *priv = netdev_priv(dev); - struct resource *res; unregister_sja1000dev(dev); - - if (priv->reg_base) - iounmap(priv->reg_base); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - free_sja1000dev(dev); return 0; } +static struct of_device_id sp_of_table[] = { + {.compatible = "nxp,sja1000"}, + {}, +}; +MODULE_DEVICE_TABLE(of, sp_of_table); + static struct platform_driver sp_driver = { .probe = sp_probe, .remove = sp_remove, .driver = { .name = DRV_NAME, .owner = THIS_MODULE, + .of_match_table = sp_of_table, }, }; diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index 6c859bba8b65..e77d11049747 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -473,6 +473,8 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev) return err; dev->nchannels = msg.u.cardinfo.nchannels; + if (dev->nchannels > MAX_NET_DEVICES) + return -EINVAL; return 0; } diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 0a2a5ee79a17..4e94057ef5cf 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -46,6 +46,7 @@ #include <linux/if_ether.h> #include <linux/can.h> #include <linux/can/dev.h> +#include <linux/can/skb.h> #include <linux/slab.h> #include <net/rtnetlink.h> @@ -109,25 +110,23 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev) stats->rx_packets++; stats->rx_bytes += cfd->len; } - kfree_skb(skb); + consume_skb(skb); return NETDEV_TX_OK; } /* perform standard echo handling for CAN network interfaces */ if (loop) { - struct sock *srcsk = skb->sk; - skb = skb_share_check(skb, GFP_ATOMIC); + skb = can_create_echo_skb(skb); if (!skb) return NETDEV_TX_OK; /* receive with packet counting */ - skb->sk = srcsk; vcan_rx(skb, dev); } else { /* no looped packets => no counting */ - kfree_skb(skb); + consume_skb(skb); } return NETDEV_TX_OK; } diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index bd8f84b0b894..1656317c96f8 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -88,16 +88,10 @@ static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) static int dummy_dev_init(struct net_device *dev) { - int i; - dev->dstats = alloc_percpu(struct pcpu_dstats); + dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats); if (!dev->dstats) return -ENOMEM; - for_each_possible_cpu(i) { - struct pcpu_dstats *dstats; - dstats = per_cpu_ptr(dev->dstats, i); - u64_stats_init(&dstats->syncp); - } return 0; } diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c index 5992860a39c9..063557e037f2 100644 --- a/drivers/net/ethernet/3com/3c589_cs.c +++ b/drivers/net/ethernet/3com/3c589_cs.c @@ -1,23 +1,24 @@ -/*====================================================================== - - A PCMCIA ethernet driver for the 3com 3c589 card. - - Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net - - 3c589_cs.c 1.162 2001/10/13 00:08:50 - - The network driver code is based on Donald Becker's 3c589 code: - - Written 1994 by Donald Becker. - Copyright 1993 United States Government as represented by the - Director, National Security Agency. This software may be used and - distributed according to the terms of the GNU General Public License, - incorporated herein by reference. - Donald Becker may be reached at becker@scyld.com - - Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> - -======================================================================*/ +/* ====================================================================== + * + * A PCMCIA ethernet driver for the 3com 3c589 card. + * + * Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net + * + * 3c589_cs.c 1.162 2001/10/13 00:08:50 + * + * The network driver code is based on Donald Becker's 3c589 code: + * + * Written 1994 by Donald Becker. + * Copyright 1993 United States Government as represented by the + * Director, National Security Agency. This software may be used and + * distributed according to the terms of the GNU General Public License, + * incorporated herein by reference. + * Donald Becker may be reached at becker@scyld.com + * + * Updated for 2.5.x by Alan Cox <alan@lxorguk.ukuu.org.uk> + * + * ====================================================================== + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -41,18 +42,20 @@ #include <linux/ioport.h> #include <linux/bitops.h> #include <linux/jiffies.h> +#include <linux/uaccess.h> +#include <linux/io.h> #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ciscode.h> #include <pcmcia/ds.h> -#include <asm/uaccess.h> -#include <asm/io.h> /* To minimize the size of the driver source I only define operating - constants if they are used several times. You'll need the manual - if you want to understand driver details. */ + * constants if they are used several times. You'll need the manual + * if you want to understand driver details. + */ + /* Offsets from base I/O address. */ #define EL3_DATA 0x00 #define EL3_TIMER 0x0a @@ -65,7 +68,9 @@ #define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD) /* The top five bits written to EL3_CMD are a command, the lower - 11 bits are the parameter, if applicable. */ + * 11 bits are the parameter, if applicable. + */ + enum c509cmd { TotalReset = 0<<11, SelectWindow = 1<<11, @@ -190,138 +195,142 @@ static const struct net_device_ops el3_netdev_ops = { static int tc589_probe(struct pcmcia_device *link) { - struct el3_private *lp; - struct net_device *dev; + struct el3_private *lp; + struct net_device *dev; - dev_dbg(&link->dev, "3c589_attach()\n"); + dev_dbg(&link->dev, "3c589_attach()\n"); - /* Create new ethernet device */ - dev = alloc_etherdev(sizeof(struct el3_private)); - if (!dev) - return -ENOMEM; - lp = netdev_priv(dev); - link->priv = dev; - lp->p_dev = link; + /* Create new ethernet device */ + dev = alloc_etherdev(sizeof(struct el3_private)); + if (!dev) + return -ENOMEM; + lp = netdev_priv(dev); + link->priv = dev; + lp->p_dev = link; - spin_lock_init(&lp->lock); - link->resource[0]->end = 16; - link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; + spin_lock_init(&lp->lock); + link->resource[0]->end = 16; + link->resource[0]->flags |= IO_DATA_PATH_WIDTH_16; - link->config_flags |= CONF_ENABLE_IRQ; - link->config_index = 1; + link->config_flags |= CONF_ENABLE_IRQ; + link->config_index = 1; - dev->netdev_ops = &el3_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; + dev->netdev_ops = &el3_netdev_ops; + dev->watchdog_timeo = TX_TIMEOUT; - SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); + SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); - return tc589_config(link); + return tc589_config(link); } static void tc589_detach(struct pcmcia_device *link) { - struct net_device *dev = link->priv; + struct net_device *dev = link->priv; - dev_dbg(&link->dev, "3c589_detach\n"); + dev_dbg(&link->dev, "3c589_detach\n"); - unregister_netdev(dev); + unregister_netdev(dev); - tc589_release(link); + tc589_release(link); - free_netdev(dev); + free_netdev(dev); } /* tc589_detach */ static int tc589_config(struct pcmcia_device *link) { - struct net_device *dev = link->priv; - __be16 *phys_addr; - int ret, i, j, multi = 0, fifo; - unsigned int ioaddr; - static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - u8 *buf; - size_t len; - - dev_dbg(&link->dev, "3c589_config\n"); - - phys_addr = (__be16 *)dev->dev_addr; - /* Is this a 3c562? */ - if (link->manf_id != MANFID_3COM) - dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); - multi = (link->card_id == PRODID_3COM_3C562); - - link->io_lines = 16; - - /* For the 3c562, the base address must be xx00-xx7f */ - for (i = j = 0; j < 0x400; j += 0x10) { - if (multi && (j & 0x80)) continue; - link->resource[0]->start = j ^ 0x300; - i = pcmcia_request_io(link); - if (i == 0) - break; - } - if (i != 0) - goto failed; - - ret = pcmcia_request_irq(link, el3_interrupt); - if (ret) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - dev->irq = link->irq; - dev->base_addr = link->resource[0]->start; - ioaddr = dev->base_addr; - EL3WINDOW(0); - - /* The 3c589 has an extra EEPROM for configuration info, including - the hardware address. The 3c562 puts the address in the CIS. */ - len = pcmcia_get_tuple(link, 0x88, &buf); - if (buf && len >= 6) { - for (i = 0; i < 3; i++) - phys_addr[i] = htons(le16_to_cpu(buf[i*2])); - kfree(buf); - } else { - kfree(buf); /* 0 < len < 6 */ - for (i = 0; i < 3; i++) - phys_addr[i] = htons(read_eeprom(ioaddr, i)); - if (phys_addr[0] == htons(0x6060)) { - dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", - dev->base_addr, dev->base_addr+15); - goto failed; + struct net_device *dev = link->priv; + __be16 *phys_addr; + int ret, i, j, multi = 0, fifo; + unsigned int ioaddr; + static const char * const ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; + u8 *buf; + size_t len; + + dev_dbg(&link->dev, "3c589_config\n"); + + phys_addr = (__be16 *)dev->dev_addr; + /* Is this a 3c562? */ + if (link->manf_id != MANFID_3COM) + dev_info(&link->dev, "hmmm, is this really a 3Com card??\n"); + multi = (link->card_id == PRODID_3COM_3C562); + + link->io_lines = 16; + + /* For the 3c562, the base address must be xx00-xx7f */ + for (i = j = 0; j < 0x400; j += 0x10) { + if (multi && (j & 0x80)) + continue; + link->resource[0]->start = j ^ 0x300; + i = pcmcia_request_io(link); + if (i == 0) + break; } - } - - /* The address and resource configuration register aren't loaded from - the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */ - outw(0x3f00, ioaddr + 8); - fifo = inl(ioaddr); - - /* The if_port symbol can be set when the module is loaded */ - if ((if_port >= 0) && (if_port <= 3)) - dev->if_port = if_port; - else - dev_err(&link->dev, "invalid if_port requested\n"); - - SET_NETDEV_DEV(dev, &link->dev); - - if (register_netdev(dev) != 0) { - dev_err(&link->dev, "register_netdev() failed\n"); - goto failed; - } - - netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", - (multi ? "562" : "589"), dev->base_addr, dev->irq, - dev->dev_addr); - netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", - (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], - if_names[dev->if_port]); - return 0; + if (i != 0) + goto failed; + + ret = pcmcia_request_irq(link, el3_interrupt); + if (ret) + goto failed; + + ret = pcmcia_enable_device(link); + if (ret) + goto failed; + + dev->irq = link->irq; + dev->base_addr = link->resource[0]->start; + ioaddr = dev->base_addr; + EL3WINDOW(0); + + /* The 3c589 has an extra EEPROM for configuration info, including + * the hardware address. The 3c562 puts the address in the CIS. + */ + len = pcmcia_get_tuple(link, 0x88, &buf); + if (buf && len >= 6) { + for (i = 0; i < 3; i++) + phys_addr[i] = htons(le16_to_cpu(buf[i*2])); + kfree(buf); + } else { + kfree(buf); /* 0 < len < 6 */ + for (i = 0; i < 3; i++) + phys_addr[i] = htons(read_eeprom(ioaddr, i)); + if (phys_addr[0] == htons(0x6060)) { + dev_err(&link->dev, "IO port conflict at 0x%03lx-0x%03lx\n", + dev->base_addr, dev->base_addr+15); + goto failed; + } + } + + /* The address and resource configuration register aren't loaded from + * the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. + */ + + outw(0x3f00, ioaddr + 8); + fifo = inl(ioaddr); + + /* The if_port symbol can be set when the module is loaded */ + if ((if_port >= 0) && (if_port <= 3)) + dev->if_port = if_port; + else + dev_err(&link->dev, "invalid if_port requested\n"); + + SET_NETDEV_DEV(dev, &link->dev); + + if (register_netdev(dev) != 0) { + dev_err(&link->dev, "register_netdev() failed\n"); + goto failed; + } + + netdev_info(dev, "3Com 3c%s, io %#3lx, irq %d, hw_addr %pM\n", + (multi ? "562" : "589"), dev->base_addr, dev->irq, + dev->dev_addr); + netdev_info(dev, " %dK FIFO split %s Rx:Tx, %s xcvr\n", + (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], + if_names[dev->if_port]); + return 0; failed: - tc589_release(link); - return -ENODEV; + tc589_release(link); + return -ENODEV; } /* tc589_config */ static void tc589_release(struct pcmcia_device *link) @@ -353,113 +362,120 @@ static int tc589_resume(struct pcmcia_device *link) /*====================================================================*/ -/* - Use this for commands that may take time to finish -*/ +/* Use this for commands that may take time to finish */ + static void tc589_wait_for_completion(struct net_device *dev, int cmd) { - int i = 100; - outw(cmd, dev->base_addr + EL3_CMD); - while (--i > 0) - if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break; - if (i == 0) - netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); + int i = 100; + outw(cmd, dev->base_addr + EL3_CMD); + while (--i > 0) + if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) + break; + if (i == 0) + netdev_warn(dev, "command 0x%04x did not complete!\n", cmd); } -/* - Read a word from the EEPROM using the regular EEPROM access register. - Assume that we are in register window zero. -*/ +/* Read a word from the EEPROM using the regular EEPROM access register. + * Assume that we are in register window zero. + */ + static u16 read_eeprom(unsigned int ioaddr, int index) { - int i; - outw(EEPROM_READ + index, ioaddr + 10); - /* Reading the eeprom takes 162 us */ - for (i = 1620; i >= 0; i--) - if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) - break; - return inw(ioaddr + 12); + int i; + outw(EEPROM_READ + index, ioaddr + 10); + /* Reading the eeprom takes 162 us */ + for (i = 1620; i >= 0; i--) + if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0) + break; + return inw(ioaddr + 12); } -/* - Set transceiver type, perhaps to something other than what the user - specified in dev->if_port. -*/ +/* Set transceiver type, perhaps to something other than what the user + * specified in dev->if_port. + */ + static void tc589_set_xcvr(struct net_device *dev, int if_port) { - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - - EL3WINDOW(0); - switch (if_port) { - case 0: case 1: outw(0, ioaddr + 6); break; - case 2: outw(3<<14, ioaddr + 6); break; - case 3: outw(1<<14, ioaddr + 6); break; - } - /* On PCMCIA, this just turns on the LED */ - outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); - /* 10baseT interface, enable link beat and jabber check. */ - EL3WINDOW(4); - outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); - EL3WINDOW(1); - if (if_port == 2) - lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); - else - lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800); + struct el3_private *lp = netdev_priv(dev); + unsigned int ioaddr = dev->base_addr; + + EL3WINDOW(0); + switch (if_port) { + case 0: + case 1: + outw(0, ioaddr + 6); + break; + case 2: + outw(3<<14, ioaddr + 6); + break; + case 3: + outw(1<<14, ioaddr + 6); + break; + } + /* On PCMCIA, this just turns on the LED */ + outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD); + /* 10baseT interface, enable link beat and jabber check. */ + EL3WINDOW(4); + outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA); + EL3WINDOW(1); + if (if_port == 2) + lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000); + else + lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800); } static void dump_status(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - EL3WINDOW(1); - netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n", - inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), - inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); - EL3WINDOW(4); - netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", - inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), - inw(ioaddr+0x0a)); - EL3WINDOW(1); + unsigned int ioaddr = dev->base_addr; + EL3WINDOW(1); + netdev_info(dev, " irq status %04x, rx status %04x, tx status %02x tx free %04x\n", + inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS), + inb(ioaddr+TX_STATUS), inw(ioaddr+TX_FREE)); + EL3WINDOW(4); + netdev_info(dev, " diagnostics: fifo %04x net %04x ethernet %04x media %04x\n", + inw(ioaddr+0x04), inw(ioaddr+0x06), inw(ioaddr+0x08), + inw(ioaddr+0x0a)); + EL3WINDOW(1); } /* Reset and restore all of the 3c589 registers. */ static void tc589_reset(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - int i; - - EL3WINDOW(0); - outw(0x0001, ioaddr + 4); /* Activate board. */ - outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ - - /* Set the station address in window 2. */ - EL3WINDOW(2); - for (i = 0; i < 6; i++) - outb(dev->dev_addr[i], ioaddr + i); - - tc589_set_xcvr(dev, dev->if_port); - - /* Switch to the stats window, and clear all stats by reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - EL3WINDOW(6); - for (i = 0; i < 9; i++) - inb(ioaddr+i); - inw(ioaddr + 10); - inw(ioaddr + 12); - - /* Switch to register set 1 for normal use. */ - EL3WINDOW(1); - - set_rx_mode(dev); - outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ - outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ - outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ - /* Allow status bits to be seen. */ - outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); - /* Ack all pending events, and set active indicator mask. */ - outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, + unsigned int ioaddr = dev->base_addr; + int i; + + EL3WINDOW(0); + outw(0x0001, ioaddr + 4); /* Activate board. */ + outw(0x3f00, ioaddr + 8); /* Set the IRQ line. */ + + /* Set the station address in window 2. */ + EL3WINDOW(2); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + i); + + tc589_set_xcvr(dev, dev->if_port); + + /* Switch to the stats window, and clear all stats by reading. */ + outw(StatsDisable, ioaddr + EL3_CMD); + EL3WINDOW(6); + for (i = 0; i < 9; i++) + inb(ioaddr+i); + inw(ioaddr + 10); + inw(ioaddr + 12); + + /* Switch to register set 1 for normal use. */ + EL3WINDOW(1); + + set_rx_mode(dev); + outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */ + outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ + outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ + /* Allow status bits to be seen. */ + outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD); + /* Ack all pending events, and set active indicator mask. */ + outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); - outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull + outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | AdapterFailure, ioaddr + EL3_CMD); } @@ -478,381 +494,406 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int el3_config(struct net_device *dev, struct ifmap *map) { - if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { - if (map->port <= 3) { - dev->if_port = map->port; - netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); - tc589_set_xcvr(dev, dev->if_port); - } else - return -EINVAL; - } - return 0; + if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) { + if (map->port <= 3) { + dev->if_port = map->port; + netdev_info(dev, "switched to %s port\n", if_names[dev->if_port]); + tc589_set_xcvr(dev, dev->if_port); + } else { + return -EINVAL; + } + } + return 0; } static int el3_open(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; + struct el3_private *lp = netdev_priv(dev); + struct pcmcia_device *link = lp->p_dev; - if (!pcmcia_dev_present(link)) - return -ENODEV; + if (!pcmcia_dev_present(link)) + return -ENODEV; - link->open++; - netif_start_queue(dev); + link->open++; + netif_start_queue(dev); - tc589_reset(dev); - init_timer(&lp->media); - lp->media.function = media_check; - lp->media.data = (unsigned long) dev; - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); + tc589_reset(dev); + init_timer(&lp->media); + lp->media.function = media_check; + lp->media.data = (unsigned long) dev; + lp->media.expires = jiffies + HZ; + add_timer(&lp->media); - dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", + dev_dbg(&link->dev, "%s: opened, status %4.4x.\n", dev->name, inw(dev->base_addr + EL3_STATUS)); - return 0; + return 0; } static void el3_tx_timeout(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - - netdev_warn(dev, "Transmit timed out!\n"); - dump_status(dev); - dev->stats.tx_errors++; - dev->trans_start = jiffies; /* prevent tx timeout */ - /* Issue TX_RESET and TX_START commands. */ - tc589_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); - netif_wake_queue(dev); + unsigned int ioaddr = dev->base_addr; + + netdev_warn(dev, "Transmit timed out!\n"); + dump_status(dev); + dev->stats.tx_errors++; + dev->trans_start = jiffies; /* prevent tx timeout */ + /* Issue TX_RESET and TX_START commands. */ + tc589_wait_for_completion(dev, TxReset); + outw(TxEnable, ioaddr + EL3_CMD); + netif_wake_queue(dev); } static void pop_tx_status(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - int i; - - /* Clear the Tx status stack. */ - for (i = 32; i > 0; i--) { - u_char tx_status = inb(ioaddr + TX_STATUS); - if (!(tx_status & 0x84)) break; - /* reset transmitter on jabber error or underrun */ - if (tx_status & 0x30) - tc589_wait_for_completion(dev, TxReset); - if (tx_status & 0x38) { - netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); - outw(TxEnable, ioaddr + EL3_CMD); - dev->stats.tx_aborted_errors++; + unsigned int ioaddr = dev->base_addr; + int i; + + /* Clear the Tx status stack. */ + for (i = 32; i > 0; i--) { + u_char tx_status = inb(ioaddr + TX_STATUS); + if (!(tx_status & 0x84)) + break; + /* reset transmitter on jabber error or underrun */ + if (tx_status & 0x30) + tc589_wait_for_completion(dev, TxReset); + if (tx_status & 0x38) { + netdev_dbg(dev, "transmit error: status 0x%02x\n", tx_status); + outw(TxEnable, ioaddr + EL3_CMD); + dev->stats.tx_aborted_errors++; + } + outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ } - outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ - } } static netdev_tx_t el3_start_xmit(struct sk_buff *skb, struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - struct el3_private *priv = netdev_priv(dev); - unsigned long flags; + unsigned int ioaddr = dev->base_addr; + struct el3_private *priv = netdev_priv(dev); + unsigned long flags; - netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n", + netdev_dbg(dev, "el3_start_xmit(length = %ld) called, status %4.4x.\n", (long)skb->len, inw(ioaddr + EL3_STATUS)); - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&priv->lock, flags); - dev->stats.tx_bytes += skb->len; + dev->stats.tx_bytes += skb->len; - /* Put out the doubleword header... */ - outw(skb->len, ioaddr + TX_FIFO); - outw(0x00, ioaddr + TX_FIFO); - /* ... and the packet rounded to a doubleword. */ - outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + /* Put out the doubleword header... */ + outw(skb->len, ioaddr + TX_FIFO); + outw(0x00, ioaddr + TX_FIFO); + /* ... and the packet rounded to a doubleword. */ + outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); - if (inw(ioaddr + TX_FREE) <= 1536) { - netif_stop_queue(dev); - /* Interrupt us when the FIFO has room for max-sized packet. */ - outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); - } + if (inw(ioaddr + TX_FREE) <= 1536) { + netif_stop_queue(dev); + /* Interrupt us when the FIFO has room for max-sized packet. */ + outw(SetTxThreshold + 1536, ioaddr + EL3_CMD); + } - pop_tx_status(dev); - spin_unlock_irqrestore(&priv->lock, flags); - dev_kfree_skb(skb); + pop_tx_status(dev); + spin_unlock_irqrestore(&priv->lock, flags); + dev_kfree_skb(skb); - return NETDEV_TX_OK; + return NETDEV_TX_OK; } /* The EL3 interrupt handler. */ static irqreturn_t el3_interrupt(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr; - __u16 status; - int i = 0, handled = 1; + struct net_device *dev = (struct net_device *) dev_id; + struct el3_private *lp = netdev_priv(dev); + unsigned int ioaddr; + __u16 status; + int i = 0, handled = 1; - if (!netif_device_present(dev)) - return IRQ_NONE; + if (!netif_device_present(dev)) + return IRQ_NONE; - ioaddr = dev->base_addr; + ioaddr = dev->base_addr; - netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); + netdev_dbg(dev, "interrupt, status %4.4x.\n", inw(ioaddr + EL3_STATUS)); - spin_lock(&lp->lock); - while ((status = inw(ioaddr + EL3_STATUS)) & + spin_lock(&lp->lock); + while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete | StatsFull)) { - if ((status & 0xe000) != 0x2000) { - netdev_dbg(dev, "interrupt from dead card\n"); - handled = 0; - break; - } - if (status & RxComplete) - el3_rx(dev); - if (status & TxAvailable) { - netdev_dbg(dev, " TX room bit was handled.\n"); - /* There's room in the FIFO for a full-sized packet. */ - outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); - netif_wake_queue(dev); - } - if (status & TxComplete) - pop_tx_status(dev); - if (status & (AdapterFailure | RxEarly | StatsFull)) { - /* Handle all uncommon interrupts. */ - if (status & StatsFull) /* Empty statistics. */ - update_stats(dev); - if (status & RxEarly) { /* Rx early is unused. */ - el3_rx(dev); - outw(AckIntr | RxEarly, ioaddr + EL3_CMD); - } - if (status & AdapterFailure) { - u16 fifo_diag; - EL3WINDOW(4); - fifo_diag = inw(ioaddr + 4); - EL3WINDOW(1); - netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", + if ((status & 0xe000) != 0x2000) { + netdev_dbg(dev, "interrupt from dead card\n"); + handled = 0; + break; + } + if (status & RxComplete) + el3_rx(dev); + if (status & TxAvailable) { + netdev_dbg(dev, " TX room bit was handled.\n"); + /* There's room in the FIFO for a full-sized packet. */ + outw(AckIntr | TxAvailable, ioaddr + EL3_CMD); + netif_wake_queue(dev); + } + if (status & TxComplete) + pop_tx_status(dev); + if (status & (AdapterFailure | RxEarly | StatsFull)) { + /* Handle all uncommon interrupts. */ + if (status & StatsFull) /* Empty statistics. */ + update_stats(dev); + if (status & RxEarly) { + /* Rx early is unused. */ + el3_rx(dev); + outw(AckIntr | RxEarly, ioaddr + EL3_CMD); + } + if (status & AdapterFailure) { + u16 fifo_diag; + EL3WINDOW(4); + fifo_diag = inw(ioaddr + 4); + EL3WINDOW(1); + netdev_warn(dev, "adapter failure, FIFO diagnostic register %04x.\n", fifo_diag); - if (fifo_diag & 0x0400) { - /* Tx overrun */ - tc589_wait_for_completion(dev, TxReset); - outw(TxEnable, ioaddr + EL3_CMD); + if (fifo_diag & 0x0400) { + /* Tx overrun */ + tc589_wait_for_completion(dev, TxReset); + outw(TxEnable, ioaddr + EL3_CMD); + } + if (fifo_diag & 0x2000) { + /* Rx underrun */ + tc589_wait_for_completion(dev, RxReset); + set_rx_mode(dev); + outw(RxEnable, ioaddr + EL3_CMD); + } + outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); + } } - if (fifo_diag & 0x2000) { - /* Rx underrun */ - tc589_wait_for_completion(dev, RxReset); - set_rx_mode(dev); - outw(RxEnable, ioaddr + EL3_CMD); + if (++i > 10) { + netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", + status); + /* Clear all interrupts */ + outw(AckIntr | 0xFF, ioaddr + EL3_CMD); + break; } - outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD); - } + /* Acknowledge the IRQ. */ + outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); } - if (++i > 10) { - netdev_err(dev, "infinite loop in interrupt, status %4.4x.\n", - status); - /* Clear all interrupts */ - outw(AckIntr | 0xFF, ioaddr + EL3_CMD); - break; - } - /* Acknowledge the IRQ. */ - outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); - } - lp->last_irq = jiffies; - spin_unlock(&lp->lock); - netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", - inw(ioaddr + EL3_STATUS)); - return IRQ_RETVAL(handled); + lp->last_irq = jiffies; + spin_unlock(&lp->lock); + netdev_dbg(dev, "exiting interrupt, status %4.4x.\n", + inw(ioaddr + EL3_STATUS)); + return IRQ_RETVAL(handled); } static void media_check(unsigned long arg) { - struct net_device *dev = (struct net_device *)(arg); - struct el3_private *lp = netdev_priv(dev); - unsigned int ioaddr = dev->base_addr; - u16 media, errs; - unsigned long flags; + struct net_device *dev = (struct net_device *)(arg); + struct el3_private *lp = netdev_priv(dev); + unsigned int ioaddr = dev->base_addr; + u16 media, errs; + unsigned long flags; - if (!netif_device_present(dev)) goto reschedule; + if (!netif_device_present(dev)) + goto reschedule; - /* Check for pending interrupt with expired latency timer: with - this, we can limp along even if the interrupt is blocked */ - if ((inw(ioaddr + EL3_STATUS) & IntLatch) && + /* Check for pending interrupt with expired latency timer: with + * this, we can limp along even if the interrupt is blocked + */ + if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + EL3_TIMER) == 0xff)) { - if (!lp->fast_poll) - netdev_warn(dev, "interrupt(s) dropped!\n"); - - local_irq_save(flags); - el3_interrupt(dev->irq, dev); - local_irq_restore(flags); - - lp->fast_poll = HZ; - } - if (lp->fast_poll) { - lp->fast_poll--; - lp->media.expires = jiffies + HZ/100; - add_timer(&lp->media); - return; - } - - /* lp->lock guards the EL3 window. Window should always be 1 except - when the lock is held */ - spin_lock_irqsave(&lp->lock, flags); - EL3WINDOW(4); - media = inw(ioaddr+WN4_MEDIA) & 0xc810; - - /* Ignore collisions unless we've had no irq's recently */ - if (time_before(jiffies, lp->last_irq + HZ)) { - media &= ~0x0010; - } else { - /* Try harder to detect carrier errors */ - EL3WINDOW(6); - outw(StatsDisable, ioaddr + EL3_CMD); - errs = inb(ioaddr + 0); - outw(StatsEnable, ioaddr + EL3_CMD); - dev->stats.tx_carrier_errors += errs; - if (errs || (lp->media_status & 0x0010)) media |= 0x0010; - } + if (!lp->fast_poll) + netdev_warn(dev, "interrupt(s) dropped!\n"); + + local_irq_save(flags); + el3_interrupt(dev->irq, dev); + local_irq_restore(flags); + + lp->fast_poll = HZ; + } + if (lp->fast_poll) { + lp->fast_poll--; + lp->media.expires = jiffies + HZ/100; + add_timer(&lp->media); + return; + } + + /* lp->lock guards the EL3 window. Window should always be 1 except + * when the lock is held + */ + + spin_lock_irqsave(&lp->lock, flags); + EL3WINDOW(4); + media = inw(ioaddr+WN4_MEDIA) & 0xc810; + + /* Ignore collisions unless we've had no irq's recently */ + if (time_before(jiffies, lp->last_irq + HZ)) { + media &= ~0x0010; + } else { + /* Try harder to detect carrier errors */ + EL3WINDOW(6); + outw(StatsDisable, ioaddr + EL3_CMD); + errs = inb(ioaddr + 0); + outw(StatsEnable, ioaddr + EL3_CMD); + dev->stats.tx_carrier_errors += errs; + if (errs || (lp->media_status & 0x0010)) + media |= 0x0010; + } - if (media != lp->media_status) { - if ((media & lp->media_status & 0x8000) && - ((lp->media_status ^ media) & 0x0800)) + if (media != lp->media_status) { + if ((media & lp->media_status & 0x8000) && + ((lp->media_status ^ media) & 0x0800)) netdev_info(dev, "%s link beat\n", - (lp->media_status & 0x0800 ? "lost" : "found")); - else if ((media & lp->media_status & 0x4000) && + (lp->media_status & 0x0800 ? "lost" : "found")); + else if ((media & lp->media_status & 0x4000) && ((lp->media_status ^ media) & 0x0010)) netdev_info(dev, "coax cable %s\n", - (lp->media_status & 0x0010 ? "ok" : "problem")); - if (dev->if_port == 0) { - if (media & 0x8000) { - if (media & 0x0800) - netdev_info(dev, "flipped to 10baseT\n"); - else + (lp->media_status & 0x0010 ? "ok" : "problem")); + if (dev->if_port == 0) { + if (media & 0x8000) { + if (media & 0x0800) + netdev_info(dev, "flipped to 10baseT\n"); + else tc589_set_xcvr(dev, 2); - } else if (media & 0x4000) { - if (media & 0x0010) - tc589_set_xcvr(dev, 1); - else - netdev_info(dev, "flipped to 10base2\n"); - } + } else if (media & 0x4000) { + if (media & 0x0010) + tc589_set_xcvr(dev, 1); + else + netdev_info(dev, "flipped to 10base2\n"); + } + } + lp->media_status = media; } - lp->media_status = media; - } - EL3WINDOW(1); - spin_unlock_irqrestore(&lp->lock, flags); + EL3WINDOW(1); + spin_unlock_irqrestore(&lp->lock, flags); reschedule: - lp->media.expires = jiffies + HZ; - add_timer(&lp->media); + lp->media.expires = jiffies + HZ; + add_timer(&lp->media); } static struct net_device_stats *el3_get_stats(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); - unsigned long flags; - struct pcmcia_device *link = lp->p_dev; + struct el3_private *lp = netdev_priv(dev); + unsigned long flags; + struct pcmcia_device *link = lp->p_dev; - if (pcmcia_dev_present(link)) { - spin_lock_irqsave(&lp->lock, flags); - update_stats(dev); - spin_unlock_irqrestore(&lp->lock, flags); - } - return &dev->stats; + if (pcmcia_dev_present(link)) { + spin_lock_irqsave(&lp->lock, flags); + update_stats(dev); + spin_unlock_irqrestore(&lp->lock, flags); + } + return &dev->stats; } -/* - Update statistics. We change to register window 6, so this should be run - single-threaded if the device is active. This is expected to be a rare - operation, and it's simpler for the rest of the driver to assume that - window 1 is always valid rather than use a special window-state variable. - - Caller must hold the lock for this +/* Update statistics. We change to register window 6, so this should be run +* single-threaded if the device is active. This is expected to be a rare +* operation, and it's simpler for the rest of the driver to assume that +* window 1 is always valid rather than use a special window-state variable. +* +* Caller must hold the lock for this */ + static void update_stats(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - - netdev_dbg(dev, "updating the statistics.\n"); - /* Turn off statistics updates while reading. */ - outw(StatsDisable, ioaddr + EL3_CMD); - /* Switch to the stats window, and read everything. */ - EL3WINDOW(6); - dev->stats.tx_carrier_errors += inb(ioaddr + 0); - dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); - /* Multiple collisions. */ inb(ioaddr + 2); - dev->stats.collisions += inb(ioaddr + 3); - dev->stats.tx_window_errors += inb(ioaddr + 4); - dev->stats.rx_fifo_errors += inb(ioaddr + 5); - dev->stats.tx_packets += inb(ioaddr + 6); - /* Rx packets */ inb(ioaddr + 7); - /* Tx deferrals */ inb(ioaddr + 8); - /* Rx octets */ inw(ioaddr + 10); - /* Tx octets */ inw(ioaddr + 12); - - /* Back to window 1, and turn statistics back on. */ - EL3WINDOW(1); - outw(StatsEnable, ioaddr + EL3_CMD); + unsigned int ioaddr = dev->base_addr; + + netdev_dbg(dev, "updating the statistics.\n"); + /* Turn off statistics updates while reading. */ + outw(StatsDisable, ioaddr + EL3_CMD); + /* Switch to the stats window, and read everything. */ + EL3WINDOW(6); + dev->stats.tx_carrier_errors += inb(ioaddr + 0); + dev->stats.tx_heartbeat_errors += inb(ioaddr + 1); + /* Multiple collisions. */ + inb(ioaddr + 2); + dev->stats.collisions += inb(ioaddr + 3); + dev->stats.tx_window_errors += inb(ioaddr + 4); + dev->stats.rx_fifo_errors += inb(ioaddr + 5); + dev->stats.tx_packets += inb(ioaddr + 6); + /* Rx packets */ + inb(ioaddr + 7); + /* Tx deferrals */ + inb(ioaddr + 8); + /* Rx octets */ + inw(ioaddr + 10); + /* Tx octets */ + inw(ioaddr + 12); + + /* Back to window 1, and turn statistics back on. */ + EL3WINDOW(1); + outw(StatsEnable, ioaddr + EL3_CMD); } static int el3_rx(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - int worklimit = 32; - short rx_status; + unsigned int ioaddr = dev->base_addr; + int worklimit = 32; + short rx_status; - netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", + netdev_dbg(dev, "in rx_packet(), status %4.4x, rx_status %4.4x.\n", inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); - while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && + while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) && worklimit > 0) { - worklimit--; - if (rx_status & 0x4000) { /* Error, update stats. */ - short error = rx_status & 0x3800; - dev->stats.rx_errors++; - switch (error) { - case 0x0000: dev->stats.rx_over_errors++; break; - case 0x0800: dev->stats.rx_length_errors++; break; - case 0x1000: dev->stats.rx_frame_errors++; break; - case 0x1800: dev->stats.rx_length_errors++; break; - case 0x2000: dev->stats.rx_frame_errors++; break; - case 0x2800: dev->stats.rx_crc_errors++; break; - } - } else { - short pkt_len = rx_status & 0x7ff; - struct sk_buff *skb; - - skb = netdev_alloc_skb(dev, pkt_len + 5); - - netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", + worklimit--; + if (rx_status & 0x4000) { /* Error, update stats. */ + short error = rx_status & 0x3800; + dev->stats.rx_errors++; + switch (error) { + case 0x0000: + dev->stats.rx_over_errors++; + break; + case 0x0800: + dev->stats.rx_length_errors++; + break; + case 0x1000: + dev->stats.rx_frame_errors++; + break; + case 0x1800: + dev->stats.rx_length_errors++; + break; + case 0x2000: + dev->stats.rx_frame_errors++; + break; + case 0x2800: + dev->stats.rx_crc_errors++; + break; + } + } else { + short pkt_len = rx_status & 0x7ff; + struct sk_buff *skb; + + skb = netdev_alloc_skb(dev, pkt_len + 5); + + netdev_dbg(dev, " Receiving packet size %d status %4.4x.\n", pkt_len, rx_status); - if (skb != NULL) { - skb_reserve(skb, 2); - insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), + if (skb != NULL) { + skb_reserve(skb, 2); + insl(ioaddr+RX_FIFO, skb_put(skb, pkt_len), (pkt_len+3)>>2); - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += pkt_len; - } else { - netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + dev->stats.rx_packets++; + dev->stats.rx_bytes += pkt_len; + } else { + netdev_dbg(dev, "couldn't allocate a sk_buff of size %d.\n", pkt_len); - dev->stats.rx_dropped++; - } + dev->stats.rx_dropped++; + } + } + /* Pop the top of the Rx FIFO */ + tc589_wait_for_completion(dev, RxDiscard); } - /* Pop the top of the Rx FIFO */ - tc589_wait_for_completion(dev, RxDiscard); - } - if (worklimit == 0) - netdev_warn(dev, "too much work in el3_rx!\n"); - return 0; + if (worklimit == 0) + netdev_warn(dev, "too much work in el3_rx!\n"); + return 0; } static void set_rx_mode(struct net_device *dev) { - unsigned int ioaddr = dev->base_addr; - u16 opts = SetRxFilter | RxStation | RxBroadcast; - - if (dev->flags & IFF_PROMISC) - opts |= RxMulticast | RxProm; - else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) - opts |= RxMulticast; - outw(opts, ioaddr + EL3_CMD); + unsigned int ioaddr = dev->base_addr; + u16 opts = SetRxFilter | RxStation | RxBroadcast; + + if (dev->flags & IFF_PROMISC) + opts |= RxMulticast | RxProm; + else if (!netdev_mc_empty(dev) || (dev->flags & IFF_ALLMULTI)) + opts |= RxMulticast; + outw(opts, ioaddr + EL3_CMD); } static void set_multicast_list(struct net_device *dev) @@ -867,44 +908,44 @@ static void set_multicast_list(struct net_device *dev) static int el3_close(struct net_device *dev) { - struct el3_private *lp = netdev_priv(dev); - struct pcmcia_device *link = lp->p_dev; - unsigned int ioaddr = dev->base_addr; - - dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); + struct el3_private *lp = netdev_priv(dev); + struct pcmcia_device *link = lp->p_dev; + unsigned int ioaddr = dev->base_addr; + + dev_dbg(&link->dev, "%s: shutting down ethercard.\n", dev->name); + + if (pcmcia_dev_present(link)) { + /* Turn off statistics ASAP. We update dev->stats below. */ + outw(StatsDisable, ioaddr + EL3_CMD); + + /* Disable the receiver and transmitter. */ + outw(RxDisable, ioaddr + EL3_CMD); + outw(TxDisable, ioaddr + EL3_CMD); + + if (dev->if_port == 2) + /* Turn off thinnet power. Green! */ + outw(StopCoax, ioaddr + EL3_CMD); + else if (dev->if_port == 1) { + /* Disable link beat and jabber */ + EL3WINDOW(4); + outw(0, ioaddr + WN4_MEDIA); + } - if (pcmcia_dev_present(link)) { - /* Turn off statistics ASAP. We update dev->stats below. */ - outw(StatsDisable, ioaddr + EL3_CMD); + /* Switching back to window 0 disables the IRQ. */ + EL3WINDOW(0); + /* But we explicitly zero the IRQ line select anyway. */ + outw(0x0f00, ioaddr + WN0_IRQ); - /* Disable the receiver and transmitter. */ - outw(RxDisable, ioaddr + EL3_CMD); - outw(TxDisable, ioaddr + EL3_CMD); - - if (dev->if_port == 2) - /* Turn off thinnet power. Green! */ - outw(StopCoax, ioaddr + EL3_CMD); - else if (dev->if_port == 1) { - /* Disable link beat and jabber */ - EL3WINDOW(4); - outw(0, ioaddr + WN4_MEDIA); + /* Check if the card still exists */ + if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) + update_stats(dev); } - /* Switching back to window 0 disables the IRQ. */ - EL3WINDOW(0); - /* But we explicitly zero the IRQ line select anyway. */ - outw(0x0f00, ioaddr + WN0_IRQ); - - /* Check if the card still exists */ - if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000) - update_stats(dev); - } - - link->open--; - netif_stop_queue(dev); - del_timer_sync(&lp->media); + link->open--; + netif_stop_queue(dev); + del_timer_sync(&lp->media); - return 0; + return 0; } static const struct pcmcia_device_id tc589_ids[] = { diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 0f4241c6e97e..238ccea965c8 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -3294,7 +3294,6 @@ static int __init vortex_init(void) static void __exit vortex_eisa_cleanup(void) { - struct vortex_private *vp; void __iomem *ioaddr; #ifdef CONFIG_EISA @@ -3303,7 +3302,6 @@ static void __exit vortex_eisa_cleanup(void) #endif if (compaq_net_device) { - vp = netdev_priv(compaq_net_device); ioaddr = ioport_map(compaq_net_device->base_addr, VORTEX_TOTAL_SIZE); diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index 0cc21437478c..511f6eecd58b 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -929,6 +929,9 @@ static int emac_resume(struct platform_device *dev) } static const struct of_device_id emac_of_match[] = { + {.compatible = "allwinner,sun4i-a10-emac",}, + + /* Deprecated */ {.compatible = "allwinner,sun4i-emac",}, {}, }; diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c index 9339cccfe05a..2ae00ed83afa 100644 --- a/drivers/net/ethernet/amd/pcnet32.c +++ b/drivers/net/ethernet/amd/pcnet32.c @@ -549,35 +549,35 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, struct pcnet32_rx_head *new_rx_ring; struct sk_buff **new_skb_list; int new, overlap; + unsigned int entries = 1 << size; new_rx_ring = pci_alloc_consistent(lp->pci_dev, sizeof(struct pcnet32_rx_head) * - (1 << size), + entries, &new_ring_dma_addr); if (new_rx_ring == NULL) { netif_err(lp, drv, dev, "Consistent memory allocation failed\n"); return; } - memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * (1 << size)); + memset(new_rx_ring, 0, sizeof(struct pcnet32_rx_head) * entries); - new_dma_addr_list = kcalloc(1 << size, sizeof(dma_addr_t), GFP_ATOMIC); + new_dma_addr_list = kcalloc(entries, sizeof(dma_addr_t), GFP_ATOMIC); if (!new_dma_addr_list) goto free_new_rx_ring; - new_skb_list = kcalloc(1 << size, sizeof(struct sk_buff *), - GFP_ATOMIC); + new_skb_list = kcalloc(entries, sizeof(struct sk_buff *), GFP_ATOMIC); if (!new_skb_list) goto free_new_lists; /* first copy the current receive buffers */ - overlap = min(size, lp->rx_ring_size); + overlap = min(entries, lp->rx_ring_size); for (new = 0; new < overlap; new++) { new_rx_ring[new] = lp->rx_ring[new]; new_dma_addr_list[new] = lp->rx_dma_addr[new]; new_skb_list[new] = lp->rx_skbuff[new]; } /* now allocate any new buffers needed */ - for (; new < size; new++) { + for (; new < entries; new++) { struct sk_buff *rx_skbuff; new_skb_list[new] = netdev_alloc_skb(dev, PKT_BUF_SKB); rx_skbuff = new_skb_list[new]; @@ -592,6 +592,13 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, new_dma_addr_list[new] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(lp->pci_dev, + new_dma_addr_list[new])) { + netif_err(lp, drv, dev, "%s dma mapping failed\n", + __func__); + dev_kfree_skb(new_skb_list[new]); + goto free_all_new; + } new_rx_ring[new].base = cpu_to_le32(new_dma_addr_list[new]); new_rx_ring[new].buf_length = cpu_to_le16(NEG_BUF_SIZE); new_rx_ring[new].status = cpu_to_le16(0x8000); @@ -599,8 +606,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, /* and free any unneeded buffers */ for (; new < lp->rx_ring_size; new++) { if (lp->rx_skbuff[new]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[new], - PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + lp->rx_dma_addr[new])) + pci_unmap_single(lp->pci_dev, + lp->rx_dma_addr[new], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb(lp->rx_skbuff[new]); } } @@ -612,7 +623,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, lp->rx_ring_size, lp->rx_ring, lp->rx_ring_dma_addr); - lp->rx_ring_size = (1 << size); + lp->rx_ring_size = entries; lp->rx_mod_mask = lp->rx_ring_size - 1; lp->rx_len_bits = (size << 4); lp->rx_ring = new_rx_ring; @@ -624,8 +635,12 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, free_all_new: while (--new >= lp->rx_ring_size) { if (new_skb_list[new]) { - pci_unmap_single(lp->pci_dev, new_dma_addr_list[new], - PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + new_dma_addr_list[new])) + pci_unmap_single(lp->pci_dev, + new_dma_addr_list[new], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb(new_skb_list[new]); } } @@ -634,8 +649,7 @@ free_new_lists: kfree(new_dma_addr_list); free_new_rx_ring: pci_free_consistent(lp->pci_dev, - sizeof(struct pcnet32_rx_head) * - (1 << size), + sizeof(struct pcnet32_rx_head) * entries, new_rx_ring, new_ring_dma_addr); } @@ -650,8 +664,12 @@ static void pcnet32_purge_rx_ring(struct net_device *dev) lp->rx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->rx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->rx_dma_addr[i], - PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + lp->rx_dma_addr[i])) + pci_unmap_single(lp->pci_dev, + lp->rx_dma_addr[i], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); dev_kfree_skb_any(lp->rx_skbuff[i]); } lp->rx_skbuff[i] = NULL; @@ -930,6 +948,12 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) lp->tx_dma_addr[x] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[x])) { + netif_printk(lp, hw, KERN_DEBUG, dev, + "DMA mapping error at line: %d!\n", + __LINE__); + goto clean_up; + } lp->tx_ring[x].base = cpu_to_le32(lp->tx_dma_addr[x]); wmb(); /* Make sure owner changes after all others are visible */ lp->tx_ring[x].status = cpu_to_le16(status); @@ -1142,24 +1166,36 @@ static void pcnet32_rx_entry(struct net_device *dev, if (pkt_len > rx_copybreak) { struct sk_buff *newskb; + dma_addr_t new_dma_addr; newskb = netdev_alloc_skb(dev, PKT_BUF_SKB); + /* + * map the new buffer, if mapping fails, drop the packet and + * reuse the old buffer + */ if (newskb) { skb_reserve(newskb, NET_IP_ALIGN); - skb = lp->rx_skbuff[entry]; - pci_unmap_single(lp->pci_dev, - lp->rx_dma_addr[entry], - PKT_BUF_SIZE, - PCI_DMA_FROMDEVICE); - skb_put(skb, pkt_len); - lp->rx_skbuff[entry] = newskb; - lp->rx_dma_addr[entry] = - pci_map_single(lp->pci_dev, - newskb->data, - PKT_BUF_SIZE, - PCI_DMA_FROMDEVICE); - rxp->base = cpu_to_le32(lp->rx_dma_addr[entry]); - rx_in_place = 1; + new_dma_addr = pci_map_single(lp->pci_dev, + newskb->data, + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(lp->pci_dev, new_dma_addr)) { + netif_err(lp, rx_err, dev, + "DMA mapping error.\n"); + dev_kfree_skb(newskb); + skb = NULL; + } else { + skb = lp->rx_skbuff[entry]; + pci_unmap_single(lp->pci_dev, + lp->rx_dma_addr[entry], + PKT_BUF_SIZE, + PCI_DMA_FROMDEVICE); + skb_put(skb, pkt_len); + lp->rx_skbuff[entry] = newskb; + lp->rx_dma_addr[entry] = new_dma_addr; + rxp->base = cpu_to_le32(new_dma_addr); + rx_in_place = 1; + } } else skb = NULL; } else @@ -2229,9 +2265,12 @@ static void pcnet32_purge_tx_ring(struct net_device *dev) lp->tx_ring[i].status = 0; /* CPU owns buffer */ wmb(); /* Make sure adapter sees owner change */ if (lp->tx_skbuff[i]) { - pci_unmap_single(lp->pci_dev, lp->tx_dma_addr[i], - lp->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); + if (!pci_dma_mapping_error(lp->pci_dev, + lp->tx_dma_addr[i])) + pci_unmap_single(lp->pci_dev, + lp->tx_dma_addr[i], + lp->tx_skbuff[i]->len, + PCI_DMA_TODEVICE); dev_kfree_skb_any(lp->tx_skbuff[i]); } lp->tx_skbuff[i] = NULL; @@ -2264,10 +2303,19 @@ static int pcnet32_init_ring(struct net_device *dev) } rmb(); - if (lp->rx_dma_addr[i] == 0) + if (lp->rx_dma_addr[i] == 0) { lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data, PKT_BUF_SIZE, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(lp->pci_dev, + lp->rx_dma_addr[i])) { + /* there is not much we can do at this point */ + netif_err(lp, drv, dev, + "%s pci dma mapping error\n", + __func__); + return -1; + } + } lp->rx_ring[i].base = cpu_to_le32(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = cpu_to_le16(NEG_BUF_SIZE); wmb(); /* Make sure owner changes after all others are visible */ @@ -2397,9 +2445,14 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb, lp->tx_ring[entry].misc = 0x00000000; - lp->tx_skbuff[entry] = skb; lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(lp->pci_dev, lp->tx_dma_addr[entry])) { + dev_kfree_skb(skb); + dev->stats.tx_dropped++; + goto drop_packet; + } + lp->tx_skbuff[entry] = skb; lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]); wmb(); /* Make sure owner changes after all others are visible */ lp->tx_ring[entry].status = cpu_to_le16(status); @@ -2414,6 +2467,7 @@ static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb, lp->tx_full = 1; netif_stop_queue(dev); } +drop_packet: spin_unlock_irqrestore(&lp->lock, flags); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/atheros/alx/main.c b/drivers/net/ethernet/atheros/alx/main.c index e92ffd6e1c15..2e45f6ec1bf0 100644 --- a/drivers/net/ethernet/atheros/alx/main.c +++ b/drivers/net/ethernet/atheros/alx/main.c @@ -1292,6 +1292,7 @@ static int alx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) alx = netdev_priv(netdev); spin_lock_init(&alx->hw.mdio_lock); spin_lock_init(&alx->irq_lock); + spin_lock_init(&alx->stats_lock); alx->dev = netdev; alx->hw.pdev = pdev; alx->msg_enable = NETIF_MSG_LINK | NETIF_MSG_HW | NETIF_MSG_IFUP | diff --git a/drivers/net/ethernet/broadcom/Kconfig b/drivers/net/ethernet/broadcom/Kconfig index 3f97d9fd0a71..85dbddd03722 100644 --- a/drivers/net/ethernet/broadcom/Kconfig +++ b/drivers/net/ethernet/broadcom/Kconfig @@ -60,6 +60,17 @@ config BCM63XX_ENET This driver supports the ethernet MACs in the Broadcom 63xx MIPS chipset family (BCM63XX). +config BCMGENET + tristate "Broadcom GENET internal MAC support" + depends on OF + select MII + select PHYLIB + select FIXED_PHY if BCMGENET=y + select BCM7XXX_PHY + help + This driver supports the built-in Ethernet MACs found in the + Broadcom BCM7xxx Set Top Box family chipset. + config BNX2 tristate "Broadcom NetXtremeII support" depends on PCI diff --git a/drivers/net/ethernet/broadcom/Makefile b/drivers/net/ethernet/broadcom/Makefile index 68efa1a3fb88..fd639a0d4c7d 100644 --- a/drivers/net/ethernet/broadcom/Makefile +++ b/drivers/net/ethernet/broadcom/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_BCM63XX_ENET) += bcm63xx_enet.o +obj-$(CONFIG_BCMGENET) += genet/ obj-$(CONFIG_BNX2) += bnx2.o obj-$(CONFIG_CNIC) += cnic.o obj-$(CONFIG_BNX2X) += bnx2x/ diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 1f7b5aa114fa..8a7bf7dad898 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -1484,6 +1484,10 @@ static int b44_open(struct net_device *dev) add_timer(&bp->timer); b44_enable_ints(bp); + + if (bp->flags & B44_FLAG_EXTERNAL_PHY) + phy_start(bp->phydev); + netif_start_queue(dev); out: return err; @@ -1646,6 +1650,9 @@ static int b44_close(struct net_device *dev) netif_stop_queue(dev); + if (bp->flags & B44_FLAG_EXTERNAL_PHY) + phy_stop(bp->phydev); + napi_disable(&bp->napi); del_timer_sync(&bp->timer); @@ -2222,7 +2229,12 @@ static void b44_adjust_link(struct net_device *dev) } if (status_changed) { - b44_check_phy(bp); + u32 val = br32(bp, B44_TX_CTRL); + if (bp->flags & B44_FLAG_FULL_DUPLEX) + val |= TX_CTRL_DUPLEX; + else + val &= ~TX_CTRL_DUPLEX; + bw32(bp, B44_TX_CTRL, val); phy_print_status(phydev); } } diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c index 9d2dedadf2df..c251ca3056de 100644 --- a/drivers/net/ethernet/broadcom/bnx2.c +++ b/drivers/net/ethernet/broadcom/bnx2.c @@ -85,7 +85,7 @@ MODULE_FIRMWARE(FW_RV2P_FILE_09_Ax); static int disable_msi = 0; -module_param(disable_msi, int, 0); +module_param(disable_msi, int, S_IRUGO); MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)"); typedef enum { @@ -2885,7 +2885,7 @@ bnx2_tx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) sw_cons = BNX2_NEXT_TX_BD(sw_cons); tx_bytes += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_pkt++; if (tx_pkt == budget) break; @@ -6206,7 +6206,7 @@ bnx2_free_irq(struct bnx2 *bp) static void bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) { - int i, total_vecs, rc; + int i, total_vecs; struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; struct net_device *dev = bp->dev; const int len = sizeof(bp->irq_tbl[0].name); @@ -6229,16 +6229,9 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) #ifdef BCM_CNIC total_vecs++; #endif - rc = -ENOSPC; - while (total_vecs >= BNX2_MIN_MSIX_VEC) { - rc = pci_enable_msix(bp->pdev, msix_ent, total_vecs); - if (rc <= 0) - break; - if (rc > 0) - total_vecs = rc; - } - - if (rc != 0) + total_vecs = pci_enable_msix_range(bp->pdev, msix_ent, + BNX2_MIN_MSIX_VEC, total_vecs); + if (total_vecs < 0) return; msix_vecs = total_vecs; @@ -6611,7 +6604,7 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev) mapping = dma_map_single(&bp->pdev->dev, skb->data, len, PCI_DMA_TODEVICE); if (dma_mapping_error(&bp->pdev->dev, mapping)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -6704,7 +6697,7 @@ dma_error: PCI_DMA_TODEVICE); } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 391f29ef6d2e..722160940ab9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -26,8 +26,8 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.78.17-0" -#define DRV_MODULE_RELDATE "2013/04/11" +#define DRV_MODULE_VERSION "1.78.19-0" +#define DRV_MODULE_RELDATE "2014/02/10" #define BNX2X_BC_VER 0x040200 #if defined(CONFIG_DCB) @@ -75,13 +75,22 @@ enum bnx2x_int_mode { #define BNX2X_MSG_DCB 0x8000000 /* regular debug print */ +#define DP_INNER(fmt, ...) \ + pr_notice("[%s:%d(%s)]" fmt, \ + __func__, __LINE__, \ + bp->dev ? (bp->dev->name) : "?", \ + ##__VA_ARGS__); + #define DP(__mask, fmt, ...) \ do { \ if (unlikely(bp->msg_enable & (__mask))) \ - pr_notice("[%s:%d(%s)]" fmt, \ - __func__, __LINE__, \ - bp->dev ? (bp->dev->name) : "?", \ - ##__VA_ARGS__); \ + DP_INNER(fmt, ##__VA_ARGS__); \ +} while (0) + +#define DP_AND(__mask, fmt, ...) \ +do { \ + if (unlikely((bp->msg_enable & (__mask)) == __mask)) \ + DP_INNER(fmt, ##__VA_ARGS__); \ } while (0) #define DP_CONT(__mask, fmt, ...) \ @@ -1261,6 +1270,7 @@ struct bnx2x_slowpath { union { struct client_init_ramrod_data init_data; struct client_update_ramrod_data update_data; + struct tpa_update_ramrod_data tpa_data; } q_rdata; union { @@ -1392,7 +1402,7 @@ struct bnx2x_fw_stats_data { }; /* Public slow path states */ -enum { +enum sp_rtnl_flag { BNX2X_SP_RTNL_SETUP_TC, BNX2X_SP_RTNL_TX_TIMEOUT, BNX2X_SP_RTNL_FAN_FAILURE, diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index 9d7419e0390b..117b5c7f8ac9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -61,10 +61,14 @@ static void bnx2x_add_all_napi(struct bnx2x *bp) 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)); + int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues(); + + /* Reduce memory usage in kdump environment by using only one queue */ + if (reset_devices) + nq = 1; + + nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp)); + return nq; } /** @@ -1638,36 +1642,16 @@ int bnx2x_enable_msix(struct bnx2x *bp) DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n", msix_vec); - rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], msix_vec); - + rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], + BNX2X_MIN_MSIX_VEC_CNT(bp), msix_vec); /* * reconfigure number of tx/rx queues according to available * MSI-X vectors */ - if (rc >= BNX2X_MIN_MSIX_VEC_CNT(bp)) { - /* how less vectors we will have? */ - int diff = msix_vec - rc; - - BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc); - - rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], rc); - - if (rc) { - BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc); - goto no_msix; - } - /* - * decrease number of queues by number of unallocated entries - */ - bp->num_ethernet_queues -= diff; - bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; - - BNX2X_DEV_INFO("New queue configuration set: %d\n", - bp->num_queues); - } else if (rc > 0) { + if (rc == -ENOSPC) { /* Get by with single vector */ - rc = pci_enable_msix(bp->pdev, &bp->msix_table[0], 1); - if (rc) { + rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], 1, 1); + if (rc < 0) { BNX2X_DEV_INFO("Single MSI-X is not attainable rc %d\n", rc); goto no_msix; @@ -1680,8 +1664,22 @@ int bnx2x_enable_msix(struct bnx2x *bp) bp->num_ethernet_queues = 1; bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; } else if (rc < 0) { - BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc); + BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc); goto no_msix; + } else if (rc < msix_vec) { + /* how less vectors we will have? */ + int diff = msix_vec - rc; + + BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc); + + /* + * decrease number of queues by number of unallocated entries + */ + bp->num_ethernet_queues -= diff; + bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; + + BNX2X_DEV_INFO("New queue configuration set: %d\n", + bp->num_queues); } bp->flags |= USING_MSIX_FLAG; @@ -1873,7 +1871,7 @@ void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) } u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { struct bnx2x *bp = netdev_priv(dev); @@ -1895,7 +1893,7 @@ u16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, } /* select a non-FCoE queue */ - return __netdev_pick_tx(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp); + return fallback(dev, skb) % BNX2X_NUM_ETH_QUEUES(bp); } void bnx2x_set_num_queues(struct bnx2x *bp) @@ -2234,8 +2232,10 @@ static int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp) sizeof(struct per_queue_stats) * num_queue_stats + sizeof(struct stats_counter); - BNX2X_PCI_ALLOC(bp->fw_stats, &bp->fw_stats_mapping, - bp->fw_stats_data_sz + bp->fw_stats_req_sz); + bp->fw_stats = BNX2X_PCI_ALLOC(&bp->fw_stats_mapping, + bp->fw_stats_data_sz + bp->fw_stats_req_sz); + if (!bp->fw_stats) + goto alloc_mem_err; /* Set shortcuts */ bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats; @@ -3875,7 +3875,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) xmit_type); } - /* Add the macs to the parsing BD this is a vf */ + /* Add the macs to the parsing BD if this is a vf or if + * Tx Switching is enabled. + */ if (IS_VF(bp)) { /* override GRE parameters in BD */ bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi, @@ -3887,6 +3889,11 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) &pbd_e2->data.mac_addr.dst_mid, &pbd_e2->data.mac_addr.dst_lo, eth->h_dest); + } else if (bp->flags & TX_SWITCHING) { + bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi, + &pbd_e2->data.mac_addr.dst_mid, + &pbd_e2->data.mac_addr.dst_lo, + eth->h_dest); } SET_FLAG(pbd_e2_parsing_data, @@ -4363,14 +4370,17 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) if (!IS_FCOE_IDX(index)) { /* status blocks */ - if (!CHIP_IS_E1x(bp)) - BNX2X_PCI_ALLOC(sb->e2_sb, - &bnx2x_fp(bp, index, status_blk_mapping), - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_ALLOC(sb->e1x_sb, - &bnx2x_fp(bp, index, status_blk_mapping), - sizeof(struct host_hc_status_block_e1x)); + if (!CHIP_IS_E1x(bp)) { + sb->e2_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e2)); + if (!sb->e2_sb) + goto alloc_mem_err; + } else { + sb->e1x_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping), + sizeof(struct host_hc_status_block_e1x)); + if (!sb->e1x_sb) + goto alloc_mem_err; + } } /* FCoE Queue uses Default SB and doesn't ACK the SB, thus no need to @@ -4389,35 +4399,49 @@ static int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) "allocating tx memory of fp %d cos %d\n", index, cos); - BNX2X_ALLOC(txdata->tx_buf_ring, - sizeof(struct sw_tx_bd) * NUM_TX_BD); - BNX2X_PCI_ALLOC(txdata->tx_desc_ring, - &txdata->tx_desc_mapping, - sizeof(union eth_tx_bd_types) * NUM_TX_BD); + txdata->tx_buf_ring = kcalloc(NUM_TX_BD, + sizeof(struct sw_tx_bd), + GFP_KERNEL); + if (!txdata->tx_buf_ring) + goto alloc_mem_err; + txdata->tx_desc_ring = BNX2X_PCI_ALLOC(&txdata->tx_desc_mapping, + sizeof(union eth_tx_bd_types) * NUM_TX_BD); + if (!txdata->tx_desc_ring) + goto alloc_mem_err; } } /* Rx */ if (!skip_rx_queue(bp, index)) { /* fastpath rx rings: rx_buf rx_desc rx_comp */ - BNX2X_ALLOC(bnx2x_fp(bp, index, rx_buf_ring), - sizeof(struct sw_rx_bd) * NUM_RX_BD); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_desc_ring), - &bnx2x_fp(bp, index, rx_desc_mapping), - sizeof(struct eth_rx_bd) * NUM_RX_BD); + bnx2x_fp(bp, index, rx_buf_ring) = + kcalloc(NUM_RX_BD, sizeof(struct sw_rx_bd), GFP_KERNEL); + if (!bnx2x_fp(bp, index, rx_buf_ring)) + goto alloc_mem_err; + bnx2x_fp(bp, index, rx_desc_ring) = + BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_desc_mapping), + sizeof(struct eth_rx_bd) * NUM_RX_BD); + if (!bnx2x_fp(bp, index, rx_desc_ring)) + goto alloc_mem_err; /* Seed all CQEs by 1s */ - BNX2X_PCI_FALLOC(bnx2x_fp(bp, index, rx_comp_ring), - &bnx2x_fp(bp, index, rx_comp_mapping), - sizeof(struct eth_fast_path_rx_cqe) * - NUM_RCQ_BD); + bnx2x_fp(bp, index, rx_comp_ring) = + BNX2X_PCI_FALLOC(&bnx2x_fp(bp, index, rx_comp_mapping), + sizeof(struct eth_fast_path_rx_cqe) * NUM_RCQ_BD); + if (!bnx2x_fp(bp, index, rx_comp_ring)) + goto alloc_mem_err; /* SGE ring */ - BNX2X_ALLOC(bnx2x_fp(bp, index, rx_page_ring), - sizeof(struct sw_rx_page) * NUM_RX_SGE); - BNX2X_PCI_ALLOC(bnx2x_fp(bp, index, rx_sge_ring), - &bnx2x_fp(bp, index, rx_sge_mapping), - BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + bnx2x_fp(bp, index, rx_page_ring) = + kcalloc(NUM_RX_SGE, sizeof(struct sw_rx_page), + GFP_KERNEL); + if (!bnx2x_fp(bp, index, rx_page_ring)) + goto alloc_mem_err; + bnx2x_fp(bp, index, rx_sge_ring) = + BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_sge_mapping), + BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); + if (!bnx2x_fp(bp, index, rx_sge_ring)) + goto alloc_mem_err; /* RX BD ring */ bnx2x_set_next_page_rx_bd(fp); @@ -4773,12 +4797,8 @@ void bnx2x_tx_timeout(struct net_device *dev) bnx2x_panic(); #endif - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_TX_TIMEOUT, &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - /* This allows the netif to be shutdown gracefully before resetting */ - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_TIMEOUT, 0); } int bnx2x_suspend(struct pci_dev *pdev, pm_message_t state) @@ -4906,3 +4926,15 @@ void bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id, disable = disable ? 1 : (usec ? 0 : 1); storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable); } + +void bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag, + u32 verbose) +{ + smp_mb__before_clear_bit(); + set_bit(flag, &bp->sp_rtnl_state); + smp_mb__after_clear_bit(); + DP((BNX2X_MSG_SP | verbose), "Scheduling sp_rtnl task [Flag: %d]\n", + flag); + schedule_delayed_work(&bp->sp_rtnl_task, 0); +} +EXPORT_SYMBOL(bnx2x_schedule_sp_rtnl); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 17d1689aec6b..05f4f5f52635 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -47,31 +47,26 @@ extern int bnx2x_num_queues; } \ } while (0) -#define BNX2X_PCI_ALLOC(x, y, size) \ - do { \ - x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - DP(NETIF_MSG_HW, "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \ - (unsigned long long)(*y), x); \ - } while (0) - -#define BNX2X_PCI_FALLOC(x, y, size) \ - do { \ - x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - memset((void *)x, 0xFFFFFFFF, size); \ - DP(NETIF_MSG_HW, "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n",\ - (unsigned long long)(*y), x); \ - } while (0) - -#define BNX2X_ALLOC(x, size) \ - do { \ - x = kzalloc(size, GFP_KERNEL); \ - if (x == NULL) \ - goto alloc_mem_err; \ - } while (0) +#define BNX2X_PCI_ALLOC(y, size) \ +({ \ + void *x = dma_zalloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x) \ + DP(NETIF_MSG_HW, \ + "BNX2X_PCI_ALLOC: Physical %Lx Virtual %p\n", \ + (unsigned long long)(*y), x); \ + x; \ +}) +#define BNX2X_PCI_FALLOC(y, size) \ +({ \ + void *x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \ + if (x) { \ + memset(x, 0xff, size); \ + DP(NETIF_MSG_HW, \ + "BNX2X_PCI_FALLOC: Physical %Lx Virtual %p\n", \ + (unsigned long long)(*y), x); \ + } \ + x; \ +}) /*********************** Interfaces **************************** * Functions that need to be implemented by each driver version @@ -496,7 +491,7 @@ 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, - void *accel_priv); + void *accel_priv, select_queue_fallback_t fallback); static inline void bnx2x_update_rx_prod(struct bnx2x *bp, struct bnx2x_fastpath *fp, @@ -936,7 +931,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp) else /* CHIP_IS_E1X */ start_params->network_cos_mode = FW_WRR; - start_params->gre_tunnel_mode = IPGRE_TUNNEL; + start_params->gre_tunnel_mode = L2GRE_TUNNEL; start_params->gre_tunnel_rss = GRE_INNER_HEADERS_RSS; return bnx2x_func_state_change(bp, &func_params); @@ -1324,4 +1319,7 @@ void bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len); int bnx2x_drain_tx_queues(struct bnx2x *bp); void bnx2x_squeeze_objects(struct bnx2x *bp); +void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag, + u32 verbose); + #endif /* BNX2X_CMN_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index fdace204b054..97ea5421dd96 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -710,8 +710,7 @@ static inline void bnx2x_dcbx_update_tc_mapping(struct bnx2x *bp) * as we are handling an attention on a work queue which must be * flushed at some rtnl-locked contexts (e.g. if down) */ - if (!test_and_set_bit(BNX2X_SP_RTNL_SETUP_TC, &bp->sp_rtnl_state)) - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_SETUP_TC, 0); } void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) @@ -764,10 +763,7 @@ void bnx2x_dcbx_set_params(struct bnx2x *bp, u32 state) if (IS_MF(bp)) bnx2x_link_sync_notify(bp); - set_bit(BNX2X_SP_RTNL_TX_STOP, &bp->sp_rtnl_state); - - schedule_delayed_work(&bp->sp_rtnl_task, 0); - + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_STOP, 0); return; } case BNX2X_DCBX_STATE_TX_PAUSED: diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index 84aecdf06f7a..95dc36543548 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -87,7 +87,6 @@ (IRO[156].base + ((vfId) * IRO[156].m1)) #define CSTORM_VF_TO_PF_OFFSET(funcId) \ (IRO[150].base + ((funcId) * IRO[150].m1)) -#define TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET (IRO[204].base) #define TSTORM_APPROXIMATE_MATCH_MULTICAST_FILTERING_OFFSET(pfId) \ (IRO[203].base + ((pfId) * IRO[203].m1)) #define TSTORM_ASSERT_LIST_INDEX_OFFSET (IRO[102].base) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index cf1df8b62e2c..46e2f18df2cb 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -2848,7 +2848,7 @@ struct afex_stats { #define BCM_5710_FW_MAJOR_VERSION 7 #define BCM_5710_FW_MINOR_VERSION 8 -#define BCM_5710_FW_REVISION_VERSION 17 +#define BCM_5710_FW_REVISION_VERSION 19 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c9c445e7b4a5..5e74599b05c7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -95,29 +95,29 @@ MODULE_FIRMWARE(FW_FILE_NAME_E1H); MODULE_FIRMWARE(FW_FILE_NAME_E2); int bnx2x_num_queues; -module_param_named(num_queues, bnx2x_num_queues, int, 0); +module_param_named(num_queues, bnx2x_num_queues, int, S_IRUGO); MODULE_PARM_DESC(num_queues, " Set number of queues (default is as a number of CPUs)"); static int disable_tpa; -module_param(disable_tpa, int, 0); +module_param(disable_tpa, int, S_IRUGO); MODULE_PARM_DESC(disable_tpa, " Disable the TPA (LRO) feature"); static int int_mode; -module_param(int_mode, int, 0); +module_param(int_mode, int, S_IRUGO); MODULE_PARM_DESC(int_mode, " Force interrupt mode other than MSI-X " "(1 INT#x; 2 MSI)"); static int dropless_fc; -module_param(dropless_fc, int, 0); +module_param(dropless_fc, int, S_IRUGO); MODULE_PARM_DESC(dropless_fc, " Pause on exhausted host ring"); static int mrrs = -1; -module_param(mrrs, int, 0); +module_param(mrrs, int, S_IRUGO); MODULE_PARM_DESC(mrrs, " Force Max Read Req Size (0..3) (for debug)"); static int debug; -module_param(debug, int, 0); +module_param(debug, int, S_IRUGO); MODULE_PARM_DESC(debug, " Default debug msglevel"); struct workqueue_struct *bnx2x_wq; @@ -918,7 +918,7 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int) u16 start = 0, end = 0; u8 cos; #endif - if (disable_int) + if (IS_PF(bp) && disable_int) bnx2x_int_disable(bp); bp->stats_state = STATS_STATE_DISABLED; @@ -929,33 +929,41 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int) /* Indices */ /* Common */ - BNX2X_ERR("def_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x) spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n", - bp->def_idx, bp->def_att_idx, bp->attn_state, - bp->spq_prod_idx, bp->stats_counter); - BNX2X_ERR("DSB: attn bits(0x%x) ack(0x%x) id(0x%x) idx(0x%x)\n", - bp->def_status_blk->atten_status_block.attn_bits, - bp->def_status_blk->atten_status_block.attn_bits_ack, - bp->def_status_blk->atten_status_block.status_block_id, - bp->def_status_blk->atten_status_block.attn_bits_index); - BNX2X_ERR(" def ("); - for (i = 0; i < HC_SP_SB_MAX_INDICES; i++) - pr_cont("0x%x%s", - bp->def_status_blk->sp_sb.index_values[i], - (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " "); - - for (i = 0; i < sizeof(struct hc_sp_status_block_data)/sizeof(u32); i++) - *((u32 *)&sp_sb_data + i) = REG_RD(bp, BAR_CSTRORM_INTMEM + - CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func) + - i*sizeof(u32)); - - pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) pf_id(0x%x) vnic_id(0x%x) vf_id(0x%x) vf_valid (0x%x) state(0x%x)\n", - sp_sb_data.igu_sb_id, - sp_sb_data.igu_seg_id, - sp_sb_data.p_func.pf_id, - sp_sb_data.p_func.vnic_id, - sp_sb_data.p_func.vf_id, - sp_sb_data.p_func.vf_valid, - sp_sb_data.state); + if (IS_PF(bp)) { + struct host_sp_status_block *def_sb = bp->def_status_blk; + int data_size, cstorm_offset; + + BNX2X_ERR("def_idx(0x%x) def_att_idx(0x%x) attn_state(0x%x) spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n", + bp->def_idx, bp->def_att_idx, bp->attn_state, + bp->spq_prod_idx, bp->stats_counter); + BNX2X_ERR("DSB: attn bits(0x%x) ack(0x%x) id(0x%x) idx(0x%x)\n", + def_sb->atten_status_block.attn_bits, + def_sb->atten_status_block.attn_bits_ack, + def_sb->atten_status_block.status_block_id, + def_sb->atten_status_block.attn_bits_index); + BNX2X_ERR(" def ("); + for (i = 0; i < HC_SP_SB_MAX_INDICES; i++) + pr_cont("0x%x%s", + def_sb->sp_sb.index_values[i], + (i == HC_SP_SB_MAX_INDICES - 1) ? ") " : " "); + + data_size = sizeof(struct hc_sp_status_block_data) / + sizeof(u32); + cstorm_offset = CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func); + for (i = 0; i < data_size; i++) + *((u32 *)&sp_sb_data + i) = + REG_RD(bp, BAR_CSTRORM_INTMEM + cstorm_offset + + i * sizeof(u32)); + + pr_cont("igu_sb_id(0x%x) igu_seg_id(0x%x) pf_id(0x%x) vnic_id(0x%x) vf_id(0x%x) vf_valid (0x%x) state(0x%x)\n", + sp_sb_data.igu_sb_id, + sp_sb_data.igu_seg_id, + sp_sb_data.p_func.pf_id, + sp_sb_data.p_func.vnic_id, + sp_sb_data.p_func.vf_id, + sp_sb_data.p_func.vf_valid, + sp_sb_data.state); + } for_each_eth_queue(bp, i) { struct bnx2x_fastpath *fp = &bp->fp[i]; @@ -1013,6 +1021,11 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int) pr_cont("0x%x%s", fp->sb_index_values[j], (j == loop - 1) ? ")" : " "); + + /* VF cannot access FW refelection for status block */ + if (IS_VF(bp)) + continue; + /* fw sb data */ data_size = CHIP_IS_E1x(bp) ? sizeof(struct hc_status_block_data_e1x) : @@ -1064,16 +1077,18 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int) } #ifdef BNX2X_STOP_ON_ERROR - - /* event queue */ - BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod); - for (i = 0; i < NUM_EQ_DESC; i++) { - u32 *data = (u32 *)&bp->eq_ring[i].message.data; - - BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n", - i, bp->eq_ring[i].message.opcode, - bp->eq_ring[i].message.error); - BNX2X_ERR("data: %x %x %x\n", data[0], data[1], data[2]); + if (IS_PF(bp)) { + /* event queue */ + BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod); + for (i = 0; i < NUM_EQ_DESC; i++) { + u32 *data = (u32 *)&bp->eq_ring[i].message.data; + + BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n", + i, bp->eq_ring[i].message.opcode, + bp->eq_ring[i].message.error); + BNX2X_ERR("data: %x %x %x\n", + data[0], data[1], data[2]); + } } /* Rings */ @@ -1140,8 +1155,10 @@ void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int) } } #endif - bnx2x_fw_dump(bp); - bnx2x_mc_assert(bp); + if (IS_PF(bp)) { + bnx2x_fw_dump(bp); + bnx2x_mc_assert(bp); + } BNX2X_ERR("end crash dump -----------------\n"); } @@ -1814,6 +1831,11 @@ void bnx2x_sp_event(struct bnx2x_fastpath *fp, union eth_rx_cqe *rr_cqe) drv_cmd = BNX2X_Q_CMD_EMPTY; break; + case (RAMROD_CMD_ID_ETH_TPA_UPDATE): + DP(BNX2X_MSG_SP, "got tpa update ramrod CID=%d\n", cid); + drv_cmd = BNX2X_Q_CMD_UPDATE_TPA; + break; + default: BNX2X_ERR("unexpected MC reply (%d) on fp[%d]\n", command, fp->index); @@ -3644,10 +3666,18 @@ int bnx2x_sp_post(struct bnx2x *bp, int command, int cid, cpu_to_le32((command << SPE_HDR_CMD_ID_SHIFT) | HW_CID(bp, cid)); - type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) & SPE_HDR_CONN_TYPE; - - type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) & - SPE_HDR_FUNCTION_ID); + /* In some cases, type may already contain the func-id + * mainly in SRIOV related use cases, so we add it here only + * if it's not already set. + */ + if (!(cmd_type & SPE_HDR_FUNCTION_ID)) { + type = (cmd_type << SPE_HDR_CONN_TYPE_SHIFT) & + SPE_HDR_CONN_TYPE; + type |= ((BP_FUNC(bp) << SPE_HDR_FUNCTION_ID_SHIFT) & + SPE_HDR_FUNCTION_ID); + } else { + type = cmd_type; + } spe->hdr.type = cpu_to_le16(type); @@ -3878,10 +3908,7 @@ static void bnx2x_fan_failure(struct bnx2x *bp) * This is due to some boards consuming sufficient power when driver is * up to overheat if fan fails. */ - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_FAN_FAILURE, &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_FAN_FAILURE, 0); } static void bnx2x_attn_int_deasserted0(struct bnx2x *bp, u32 attn) @@ -5221,9 +5248,9 @@ static void bnx2x_eq_int(struct bnx2x *bp) continue; case EVENT_RING_OPCODE_STAT_QUERY: - DP(BNX2X_MSG_SP | BNX2X_MSG_STATS, - "got statistics comp event %d\n", - bp->stats_comp++); + DP_AND((BNX2X_MSG_SP | BNX2X_MSG_STATS), + "got statistics comp event %d\n", + bp->stats_comp++); /* nothing to do with stats comp */ goto next_spqe; @@ -5273,6 +5300,8 @@ static void bnx2x_eq_int(struct bnx2x *bp) break; } else { + int cmd = BNX2X_SP_RTNL_AFEX_F_UPDATE; + DP(BNX2X_MSG_SP | BNX2X_MSG_MCP, "AFEX: ramrod completed FUNCTION_UPDATE\n"); f_obj->complete_cmd(bp, f_obj, @@ -5282,12 +5311,7 @@ static void bnx2x_eq_int(struct bnx2x *bp) * sp_rtnl task as all Queue SP operations * should run under rtnl_lock. */ - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_AFEX_F_UPDATE, - &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, cmd, 0); } goto next_spqe; @@ -6005,18 +6029,6 @@ static void bnx2x_init_internal_common(struct bnx2x *bp) { int i; - if (IS_MF_SI(bp)) - /* - * In switch independent mode, the TSTORM needs to accept - * packets that failed classification, since approximate match - * mac addresses aren't written to NIG LLH - */ - REG_WR8(bp, BAR_TSTRORM_INTMEM + - TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 2); - else if (!CHIP_IS_E1(bp)) /* 57710 doesn't support MF */ - REG_WR8(bp, BAR_TSTRORM_INTMEM + - TSTORM_ACCEPT_CLASSIFY_FAILED_OFFSET, 0); - /* Zero this manually as its initialization is currently missing in the initTool */ for (i = 0; i < (USTORM_AGG_DATA_SIZE >> 2); i++) @@ -7989,19 +8001,25 @@ void bnx2x_free_mem(struct bnx2x *bp) int bnx2x_alloc_mem_cnic(struct bnx2x *bp) { - if (!CHIP_IS_E1x(bp)) + if (!CHIP_IS_E1x(bp)) { /* size = the status block + ramrod buffers */ - BNX2X_PCI_ALLOC(bp->cnic_sb.e2_sb, &bp->cnic_sb_mapping, - sizeof(struct host_hc_status_block_e2)); - else - BNX2X_PCI_ALLOC(bp->cnic_sb.e1x_sb, - &bp->cnic_sb_mapping, - sizeof(struct - host_hc_status_block_e1x)); + bp->cnic_sb.e2_sb = BNX2X_PCI_ALLOC(&bp->cnic_sb_mapping, + sizeof(struct host_hc_status_block_e2)); + if (!bp->cnic_sb.e2_sb) + goto alloc_mem_err; + } else { + bp->cnic_sb.e1x_sb = BNX2X_PCI_ALLOC(&bp->cnic_sb_mapping, + sizeof(struct host_hc_status_block_e1x)); + if (!bp->cnic_sb.e1x_sb) + goto alloc_mem_err; + } - if (CONFIGURE_NIC_MODE(bp) && !bp->t2) + if (CONFIGURE_NIC_MODE(bp) && !bp->t2) { /* allocate searcher T2 table, as it wasn't allocated before */ - BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ); + bp->t2 = BNX2X_PCI_ALLOC(&bp->t2_mapping, SRC_T2_SZ); + if (!bp->t2) + goto alloc_mem_err; + } /* write address to which L5 should insert its values */ bp->cnic_eth_dev.addr_drv_info_to_mcp = @@ -8022,15 +8040,22 @@ int bnx2x_alloc_mem(struct bnx2x *bp) { int i, allocated, context_size; - if (!CONFIGURE_NIC_MODE(bp) && !bp->t2) + if (!CONFIGURE_NIC_MODE(bp) && !bp->t2) { /* allocate searcher T2 table */ - BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, SRC_T2_SZ); + bp->t2 = BNX2X_PCI_ALLOC(&bp->t2_mapping, SRC_T2_SZ); + if (!bp->t2) + goto alloc_mem_err; + } - BNX2X_PCI_ALLOC(bp->def_status_blk, &bp->def_status_blk_mapping, - sizeof(struct host_sp_status_block)); + bp->def_status_blk = BNX2X_PCI_ALLOC(&bp->def_status_blk_mapping, + sizeof(struct host_sp_status_block)); + if (!bp->def_status_blk) + goto alloc_mem_err; - BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping, - sizeof(struct bnx2x_slowpath)); + bp->slowpath = BNX2X_PCI_ALLOC(&bp->slowpath_mapping, + sizeof(struct bnx2x_slowpath)); + if (!bp->slowpath) + goto alloc_mem_err; /* Allocate memory for CDU context: * This memory is allocated separately and not in the generic ILT @@ -8050,12 +8075,16 @@ int bnx2x_alloc_mem(struct bnx2x *bp) for (i = 0, allocated = 0; allocated < context_size; i++) { bp->context[i].size = min(CDU_ILT_PAGE_SZ, (context_size - allocated)); - BNX2X_PCI_ALLOC(bp->context[i].vcxt, - &bp->context[i].cxt_mapping, - bp->context[i].size); + bp->context[i].vcxt = BNX2X_PCI_ALLOC(&bp->context[i].cxt_mapping, + bp->context[i].size); + if (!bp->context[i].vcxt) + goto alloc_mem_err; allocated += bp->context[i].size; } - BNX2X_ALLOC(bp->ilt->lines, sizeof(struct ilt_line) * ILT_MAX_LINES); + bp->ilt->lines = kcalloc(ILT_MAX_LINES, sizeof(struct ilt_line), + GFP_KERNEL); + if (!bp->ilt->lines) + goto alloc_mem_err; if (bnx2x_ilt_mem_op(bp, ILT_MEMOP_ALLOC)) goto alloc_mem_err; @@ -8064,11 +8093,15 @@ int bnx2x_alloc_mem(struct bnx2x *bp) goto alloc_mem_err; /* Slow path ring */ - BNX2X_PCI_ALLOC(bp->spq, &bp->spq_mapping, BCM_PAGE_SIZE); + bp->spq = BNX2X_PCI_ALLOC(&bp->spq_mapping, BCM_PAGE_SIZE); + if (!bp->spq) + goto alloc_mem_err; /* EQ */ - BNX2X_PCI_ALLOC(bp->eq_ring, &bp->eq_mapping, - BCM_PAGE_SIZE * NUM_EQ_PAGES); + bp->eq_ring = BNX2X_PCI_ALLOC(&bp->eq_mapping, + BCM_PAGE_SIZE * NUM_EQ_PAGES); + if (!bp->eq_ring) + goto alloc_mem_err; return 0; @@ -11771,6 +11804,8 @@ static int bnx2x_init_bp(struct bnx2x *bp) bp->disable_tpa = disable_tpa; bp->disable_tpa |= IS_MF_STORAGE_SD(bp) || IS_MF_FCOE_AFEX(bp); + /* Reduce memory usage in kdump environment by disabling TPA */ + bp->disable_tpa |= reset_devices; /* Set TPA flags */ if (bp->disable_tpa) { @@ -11942,7 +11977,7 @@ static int bnx2x_init_mcast_macs_list(struct bnx2x *bp, { int mc_count = netdev_mc_count(bp->dev); struct bnx2x_mcast_list_elem *mc_mac = - kzalloc(sizeof(*mc_mac) * mc_count, GFP_ATOMIC); + kcalloc(mc_count, sizeof(*mc_mac), GFP_ATOMIC); struct netdev_hw_addr *ha; if (!mc_mac) @@ -12064,11 +12099,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev) return; } else { /* Schedule an SP task to handle rest of change */ - DP(NETIF_MSG_IFUP, "Scheduling an Rx mode change\n"); - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_RX_MODE, &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_RX_MODE, + NETIF_MSG_IFUP); } } @@ -12101,11 +12133,8 @@ void bnx2x_set_rx_mode_inner(struct bnx2x *bp) /* configuring mcast to a vf involves sleeping (when we * wait for the pf's response). */ - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_VFPF_MCAST, - &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, + BNX2X_SP_RTNL_VFPF_MCAST, 0); } } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 0fb6ff2ac8e3..31297266b743 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -2277,11 +2277,11 @@ static int bnx2x_set_rx_mode_e2(struct bnx2x *bp, data->header.rule_cnt, p->rx_accept_flags, p->tx_accept_flags); - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ /* Send a ramrod */ @@ -2982,11 +2982,11 @@ static int bnx2x_mcast_setup_e2(struct bnx2x *bp, raw->clear_pending(raw); return 0; } else { - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ /* Send a ramrod */ @@ -3466,11 +3466,11 @@ static int bnx2x_mcast_setup_e1(struct bnx2x *bp, raw->clear_pending(raw); return 0; } else { - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ /* Send a ramrod */ @@ -4091,11 +4091,11 @@ static int bnx2x_setup_rss(struct bnx2x *bp, data->capabilities |= ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY; } - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ /* Send a ramrod */ @@ -4158,16 +4158,6 @@ void bnx2x_init_rss_config_obj(struct bnx2x *bp, rss_obj->config_rss = bnx2x_setup_rss; } -int validate_vlan_mac(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *vlan_mac) -{ - if (!vlan_mac->get_n_elements) { - BNX2X_ERR("vlan mac object was not intialized\n"); - return -EINVAL; - } - return 0; -} - /********************** Queue state object ***********************************/ /** @@ -4587,13 +4577,12 @@ static inline int bnx2x_q_send_setup_e1x(struct bnx2x *bp, /* Fill the ramrod data */ bnx2x_q_fill_setup_data_cmn(bp, params, rdata); - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ - return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX], U64_HI(data_mapping), U64_LO(data_mapping), ETH_CONNECTION_TYPE); @@ -4615,13 +4604,12 @@ static inline int bnx2x_q_send_setup_e2(struct bnx2x *bp, bnx2x_q_fill_setup_data_cmn(bp, params, rdata); bnx2x_q_fill_setup_data_e2(bp, params, rdata); - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ - return bnx2x_sp_post(bp, ramrod, o->cids[BNX2X_PRIMARY_CID_INDEX], U64_HI(data_mapping), U64_LO(data_mapping), ETH_CONNECTION_TYPE); @@ -4659,13 +4647,12 @@ static inline int bnx2x_q_send_setup_tx_only(struct bnx2x *bp, o->cids[cid_index], rdata->general.client_id, rdata->general.sp_client_id, rdata->general.cos); - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ - return bnx2x_sp_post(bp, ramrod, o->cids[cid_index], U64_HI(data_mapping), U64_LO(data_mapping), ETH_CONNECTION_TYPE); @@ -4760,13 +4747,12 @@ static inline int bnx2x_q_send_update(struct bnx2x *bp, /* Fill the ramrod data */ bnx2x_q_fill_update_data(bp, o, update_params, rdata); - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ - return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_CLIENT_UPDATE, o->cids[cid_index], U64_HI(data_mapping), U64_LO(data_mapping), ETH_CONNECTION_TYPE); @@ -4813,11 +4799,62 @@ static inline int bnx2x_q_send_activate(struct bnx2x *bp, return bnx2x_q_send_update(bp, params); } +static void bnx2x_q_fill_update_tpa_data(struct bnx2x *bp, + struct bnx2x_queue_sp_obj *obj, + struct bnx2x_queue_update_tpa_params *params, + struct tpa_update_ramrod_data *data) +{ + data->client_id = obj->cl_id; + data->complete_on_both_clients = params->complete_on_both_clients; + data->dont_verify_rings_pause_thr_flg = + params->dont_verify_thr; + data->max_agg_size = cpu_to_le16(params->max_agg_sz); + data->max_sges_for_packet = params->max_sges_pkt; + data->max_tpa_queues = params->max_tpa_queues; + data->sge_buff_size = cpu_to_le16(params->sge_buff_sz); + data->sge_page_base_hi = cpu_to_le32(U64_HI(params->sge_map)); + data->sge_page_base_lo = cpu_to_le32(U64_LO(params->sge_map)); + data->sge_pause_thr_high = cpu_to_le16(params->sge_pause_thr_high); + data->sge_pause_thr_low = cpu_to_le16(params->sge_pause_thr_low); + data->tpa_mode = params->tpa_mode; + data->update_ipv4 = params->update_ipv4; + data->update_ipv6 = params->update_ipv6; +} + static inline int bnx2x_q_send_update_tpa(struct bnx2x *bp, struct bnx2x_queue_state_params *params) { - /* TODO: Not implemented yet. */ - return -1; + struct bnx2x_queue_sp_obj *o = params->q_obj; + struct tpa_update_ramrod_data *rdata = + (struct tpa_update_ramrod_data *)o->rdata; + dma_addr_t data_mapping = o->rdata_mapping; + struct bnx2x_queue_update_tpa_params *update_tpa_params = + ¶ms->params.update_tpa; + u16 type; + + /* Clear the ramrod data */ + memset(rdata, 0, sizeof(*rdata)); + + /* Fill the ramrod data */ + bnx2x_q_fill_update_tpa_data(bp, o, update_tpa_params, rdata); + + /* Add the function id inside the type, so that sp post function + * doesn't automatically add the PF func-id, this is required + * for operations done by PFs on behalf of their VFs + */ + type = ETH_CONNECTION_TYPE | + ((o->func_id) << SPE_HDR_FUNCTION_ID_SHIFT); + + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). + */ + return bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_TPA_UPDATE, + o->cids[BNX2X_PRIMARY_CID_INDEX], + U64_HI(data_mapping), + U64_LO(data_mapping), type); } static inline int bnx2x_q_send_halt(struct bnx2x *bp, @@ -5647,6 +5684,12 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp, rdata->tx_switch_suspend = switch_update_params->suspend; rdata->echo = SWITCH_UPDATE; + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). + */ return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_FUNCTION_UPDATE, 0, U64_HI(data_mapping), U64_LO(data_mapping), NONE_CONNECTION_TYPE); @@ -5674,11 +5717,11 @@ static inline int bnx2x_func_send_afex_update(struct bnx2x *bp, rdata->allowed_priorities = afex_update_params->allowed_priorities; rdata->echo = AFEX_UPDATE; - /* No need for an explicit memory barrier here as long we would - * need to ensure the ordering of writing to the SPQ element - * and updating of the SPQ producer which involves a memory - * read and we will have to put a full memory barrier there - * (inside bnx2x_sp_post()). + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). */ DP(BNX2X_MSG_SP, "afex: sending func_update vif_id 0x%x dvlan 0x%x prio 0x%x\n", @@ -5763,6 +5806,12 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp, rdata->traffic_type_to_priority_cos[i] = tx_start_params->traffic_type_to_priority_cos[i]; + /* No need for an explicit memory barrier here as long as we + * ensure the ordering of writing to the SPQ element + * and updating of the SPQ producer which involves a memory + * read. If the memory read is removed we will have to put a + * full memory barrier there (inside bnx2x_sp_post()). + */ return bnx2x_sp_post(bp, RAMROD_CMD_ID_COMMON_START_TRAFFIC, 0, U64_HI(data_mapping), U64_LO(data_mapping), NONE_CONNECTION_TYPE); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 00d7f214a40a..80f6c790ed88 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -893,6 +893,24 @@ struct bnx2x_queue_update_params { u8 cid_index; }; +struct bnx2x_queue_update_tpa_params { + dma_addr_t sge_map; + u8 update_ipv4; + u8 update_ipv6; + u8 max_tpa_queues; + u8 max_sges_pkt; + u8 complete_on_both_clients; + u8 dont_verify_thr; + u8 tpa_mode; + u8 _pad; + + u16 sge_buff_sz; + u16 max_agg_sz; + + u16 sge_pause_thr_low; + u16 sge_pause_thr_high; +}; + struct rxq_pause_params { u16 bd_th_lo; u16 bd_th_hi; @@ -987,6 +1005,7 @@ struct bnx2x_queue_state_params { /* Params according to the current command */ union { struct bnx2x_queue_update_params update; + struct bnx2x_queue_update_tpa_params update_tpa; struct bnx2x_queue_setup_params setup; struct bnx2x_queue_init_params init; struct bnx2x_queue_setup_tx_only_params tx_only; @@ -1403,6 +1422,4 @@ int bnx2x_config_rss(struct bnx2x *bp, void bnx2x_get_rss_ind_table(struct bnx2x_rss_config_obj *rss_obj, u8 *ind_table); -int validate_vlan_mac(struct bnx2x *bp, - struct bnx2x_vlan_mac_obj *vlan_mac); #endif /* BNX2X_SP_VERBS */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index aec5ef2ed7ce..61e6f606d8a4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -102,6 +102,21 @@ static void bnx2x_vf_igu_ack_sb(struct bnx2x *bp, struct bnx2x_virtf *vf, mmiowb(); barrier(); } + +static bool bnx2x_validate_vf_sp_objs(struct bnx2x *bp, + struct bnx2x_virtf *vf, + bool print_err) +{ + if (!bnx2x_leading_vfq(vf, sp_initialized)) { + if (print_err) + BNX2X_ERR("Slowpath objects not yet initialized!\n"); + else + DP(BNX2X_MSG_IOV, "Slowpath objects not yet initialized!\n"); + return false; + } + return true; +} + /* VFOP - VF slow-path operation support */ #define BNX2X_VFOP_FILTER_ADD_CNT_MAX 0x10000 @@ -176,6 +191,11 @@ enum bnx2x_vfop_rss_state { BNX2X_VFOP_RSS_DONE }; +enum bnx2x_vfop_tpa_state { + BNX2X_VFOP_TPA_CONFIG, + BNX2X_VFOP_TPA_DONE +}; + #define bnx2x_vfop_reset_wq(vf) atomic_set(&vf->op_in_progress, 0) void bnx2x_vfop_qctor_dump_tx(struct bnx2x *bp, struct bnx2x_virtf *vf, @@ -716,7 +736,6 @@ static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp, int qid, bool drv_only) { struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); - int rc; if (vfop) { struct bnx2x_vfop_args_filters filters = { @@ -736,9 +755,6 @@ static int bnx2x_vfop_mac_delall_cmd(struct bnx2x *bp, bnx2x_vfop_mac_prep_ramrod(ramrod, &flags); /* set object */ - rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj)); - if (rc) - return rc; ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj); /* set extra args */ @@ -758,9 +774,12 @@ int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp, struct bnx2x_vfop_filters *macs, int qid, bool drv_only) { - struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); - int rc; + struct bnx2x_vfop *vfop; + + if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) + return -EINVAL; + vfop = bnx2x_vfop_add(bp, vf); if (vfop) { struct bnx2x_vfop_args_filters filters = { .multi_filter = macs, @@ -782,9 +801,6 @@ int bnx2x_vfop_mac_list_cmd(struct bnx2x *bp, bnx2x_vfop_mac_prep_ramrod(ramrod, &flags); /* set object */ - rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj)); - if (rc) - return rc; ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, mac_obj); /* set extra args */ @@ -804,9 +820,12 @@ static int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp, struct bnx2x_vfop_cmd *cmd, int qid, u16 vid, bool add) { - struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); - int rc; + struct bnx2x_vfop *vfop; + if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) + return -EINVAL; + + vfop = bnx2x_vfop_add(bp, vf); if (vfop) { struct bnx2x_vfop_args_filters filters = { .multi_filter = NULL, /* single command */ @@ -826,9 +845,6 @@ static int bnx2x_vfop_vlan_set_cmd(struct bnx2x *bp, ramrod->user_req.u.vlan.vlan = vid; /* set object */ - rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj)); - if (rc) - return rc; ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj); /* set extra args */ @@ -848,7 +864,6 @@ static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp, int qid, bool drv_only) { struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); - int rc; if (vfop) { struct bnx2x_vfop_args_filters filters = { @@ -868,9 +883,6 @@ static int bnx2x_vfop_vlan_delall_cmd(struct bnx2x *bp, bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags); /* set object */ - rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj)); - if (rc) - return rc; ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj); /* set extra args */ @@ -890,9 +902,12 @@ int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp, struct bnx2x_vfop_filters *vlans, int qid, bool drv_only) { - struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); - int rc; + struct bnx2x_vfop *vfop; + if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) + return -EINVAL; + + vfop = bnx2x_vfop_add(bp, vf); if (vfop) { struct bnx2x_vfop_args_filters filters = { .multi_filter = vlans, @@ -911,9 +926,6 @@ int bnx2x_vfop_vlan_list_cmd(struct bnx2x *bp, bnx2x_vfop_vlan_mac_prep_ramrod(ramrod, &flags); /* set object */ - rc = validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj)); - if (rc) - return rc; ramrod->vlan_mac_obj = &bnx2x_vfq(vf, qid, vlan_obj); /* set extra args */ @@ -971,11 +983,8 @@ op_err: op_done: case BNX2X_VFOP_QSETUP_DONE: vf->cfg_flags |= VF_CFG_VLAN; - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_HYPERVISOR_VLAN, - &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - schedule_delayed_work(&bp->sp_rtnl_task, 0); + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_HYPERVISOR_VLAN, + BNX2X_MSG_IOV); bnx2x_vfop_end(bp, vf, vfop); return; default: @@ -1025,34 +1034,20 @@ static void bnx2x_vfop_qflr(struct bnx2x *bp, struct bnx2x_virtf *vf) /* vlan-clear-all: driver-only, don't consume credit */ vfop->state = BNX2X_VFOP_QFLR_CLR_MAC; - if (!validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, vlan_obj))) { - /* the vlan_mac vfop will re-schedule us */ - vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, - qid, true); - if (vfop->rc) - goto op_err; - return; - - } else { - /* need to reschedule ourselves */ - bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); - } + /* the vlan_mac vfop will re-schedule us */ + vfop->rc = bnx2x_vfop_vlan_delall_cmd(bp, vf, &cmd, qid, true); + if (vfop->rc) + goto op_err; + return; case BNX2X_VFOP_QFLR_CLR_MAC: /* mac-clear-all: driver only consume credit */ vfop->state = BNX2X_VFOP_QFLR_TERMINATE; - if (!validate_vlan_mac(bp, &bnx2x_vfq(vf, qid, mac_obj))) { - /* the vlan_mac vfop will re-schedule us */ - vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, - qid, true); - if (vfop->rc) - goto op_err; - return; - - } else { - /* need to reschedule ourselves */ - bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); - } + /* the vlan_mac vfop will re-schedule us */ + vfop->rc = bnx2x_vfop_mac_delall_cmd(bp, vf, &cmd, qid, true); + if (vfop->rc) + goto op_err; + return; case BNX2X_VFOP_QFLR_TERMINATE: qstate = &vfop->op_p->qctor.qstate; @@ -1095,8 +1090,13 @@ static int bnx2x_vfop_qflr_cmd(struct bnx2x *bp, if (vfop) { vfop->args.qx.qid = qid; - bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN, - bnx2x_vfop_qflr, cmd->done); + if ((qid == LEADING_IDX) && + bnx2x_validate_vf_sp_objs(bp, vf, false)) + bnx2x_vfop_opset(BNX2X_VFOP_QFLR_CLR_VLAN, + bnx2x_vfop_qflr, cmd->done); + else + bnx2x_vfop_opset(BNX2X_VFOP_QFLR_TERMINATE, + bnx2x_vfop_qflr, cmd->done); return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_qflr, cmd->block); } @@ -1310,7 +1310,10 @@ static void bnx2x_vfop_qdown(struct bnx2x *bp, struct bnx2x_virtf *vf) switch (state) { case BNX2X_VFOP_QTEARDOWN_RXMODE: /* Drop all */ - vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN; + if (bnx2x_validate_vf_sp_objs(bp, vf, true)) + vfop->state = BNX2X_VFOP_QTEARDOWN_CLR_VLAN; + else + vfop->state = BNX2X_VFOP_QTEARDOWN_QDTOR; vfop->rc = bnx2x_vfop_rxmode_cmd(bp, vf, &cmd, qid, 0); if (vfop->rc) goto op_err; @@ -1446,12 +1449,12 @@ static void bnx2x_vf_igu_reset(struct bnx2x *bp, struct bnx2x_virtf *vf) if (vf->cfg_flags & VF_CFG_INT_SIMD) val |= IGU_VF_CONF_SINGLE_ISR_EN; val &= ~IGU_VF_CONF_PARENT_MASK; - val |= BP_FUNC(bp) << IGU_VF_CONF_PARENT_SHIFT; /* parent PF */ + val |= (BP_ABS_FUNC(bp) >> 1) << IGU_VF_CONF_PARENT_SHIFT; REG_WR(bp, IGU_REG_VF_CONFIGURATION, val); DP(BNX2X_MSG_IOV, - "value in IGU_REG_VF_CONFIGURATION of vf %d after write %x\n", - vf->abs_vfid, REG_RD(bp, IGU_REG_VF_CONFIGURATION)); + "value in IGU_REG_VF_CONFIGURATION of vf %d after write is 0x%08x\n", + vf->abs_vfid, val); bnx2x_pretend_func(bp, BP_ABS_FUNC(bp)); @@ -2117,7 +2120,9 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp) cxt->size = min_t(size_t, tot_size, CDU_ILT_PAGE_SZ); if (cxt->size) { - BNX2X_PCI_ALLOC(cxt->addr, &cxt->mapping, cxt->size); + cxt->addr = BNX2X_PCI_ALLOC(&cxt->mapping, cxt->size); + if (!cxt->addr) + goto alloc_mem_err; } else { cxt->addr = NULL; cxt->mapping = 0; @@ -2127,20 +2132,28 @@ int bnx2x_iov_alloc_mem(struct bnx2x *bp) /* allocate vfs ramrods dma memory - client_init and set_mac */ tot_size = BNX2X_NR_VIRTFN(bp) * sizeof(struct bnx2x_vf_sp); - BNX2X_PCI_ALLOC(BP_VFDB(bp)->sp_dma.addr, &BP_VFDB(bp)->sp_dma.mapping, - tot_size); + BP_VFDB(bp)->sp_dma.addr = BNX2X_PCI_ALLOC(&BP_VFDB(bp)->sp_dma.mapping, + tot_size); + if (!BP_VFDB(bp)->sp_dma.addr) + goto alloc_mem_err; BP_VFDB(bp)->sp_dma.size = tot_size; /* allocate mailboxes */ tot_size = BNX2X_NR_VIRTFN(bp) * MBX_MSG_ALIGNED_SIZE; - BNX2X_PCI_ALLOC(BP_VF_MBX_DMA(bp)->addr, &BP_VF_MBX_DMA(bp)->mapping, - tot_size); + BP_VF_MBX_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_MBX_DMA(bp)->mapping, + tot_size); + if (!BP_VF_MBX_DMA(bp)->addr) + goto alloc_mem_err; + BP_VF_MBX_DMA(bp)->size = tot_size; /* allocate local bulletin boards */ tot_size = BNX2X_NR_VIRTFN(bp) * BULLETIN_CONTENT_SIZE; - BNX2X_PCI_ALLOC(BP_VF_BULLETIN_DMA(bp)->addr, - &BP_VF_BULLETIN_DMA(bp)->mapping, tot_size); + BP_VF_BULLETIN_DMA(bp)->addr = BNX2X_PCI_ALLOC(&BP_VF_BULLETIN_DMA(bp)->mapping, + tot_size); + if (!BP_VF_BULLETIN_DMA(bp)->addr) + goto alloc_mem_err; + BP_VF_BULLETIN_DMA(bp)->size = tot_size; return 0; @@ -2166,6 +2179,9 @@ static void bnx2x_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf, bnx2x_vf_sp_map(bp, vf, q_data), q_type); + /* sp indication is set only when vlan/mac/etc. are initialized */ + q->sp_initialized = false; + DP(BNX2X_MSG_IOV, "initialized vf %d's queue object. func id set to %d. cid set to 0x%x\n", vf->abs_vfid, q->sp_obj.func_id, q->cid); @@ -2527,10 +2543,10 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp) first_queue_query_index = BNX2X_FIRST_QUEUE_QUERY_IDX - (is_fcoe ? 0 : 1); - DP(BNX2X_MSG_IOV, - "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n", - BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index, - first_queue_query_index + num_queues_req); + DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS), + "BNX2X_NUM_ETH_QUEUES %d, is_fcoe %d, first_queue_query_index %d => determined the last non virtual statistics query index is %d. Will add queries on top of that\n", + BNX2X_NUM_ETH_QUEUES(bp), is_fcoe, first_queue_query_index, + first_queue_query_index + num_queues_req); cur_data_offset = bp->fw_stats_data_mapping + offsetof(struct bnx2x_fw_stats_data, queue_stats) + @@ -2544,9 +2560,9 @@ void bnx2x_iov_adjust_stats_req(struct bnx2x *bp) struct bnx2x_virtf *vf = BP_VF(bp, i); if (vf->state != VF_ENABLED) { - DP(BNX2X_MSG_IOV, - "vf %d not enabled so no stats for it\n", - vf->abs_vfid); + DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_STATS), + "vf %d not enabled so no stats for it\n", + vf->abs_vfid); continue; } @@ -2597,7 +2613,8 @@ void bnx2x_iov_sp_task(struct bnx2x *bp) /* Iterate over all VFs and invoke state transition for VFs with * 'in-progress' slow-path operations */ - DP(BNX2X_MSG_IOV, "searching for pending vf operations\n"); + DP_AND((BNX2X_MSG_IOV | BNX2X_MSG_SP), + "searching for pending vf operations\n"); for_each_vf(bp, i) { struct bnx2x_virtf *vf = BP_VF(bp, i); @@ -3046,6 +3063,83 @@ int bnx2x_vfop_rss_cmd(struct bnx2x *bp, return -ENOMEM; } +/* VFOP tpa update, send update on all queues */ +static void bnx2x_vfop_tpa(struct bnx2x *bp, struct bnx2x_virtf *vf) +{ + struct bnx2x_vfop *vfop = bnx2x_vfop_cur(bp, vf); + struct bnx2x_vfop_args_tpa *tpa_args = &vfop->args.tpa; + enum bnx2x_vfop_tpa_state state = vfop->state; + + bnx2x_vfop_reset_wq(vf); + + if (vfop->rc < 0) + goto op_err; + + DP(BNX2X_MSG_IOV, "vf[%d:%d] STATE: %d\n", + vf->abs_vfid, tpa_args->qid, + state); + + switch (state) { + case BNX2X_VFOP_TPA_CONFIG: + + if (tpa_args->qid < vf_rxq_count(vf)) { + struct bnx2x_queue_state_params *qstate = + &vf->op_params.qstate; + + qstate->q_obj = &bnx2x_vfq(vf, tpa_args->qid, sp_obj); + + /* The only thing that changes for the ramrod params + * between calls is the sge_map + */ + qstate->params.update_tpa.sge_map = + tpa_args->sge_map[tpa_args->qid]; + + DP(BNX2X_MSG_IOV, "sge_addr[%d] %08x:%08x\n", + tpa_args->qid, + U64_HI(qstate->params.update_tpa.sge_map), + U64_LO(qstate->params.update_tpa.sge_map)); + qstate->cmd = BNX2X_Q_CMD_UPDATE_TPA; + vfop->rc = bnx2x_queue_state_change(bp, qstate); + + tpa_args->qid++; + bnx2x_vfop_finalize(vf, vfop->rc, VFOP_CONT); + } + vfop->state = BNX2X_VFOP_TPA_DONE; + vfop->rc = 0; + bnx2x_vfop_finalize(vf, vfop->rc, VFOP_DONE); +op_err: + BNX2X_ERR("TPA update error: rc %d\n", vfop->rc); +op_done: + case BNX2X_VFOP_TPA_DONE: + bnx2x_vfop_end(bp, vf, vfop); + return; + default: + bnx2x_vfop_default(state); + } +op_pending: + return; +} + +int bnx2x_vfop_tpa_cmd(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vfop_cmd *cmd, + struct vfpf_tpa_tlv *tpa_tlv) +{ + struct bnx2x_vfop *vfop = bnx2x_vfop_add(bp, vf); + + if (vfop) { + vfop->args.qx.qid = 0; /* loop */ + memcpy(&vfop->args.tpa.sge_map, + tpa_tlv->tpa_client_info.sge_addr, + sizeof(vfop->args.tpa.sge_map)); + bnx2x_vfop_opset(BNX2X_VFOP_TPA_CONFIG, + bnx2x_vfop_tpa, cmd->done); + return bnx2x_vfop_transition(bp, vf, bnx2x_vfop_tpa, + cmd->block); + } + return -ENOMEM; +} + /* VF release ~ VF close + VF release-resources * Release is the ultimate SW shutdown and is called whenever an * irrecoverable error is encountered. @@ -3074,16 +3168,6 @@ static inline void bnx2x_vf_get_sbdf(struct bnx2x *bp, *sbdf = vf->devfn | (vf->bus << 8); } -static inline void bnx2x_vf_get_bars(struct bnx2x *bp, struct bnx2x_virtf *vf, - struct bnx2x_vf_bar_info *bar_info) -{ - int n; - - bar_info->nr_bars = bp->vfdb->sriov.nres; - for (n = 0; n < bar_info->nr_bars; n++) - bar_info->bars[n] = vf->bars[n]; -} - void bnx2x_lock_vf_pf_channel(struct bnx2x *bp, struct bnx2x_virtf *vf, enum channel_tlvs tlv) { @@ -3405,13 +3489,13 @@ int bnx2x_get_vf_config(struct net_device *dev, int vfidx, ivi->spoofchk = 1; /*always enabled */ if (vf->state == VF_ENABLED) { /* mac and vlan are in vlan_mac objects */ - if (validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj))) + if (bnx2x_validate_vf_sp_objs(bp, vf, false)) { mac_obj->get_n_elements(bp, mac_obj, 1, (u8 *)&ivi->mac, 0, ETH_ALEN); - if (validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, vlan_obj))) vlan_obj->get_n_elements(bp, vlan_obj, 1, (u8 *)&ivi->vlan, 0, VLAN_HLEN); + } } else { /* mac */ if (bulletin->valid_bitmap & (1 << MAC_ADDR_VALID)) @@ -3485,17 +3569,17 @@ int bnx2x_set_vf_mac(struct net_device *dev, int vfidx, u8 *mac) q_logical_state == BNX2X_Q_LOGICAL_STATE_ACTIVE) { /* configure the mac in device on this vf's queue */ unsigned long ramrod_flags = 0; - struct bnx2x_vlan_mac_obj *mac_obj = - &bnx2x_leading_vfq(vf, mac_obj); + struct bnx2x_vlan_mac_obj *mac_obj; - rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj)); - if (rc) - return rc; + /* User should be able to see failure reason in system logs */ + if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) + return -EINVAL; /* must lock vfpf channel to protect against vf flows */ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_MAC); /* remove existing eth macs */ + mac_obj = &bnx2x_leading_vfq(vf, mac_obj); rc = bnx2x_del_all_macs(bp, mac_obj, BNX2X_ETH_MAC, true); if (rc) { BNX2X_ERR("failed to delete eth macs\n"); @@ -3569,17 +3653,16 @@ int bnx2x_set_vf_vlan(struct net_device *dev, int vfidx, u16 vlan, u8 qos) BNX2X_Q_LOGICAL_STATE_ACTIVE) return rc; - /* configure the vlan in device on this vf's queue */ - vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj); - rc = validate_vlan_mac(bp, &bnx2x_leading_vfq(vf, mac_obj)); - if (rc) - return rc; + /* User should be able to see error in system logs */ + if (!bnx2x_validate_vf_sp_objs(bp, vf, true)) + return -EINVAL; /* must lock vfpf channel to protect against vf flows */ bnx2x_lock_vf_pf_channel(bp, vf, CHANNEL_TLV_PF_SET_VLAN); /* remove existing vlans */ __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); + vlan_obj = &bnx2x_leading_vfq(vf, vlan_obj); rc = vlan_obj->delete_all(bp, vlan_obj, &vlan_mac_flags, &ramrod_flags); if (rc) { @@ -3736,13 +3819,9 @@ void bnx2x_timer_sriov(struct bnx2x *bp) bnx2x_sample_bulletin(bp); /* if channel is down we need to self destruct */ - if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN) { - smp_mb__before_clear_bit(); - set_bit(BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN, - &bp->sp_rtnl_state); - smp_mb__after_clear_bit(); - schedule_delayed_work(&bp->sp_rtnl_task, 0); - } + if (bp->old_bulletin.valid_bitmap & 1 << CHANNEL_DOWN) + bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_VFPF_CHANNEL_DOWN, + BNX2X_MSG_IOV); } void __iomem *bnx2x_vf_doorbells(struct bnx2x *bp) @@ -3756,12 +3835,16 @@ int bnx2x_vf_pci_alloc(struct bnx2x *bp) mutex_init(&bp->vf2pf_mutex); /* allocate vf2pf mailbox for vf to pf channel */ - BNX2X_PCI_ALLOC(bp->vf2pf_mbox, &bp->vf2pf_mbox_mapping, - sizeof(struct bnx2x_vf_mbx_msg)); + bp->vf2pf_mbox = BNX2X_PCI_ALLOC(&bp->vf2pf_mbox_mapping, + sizeof(struct bnx2x_vf_mbx_msg)); + if (!bp->vf2pf_mbox) + goto alloc_mem_err; /* allocate pf 2 vf bulletin board */ - BNX2X_PCI_ALLOC(bp->pf2vf_bulletin, &bp->pf2vf_bulletin_mapping, - sizeof(union pf_vf_bulletin)); + bp->pf2vf_bulletin = BNX2X_PCI_ALLOC(&bp->pf2vf_bulletin_mapping, + sizeof(union pf_vf_bulletin)); + if (!bp->pf2vf_bulletin) + goto alloc_mem_err; return 0; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index d9fcca1b5a9d..b1dc751c6175 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -83,6 +83,7 @@ struct bnx2x_vf_queue { u16 index; u16 sb_idx; bool is_leading; + bool sp_initialized; }; /* struct bnx2x_vfop_qctor_params - prepare queue construction parameters: @@ -100,6 +101,7 @@ union bnx2x_vfop_params { struct bnx2x_mcast_ramrod_params mcast; struct bnx2x_config_rss_params rss; struct bnx2x_vfop_qctor_params qctor; + struct bnx2x_queue_state_params qstate; }; /* forward */ @@ -166,6 +168,11 @@ struct bnx2x_vfop_args_filters { atomic_t *credit; /* non NULL means 'don't consume credit' */ }; +struct bnx2x_vfop_args_tpa { + int qid; + dma_addr_t sge_map[PFVF_MAX_QUEUES_PER_VF]; +}; + union bnx2x_vfop_args { struct bnx2x_vfop_args_mcast mc_list; struct bnx2x_vfop_args_qctor qctor; @@ -173,6 +180,7 @@ union bnx2x_vfop_args { struct bnx2x_vfop_args_defvlan defvlan; struct bnx2x_vfop_args_qx qx; struct bnx2x_vfop_args_filters filters; + struct bnx2x_vfop_args_tpa tpa; }; struct bnx2x_vfop { @@ -704,6 +712,11 @@ int bnx2x_vfop_rss_cmd(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vfop_cmd *cmd); +int bnx2x_vfop_tpa_cmd(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vfop_cmd *cmd, + struct vfpf_tpa_tlv *tpa_tlv); + /* VF release ~ VF close + VF release-resources * * Release is the ultimate SW shutdown and is called whenever an diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 3fa6c2a2a5a9..1117ed7776b6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -548,6 +548,7 @@ static void bnx2x_leading_vfq_init(struct bnx2x *bp, struct bnx2x_virtf *vf, vf->leading_rss = cl_id; q->is_leading = true; + q->sp_initialized = true; } /* ask the pf to open a queue for the vf */ @@ -1159,7 +1160,8 @@ static void bnx2x_vf_mbx_acquire_resp(struct bnx2x *bp, struct bnx2x_virtf *vf, resp->pfdev_info.db_size = bp->db_size; resp->pfdev_info.indices_per_sb = HC_SB_MAX_INDICES_E2; resp->pfdev_info.pf_cap = (PFVF_CAP_RSS | - /* PFVF_CAP_DHC |*/ PFVF_CAP_TPA); + PFVF_CAP_TPA | + PFVF_CAP_TPA_UPDATE); bnx2x_fill_fw_str(bp, resp->pfdev_info.fw_ver, sizeof(resp->pfdev_info.fw_ver)); @@ -1694,16 +1696,12 @@ static int bnx2x_vfop_mbx_qfilters_cmd(struct bnx2x *bp, return -ENOMEM; } -static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, - struct bnx2x_virtf *vf, - struct bnx2x_vf_mbx *mbx) +static int bnx2x_filters_validate_mac(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct vfpf_set_q_filters_tlv *filters) { - struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters; struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index); - struct bnx2x_vfop_cmd cmd = { - .done = bnx2x_vf_mbx_resp, - .block = false, - }; + int rc = 0; /* if a mac was already set for this VF via the set vf mac ndo, we only * accept mac configurations of that mac. Why accept them at all? @@ -1716,6 +1714,7 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, BNX2X_ERR("VF[%d] requested the addition of multiple macs after set_vf_mac ndo was called\n", vf->abs_vfid); vf->op_rc = -EPERM; + rc = -EPERM; goto response; } @@ -1726,9 +1725,22 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, vf->abs_vfid); vf->op_rc = -EPERM; + rc = -EPERM; goto response; } } + +response: + return rc; +} + +static int bnx2x_filters_validate_vlan(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct vfpf_set_q_filters_tlv *filters) +{ + struct pf_vf_bulletin_content *bulletin = BP_VF_BULLETIN(bp, vf->index); + int rc = 0; + /* if vlan was set by hypervisor we don't allow guest to config vlan */ if (bulletin->valid_bitmap & 1 << VLAN_VALID) { int i; @@ -1740,13 +1752,36 @@ static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, BNX2X_ERR("VF[%d] attempted to configure vlan but one was already set by Hypervisor. Aborting request\n", vf->abs_vfid); vf->op_rc = -EPERM; + rc = -EPERM; goto response; } } } /* verify vf_qid */ - if (filters->vf_qid > vf_rxq_count(vf)) + if (filters->vf_qid > vf_rxq_count(vf)) { + rc = -EPERM; + goto response; + } + +response: + return rc; +} + +static void bnx2x_vf_mbx_set_q_filters(struct bnx2x *bp, + struct bnx2x_virtf *vf, + struct bnx2x_vf_mbx *mbx) +{ + struct vfpf_set_q_filters_tlv *filters = &mbx->msg->req.set_q_filters; + struct bnx2x_vfop_cmd cmd = { + .done = bnx2x_vf_mbx_resp, + .block = false, + }; + + if (bnx2x_filters_validate_mac(bp, vf, filters)) + goto response; + + if (bnx2x_filters_validate_vlan(bp, vf, filters)) goto response; DP(BNX2X_MSG_IOV, "VF[%d] Q_FILTERS: queue[%d]\n", @@ -1877,6 +1912,75 @@ mbx_resp: bnx2x_vf_mbx_resp(bp, vf); } +static int bnx2x_validate_tpa_params(struct bnx2x *bp, + struct vfpf_tpa_tlv *tpa_tlv) +{ + int rc = 0; + + if (tpa_tlv->tpa_client_info.max_sges_for_packet > + U_ETH_MAX_SGES_FOR_PACKET) { + rc = -EINVAL; + BNX2X_ERR("TPA update: max_sges received %d, max is %d\n", + tpa_tlv->tpa_client_info.max_sges_for_packet, + U_ETH_MAX_SGES_FOR_PACKET); + } + + if (tpa_tlv->tpa_client_info.max_tpa_queues > MAX_AGG_QS(bp)) { + rc = -EINVAL; + BNX2X_ERR("TPA update: max_tpa_queues received %d, max is %d\n", + tpa_tlv->tpa_client_info.max_tpa_queues, + MAX_AGG_QS(bp)); + } + + return rc; +} + +static void bnx2x_vf_mbx_update_tpa(struct bnx2x *bp, struct bnx2x_virtf *vf, + struct bnx2x_vf_mbx *mbx) +{ + struct bnx2x_vfop_cmd cmd = { + .done = bnx2x_vf_mbx_resp, + .block = false, + }; + struct bnx2x_queue_update_tpa_params *vf_op_params = + &vf->op_params.qstate.params.update_tpa; + struct vfpf_tpa_tlv *tpa_tlv = &mbx->msg->req.update_tpa; + + memset(vf_op_params, 0, sizeof(*vf_op_params)); + + if (bnx2x_validate_tpa_params(bp, tpa_tlv)) + goto mbx_resp; + + vf_op_params->complete_on_both_clients = + tpa_tlv->tpa_client_info.complete_on_both_clients; + vf_op_params->dont_verify_thr = + tpa_tlv->tpa_client_info.dont_verify_thr; + vf_op_params->max_agg_sz = + tpa_tlv->tpa_client_info.max_agg_size; + vf_op_params->max_sges_pkt = + tpa_tlv->tpa_client_info.max_sges_for_packet; + vf_op_params->max_tpa_queues = + tpa_tlv->tpa_client_info.max_tpa_queues; + vf_op_params->sge_buff_sz = + tpa_tlv->tpa_client_info.sge_buff_size; + vf_op_params->sge_pause_thr_high = + tpa_tlv->tpa_client_info.sge_pause_thr_high; + vf_op_params->sge_pause_thr_low = + tpa_tlv->tpa_client_info.sge_pause_thr_low; + vf_op_params->tpa_mode = + tpa_tlv->tpa_client_info.tpa_mode; + vf_op_params->update_ipv4 = + tpa_tlv->tpa_client_info.update_ipv4; + vf_op_params->update_ipv6 = + tpa_tlv->tpa_client_info.update_ipv6; + + vf->op_rc = bnx2x_vfop_tpa_cmd(bp, vf, &cmd, tpa_tlv); + +mbx_resp: + if (vf->op_rc) + bnx2x_vf_mbx_resp(bp, vf); +} + /* dispatch request */ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf, struct bnx2x_vf_mbx *mbx) @@ -1916,6 +2020,9 @@ static void bnx2x_vf_mbx_request(struct bnx2x *bp, struct bnx2x_virtf *vf, case CHANNEL_TLV_UPDATE_RSS: bnx2x_vf_mbx_update_rss(bp, vf, mbx); return; + case CHANNEL_TLV_UPDATE_TPA: + bnx2x_vf_mbx_update_tpa(bp, vf, mbx); + return; } } else { diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h index 208568bc7a71..c922b81170e5 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h @@ -162,6 +162,7 @@ struct pfvf_acquire_resp_tlv { #define PFVF_CAP_RSS 0x00000001 #define PFVF_CAP_DHC 0x00000002 #define PFVF_CAP_TPA 0x00000004 +#define PFVF_CAP_TPA_UPDATE 0x00000008 char fw_ver[32]; u16 db_size; u8 indices_per_sb; @@ -303,6 +304,25 @@ struct vfpf_set_q_filters_tlv { u32 rx_mask; /* see mask constants at the top of the file */ }; +struct vfpf_tpa_tlv { + struct vfpf_first_tlv first_tlv; + + struct vf_pf_tpa_client_info { + aligned_u64 sge_addr[PFVF_MAX_QUEUES_PER_VF]; + u8 update_ipv4; + u8 update_ipv6; + u8 max_tpa_queues; + u8 max_sges_for_packet; + u8 complete_on_both_clients; + u8 dont_verify_thr; + u8 tpa_mode; + u16 sge_buff_size; + u16 max_agg_size; + u16 sge_pause_thr_low; + u16 sge_pause_thr_high; + } tpa_client_info; +}; + /* close VF (disable VF) */ struct vfpf_close_tlv { struct vfpf_first_tlv first_tlv; @@ -331,6 +351,7 @@ union vfpf_tlvs { struct vfpf_set_q_filters_tlv set_q_filters; struct vfpf_release_tlv release; struct vfpf_rss_tlv update_rss; + struct vfpf_tpa_tlv update_tpa; struct channel_list_end_tlv list_end; struct tlv_buffer_size tlv_buf_size; }; @@ -405,6 +426,7 @@ enum channel_tlvs { CHANNEL_TLV_PF_SET_VLAN, CHANNEL_TLV_UPDATE_RSS, CHANNEL_TLV_PHYS_PORT_ID, + CHANNEL_TLV_UPDATE_TPA, CHANNEL_TLV_MAX }; diff --git a/drivers/net/ethernet/broadcom/genet/Makefile b/drivers/net/ethernet/broadcom/genet/Makefile new file mode 100644 index 000000000000..31f55a90a197 --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/Makefile @@ -0,0 +1,2 @@ +obj-$(CONFIG_BCMGENET) += genet.o +genet-objs := bcmgenet.o bcmmii.o diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c new file mode 100644 index 000000000000..72ce6e8115fa --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -0,0 +1,2578 @@ +/* + * Broadcom GENET (Gigabit Ethernet) controller driver + * + * Copyright (c) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#define pr_fmt(fmt) "bcmgenet: " fmt + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/types.h> +#include <linux/fcntl.h> +#include <linux/interrupt.h> +#include <linux/string.h> +#include <linux/if_ether.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/pm.h> +#include <linux/clk.h> +#include <linux/version.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_irq.h> +#include <linux/of_net.h> +#include <linux/of_platform.h> +#include <net/arp.h> + +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/netdevice.h> +#include <linux/inetdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/phy.h> + +#include <asm/unaligned.h> + +#include "bcmgenet.h" + +/* Maximum number of hardware queues, downsized if needed */ +#define GENET_MAX_MQ_CNT 4 + +/* Default highest priority queue for multi queue support */ +#define GENET_Q0_PRIORITY 0 + +#define GENET_DEFAULT_BD_CNT \ + (TOTAL_DESC - priv->hw_params->tx_queues * priv->hw_params->bds_cnt) + +#define RX_BUF_LENGTH 2048 +#define SKB_ALIGNMENT 32 + +/* Tx/Rx DMA register offset, skip 256 descriptors */ +#define WORDS_PER_BD(p) (p->hw_params->words_per_bd) +#define DMA_DESC_SIZE (WORDS_PER_BD(priv) * sizeof(u32)) + +#define GENET_TDMA_REG_OFF (priv->hw_params->tdma_offset + \ + TOTAL_DESC * DMA_DESC_SIZE) + +#define GENET_RDMA_REG_OFF (priv->hw_params->rdma_offset + \ + TOTAL_DESC * DMA_DESC_SIZE) + +static inline void dmadesc_set_length_status(struct bcmgenet_priv *priv, + void __iomem *d, u32 value) +{ + __raw_writel(value, d + DMA_DESC_LENGTH_STATUS); +} + +static inline u32 dmadesc_get_length_status(struct bcmgenet_priv *priv, + void __iomem *d) +{ + return __raw_readl(d + DMA_DESC_LENGTH_STATUS); +} + +static inline void dmadesc_set_addr(struct bcmgenet_priv *priv, + void __iomem *d, + dma_addr_t addr) +{ + __raw_writel(lower_32_bits(addr), d + DMA_DESC_ADDRESS_LO); + + /* Register writes to GISB bus can take couple hundred nanoseconds + * and are done for each packet, save these expensive writes unless + * the platform is explicitely configured for 64-bits/LPAE. + */ +#ifdef CONFIG_PHYS_ADDR_T_64BIT + if (priv->hw_params->flags & GENET_HAS_40BITS) + __raw_writel(upper_32_bits(addr), d + DMA_DESC_ADDRESS_HI); +#endif +} + +/* Combined address + length/status setter */ +static inline void dmadesc_set(struct bcmgenet_priv *priv, + void __iomem *d, dma_addr_t addr, u32 val) +{ + dmadesc_set_length_status(priv, d, val); + dmadesc_set_addr(priv, d, addr); +} + +static inline dma_addr_t dmadesc_get_addr(struct bcmgenet_priv *priv, + void __iomem *d) +{ + dma_addr_t addr; + + addr = __raw_readl(d + DMA_DESC_ADDRESS_LO); + + /* Register writes to GISB bus can take couple hundred nanoseconds + * and are done for each packet, save these expensive writes unless + * the platform is explicitely configured for 64-bits/LPAE. + */ +#ifdef CONFIG_PHYS_ADDR_T_64BIT + if (priv->hw_params->flags & GENET_HAS_40BITS) + addr |= (u64)__raw_readl(d + DMA_DESC_ADDRESS_HI) << 32; +#endif + return addr; +} + +#define GENET_VER_FMT "%1d.%1d EPHY: 0x%04x" + +#define GENET_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | \ + NETIF_MSG_LINK) + +static inline u32 bcmgenet_rbuf_ctrl_get(struct bcmgenet_priv *priv) +{ + if (GENET_IS_V1(priv)) + return bcmgenet_rbuf_readl(priv, RBUF_FLUSH_CTRL_V1); + else + return bcmgenet_sys_readl(priv, SYS_RBUF_FLUSH_CTRL); +} + +static inline void bcmgenet_rbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val) +{ + if (GENET_IS_V1(priv)) + bcmgenet_rbuf_writel(priv, val, RBUF_FLUSH_CTRL_V1); + else + bcmgenet_sys_writel(priv, val, SYS_RBUF_FLUSH_CTRL); +} + +/* These macros are defined to deal with register map change + * between GENET1.1 and GENET2. Only those currently being used + * by driver are defined. + */ +static inline u32 bcmgenet_tbuf_ctrl_get(struct bcmgenet_priv *priv) +{ + if (GENET_IS_V1(priv)) + return bcmgenet_rbuf_readl(priv, TBUF_CTRL_V1); + else + return __raw_readl(priv->base + + priv->hw_params->tbuf_offset + TBUF_CTRL); +} + +static inline void bcmgenet_tbuf_ctrl_set(struct bcmgenet_priv *priv, u32 val) +{ + if (GENET_IS_V1(priv)) + bcmgenet_rbuf_writel(priv, val, TBUF_CTRL_V1); + else + __raw_writel(val, priv->base + + priv->hw_params->tbuf_offset + TBUF_CTRL); +} + +static inline u32 bcmgenet_bp_mc_get(struct bcmgenet_priv *priv) +{ + if (GENET_IS_V1(priv)) + return bcmgenet_rbuf_readl(priv, TBUF_BP_MC_V1); + else + return __raw_readl(priv->base + + priv->hw_params->tbuf_offset + TBUF_BP_MC); +} + +static inline void bcmgenet_bp_mc_set(struct bcmgenet_priv *priv, u32 val) +{ + if (GENET_IS_V1(priv)) + bcmgenet_rbuf_writel(priv, val, TBUF_BP_MC_V1); + else + __raw_writel(val, priv->base + + priv->hw_params->tbuf_offset + TBUF_BP_MC); +} + +/* RX/TX DMA register accessors */ +enum dma_reg { + DMA_RING_CFG = 0, + DMA_CTRL, + DMA_STATUS, + DMA_SCB_BURST_SIZE, + DMA_ARB_CTRL, + DMA_PRIORITY, + DMA_RING_PRIORITY, +}; + +static const u8 bcmgenet_dma_regs_v3plus[] = { + [DMA_RING_CFG] = 0x00, + [DMA_CTRL] = 0x04, + [DMA_STATUS] = 0x08, + [DMA_SCB_BURST_SIZE] = 0x0C, + [DMA_ARB_CTRL] = 0x2C, + [DMA_PRIORITY] = 0x30, + [DMA_RING_PRIORITY] = 0x38, +}; + +static const u8 bcmgenet_dma_regs_v2[] = { + [DMA_RING_CFG] = 0x00, + [DMA_CTRL] = 0x04, + [DMA_STATUS] = 0x08, + [DMA_SCB_BURST_SIZE] = 0x0C, + [DMA_ARB_CTRL] = 0x30, + [DMA_PRIORITY] = 0x34, + [DMA_RING_PRIORITY] = 0x3C, +}; + +static const u8 bcmgenet_dma_regs_v1[] = { + [DMA_CTRL] = 0x00, + [DMA_STATUS] = 0x04, + [DMA_SCB_BURST_SIZE] = 0x0C, + [DMA_ARB_CTRL] = 0x30, + [DMA_PRIORITY] = 0x34, + [DMA_RING_PRIORITY] = 0x3C, +}; + +/* Set at runtime once bcmgenet version is known */ +static const u8 *bcmgenet_dma_regs; + +static inline struct bcmgenet_priv *dev_to_priv(struct device *dev) +{ + return netdev_priv(dev_get_drvdata(dev)); +} + +static inline u32 bcmgenet_tdma_readl(struct bcmgenet_priv *priv, + enum dma_reg r) +{ + return __raw_readl(priv->base + GENET_TDMA_REG_OFF + + DMA_RINGS_SIZE + bcmgenet_dma_regs[r]); +} + +static inline void bcmgenet_tdma_writel(struct bcmgenet_priv *priv, + u32 val, enum dma_reg r) +{ + __raw_writel(val, priv->base + GENET_TDMA_REG_OFF + + DMA_RINGS_SIZE + bcmgenet_dma_regs[r]); +} + +static inline u32 bcmgenet_rdma_readl(struct bcmgenet_priv *priv, + enum dma_reg r) +{ + return __raw_readl(priv->base + GENET_RDMA_REG_OFF + + DMA_RINGS_SIZE + bcmgenet_dma_regs[r]); +} + +static inline void bcmgenet_rdma_writel(struct bcmgenet_priv *priv, + u32 val, enum dma_reg r) +{ + __raw_writel(val, priv->base + GENET_RDMA_REG_OFF + + DMA_RINGS_SIZE + bcmgenet_dma_regs[r]); +} + +/* RDMA/TDMA ring registers and accessors + * we merge the common fields and just prefix with T/D the registers + * having different meaning depending on the direction + */ +enum dma_ring_reg { + TDMA_READ_PTR = 0, + RDMA_WRITE_PTR = TDMA_READ_PTR, + TDMA_READ_PTR_HI, + RDMA_WRITE_PTR_HI = TDMA_READ_PTR_HI, + TDMA_CONS_INDEX, + RDMA_PROD_INDEX = TDMA_CONS_INDEX, + TDMA_PROD_INDEX, + RDMA_CONS_INDEX = TDMA_PROD_INDEX, + DMA_RING_BUF_SIZE, + DMA_START_ADDR, + DMA_START_ADDR_HI, + DMA_END_ADDR, + DMA_END_ADDR_HI, + DMA_MBUF_DONE_THRESH, + TDMA_FLOW_PERIOD, + RDMA_XON_XOFF_THRESH = TDMA_FLOW_PERIOD, + TDMA_WRITE_PTR, + RDMA_READ_PTR = TDMA_WRITE_PTR, + TDMA_WRITE_PTR_HI, + RDMA_READ_PTR_HI = TDMA_WRITE_PTR_HI +}; + +/* GENET v4 supports 40-bits pointer addressing + * for obvious reasons the LO and HI word parts + * are contiguous, but this offsets the other + * registers. + */ +static const u8 genet_dma_ring_regs_v4[] = { + [TDMA_READ_PTR] = 0x00, + [TDMA_READ_PTR_HI] = 0x04, + [TDMA_CONS_INDEX] = 0x08, + [TDMA_PROD_INDEX] = 0x0C, + [DMA_RING_BUF_SIZE] = 0x10, + [DMA_START_ADDR] = 0x14, + [DMA_START_ADDR_HI] = 0x18, + [DMA_END_ADDR] = 0x1C, + [DMA_END_ADDR_HI] = 0x20, + [DMA_MBUF_DONE_THRESH] = 0x24, + [TDMA_FLOW_PERIOD] = 0x28, + [TDMA_WRITE_PTR] = 0x2C, + [TDMA_WRITE_PTR_HI] = 0x30, +}; + +static const u8 genet_dma_ring_regs_v123[] = { + [TDMA_READ_PTR] = 0x00, + [TDMA_CONS_INDEX] = 0x04, + [TDMA_PROD_INDEX] = 0x08, + [DMA_RING_BUF_SIZE] = 0x0C, + [DMA_START_ADDR] = 0x10, + [DMA_END_ADDR] = 0x14, + [DMA_MBUF_DONE_THRESH] = 0x18, + [TDMA_FLOW_PERIOD] = 0x1C, + [TDMA_WRITE_PTR] = 0x20, +}; + +/* Set at runtime once GENET version is known */ +static const u8 *genet_dma_ring_regs; + +static inline u32 bcmgenet_tdma_ring_readl(struct bcmgenet_priv *priv, + unsigned int ring, + enum dma_ring_reg r) +{ + return __raw_readl(priv->base + GENET_TDMA_REG_OFF + + (DMA_RING_SIZE * ring) + + genet_dma_ring_regs[r]); +} + +static inline void bcmgenet_tdma_ring_writel(struct bcmgenet_priv *priv, + unsigned int ring, + u32 val, + enum dma_ring_reg r) +{ + __raw_writel(val, priv->base + GENET_TDMA_REG_OFF + + (DMA_RING_SIZE * ring) + + genet_dma_ring_regs[r]); +} + +static inline u32 bcmgenet_rdma_ring_readl(struct bcmgenet_priv *priv, + unsigned int ring, + enum dma_ring_reg r) +{ + return __raw_readl(priv->base + GENET_RDMA_REG_OFF + + (DMA_RING_SIZE * ring) + + genet_dma_ring_regs[r]); +} + +static inline void bcmgenet_rdma_ring_writel(struct bcmgenet_priv *priv, + unsigned int ring, + u32 val, + enum dma_ring_reg r) +{ + __raw_writel(val, priv->base + GENET_RDMA_REG_OFF + + (DMA_RING_SIZE * ring) + + genet_dma_ring_regs[r]); +} + +static int bcmgenet_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!priv->phydev) + return -ENODEV; + + return phy_ethtool_gset(priv->phydev, cmd); +} + +static int bcmgenet_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + if (!netif_running(dev)) + return -EINVAL; + + if (!priv->phydev) + return -ENODEV; + + return phy_ethtool_sset(priv->phydev, cmd); +} + +static int bcmgenet_set_rx_csum(struct net_device *dev, + netdev_features_t wanted) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 rbuf_chk_ctrl; + bool rx_csum_en; + + rx_csum_en = !!(wanted & NETIF_F_RXCSUM); + + rbuf_chk_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CHK_CTRL); + + /* enable rx checksumming */ + if (rx_csum_en) + rbuf_chk_ctrl |= RBUF_RXCHK_EN; + else + rbuf_chk_ctrl &= ~RBUF_RXCHK_EN; + priv->desc_rxchk_en = rx_csum_en; + bcmgenet_rbuf_writel(priv, rbuf_chk_ctrl, RBUF_CHK_CTRL); + + return 0; +} + +static int bcmgenet_set_tx_csum(struct net_device *dev, + netdev_features_t wanted) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + bool desc_64b_en; + u32 tbuf_ctrl, rbuf_ctrl; + + tbuf_ctrl = bcmgenet_tbuf_ctrl_get(priv); + rbuf_ctrl = bcmgenet_rbuf_readl(priv, RBUF_CTRL); + + desc_64b_en = !!(wanted & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)); + + /* enable 64 bytes descriptor in both directions (RBUF and TBUF) */ + if (desc_64b_en) { + tbuf_ctrl |= RBUF_64B_EN; + rbuf_ctrl |= RBUF_64B_EN; + } else { + tbuf_ctrl &= ~RBUF_64B_EN; + rbuf_ctrl &= ~RBUF_64B_EN; + } + priv->desc_64b_en = desc_64b_en; + + bcmgenet_tbuf_ctrl_set(priv, tbuf_ctrl); + bcmgenet_rbuf_writel(priv, rbuf_ctrl, RBUF_CTRL); + + return 0; +} + +static int bcmgenet_set_features(struct net_device *dev, + netdev_features_t features) +{ + netdev_features_t changed = features ^ dev->features; + netdev_features_t wanted = dev->wanted_features; + int ret = 0; + + if (changed & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) + ret = bcmgenet_set_tx_csum(dev, wanted); + if (changed & (NETIF_F_RXCSUM)) + ret = bcmgenet_set_rx_csum(dev, wanted); + + return ret; +} + +static u32 bcmgenet_get_msglevel(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + return priv->msg_enable; +} + +static void bcmgenet_set_msglevel(struct net_device *dev, u32 level) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + priv->msg_enable = level; +} + +/* standard ethtool support functions. */ +enum bcmgenet_stat_type { + BCMGENET_STAT_NETDEV = -1, + BCMGENET_STAT_MIB_RX, + BCMGENET_STAT_MIB_TX, + BCMGENET_STAT_RUNT, + BCMGENET_STAT_MISC, +}; + +struct bcmgenet_stats { + char stat_string[ETH_GSTRING_LEN]; + int stat_sizeof; + int stat_offset; + enum bcmgenet_stat_type type; + /* reg offset from UMAC base for misc counters */ + u16 reg_offset; +}; + +#define STAT_NETDEV(m) { \ + .stat_string = __stringify(m), \ + .stat_sizeof = sizeof(((struct net_device_stats *)0)->m), \ + .stat_offset = offsetof(struct net_device_stats, m), \ + .type = BCMGENET_STAT_NETDEV, \ +} + +#define STAT_GENET_MIB(str, m, _type) { \ + .stat_string = str, \ + .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->m), \ + .stat_offset = offsetof(struct bcmgenet_priv, m), \ + .type = _type, \ +} + +#define STAT_GENET_MIB_RX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_RX) +#define STAT_GENET_MIB_TX(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_MIB_TX) +#define STAT_GENET_RUNT(str, m) STAT_GENET_MIB(str, m, BCMGENET_STAT_RUNT) + +#define STAT_GENET_MISC(str, m, offset) { \ + .stat_string = str, \ + .stat_sizeof = sizeof(((struct bcmgenet_priv *)0)->m), \ + .stat_offset = offsetof(struct bcmgenet_priv, m), \ + .type = BCMGENET_STAT_MISC, \ + .reg_offset = offset, \ +} + + +/* There is a 0xC gap between the end of RX and beginning of TX stats and then + * between the end of TX stats and the beginning of the RX RUNT + */ +#define BCMGENET_STAT_OFFSET 0xc + +/* Hardware counters must be kept in sync because the order/offset + * is important here (order in structure declaration = order in hardware) + */ +static const struct bcmgenet_stats bcmgenet_gstrings_stats[] = { + /* general stats */ + STAT_NETDEV(rx_packets), + STAT_NETDEV(tx_packets), + STAT_NETDEV(rx_bytes), + STAT_NETDEV(tx_bytes), + STAT_NETDEV(rx_errors), + STAT_NETDEV(tx_errors), + STAT_NETDEV(rx_dropped), + STAT_NETDEV(tx_dropped), + STAT_NETDEV(multicast), + /* UniMAC RSV counters */ + STAT_GENET_MIB_RX("rx_64_octets", mib.rx.pkt_cnt.cnt_64), + STAT_GENET_MIB_RX("rx_65_127_oct", mib.rx.pkt_cnt.cnt_127), + STAT_GENET_MIB_RX("rx_128_255_oct", mib.rx.pkt_cnt.cnt_255), + STAT_GENET_MIB_RX("rx_256_511_oct", mib.rx.pkt_cnt.cnt_511), + STAT_GENET_MIB_RX("rx_512_1023_oct", mib.rx.pkt_cnt.cnt_1023), + STAT_GENET_MIB_RX("rx_1024_1518_oct", mib.rx.pkt_cnt.cnt_1518), + STAT_GENET_MIB_RX("rx_vlan_1519_1522_oct", mib.rx.pkt_cnt.cnt_mgv), + STAT_GENET_MIB_RX("rx_1522_2047_oct", mib.rx.pkt_cnt.cnt_2047), + STAT_GENET_MIB_RX("rx_2048_4095_oct", mib.rx.pkt_cnt.cnt_4095), + STAT_GENET_MIB_RX("rx_4096_9216_oct", mib.rx.pkt_cnt.cnt_9216), + STAT_GENET_MIB_RX("rx_pkts", mib.rx.pkt), + STAT_GENET_MIB_RX("rx_bytes", mib.rx.bytes), + STAT_GENET_MIB_RX("rx_multicast", mib.rx.mca), + STAT_GENET_MIB_RX("rx_broadcast", mib.rx.bca), + STAT_GENET_MIB_RX("rx_fcs", mib.rx.fcs), + STAT_GENET_MIB_RX("rx_control", mib.rx.cf), + STAT_GENET_MIB_RX("rx_pause", mib.rx.pf), + STAT_GENET_MIB_RX("rx_unknown", mib.rx.uo), + STAT_GENET_MIB_RX("rx_align", mib.rx.aln), + STAT_GENET_MIB_RX("rx_outrange", mib.rx.flr), + STAT_GENET_MIB_RX("rx_code", mib.rx.cde), + STAT_GENET_MIB_RX("rx_carrier", mib.rx.fcr), + STAT_GENET_MIB_RX("rx_oversize", mib.rx.ovr), + STAT_GENET_MIB_RX("rx_jabber", mib.rx.jbr), + STAT_GENET_MIB_RX("rx_mtu_err", mib.rx.mtue), + STAT_GENET_MIB_RX("rx_good_pkts", mib.rx.pok), + STAT_GENET_MIB_RX("rx_unicast", mib.rx.uc), + STAT_GENET_MIB_RX("rx_ppp", mib.rx.ppp), + STAT_GENET_MIB_RX("rx_crc", mib.rx.rcrc), + /* UniMAC TSV counters */ + STAT_GENET_MIB_TX("tx_64_octets", mib.tx.pkt_cnt.cnt_64), + STAT_GENET_MIB_TX("tx_65_127_oct", mib.tx.pkt_cnt.cnt_127), + STAT_GENET_MIB_TX("tx_128_255_oct", mib.tx.pkt_cnt.cnt_255), + STAT_GENET_MIB_TX("tx_256_511_oct", mib.tx.pkt_cnt.cnt_511), + STAT_GENET_MIB_TX("tx_512_1023_oct", mib.tx.pkt_cnt.cnt_1023), + STAT_GENET_MIB_TX("tx_1024_1518_oct", mib.tx.pkt_cnt.cnt_1518), + STAT_GENET_MIB_TX("tx_vlan_1519_1522_oct", mib.tx.pkt_cnt.cnt_mgv), + STAT_GENET_MIB_TX("tx_1522_2047_oct", mib.tx.pkt_cnt.cnt_2047), + STAT_GENET_MIB_TX("tx_2048_4095_oct", mib.tx.pkt_cnt.cnt_4095), + STAT_GENET_MIB_TX("tx_4096_9216_oct", mib.tx.pkt_cnt.cnt_9216), + STAT_GENET_MIB_TX("tx_pkts", mib.tx.pkts), + STAT_GENET_MIB_TX("tx_multicast", mib.tx.mca), + STAT_GENET_MIB_TX("tx_broadcast", mib.tx.bca), + STAT_GENET_MIB_TX("tx_pause", mib.tx.pf), + STAT_GENET_MIB_TX("tx_control", mib.tx.cf), + STAT_GENET_MIB_TX("tx_fcs_err", mib.tx.fcs), + STAT_GENET_MIB_TX("tx_oversize", mib.tx.ovr), + STAT_GENET_MIB_TX("tx_defer", mib.tx.drf), + STAT_GENET_MIB_TX("tx_excess_defer", mib.tx.edf), + STAT_GENET_MIB_TX("tx_single_col", mib.tx.scl), + STAT_GENET_MIB_TX("tx_multi_col", mib.tx.mcl), + STAT_GENET_MIB_TX("tx_late_col", mib.tx.lcl), + STAT_GENET_MIB_TX("tx_excess_col", mib.tx.ecl), + STAT_GENET_MIB_TX("tx_frags", mib.tx.frg), + STAT_GENET_MIB_TX("tx_total_col", mib.tx.ncl), + STAT_GENET_MIB_TX("tx_jabber", mib.tx.jbr), + STAT_GENET_MIB_TX("tx_bytes", mib.tx.bytes), + STAT_GENET_MIB_TX("tx_good_pkts", mib.tx.pok), + STAT_GENET_MIB_TX("tx_unicast", mib.tx.uc), + /* UniMAC RUNT counters */ + STAT_GENET_RUNT("rx_runt_pkts", mib.rx_runt_cnt), + STAT_GENET_RUNT("rx_runt_valid_fcs", mib.rx_runt_fcs), + STAT_GENET_RUNT("rx_runt_inval_fcs_align", mib.rx_runt_fcs_align), + STAT_GENET_RUNT("rx_runt_bytes", mib.rx_runt_bytes), + /* Misc UniMAC counters */ + STAT_GENET_MISC("rbuf_ovflow_cnt", mib.rbuf_ovflow_cnt, + UMAC_RBUF_OVFL_CNT), + STAT_GENET_MISC("rbuf_err_cnt", mib.rbuf_err_cnt, UMAC_RBUF_ERR_CNT), + STAT_GENET_MISC("mdf_err_cnt", mib.mdf_err_cnt, UMAC_MDF_ERR_CNT), +}; + +#define BCMGENET_STATS_LEN ARRAY_SIZE(bcmgenet_gstrings_stats) + +static void bcmgenet_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, "bcmgenet", sizeof(info->driver)); + strlcpy(info->version, "v2.0", sizeof(info->version)); + info->n_stats = BCMGENET_STATS_LEN; + +} + +static int bcmgenet_get_sset_count(struct net_device *dev, int string_set) +{ + switch (string_set) { + case ETH_SS_STATS: + return BCMGENET_STATS_LEN; + default: + return -EOPNOTSUPP; + } +} + +static void bcmgenet_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < BCMGENET_STATS_LEN; i++) { + memcpy(data + i * ETH_GSTRING_LEN, + bcmgenet_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + } + break; + } +} + +static void bcmgenet_update_mib_counters(struct bcmgenet_priv *priv) +{ + int i, j = 0; + + for (i = 0; i < BCMGENET_STATS_LEN; i++) { + const struct bcmgenet_stats *s; + u8 offset = 0; + u32 val = 0; + char *p; + + s = &bcmgenet_gstrings_stats[i]; + switch (s->type) { + case BCMGENET_STAT_NETDEV: + continue; + case BCMGENET_STAT_MIB_RX: + case BCMGENET_STAT_MIB_TX: + case BCMGENET_STAT_RUNT: + if (s->type != BCMGENET_STAT_MIB_RX) + offset = BCMGENET_STAT_OFFSET; + val = bcmgenet_umac_readl(priv, UMAC_MIB_START + + j + offset); + break; + case BCMGENET_STAT_MISC: + val = bcmgenet_umac_readl(priv, s->reg_offset); + /* clear if overflowed */ + if (val == ~0) + bcmgenet_umac_writel(priv, 0, s->reg_offset); + break; + } + + j += s->stat_sizeof; + p = (char *)priv + s->stat_offset; + *(u32 *)p = val; + } +} + +static void bcmgenet_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, + u64 *data) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + int i; + + if (netif_running(dev)) + bcmgenet_update_mib_counters(priv); + + for (i = 0; i < BCMGENET_STATS_LEN; i++) { + const struct bcmgenet_stats *s; + char *p; + + s = &bcmgenet_gstrings_stats[i]; + if (s->type == BCMGENET_STAT_NETDEV) + p = (char *)&dev->stats; + else + p = (char *)priv; + p += s->stat_offset; + data[i] = *(u32 *)p; + } +} + +/* standard ethtool support functions. */ +static struct ethtool_ops bcmgenet_ethtool_ops = { + .get_strings = bcmgenet_get_strings, + .get_sset_count = bcmgenet_get_sset_count, + .get_ethtool_stats = bcmgenet_get_ethtool_stats, + .get_settings = bcmgenet_get_settings, + .set_settings = bcmgenet_set_settings, + .get_drvinfo = bcmgenet_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_msglevel = bcmgenet_get_msglevel, + .set_msglevel = bcmgenet_set_msglevel, +}; + +/* Power down the unimac, based on mode. */ +static void bcmgenet_power_down(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) +{ + u32 reg; + + switch (mode) { + case GENET_POWER_CABLE_SENSE: + phy_detach(priv->phydev); + break; + + case GENET_POWER_PASSIVE: + /* Power down LED */ + bcmgenet_mii_reset(priv->dev); + if (priv->hw_params->flags & GENET_HAS_EXT) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg |= (EXT_PWR_DOWN_PHY | + EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_BIAS); + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + } + break; + default: + break; + } +} + +static void bcmgenet_power_up(struct bcmgenet_priv *priv, + enum bcmgenet_power_mode mode) +{ + u32 reg; + + if (!(priv->hw_params->flags & GENET_HAS_EXT)) + return; + + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + + switch (mode) { + case GENET_POWER_PASSIVE: + reg &= ~(EXT_PWR_DOWN_DLL | EXT_PWR_DOWN_PHY | + EXT_PWR_DOWN_BIAS); + /* fallthrough */ + case GENET_POWER_CABLE_SENSE: + /* enable APD */ + reg |= EXT_PWR_DN_EN_LD; + break; + default: + break; + } + + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + bcmgenet_mii_reset(priv->dev); +} + +/* ioctl handle special commands that are not present in ethtool. */ +static int bcmgenet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + int val = 0; + + if (!netif_running(dev)) + return -EINVAL; + + switch (cmd) { + case SIOCGMIIPHY: + case SIOCGMIIREG: + case SIOCSMIIREG: + if (!priv->phydev) + val = -ENODEV; + else + val = phy_mii_ioctl(priv->phydev, rq, cmd); + break; + + default: + val = -EINVAL; + break; + } + + return val; +} + +static struct enet_cb *bcmgenet_get_txcb(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring) +{ + struct enet_cb *tx_cb_ptr; + + tx_cb_ptr = ring->cbs; + tx_cb_ptr += ring->write_ptr - ring->cb_ptr; + tx_cb_ptr->bd_addr = priv->tx_bds + ring->write_ptr * DMA_DESC_SIZE; + /* Advancing local write pointer */ + if (ring->write_ptr == ring->end_ptr) + ring->write_ptr = ring->cb_ptr; + else + ring->write_ptr++; + + return tx_cb_ptr; +} + +/* Simple helper to free a control block's resources */ +static void bcmgenet_free_cb(struct enet_cb *cb) +{ + dev_kfree_skb_any(cb->skb); + cb->skb = NULL; + dma_unmap_addr_set(cb, dma_addr, 0); +} + +static inline void bcmgenet_tx_ring16_int_disable(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring) +{ + bcmgenet_intrl2_0_writel(priv, + UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, + INTRL2_CPU_MASK_SET); +} + +static inline void bcmgenet_tx_ring16_int_enable(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring) +{ + bcmgenet_intrl2_0_writel(priv, + UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE, + INTRL2_CPU_MASK_CLEAR); +} + +static inline void bcmgenet_tx_ring_int_enable(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring) +{ + bcmgenet_intrl2_1_writel(priv, + (1 << ring->index), INTRL2_CPU_MASK_CLEAR); + priv->int1_mask &= ~(1 << ring->index); +} + +static inline void bcmgenet_tx_ring_int_disable(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *ring) +{ + bcmgenet_intrl2_1_writel(priv, + (1 << ring->index), INTRL2_CPU_MASK_SET); + priv->int1_mask |= (1 << ring->index); +} + +/* Unlocked version of the reclaim routine */ +static void __bcmgenet_tx_reclaim(struct net_device *dev, + struct bcmgenet_tx_ring *ring) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + int last_tx_cn, last_c_index, num_tx_bds; + struct enet_cb *tx_cb_ptr; + unsigned int c_index; + + /* Compute how many buffers are transmited since last xmit call */ + c_index = bcmgenet_tdma_ring_readl(priv, ring->index, TDMA_CONS_INDEX); + + last_c_index = ring->c_index; + num_tx_bds = ring->size; + + c_index &= (num_tx_bds - 1); + + if (c_index >= last_c_index) + last_tx_cn = c_index - last_c_index; + else + last_tx_cn = num_tx_bds - last_c_index + c_index; + + netif_dbg(priv, tx_done, dev, + "%s ring=%d index=%d last_tx_cn=%d last_index=%d\n", + __func__, ring->index, + c_index, last_tx_cn, last_c_index); + + /* Reclaim transmitted buffers */ + while (last_tx_cn-- > 0) { + tx_cb_ptr = ring->cbs + last_c_index; + if (tx_cb_ptr->skb) { + dev->stats.tx_bytes += tx_cb_ptr->skb->len; + dma_unmap_single(&dev->dev, + dma_unmap_addr(tx_cb_ptr, dma_addr), + tx_cb_ptr->skb->len, + DMA_TO_DEVICE); + bcmgenet_free_cb(tx_cb_ptr); + } else if (dma_unmap_addr(tx_cb_ptr, dma_addr)) { + dev->stats.tx_bytes += + dma_unmap_len(tx_cb_ptr, dma_len); + dma_unmap_page(&dev->dev, + dma_unmap_addr(tx_cb_ptr, dma_addr), + dma_unmap_len(tx_cb_ptr, dma_len), + DMA_TO_DEVICE); + dma_unmap_addr_set(tx_cb_ptr, dma_addr, 0); + } + dev->stats.tx_packets++; + ring->free_bds += 1; + + last_c_index++; + last_c_index &= (num_tx_bds - 1); + } + + if (ring->free_bds > (MAX_SKB_FRAGS + 1)) + ring->int_disable(priv, ring); + + if (__netif_subqueue_stopped(dev, ring->queue)) + netif_wake_subqueue(dev, ring->queue); + + ring->c_index = c_index; +} + +static void bcmgenet_tx_reclaim(struct net_device *dev, + struct bcmgenet_tx_ring *ring) +{ + unsigned long flags; + + spin_lock_irqsave(&ring->lock, flags); + __bcmgenet_tx_reclaim(dev, ring); + spin_unlock_irqrestore(&ring->lock, flags); +} + +static void bcmgenet_tx_reclaim_all(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + int i; + + if (netif_is_multiqueue(dev)) { + for (i = 0; i < priv->hw_params->tx_queues; i++) + bcmgenet_tx_reclaim(dev, &priv->tx_rings[i]); + } + + bcmgenet_tx_reclaim(dev, &priv->tx_rings[DESC_INDEX]); +} + +/* Transmits a single SKB (either head of a fragment or a single SKB) + * caller must hold priv->lock + */ +static int bcmgenet_xmit_single(struct net_device *dev, + struct sk_buff *skb, + u16 dma_desc_flags, + struct bcmgenet_tx_ring *ring) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + struct enet_cb *tx_cb_ptr; + unsigned int skb_len; + dma_addr_t mapping; + u32 length_status; + int ret; + + tx_cb_ptr = bcmgenet_get_txcb(priv, ring); + + if (unlikely(!tx_cb_ptr)) + BUG(); + + tx_cb_ptr->skb = skb; + + skb_len = skb_headlen(skb) < ETH_ZLEN ? ETH_ZLEN : skb_headlen(skb); + + mapping = dma_map_single(kdev, skb->data, skb_len, DMA_TO_DEVICE); + ret = dma_mapping_error(kdev, mapping); + if (ret) { + netif_err(priv, tx_err, dev, "Tx DMA map failed\n"); + dev_kfree_skb(skb); + return ret; + } + + dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping); + dma_unmap_len_set(tx_cb_ptr, dma_len, skb->len); + length_status = (skb_len << DMA_BUFLENGTH_SHIFT) | dma_desc_flags | + (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT) | + DMA_TX_APPEND_CRC; + + if (skb->ip_summed == CHECKSUM_PARTIAL) + length_status |= DMA_TX_DO_CSUM; + + dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, length_status); + + /* Decrement total BD count and advance our write pointer */ + ring->free_bds -= 1; + ring->prod_index += 1; + ring->prod_index &= DMA_P_INDEX_MASK; + + return 0; +} + +/* Transmit a SKB fragement */ +static int bcmgenet_xmit_frag(struct net_device *dev, + skb_frag_t *frag, + u16 dma_desc_flags, + struct bcmgenet_tx_ring *ring) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct device *kdev = &priv->pdev->dev; + struct enet_cb *tx_cb_ptr; + dma_addr_t mapping; + int ret; + + tx_cb_ptr = bcmgenet_get_txcb(priv, ring); + + if (unlikely(!tx_cb_ptr)) + BUG(); + tx_cb_ptr->skb = NULL; + + mapping = skb_frag_dma_map(kdev, frag, 0, + skb_frag_size(frag), DMA_TO_DEVICE); + ret = dma_mapping_error(kdev, mapping); + if (ret) { + netif_err(priv, tx_err, dev, "%s: Tx DMA map failed\n", + __func__); + return ret; + } + + dma_unmap_addr_set(tx_cb_ptr, dma_addr, mapping); + dma_unmap_len_set(tx_cb_ptr, dma_len, frag->size); + + dmadesc_set(priv, tx_cb_ptr->bd_addr, mapping, + (frag->size << DMA_BUFLENGTH_SHIFT) | dma_desc_flags | + (priv->hw_params->qtag_mask << DMA_TX_QTAG_SHIFT)); + + + ring->free_bds -= 1; + ring->prod_index += 1; + ring->prod_index &= DMA_P_INDEX_MASK; + + return 0; +} + +/* Reallocate the SKB to put enough headroom in front of it and insert + * the transmit checksum offsets in the descriptors + */ +static int bcmgenet_put_tx_csum(struct net_device *dev, struct sk_buff *skb) +{ + struct status_64 *status = NULL; + struct sk_buff *new_skb; + u16 offset; + u8 ip_proto; + u16 ip_ver; + u32 tx_csum_info; + + if (unlikely(skb_headroom(skb) < sizeof(*status))) { + /* If 64 byte status block enabled, must make sure skb has + * enough headroom for us to insert 64B status block. + */ + new_skb = skb_realloc_headroom(skb, sizeof(*status)); + dev_kfree_skb(skb); + if (!new_skb) { + dev->stats.tx_errors++; + dev->stats.tx_dropped++; + return -ENOMEM; + } + skb = new_skb; + } + + skb_push(skb, sizeof(*status)); + status = (struct status_64 *)skb->data; + + if (skb->ip_summed == CHECKSUM_PARTIAL) { + ip_ver = htons(skb->protocol); + switch (ip_ver) { + case ETH_P_IP: + ip_proto = ip_hdr(skb)->protocol; + break; + case ETH_P_IPV6: + ip_proto = ipv6_hdr(skb)->nexthdr; + break; + default: + return 0; + } + + offset = skb_checksum_start_offset(skb) - sizeof(*status); + tx_csum_info = (offset << STATUS_TX_CSUM_START_SHIFT) | + (offset + skb->csum_offset); + + /* Set the length valid bit for TCP and UDP and just set + * the special UDP flag for IPv4, else just set to 0. + */ + if (ip_proto == IPPROTO_TCP || ip_proto == IPPROTO_UDP) { + tx_csum_info |= STATUS_TX_CSUM_LV; + if (ip_proto == IPPROTO_UDP && ip_ver == ETH_P_IP) + tx_csum_info |= STATUS_TX_CSUM_PROTO_UDP; + } else + tx_csum_info = 0; + + status->tx_csum_info = tx_csum_info; + } + + return 0; +} + +static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct bcmgenet_tx_ring *ring = NULL; + unsigned long flags = 0; + int nr_frags, index; + u16 dma_desc_flags; + int ret; + int i; + + index = skb_get_queue_mapping(skb); + /* Mapping strategy: + * queue_mapping = 0, unclassified, packet xmited through ring16 + * queue_mapping = 1, goes to ring 0. (highest priority queue + * queue_mapping = 2, goes to ring 1. + * queue_mapping = 3, goes to ring 2. + * queue_mapping = 4, goes to ring 3. + */ + if (index == 0) + index = DESC_INDEX; + else + index -= 1; + + if ((index != DESC_INDEX) && (index > priv->hw_params->tx_queues - 1)) { + netdev_err(dev, "%s: queue_mapping %d is invalid\n", + __func__, skb_get_queue_mapping(skb)); + dev->stats.tx_errors++; + dev->stats.tx_dropped++; + ret = NETDEV_TX_OK; + goto out; + } + nr_frags = skb_shinfo(skb)->nr_frags; + ring = &priv->tx_rings[index]; + + spin_lock_irqsave(&ring->lock, flags); + if (ring->free_bds <= nr_frags + 1) { + netif_stop_subqueue(dev, ring->queue); + netdev_err(dev, "%s: tx ring %d full when queue %d awake\n", + __func__, index, ring->queue); + ret = NETDEV_TX_BUSY; + goto out; + } + + /* set the SKB transmit checksum */ + if (priv->desc_64b_en) { + ret = bcmgenet_put_tx_csum(dev, skb); + if (ret) { + ret = NETDEV_TX_OK; + goto out; + } + } + + dma_desc_flags = DMA_SOP; + if (nr_frags == 0) + dma_desc_flags |= DMA_EOP; + + /* Transmit single SKB or head of fragment list */ + ret = bcmgenet_xmit_single(dev, skb, dma_desc_flags, ring); + if (ret) { + ret = NETDEV_TX_OK; + goto out; + } + + /* xmit fragment */ + for (i = 0; i < nr_frags; i++) { + ret = bcmgenet_xmit_frag(dev, + &skb_shinfo(skb)->frags[i], + (i == nr_frags - 1) ? DMA_EOP : 0, ring); + if (ret) { + ret = NETDEV_TX_OK; + goto out; + } + } + + /* we kept a software copy of how much we should advance the TDMA + * producer index, now write it down to the hardware + */ + bcmgenet_tdma_ring_writel(priv, ring->index, + ring->prod_index, TDMA_PROD_INDEX); + + if (ring->free_bds <= (MAX_SKB_FRAGS + 1)) { + netif_stop_subqueue(dev, ring->queue); + ring->int_enable(priv, ring); + } + +out: + spin_unlock_irqrestore(&ring->lock, flags); + + return ret; +} + + +static int bcmgenet_rx_refill(struct bcmgenet_priv *priv, + struct enet_cb *cb) +{ + struct device *kdev = &priv->pdev->dev; + struct sk_buff *skb; + dma_addr_t mapping; + int ret; + + skb = netdev_alloc_skb(priv->dev, + priv->rx_buf_len + SKB_ALIGNMENT); + if (!skb) + return -ENOMEM; + + /* a caller did not release this control block */ + WARN_ON(cb->skb != NULL); + cb->skb = skb; + mapping = dma_map_single(kdev, skb->data, + priv->rx_buf_len, DMA_FROM_DEVICE); + ret = dma_mapping_error(kdev, mapping); + if (ret) { + bcmgenet_free_cb(cb); + netif_err(priv, rx_err, priv->dev, + "%s DMA map failed\n", __func__); + return ret; + } + + dma_unmap_addr_set(cb, dma_addr, mapping); + /* assign packet, prepare descriptor, and advance pointer */ + + dmadesc_set_addr(priv, priv->rx_bd_assign_ptr, mapping); + + /* turn on the newly assigned BD for DMA to use */ + priv->rx_bd_assign_index++; + priv->rx_bd_assign_index &= (priv->num_rx_bds - 1); + + priv->rx_bd_assign_ptr = priv->rx_bds + + (priv->rx_bd_assign_index * DMA_DESC_SIZE); + + return 0; +} + +/* bcmgenet_desc_rx - descriptor based rx process. + * this could be called from bottom half, or from NAPI polling method. + */ +static unsigned int bcmgenet_desc_rx(struct bcmgenet_priv *priv, + unsigned int budget) +{ + struct net_device *dev = priv->dev; + struct enet_cb *cb; + struct sk_buff *skb; + u32 dma_length_status; + unsigned long dma_flag; + int len, err; + unsigned int rxpktprocessed = 0, rxpkttoprocess; + unsigned int p_index; + unsigned int chksum_ok = 0; + + p_index = bcmgenet_rdma_ring_readl(priv, + DESC_INDEX, RDMA_PROD_INDEX); + p_index &= DMA_P_INDEX_MASK; + + if (p_index < priv->rx_c_index) + rxpkttoprocess = (DMA_C_INDEX_MASK + 1) - + priv->rx_c_index + p_index; + else + rxpkttoprocess = p_index - priv->rx_c_index; + + netif_dbg(priv, rx_status, dev, + "RDMA: rxpkttoprocess=%d\n", rxpkttoprocess); + + while ((rxpktprocessed < rxpkttoprocess) && + (rxpktprocessed < budget)) { + + /* Unmap the packet contents such that we can use the + * RSV from the 64 bytes descriptor when enabled and save + * a 32-bits register read + */ + cb = &priv->rx_cbs[priv->rx_read_ptr]; + skb = cb->skb; + dma_unmap_single(&dev->dev, dma_unmap_addr(cb, dma_addr), + priv->rx_buf_len, DMA_FROM_DEVICE); + + if (!priv->desc_64b_en) { + dma_length_status = dmadesc_get_length_status(priv, + priv->rx_bds + + (priv->rx_read_ptr * + DMA_DESC_SIZE)); + } else { + struct status_64 *status; + status = (struct status_64 *)skb->data; + dma_length_status = status->length_status; + } + + /* DMA flags and length are still valid no matter how + * we got the Receive Status Vector (64B RSB or register) + */ + dma_flag = dma_length_status & 0xffff; + len = dma_length_status >> DMA_BUFLENGTH_SHIFT; + + netif_dbg(priv, rx_status, dev, + "%s: p_ind=%d c_ind=%d read_ptr=%d len_stat=0x%08x\n", + __func__, p_index, priv->rx_c_index, priv->rx_read_ptr, + dma_length_status); + + rxpktprocessed++; + + priv->rx_read_ptr++; + priv->rx_read_ptr &= (priv->num_rx_bds - 1); + + /* out of memory, just drop packets at the hardware level */ + if (unlikely(!skb)) { + dev->stats.rx_dropped++; + dev->stats.rx_errors++; + goto refill; + } + + if (unlikely(!(dma_flag & DMA_EOP) || !(dma_flag & DMA_SOP))) { + netif_err(priv, rx_status, dev, + "Droping fragmented packet!\n"); + dev->stats.rx_dropped++; + dev->stats.rx_errors++; + dev_kfree_skb_any(cb->skb); + cb->skb = NULL; + goto refill; + } + /* report errors */ + if (unlikely(dma_flag & (DMA_RX_CRC_ERROR | + DMA_RX_OV | + DMA_RX_NO | + DMA_RX_LG | + DMA_RX_RXER))) { + netif_err(priv, rx_status, dev, "dma_flag=0x%x\n", + (unsigned int)dma_flag); + if (dma_flag & DMA_RX_CRC_ERROR) + dev->stats.rx_crc_errors++; + if (dma_flag & DMA_RX_OV) + dev->stats.rx_over_errors++; + if (dma_flag & DMA_RX_NO) + dev->stats.rx_frame_errors++; + if (dma_flag & DMA_RX_LG) + dev->stats.rx_length_errors++; + dev->stats.rx_dropped++; + dev->stats.rx_errors++; + + /* discard the packet and advance consumer index.*/ + dev_kfree_skb_any(cb->skb); + cb->skb = NULL; + goto refill; + } /* error packet */ + + chksum_ok = (dma_flag & priv->dma_rx_chk_bit) && + priv->desc_rxchk_en; + + skb_put(skb, len); + if (priv->desc_64b_en) { + skb_pull(skb, 64); + len -= 64; + } + + if (likely(chksum_ok)) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + /* remove hardware 2bytes added for IP alignment */ + skb_pull(skb, 2); + len -= 2; + + if (priv->crc_fwd_en) { + skb_trim(skb, len - ETH_FCS_LEN); + len -= ETH_FCS_LEN; + } + + /*Finish setting up the received SKB and send it to the kernel*/ + skb->protocol = eth_type_trans(skb, priv->dev); + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + if (dma_flag & DMA_RX_MULT) + dev->stats.multicast++; + + /* Notify kernel */ + napi_gro_receive(&priv->napi, skb); + cb->skb = NULL; + netif_dbg(priv, rx_status, dev, "pushed up to kernel\n"); + + /* refill RX path on the current control block */ +refill: + err = bcmgenet_rx_refill(priv, cb); + if (err) + netif_err(priv, rx_err, dev, "Rx refill failed\n"); + } + + return rxpktprocessed; +} + +/* Assign skb to RX DMA descriptor. */ +static int bcmgenet_alloc_rx_buffers(struct bcmgenet_priv *priv) +{ + struct enet_cb *cb; + int ret = 0; + int i; + + netif_dbg(priv, hw, priv->dev, "%s:\n", __func__); + + /* loop here for each buffer needing assign */ + for (i = 0; i < priv->num_rx_bds; i++) { + cb = &priv->rx_cbs[priv->rx_bd_assign_index]; + if (cb->skb) + continue; + + /* set the DMA descriptor length once and for all + * it will only change if we support dynamically sizing + * priv->rx_buf_len, but we do not + */ + dmadesc_set_length_status(priv, priv->rx_bd_assign_ptr, + priv->rx_buf_len << DMA_BUFLENGTH_SHIFT); + + ret = bcmgenet_rx_refill(priv, cb); + if (ret) + break; + + } + + return ret; +} + +static void bcmgenet_free_rx_buffers(struct bcmgenet_priv *priv) +{ + struct enet_cb *cb; + int i; + + for (i = 0; i < priv->num_rx_bds; i++) { + cb = &priv->rx_cbs[i]; + + if (dma_unmap_addr(cb, dma_addr)) { + dma_unmap_single(&priv->dev->dev, + dma_unmap_addr(cb, dma_addr), + priv->rx_buf_len, DMA_FROM_DEVICE); + dma_unmap_addr_set(cb, dma_addr, 0); + } + + if (cb->skb) + bcmgenet_free_cb(cb); + } +} + +static int reset_umac(struct bcmgenet_priv *priv) +{ + struct device *kdev = &priv->pdev->dev; + unsigned int timeout = 0; + u32 reg; + + /* 7358a0/7552a0: bad default in RBUF_FLUSH_CTRL.umac_sw_rst */ + bcmgenet_rbuf_ctrl_set(priv, 0); + udelay(10); + + /* disable MAC while updating its registers */ + bcmgenet_umac_writel(priv, 0, UMAC_CMD); + + /* issue soft reset, wait for it to complete */ + bcmgenet_umac_writel(priv, CMD_SW_RESET, UMAC_CMD); + while (timeout++ < 1000) { + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + if (!(reg & CMD_SW_RESET)) + return 0; + + udelay(1); + } + + if (timeout == 1000) { + dev_err(kdev, + "timeout waiting for MAC to come out of resetn\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int init_umac(struct bcmgenet_priv *priv) +{ + struct device *kdev = &priv->pdev->dev; + int ret; + u32 reg, cpu_mask_clear; + + dev_dbg(&priv->pdev->dev, "bcmgenet: init_umac\n"); + + ret = reset_umac(priv); + if (ret) + return ret; + + bcmgenet_umac_writel(priv, 0, UMAC_CMD); + /* clear tx/rx counter */ + bcmgenet_umac_writel(priv, + MIB_RESET_RX | MIB_RESET_TX | MIB_RESET_RUNT, UMAC_MIB_CTRL); + bcmgenet_umac_writel(priv, 0, UMAC_MIB_CTRL); + + bcmgenet_umac_writel(priv, ENET_MAX_MTU_SIZE, UMAC_MAX_FRAME_LEN); + + /* init rx registers, enable ip header optimization */ + reg = bcmgenet_rbuf_readl(priv, RBUF_CTRL); + reg |= RBUF_ALIGN_2B; + bcmgenet_rbuf_writel(priv, reg, RBUF_CTRL); + + if (!GENET_IS_V1(priv) && !GENET_IS_V2(priv)) + bcmgenet_rbuf_writel(priv, 1, RBUF_TBUF_SIZE_CTRL); + + /* Mask all interrupts.*/ + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_MASK_SET); + bcmgenet_intrl2_0_writel(priv, 0xFFFFFFFF, INTRL2_CPU_CLEAR); + bcmgenet_intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR); + + cpu_mask_clear = UMAC_IRQ_RXDMA_BDONE; + + dev_dbg(kdev, "%s:Enabling RXDMA_BDONE interrupt\n", __func__); + + /* Monitor cable plug/unpluged event for internal PHY */ + if (phy_is_internal(priv->phydev)) + cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); + else if (priv->ext_phy) + cpu_mask_clear |= (UMAC_IRQ_LINK_DOWN | UMAC_IRQ_LINK_UP); + else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { + reg = bcmgenet_bp_mc_get(priv); + reg |= BIT(priv->hw_params->bp_in_en_shift); + + /* bp_mask: back pressure mask */ + if (netif_is_multiqueue(priv->dev)) + reg |= priv->hw_params->bp_in_mask; + else + reg &= ~priv->hw_params->bp_in_mask; + bcmgenet_bp_mc_set(priv, reg); + } + + /* Enable MDIO interrupts on GENET v3+ */ + if (priv->hw_params->flags & GENET_HAS_MDIO_INTR) + cpu_mask_clear |= UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR; + + bcmgenet_intrl2_0_writel(priv, cpu_mask_clear, + INTRL2_CPU_MASK_CLEAR); + + /* Enable rx/tx engine.*/ + dev_dbg(kdev, "done init umac\n"); + + return 0; +} + +/* Initialize all house-keeping variables for a TX ring, along + * with corresponding hardware registers + */ +static void bcmgenet_init_tx_ring(struct bcmgenet_priv *priv, + unsigned int index, unsigned int size, + unsigned int write_ptr, unsigned int end_ptr) +{ + struct bcmgenet_tx_ring *ring = &priv->tx_rings[index]; + u32 words_per_bd = WORDS_PER_BD(priv); + u32 flow_period_val = 0; + unsigned int first_bd; + + spin_lock_init(&ring->lock); + ring->index = index; + if (index == DESC_INDEX) { + ring->queue = 0; + ring->int_enable = bcmgenet_tx_ring16_int_enable; + ring->int_disable = bcmgenet_tx_ring16_int_disable; + } else { + ring->queue = index + 1; + ring->int_enable = bcmgenet_tx_ring_int_enable; + ring->int_disable = bcmgenet_tx_ring_int_disable; + } + ring->cbs = priv->tx_cbs + write_ptr; + ring->size = size; + ring->c_index = 0; + ring->free_bds = size; + ring->write_ptr = write_ptr; + ring->cb_ptr = write_ptr; + ring->end_ptr = end_ptr - 1; + ring->prod_index = 0; + + /* Set flow period for ring != 16 */ + if (index != DESC_INDEX) + flow_period_val = ENET_MAX_MTU_SIZE << 16; + + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_PROD_INDEX); + bcmgenet_tdma_ring_writel(priv, index, 0, TDMA_CONS_INDEX); + bcmgenet_tdma_ring_writel(priv, index, 1, DMA_MBUF_DONE_THRESH); + /* Disable rate control for now */ + bcmgenet_tdma_ring_writel(priv, index, flow_period_val, + TDMA_FLOW_PERIOD); + /* Unclassified traffic goes to ring 16 */ + bcmgenet_tdma_ring_writel(priv, index, + ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH), + DMA_RING_BUF_SIZE); + + first_bd = write_ptr; + + /* Set start and end address, read and write pointers */ + bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd, + DMA_START_ADDR); + bcmgenet_tdma_ring_writel(priv, index, first_bd * words_per_bd, + TDMA_READ_PTR); + bcmgenet_tdma_ring_writel(priv, index, first_bd, + TDMA_WRITE_PTR); + bcmgenet_tdma_ring_writel(priv, index, end_ptr * words_per_bd - 1, + DMA_END_ADDR); +} + +/* Initialize a RDMA ring */ +static int bcmgenet_init_rx_ring(struct bcmgenet_priv *priv, + unsigned int index, unsigned int size) +{ + u32 words_per_bd = WORDS_PER_BD(priv); + int ret; + + priv->num_rx_bds = TOTAL_DESC; + priv->rx_bds = priv->base + priv->hw_params->rdma_offset; + priv->rx_bd_assign_ptr = priv->rx_bds; + priv->rx_bd_assign_index = 0; + priv->rx_c_index = 0; + priv->rx_read_ptr = 0; + priv->rx_cbs = kzalloc(priv->num_rx_bds * sizeof(struct enet_cb), + GFP_KERNEL); + if (!priv->rx_cbs) + return -ENOMEM; + + ret = bcmgenet_alloc_rx_buffers(priv); + if (ret) { + kfree(priv->rx_cbs); + return ret; + } + + bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_WRITE_PTR); + bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_PROD_INDEX); + bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_CONS_INDEX); + bcmgenet_rdma_ring_writel(priv, index, + ((size << DMA_RING_SIZE_SHIFT) | RX_BUF_LENGTH), + DMA_RING_BUF_SIZE); + bcmgenet_rdma_ring_writel(priv, index, 0, DMA_START_ADDR); + bcmgenet_rdma_ring_writel(priv, index, + words_per_bd * size - 1, DMA_END_ADDR); + bcmgenet_rdma_ring_writel(priv, index, + (DMA_FC_THRESH_LO << DMA_XOFF_THRESHOLD_SHIFT) | + DMA_FC_THRESH_HI, RDMA_XON_XOFF_THRESH); + bcmgenet_rdma_ring_writel(priv, index, 0, RDMA_READ_PTR); + + return ret; +} + +/* init multi xmit queues, only available for GENET2+ + * the queue is partitioned as follows: + * + * queue 0 - 3 is priority based, each one has 32 descriptors, + * with queue 0 being the highest priority queue. + * + * queue 16 is the default tx queue with GENET_DEFAULT_BD_CNT + * descriptors: 256 - (number of tx queues * bds per queues) = 128 + * descriptors. + * + * The transmit control block pool is then partitioned as following: + * - tx_cbs[0...127] are for queue 16 + * - tx_ring_cbs[0] points to tx_cbs[128..159] + * - tx_ring_cbs[1] points to tx_cbs[160..191] + * - tx_ring_cbs[2] points to tx_cbs[192..223] + * - tx_ring_cbs[3] points to tx_cbs[224..255] + */ +static void bcmgenet_init_multiq(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned int i, dma_enable; + u32 reg, dma_ctrl, ring_cfg = 0, dma_priority = 0; + + if (!netif_is_multiqueue(dev)) { + netdev_warn(dev, "called with non multi queue aware HW\n"); + return; + } + + dma_ctrl = bcmgenet_tdma_readl(priv, DMA_CTRL); + dma_enable = dma_ctrl & DMA_EN; + dma_ctrl &= ~DMA_EN; + bcmgenet_tdma_writel(priv, dma_ctrl, DMA_CTRL); + + /* Enable strict priority arbiter mode */ + bcmgenet_tdma_writel(priv, DMA_ARBITER_SP, DMA_ARB_CTRL); + + for (i = 0; i < priv->hw_params->tx_queues; i++) { + /* first 64 tx_cbs are reserved for default tx queue + * (ring 16) + */ + bcmgenet_init_tx_ring(priv, i, priv->hw_params->bds_cnt, + i * priv->hw_params->bds_cnt, + (i + 1) * priv->hw_params->bds_cnt); + + /* Configure ring as decriptor ring and setup priority */ + ring_cfg |= 1 << i; + dma_priority |= ((GENET_Q0_PRIORITY + i) << + (GENET_MAX_MQ_CNT + 1) * i); + dma_ctrl |= 1 << (i + DMA_RING_BUF_EN_SHIFT); + } + + /* Enable rings */ + reg = bcmgenet_tdma_readl(priv, DMA_RING_CFG); + reg |= ring_cfg; + bcmgenet_tdma_writel(priv, reg, DMA_RING_CFG); + + /* Use configured rings priority and set ring #16 priority */ + reg = bcmgenet_tdma_readl(priv, DMA_RING_PRIORITY); + reg |= ((GENET_Q0_PRIORITY + priv->hw_params->tx_queues) << 20); + reg |= dma_priority; + bcmgenet_tdma_writel(priv, reg, DMA_PRIORITY); + + /* Configure ring as descriptor ring and re-enable DMA if enabled */ + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg |= dma_ctrl; + if (dma_enable) + reg |= DMA_EN; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); +} + +static void bcmgenet_fini_dma(struct bcmgenet_priv *priv) +{ + int i; + + /* disable DMA */ + bcmgenet_rdma_writel(priv, 0, DMA_CTRL); + bcmgenet_tdma_writel(priv, 0, DMA_CTRL); + + for (i = 0; i < priv->num_tx_bds; i++) { + if (priv->tx_cbs[i].skb != NULL) { + dev_kfree_skb(priv->tx_cbs[i].skb); + priv->tx_cbs[i].skb = NULL; + } + } + + bcmgenet_free_rx_buffers(priv); + kfree(priv->rx_cbs); + kfree(priv->tx_cbs); +} + +/* init_edma: Initialize DMA control register */ +static int bcmgenet_init_dma(struct bcmgenet_priv *priv) +{ + int ret; + + netif_dbg(priv, hw, priv->dev, "bcmgenet: init_edma\n"); + + /* by default, enable ring 16 (descriptor based) */ + ret = bcmgenet_init_rx_ring(priv, DESC_INDEX, TOTAL_DESC); + if (ret) { + netdev_err(priv->dev, "failed to initialize RX ring\n"); + return ret; + } + + /* init rDma */ + bcmgenet_rdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); + + /* Init tDma */ + bcmgenet_tdma_writel(priv, DMA_MAX_BURST_LENGTH, DMA_SCB_BURST_SIZE); + + /* Initialize commont TX ring structures */ + priv->tx_bds = priv->base + priv->hw_params->tdma_offset; + priv->num_tx_bds = TOTAL_DESC; + priv->tx_cbs = kzalloc(priv->num_tx_bds * sizeof(struct enet_cb), + GFP_KERNEL); + if (!priv->tx_cbs) { + bcmgenet_fini_dma(priv); + return -ENOMEM; + } + + /* initialize multi xmit queue */ + bcmgenet_init_multiq(priv->dev); + + /* initialize special ring 16 */ + bcmgenet_init_tx_ring(priv, DESC_INDEX, GENET_DEFAULT_BD_CNT, + priv->hw_params->tx_queues * priv->hw_params->bds_cnt, + TOTAL_DESC); + + return 0; +} + +/* NAPI polling method*/ +static int bcmgenet_poll(struct napi_struct *napi, int budget) +{ + struct bcmgenet_priv *priv = container_of(napi, + struct bcmgenet_priv, napi); + unsigned int work_done; + + /* tx reclaim */ + bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]); + + work_done = bcmgenet_desc_rx(priv, budget); + + /* Advancing our consumer index*/ + priv->rx_c_index += work_done; + priv->rx_c_index &= DMA_C_INDEX_MASK; + bcmgenet_rdma_ring_writel(priv, DESC_INDEX, + priv->rx_c_index, RDMA_CONS_INDEX); + if (work_done < budget) { + napi_complete(napi); + bcmgenet_intrl2_0_writel(priv, + UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_CLEAR); + } + + return work_done; +} + +/* Interrupt bottom half */ +static void bcmgenet_irq_task(struct work_struct *work) +{ + struct bcmgenet_priv *priv = container_of( + work, struct bcmgenet_priv, bcmgenet_irq_work); + + netif_dbg(priv, intr, priv->dev, "%s\n", __func__); + + /* Link UP/DOWN event */ + if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && + (priv->irq0_stat & (UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN))) { + phy_mac_interrupt(priv->phydev, + priv->irq0_stat & UMAC_IRQ_LINK_UP); + priv->irq0_stat &= ~(UMAC_IRQ_LINK_UP|UMAC_IRQ_LINK_DOWN); + } +} + +/* bcmgenet_isr1: interrupt handler for ring buffer. */ +static irqreturn_t bcmgenet_isr1(int irq, void *dev_id) +{ + struct bcmgenet_priv *priv = dev_id; + unsigned int index; + + /* Save irq status for bottom-half processing. */ + priv->irq1_stat = + bcmgenet_intrl2_1_readl(priv, INTRL2_CPU_STAT) & + ~priv->int1_mask; + /* clear inerrupts*/ + bcmgenet_intrl2_1_writel(priv, priv->irq1_stat, INTRL2_CPU_CLEAR); + + netif_dbg(priv, intr, priv->dev, + "%s: IRQ=0x%x\n", __func__, priv->irq1_stat); + /* Check the MBDONE interrupts. + * packet is done, reclaim descriptors + */ + if (priv->irq1_stat & 0x0000ffff) { + index = 0; + for (index = 0; index < 16; index++) { + if (priv->irq1_stat & (1 << index)) + bcmgenet_tx_reclaim(priv->dev, + &priv->tx_rings[index]); + } + } + return IRQ_HANDLED; +} + +/* bcmgenet_isr0: Handle various interrupts. */ +static irqreturn_t bcmgenet_isr0(int irq, void *dev_id) +{ + struct bcmgenet_priv *priv = dev_id; + + /* Save irq status for bottom-half processing. */ + priv->irq0_stat = + bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_STAT) & + ~bcmgenet_intrl2_0_readl(priv, INTRL2_CPU_MASK_STATUS); + /* clear inerrupts*/ + bcmgenet_intrl2_0_writel(priv, priv->irq0_stat, INTRL2_CPU_CLEAR); + + netif_dbg(priv, intr, priv->dev, + "IRQ=0x%x\n", priv->irq0_stat); + + if (priv->irq0_stat & (UMAC_IRQ_RXDMA_BDONE | UMAC_IRQ_RXDMA_PDONE)) { + /* We use NAPI(software interrupt throttling, if + * Rx Descriptor throttling is not used. + * Disable interrupt, will be enabled in the poll method. + */ + if (likely(napi_schedule_prep(&priv->napi))) { + bcmgenet_intrl2_0_writel(priv, + UMAC_IRQ_RXDMA_BDONE, INTRL2_CPU_MASK_SET); + __napi_schedule(&priv->napi); + } + } + if (priv->irq0_stat & + (UMAC_IRQ_TXDMA_BDONE | UMAC_IRQ_TXDMA_PDONE)) { + /* Tx reclaim */ + bcmgenet_tx_reclaim(priv->dev, &priv->tx_rings[DESC_INDEX]); + } + if (priv->irq0_stat & (UMAC_IRQ_PHY_DET_R | + UMAC_IRQ_PHY_DET_F | + UMAC_IRQ_LINK_UP | + UMAC_IRQ_LINK_DOWN | + UMAC_IRQ_HFB_SM | + UMAC_IRQ_HFB_MM | + UMAC_IRQ_MPD_R)) { + /* all other interested interrupts handled in bottom half */ + schedule_work(&priv->bcmgenet_irq_work); + } + + if ((priv->hw_params->flags & GENET_HAS_MDIO_INTR) && + priv->irq0_stat & (UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR)) { + priv->irq0_stat &= ~(UMAC_IRQ_MDIO_DONE | UMAC_IRQ_MDIO_ERROR); + wake_up(&priv->wq); + } + + return IRQ_HANDLED; +} + +static void bcmgenet_umac_reset(struct bcmgenet_priv *priv) +{ + u32 reg; + + reg = bcmgenet_rbuf_ctrl_get(priv); + reg |= BIT(1); + bcmgenet_rbuf_ctrl_set(priv, reg); + udelay(10); + + reg &= ~BIT(1); + bcmgenet_rbuf_ctrl_set(priv, reg); + udelay(10); +} + +static void bcmgenet_set_hw_addr(struct bcmgenet_priv *priv, + unsigned char *addr) +{ + bcmgenet_umac_writel(priv, (addr[0] << 24) | (addr[1] << 16) | + (addr[2] << 8) | addr[3], UMAC_MAC0); + bcmgenet_umac_writel(priv, (addr[4] << 8) | addr[5], UMAC_MAC1); +} + +static int bcmgenet_wol_resume(struct bcmgenet_priv *priv) +{ + int ret; + + /* From WOL-enabled suspend, switch to regular clock */ + clk_disable(priv->clk_wol); + /* init umac registers to synchronize s/w with h/w */ + ret = init_umac(priv); + if (ret) + return ret; + + phy_init_hw(priv->phydev); + /* Speed settings must be restored */ + bcmgenet_mii_config(priv->dev); + + return 0; +} + +/* Returns a reusable dma control register value */ +static u32 bcmgenet_dma_disable(struct bcmgenet_priv *priv) +{ + u32 reg; + u32 dma_ctrl; + + /* disable DMA */ + dma_ctrl = 1 << (DESC_INDEX + DMA_RING_BUF_EN_SHIFT) | DMA_EN; + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~dma_ctrl; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + bcmgenet_umac_writel(priv, 1, UMAC_TX_FLUSH); + udelay(10); + bcmgenet_umac_writel(priv, 0, UMAC_TX_FLUSH); + + return dma_ctrl; +} + +static void bcmgenet_enable_dma(struct bcmgenet_priv *priv, u32 dma_ctrl) +{ + u32 reg; + + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg |= dma_ctrl; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg |= dma_ctrl; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); +} + +static int bcmgenet_open(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + unsigned long dma_ctrl; + u32 reg; + int ret; + + netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); + + /* Turn on the clock */ + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); + + /* take MAC out of reset */ + bcmgenet_umac_reset(priv); + + ret = init_umac(priv); + if (ret) + goto err_clk_disable; + + /* disable ethernet MAC while updating its registers */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~(CMD_TX_EN | CMD_RX_EN); + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + bcmgenet_set_hw_addr(priv, dev->dev_addr); + + if (priv->wol_enabled) { + ret = bcmgenet_wol_resume(priv); + if (ret) + return ret; + } + + if (phy_is_internal(priv->phydev)) { + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg |= EXT_ENERGY_DET_MASK; + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + } + + /* Disable RX/TX DMA and flush TX queues */ + dma_ctrl = bcmgenet_dma_disable(priv); + + /* Reinitialize TDMA and RDMA and SW housekeeping */ + ret = bcmgenet_init_dma(priv); + if (ret) { + netdev_err(dev, "failed to initialize DMA\n"); + goto err_fini_dma; + } + + /* Always enable ring 16 - descriptor ring */ + bcmgenet_enable_dma(priv, dma_ctrl); + + ret = request_irq(priv->irq0, bcmgenet_isr0, IRQF_SHARED, + dev->name, priv); + if (ret < 0) { + netdev_err(dev, "can't request IRQ %d\n", priv->irq0); + goto err_fini_dma; + } + + ret = request_irq(priv->irq1, bcmgenet_isr1, IRQF_SHARED, + dev->name, priv); + if (ret < 0) { + netdev_err(dev, "can't request IRQ %d\n", priv->irq1); + goto err_irq0; + } + + /* Start the network engine */ + napi_enable(&priv->napi); + + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg |= (CMD_TX_EN | CMD_RX_EN); + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + /* Make sure we reflect the value of CRC_CMD_FWD */ + priv->crc_fwd_en = !!(reg & CMD_CRC_FWD); + + device_set_wakeup_capable(&dev->dev, 1); + + if (phy_is_internal(priv->phydev)) + bcmgenet_power_up(priv, GENET_POWER_PASSIVE); + + netif_tx_start_all_queues(dev); + + phy_start(priv->phydev); + + return 0; + +err_irq0: + free_irq(priv->irq0, dev); +err_fini_dma: + bcmgenet_fini_dma(priv); +err_clk_disable: + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + return ret; +} + +static int bcmgenet_dma_teardown(struct bcmgenet_priv *priv) +{ + int ret = 0; + int timeout = 0; + u32 reg; + + /* Disable TDMA to stop add more frames in TX DMA */ + reg = bcmgenet_tdma_readl(priv, DMA_CTRL); + reg &= ~DMA_EN; + bcmgenet_tdma_writel(priv, reg, DMA_CTRL); + + /* Check TDMA status register to confirm TDMA is disabled */ + while (timeout++ < DMA_TIMEOUT_VAL) { + reg = bcmgenet_tdma_readl(priv, DMA_STATUS); + if (reg & DMA_DISABLED) + break; + + udelay(1); + } + + if (timeout == DMA_TIMEOUT_VAL) { + netdev_warn(priv->dev, + "Timed out while disabling TX DMA\n"); + ret = -ETIMEDOUT; + } + + /* Wait 10ms for packet drain in both tx and rx dma */ + usleep_range(10000, 20000); + + /* Disable RDMA */ + reg = bcmgenet_rdma_readl(priv, DMA_CTRL); + reg &= ~DMA_EN; + bcmgenet_rdma_writel(priv, reg, DMA_CTRL); + + timeout = 0; + /* Check RDMA status register to confirm RDMA is disabled */ + while (timeout++ < DMA_TIMEOUT_VAL) { + reg = bcmgenet_rdma_readl(priv, DMA_STATUS); + if (reg & DMA_DISABLED) + break; + + udelay(1); + } + + if (timeout == DMA_TIMEOUT_VAL) { + netdev_warn(priv->dev, + "Timed out while disabling RX DMA\n"); + ret = -ETIMEDOUT; + } + + return ret; +} + +static int bcmgenet_close(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + int ret; + u32 reg; + + netif_dbg(priv, ifdown, dev, "bcmgenet_close\n"); + + phy_stop(priv->phydev); + + /* Disable MAC receive */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~CMD_RX_EN; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + netif_tx_stop_all_queues(dev); + + ret = bcmgenet_dma_teardown(priv); + if (ret) + return ret; + + /* Disable MAC transmit. TX DMA disabled have to done before this */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~CMD_TX_EN; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + + napi_disable(&priv->napi); + + /* tx reclaim */ + bcmgenet_tx_reclaim_all(dev); + bcmgenet_fini_dma(priv); + + free_irq(priv->irq0, priv); + free_irq(priv->irq1, priv); + + /* Wait for pending work items to complete - we are stopping + * the clock now. Since interrupts are disabled, no new work + * will be scheduled. + */ + cancel_work_sync(&priv->bcmgenet_irq_work); + + if (phy_is_internal(priv->phydev)) + bcmgenet_power_down(priv, GENET_POWER_PASSIVE); + + if (priv->wol_enabled) + clk_enable(priv->clk_wol); + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + + return 0; +} + +static void bcmgenet_timeout(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + netif_dbg(priv, tx_err, dev, "bcmgenet_timeout\n"); + + dev->trans_start = jiffies; + + dev->stats.tx_errors++; + + netif_tx_wake_all_queues(dev); +} + +#define MAX_MC_COUNT 16 + +static inline void bcmgenet_set_mdf_addr(struct bcmgenet_priv *priv, + unsigned char *addr, + int *i, + int *mc) +{ + u32 reg; + + bcmgenet_umac_writel(priv, + addr[0] << 8 | addr[1], UMAC_MDF_ADDR + (*i * 4)); + bcmgenet_umac_writel(priv, + addr[2] << 24 | addr[3] << 16 | + addr[4] << 8 | addr[5], + UMAC_MDF_ADDR + ((*i + 1) * 4)); + reg = bcmgenet_umac_readl(priv, UMAC_MDF_CTRL); + reg |= (1 << (MAX_MC_COUNT - *mc)); + bcmgenet_umac_writel(priv, reg, UMAC_MDF_CTRL); + *i += 2; + (*mc)++; +} + +static void bcmgenet_set_rx_mode(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct netdev_hw_addr *ha; + int i, mc; + u32 reg; + + netif_dbg(priv, hw, dev, "%s: %08X\n", __func__, dev->flags); + + /* Promiscous mode */ + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + if (dev->flags & IFF_PROMISC) { + reg |= CMD_PROMISC; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + bcmgenet_umac_writel(priv, 0, UMAC_MDF_CTRL); + return; + } else { + reg &= ~CMD_PROMISC; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + } + + /* UniMac doesn't support ALLMULTI */ + if (dev->flags & IFF_ALLMULTI) { + netdev_warn(dev, "ALLMULTI is not supported\n"); + return; + } + + /* update MDF filter */ + i = 0; + mc = 0; + /* Broadcast */ + bcmgenet_set_mdf_addr(priv, dev->broadcast, &i, &mc); + /* my own address.*/ + bcmgenet_set_mdf_addr(priv, dev->dev_addr, &i, &mc); + /* Unicast list*/ + if (netdev_uc_count(dev) > (MAX_MC_COUNT - mc)) + return; + + if (!netdev_uc_empty(dev)) + netdev_for_each_uc_addr(ha, dev) + bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc); + /* Multicast */ + if (netdev_mc_empty(dev) || netdev_mc_count(dev) >= (MAX_MC_COUNT - mc)) + return; + + netdev_for_each_mc_addr(ha, dev) + bcmgenet_set_mdf_addr(priv, ha->addr, &i, &mc); +} + +/* Set the hardware MAC address. */ +static int bcmgenet_set_mac_addr(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + /* Setting the MAC address at the hardware level is not possible + * without disabling the UniMAC RX/TX enable bits. + */ + if (netif_running(dev)) + return -EBUSY; + + ether_addr_copy(dev->dev_addr, addr->sa_data); + + return 0; +} + +static const struct net_device_ops bcmgenet_netdev_ops = { + .ndo_open = bcmgenet_open, + .ndo_stop = bcmgenet_close, + .ndo_start_xmit = bcmgenet_xmit, + .ndo_tx_timeout = bcmgenet_timeout, + .ndo_set_rx_mode = bcmgenet_set_rx_mode, + .ndo_set_mac_address = bcmgenet_set_mac_addr, + .ndo_do_ioctl = bcmgenet_ioctl, + .ndo_set_features = bcmgenet_set_features, +}; + +/* Array of GENET hardware parameters/characteristics */ +static struct bcmgenet_hw_params bcmgenet_hw_params[] = { + [GENET_V1] = { + .tx_queues = 0, + .rx_queues = 0, + .bds_cnt = 0, + .bp_in_en_shift = 16, + .bp_in_mask = 0xffff, + .hfb_filter_cnt = 16, + .qtag_mask = 0x1F, + .hfb_offset = 0x1000, + .rdma_offset = 0x2000, + .tdma_offset = 0x3000, + .words_per_bd = 2, + }, + [GENET_V2] = { + .tx_queues = 4, + .rx_queues = 4, + .bds_cnt = 32, + .bp_in_en_shift = 16, + .bp_in_mask = 0xffff, + .hfb_filter_cnt = 16, + .qtag_mask = 0x1F, + .tbuf_offset = 0x0600, + .hfb_offset = 0x1000, + .hfb_reg_offset = 0x2000, + .rdma_offset = 0x3000, + .tdma_offset = 0x4000, + .words_per_bd = 2, + .flags = GENET_HAS_EXT, + }, + [GENET_V3] = { + .tx_queues = 4, + .rx_queues = 4, + .bds_cnt = 32, + .bp_in_en_shift = 17, + .bp_in_mask = 0x1ffff, + .hfb_filter_cnt = 48, + .qtag_mask = 0x3F, + .tbuf_offset = 0x0600, + .hfb_offset = 0x8000, + .hfb_reg_offset = 0xfc00, + .rdma_offset = 0x10000, + .tdma_offset = 0x11000, + .words_per_bd = 2, + .flags = GENET_HAS_EXT | GENET_HAS_MDIO_INTR, + }, + [GENET_V4] = { + .tx_queues = 4, + .rx_queues = 4, + .bds_cnt = 32, + .bp_in_en_shift = 17, + .bp_in_mask = 0x1ffff, + .hfb_filter_cnt = 48, + .qtag_mask = 0x3F, + .tbuf_offset = 0x0600, + .hfb_offset = 0x8000, + .hfb_reg_offset = 0xfc00, + .rdma_offset = 0x2000, + .tdma_offset = 0x4000, + .words_per_bd = 3, + .flags = GENET_HAS_40BITS | GENET_HAS_EXT | GENET_HAS_MDIO_INTR, + }, +}; + +/* Infer hardware parameters from the detected GENET version */ +static void bcmgenet_set_hw_params(struct bcmgenet_priv *priv) +{ + struct bcmgenet_hw_params *params; + u32 reg; + u8 major; + + if (GENET_IS_V4(priv)) { + bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; + genet_dma_ring_regs = genet_dma_ring_regs_v4; + priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS; + priv->version = GENET_V4; + } else if (GENET_IS_V3(priv)) { + bcmgenet_dma_regs = bcmgenet_dma_regs_v3plus; + genet_dma_ring_regs = genet_dma_ring_regs_v123; + priv->dma_rx_chk_bit = DMA_RX_CHK_V3PLUS; + priv->version = GENET_V3; + } else if (GENET_IS_V2(priv)) { + bcmgenet_dma_regs = bcmgenet_dma_regs_v2; + genet_dma_ring_regs = genet_dma_ring_regs_v123; + priv->dma_rx_chk_bit = DMA_RX_CHK_V12; + priv->version = GENET_V2; + } else if (GENET_IS_V1(priv)) { + bcmgenet_dma_regs = bcmgenet_dma_regs_v1; + genet_dma_ring_regs = genet_dma_ring_regs_v123; + priv->dma_rx_chk_bit = DMA_RX_CHK_V12; + priv->version = GENET_V1; + } + + /* enum genet_version starts at 1 */ + priv->hw_params = &bcmgenet_hw_params[priv->version]; + params = priv->hw_params; + + /* Read GENET HW version */ + reg = bcmgenet_sys_readl(priv, SYS_REV_CTRL); + major = (reg >> 24 & 0x0f); + if (major == 5) + major = 4; + else if (major == 0) + major = 1; + if (major != priv->version) { + dev_err(&priv->pdev->dev, + "GENET version mismatch, got: %d, configured for: %d\n", + major, priv->version); + } + + /* Print the GENET core version */ + dev_info(&priv->pdev->dev, "GENET " GENET_VER_FMT, + major, (reg >> 16) & 0x0f, reg & 0xffff); + +#ifdef CONFIG_PHYS_ADDR_T_64BIT + if (!(params->flags & GENET_HAS_40BITS)) + pr_warn("GENET does not support 40-bits PA\n"); +#endif + + pr_debug("Configuration for version: %d\n" + "TXq: %1d, RXq: %1d, BDs: %1d\n" + "BP << en: %2d, BP msk: 0x%05x\n" + "HFB count: %2d, QTAQ msk: 0x%05x\n" + "TBUF: 0x%04x, HFB: 0x%04x, HFBreg: 0x%04x\n" + "RDMA: 0x%05x, TDMA: 0x%05x\n" + "Words/BD: %d\n", + priv->version, + params->tx_queues, params->rx_queues, params->bds_cnt, + params->bp_in_en_shift, params->bp_in_mask, + params->hfb_filter_cnt, params->qtag_mask, + params->tbuf_offset, params->hfb_offset, + params->hfb_reg_offset, + params->rdma_offset, params->tdma_offset, + params->words_per_bd); +} + +static const struct of_device_id bcmgenet_match[] = { + { .compatible = "brcm,genet-v1", .data = (void *)GENET_V1 }, + { .compatible = "brcm,genet-v2", .data = (void *)GENET_V2 }, + { .compatible = "brcm,genet-v3", .data = (void *)GENET_V3 }, + { .compatible = "brcm,genet-v4", .data = (void *)GENET_V4 }, + { }, +}; + +static int bcmgenet_probe(struct platform_device *pdev) +{ + struct device_node *dn = pdev->dev.of_node; + const struct of_device_id *of_id; + struct bcmgenet_priv *priv; + struct net_device *dev; + const void *macaddr; + struct resource *r; + int err = -EIO; + + /* Up to GENET_MAX_MQ_CNT + 1 TX queues and a single RX queue */ + dev = alloc_etherdev_mqs(sizeof(*priv), GENET_MAX_MQ_CNT + 1, 1); + if (!dev) { + dev_err(&pdev->dev, "can't allocate net device\n"); + return -ENOMEM; + } + + of_id = of_match_node(bcmgenet_match, dn); + if (!of_id) + return -EINVAL; + + priv = netdev_priv(dev); + priv->irq0 = platform_get_irq(pdev, 0); + priv->irq1 = platform_get_irq(pdev, 1); + if (!priv->irq0 || !priv->irq1) { + dev_err(&pdev->dev, "can't find IRQs\n"); + err = -EINVAL; + goto err; + } + + macaddr = of_get_mac_address(dn); + if (!macaddr) { + dev_err(&pdev->dev, "can't find MAC address\n"); + err = -EINVAL; + goto err; + } + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(priv->base)) { + err = PTR_ERR(priv->base); + goto err; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + dev_set_drvdata(&pdev->dev, dev); + ether_addr_copy(dev->dev_addr, macaddr); + dev->watchdog_timeo = 2 * HZ; + SET_ETHTOOL_OPS(dev, &bcmgenet_ethtool_ops); + dev->netdev_ops = &bcmgenet_netdev_ops; + netif_napi_add(dev, &priv->napi, bcmgenet_poll, 64); + + priv->msg_enable = netif_msg_init(-1, GENET_MSG_DEFAULT); + + /* Set hardware features */ + dev->hw_features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM | NETIF_F_RXCSUM; + + /* Set the needed headroom to account for any possible + * features enabling/disabling at runtime + */ + dev->needed_headroom += 64; + + netdev_boot_setup_check(dev); + + priv->dev = dev; + priv->pdev = pdev; + priv->version = (enum bcmgenet_version)of_id->data; + + bcmgenet_set_hw_params(priv); + + spin_lock_init(&priv->lock); + /* Mii wait queue */ + init_waitqueue_head(&priv->wq); + /* Always use RX_BUF_LENGTH (2KB) buffer for all chips */ + priv->rx_buf_len = RX_BUF_LENGTH; + INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); + + priv->clk = devm_clk_get(&priv->pdev->dev, "enet"); + if (IS_ERR(priv->clk)) + dev_warn(&priv->pdev->dev, "failed to get enet clock\n"); + + priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol"); + if (IS_ERR(priv->clk_wol)) + dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n"); + + if (!IS_ERR(priv->clk)) + clk_prepare_enable(priv->clk); + + err = reset_umac(priv); + if (err) + goto err_clk_disable; + + err = bcmgenet_mii_init(dev); + if (err) + goto err_clk_disable; + + /* setup number of real queues + 1 (GENET_V1 has 0 hardware queues + * just the ring 16 descriptor based TX + */ + netif_set_real_num_tx_queues(priv->dev, priv->hw_params->tx_queues + 1); + netif_set_real_num_rx_queues(priv->dev, priv->hw_params->rx_queues + 1); + + err = register_netdev(dev); + if (err) + goto err_clk_disable; + + /* Turn off the main clock, WOL clock is handled separately */ + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + + return err; + +err_clk_disable: + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); +err: + free_netdev(dev); + return err; +} + +static int bcmgenet_remove(struct platform_device *pdev) +{ + struct bcmgenet_priv *priv = dev_to_priv(&pdev->dev); + + dev_set_drvdata(&pdev->dev, NULL); + unregister_netdev(priv->dev); + bcmgenet_mii_exit(priv->dev); + free_netdev(priv->dev); + + return 0; +} + + +static struct platform_driver bcmgenet_driver = { + .probe = bcmgenet_probe, + .remove = bcmgenet_remove, + .driver = { + .name = "bcmgenet", + .owner = THIS_MODULE, + .of_match_table = bcmgenet_match, + }, +}; +module_platform_driver(bcmgenet_driver); + +MODULE_AUTHOR("Broadcom Corporation"); +MODULE_DESCRIPTION("Broadcom GENET Ethernet controller driver"); +MODULE_ALIAS("platform:bcmgenet"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h new file mode 100644 index 000000000000..a6758adefaab --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -0,0 +1,629 @@ +/* + * Copyright (c) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * +*/ +#ifndef __BCMGENET_H__ +#define __BCMGENET_H__ + +#include <linux/skbuff.h> +#include <linux/netdevice.h> +#include <linux/spinlock.h> +#include <linux/clk.h> +#include <linux/mii.h> +#include <linux/if_vlan.h> +#include <linux/phy.h> + +/* total number of Buffer Descriptors, same for Rx/Tx */ +#define TOTAL_DESC 256 + +/* which ring is descriptor based */ +#define DESC_INDEX 16 + +/* Body(1500) + EH_SIZE(14) + VLANTAG(4) + BRCMTAG(6) + FCS(4) = 1528. + * 1536 is multiple of 256 bytes + */ +#define ENET_BRCM_TAG_LEN 6 +#define ENET_PAD 8 +#define ENET_MAX_MTU_SIZE (ETH_DATA_LEN + ETH_HLEN + VLAN_HLEN + \ + ENET_BRCM_TAG_LEN + ETH_FCS_LEN + ENET_PAD) +#define DMA_MAX_BURST_LENGTH 0x10 + +/* misc. configuration */ +#define CLEAR_ALL_HFB 0xFF +#define DMA_FC_THRESH_HI (TOTAL_DESC >> 4) +#define DMA_FC_THRESH_LO 5 + +/* 64B receive/transmit status block */ +struct status_64 { + u32 length_status; /* length and peripheral status */ + u32 ext_status; /* Extended status*/ + u32 rx_csum; /* partial rx checksum */ + u32 unused1[9]; /* unused */ + u32 tx_csum_info; /* Tx checksum info. */ + u32 unused2[3]; /* unused */ +}; + +/* Rx status bits */ +#define STATUS_RX_EXT_MASK 0x1FFFFF +#define STATUS_RX_CSUM_MASK 0xFFFF +#define STATUS_RX_CSUM_OK 0x10000 +#define STATUS_RX_CSUM_FR 0x20000 +#define STATUS_RX_PROTO_TCP 0 +#define STATUS_RX_PROTO_UDP 1 +#define STATUS_RX_PROTO_ICMP 2 +#define STATUS_RX_PROTO_OTHER 3 +#define STATUS_RX_PROTO_MASK 3 +#define STATUS_RX_PROTO_SHIFT 18 +#define STATUS_FILTER_INDEX_MASK 0xFFFF +/* Tx status bits */ +#define STATUS_TX_CSUM_START_MASK 0X7FFF +#define STATUS_TX_CSUM_START_SHIFT 16 +#define STATUS_TX_CSUM_PROTO_UDP 0x8000 +#define STATUS_TX_CSUM_OFFSET_MASK 0x7FFF +#define STATUS_TX_CSUM_LV 0x80000000 + +/* DMA Descriptor */ +#define DMA_DESC_LENGTH_STATUS 0x00 /* in bytes of data in buffer */ +#define DMA_DESC_ADDRESS_LO 0x04 /* lower bits of PA */ +#define DMA_DESC_ADDRESS_HI 0x08 /* upper 32 bits of PA, GENETv4+ */ + +/* Rx/Tx common counter group */ +struct bcmgenet_pkt_counters { + u32 cnt_64; /* RO Received/Transmited 64 bytes packet */ + u32 cnt_127; /* RO Rx/Tx 127 bytes packet */ + u32 cnt_255; /* RO Rx/Tx 65-255 bytes packet */ + u32 cnt_511; /* RO Rx/Tx 256-511 bytes packet */ + u32 cnt_1023; /* RO Rx/Tx 512-1023 bytes packet */ + u32 cnt_1518; /* RO Rx/Tx 1024-1518 bytes packet */ + u32 cnt_mgv; /* RO Rx/Tx 1519-1522 good VLAN packet */ + u32 cnt_2047; /* RO Rx/Tx 1522-2047 bytes packet*/ + u32 cnt_4095; /* RO Rx/Tx 2048-4095 bytes packet*/ + u32 cnt_9216; /* RO Rx/Tx 4096-9216 bytes packet*/ +}; + +/* RSV, Receive Status Vector */ +struct bcmgenet_rx_counters { + struct bcmgenet_pkt_counters pkt_cnt; + u32 pkt; /* RO (0x428) Received pkt count*/ + u32 bytes; /* RO Received byte count */ + u32 mca; /* RO # of Received multicast pkt */ + u32 bca; /* RO # of Receive broadcast pkt */ + u32 fcs; /* RO # of Received FCS error */ + u32 cf; /* RO # of Received control frame pkt*/ + u32 pf; /* RO # of Received pause frame pkt */ + u32 uo; /* RO # of unknown op code pkt */ + u32 aln; /* RO # of alignment error count */ + u32 flr; /* RO # of frame length out of range count */ + u32 cde; /* RO # of code error pkt */ + u32 fcr; /* RO # of carrier sense error pkt */ + u32 ovr; /* RO # of oversize pkt*/ + u32 jbr; /* RO # of jabber count */ + u32 mtue; /* RO # of MTU error pkt*/ + u32 pok; /* RO # of Received good pkt */ + u32 uc; /* RO # of unicast pkt */ + u32 ppp; /* RO # of PPP pkt */ + u32 rcrc; /* RO (0x470),# of CRC match pkt */ +}; + +/* TSV, Transmit Status Vector */ +struct bcmgenet_tx_counters { + struct bcmgenet_pkt_counters pkt_cnt; + u32 pkts; /* RO (0x4a8) Transmited pkt */ + u32 mca; /* RO # of xmited multicast pkt */ + u32 bca; /* RO # of xmited broadcast pkt */ + u32 pf; /* RO # of xmited pause frame count */ + u32 cf; /* RO # of xmited control frame count */ + u32 fcs; /* RO # of xmited FCS error count */ + u32 ovr; /* RO # of xmited oversize pkt */ + u32 drf; /* RO # of xmited deferral pkt */ + u32 edf; /* RO # of xmited Excessive deferral pkt*/ + u32 scl; /* RO # of xmited single collision pkt */ + u32 mcl; /* RO # of xmited multiple collision pkt*/ + u32 lcl; /* RO # of xmited late collision pkt */ + u32 ecl; /* RO # of xmited excessive collision pkt*/ + u32 frg; /* RO # of xmited fragments pkt*/ + u32 ncl; /* RO # of xmited total collision count */ + u32 jbr; /* RO # of xmited jabber count*/ + u32 bytes; /* RO # of xmited byte count */ + u32 pok; /* RO # of xmited good pkt */ + u32 uc; /* RO (0x0x4f0)# of xmited unitcast pkt */ +}; + +struct bcmgenet_mib_counters { + struct bcmgenet_rx_counters rx; + struct bcmgenet_tx_counters tx; + u32 rx_runt_cnt; + u32 rx_runt_fcs; + u32 rx_runt_fcs_align; + u32 rx_runt_bytes; + u32 rbuf_ovflow_cnt; + u32 rbuf_err_cnt; + u32 mdf_err_cnt; +}; + +#define UMAC_HD_BKP_CTRL 0x004 +#define HD_FC_EN (1 << 0) +#define HD_FC_BKOFF_OK (1 << 1) +#define IPG_CONFIG_RX_SHIFT 2 +#define IPG_CONFIG_RX_MASK 0x1F + +#define UMAC_CMD 0x008 +#define CMD_TX_EN (1 << 0) +#define CMD_RX_EN (1 << 1) +#define UMAC_SPEED_10 0 +#define UMAC_SPEED_100 1 +#define UMAC_SPEED_1000 2 +#define UMAC_SPEED_2500 3 +#define CMD_SPEED_SHIFT 2 +#define CMD_SPEED_MASK 3 +#define CMD_PROMISC (1 << 4) +#define CMD_PAD_EN (1 << 5) +#define CMD_CRC_FWD (1 << 6) +#define CMD_PAUSE_FWD (1 << 7) +#define CMD_RX_PAUSE_IGNORE (1 << 8) +#define CMD_TX_ADDR_INS (1 << 9) +#define CMD_HD_EN (1 << 10) +#define CMD_SW_RESET (1 << 13) +#define CMD_LCL_LOOP_EN (1 << 15) +#define CMD_AUTO_CONFIG (1 << 22) +#define CMD_CNTL_FRM_EN (1 << 23) +#define CMD_NO_LEN_CHK (1 << 24) +#define CMD_RMT_LOOP_EN (1 << 25) +#define CMD_PRBL_EN (1 << 27) +#define CMD_TX_PAUSE_IGNORE (1 << 28) +#define CMD_TX_RX_EN (1 << 29) +#define CMD_RUNT_FILTER_DIS (1 << 30) + +#define UMAC_MAC0 0x00C +#define UMAC_MAC1 0x010 +#define UMAC_MAX_FRAME_LEN 0x014 + +#define UMAC_TX_FLUSH 0x334 + +#define UMAC_MIB_START 0x400 + +#define UMAC_MDIO_CMD 0x614 +#define MDIO_START_BUSY (1 << 29) +#define MDIO_READ_FAIL (1 << 28) +#define MDIO_RD (2 << 26) +#define MDIO_WR (1 << 26) +#define MDIO_PMD_SHIFT 21 +#define MDIO_PMD_MASK 0x1F +#define MDIO_REG_SHIFT 16 +#define MDIO_REG_MASK 0x1F + +#define UMAC_RBUF_OVFL_CNT 0x61C + +#define UMAC_MPD_CTRL 0x620 +#define MPD_EN (1 << 0) +#define MPD_PW_EN (1 << 27) +#define MPD_MSEQ_LEN_SHIFT 16 +#define MPD_MSEQ_LEN_MASK 0xFF + +#define UMAC_MPD_PW_MS 0x624 +#define UMAC_MPD_PW_LS 0x628 +#define UMAC_RBUF_ERR_CNT 0x634 +#define UMAC_MDF_ERR_CNT 0x638 +#define UMAC_MDF_CTRL 0x650 +#define UMAC_MDF_ADDR 0x654 +#define UMAC_MIB_CTRL 0x580 +#define MIB_RESET_RX (1 << 0) +#define MIB_RESET_RUNT (1 << 1) +#define MIB_RESET_TX (1 << 2) + +#define RBUF_CTRL 0x00 +#define RBUF_64B_EN (1 << 0) +#define RBUF_ALIGN_2B (1 << 1) +#define RBUF_BAD_DIS (1 << 2) + +#define RBUF_STATUS 0x0C +#define RBUF_STATUS_WOL (1 << 0) +#define RBUF_STATUS_MPD_INTR_ACTIVE (1 << 1) +#define RBUF_STATUS_ACPI_INTR_ACTIVE (1 << 2) + +#define RBUF_CHK_CTRL 0x14 +#define RBUF_RXCHK_EN (1 << 0) +#define RBUF_SKIP_FCS (1 << 4) + +#define RBUF_TBUF_SIZE_CTRL 0xb4 + +#define RBUF_HFB_CTRL_V1 0x38 +#define RBUF_HFB_FILTER_EN_SHIFT 16 +#define RBUF_HFB_FILTER_EN_MASK 0xffff0000 +#define RBUF_HFB_EN (1 << 0) +#define RBUF_HFB_256B (1 << 1) +#define RBUF_ACPI_EN (1 << 2) + +#define RBUF_HFB_LEN_V1 0x3C +#define RBUF_FLTR_LEN_MASK 0xFF +#define RBUF_FLTR_LEN_SHIFT 8 + +#define TBUF_CTRL 0x00 +#define TBUF_BP_MC 0x0C + +#define TBUF_CTRL_V1 0x80 +#define TBUF_BP_MC_V1 0xA0 + +#define HFB_CTRL 0x00 +#define HFB_FLT_ENABLE_V3PLUS 0x04 +#define HFB_FLT_LEN_V2 0x04 +#define HFB_FLT_LEN_V3PLUS 0x1C + +/* uniMac intrl2 registers */ +#define INTRL2_CPU_STAT 0x00 +#define INTRL2_CPU_SET 0x04 +#define INTRL2_CPU_CLEAR 0x08 +#define INTRL2_CPU_MASK_STATUS 0x0C +#define INTRL2_CPU_MASK_SET 0x10 +#define INTRL2_CPU_MASK_CLEAR 0x14 + +/* INTRL2 instance 0 definitions */ +#define UMAC_IRQ_SCB (1 << 0) +#define UMAC_IRQ_EPHY (1 << 1) +#define UMAC_IRQ_PHY_DET_R (1 << 2) +#define UMAC_IRQ_PHY_DET_F (1 << 3) +#define UMAC_IRQ_LINK_UP (1 << 4) +#define UMAC_IRQ_LINK_DOWN (1 << 5) +#define UMAC_IRQ_UMAC (1 << 6) +#define UMAC_IRQ_UMAC_TSV (1 << 7) +#define UMAC_IRQ_TBUF_UNDERRUN (1 << 8) +#define UMAC_IRQ_RBUF_OVERFLOW (1 << 9) +#define UMAC_IRQ_HFB_SM (1 << 10) +#define UMAC_IRQ_HFB_MM (1 << 11) +#define UMAC_IRQ_MPD_R (1 << 12) +#define UMAC_IRQ_RXDMA_MBDONE (1 << 13) +#define UMAC_IRQ_RXDMA_PDONE (1 << 14) +#define UMAC_IRQ_RXDMA_BDONE (1 << 15) +#define UMAC_IRQ_TXDMA_MBDONE (1 << 16) +#define UMAC_IRQ_TXDMA_PDONE (1 << 17) +#define UMAC_IRQ_TXDMA_BDONE (1 << 18) +/* Only valid for GENETv3+ */ +#define UMAC_IRQ_MDIO_DONE (1 << 23) +#define UMAC_IRQ_MDIO_ERROR (1 << 24) + +/* Register block offsets */ +#define GENET_SYS_OFF 0x0000 +#define GENET_GR_BRIDGE_OFF 0x0040 +#define GENET_EXT_OFF 0x0080 +#define GENET_INTRL2_0_OFF 0x0200 +#define GENET_INTRL2_1_OFF 0x0240 +#define GENET_RBUF_OFF 0x0300 +#define GENET_UMAC_OFF 0x0800 + +/* SYS block offsets and register definitions */ +#define SYS_REV_CTRL 0x00 +#define SYS_PORT_CTRL 0x04 +#define PORT_MODE_INT_EPHY 0 +#define PORT_MODE_INT_GPHY 1 +#define PORT_MODE_EXT_EPHY 2 +#define PORT_MODE_EXT_GPHY 3 +#define PORT_MODE_EXT_RVMII_25 (4 | BIT(4)) +#define PORT_MODE_EXT_RVMII_50 4 +#define LED_ACT_SOURCE_MAC (1 << 9) + +#define SYS_RBUF_FLUSH_CTRL 0x08 +#define SYS_TBUF_FLUSH_CTRL 0x0C +#define RBUF_FLUSH_CTRL_V1 0x04 + +/* Ext block register offsets and definitions */ +#define EXT_EXT_PWR_MGMT 0x00 +#define EXT_PWR_DOWN_BIAS (1 << 0) +#define EXT_PWR_DOWN_DLL (1 << 1) +#define EXT_PWR_DOWN_PHY (1 << 2) +#define EXT_PWR_DN_EN_LD (1 << 3) +#define EXT_ENERGY_DET (1 << 4) +#define EXT_IDDQ_FROM_PHY (1 << 5) +#define EXT_PHY_RESET (1 << 8) +#define EXT_ENERGY_DET_MASK (1 << 12) + +#define EXT_RGMII_OOB_CTRL 0x0C +#define RGMII_MODE_EN (1 << 0) +#define RGMII_LINK (1 << 4) +#define OOB_DISABLE (1 << 5) +#define ID_MODE_DIS (1 << 16) + +#define EXT_GPHY_CTRL 0x1C +#define EXT_CFG_IDDQ_BIAS (1 << 0) +#define EXT_CFG_PWR_DOWN (1 << 1) +#define EXT_GPHY_RESET (1 << 5) + +/* DMA rings size */ +#define DMA_RING_SIZE (0x40) +#define DMA_RINGS_SIZE (DMA_RING_SIZE * (DESC_INDEX + 1)) + +/* DMA registers common definitions */ +#define DMA_RW_POINTER_MASK 0x1FF +#define DMA_P_INDEX_DISCARD_CNT_MASK 0xFFFF +#define DMA_P_INDEX_DISCARD_CNT_SHIFT 16 +#define DMA_BUFFER_DONE_CNT_MASK 0xFFFF +#define DMA_BUFFER_DONE_CNT_SHIFT 16 +#define DMA_P_INDEX_MASK 0xFFFF +#define DMA_C_INDEX_MASK 0xFFFF + +/* DMA ring size register */ +#define DMA_RING_SIZE_MASK 0xFFFF +#define DMA_RING_SIZE_SHIFT 16 +#define DMA_RING_BUFFER_SIZE_MASK 0xFFFF + +/* DMA interrupt threshold register */ +#define DMA_INTR_THRESHOLD_MASK 0x00FF + +/* DMA XON/XOFF register */ +#define DMA_XON_THREHOLD_MASK 0xFFFF +#define DMA_XOFF_THRESHOLD_MASK 0xFFFF +#define DMA_XOFF_THRESHOLD_SHIFT 16 + +/* DMA flow period register */ +#define DMA_FLOW_PERIOD_MASK 0xFFFF +#define DMA_MAX_PKT_SIZE_MASK 0xFFFF +#define DMA_MAX_PKT_SIZE_SHIFT 16 + + +/* DMA control register */ +#define DMA_EN (1 << 0) +#define DMA_RING_BUF_EN_SHIFT 0x01 +#define DMA_RING_BUF_EN_MASK 0xFFFF +#define DMA_TSB_SWAP_EN (1 << 20) + +/* DMA status register */ +#define DMA_DISABLED (1 << 0) +#define DMA_DESC_RAM_INIT_BUSY (1 << 1) + +/* DMA SCB burst size register */ +#define DMA_SCB_BURST_SIZE_MASK 0x1F + +/* DMA activity vector register */ +#define DMA_ACTIVITY_VECTOR_MASK 0x1FFFF + +/* DMA backpressure mask register */ +#define DMA_BACKPRESSURE_MASK 0x1FFFF +#define DMA_PFC_ENABLE (1 << 31) + +/* DMA backpressure status register */ +#define DMA_BACKPRESSURE_STATUS_MASK 0x1FFFF + +/* DMA override register */ +#define DMA_LITTLE_ENDIAN_MODE (1 << 0) +#define DMA_REGISTER_MODE (1 << 1) + +/* DMA timeout register */ +#define DMA_TIMEOUT_MASK 0xFFFF +#define DMA_TIMEOUT_VAL 5000 /* micro seconds */ + +/* TDMA rate limiting control register */ +#define DMA_RATE_LIMIT_EN_MASK 0xFFFF + +/* TDMA arbitration control register */ +#define DMA_ARBITER_MODE_MASK 0x03 +#define DMA_RING_BUF_PRIORITY_MASK 0x1F +#define DMA_RING_BUF_PRIORITY_SHIFT 5 +#define DMA_RATE_ADJ_MASK 0xFF + +/* Tx/Rx Dma Descriptor common bits*/ +#define DMA_BUFLENGTH_MASK 0x0fff +#define DMA_BUFLENGTH_SHIFT 16 +#define DMA_OWN 0x8000 +#define DMA_EOP 0x4000 +#define DMA_SOP 0x2000 +#define DMA_WRAP 0x1000 +/* Tx specific Dma descriptor bits */ +#define DMA_TX_UNDERRUN 0x0200 +#define DMA_TX_APPEND_CRC 0x0040 +#define DMA_TX_OW_CRC 0x0020 +#define DMA_TX_DO_CSUM 0x0010 +#define DMA_TX_QTAG_SHIFT 7 + +/* Rx Specific Dma descriptor bits */ +#define DMA_RX_CHK_V3PLUS 0x8000 +#define DMA_RX_CHK_V12 0x1000 +#define DMA_RX_BRDCAST 0x0040 +#define DMA_RX_MULT 0x0020 +#define DMA_RX_LG 0x0010 +#define DMA_RX_NO 0x0008 +#define DMA_RX_RXER 0x0004 +#define DMA_RX_CRC_ERROR 0x0002 +#define DMA_RX_OV 0x0001 +#define DMA_RX_FI_MASK 0x001F +#define DMA_RX_FI_SHIFT 0x0007 +#define DMA_DESC_ALLOC_MASK 0x00FF + +#define DMA_ARBITER_RR 0x00 +#define DMA_ARBITER_WRR 0x01 +#define DMA_ARBITER_SP 0x02 + +struct enet_cb { + struct sk_buff *skb; + void __iomem *bd_addr; + DEFINE_DMA_UNMAP_ADDR(dma_addr); + DEFINE_DMA_UNMAP_LEN(dma_len); +}; + +/* power management mode */ +enum bcmgenet_power_mode { + GENET_POWER_CABLE_SENSE = 0, + GENET_POWER_PASSIVE, +}; + +struct bcmgenet_priv; + +/* We support both runtime GENET detection and compile-time + * to optimize code-paths for a given hardware + */ +enum bcmgenet_version { + GENET_V1 = 1, + GENET_V2, + GENET_V3, + GENET_V4 +}; + +#define GENET_IS_V1(p) ((p)->version == GENET_V1) +#define GENET_IS_V2(p) ((p)->version == GENET_V2) +#define GENET_IS_V3(p) ((p)->version == GENET_V3) +#define GENET_IS_V4(p) ((p)->version == GENET_V4) + +/* Hardware flags */ +#define GENET_HAS_40BITS (1 << 0) +#define GENET_HAS_EXT (1 << 1) +#define GENET_HAS_MDIO_INTR (1 << 2) + +/* BCMGENET hardware parameters, keep this structure nicely aligned + * since it is going to be used in hot paths + */ +struct bcmgenet_hw_params { + u8 tx_queues; + u8 rx_queues; + u8 bds_cnt; + u8 bp_in_en_shift; + u32 bp_in_mask; + u8 hfb_filter_cnt; + u8 qtag_mask; + u16 tbuf_offset; + u32 hfb_offset; + u32 hfb_reg_offset; + u32 rdma_offset; + u32 tdma_offset; + u32 words_per_bd; + u32 flags; +}; + +struct bcmgenet_tx_ring { + spinlock_t lock; /* ring lock */ + unsigned int index; /* ring index */ + unsigned int queue; /* queue index */ + struct enet_cb *cbs; /* tx ring buffer control block*/ + unsigned int size; /* size of each tx ring */ + unsigned int c_index; /* last consumer index of each ring*/ + unsigned int free_bds; /* # of free bds for each ring */ + unsigned int write_ptr; /* Tx ring write pointer SW copy */ + unsigned int prod_index; /* Tx ring producer index SW copy */ + unsigned int cb_ptr; /* Tx ring initial CB ptr */ + unsigned int end_ptr; /* Tx ring end CB ptr */ + void (*int_enable)(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *); + void (*int_disable)(struct bcmgenet_priv *priv, + struct bcmgenet_tx_ring *); +}; + +/* device context */ +struct bcmgenet_priv { + void __iomem *base; + enum bcmgenet_version version; + struct net_device *dev; + spinlock_t lock; + u32 int0_mask; + u32 int1_mask; + + /* NAPI for descriptor based rx */ + struct napi_struct napi ____cacheline_aligned; + + /* transmit variables */ + void __iomem *tx_bds; + struct enet_cb *tx_cbs; + unsigned int num_tx_bds; + + struct bcmgenet_tx_ring tx_rings[DESC_INDEX + 1]; + + /* receive variables */ + void __iomem *rx_bds; + void __iomem *rx_bd_assign_ptr; + int rx_bd_assign_index; + struct enet_cb *rx_cbs; + unsigned int num_rx_bds; + unsigned int rx_buf_len; + unsigned int rx_read_ptr; + unsigned int rx_c_index; + + /* other misc variables */ + struct bcmgenet_hw_params *hw_params; + + /* MDIO bus variables */ + wait_queue_head_t wq; + struct phy_device *phydev; + struct device_node *phy_dn; + struct mii_bus *mii_bus; + + /* PHY device variables */ + int old_duplex; + int old_link; + int old_pause; + phy_interface_t phy_interface; + int phy_addr; + int ext_phy; + + /* Interrupt variables */ + struct work_struct bcmgenet_irq_work; + int irq0; + int irq1; + unsigned int irq0_stat; + unsigned int irq1_stat; + + /* HW descriptors/checksum variables */ + bool desc_64b_en; + bool desc_rxchk_en; + bool crc_fwd_en; + + unsigned int dma_rx_chk_bit; + + u32 msg_enable; + + struct clk *clk; + struct platform_device *pdev; + + /* WOL */ + unsigned long wol_enabled; + struct clk *clk_wol; + u32 wolopts; + + struct bcmgenet_mib_counters mib; +}; + +#define GENET_IO_MACRO(name, offset) \ +static inline u32 bcmgenet_##name##_readl(struct bcmgenet_priv *priv, \ + u32 off) \ +{ \ + return __raw_readl(priv->base + offset + off); \ +} \ +static inline void bcmgenet_##name##_writel(struct bcmgenet_priv *priv, \ + u32 val, u32 off) \ +{ \ + __raw_writel(val, priv->base + offset + off); \ +} + +GENET_IO_MACRO(ext, GENET_EXT_OFF); +GENET_IO_MACRO(umac, GENET_UMAC_OFF); +GENET_IO_MACRO(sys, GENET_SYS_OFF); + +/* interrupt l2 registers accessors */ +GENET_IO_MACRO(intrl2_0, GENET_INTRL2_0_OFF); +GENET_IO_MACRO(intrl2_1, GENET_INTRL2_1_OFF); + +/* HFB register accessors */ +GENET_IO_MACRO(hfb, priv->hw_params->hfb_offset); + +/* GENET v2+ HFB control and filter len helpers */ +GENET_IO_MACRO(hfb_reg, priv->hw_params->hfb_reg_offset); + +/* RBUF register accessors */ +GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); + +/* MDIO routines */ +int bcmgenet_mii_init(struct net_device *dev); +int bcmgenet_mii_config(struct net_device *dev); +void bcmgenet_mii_exit(struct net_device *dev); +void bcmgenet_mii_reset(struct net_device *dev); + +#endif /* __BCMGENET_H__ */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c new file mode 100644 index 000000000000..4608673beaff --- /dev/null +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -0,0 +1,464 @@ +/* + * Broadcom GENET MDIO routines + * + * Copyright (c) 2014 Broadcom Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +#include <linux/types.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/bitops.h> +#include <linux/netdevice.h> +#include <linux/platform_device.h> +#include <linux/phy.h> +#include <linux/phy_fixed.h> +#include <linux/brcmphy.h> +#include <linux/of.h> +#include <linux/of_net.h> +#include <linux/of_mdio.h> + +#include "bcmgenet.h" + +/* read a value from the MII */ +static int bcmgenet_mii_read(struct mii_bus *bus, int phy_id, int location) +{ + int ret; + struct net_device *dev = bus->priv; + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 reg; + + bcmgenet_umac_writel(priv, (MDIO_RD | (phy_id << MDIO_PMD_SHIFT) | + (location << MDIO_REG_SHIFT)), UMAC_MDIO_CMD); + /* Start MDIO transaction*/ + reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); + reg |= MDIO_START_BUSY; + bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD); + wait_event_timeout(priv->wq, + !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) + & MDIO_START_BUSY), + HZ / 100); + ret = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); + + if (ret & MDIO_READ_FAIL) + return -EIO; + + return ret & 0xffff; +} + +/* write a value to the MII */ +static int bcmgenet_mii_write(struct mii_bus *bus, int phy_id, + int location, u16 val) +{ + struct net_device *dev = bus->priv; + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 reg; + + bcmgenet_umac_writel(priv, (MDIO_WR | (phy_id << MDIO_PMD_SHIFT) | + (location << MDIO_REG_SHIFT) | (0xffff & val)), + UMAC_MDIO_CMD); + reg = bcmgenet_umac_readl(priv, UMAC_MDIO_CMD); + reg |= MDIO_START_BUSY; + bcmgenet_umac_writel(priv, reg, UMAC_MDIO_CMD); + wait_event_timeout(priv->wq, + !(bcmgenet_umac_readl(priv, UMAC_MDIO_CMD) & + MDIO_START_BUSY), + HZ / 100); + + return 0; +} + +/* setup netdev link state when PHY link status change and + * update UMAC and RGMII block when link up + */ +static void bcmgenet_mii_setup(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + u32 reg, cmd_bits = 0; + unsigned int status_changed = 0; + + if (priv->old_link != phydev->link) { + status_changed = 1; + priv->old_link = phydev->link; + } + + if (phydev->link) { + /* program UMAC and RGMII block based on established link + * speed, pause, and duplex. + * the speed set in umac->cmd tell RGMII block which clock + * 25MHz(100Mbps)/125MHz(1Gbps) to use for transmit. + * receive clock is provided by PHY. + */ + reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); + reg &= ~OOB_DISABLE; + reg |= RGMII_LINK; + bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); + + /* speed */ + if (phydev->speed == SPEED_1000) + cmd_bits = UMAC_SPEED_1000; + else if (phydev->speed == SPEED_100) + cmd_bits = UMAC_SPEED_100; + else + cmd_bits = UMAC_SPEED_10; + cmd_bits <<= CMD_SPEED_SHIFT; + + if (priv->old_duplex != phydev->duplex) { + status_changed = 1; + priv->old_duplex = phydev->duplex; + } + + /* duplex */ + if (phydev->duplex != DUPLEX_FULL) + cmd_bits |= CMD_HD_EN; + + if (priv->old_pause != phydev->pause) { + status_changed = 1; + priv->old_pause = phydev->pause; + } + + /* pause capability */ + if (!phydev->pause) + cmd_bits |= CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE; + + reg = bcmgenet_umac_readl(priv, UMAC_CMD); + reg &= ~((CMD_SPEED_MASK << CMD_SPEED_SHIFT) | + CMD_HD_EN | + CMD_RX_PAUSE_IGNORE | CMD_TX_PAUSE_IGNORE); + reg |= cmd_bits; + bcmgenet_umac_writel(priv, reg, UMAC_CMD); + } + + if (status_changed) + phy_print_status(phydev); +} + +void bcmgenet_mii_reset(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + if (priv->phydev) { + phy_init_hw(priv->phydev); + phy_start_aneg(priv->phydev); + } +} + +static void bcmgenet_ephy_power_up(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 reg = 0; + + /* EXT_GPHY_CTRL is only valid for GENETv4 and onward */ + if (!GENET_IS_V4(priv)) + return; + + reg = bcmgenet_ext_readl(priv, EXT_GPHY_CTRL); + reg &= ~(EXT_CFG_IDDQ_BIAS | EXT_CFG_PWR_DOWN); + reg |= EXT_GPHY_RESET; + bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL); + mdelay(2); + + reg &= ~EXT_GPHY_RESET; + bcmgenet_ext_writel(priv, reg, EXT_GPHY_CTRL); + udelay(20); +} + +static void bcmgenet_internal_phy_setup(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + u32 reg; + + /* Power up EPHY */ + bcmgenet_ephy_power_up(dev); + /* enable APD */ + reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); + reg |= EXT_PWR_DN_EN_LD; + bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + bcmgenet_mii_reset(dev); +} + +static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) +{ + u32 reg; + + /* Speed settings are set in bcmgenet_mii_setup() */ + reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL); + reg |= LED_ACT_SOURCE_MAC; + bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL); +} + +int bcmgenet_mii_config(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phydev; + struct device *kdev = &priv->pdev->dev; + const char *phy_name = NULL; + u32 id_mode_dis = 0; + u32 port_ctrl; + u32 reg; + + priv->ext_phy = !phy_is_internal(priv->phydev) && + (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); + + if (phy_is_internal(priv->phydev)) + priv->phy_interface = PHY_INTERFACE_MODE_NA; + + switch (priv->phy_interface) { + case PHY_INTERFACE_MODE_NA: + case PHY_INTERFACE_MODE_MOCA: + /* Irrespective of the actually configured PHY speed (100 or + * 1000) GENETv4 only has an internal GPHY so we will just end + * up masking the Gigabit features from what we support, not + * switching to the EPHY + */ + if (GENET_IS_V4(priv)) + port_ctrl = PORT_MODE_INT_GPHY; + else + port_ctrl = PORT_MODE_INT_EPHY; + + bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); + + if (phy_is_internal(priv->phydev)) { + phy_name = "internal PHY"; + bcmgenet_internal_phy_setup(dev); + } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { + phy_name = "MoCA"; + bcmgenet_moca_phy_setup(priv); + } + break; + + case PHY_INTERFACE_MODE_MII: + phy_name = "external MII"; + phydev->supported &= PHY_BASIC_FEATURES; + bcmgenet_sys_writel(priv, + PORT_MODE_EXT_EPHY, SYS_PORT_CTRL); + break; + + case PHY_INTERFACE_MODE_REVMII: + phy_name = "external RvMII"; + /* of_mdiobus_register took care of reading the 'max-speed' + * PHY property for us, effectively limiting the PHY supported + * capabilities, use that knowledge to also configure the + * Reverse MII interface correctly. + */ + if ((priv->phydev->supported & PHY_BASIC_FEATURES) == + PHY_BASIC_FEATURES) + port_ctrl = PORT_MODE_EXT_RVMII_25; + else + port_ctrl = PORT_MODE_EXT_RVMII_50; + bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); + break; + + case PHY_INTERFACE_MODE_RGMII: + /* RGMII_NO_ID: TXC transitions at the same time as TXD + * (requires PCB or receiver-side delay) + * RGMII: Add 2ns delay on TXC (90 degree shift) + * + * ID is implicitly disabled for 100Mbps (RG)MII operation. + */ + id_mode_dis = BIT(16); + /* fall through */ + case PHY_INTERFACE_MODE_RGMII_TXID: + if (id_mode_dis) + phy_name = "external RGMII (no delay)"; + else + phy_name = "external RGMII (TX delay)"; + reg = bcmgenet_ext_readl(priv, EXT_RGMII_OOB_CTRL); + reg |= RGMII_MODE_EN | id_mode_dis; + bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); + bcmgenet_sys_writel(priv, + PORT_MODE_EXT_GPHY, SYS_PORT_CTRL); + break; + default: + dev_err(kdev, "unknown phy mode: %d\n", priv->phy_interface); + return -EINVAL; + } + + dev_info(kdev, "configuring instance for %s\n", phy_name); + + return 0; +} + +static int bcmgenet_mii_probe(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + struct phy_device *phydev; + unsigned int phy_flags; + int ret; + + if (priv->phydev) { + pr_info("PHY already attached\n"); + return 0; + } + + if (priv->phy_dn) + phydev = of_phy_connect(dev, priv->phy_dn, + bcmgenet_mii_setup, 0, + priv->phy_interface); + else + phydev = of_phy_connect_fixed_link(dev, + bcmgenet_mii_setup, + priv->phy_interface); + + if (!phydev) { + pr_err("could not attach to PHY\n"); + return -ENODEV; + } + + priv->old_link = -1; + priv->old_duplex = -1; + priv->old_pause = -1; + priv->phydev = phydev; + + /* Configure port multiplexer based on what the probed PHY device since + * reading the 'max-speed' property determines the maximum supported + * PHY speed which is needed for bcmgenet_mii_config() to configure + * things appropriately. + */ + ret = bcmgenet_mii_config(dev); + if (ret) { + phy_disconnect(priv->phydev); + return ret; + } + + phy_flags = PHY_BRCM_100MBPS_WAR; + + /* workarounds are only needed for 100Mpbs PHYs, and + * never on GENET V1 hardware + */ + if ((phydev->supported & PHY_GBIT_FEATURES) || GENET_IS_V1(priv)) + phy_flags = 0; + + phydev->dev_flags |= phy_flags; + phydev->advertising = phydev->supported; + + /* The internal PHY has its link interrupts routed to the + * Ethernet MAC ISRs + */ + if (phy_is_internal(priv->phydev)) + priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT; + else + priv->mii_bus->irq[phydev->addr] = PHY_POLL; + + pr_info("attached PHY at address %d [%s]\n", + phydev->addr, phydev->drv->name); + + return 0; +} + +static int bcmgenet_mii_alloc(struct bcmgenet_priv *priv) +{ + struct mii_bus *bus; + + if (priv->mii_bus) + return 0; + + priv->mii_bus = mdiobus_alloc(); + if (!priv->mii_bus) { + pr_err("failed to allocate\n"); + return -ENOMEM; + } + + bus = priv->mii_bus; + bus->priv = priv->dev; + bus->name = "bcmgenet MII bus"; + bus->parent = &priv->pdev->dev; + bus->read = bcmgenet_mii_read; + bus->write = bcmgenet_mii_write; + snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", + priv->pdev->name, priv->pdev->id); + + bus->irq = kzalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); + if (!bus->irq) { + mdiobus_free(priv->mii_bus); + return -ENOMEM; + } + + return 0; +} + +static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) +{ + struct device_node *dn = priv->pdev->dev.of_node; + struct device *kdev = &priv->pdev->dev; + struct device_node *mdio_dn; + char *compat; + int ret; + + compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version); + if (!compat) + return -ENOMEM; + + mdio_dn = of_find_compatible_node(dn, NULL, compat); + kfree(compat); + if (!mdio_dn) { + dev_err(kdev, "unable to find MDIO bus node\n"); + return -ENODEV; + } + + ret = of_mdiobus_register(priv->mii_bus, mdio_dn); + if (ret) { + dev_err(kdev, "failed to register MDIO bus\n"); + return ret; + } + + /* Fetch the PHY phandle */ + priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0); + + /* Get the link mode */ + priv->phy_interface = of_get_phy_mode(dn); + + return 0; +} + +int bcmgenet_mii_init(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + int ret; + + ret = bcmgenet_mii_alloc(priv); + if (ret) + return ret; + + ret = bcmgenet_mii_of_init(priv); + if (ret) + goto out_free; + + ret = bcmgenet_mii_probe(dev); + if (ret) + goto out; + + return 0; + +out: + mdiobus_unregister(priv->mii_bus); +out_free: + kfree(priv->mii_bus->irq); + mdiobus_free(priv->mii_bus); + return ret; +} + +void bcmgenet_mii_exit(struct net_device *dev) +{ + struct bcmgenet_priv *priv = netdev_priv(dev); + + mdiobus_unregister(priv->mii_bus); + kfree(priv->mii_bus->irq); + mdiobus_free(priv->mii_bus); +} diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index e2ca03e23dc1..bbbd2a4bc161 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -2609,13 +2609,14 @@ static int tg3_phy_reset_5703_4_5(struct tg3 *tp) tg3_writephy(tp, MII_CTRL1000, phy9_orig); - if (!tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32)) { - reg32 &= ~0x3000; - tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32); - } else if (!err) - err = -EBUSY; + err = tg3_readphy(tp, MII_TG3_EXT_CTRL, ®32); + if (err) + return err; - return err; + reg32 &= ~0x3000; + tg3_writephy(tp, MII_TG3_EXT_CTRL, reg32); + + return 0; } static void tg3_carrier_off(struct tg3 *tp) @@ -6592,7 +6593,7 @@ static void tg3_tx(struct tg3_napi *tnapi) pkts_compl++; bytes_compl += skb->len; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); if (unlikely(tx_bug)) { tg3_tx_recover(tp); @@ -6842,8 +6843,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) work_mask |= opaque_key; - if ((desc->err_vlan & RXD_ERR_MASK) != 0 && - (desc->err_vlan != RXD_ERR_ODD_NIBBLE_RCVD_MII)) { + if (desc->err_vlan & RXD_ERR_MASK) { drop_it: tg3_recycle_rx(tnapi, tpr, opaque_key, desc_idx, *post_ptr); @@ -6924,7 +6924,7 @@ static int tg3_rx(struct tg3_napi *tnapi, int budget) if (len > (tp->dev->mtu + ETH_HLEN) && skb->protocol != htons(ETH_P_8021Q)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); goto drop_it_no_recycle; } @@ -7807,7 +7807,7 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, PCI_DMA_TODEVICE); /* Make sure the mapping succeeded */ if (pci_dma_mapping_error(tp->pdev, new_addr)) { - dev_kfree_skb(new_skb); + dev_kfree_skb_any(new_skb); ret = -1; } else { u32 save_entry = *entry; @@ -7822,13 +7822,13 @@ static int tigon3_dma_hwbug_workaround(struct tg3_napi *tnapi, new_skb->len, base_flags, mss, vlan)) { tg3_tx_skb_unmap(tnapi, save_entry, -1); - dev_kfree_skb(new_skb); + dev_kfree_skb_any(new_skb); ret = -1; } } } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); *pskb = new_skb; return ret; } @@ -7871,7 +7871,7 @@ static int tg3_tso_bug(struct tg3 *tp, struct sk_buff *skb) } while (segs); tg3_tso_bug_end: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -8093,7 +8093,7 @@ dma_error: tg3_tx_skb_unmap(tnapi, tnapi->tx_prod, --i); tnapi->tx_buffers[tnapi->tx_prod].skb = NULL; drop: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); drop_nofree: tp->tx_dropped++; return NETDEV_TX_OK; @@ -11361,12 +11361,10 @@ static bool tg3_enable_msix(struct tg3 *tp) msix_ent[i].vector = 0; } - rc = pci_enable_msix(tp->pdev, msix_ent, tp->irq_cnt); + rc = pci_enable_msix_range(tp->pdev, msix_ent, 1, tp->irq_cnt); if (rc < 0) { return false; - } else if (rc != 0) { - if (pci_enable_msix(tp->pdev, msix_ent, rc)) - return false; + } else if (rc < tp->irq_cnt) { netdev_notice(tp->dev, "Requested %d MSI-X vectors, received %d\n", tp->irq_cnt, rc); tp->irq_cnt = rc; @@ -14113,12 +14111,12 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu) tg3_netif_stop(tp); + tg3_set_mtu(dev, tp, new_mtu); + tg3_full_lock(tp, 1); tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); - tg3_set_mtu(dev, tp, new_mtu); - /* Reset PHY, otherwise the read DMA engine will be in a mode that * breaks all requests to 256 bytes. */ diff --git a/drivers/net/ethernet/broadcom/tg3.h b/drivers/net/ethernet/broadcom/tg3.h index ef472385bce4..04321e5a356e 100644 --- a/drivers/net/ethernet/broadcom/tg3.h +++ b/drivers/net/ethernet/broadcom/tg3.h @@ -2608,7 +2608,11 @@ struct tg3_rx_buffer_desc { #define RXD_ERR_TOO_SMALL 0x00400000 #define RXD_ERR_NO_RESOURCES 0x00800000 #define RXD_ERR_HUGE_FRAME 0x01000000 -#define RXD_ERR_MASK 0xffff0000 + +#define RXD_ERR_MASK (RXD_ERR_BAD_CRC | RXD_ERR_COLLISION | \ + RXD_ERR_LINK_LOST | RXD_ERR_PHY_DECODE | \ + RXD_ERR_MAC_ABRT | RXD_ERR_TOO_SMALL | \ + RXD_ERR_NO_RESOURCES | RXD_ERR_HUGE_FRAME) u32 reserved; u32 opaque; diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c index cf64f3d0b60d..cb7625366ec2 100644 --- a/drivers/net/ethernet/brocade/bna/bnad.c +++ b/drivers/net/ethernet/brocade/bna/bnad.c @@ -707,7 +707,8 @@ bnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) else skb_checksum_none_assert(skb); - if (flags & BNA_CQ_EF_VLAN) + if ((flags & BNA_CQ_EF_VLAN) && + (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag)); if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) @@ -2094,7 +2095,9 @@ bnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config) rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE; } - rx_config->vlan_strip_status = BNA_STATUS_T_ENABLED; + rx_config->vlan_strip_status = + (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ? + BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED; } static void @@ -2666,9 +2669,11 @@ bnad_enable_msix(struct bnad *bnad) for (i = 0; i < bnad->msix_num; i++) bnad->msix_table[i].entry = i; - ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, bnad->msix_num); - if (ret > 0) { - /* Not enough MSI-X vectors. */ + ret = pci_enable_msix_range(bnad->pcidev, bnad->msix_table, + 1, bnad->msix_num); + if (ret < 0) { + goto intx_mode; + } else if (ret < bnad->msix_num) { pr_warn("BNA: %d MSI-X vectors allocated < %d requested\n", ret, bnad->msix_num); @@ -2681,18 +2686,11 @@ bnad_enable_msix(struct bnad *bnad) bnad->msix_num = BNAD_NUM_TXQ + BNAD_NUM_RXP + BNAD_MAILBOX_MSIX_VECTORS; - if (bnad->msix_num > ret) - goto intx_mode; - - /* Try once more with adjusted numbers */ - /* If this fails, fall back to INTx */ - ret = pci_enable_msix(bnad->pcidev, bnad->msix_table, - bnad->msix_num); - if (ret) + if (bnad->msix_num > ret) { + pci_disable_msix(bnad->pcidev); goto intx_mode; - - } else if (ret < 0) - goto intx_mode; + } + } pci_intx(bnad->pcidev, 0); @@ -2847,13 +2845,11 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, } if (unlikely((gso_size + skb_transport_offset(skb) + tcp_hdrlen(skb)) >= skb->len)) { - txqent->hdr.wi.opcode = - __constant_htons(BNA_TXQ_WI_SEND); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.lso_mss = 0; BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short); } else { - txqent->hdr.wi.opcode = - __constant_htons(BNA_TXQ_WI_SEND_LSO); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO); txqent->hdr.wi.lso_mss = htons(gso_size); } @@ -2867,7 +2863,7 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, htons(BNA_TXQ_WI_L4_HDR_N_OFFSET( tcp_hdrlen(skb) >> 2, skb_transport_offset(skb))); } else { - txqent->hdr.wi.opcode = __constant_htons(BNA_TXQ_WI_SEND); + txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); txqent->hdr.wi.lso_mss = 0; if (unlikely(skb->len > (bnad->netdev->mtu + ETH_HLEN))) { @@ -2878,11 +2874,10 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 proto = 0; - if (skb->protocol == __constant_htons(ETH_P_IP)) + if (skb->protocol == htons(ETH_P_IP)) proto = ip_hdr(skb)->protocol; #ifdef NETIF_F_IPV6_CSUM - else if (skb->protocol == - __constant_htons(ETH_P_IPV6)) { + else if (skb->protocol == htons(ETH_P_IPV6)) { /* nexthdr may not be TCP immediately. */ proto = ipv6_hdr(skb)->nexthdr; } @@ -3064,8 +3059,7 @@ bnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) vect_id = 0; BNA_QE_INDX_INC(prod, q_depth); txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod]; - txqent->hdr.wi_ext.opcode = - __constant_htons(BNA_TXQ_WI_EXTENSION); + txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION); unmap = &unmap_q[prod]; } @@ -3245,11 +3239,6 @@ bnad_set_rx_mode(struct net_device *netdev) BNA_RXMODE_ALLMULTI; bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask, NULL); - if (bnad->cfg_flags & BNAD_CF_PROMISC) - bna_rx_vlan_strip_disable(bnad->rx_info[0].rx); - else - bna_rx_vlan_strip_enable(bnad->rx_info[0].rx); - spin_unlock_irqrestore(&bnad->bna_lock, flags); } @@ -3374,6 +3363,27 @@ bnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) return 0; } +static int bnad_set_features(struct net_device *dev, netdev_features_t features) +{ + struct bnad *bnad = netdev_priv(dev); + netdev_features_t changed = features ^ dev->features; + + if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) { + unsigned long flags; + + spin_lock_irqsave(&bnad->bna_lock, flags); + + if (features & NETIF_F_HW_VLAN_CTAG_RX) + bna_rx_vlan_strip_enable(bnad->rx_info[0].rx); + else + bna_rx_vlan_strip_disable(bnad->rx_info[0].rx); + + spin_unlock_irqrestore(&bnad->bna_lock, flags); + } + + return 0; +} + #ifdef CONFIG_NET_POLL_CONTROLLER static void bnad_netpoll(struct net_device *netdev) @@ -3421,6 +3431,7 @@ static const struct net_device_ops bnad_netdev_ops = { .ndo_change_mtu = bnad_change_mtu, .ndo_vlan_rx_add_vid = bnad_vlan_rx_add_vid, .ndo_vlan_rx_kill_vid = bnad_vlan_rx_kill_vid, + .ndo_set_features = bnad_set_features, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = bnad_netpoll #endif @@ -3433,14 +3444,14 @@ bnad_netdev_init(struct bnad *bnad, bool using_dac) netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | - NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX; + NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX; netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6; - netdev->features |= netdev->hw_features | - NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_FILTER; + netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 45d77334d7d9..07bbb711b7e5 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -3088,30 +3088,22 @@ static int cxgb_enable_msix(struct adapter *adap) { struct msix_entry entries[SGE_QSETS + 1]; int vectors; - int i, err; + int i; vectors = ARRAY_SIZE(entries); for (i = 0; i < vectors; ++i) entries[i].entry = i; - while ((err = pci_enable_msix(adap->pdev, entries, vectors)) > 0) - vectors = err; - - if (err < 0) - pci_disable_msix(adap->pdev); - - if (!err && vectors < (adap->params.nports + 1)) { - pci_disable_msix(adap->pdev); - err = -1; - } + vectors = pci_enable_msix_range(adap->pdev, entries, + adap->params.nports + 1, vectors); + if (vectors < 0) + return vectors; - if (!err) { - for (i = 0; i < vectors; ++i) - adap->msix_info[i].vec = entries[i].vector; - adap->msix_nvectors = vectors; - } + for (i = 0; i < vectors; ++i) + adap->msix_info[i].vec = entries[i].vector; + adap->msix_nvectors = vectors; - return err; + return 0; } static void print_port_info(struct adapter *adap, const struct adapter_info *ai) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 1f4b9b30b9ed..944f2cbc1795 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -66,6 +66,7 @@ enum { SERNUM_LEN = 24, /* Serial # length */ EC_LEN = 16, /* E/C length */ ID_LEN = 16, /* ID length */ + PN_LEN = 16, /* Part Number length */ }; enum { @@ -254,6 +255,7 @@ struct vpd_params { u8 ec[EC_LEN + 1]; u8 sn[SERNUM_LEN + 1]; u8 id[ID_LEN + 1]; + u8 pn[PN_LEN + 1]; }; struct pci_params { @@ -306,6 +308,7 @@ struct adapter_params { unsigned char bypass; unsigned int ofldq_wr_cred; + bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ }; #include "t4fw_api.h" @@ -957,7 +960,7 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *parity); - +const char *t4_get_port_type_description(enum fw_port_type port_type); void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p); void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log); void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr, diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 43ab35fea48d..0ac53dd84c61 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -254,6 +254,8 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { CH_DEVICE(0x5011, 4), CH_DEVICE(0x5012, 4), CH_DEVICE(0x5013, 4), + CH_DEVICE(0x5014, 4), + CH_DEVICE(0x5015, 4), CH_DEVICE(0x5401, 4), CH_DEVICE(0x5402, 4), CH_DEVICE(0x5403, 4), @@ -273,6 +275,8 @@ static DEFINE_PCI_DEVICE_TABLE(cxgb4_pci_tbl) = { CH_DEVICE(0x5411, 4), CH_DEVICE(0x5412, 4), CH_DEVICE(0x5413, 4), + CH_DEVICE(0x5414, 4), + CH_DEVICE(0x5415, 4), { 0, } }; @@ -423,15 +427,18 @@ static void link_report(struct net_device *dev) const struct port_info *p = netdev_priv(dev); switch (p->link_cfg.speed) { - case SPEED_10000: + case 10000: s = "10Gbps"; break; - case SPEED_1000: + case 1000: s = "1000Mbps"; break; - case SPEED_100: + case 100: s = "100Mbps"; break; + case 40000: + s = "40Gbps"; + break; } netdev_info(dev, "link up, %s, full-duplex, %s PAUSE\n", s, @@ -2061,7 +2068,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, 0x40200, 0x40298, 0x402ac, 0x4033c, 0x403f8, 0x403fc, - 0x41300, 0x413c4, + 0x41304, 0x413c4, 0x41400, 0x4141c, 0x41480, 0x414d0, 0x44000, 0x44078, @@ -2089,7 +2096,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, 0x48200, 0x48298, 0x482ac, 0x4833c, 0x483f8, 0x483fc, - 0x49300, 0x493c4, + 0x49304, 0x493c4, 0x49400, 0x4941c, 0x49480, 0x494d0, 0x4c000, 0x4c078, @@ -2199,6 +2206,8 @@ static unsigned int from_fw_linkcaps(unsigned int type, unsigned int caps) else if (type == FW_PORT_TYPE_FIBER_XFI || type == FW_PORT_TYPE_FIBER_XAUI || type == FW_PORT_TYPE_SFP) v |= SUPPORTED_FIBRE; + else if (type == FW_PORT_TYPE_BP40_BA) + v |= SUPPORTED_40000baseSR4_Full; if (caps & FW_PORT_CAP_ANEG) v |= SUPPORTED_Autoneg; @@ -2215,6 +2224,8 @@ static unsigned int to_fw_linkcaps(unsigned int caps) v |= FW_PORT_CAP_SPEED_1G; if (caps & ADVERTISED_10000baseT_Full) v |= FW_PORT_CAP_SPEED_10G; + if (caps & ADVERTISED_40000baseSR4_Full) + v |= FW_PORT_CAP_SPEED_40G; return v; } @@ -2263,12 +2274,14 @@ static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static unsigned int speed_to_caps(int speed) { - if (speed == SPEED_100) + if (speed == 100) return FW_PORT_CAP_SPEED_100M; - if (speed == SPEED_1000) + if (speed == 1000) return FW_PORT_CAP_SPEED_1G; - if (speed == SPEED_10000) + if (speed == 10000) return FW_PORT_CAP_SPEED_10G; + if (speed == 40000) + return FW_PORT_CAP_SPEED_40G; return 0; } @@ -2296,8 +2309,10 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) if (cmd->autoneg == AUTONEG_DISABLE) { cap = speed_to_caps(speed); - if (!(lc->supported & cap) || (speed == SPEED_1000) || - (speed == SPEED_10000)) + if (!(lc->supported & cap) || + (speed == 1000) || + (speed == 10000) || + (speed == 40000)) return -EINVAL; lc->requested_speed = cap; lc->advertising = 0; @@ -3765,6 +3780,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld) lli.dbfifo_int_thresh = dbfifo_int_thresh; lli.sge_pktshift = adap->sge.pktshift; lli.enable_fw_ofld_conn = adap->flags & FW_OFLD_CONN; + lli.ulptx_memwrite_dsgl = adap->params.ulptx_memwrite_dsgl; handle = ulds[uld].add(&lli); if (IS_ERR(handle)) { @@ -5370,6 +5386,21 @@ static int adap_init0(struct adapter *adap) (void) t4_set_params(adap, adap->mbox, adap->fn, 0, 1, params, val); /* + * Find out whether we're allowed to use the T5+ ULPTX MEMWRITE DSGL + * capability. Earlier versions of the firmware didn't have the + * ULPTX_MEMWRITE_DSGL so we'll interpret a query failure as no + * permission to use ULPTX MEMWRITE DSGL. + */ + if (is_t4(adap->params.chip)) { + adap->params.ulptx_memwrite_dsgl = false; + } else { + params[0] = FW_PARAM_DEV(ULPTX_MEMWRITE_DSGL); + ret = t4_query_params(adap, adap->mbox, adap->fn, 0, + 1, params, val); + adap->params.ulptx_memwrite_dsgl = (ret == 0 && val[0] != 0); + } + + /* * Get device capabilities so we can determine what resources we need * to manage. */ @@ -5603,9 +5634,10 @@ static const struct pci_error_handlers cxgb4_eeh = { .resume = eeh_resume, }; -static inline bool is_10g_port(const struct link_config *lc) +static inline bool is_x_10g_port(const struct link_config *lc) { - return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0; + return (lc->supported & FW_PORT_CAP_SPEED_10G) != 0 || + (lc->supported & FW_PORT_CAP_SPEED_40G) != 0; } static inline void init_rspq(struct sge_rspq *q, u8 timer_idx, u8 pkt_cnt_idx, @@ -5629,7 +5661,7 @@ static void cfg_queues(struct adapter *adap) int i, q10g = 0, n10g = 0, qidx = 0; for_each_port(adap, i) - n10g += is_10g_port(&adap2pinfo(adap, i)->link_cfg); + n10g += is_x_10g_port(&adap2pinfo(adap, i)->link_cfg); /* * We default to 1 queue per non-10G port and up to # of cores queues @@ -5644,7 +5676,7 @@ static void cfg_queues(struct adapter *adap) struct port_info *pi = adap2pinfo(adap, i); pi->first_qset = qidx; - pi->nqsets = is_10g_port(&pi->link_cfg) ? q10g : 1; + pi->nqsets = is_x_10g_port(&pi->link_cfg) ? q10g : 1; qidx += pi->nqsets; } @@ -5737,7 +5769,7 @@ static void reduce_ethqs(struct adapter *adap, int n) static int enable_msix(struct adapter *adap) { int ofld_need = 0; - int i, err, want, need; + int i, want, need; struct sge *s = &adap->sge; unsigned int nchan = adap->params.nports; struct msix_entry entries[MAX_INGQ + 1]; @@ -5753,32 +5785,30 @@ static int enable_msix(struct adapter *adap) } need = adap->params.nports + EXTRA_VECS + ofld_need; - while ((err = pci_enable_msix(adap->pdev, entries, want)) >= need) - want = err; + want = pci_enable_msix_range(adap->pdev, entries, need, want); + if (want < 0) + return want; - if (!err) { - /* - * Distribute available vectors to the various queue groups. - * Every group gets its minimum requirement and NIC gets top - * priority for leftovers. - */ - i = want - EXTRA_VECS - ofld_need; - if (i < s->max_ethqsets) { - s->max_ethqsets = i; - if (i < s->ethqsets) - reduce_ethqs(adap, i); - } - if (is_offload(adap)) { - i = want - EXTRA_VECS - s->max_ethqsets; - i -= ofld_need - nchan; - s->ofldqsets = (i / nchan) * nchan; /* round down */ - } - for (i = 0; i < want; ++i) - adap->msix_info[i].vec = entries[i].vector; - } else if (err > 0) - dev_info(adap->pdev_dev, - "only %d MSI-X vectors left, not using MSI-X\n", err); - return err; + /* + * Distribute available vectors to the various queue groups. + * Every group gets its minimum requirement and NIC gets top + * priority for leftovers. + */ + i = want - EXTRA_VECS - ofld_need; + if (i < s->max_ethqsets) { + s->max_ethqsets = i; + if (i < s->ethqsets) + reduce_ethqs(adap, i); + } + if (is_offload(adap)) { + i = want - EXTRA_VECS - s->max_ethqsets; + i -= ofld_need - nchan; + s->ofldqsets = (i / nchan) * nchan; /* round down */ + } + for (i = 0; i < want; ++i) + adap->msix_info[i].vec = entries[i].vector; + + return 0; } #undef EXTRA_VECS @@ -5801,11 +5831,6 @@ static int init_rss(struct adapter *adap) static void print_port_info(const struct net_device *dev) { - static const char *base[] = { - "R XFI", "R XAUI", "T SGMII", "T XFI", "T XAUI", "KX4", "CX4", - "KX", "KR", "R SFP+", "KR/KX", "KR/KX/KX4" - }; - char buf[80]; char *bufp = buf; const char *spd = ""; @@ -5823,9 +5848,11 @@ static void print_port_info(const struct net_device *dev) bufp += sprintf(bufp, "1000/"); if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) bufp += sprintf(bufp, "10G/"); + if (pi->link_cfg.supported & FW_PORT_CAP_SPEED_40G) + bufp += sprintf(bufp, "40G/"); if (bufp != buf) --bufp; - sprintf(bufp, "BASE-%s", base[pi->port_type]); + sprintf(bufp, "BASE-%s", t4_get_port_type_description(pi->port_type)); netdev_info(dev, "Chelsio %s rev %d %s %sNIC PCIe x%d%s%s\n", adap->params.vpd.id, @@ -5833,8 +5860,8 @@ static void print_port_info(const struct net_device *dev) is_offload(adap) ? "R" : "", adap->params.pci.width, spd, (adap->flags & USING_MSIX) ? " MSI-X" : (adap->flags & USING_MSI) ? " MSI" : ""); - netdev_info(dev, "S/N: %s, E/C: %s\n", - adap->params.vpd.sn, adap->params.vpd.ec); + netdev_info(dev, "S/N: %s, P/N: %s\n", + adap->params.vpd.sn, adap->params.vpd.pn); } static void enable_pcie_relaxed_ordering(struct pci_dev *dev) @@ -6179,6 +6206,7 @@ static struct pci_driver cxgb4_driver = { .id_table = cxgb4_pci_tbl, .probe = init_one, .remove = remove_one, + .shutdown = remove_one, .err_handler = &cxgb4_eeh, }; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h index 4dd0a82533e4..e274a047528f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h @@ -253,6 +253,7 @@ struct cxgb4_lld_info { /* packet data */ bool enable_fw_ofld_conn; /* Enable connection through fw */ /* WR */ + bool ulptx_memwrite_dsgl; /* use of T5 DSGL allowed */ }; struct cxgb4_uld_info { diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 47ffa64fcf19..af76b25bb606 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -706,11 +706,17 @@ static inline unsigned int flits_to_desc(unsigned int n) * @skb: the packet * * Returns whether an Ethernet packet is small enough to fit as - * immediate data. + * immediate data. Return value corresponds to headroom required. */ static inline int is_eth_imm(const struct sk_buff *skb) { - return skb->len <= MAX_IMM_TX_PKT_LEN - sizeof(struct cpl_tx_pkt); + int hdrlen = skb_shinfo(skb)->gso_size ? + sizeof(struct cpl_tx_pkt_lso_core) : 0; + + hdrlen += sizeof(struct cpl_tx_pkt); + if (skb->len <= MAX_IMM_TX_PKT_LEN - hdrlen) + return hdrlen; + return 0; } /** @@ -723,9 +729,10 @@ static inline int is_eth_imm(const struct sk_buff *skb) static inline unsigned int calc_tx_flits(const struct sk_buff *skb) { unsigned int flits; + int hdrlen = is_eth_imm(skb); - if (is_eth_imm(skb)) - return DIV_ROUND_UP(skb->len + sizeof(struct cpl_tx_pkt), 8); + if (hdrlen) + return DIV_ROUND_UP(skb->len + hdrlen, sizeof(__be64)); flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4; if (skb_shinfo(skb)->gso_size) @@ -971,6 +978,7 @@ static inline void txq_advance(struct sge_txq *q, unsigned int n) */ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { + int len; u32 wr_mid; u64 cntrl, *end; int qidx, credits; @@ -982,6 +990,7 @@ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) struct cpl_tx_pkt_core *cpl; const struct skb_shared_info *ssi; dma_addr_t addr[MAX_SKB_FRAGS + 1]; + bool immediate = false; /* * The chip min packet length is 10 octets but play safe and reject @@ -1011,7 +1020,10 @@ out_free: dev_kfree_skb(skb); return NETDEV_TX_BUSY; } - if (!is_eth_imm(skb) && + if (is_eth_imm(skb)) + immediate = true; + + if (!immediate && unlikely(map_skb(adap->pdev_dev, skb, addr) < 0)) { q->mapping_err++; goto out_free; @@ -1028,6 +1040,8 @@ out_free: dev_kfree_skb(skb); wr->r3 = cpu_to_be64(0); end = (u64 *)wr + flits; + len = immediate ? skb->len : 0; + len += sizeof(*cpl); ssi = skb_shinfo(skb); if (ssi->gso_size) { struct cpl_tx_pkt_lso *lso = (void *)wr; @@ -1035,8 +1049,9 @@ out_free: dev_kfree_skb(skb); int l3hdr_len = skb_network_header_len(skb); int eth_xtra_len = skb_network_offset(skb) - ETH_HLEN; + len += sizeof(*lso); wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | - FW_WR_IMMDLEN(sizeof(*lso))); + FW_WR_IMMDLEN(len)); lso->c.lso_ctrl = htonl(LSO_OPCODE(CPL_TX_PKT_LSO) | LSO_FIRST_SLICE | LSO_LAST_SLICE | LSO_IPV6(v6) | @@ -1054,9 +1069,6 @@ out_free: dev_kfree_skb(skb); q->tso++; q->tx_cso += ssi->gso_segs; } else { - int len; - - len = is_eth_imm(skb) ? skb->len + sizeof(*cpl) : sizeof(*cpl); wr->op_immdlen = htonl(FW_WR_OP(FW_ETH_TX_PKT_WR) | FW_WR_IMMDLEN(len)); cpl = (void *)(wr + 1); @@ -1078,7 +1090,7 @@ out_free: dev_kfree_skb(skb); cpl->len = htons(skb->len); cpl->ctrl1 = cpu_to_be64(cntrl); - if (is_eth_imm(skb)) { + if (immediate) { inline_tx_skb(skb, &q->q, cpl + 1); dev_kfree_skb(skb); } else { @@ -1467,8 +1479,12 @@ static inline int ofld_send(struct adapter *adap, struct sk_buff *skb) { unsigned int idx = skb_txq(skb); - if (unlikely(is_ctrl_pkt(skb))) + if (unlikely(is_ctrl_pkt(skb))) { + /* Single ctrl queue is a requirement for LE workaround path */ + if (adap->tids.nsftids) + idx = 0; return ctrl_xmit(&adap->sge.ctrlq[idx], skb); + } return ofld_xmit(&adap->sge.ofldtxq[idx], skb); } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2c109343d570..d3c2a516fa88 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -573,7 +573,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) { u32 cclk_param, cclk_val; int i, ret, addr; - int ec, sn; + int ec, sn, pn; u8 *vpd, csum; unsigned int vpdr_len, kw_offset, id_len; @@ -638,6 +638,7 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) FIND_VPD_KW(ec, "EC"); FIND_VPD_KW(sn, "SN"); + FIND_VPD_KW(pn, "PN"); #undef FIND_VPD_KW memcpy(p->id, vpd + PCI_VPD_LRDT_TAG_SIZE, id_len); @@ -647,6 +648,8 @@ int get_vpd_params(struct adapter *adapter, struct vpd_params *p) i = pci_vpd_info_field_size(vpd + sn - PCI_VPD_INFO_FLD_HDR_SIZE); memcpy(p->sn, vpd + sn, min(i, SERNUM_LEN)); strim(p->sn); + memcpy(p->pn, vpd + pn, min(i, PN_LEN)); + strim(p->pn); /* * Ask firmware for the Core Clock since it knows how to translate the @@ -1155,7 +1158,8 @@ out: } #define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\ - FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG) + FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \ + FW_PORT_CAP_ANEG) /** * t4_link_start - apply link configuration to MAC/PHY @@ -2247,6 +2251,36 @@ static unsigned int get_mps_bg_map(struct adapter *adap, int idx) } /** + * t4_get_port_type_description - return Port Type string description + * @port_type: firmware Port Type enumeration + */ +const char *t4_get_port_type_description(enum fw_port_type port_type) +{ + static const char *const port_type_description[] = { + "R XFI", + "R XAUI", + "T SGMII", + "T XFI", + "T XAUI", + "KX4", + "CX4", + "KX", + "KR", + "R SFP+", + "KR/KX", + "KR/KX/KX4", + "R QSFP_10G", + "", + "R QSFP", + "R BP40_BA", + }; + + if (port_type < ARRAY_SIZE(port_type_description)) + return port_type_description[port_type]; + return "UNKNOWN"; +} + +/** * t4_get_port_stats - collect port statistics * @adap: the adapter * @idx: the port index @@ -3533,11 +3567,13 @@ int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl) if (stat & FW_PORT_CMD_TXPAUSE) fc |= PAUSE_TX; if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_100M)) - speed = SPEED_100; + speed = 100; else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_1G)) - speed = SPEED_1000; + speed = 1000; else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_10G)) - speed = SPEED_10000; + speed = 10000; + else if (stat & FW_PORT_CMD_LSPEED(FW_PORT_CAP_SPEED_40G)) + speed = 40000; if (link_ok != lc->link_ok || speed != lc->speed || fc != lc->fc) { /* something changed */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index 74fea74ce0aa..9cc973fbcf26 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -932,6 +932,7 @@ enum fw_params_param_dev { FW_PARAMS_PARAM_DEV_FWREV = 0x0B, FW_PARAMS_PARAM_DEV_TPREV = 0x0C, FW_PARAMS_PARAM_DEV_CF = 0x0D, + FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17, }; /* @@ -1742,6 +1743,9 @@ enum fw_port_type { FW_PORT_TYPE_SFP, FW_PORT_TYPE_BP_AP, FW_PORT_TYPE_BP4_AP, + FW_PORT_TYPE_QSFP_10G, + FW_PORT_TYPE_QSFP, + FW_PORT_TYPE_BP40_BA, FW_PORT_TYPE_NONE = FW_PORT_CMD_PTYPE_MASK }; diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c index 0899c0983594..1d0fe9b60312 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c @@ -2444,7 +2444,7 @@ static void reduce_ethqs(struct adapter *adapter, int n) */ static int enable_msix(struct adapter *adapter) { - int i, err, want, need; + int i, want, need, nqsets; struct msix_entry entries[MSIX_ENTRIES]; struct sge *s = &adapter->sge; @@ -2460,26 +2460,23 @@ static int enable_msix(struct adapter *adapter) */ want = s->max_ethqsets + MSIX_EXTRAS; need = adapter->params.nports + MSIX_EXTRAS; - while ((err = pci_enable_msix(adapter->pdev, entries, want)) >= need) - want = err; - if (err == 0) { - int nqsets = want - MSIX_EXTRAS; - if (nqsets < s->max_ethqsets) { - dev_warn(adapter->pdev_dev, "only enough MSI-X vectors" - " for %d Queue Sets\n", nqsets); - s->max_ethqsets = nqsets; - if (nqsets < s->ethqsets) - reduce_ethqs(adapter, nqsets); - } - for (i = 0; i < want; ++i) - adapter->msix_info[i].vec = entries[i].vector; - } else if (err > 0) { - pci_disable_msix(adapter->pdev); - dev_info(adapter->pdev_dev, "only %d MSI-X vectors left," - " not using MSI-X\n", err); + want = pci_enable_msix_range(adapter->pdev, entries, need, want); + if (want < 0) + return want; + + nqsets = want - MSIX_EXTRAS; + if (nqsets < s->max_ethqsets) { + dev_warn(adapter->pdev_dev, "only enough MSI-X vectors" + " for %d Queue Sets\n", nqsets); + s->max_ethqsets = nqsets; + if (nqsets < s->ethqsets) + reduce_ethqs(adapter, nqsets); } - return err; + for (i = 0; i < want; ++i) + adapter->msix_info[i].vec = entries[i].vector; + + return 0; } static const struct net_device_ops cxgb4vf_netdev_ops = { diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index b740bfce72ef..dcd58f23834a 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1796,7 +1796,8 @@ static int enic_set_intr_mode(struct enic *enic) enic->cq_count >= n + m && enic->intr_count >= n + m + 2) { - if (!pci_enable_msix(enic->pdev, enic->msix_entry, n + m + 2)) { + if (pci_enable_msix_range(enic->pdev, enic->msix_entry, + n + m + 2, n + m + 2) > 0) { enic->rq_count = n; enic->wq_count = m; @@ -1815,7 +1816,8 @@ static int enic_set_intr_mode(struct enic *enic) enic->wq_count >= m && enic->cq_count >= 1 + m && enic->intr_count >= 1 + m + 2) { - if (!pci_enable_msix(enic->pdev, enic->msix_entry, 1 + m + 2)) { + if (pci_enable_msix_range(enic->pdev, enic->msix_entry, + 1 + m + 2, 1 + m + 2) > 0) { enic->rq_count = 1; enic->wq_count = m; diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index add05f14b38b..1642de78aac8 100644 --- a/drivers/net/ethernet/dec/tulip/tulip_core.c +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c @@ -1939,6 +1939,7 @@ static void tulip_remove_one(struct pci_dev *pdev) pci_iounmap(pdev, tp->base_addr); free_netdev (dev); pci_release_regions (pdev); + pci_disable_device(pdev); /* pci_power_off (pdev, -1); */ } diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 8d09615da585..a587c8aa27ed 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -34,7 +34,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "10.0.600.0u" +#define DRV_VER "10.2u" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" @@ -88,7 +88,6 @@ static inline char *nic_name(struct pci_dev *pdev) #define BE_MIN_MTU 256 #define BE_NUM_VLANS_SUPPORTED 64 -#define BE_UMC_NUM_VLANS_SUPPORTED 15 #define BE_MAX_EQD 128u #define BE_MAX_TX_FRAG_COUNT 30 @@ -262,9 +261,10 @@ struct be_tx_obj { /* Struct to remember the pages posted for rx frags */ struct be_rx_page_info { struct page *page; + /* set to page-addr for last frag of the page & frag-addr otherwise */ DEFINE_DMA_UNMAP_ADDR(bus); u16 page_offset; - bool last_page_user; + bool last_frag; /* last frag of the page */ }; struct be_rx_stats { @@ -293,7 +293,7 @@ struct be_rx_compl_info { u8 ip_csum; u8 l4_csum; u8 ipv6; - u8 vtm; + u8 qnq; u8 pkt_type; u8 ip_frag; }; @@ -350,13 +350,16 @@ struct be_drv_stats { u32 roce_drops_crc; }; +/* A vlan-id of 0xFFFF must be used to clear transparent vlan-tagging */ +#define BE_RESET_VLAN_TAG_ID 0xFFFF + struct be_vf_cfg { unsigned char mac_addr[ETH_ALEN]; int if_handle; int pmac_id; - u16 def_vid; u16 vlan_tag; u32 tx_rate; + u32 plink_tracking; }; enum vf_state { @@ -465,6 +468,7 @@ struct be_adapter { u32 port_num; bool promiscuous; + u8 mc_type; u32 function_mode; u32 function_caps; u32 rx_fc; /* Rx flow control */ @@ -534,6 +538,14 @@ static inline u16 be_max_qs(struct be_adapter *adapter) return min_t(u16, num, num_online_cpus()); } +/* Is BE in pvid_tagging mode */ +#define be_pvid_tagging_enabled(adapter) (adapter->pvid) + +/* Is BE in QNQ multi-channel mode */ +#define be_is_qnq_mode(adapter) (adapter->mc_type == FLEX10 || \ + adapter->mc_type == vNIC1 || \ + adapter->mc_type == UFP) + #define lancer_chip(adapter) (adapter->pdev->device == OC_DEVICE_ID3 || \ adapter->pdev->device == OC_DEVICE_ID4) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 48076a6370c3..cf5afe72f12f 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -202,8 +202,12 @@ static void be_async_link_state_process(struct be_adapter *adapter, /* When link status changes, link speed must be re-queried from FW */ adapter->phy.link_speed = -1; - /* Ignore physical link event */ - if (lancer_chip(adapter) && + /* On BEx the FW does not send a separate link status + * notification for physical and logical link. + * On other chips just process the logical link + * status notification + */ + if (!BEx_chip(adapter) && !(evt->port_link_status & LOGICAL_LINK_STATUS_MASK)) return; @@ -211,7 +215,8 @@ static void be_async_link_state_process(struct be_adapter *adapter, * it may not be received in some cases. */ if (adapter->flags & BE_FLAGS_LINK_STATUS_INIT) - be_link_status_update(adapter, evt->port_link_status); + be_link_status_update(adapter, + evt->port_link_status & LINK_STATUS_MASK); } /* Grp5 CoS Priority evt */ @@ -239,10 +244,12 @@ static void be_async_grp5_qos_speed_process(struct be_adapter *adapter, static void be_async_grp5_pvid_state_process(struct be_adapter *adapter, struct be_async_event_grp5_pvid_state *evt) { - if (evt->enabled) + if (evt->enabled) { adapter->pvid = le16_to_cpu(evt->tag) & VLAN_VID_MASK; - else + dev_info(&adapter->pdev->dev, "LPVID: %d\n", adapter->pvid); + } else { adapter->pvid = 0; + } } static void be_async_grp5_evt_process(struct be_adapter *adapter, @@ -3296,6 +3303,21 @@ static struct be_pcie_res_desc *be_get_pcie_desc(u8 devfn, u8 *buf, return NULL; } +static struct be_port_res_desc *be_get_port_desc(u8 *buf, u32 desc_count) +{ + struct be_res_desc_hdr *hdr = (struct be_res_desc_hdr *)buf; + int i; + + for (i = 0; i < desc_count; i++) { + if (hdr->desc_type == PORT_RESOURCE_DESC_TYPE_V1) + return (struct be_port_res_desc *)hdr; + + hdr->desc_len = hdr->desc_len ? : RESOURCE_DESC_SIZE_V0; + hdr = (void *)hdr + hdr->desc_len; + } + return NULL; +} + static void be_copy_nic_desc(struct be_resources *res, struct be_nic_res_desc *desc) { @@ -3439,6 +3461,7 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, { struct be_cmd_resp_get_profile_config *resp; struct be_pcie_res_desc *pcie; + struct be_port_res_desc *port; struct be_nic_res_desc *nic; struct be_queue_info *mccq = &adapter->mcc_obj.q; struct be_dma_mem cmd; @@ -3466,6 +3489,10 @@ int be_cmd_get_profile_config(struct be_adapter *adapter, if (pcie) res->max_vfs = le16_to_cpu(pcie->num_vfs); + port = be_get_port_desc(resp->func_param, desc_count); + if (port) + adapter->mc_type = port->mc_type; + nic = be_get_nic_desc(resp->func_param, desc_count); if (nic) be_copy_nic_desc(res, nic); @@ -3723,6 +3750,45 @@ err: return status; } +int be_cmd_set_logical_link_config(struct be_adapter *adapter, + int link_state, u8 domain) +{ + struct be_mcc_wrb *wrb; + struct be_cmd_req_set_ll_link *req; + int status; + + if (BEx_chip(adapter) || lancer_chip(adapter)) + return 0; + + spin_lock_bh(&adapter->mcc_lock); + + wrb = wrb_from_mccq(adapter); + if (!wrb) { + status = -EBUSY; + goto err; + } + + req = embedded_payload(wrb); + + be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON, + OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG, + sizeof(*req), wrb, NULL); + + req->hdr.version = 1; + req->hdr.domain = domain; + + if (link_state == IFLA_VF_LINK_STATE_ENABLE) + req->link_config |= 1; + + if (link_state == IFLA_VF_LINK_STATE_AUTO) + req->link_config |= 1 << PLINK_TRACK_SHIFT; + + status = be_mcc_notify_wait(adapter); +err: + spin_unlock_bh(&adapter->mcc_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 fc4e076dc202..fda3e8851e17 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -203,6 +203,7 @@ struct be_mcc_mailbox { #define OPCODE_COMMON_GET_BEACON_STATE 70 #define OPCODE_COMMON_READ_TRANSRECV_DATA 73 #define OPCODE_COMMON_GET_PORT_NAME 77 +#define OPCODE_COMMON_SET_LOGICAL_LINK_CONFIG 80 #define OPCODE_COMMON_SET_INTERRUPT_ENABLE 89 #define OPCODE_COMMON_SET_FN_PRIVILEGES 100 #define OPCODE_COMMON_GET_PHY_DETAILS 102 @@ -1098,14 +1099,6 @@ 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 @@ -1828,6 +1821,7 @@ struct be_cmd_req_set_ext_fat_caps { #define NIC_RESOURCE_DESC_TYPE_V0 0x41 #define PCIE_RESOURCE_DESC_TYPE_V1 0x50 #define NIC_RESOURCE_DESC_TYPE_V1 0x51 +#define PORT_RESOURCE_DESC_TYPE_V1 0x55 #define MAX_RESOURCE_DESC 264 /* QOS unit number */ @@ -1891,6 +1885,33 @@ struct be_nic_res_desc { u32 rsvd8[7]; } __packed; +/************ Multi-Channel type ***********/ +enum mc_type { + MC_NONE = 0x01, + UMC = 0x02, + FLEX10 = 0x03, + vNIC1 = 0x04, + nPAR = 0x05, + UFP = 0x06, + vNIC2 = 0x07 +}; + +struct be_port_res_desc { + struct be_res_desc_hdr hdr; + u8 rsvd0; + u8 flags; + u8 rsvd1; + u8 mc_type; + u16 rsvd2; + u32 rsvd3[20]; +} __packed; + +/* Is BE in a multi-channel mode */ +static inline bool be_is_mc(struct be_adapter *adapter) +{ + return adapter->mc_type > MC_NONE; +} + struct be_cmd_req_get_func_config { struct be_cmd_req_hdr hdr; }; @@ -1971,6 +1992,13 @@ struct be_cmd_resp_get_iface_list { struct be_if_desc if_desc; }; +/*************** Set logical link ********************/ +#define PLINK_TRACK_SHIFT 8 +struct be_cmd_req_set_ll_link { + struct be_cmd_req_hdr hdr; + u32 link_config; /* Bit 0: UP_DOWN, Bit 9: PLINK */ +}; + int be_pci_fnum_get(struct be_adapter *adapter); int be_fw_wait_ready(struct be_adapter *adapter); int be_cmd_mac_addr_query(struct be_adapter *adapter, u8 *mac_addr, @@ -2092,3 +2120,5 @@ 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); int be_cmd_intr_set(struct be_adapter *adapter, bool intr_enable); +int be_cmd_set_logical_link_config(struct be_adapter *adapter, + int link_state, u8 domain); diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index 05be0070f55f..66759b6ce373 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -802,16 +802,18 @@ be_self_test(struct net_device *netdev, struct ethtool_test *test, u64 *data) if (test->flags & ETH_TEST_FL_OFFLINE) { if (be_loopback_test(adapter, BE_MAC_LOOPBACK, - &data[0]) != 0) { + &data[0]) != 0) test->flags |= ETH_TEST_FL_FAILED; - } + if (be_loopback_test(adapter, BE_PHY_LOOPBACK, - &data[1]) != 0) { - test->flags |= ETH_TEST_FL_FAILED; - } - if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, - &data[2]) != 0) { + &data[1]) != 0) test->flags |= ETH_TEST_FL_FAILED; + + if (test->flags & ETH_TEST_FL_EXTERNAL_LB) { + if (be_loopback_test(adapter, BE_ONE_PORT_EXT_LOOPBACK, + &data[2]) != 0) + test->flags |= ETH_TEST_FL_FAILED; + test->flags |= ETH_TEST_FL_EXTERNAL_LB_DONE; } } diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index dc88782185f2..28ac8dd0beaa 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -368,7 +368,7 @@ struct amap_eth_rx_compl_v0 { u8 numfrags[3]; /* dword 1 */ u8 rss_flush; /* dword 2 */ u8 cast_enc[2]; /* dword 2 */ - u8 vtm; /* dword 2 */ + u8 qnq; /* dword 2 */ u8 rss_bank; /* dword 2 */ u8 rsvd1[23]; /* dword 2 */ u8 lro_pkt; /* dword 2 */ @@ -401,7 +401,7 @@ struct amap_eth_rx_compl_v1 { u8 numfrags[3]; /* dword 1 */ u8 rss_flush; /* dword 2 */ u8 cast_enc[2]; /* dword 2 */ - u8 vtm; /* dword 2 */ + u8 qnq; /* dword 2 */ u8 rss_bank; /* dword 2 */ u8 port[2]; /* dword 2 */ u8 vntagp; /* dword 2 */ diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 04ac9c6a0d39..239273b7b881 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or @@ -652,7 +652,7 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status) adapter->flags |= BE_FLAGS_LINK_STATUS_INIT; } - if ((link_status & LINK_STATUS_MASK) == LINK_UP) + if (link_status) netif_carrier_on(netdev); else netif_carrier_off(netdev); @@ -913,24 +913,14 @@ static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, return BE3_chip(adapter) && be_ipv6_exthdr_check(skb); } -static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, - struct sk_buff *skb, - bool *skip_hw_vlan) +static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter, + struct sk_buff *skb, + bool *skip_hw_vlan) { struct vlan_ethhdr *veh = (struct vlan_ethhdr *)skb->data; unsigned int eth_hdr_len; struct iphdr *ip; - /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or less - * may cause a transmit stall on that port. So the work-around is to - * pad short packets (<= 32 bytes) to a 36-byte length. - */ - if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) { - if (skb_padto(skb, 36)) - goto tx_drop; - skb->len = 36; - } - /* For padded packets, BE HW modifies tot_len field in IP header * incorrecly when VLAN tag is inserted by HW. * For padded packets, Lancer computes incorrect checksum. @@ -945,9 +935,9 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, } /* If vlan tag is already inlined in the packet, skip HW VLAN - * tagging in UMC mode + * tagging in pvid-tagging mode */ - if ((adapter->function_mode & UMC_ENABLED) && + if (be_pvid_tagging_enabled(adapter) && veh->h_vlan_proto == htons(ETH_P_8021Q)) *skip_hw_vlan = true; @@ -959,7 +949,7 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, vlan_tx_tag_present(skb)) { skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); if (unlikely(!skb)) - goto tx_drop; + goto err; } /* HW may lockup when VLAN HW tagging is requested on @@ -981,15 +971,39 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, be_vlan_tag_tx_chk(adapter, skb)) { skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan); if (unlikely(!skb)) - goto tx_drop; + goto err; } return skb; tx_drop: dev_kfree_skb_any(skb); +err: return NULL; } +static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter, + struct sk_buff *skb, + bool *skip_hw_vlan) +{ + /* Lancer, SH-R ASICs have a bug wherein Packets that are 32 bytes or + * less may cause a transmit stall on that port. So the work-around is + * to pad short packets (<= 32 bytes) to a 36-byte length. + */ + if (unlikely(!BEx_chip(adapter) && skb->len <= 32)) { + if (skb_padto(skb, 36)) + return NULL; + skb->len = 36; + } + + if (BEx_chip(adapter) || lancer_chip(adapter)) { + skb = be_lancer_xmit_workarounds(adapter, skb, skip_hw_vlan); + if (!skb) + return NULL; + } + + return skb; +} + static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -1124,7 +1138,10 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid) /* Packets with VID 0 are always received by Lancer by default */ if (lancer_chip(adapter) && vid == 0) - goto ret; + return status; + + if (adapter->vlan_tag[vid]) + return status; adapter->vlan_tag[vid] = 1; adapter->vlans_added++; @@ -1134,7 +1151,7 @@ static int be_vlan_add_vid(struct net_device *netdev, __be16 proto, u16 vid) adapter->vlans_added--; adapter->vlan_tag[vid] = 0; } -ret: + return status; } @@ -1157,6 +1174,14 @@ ret: return status; } +static void be_clear_promisc(struct be_adapter *adapter) +{ + adapter->promiscuous = false; + adapter->flags &= ~BE_FLAGS_VLAN_PROMISC; + + be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); +} + static void be_set_rx_mode(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); @@ -1170,9 +1195,7 @@ static void be_set_rx_mode(struct net_device *netdev) /* BE was previously in promiscuous mode; disable it */ if (adapter->promiscuous) { - adapter->promiscuous = false; - be_cmd_rx_filter(adapter, IFF_PROMISC, OFF); - + be_clear_promisc(adapter); if (adapter->vlans_added) be_vid_config(adapter); } @@ -1268,6 +1291,7 @@ static int be_get_vf_config(struct net_device *netdev, int vf, vi->vlan = vf_cfg->vlan_tag & VLAN_VID_MASK; vi->qos = vf_cfg->vlan_tag >> VLAN_PRIO_SHIFT; memcpy(&vi->mac, vf_cfg->mac_addr, ETH_ALEN); + vi->linkstate = adapter->vf_cfg[vf].plink_tracking; return 0; } @@ -1287,24 +1311,20 @@ static int be_set_vf_vlan(struct net_device *netdev, if (vlan || qos) { vlan |= qos << VLAN_PRIO_SHIFT; - if (vf_cfg->vlan_tag != vlan) { - /* If this is new value, program it. Else skip. */ - vf_cfg->vlan_tag = vlan; + if (vf_cfg->vlan_tag != vlan) status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, vf_cfg->if_handle, 0); - } } else { /* Reset Transparent Vlan Tagging. */ - vf_cfg->vlan_tag = 0; - vlan = vf_cfg->def_vid; - status = be_cmd_set_hsw_config(adapter, vlan, vf + 1, - vf_cfg->if_handle, 0); + status = be_cmd_set_hsw_config(adapter, BE_RESET_VLAN_TAG_ID, + vf + 1, vf_cfg->if_handle, 0); } - - if (status) + if (!status) + vf_cfg->vlan_tag = vlan; + else dev_info(&adapter->pdev->dev, - "VLAN %d config on VF %d failed\n", vlan, vf); + "VLAN %d config on VF %d failed\n", vlan, vf); return status; } @@ -1338,6 +1358,24 @@ static int be_set_vf_tx_rate(struct net_device *netdev, adapter->vf_cfg[vf].tx_rate = rate; return status; } +static int be_set_vf_link_state(struct net_device *netdev, int vf, + int link_state) +{ + struct be_adapter *adapter = netdev_priv(netdev); + int status; + + if (!sriov_enabled(adapter)) + return -EPERM; + + if (vf >= adapter->num_vfs) + return -EINVAL; + + status = be_cmd_set_logical_link_config(adapter, link_state, vf+1); + if (!status) + adapter->vf_cfg[vf].plink_tracking = link_state; + + return status; +} static void be_aic_update(struct be_aic_obj *aic, u64 rx_pkts, u64 tx_pkts, ulong now) @@ -1448,11 +1486,15 @@ static struct be_rx_page_info *get_rx_page_info(struct be_rx_obj *rxo) rx_page_info = &rxo->page_info_tbl[frag_idx]; BUG_ON(!rx_page_info->page); - if (rx_page_info->last_page_user) { + if (rx_page_info->last_frag) { dma_unmap_page(&adapter->pdev->dev, dma_unmap_addr(rx_page_info, bus), adapter->big_page_size, DMA_FROM_DEVICE); - rx_page_info->last_page_user = false; + rx_page_info->last_frag = false; + } else { + dma_sync_single_for_cpu(&adapter->pdev->dev, + dma_unmap_addr(rx_page_info, bus), + rx_frag_size, DMA_FROM_DEVICE); } queue_tail_inc(rxq); @@ -1660,7 +1702,7 @@ static void be_parse_rx_compl_v1(struct be_eth_rx_compl *compl, rxcp->rss_hash = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, rsshash, compl); if (rxcp->vlanf) { - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vtm, + rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, qnq, compl); rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v1, vlan_tag, compl); @@ -1690,7 +1732,7 @@ static void be_parse_rx_compl_v0(struct be_eth_rx_compl *compl, rxcp->rss_hash = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, rsshash, compl); if (rxcp->vlanf) { - rxcp->vtm = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vtm, + rxcp->qnq = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, qnq, compl); rxcp->vlan_tag = AMAP_GET_BITS(struct amap_eth_rx_compl_v0, vlan_tag, compl); @@ -1723,9 +1765,11 @@ static struct be_rx_compl_info *be_rx_compl_get(struct be_rx_obj *rxo) rxcp->l4_csum = 0; if (rxcp->vlanf) { - /* vlanf could be wrongly set in some cards. - * ignore if vtm is not set */ - if ((adapter->function_mode & FLEX10_MODE) && !rxcp->vtm) + /* In QNQ modes, if qnq bit is not set, then the packet was + * tagged only with the transparent outer vlan-tag and must + * not be treated as a vlan packet by host + */ + if (be_is_qnq_mode(adapter) && !rxcp->qnq) rxcp->vlanf = 0; if (!lancer_chip(adapter)) @@ -1784,17 +1828,16 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp) rx_stats(rxo)->rx_post_fail++; break; } - page_info->page_offset = 0; + page_offset = 0; } else { get_page(pagep); - page_info->page_offset = page_offset + rx_frag_size; + page_offset += rx_frag_size; } - page_offset = page_info->page_offset; + page_info->page_offset = page_offset; page_info->page = pagep; - dma_unmap_addr_set(page_info, bus, page_dmaaddr); - frag_dmaaddr = page_dmaaddr + page_info->page_offset; rxd = queue_head_node(rxq); + frag_dmaaddr = page_dmaaddr + page_info->page_offset; rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF); rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr)); @@ -1802,15 +1845,24 @@ static void be_post_rx_frags(struct be_rx_obj *rxo, gfp_t gfp) if ((page_offset + rx_frag_size + rx_frag_size) > adapter->big_page_size) { pagep = NULL; - page_info->last_page_user = true; + page_info->last_frag = true; + dma_unmap_addr_set(page_info, bus, page_dmaaddr); + } else { + dma_unmap_addr_set(page_info, bus, frag_dmaaddr); } prev_page_info = page_info; queue_head_inc(rxq); page_info = &rxo->page_info_tbl[rxq->head]; } - if (pagep) - prev_page_info->last_page_user = true; + + /* Mark the last frag of a page when we break out of the above loop + * with no more slots available in the RXQ + */ + if (pagep) { + prev_page_info->last_frag = true; + dma_unmap_addr_set(prev_page_info, bus, page_dmaaddr); + } if (posted) { atomic_add(posted, &rxq->used); @@ -1867,7 +1919,7 @@ static u16 be_tx_compl_process(struct be_adapter *adapter, queue_tail_inc(txq); } while (cur_index != last_index); - kfree_skb(sent_skb); + dev_kfree_skb_any(sent_skb); return num_wrbs; } @@ -2423,6 +2475,9 @@ void be_detect_error(struct be_adapter *adapter) u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; u32 i; + bool error_detected = false; + struct device *dev = &adapter->pdev->dev; + struct net_device *netdev = adapter->netdev; if (be_hw_error(adapter)) return; @@ -2434,6 +2489,21 @@ void be_detect_error(struct be_adapter *adapter) SLIPORT_ERROR1_OFFSET); sliport_err2 = ioread32(adapter->db + SLIPORT_ERROR2_OFFSET); + adapter->hw_error = true; + /* Do not log error messages if its a FW reset */ + if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 && + sliport_err2 == SLIPORT_ERROR_FW_RESET2) { + dev_info(dev, "Firmware update in progress\n"); + } else { + error_detected = true; + dev_err(dev, "Error detected in the card\n"); + dev_err(dev, "ERR: sliport status 0x%x\n", + sliport_status); + dev_err(dev, "ERR: sliport error1 0x%x\n", + sliport_err1); + dev_err(dev, "ERR: sliport error2 0x%x\n", + sliport_err2); + } } } else { pci_read_config_dword(adapter->pdev, @@ -2447,51 +2517,33 @@ void be_detect_error(struct be_adapter *adapter) ue_lo = (ue_lo & ~ue_lo_mask); ue_hi = (ue_hi & ~ue_hi_mask); - } - - /* On certain platforms BE hardware can indicate spurious UEs. - * Allow the h/w to stop working completely in case of a real UE. - * Hence not setting the hw_error for UE detection. - */ - if (sliport_status & SLIPORT_STATUS_ERR_MASK) { - adapter->hw_error = true; - /* Do not log error messages if its a FW reset */ - if (sliport_err1 == SLIPORT_ERROR_FW_RESET1 && - sliport_err2 == SLIPORT_ERROR_FW_RESET2) { - dev_info(&adapter->pdev->dev, - "Firmware update in progress\n"); - return; - } else { - dev_err(&adapter->pdev->dev, - "Error detected in the card\n"); - } - } - - if (sliport_status & SLIPORT_STATUS_ERR_MASK) { - dev_err(&adapter->pdev->dev, - "ERR: sliport status 0x%x\n", sliport_status); - dev_err(&adapter->pdev->dev, - "ERR: sliport error1 0x%x\n", sliport_err1); - dev_err(&adapter->pdev->dev, - "ERR: sliport error2 0x%x\n", sliport_err2); - } - if (ue_lo) { - for (i = 0; ue_lo; ue_lo >>= 1, i++) { - if (ue_lo & 1) - dev_err(&adapter->pdev->dev, - "UE: %s bit set\n", ue_status_low_desc[i]); - } - } + /* On certain platforms BE hardware can indicate spurious UEs. + * Allow HW to stop working completely in case of a real UE. + * Hence not setting the hw_error for UE detection. + */ - if (ue_hi) { - for (i = 0; ue_hi; ue_hi >>= 1, i++) { - if (ue_hi & 1) - dev_err(&adapter->pdev->dev, - "UE: %s bit set\n", ue_status_hi_desc[i]); + if (ue_lo || ue_hi) { + error_detected = true; + dev_err(dev, + "Unrecoverable Error detected in the adapter"); + dev_err(dev, "Please reboot server to recover"); + if (skyhawk_chip(adapter)) + adapter->hw_error = true; + for (i = 0; ue_lo; ue_lo >>= 1, i++) { + if (ue_lo & 1) + dev_err(dev, "UE: %s bit set\n", + ue_status_low_desc[i]); + } + for (i = 0; ue_hi; ue_hi >>= 1, i++) { + if (ue_hi & 1) + dev_err(dev, "UE: %s bit set\n", + ue_status_hi_desc[i]); + } } } - + if (error_detected) + netif_carrier_off(netdev); } static void be_msix_disable(struct be_adapter *adapter) @@ -2505,7 +2557,7 @@ static void be_msix_disable(struct be_adapter *adapter) static int be_msix_enable(struct be_adapter *adapter) { - int i, status, num_vec; + int i, num_vec; struct device *dev = &adapter->pdev->dev; /* If RoCE is supported, program the max number of NIC vectors that @@ -2521,24 +2573,11 @@ static int be_msix_enable(struct be_adapter *adapter) for (i = 0; i < num_vec; i++) adapter->msix_entries[i].entry = i; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, num_vec); - if (status == 0) { - goto done; - } else if (status >= MIN_MSIX_VECTORS) { - num_vec = status; - status = pci_enable_msix(adapter->pdev, adapter->msix_entries, - num_vec); - if (!status) - goto done; - } - - dev_warn(dev, "MSIx enable failed\n"); + num_vec = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + MIN_MSIX_VECTORS, num_vec); + if (num_vec < 0) + goto fail; - /* INTx is not supported in VFs, so fail probe if enable_msix fails */ - if (!be_physfn(adapter)) - return status; - return 0; -done: if (be_roce_supported(adapter) && num_vec > MIN_MSIX_VECTORS) { adapter->num_msix_roce_vec = num_vec / 2; dev_info(dev, "enabled %d MSI-x vector(s) for RoCE\n", @@ -2550,6 +2589,14 @@ done: dev_info(dev, "enabled %d MSI-x vector(s) for NIC\n", adapter->num_msix_vec); return 0; + +fail: + dev_warn(dev, "MSIx enable failed\n"); + + /* INTx is not supported in VFs, so fail probe if enable_msix fails */ + if (!be_physfn(adapter)) + return num_vec; + return 0; } static inline int be_msix_vec_get(struct be_adapter *adapter, @@ -3013,11 +3060,11 @@ static int be_vf_setup_init(struct be_adapter *adapter) static int be_vf_setup(struct be_adapter *adapter) { + struct device *dev = &adapter->pdev->dev; struct be_vf_cfg *vf_cfg; - u16 def_vlan, lnk_speed; int status, old_vfs, vf; - struct device *dev = &adapter->pdev->dev; u32 privileges; + u16 lnk_speed; old_vfs = pci_num_vf(adapter->pdev); if (old_vfs) { @@ -3084,14 +3131,12 @@ static int be_vf_setup(struct be_adapter *adapter) if (!status) vf_cfg->tx_rate = lnk_speed; - status = be_cmd_get_hsw_config(adapter, &def_vlan, - vf + 1, vf_cfg->if_handle, NULL); - if (status) - goto err; - vf_cfg->def_vid = def_vlan; - - if (!old_vfs) + if (!old_vfs) { be_cmd_enable_vf(adapter, vf + 1); + be_cmd_set_logical_link_config(adapter, + IFLA_VF_LINK_STATE_AUTO, + vf+1); + } } if (!old_vfs) { @@ -3109,19 +3154,38 @@ err: return status; } +/* Converting function_mode bits on BE3 to SH mc_type enums */ + +static u8 be_convert_mc_type(u32 function_mode) +{ + if (function_mode & VNIC_MODE && function_mode & FLEX10_MODE) + return vNIC1; + else if (function_mode & FLEX10_MODE) + return FLEX10; + else if (function_mode & VNIC_MODE) + return vNIC2; + else if (function_mode & UMC_ENABLED) + return UMC; + else + return MC_NONE; +} + /* On BE2/BE3 FW does not suggest the supported limits */ static void BEx_get_resources(struct be_adapter *adapter, struct be_resources *res) { struct pci_dev *pdev = adapter->pdev; bool use_sriov = false; - int max_vfs; - - max_vfs = pci_sriov_get_totalvfs(pdev); - - if (BE3_chip(adapter) && sriov_want(adapter)) { - res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; - use_sriov = res->max_vfs; + int max_vfs = 0; + + if (be_physfn(adapter) && BE3_chip(adapter)) { + be_cmd_get_profile_config(adapter, res, 0); + /* Some old versions of BE3 FW don't report max_vfs value */ + if (res->max_vfs == 0) { + max_vfs = pci_sriov_get_totalvfs(pdev); + res->max_vfs = max_vfs > 0 ? min(MAX_VFS, max_vfs) : 0; + } + use_sriov = res->max_vfs && sriov_want(adapter); } if (be_physfn(adapter)) @@ -3129,17 +3193,32 @@ static void BEx_get_resources(struct be_adapter *adapter, else res->max_uc_mac = BE_VF_UC_PMAC_COUNT; - if (adapter->function_mode & FLEX10_MODE) - res->max_vlans = BE_NUM_VLANS_SUPPORTED/8; - else if (adapter->function_mode & UMC_ENABLED) - res->max_vlans = BE_UMC_NUM_VLANS_SUPPORTED; - else + adapter->mc_type = be_convert_mc_type(adapter->function_mode); + + if (be_is_mc(adapter)) { + /* Assuming that there are 4 channels per port, + * when multi-channel is enabled + */ + if (be_is_qnq_mode(adapter)) + res->max_vlans = BE_NUM_VLANS_SUPPORTED/8; + else + /* In a non-qnq multichannel mode, the pvid + * takes up one vlan entry + */ + res->max_vlans = (BE_NUM_VLANS_SUPPORTED / 4) - 1; + } else { res->max_vlans = BE_NUM_VLANS_SUPPORTED; + } + res->max_mcast_mac = BE_MAX_MC; - /* For BE3 1Gb ports, F/W does not properly support multiple TXQs */ - if (BE2_chip(adapter) || use_sriov || be_is_mc(adapter) || - !be_physfn(adapter) || (adapter->port_num > 1)) + /* 1) For BE3 1Gb ports, FW does not support multiple TXQs + * 2) Create multiple TX rings on a BE3-R multi-channel interface + * *only* if it is RSS-capable. + */ + if (BE2_chip(adapter) || use_sriov || (adapter->port_num > 1) || + !be_physfn(adapter) || (be_is_mc(adapter) && + !(adapter->function_caps & BE_FUNCTION_CAPS_RSS))) res->max_tx_qs = 1; else res->max_tx_qs = BE3_MAX_TX_QS; @@ -3151,7 +3230,7 @@ static void BEx_get_resources(struct be_adapter *adapter, res->max_rx_qs = res->max_rss_qs + 1; if (be_physfn(adapter)) - res->max_evt_qs = (max_vfs > 0) ? + res->max_evt_qs = (res->max_vfs > 0) ? BE3_SRIOV_MAX_EVT_QS : BE3_MAX_EVT_QS; else res->max_evt_qs = 1; @@ -3242,9 +3321,8 @@ static int be_get_config(struct be_adapter *adapter) if (status) return status; - /* primary mac needs 1 pmac entry */ - adapter->pmac_id = kcalloc(be_max_uc(adapter) + 1, sizeof(u32), - GFP_KERNEL); + adapter->pmac_id = kcalloc(be_max_uc(adapter), + sizeof(*adapter->pmac_id), GFP_KERNEL); if (!adapter->pmac_id) return -ENOMEM; @@ -3418,6 +3496,10 @@ static int be_setup(struct be_adapter *adapter) be_cmd_set_flow_control(adapter, adapter->tx_fc, adapter->rx_fc); + if (be_physfn(adapter)) + be_cmd_set_logical_link_config(adapter, + IFLA_VF_LINK_STATE_AUTO, 0); + if (sriov_want(adapter)) { if (be_max_vfs(adapter)) be_vf_setup(adapter); @@ -4057,6 +4139,7 @@ static const struct net_device_ops be_netdev_ops = { .ndo_set_vf_vlan = be_set_vf_vlan, .ndo_set_vf_tx_rate = be_set_vf_tx_rate, .ndo_get_vf_config = be_get_vf_config, + .ndo_set_vf_link_state = be_set_vf_link_state, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = be_netpoll, #endif @@ -4417,14 +4500,32 @@ static bool be_reset_required(struct be_adapter *adapter) static char *mc_name(struct be_adapter *adapter) { - if (adapter->function_mode & FLEX10_MODE) - return "FLEX10"; - else if (adapter->function_mode & VNIC_MODE) - return "vNIC"; - else if (adapter->function_mode & UMC_ENABLED) - return "UMC"; - else - return ""; + char *str = ""; /* default */ + + switch (adapter->mc_type) { + case UMC: + str = "UMC"; + break; + case FLEX10: + str = "FLEX10"; + break; + case vNIC1: + str = "vNIC-1"; + break; + case nPAR: + str = "nPAR"; + break; + case UFP: + str = "UFP"; + break; + case vNIC2: + str = "vNIC-2"; + break; + default: + str = ""; + } + + return str; } static inline char *func_name(struct be_adapter *adapter) diff --git a/drivers/net/ethernet/emulex/benet/be_roce.c b/drivers/net/ethernet/emulex/benet/be_roce.c index 9cd5415fe017..a5dae4a62bb3 100644 --- a/drivers/net/ethernet/emulex/benet/be_roce.c +++ b/drivers/net/ethernet/emulex/benet/be_roce.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/net/ethernet/emulex/benet/be_roce.h b/drivers/net/ethernet/emulex/benet/be_roce.h index 2cd1129e19af..a3ef8f804b9e 100644 --- a/drivers/net/ethernet/emulex/benet/be_roce.h +++ b/drivers/net/ethernet/emulex/benet/be_roce.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 - 2013 Emulex + * Copyright (C) 2005 - 2014 Emulex * All rights reserved. * * This program is free software; you can redistribute it and/or diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 4de8cfd149cf..55e0fa03dc90 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -13,6 +13,7 @@ #include <linux/dma-mapping.h> #include <linux/etherdevice.h> +#include <linux/clk.h> #include <linux/crc32.h> #include <linux/interrupt.h> #include <linux/io.h> @@ -51,6 +52,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); #define ETH_HASH0 0x48 #define ETH_HASH1 0x4c #define ETH_TXCTRL 0x50 +#define ETH_END 0x54 /* mode register */ #define MODER_RXEN (1 << 0) /* receive enable */ @@ -179,6 +181,7 @@ MODULE_PARM_DESC(buffer_size, "DMA buffer allocation size"); * @membase: pointer to buffer memory region * @dma_alloc: dma allocated buffer size * @io_region_size: I/O memory region size + * @num_bd: number of buffer descriptors * @num_tx: number of send buffers * @cur_tx: last send buffer written * @dty_tx: last buffer actually sent @@ -199,6 +202,7 @@ struct ethoc { int dma_alloc; resource_size_t io_region_size; + unsigned int num_bd; unsigned int num_tx; unsigned int cur_tx; unsigned int dty_tx; @@ -216,6 +220,7 @@ struct ethoc { struct phy_device *phy; struct mii_bus *mdio; + struct clk *clk; s8 phy_id; }; @@ -688,6 +693,11 @@ static int ethoc_mdio_probe(struct net_device *dev) } priv->phy = phy; + phy->advertising &= ~(ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half); + phy->supported &= ~(SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half); + return 0; } @@ -890,6 +900,102 @@ out: return NETDEV_TX_OK; } +static int ethoc_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ethoc *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phy; + + if (!phydev) + return -EOPNOTSUPP; + + return phy_ethtool_gset(phydev, cmd); +} + +static int ethoc_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct ethoc *priv = netdev_priv(dev); + struct phy_device *phydev = priv->phy; + + if (!phydev) + return -EOPNOTSUPP; + + return phy_ethtool_sset(phydev, cmd); +} + +static int ethoc_get_regs_len(struct net_device *netdev) +{ + return ETH_END; +} + +static void ethoc_get_regs(struct net_device *dev, struct ethtool_regs *regs, + void *p) +{ + struct ethoc *priv = netdev_priv(dev); + u32 *regs_buff = p; + unsigned i; + + regs->version = 0; + for (i = 0; i < ETH_END / sizeof(u32); ++i) + regs_buff[i] = ethoc_read(priv, i * sizeof(u32)); +} + +static void ethoc_get_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct ethoc *priv = netdev_priv(dev); + + ring->rx_max_pending = priv->num_bd - 1; + ring->rx_mini_max_pending = 0; + ring->rx_jumbo_max_pending = 0; + ring->tx_max_pending = priv->num_bd - 1; + + ring->rx_pending = priv->num_rx; + ring->rx_mini_pending = 0; + ring->rx_jumbo_pending = 0; + ring->tx_pending = priv->num_tx; +} + +static int ethoc_set_ringparam(struct net_device *dev, + struct ethtool_ringparam *ring) +{ + struct ethoc *priv = netdev_priv(dev); + + if (ring->tx_pending < 1 || ring->rx_pending < 1 || + ring->tx_pending + ring->rx_pending > priv->num_bd) + return -EINVAL; + if (ring->rx_mini_pending || ring->rx_jumbo_pending) + return -EINVAL; + + if (netif_running(dev)) { + netif_tx_disable(dev); + ethoc_disable_rx_and_tx(priv); + ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX); + synchronize_irq(dev->irq); + } + + priv->num_tx = rounddown_pow_of_two(ring->tx_pending); + priv->num_rx = ring->rx_pending; + ethoc_init_ring(priv, dev->mem_start); + + if (netif_running(dev)) { + ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX); + ethoc_enable_rx_and_tx(priv); + netif_wake_queue(dev); + } + return 0; +} + +const struct ethtool_ops ethoc_ethtool_ops = { + .get_settings = ethoc_get_settings, + .set_settings = ethoc_set_settings, + .get_regs_len = ethoc_get_regs_len, + .get_regs = ethoc_get_regs, + .get_link = ethtool_op_get_link, + .get_ringparam = ethoc_get_ringparam, + .set_ringparam = ethoc_set_ringparam, + .get_ts_info = ethtool_op_get_ts_info, +}; + static const struct net_device_ops ethoc_netdev_ops = { .ndo_open = ethoc_open, .ndo_stop = ethoc_stop, @@ -917,6 +1023,8 @@ static int ethoc_probe(struct platform_device *pdev) int num_bd; int ret = 0; bool random_mac = false; + struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev); + u32 eth_clkfreq = pdata ? pdata->eth_clkfreq : 0; /* allocate networking device */ netdev = alloc_etherdev(sizeof(struct ethoc)); @@ -1016,6 +1124,7 @@ static int ethoc_probe(struct platform_device *pdev) ret = -ENODEV; goto error; } + priv->num_bd = num_bd; /* num_tx must be a power of two */ priv->num_tx = rounddown_pow_of_two(num_bd >> 1); priv->num_rx = num_bd - priv->num_tx; @@ -1030,8 +1139,7 @@ static int ethoc_probe(struct platform_device *pdev) } /* Allow the platform setup code to pass in a MAC address. */ - if (dev_get_platdata(&pdev->dev)) { - struct ethoc_platform_data *pdata = dev_get_platdata(&pdev->dev); + if (pdata) { memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN); priv->phy_id = pdata->phy_id; } else { @@ -1069,6 +1177,27 @@ static int ethoc_probe(struct platform_device *pdev) if (random_mac) netdev->addr_assign_type = NET_ADDR_RANDOM; + /* Allow the platform setup code to adjust MII management bus clock. */ + if (!eth_clkfreq) { + struct clk *clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(clk)) { + priv->clk = clk; + clk_prepare_enable(clk); + eth_clkfreq = clk_get_rate(clk); + } + } + if (eth_clkfreq) { + u32 clkdiv = MIIMODER_CLKDIV(eth_clkfreq / 2500000 + 1); + + if (!clkdiv) + clkdiv = 2; + dev_dbg(&pdev->dev, "setting MII clkdiv to %u\n", clkdiv); + ethoc_write(priv, MIIMODER, + (ethoc_read(priv, MIIMODER) & MIIMODER_NOPRE) | + clkdiv); + } + /* register MII bus */ priv->mdio = mdiobus_alloc(); if (!priv->mdio) { @@ -1111,6 +1240,7 @@ static int ethoc_probe(struct platform_device *pdev) netdev->netdev_ops = ðoc_netdev_ops; netdev->watchdog_timeo = ETHOC_TIMEOUT; netdev->features |= 0; + netdev->ethtool_ops = ðoc_ethtool_ops; /* setup NAPI */ netif_napi_add(netdev, &priv->napi, ethoc_poll, 64); @@ -1133,6 +1263,8 @@ free_mdio: kfree(priv->mdio->irq); mdiobus_free(priv->mdio); free: + if (priv->clk) + clk_disable_unprepare(priv->clk); free_netdev(netdev); out: return ret; @@ -1157,6 +1289,8 @@ static int ethoc_remove(struct platform_device *pdev) kfree(priv->mdio->irq); mdiobus_free(priv->mdio); } + if (priv->clk) + clk_disable_unprepare(priv->clk); unregister_netdev(netdev); free_netdev(netdev); } diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index 549ce13b92ac..71debd1c18c9 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -14,7 +14,6 @@ obj-$(CONFIG_FSL_XGMAC_MDIO) += xgmac_mdio.o obj-$(CONFIG_GIANFAR) += gianfar_driver.o obj-$(CONFIG_PTP_1588_CLOCK_GIANFAR) += gianfar_ptp.o gianfar_driver-objs := gianfar.o \ - gianfar_ethtool.o \ - gianfar_sysfs.o + gianfar_ethtool.o obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o ucc_geth_driver-objs := ucc_geth.o ucc_geth_ethtool.o diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index d4782b42401b..479a7cba45c0 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -389,12 +389,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) netdev_err(ndev, "Tx DMA memory map failed\n"); return NETDEV_TX_OK; } - /* Send it on its way. Tell FEC it's ready, interrupt when done, - * it's the last BD of the frame, and to put the CRC on the end. - */ - status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR - | BD_ENET_TX_LAST | BD_ENET_TX_TC); - bdp->cbd_sc = status; if (fep->bufdesc_ex) { @@ -416,6 +410,13 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) } } + /* Send it on its way. Tell FEC it's ready, interrupt when done, + * it's the last BD of the frame, and to put the CRC on the end. + */ + status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR + | BD_ENET_TX_LAST | BD_ENET_TX_TC); + bdp->cbd_sc = status; + bdp_pre = fec_enet_get_prevdesc(bdp, fep); if ((id_entry->driver_data & FEC_QUIRK_ERR006358) && !(bdp_pre->cbd_sc & BD_ENET_TX_READY)) { @@ -1778,8 +1779,6 @@ fec_enet_open(struct net_device *ndev) struct fec_enet_private *fep = netdev_priv(ndev); int ret; - napi_enable(&fep->napi); - /* I should reset the ring buffers here, but I don't yet know * a simple way to do that. */ @@ -1794,6 +1793,8 @@ fec_enet_open(struct net_device *ndev) fec_enet_free_buffers(ndev); return ret; } + + napi_enable(&fep->napi); phy_start(fep->phy_dev); netif_start_queue(ndev); fep->opened = 1; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index ad5a5aadc7e1..6e12f9365856 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -9,7 +9,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc. + * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc. * Copyright 2007 MontaVista Software, Inc. * * This program is free software; you can redistribute it and/or modify it @@ -121,7 +121,6 @@ static irqreturn_t gfar_error(int irq, void *dev_id); static irqreturn_t gfar_transmit(int irq, void *dev_id); static irqreturn_t gfar_interrupt(int irq, void *dev_id); static void adjust_link(struct net_device *dev); -static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); static int gfar_probe(struct platform_device *ofdev); static int gfar_remove(struct platform_device *ofdev); @@ -129,8 +128,10 @@ static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); static void gfar_configure_serdes(struct net_device *dev); -static int gfar_poll(struct napi_struct *napi, int budget); -static int gfar_poll_sq(struct napi_struct *napi, int budget); +static int gfar_poll_rx(struct napi_struct *napi, int budget); +static int gfar_poll_tx(struct napi_struct *napi, int budget); +static int gfar_poll_rx_sq(struct napi_struct *napi, int budget); +static int gfar_poll_tx_sq(struct napi_struct *napi, int budget); #ifdef CONFIG_NET_POLL_CONTROLLER static void gfar_netpoll(struct net_device *dev); #endif @@ -138,9 +139,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int amount_pull, struct napi_struct *napi); -void gfar_halt(struct net_device *dev); -static void gfar_halt_nodisable(struct net_device *dev); -void gfar_start(struct net_device *dev); +static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, const u8 *addr); @@ -332,72 +331,76 @@ static void gfar_init_tx_rx_base(struct gfar_private *priv) } } -static void gfar_init_mac(struct net_device *ndev) +static void gfar_rx_buff_size_config(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 rctrl = 0; - u32 tctrl = 0; - u32 attrs = 0; - - /* write the tx/rx base registers */ - gfar_init_tx_rx_base(priv); - - /* Configure the coalescing support */ - gfar_configure_coalescing_all(priv); + int frame_size = priv->ndev->mtu + ETH_HLEN; /* set this when rx hw offload (TOE) functions are being used */ priv->uses_rxfcb = 0; + if (priv->ndev->features & (NETIF_F_RXCSUM | NETIF_F_HW_VLAN_CTAG_RX)) + priv->uses_rxfcb = 1; + + if (priv->hwts_rx_en) + priv->uses_rxfcb = 1; + + if (priv->uses_rxfcb) + frame_size += GMAC_FCB_LEN; + + frame_size += priv->padding; + + frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + + INCREMENTAL_BUFFER_SIZE; + + priv->rx_buffer_size = frame_size; +} + +static void gfar_mac_rx_config(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 rctrl = 0; + if (priv->rx_filer_enable) { rctrl |= RCTRL_FILREN; /* Program the RIR0 reg with the required distribution */ - gfar_write(®s->rir0, DEFAULT_RIR0); + if (priv->poll_mode == GFAR_SQ_POLLING) + gfar_write(®s->rir0, DEFAULT_2RXQ_RIR0); + else /* GFAR_MQ_POLLING */ + gfar_write(®s->rir0, DEFAULT_8RXQ_RIR0); } /* Restore PROMISC mode */ - if (ndev->flags & IFF_PROMISC) + if (priv->ndev->flags & IFF_PROMISC) rctrl |= RCTRL_PROM; - if (ndev->features & NETIF_F_RXCSUM) { + if (priv->ndev->features & NETIF_F_RXCSUM) rctrl |= RCTRL_CHECKSUMMING; - priv->uses_rxfcb = 1; - } - if (priv->extended_hash) { - rctrl |= RCTRL_EXTHASH; - - gfar_clear_exact_match(ndev); - rctrl |= RCTRL_EMEN; - } + if (priv->extended_hash) + rctrl |= RCTRL_EXTHASH | RCTRL_EMEN; if (priv->padding) { rctrl &= ~RCTRL_PAL_MASK; rctrl |= RCTRL_PADDING(priv->padding); } - /* Insert receive time stamps into padding alignment bytes */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) { - rctrl &= ~RCTRL_PAL_MASK; - rctrl |= RCTRL_PADDING(8); - priv->padding = 8; - } - /* Enable HW time stamping if requested from user space */ - if (priv->hwts_rx_en) { + if (priv->hwts_rx_en) rctrl |= RCTRL_PRSDEP_INIT | RCTRL_TS_ENABLE; - priv->uses_rxfcb = 1; - } - if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX) { + if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_RX) rctrl |= RCTRL_VLEX | RCTRL_PRSDEP_INIT; - priv->uses_rxfcb = 1; - } /* Init rctrl based on our settings */ gfar_write(®s->rctrl, rctrl); +} + +static void gfar_mac_tx_config(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 tctrl = 0; - if (ndev->features & NETIF_F_IP_CSUM) + if (priv->ndev->features & NETIF_F_IP_CSUM) tctrl |= TCTRL_INIT_CSUM; if (priv->prio_sched_en) @@ -408,30 +411,51 @@ static void gfar_init_mac(struct net_device *ndev) gfar_write(®s->tr47wt, DEFAULT_WRRS_WEIGHT); } - gfar_write(®s->tctrl, tctrl); + if (priv->ndev->features & NETIF_F_HW_VLAN_CTAG_TX) + tctrl |= TCTRL_VLINS; - /* Set the extraction length and index */ - attrs = ATTRELI_EL(priv->rx_stash_size) | - ATTRELI_EI(priv->rx_stash_index); + gfar_write(®s->tctrl, tctrl); +} - gfar_write(®s->attreli, attrs); +static void gfar_configure_coalescing(struct gfar_private *priv, + unsigned long tx_mask, unsigned long rx_mask) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 __iomem *baddr; - /* Start with defaults, and add stashing or locking - * depending on the approprate variables - */ - attrs = ATTR_INIT_SETTINGS; + if (priv->mode == MQ_MG_MODE) { + int i = 0; - if (priv->bd_stash_en) - attrs |= ATTR_BDSTASH; + baddr = ®s->txic0; + for_each_set_bit(i, &tx_mask, priv->num_tx_queues) { + gfar_write(baddr + i, 0); + if (likely(priv->tx_queue[i]->txcoalescing)) + gfar_write(baddr + i, priv->tx_queue[i]->txic); + } - if (priv->rx_stash_size != 0) - attrs |= ATTR_BUFSTASH; + baddr = ®s->rxic0; + for_each_set_bit(i, &rx_mask, priv->num_rx_queues) { + gfar_write(baddr + i, 0); + if (likely(priv->rx_queue[i]->rxcoalescing)) + gfar_write(baddr + i, priv->rx_queue[i]->rxic); + } + } else { + /* Backward compatible case -- even if we enable + * multiple queues, there's only single reg to program + */ + gfar_write(®s->txic, 0); + if (likely(priv->tx_queue[0]->txcoalescing)) + gfar_write(®s->txic, priv->tx_queue[0]->txic); - gfar_write(®s->attr, attrs); + gfar_write(®s->rxic, 0); + if (unlikely(priv->rx_queue[0]->rxcoalescing)) + gfar_write(®s->rxic, priv->rx_queue[0]->rxic); + } +} - gfar_write(®s->fifo_tx_thr, priv->fifo_threshold); - gfar_write(®s->fifo_tx_starve, priv->fifo_starve); - gfar_write(®s->fifo_tx_starve_shutoff, priv->fifo_starve_off); +void gfar_configure_coalescing_all(struct gfar_private *priv) +{ + gfar_configure_coalescing(priv, 0xFF, 0xFF); } static struct net_device_stats *gfar_get_stats(struct net_device *dev) @@ -479,12 +503,27 @@ static const struct net_device_ops gfar_netdev_ops = { #endif }; -void lock_rx_qs(struct gfar_private *priv) +static void gfar_ints_disable(struct gfar_private *priv) { int i; + for (i = 0; i < priv->num_grps; i++) { + struct gfar __iomem *regs = priv->gfargrp[i].regs; + /* Clear IEVENT */ + gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - for (i = 0; i < priv->num_rx_queues; i++) - spin_lock(&priv->rx_queue[i]->rxlock); + /* Initialize IMASK */ + gfar_write(®s->imask, IMASK_INIT_CLEAR); + } +} + +static void gfar_ints_enable(struct gfar_private *priv) +{ + int i; + for (i = 0; i < priv->num_grps; i++) { + struct gfar __iomem *regs = priv->gfargrp[i].regs; + /* Unmask the interrupts we look for */ + gfar_write(®s->imask, IMASK_DEFAULT); + } } void lock_tx_qs(struct gfar_private *priv) @@ -495,23 +534,50 @@ void lock_tx_qs(struct gfar_private *priv) spin_lock(&priv->tx_queue[i]->txlock); } -void unlock_rx_qs(struct gfar_private *priv) +void unlock_tx_qs(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_rx_queues; i++) - spin_unlock(&priv->rx_queue[i]->rxlock); + for (i = 0; i < priv->num_tx_queues; i++) + spin_unlock(&priv->tx_queue[i]->txlock); } -void unlock_tx_qs(struct gfar_private *priv) +static int gfar_alloc_tx_queues(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_tx_queues; i++) - spin_unlock(&priv->tx_queue[i]->txlock); + for (i = 0; i < priv->num_tx_queues; i++) { + priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q), + GFP_KERNEL); + if (!priv->tx_queue[i]) + return -ENOMEM; + + priv->tx_queue[i]->tx_skbuff = NULL; + priv->tx_queue[i]->qindex = i; + priv->tx_queue[i]->dev = priv->ndev; + spin_lock_init(&(priv->tx_queue[i]->txlock)); + } + return 0; } -static void free_tx_pointers(struct gfar_private *priv) +static int gfar_alloc_rx_queues(struct gfar_private *priv) +{ + int i; + + for (i = 0; i < priv->num_rx_queues; i++) { + priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q), + GFP_KERNEL); + if (!priv->rx_queue[i]) + return -ENOMEM; + + priv->rx_queue[i]->rx_skbuff = NULL; + priv->rx_queue[i]->qindex = i; + priv->rx_queue[i]->dev = priv->ndev; + } + return 0; +} + +static void gfar_free_tx_queues(struct gfar_private *priv) { int i; @@ -519,7 +585,7 @@ static void free_tx_pointers(struct gfar_private *priv) kfree(priv->tx_queue[i]); } -static void free_rx_pointers(struct gfar_private *priv) +static void gfar_free_rx_queues(struct gfar_private *priv) { int i; @@ -553,23 +619,26 @@ static void disable_napi(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_grps; i++) - napi_disable(&priv->gfargrp[i].napi); + for (i = 0; i < priv->num_grps; i++) { + napi_disable(&priv->gfargrp[i].napi_rx); + napi_disable(&priv->gfargrp[i].napi_tx); + } } static void enable_napi(struct gfar_private *priv) { int i; - for (i = 0; i < priv->num_grps; i++) - napi_enable(&priv->gfargrp[i].napi); + for (i = 0; i < priv->num_grps; i++) { + napi_enable(&priv->gfargrp[i].napi_rx); + napi_enable(&priv->gfargrp[i].napi_tx); + } } static int gfar_parse_group(struct device_node *np, struct gfar_private *priv, const char *model) { struct gfar_priv_grp *grp = &priv->gfargrp[priv->num_grps]; - u32 *queue_mask; int i; for (i = 0; i < GFAR_NUM_IRQS; i++) { @@ -598,16 +667,52 @@ static int gfar_parse_group(struct device_node *np, grp->priv = priv; spin_lock_init(&grp->grplock); if (priv->mode == MQ_MG_MODE) { - queue_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); - grp->rx_bit_map = queue_mask ? - *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); - queue_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); - grp->tx_bit_map = queue_mask ? - *queue_mask : (DEFAULT_MAPPING >> priv->num_grps); + u32 *rxq_mask, *txq_mask; + rxq_mask = (u32 *)of_get_property(np, "fsl,rx-bit-map", NULL); + txq_mask = (u32 *)of_get_property(np, "fsl,tx-bit-map", NULL); + + if (priv->poll_mode == GFAR_SQ_POLLING) { + /* One Q per interrupt group: Q0 to G0, Q1 to G1 */ + grp->rx_bit_map = (DEFAULT_MAPPING >> priv->num_grps); + grp->tx_bit_map = (DEFAULT_MAPPING >> priv->num_grps); + } else { /* GFAR_MQ_POLLING */ + grp->rx_bit_map = rxq_mask ? + *rxq_mask : (DEFAULT_MAPPING >> priv->num_grps); + grp->tx_bit_map = txq_mask ? + *txq_mask : (DEFAULT_MAPPING >> priv->num_grps); + } } else { grp->rx_bit_map = 0xFF; grp->tx_bit_map = 0xFF; } + + /* bit_map's MSB is q0 (from q0 to q7) but, for_each_set_bit parses + * right to left, so we need to revert the 8 bits to get the q index + */ + grp->rx_bit_map = bitrev8(grp->rx_bit_map); + grp->tx_bit_map = bitrev8(grp->tx_bit_map); + + /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values, + * also assign queues to groups + */ + for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) { + if (!grp->rx_queue) + grp->rx_queue = priv->rx_queue[i]; + grp->num_rx_queues++; + grp->rstat |= (RSTAT_CLEAR_RHALT >> i); + priv->rqueue |= ((RQUEUE_EN0 | RQUEUE_EX0) >> i); + priv->rx_queue[i]->grp = grp; + } + + for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) { + if (!grp->tx_queue) + grp->tx_queue = priv->tx_queue[i]; + grp->num_tx_queues++; + grp->tstat |= (TSTAT_CLEAR_THALT >> i); + priv->tqueue |= (TQUEUE_EN0 >> i); + priv->tx_queue[i]->grp = grp; + } + priv->num_grps++; return 0; @@ -628,13 +733,35 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) const u32 *stash_idx; unsigned int num_tx_qs, num_rx_qs; u32 *tx_queues, *rx_queues; + unsigned short mode, poll_mode; if (!np || !of_device_is_available(np)) return -ENODEV; - /* parse the num of tx and rx queues */ + if (of_device_is_compatible(np, "fsl,etsec2")) { + mode = MQ_MG_MODE; + poll_mode = GFAR_SQ_POLLING; + } else { + mode = SQ_SG_MODE; + poll_mode = GFAR_SQ_POLLING; + } + + /* parse the num of HW tx and rx queues */ tx_queues = (u32 *)of_get_property(np, "fsl,num_tx_queues", NULL); - num_tx_qs = tx_queues ? *tx_queues : 1; + rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); + + if (mode == SQ_SG_MODE) { + num_tx_qs = 1; + num_rx_qs = 1; + } else { /* MQ_MG_MODE */ + if (poll_mode == GFAR_SQ_POLLING) { + num_tx_qs = 2; /* one txq per int group */ + num_rx_qs = 2; /* one rxq per int group */ + } else { /* GFAR_MQ_POLLING */ + num_tx_qs = tx_queues ? *tx_queues : 1; + num_rx_qs = rx_queues ? *rx_queues : 1; + } + } if (num_tx_qs > MAX_TX_QS) { pr_err("num_tx_qs(=%d) greater than MAX_TX_QS(=%d)\n", @@ -643,9 +770,6 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) return -EINVAL; } - rx_queues = (u32 *)of_get_property(np, "fsl,num_rx_queues", NULL); - num_rx_qs = rx_queues ? *rx_queues : 1; - if (num_rx_qs > MAX_RX_QS) { pr_err("num_rx_qs(=%d) greater than MAX_RX_QS(=%d)\n", num_rx_qs, MAX_RX_QS); @@ -661,10 +785,20 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv = netdev_priv(dev); priv->ndev = dev; + priv->mode = mode; + priv->poll_mode = poll_mode; + priv->num_tx_queues = num_tx_qs; netif_set_real_num_rx_queues(dev, num_rx_qs); priv->num_rx_queues = num_rx_qs; - priv->num_grps = 0x0; + + err = gfar_alloc_tx_queues(priv); + if (err) + goto tx_alloc_failed; + + err = gfar_alloc_rx_queues(priv); + if (err) + goto rx_alloc_failed; /* Init Rx queue filer rule set linked list */ INIT_LIST_HEAD(&priv->rx_list.list); @@ -677,52 +811,18 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) priv->gfargrp[i].regs = NULL; /* Parse and initialize group specific information */ - if (of_device_is_compatible(np, "fsl,etsec2")) { - priv->mode = MQ_MG_MODE; + if (priv->mode == MQ_MG_MODE) { for_each_child_of_node(np, child) { err = gfar_parse_group(child, priv, model); if (err) goto err_grp_init; } - } else { - priv->mode = SQ_SG_MODE; + } else { /* SQ_SG_MODE */ err = gfar_parse_group(np, priv, model); if (err) goto err_grp_init; } - for (i = 0; i < priv->num_tx_queues; i++) - priv->tx_queue[i] = NULL; - for (i = 0; i < priv->num_rx_queues; i++) - priv->rx_queue[i] = NULL; - - for (i = 0; i < priv->num_tx_queues; i++) { - priv->tx_queue[i] = kzalloc(sizeof(struct gfar_priv_tx_q), - GFP_KERNEL); - if (!priv->tx_queue[i]) { - err = -ENOMEM; - goto tx_alloc_failed; - } - priv->tx_queue[i]->tx_skbuff = NULL; - priv->tx_queue[i]->qindex = i; - priv->tx_queue[i]->dev = dev; - spin_lock_init(&(priv->tx_queue[i]->txlock)); - } - - for (i = 0; i < priv->num_rx_queues; i++) { - priv->rx_queue[i] = kzalloc(sizeof(struct gfar_priv_rx_q), - GFP_KERNEL); - if (!priv->rx_queue[i]) { - err = -ENOMEM; - goto rx_alloc_failed; - } - priv->rx_queue[i]->rx_skbuff = NULL; - priv->rx_queue[i]->qindex = i; - priv->rx_queue[i]->dev = dev; - spin_lock_init(&(priv->rx_queue[i]->rxlock)); - } - - stash = of_get_property(np, "bd-stash", NULL); if (stash) { @@ -749,17 +849,16 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) memcpy(dev->dev_addr, mac_addr, ETH_ALEN); if (model && !strcasecmp(model, "TSEC")) - priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR; if (model && !strcasecmp(model, "eTSEC")) - priv->device_flags = FSL_GIANFAR_DEV_HAS_GIGABIT | + priv->device_flags |= FSL_GIANFAR_DEV_HAS_GIGABIT | FSL_GIANFAR_DEV_HAS_COALESCE | FSL_GIANFAR_DEV_HAS_RMON | FSL_GIANFAR_DEV_HAS_MULTI_INTR | - FSL_GIANFAR_DEV_HAS_PADDING | FSL_GIANFAR_DEV_HAS_CSUM | FSL_GIANFAR_DEV_HAS_VLAN | FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | @@ -784,12 +883,12 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev) return 0; -rx_alloc_failed: - free_rx_pointers(priv); -tx_alloc_failed: - free_tx_pointers(priv); err_grp_init: unmap_group_regs(priv); +rx_alloc_failed: + gfar_free_rx_queues(priv); +tx_alloc_failed: + gfar_free_tx_queues(priv); free_gfar_dev(priv); return err; } @@ -822,18 +921,16 @@ static int gfar_hwtstamp_set(struct net_device *netdev, struct ifreq *ifr) switch (config.rx_filter) { case HWTSTAMP_FILTER_NONE: if (priv->hwts_rx_en) { - stop_gfar(netdev); priv->hwts_rx_en = 0; - startup_gfar(netdev); + reset_gfar(netdev); } break; default: if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER)) return -ERANGE; if (!priv->hwts_rx_en) { - stop_gfar(netdev); priv->hwts_rx_en = 1; - startup_gfar(netdev); + reset_gfar(netdev); } config.rx_filter = HWTSTAMP_FILTER_ALL; break; @@ -875,19 +972,6 @@ static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) return phy_mii_ioctl(priv->phydev, rq, cmd); } -static unsigned int reverse_bitmap(unsigned int bit_map, unsigned int max_qs) -{ - unsigned int new_bit_map = 0x0; - int mask = 0x1 << (max_qs - 1), i; - - for (i = 0; i < max_qs; i++) { - if (bit_map & mask) - new_bit_map = new_bit_map + (1 << i); - mask = mask >> 0x1; - } - return new_bit_map; -} - static u32 cluster_entry_per_class(struct gfar_private *priv, u32 rqfar, u32 class) { @@ -1005,99 +1089,140 @@ static void gfar_detect_errata(struct gfar_private *priv) priv->errata); } -/* Set up the ethernet device structure, private data, - * and anything else we need before we start - */ -static int gfar_probe(struct platform_device *ofdev) +void gfar_mac_reset(struct gfar_private *priv) { + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - struct net_device *dev = NULL; - struct gfar_private *priv = NULL; - struct gfar __iomem *regs = NULL; - int err = 0, i, grp_idx = 0; - u32 rstat = 0, tstat = 0, rqueue = 0, tqueue = 0; - u32 isrg = 0; - u32 __iomem *baddr; - - err = gfar_of_init(ofdev, &dev); - - if (err) - return err; - - priv = netdev_priv(dev); - priv->ndev = dev; - priv->ofdev = ofdev; - priv->dev = &ofdev->dev; - SET_NETDEV_DEV(dev, &ofdev->dev); - - spin_lock_init(&priv->bflock); - INIT_WORK(&priv->reset_task, gfar_reset_task); - - platform_set_drvdata(ofdev, priv); - regs = priv->gfargrp[0].regs; - - gfar_detect_errata(priv); - - /* Stop the DMA engine now, in case it was running before - * (The firmware could have used it, and left it running). - */ - gfar_halt(dev); /* Reset MAC layer */ gfar_write(®s->maccfg1, MACCFG1_SOFT_RESET); /* We need to delay at least 3 TX clocks */ - udelay(2); + udelay(3); - tempval = 0; - if (!priv->pause_aneg_en && priv->tx_pause_en) - tempval |= MACCFG1_TX_FLOW; - if (!priv->pause_aneg_en && priv->rx_pause_en) - tempval |= MACCFG1_RX_FLOW; /* the soft reset bit is not self-resetting, so we need to * clear it before resuming normal operation */ - gfar_write(®s->maccfg1, tempval); + gfar_write(®s->maccfg1, 0); + + udelay(3); + + /* Compute rx_buff_size based on config flags */ + gfar_rx_buff_size_config(priv); + + /* Initialize the max receive frame/buffer lengths */ + gfar_write(®s->maxfrm, priv->rx_buffer_size); + gfar_write(®s->mrblr, priv->rx_buffer_size); + + /* Initialize the Minimum Frame Length Register */ + gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); /* Initialize MACCFG2. */ tempval = MACCFG2_INIT_SETTINGS; - if (gfar_has_errata(priv, GFAR_ERRATA_74)) + + /* If the mtu is larger than the max size for standard + * ethernet frames (ie, a jumbo frame), then set maccfg2 + * to allow huge frames, and to check the length + */ + if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || + gfar_has_errata(priv, GFAR_ERRATA_74)) tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; + gfar_write(®s->maccfg2, tempval); + /* Clear mac addr hash registers */ + gfar_write(®s->igaddr0, 0); + gfar_write(®s->igaddr1, 0); + gfar_write(®s->igaddr2, 0); + gfar_write(®s->igaddr3, 0); + gfar_write(®s->igaddr4, 0); + gfar_write(®s->igaddr5, 0); + gfar_write(®s->igaddr6, 0); + gfar_write(®s->igaddr7, 0); + + gfar_write(®s->gaddr0, 0); + gfar_write(®s->gaddr1, 0); + gfar_write(®s->gaddr2, 0); + gfar_write(®s->gaddr3, 0); + gfar_write(®s->gaddr4, 0); + gfar_write(®s->gaddr5, 0); + gfar_write(®s->gaddr6, 0); + gfar_write(®s->gaddr7, 0); + + if (priv->extended_hash) + gfar_clear_exact_match(priv->ndev); + + gfar_mac_rx_config(priv); + + gfar_mac_tx_config(priv); + + gfar_set_mac_address(priv->ndev); + + gfar_set_multi(priv->ndev); + + /* clear ievent and imask before configuring coalescing */ + gfar_ints_disable(priv); + + /* Configure the coalescing support */ + gfar_configure_coalescing_all(priv); +} + +static void gfar_hw_init(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 attrs; + + /* Stop the DMA engine now, in case it was running before + * (The firmware could have used it, and left it running). + */ + gfar_halt(priv); + + gfar_mac_reset(priv); + + /* Zero out the rmon mib registers if it has them */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + memset_io(&(regs->rmon), 0, sizeof(struct rmon_mib)); + + /* Mask off the CAM interrupts */ + gfar_write(®s->rmon.cam1, 0xffffffff); + gfar_write(®s->rmon.cam2, 0xffffffff); + } + /* Initialize ECNTRL */ gfar_write(®s->ecntrl, ECNTRL_INIT_SETTINGS); - /* Set the dev->base_addr to the gfar reg region */ - dev->base_addr = (unsigned long) regs; + /* Set the extraction length and index */ + attrs = ATTRELI_EL(priv->rx_stash_size) | + ATTRELI_EI(priv->rx_stash_index); - /* Fill in the dev structure */ - dev->watchdog_timeo = TX_TIMEOUT; - dev->mtu = 1500; - dev->netdev_ops = &gfar_netdev_ops; - dev->ethtool_ops = &gfar_ethtool_ops; + gfar_write(®s->attreli, attrs); - /* Register for napi ...We are registering NAPI for each grp */ - if (priv->mode == SQ_SG_MODE) - netif_napi_add(dev, &priv->gfargrp[0].napi, gfar_poll_sq, - GFAR_DEV_WEIGHT); - else - for (i = 0; i < priv->num_grps; i++) - netif_napi_add(dev, &priv->gfargrp[i].napi, gfar_poll, - GFAR_DEV_WEIGHT); + /* Start with defaults, and add stashing + * depending on driver parameters + */ + attrs = ATTR_INIT_SETTINGS; - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { - dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_RXCSUM; - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_RXCSUM | NETIF_F_HIGHDMA; - } + if (priv->bd_stash_en) + attrs |= ATTR_BDSTASH; - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { - dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_CTAG_RX; - dev->features |= NETIF_F_HW_VLAN_CTAG_RX; - } + if (priv->rx_stash_size != 0) + attrs |= ATTR_BUFSTASH; + + gfar_write(®s->attr, attrs); + + /* FIFO configs */ + gfar_write(®s->fifo_tx_thr, DEFAULT_FIFO_TX_THR); + gfar_write(®s->fifo_tx_starve, DEFAULT_FIFO_TX_STARVE); + gfar_write(®s->fifo_tx_starve_shutoff, DEFAULT_FIFO_TX_STARVE_OFF); + + /* Program the interrupt steering regs, only for MG devices */ + if (priv->num_grps > 1) + gfar_write_isrg(priv); +} + +static void __init gfar_init_addr_hash_table(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { priv->extended_hash = 1; @@ -1133,68 +1258,81 @@ static int gfar_probe(struct platform_device *ofdev) priv->hash_regs[6] = ®s->gaddr6; priv->hash_regs[7] = ®s->gaddr7; } +} - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) - priv->padding = DEFAULT_PADDING; - else - priv->padding = 0; +/* Set up the ethernet device structure, private data, + * and anything else we need before we start + */ +static int gfar_probe(struct platform_device *ofdev) +{ + struct net_device *dev = NULL; + struct gfar_private *priv = NULL; + int err = 0, i; - if (dev->features & NETIF_F_IP_CSUM || - priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) - dev->needed_headroom = GMAC_FCB_LEN; + err = gfar_of_init(ofdev, &dev); - /* Program the isrg regs only if number of grps > 1 */ - if (priv->num_grps > 1) { - baddr = ®s->isrg0; - for (i = 0; i < priv->num_grps; i++) { - isrg |= (priv->gfargrp[i].rx_bit_map << ISRG_SHIFT_RX); - isrg |= (priv->gfargrp[i].tx_bit_map << ISRG_SHIFT_TX); - gfar_write(baddr, isrg); - baddr++; - isrg = 0x0; + if (err) + return err; + + priv = netdev_priv(dev); + priv->ndev = dev; + priv->ofdev = ofdev; + priv->dev = &ofdev->dev; + SET_NETDEV_DEV(dev, &ofdev->dev); + + spin_lock_init(&priv->bflock); + INIT_WORK(&priv->reset_task, gfar_reset_task); + + platform_set_drvdata(ofdev, priv); + + gfar_detect_errata(priv); + + /* Set the dev->base_addr to the gfar reg region */ + dev->base_addr = (unsigned long) priv->gfargrp[0].regs; + + /* Fill in the dev structure */ + dev->watchdog_timeo = TX_TIMEOUT; + dev->mtu = 1500; + dev->netdev_ops = &gfar_netdev_ops; + dev->ethtool_ops = &gfar_ethtool_ops; + + /* Register for napi ...We are registering NAPI for each grp */ + for (i = 0; i < priv->num_grps; i++) { + if (priv->poll_mode == GFAR_SQ_POLLING) { + netif_napi_add(dev, &priv->gfargrp[i].napi_rx, + gfar_poll_rx_sq, GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[i].napi_tx, + gfar_poll_tx_sq, 2); + } else { + netif_napi_add(dev, &priv->gfargrp[i].napi_rx, + gfar_poll_rx, GFAR_DEV_WEIGHT); + netif_napi_add(dev, &priv->gfargrp[i].napi_tx, + gfar_poll_tx, 2); } } - /* Need to reverse the bit maps as bit_map's MSB is q0 - * but, for_each_set_bit parses from right to left, which - * basically reverses the queue numbers - */ - for (i = 0; i< priv->num_grps; i++) { - priv->gfargrp[i].tx_bit_map = - reverse_bitmap(priv->gfargrp[i].tx_bit_map, MAX_TX_QS); - priv->gfargrp[i].rx_bit_map = - reverse_bitmap(priv->gfargrp[i].rx_bit_map, MAX_RX_QS); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { + dev->hw_features = NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_RXCSUM | NETIF_F_HIGHDMA; } - /* Calculate RSTAT, TSTAT, RQUEUE and TQUEUE values, - * also assign queues to groups - */ - for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) { - priv->gfargrp[grp_idx].num_rx_queues = 0x0; - - for_each_set_bit(i, &priv->gfargrp[grp_idx].rx_bit_map, - priv->num_rx_queues) { - priv->gfargrp[grp_idx].num_rx_queues++; - priv->rx_queue[i]->grp = &priv->gfargrp[grp_idx]; - rstat = rstat | (RSTAT_CLEAR_RHALT >> i); - rqueue = rqueue | ((RQUEUE_EN0 | RQUEUE_EX0) >> i); - } - priv->gfargrp[grp_idx].num_tx_queues = 0x0; - - for_each_set_bit(i, &priv->gfargrp[grp_idx].tx_bit_map, - priv->num_tx_queues) { - priv->gfargrp[grp_idx].num_tx_queues++; - priv->tx_queue[i]->grp = &priv->gfargrp[grp_idx]; - tstat = tstat | (TSTAT_CLEAR_THALT >> i); - tqueue = tqueue | (TQUEUE_EN0 >> i); - } - priv->gfargrp[grp_idx].rstat = rstat; - priv->gfargrp[grp_idx].tstat = tstat; - rstat = tstat =0; + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { + dev->hw_features |= NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX; + dev->features |= NETIF_F_HW_VLAN_CTAG_RX; } - gfar_write(®s->rqueue, rqueue); - gfar_write(®s->tqueue, tqueue); + gfar_init_addr_hash_table(priv); + + /* Insert receive time stamps into padding alignment bytes */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) + priv->padding = 8; + + if (dev->features & NETIF_F_IP_CSUM || + priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) + dev->needed_headroom = GMAC_FCB_LEN; priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; @@ -1220,8 +1358,9 @@ static int gfar_probe(struct platform_device *ofdev) if (priv->num_tx_queues == 1) priv->prio_sched_en = 1; - /* Carrier starts down, phylib will bring it up */ - netif_carrier_off(dev); + set_bit(GFAR_DOWN, &priv->state); + + gfar_hw_init(priv); err = register_netdev(dev); @@ -1230,6 +1369,9 @@ static int gfar_probe(struct platform_device *ofdev) goto register_fail; } + /* Carrier starts down, phylib will bring it up */ + netif_carrier_off(dev); + device_init_wakeup(&dev->dev, priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); @@ -1251,9 +1393,6 @@ static int gfar_probe(struct platform_device *ofdev) /* Initialize the filer table */ gfar_init_filer_table(priv); - /* Create all the sysfs files */ - gfar_init_sysfs(dev); - /* Print out the device info */ netdev_info(dev, "mac: %pM\n", dev->dev_addr); @@ -1272,8 +1411,8 @@ static int gfar_probe(struct platform_device *ofdev) register_fail: unmap_group_regs(priv); - free_tx_pointers(priv); - free_rx_pointers(priv); + gfar_free_rx_queues(priv); + gfar_free_tx_queues(priv); if (priv->phy_node) of_node_put(priv->phy_node); if (priv->tbi_node) @@ -1293,6 +1432,8 @@ static int gfar_remove(struct platform_device *ofdev) unregister_netdev(priv->ndev); unmap_group_regs(priv); + gfar_free_rx_queues(priv); + gfar_free_tx_queues(priv); free_gfar_dev(priv); return 0; @@ -1318,9 +1459,8 @@ static int gfar_suspend(struct device *dev) local_irq_save(flags); lock_tx_qs(priv); - lock_rx_qs(priv); - gfar_halt_nodisable(ndev); + gfar_halt_nodisable(priv); /* Disable Tx, and Rx if wake-on-LAN is disabled. */ tempval = gfar_read(®s->maccfg1); @@ -1332,7 +1472,6 @@ static int gfar_suspend(struct device *dev) gfar_write(®s->maccfg1, tempval); - unlock_rx_qs(priv); unlock_tx_qs(priv); local_irq_restore(flags); @@ -1378,15 +1517,13 @@ static int gfar_resume(struct device *dev) */ local_irq_save(flags); lock_tx_qs(priv); - lock_rx_qs(priv); tempval = gfar_read(®s->maccfg2); tempval &= ~MACCFG2_MPEN; gfar_write(®s->maccfg2, tempval); - gfar_start(ndev); + gfar_start(priv); - unlock_rx_qs(priv); unlock_tx_qs(priv); local_irq_restore(flags); @@ -1413,10 +1550,11 @@ static int gfar_restore(struct device *dev) return -ENOMEM; } - init_registers(ndev); - gfar_set_mac_address(ndev); - gfar_init_mac(ndev); - gfar_start(ndev); + gfar_mac_reset(priv); + + gfar_init_tx_rx_base(priv); + + gfar_start(priv); priv->oldlink = 0; priv->oldspeed = 0; @@ -1574,57 +1712,6 @@ static void gfar_configure_serdes(struct net_device *dev) BMCR_SPEED1000); } -static void init_registers(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; - int i; - - for (i = 0; i < priv->num_grps; i++) { - regs = priv->gfargrp[i].regs; - /* Clear IEVENT */ - gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - - /* Initialize IMASK */ - gfar_write(®s->imask, IMASK_INIT_CLEAR); - } - - regs = priv->gfargrp[0].regs; - /* Init hash registers to zero */ - gfar_write(®s->igaddr0, 0); - gfar_write(®s->igaddr1, 0); - gfar_write(®s->igaddr2, 0); - gfar_write(®s->igaddr3, 0); - gfar_write(®s->igaddr4, 0); - gfar_write(®s->igaddr5, 0); - gfar_write(®s->igaddr6, 0); - gfar_write(®s->igaddr7, 0); - - gfar_write(®s->gaddr0, 0); - gfar_write(®s->gaddr1, 0); - gfar_write(®s->gaddr2, 0); - gfar_write(®s->gaddr3, 0); - gfar_write(®s->gaddr4, 0); - gfar_write(®s->gaddr5, 0); - gfar_write(®s->gaddr6, 0); - gfar_write(®s->gaddr7, 0); - - /* Zero out the rmon mib registers if it has them */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { - memset_io(&(regs->rmon), 0, sizeof (struct rmon_mib)); - - /* Mask off the CAM interrupts */ - gfar_write(®s->rmon.cam1, 0xffffffff); - gfar_write(®s->rmon.cam2, 0xffffffff); - } - - /* Initialize the max receive buffer length */ - gfar_write(®s->mrblr, priv->rx_buffer_size); - - /* Initialize the Minimum Frame Length Register */ - gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); -} - static int __gfar_is_rx_idle(struct gfar_private *priv) { u32 res; @@ -1648,23 +1735,13 @@ static int __gfar_is_rx_idle(struct gfar_private *priv) } /* Halt the receive and transmit queues */ -static void gfar_halt_nodisable(struct net_device *dev) +static void gfar_halt_nodisable(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; + struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - int i; - - for (i = 0; i < priv->num_grps; i++) { - regs = priv->gfargrp[i].regs; - /* Mask all interrupts */ - gfar_write(®s->imask, IMASK_INIT_CLEAR); - /* Clear all interrupts */ - gfar_write(®s->ievent, IEVENT_INIT_CLEAR); - } + gfar_ints_disable(priv); - regs = priv->gfargrp[0].regs; /* Stop the DMA, and wait for it to stop */ tempval = gfar_read(®s->dmactrl); if ((tempval & (DMACTRL_GRS | DMACTRL_GTS)) != @@ -1685,56 +1762,41 @@ static void gfar_halt_nodisable(struct net_device *dev) } /* Halt the receive and transmit queues */ -void gfar_halt(struct net_device *dev) +void gfar_halt(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; - gfar_halt_nodisable(dev); + /* Dissable the Rx/Tx hw queues */ + gfar_write(®s->rqueue, 0); + gfar_write(®s->tqueue, 0); + + mdelay(10); - /* Disable Rx and Tx */ + gfar_halt_nodisable(priv); + + /* Disable Rx/Tx DMA */ tempval = gfar_read(®s->maccfg1); tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN); gfar_write(®s->maccfg1, tempval); } -static void free_grp_irqs(struct gfar_priv_grp *grp) -{ - free_irq(gfar_irq(grp, TX)->irq, grp); - free_irq(gfar_irq(grp, RX)->irq, grp); - free_irq(gfar_irq(grp, ER)->irq, grp); -} - void stop_gfar(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - unsigned long flags; - int i; - - phy_stop(priv->phydev); + netif_tx_stop_all_queues(dev); - /* Lock it down */ - local_irq_save(flags); - lock_tx_qs(priv); - lock_rx_qs(priv); + smp_mb__before_clear_bit(); + set_bit(GFAR_DOWN, &priv->state); + smp_mb__after_clear_bit(); - gfar_halt(dev); + disable_napi(priv); - unlock_rx_qs(priv); - unlock_tx_qs(priv); - local_irq_restore(flags); + /* disable ints and gracefully shut down Rx/Tx DMA */ + gfar_halt(priv); - /* Free the IRQs */ - if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - for (i = 0; i < priv->num_grps; i++) - free_grp_irqs(&priv->gfargrp[i]); - } else { - for (i = 0; i < priv->num_grps; i++) - free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq, - &priv->gfargrp[i]); - } + phy_stop(priv->phydev); free_skb_resources(priv); } @@ -1825,17 +1887,15 @@ static void free_skb_resources(struct gfar_private *priv) priv->tx_queue[0]->tx_bd_dma_base); } -void gfar_start(struct net_device *dev) +void gfar_start(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = priv->gfargrp[0].regs; u32 tempval; int i = 0; - /* Enable Rx and Tx in MACCFG1 */ - tempval = gfar_read(®s->maccfg1); - tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN); - gfar_write(®s->maccfg1, tempval); + /* Enable Rx/Tx hw queues */ + gfar_write(®s->rqueue, priv->rqueue); + gfar_write(®s->tqueue, priv->tqueue); /* Initialize DMACTRL to have WWR and WOP */ tempval = gfar_read(®s->dmactrl); @@ -1852,52 +1912,23 @@ void gfar_start(struct net_device *dev) /* Clear THLT/RHLT, so that the DMA starts polling now */ gfar_write(®s->tstat, priv->gfargrp[i].tstat); gfar_write(®s->rstat, priv->gfargrp[i].rstat); - /* Unmask the interrupts we look for */ - gfar_write(®s->imask, IMASK_DEFAULT); } - dev->trans_start = jiffies; /* prevent tx timeout */ -} - -static void gfar_configure_coalescing(struct gfar_private *priv, - unsigned long tx_mask, unsigned long rx_mask) -{ - struct gfar __iomem *regs = priv->gfargrp[0].regs; - u32 __iomem *baddr; - - if (priv->mode == MQ_MG_MODE) { - int i = 0; - - baddr = ®s->txic0; - for_each_set_bit(i, &tx_mask, priv->num_tx_queues) { - gfar_write(baddr + i, 0); - if (likely(priv->tx_queue[i]->txcoalescing)) - gfar_write(baddr + i, priv->tx_queue[i]->txic); - } + /* Enable Rx/Tx DMA */ + tempval = gfar_read(®s->maccfg1); + tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN); + gfar_write(®s->maccfg1, tempval); - baddr = ®s->rxic0; - for_each_set_bit(i, &rx_mask, priv->num_rx_queues) { - gfar_write(baddr + i, 0); - if (likely(priv->rx_queue[i]->rxcoalescing)) - gfar_write(baddr + i, priv->rx_queue[i]->rxic); - } - } else { - /* Backward compatible case -- even if we enable - * multiple queues, there's only single reg to program - */ - gfar_write(®s->txic, 0); - if (likely(priv->tx_queue[0]->txcoalescing)) - gfar_write(®s->txic, priv->tx_queue[0]->txic); + gfar_ints_enable(priv); - gfar_write(®s->rxic, 0); - if (unlikely(priv->rx_queue[0]->rxcoalescing)) - gfar_write(®s->rxic, priv->rx_queue[0]->rxic); - } + priv->ndev->trans_start = jiffies; /* prevent tx timeout */ } -void gfar_configure_coalescing_all(struct gfar_private *priv) +static void free_grp_irqs(struct gfar_priv_grp *grp) { - gfar_configure_coalescing(priv, 0xFF, 0xFF); + free_irq(gfar_irq(grp, TX)->irq, grp); + free_irq(gfar_irq(grp, RX)->irq, grp); + free_irq(gfar_irq(grp, ER)->irq, grp); } static int register_grp_irqs(struct gfar_priv_grp *grp) @@ -1956,46 +1987,65 @@ err_irq_fail: } -/* Bring the controller up and running */ -int startup_gfar(struct net_device *ndev) +static void gfar_free_irq(struct gfar_private *priv) { - struct gfar_private *priv = netdev_priv(ndev); - struct gfar __iomem *regs = NULL; - int err, i, j; + int i; - for (i = 0; i < priv->num_grps; i++) { - regs= priv->gfargrp[i].regs; - gfar_write(®s->imask, IMASK_INIT_CLEAR); + /* Free the IRQs */ + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + for (i = 0; i < priv->num_grps; i++) + free_grp_irqs(&priv->gfargrp[i]); + } else { + for (i = 0; i < priv->num_grps; i++) + free_irq(gfar_irq(&priv->gfargrp[i], TX)->irq, + &priv->gfargrp[i]); } +} - regs= priv->gfargrp[0].regs; - err = gfar_alloc_skb_resources(ndev); - if (err) - return err; - - gfar_init_mac(ndev); +static int gfar_request_irq(struct gfar_private *priv) +{ + int err, i, j; for (i = 0; i < priv->num_grps; i++) { err = register_grp_irqs(&priv->gfargrp[i]); if (err) { for (j = 0; j < i; j++) free_grp_irqs(&priv->gfargrp[j]); - goto irq_fail; + return err; } } - /* Start the controller */ - gfar_start(ndev); + return 0; +} + +/* Bring the controller up and running */ +int startup_gfar(struct net_device *ndev) +{ + struct gfar_private *priv = netdev_priv(ndev); + int err; + + gfar_mac_reset(priv); + + err = gfar_alloc_skb_resources(ndev); + if (err) + return err; + + gfar_init_tx_rx_base(priv); + + smp_mb__before_clear_bit(); + clear_bit(GFAR_DOWN, &priv->state); + smp_mb__after_clear_bit(); + + /* Start Rx/Tx DMA and enable the interrupts */ + gfar_start(priv); phy_start(priv->phydev); - gfar_configure_coalescing_all(priv); + enable_napi(priv); - return 0; + netif_tx_wake_all_queues(ndev); -irq_fail: - free_skb_resources(priv); - return err; + return 0; } /* Called when something needs to use the ethernet device @@ -2006,27 +2056,17 @@ static int gfar_enet_open(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); int err; - enable_napi(priv); - - /* Initialize a bunch of registers */ - init_registers(dev); - - gfar_set_mac_address(dev); - err = init_phy(dev); + if (err) + return err; - if (err) { - disable_napi(priv); + err = gfar_request_irq(priv); + if (err) return err; - } err = startup_gfar(dev); - if (err) { - disable_napi(priv); + if (err) return err; - } - - netif_tx_start_all_queues(dev); device_set_wakeup_enable(&dev->dev, priv->wol_en); @@ -2152,13 +2192,13 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) skb_new = skb_realloc_headroom(skb, fcb_len); if (!skb_new) { dev->stats.tx_errors++; - kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } if (skb->sk) skb_set_owner_w(skb_new, skb->sk); - consume_skb(skb); + dev_consume_skb_any(skb); skb = skb_new; } @@ -2351,8 +2391,6 @@ static int gfar_close(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - disable_napi(priv); - cancel_work_sync(&priv->reset_task); stop_gfar(dev); @@ -2360,7 +2398,7 @@ static int gfar_close(struct net_device *dev) phy_disconnect(priv->phydev); priv->phydev = NULL; - netif_tx_stop_all_queues(dev); + gfar_free_irq(priv); return 0; } @@ -2373,77 +2411,9 @@ static int gfar_set_mac_address(struct net_device *dev) return 0; } -/* Check if rx parser should be activated */ -void gfar_check_rx_parser_mode(struct gfar_private *priv) -{ - struct gfar __iomem *regs; - u32 tempval; - - regs = priv->gfargrp[0].regs; - - tempval = gfar_read(®s->rctrl); - /* If parse is no longer required, then disable parser */ - if (tempval & RCTRL_REQ_PARSER) { - tempval |= RCTRL_PRSDEP_INIT; - priv->uses_rxfcb = 1; - } else { - tempval &= ~RCTRL_PRSDEP_INIT; - priv->uses_rxfcb = 0; - } - gfar_write(®s->rctrl, tempval); -} - -/* Enables and disables VLAN insertion/extraction */ -void gfar_vlan_mode(struct net_device *dev, netdev_features_t features) -{ - struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = NULL; - unsigned long flags; - u32 tempval; - - regs = priv->gfargrp[0].regs; - local_irq_save(flags); - lock_rx_qs(priv); - - if (features & NETIF_F_HW_VLAN_CTAG_TX) { - /* Enable VLAN tag insertion */ - tempval = gfar_read(®s->tctrl); - tempval |= TCTRL_VLINS; - gfar_write(®s->tctrl, tempval); - } else { - /* Disable VLAN tag insertion */ - tempval = gfar_read(®s->tctrl); - tempval &= ~TCTRL_VLINS; - gfar_write(®s->tctrl, tempval); - } - - if (features & NETIF_F_HW_VLAN_CTAG_RX) { - /* Enable VLAN tag extraction */ - tempval = gfar_read(®s->rctrl); - tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); - gfar_write(®s->rctrl, tempval); - priv->uses_rxfcb = 1; - } else { - /* Disable VLAN tag extraction */ - tempval = gfar_read(®s->rctrl); - tempval &= ~RCTRL_VLEX; - gfar_write(®s->rctrl, tempval); - - gfar_check_rx_parser_mode(priv); - } - - gfar_change_mtu(dev, dev->mtu); - - unlock_rx_qs(priv); - local_irq_restore(flags); -} - static int gfar_change_mtu(struct net_device *dev, int new_mtu) { - int tempsize, tempval; struct gfar_private *priv = netdev_priv(dev); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - int oldsize = priv->rx_buffer_size; int frame_size = new_mtu + ETH_HLEN; if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { @@ -2451,45 +2421,33 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } - if (priv->uses_rxfcb) - frame_size += GMAC_FCB_LEN; + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - frame_size += priv->padding; - - tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + - INCREMENTAL_BUFFER_SIZE; - - /* Only stop and start the controller if it isn't already - * stopped, and we changed something - */ - if ((oldsize != tempsize) && (dev->flags & IFF_UP)) + if (dev->flags & IFF_UP) stop_gfar(dev); - priv->rx_buffer_size = tempsize; - dev->mtu = new_mtu; - gfar_write(®s->mrblr, priv->rx_buffer_size); - gfar_write(®s->maxfrm, priv->rx_buffer_size); + if (dev->flags & IFF_UP) + startup_gfar(dev); - /* If the mtu is larger than the max size for standard - * ethernet frames (ie, a jumbo frame), then set maccfg2 - * to allow huge frames, and to check the length - */ - tempval = gfar_read(®s->maccfg2); + clear_bit_unlock(GFAR_RESETTING, &priv->state); - if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || - gfar_has_errata(priv, GFAR_ERRATA_74)) - tempval |= (MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); - else - tempval &= ~(MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK); + return 0; +} - gfar_write(®s->maccfg2, tempval); +void reset_gfar(struct net_device *ndev) +{ + struct gfar_private *priv = netdev_priv(ndev); - if ((oldsize != tempsize) && (dev->flags & IFF_UP)) - startup_gfar(dev); + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - return 0; + stop_gfar(ndev); + startup_gfar(ndev); + + clear_bit_unlock(GFAR_RESETTING, &priv->state); } /* gfar_reset_task gets scheduled when a packet has not been @@ -2501,16 +2459,7 @@ static void gfar_reset_task(struct work_struct *work) { struct gfar_private *priv = container_of(work, struct gfar_private, reset_task); - struct net_device *dev = priv->ndev; - - if (dev->flags & IFF_UP) { - netif_tx_stop_all_queues(dev); - stop_gfar(dev); - startup_gfar(dev); - netif_tx_start_all_queues(dev); - } - - netif_tx_schedule_all(dev); + reset_gfar(priv->ndev); } static void gfar_timeout(struct net_device *dev) @@ -2623,8 +2572,10 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) } /* If we freed a buffer, we can restart transmission, if necessary */ - if (netif_tx_queue_stopped(txq) && tx_queue->num_txbdfree) - netif_wake_subqueue(dev, tqi); + if (tx_queue->num_txbdfree && + netif_tx_queue_stopped(txq) && + !(test_bit(GFAR_DOWN, &priv->state))) + netif_wake_subqueue(priv->ndev, tqi); /* Update dirty indicators */ tx_queue->skb_dirtytx = skb_dirtytx; @@ -2633,31 +2584,6 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static void gfar_schedule_cleanup(struct gfar_priv_grp *gfargrp) -{ - unsigned long flags; - - spin_lock_irqsave(&gfargrp->grplock, flags); - if (napi_schedule_prep(&gfargrp->napi)) { - gfar_write(&gfargrp->regs->imask, IMASK_RTX_DISABLED); - __napi_schedule(&gfargrp->napi); - } else { - /* Clear IEVENT, so interrupts aren't called again - * because of the packets that have already arrived. - */ - gfar_write(&gfargrp->regs->ievent, IEVENT_RTX_MASK); - } - spin_unlock_irqrestore(&gfargrp->grplock, flags); - -} - -/* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *grp_id) -{ - gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); - return IRQ_HANDLED; -} - static void gfar_new_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, struct sk_buff *skb) { @@ -2728,7 +2654,48 @@ static inline void count_errors(unsigned short status, struct net_device *dev) irqreturn_t gfar_receive(int irq, void *grp_id) { - gfar_schedule_cleanup((struct gfar_priv_grp *)grp_id); + struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; + unsigned long flags; + u32 imask; + + if (likely(napi_schedule_prep(&grp->napi_rx))) { + spin_lock_irqsave(&grp->grplock, flags); + imask = gfar_read(&grp->regs->imask); + imask &= IMASK_RX_DISABLED; + gfar_write(&grp->regs->imask, imask); + spin_unlock_irqrestore(&grp->grplock, flags); + __napi_schedule(&grp->napi_rx); + } else { + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived. + */ + gfar_write(&grp->regs->ievent, IEVENT_RX_MASK); + } + + return IRQ_HANDLED; +} + +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *grp_id) +{ + struct gfar_priv_grp *grp = (struct gfar_priv_grp *)grp_id; + unsigned long flags; + u32 imask; + + if (likely(napi_schedule_prep(&grp->napi_tx))) { + spin_lock_irqsave(&grp->grplock, flags); + imask = gfar_read(&grp->regs->imask); + imask &= IMASK_TX_DISABLED; + gfar_write(&grp->regs->imask, imask); + spin_unlock_irqrestore(&grp->grplock, flags); + __napi_schedule(&grp->napi_tx); + } else { + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived. + */ + gfar_write(&grp->regs->ievent, IEVENT_TX_MASK); + } + return IRQ_HANDLED; } @@ -2852,7 +2819,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); gfar_process_frame(dev, skb, amount_pull, - &rx_queue->grp->napi); + &rx_queue->grp->napi_rx); } else { netif_warn(priv, rx_err, dev, "Missing skb!\n"); @@ -2881,66 +2848,81 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) return howmany; } -static int gfar_poll_sq(struct napi_struct *napi, int budget) +static int gfar_poll_rx_sq(struct napi_struct *napi, int budget) { struct gfar_priv_grp *gfargrp = - container_of(napi, struct gfar_priv_grp, napi); + container_of(napi, struct gfar_priv_grp, napi_rx); struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_tx_q *tx_queue = gfargrp->priv->tx_queue[0]; - struct gfar_priv_rx_q *rx_queue = gfargrp->priv->rx_queue[0]; + struct gfar_priv_rx_q *rx_queue = gfargrp->rx_queue; int work_done = 0; /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ - gfar_write(®s->ievent, IEVENT_RTX_MASK); - - /* run Tx cleanup to completion */ - if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) - gfar_clean_tx_ring(tx_queue); + gfar_write(®s->ievent, IEVENT_RX_MASK); work_done = gfar_clean_rx_ring(rx_queue, budget); if (work_done < budget) { + u32 imask; napi_complete(napi); /* Clear the halt bit in RSTAT */ gfar_write(®s->rstat, gfargrp->rstat); - gfar_write(®s->imask, IMASK_DEFAULT); - - /* If we are coalescing interrupts, update the timer - * Otherwise, clear it - */ - gfar_write(®s->txic, 0); - if (likely(tx_queue->txcoalescing)) - gfar_write(®s->txic, tx_queue->txic); - - gfar_write(®s->rxic, 0); - if (unlikely(rx_queue->rxcoalescing)) - gfar_write(®s->rxic, rx_queue->rxic); + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_RX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); } return work_done; } -static int gfar_poll(struct napi_struct *napi, int budget) +static int gfar_poll_tx_sq(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_tx); + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_tx_q *tx_queue = gfargrp->tx_queue; + u32 imask; + + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_TX_MASK); + + /* run Tx cleanup to completion */ + if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) + gfar_clean_tx_ring(tx_queue); + + napi_complete(napi); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_TX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + + return 0; +} + +static int gfar_poll_rx(struct napi_struct *napi, int budget) { struct gfar_priv_grp *gfargrp = - container_of(napi, struct gfar_priv_grp, napi); + container_of(napi, struct gfar_priv_grp, napi_rx); struct gfar_private *priv = gfargrp->priv; struct gfar __iomem *regs = gfargrp->regs; - struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; int work_done = 0, work_done_per_q = 0; int i, budget_per_q = 0; - int has_tx_work = 0; unsigned long rstat_rxf; int num_act_queues; /* Clear IEVENT, so interrupts aren't called again * because of the packets that have already arrived */ - gfar_write(®s->ievent, IEVENT_RTX_MASK); + gfar_write(®s->ievent, IEVENT_RX_MASK); rstat_rxf = gfar_read(®s->rstat) & RSTAT_RXF_MASK; @@ -2948,15 +2930,6 @@ static int gfar_poll(struct napi_struct *napi, int budget) if (num_act_queues) budget_per_q = budget/num_act_queues; - for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) { - tx_queue = priv->tx_queue[i]; - /* run Tx cleanup to completion */ - if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) { - gfar_clean_tx_ring(tx_queue); - has_tx_work = 1; - } - } - for_each_set_bit(i, &gfargrp->rx_bit_map, priv->num_rx_queues) { /* skip queue if not active */ if (!(rstat_rxf & (RSTAT_CLEAR_RXF0 >> i))) @@ -2979,25 +2952,62 @@ static int gfar_poll(struct napi_struct *napi, int budget) } } - if (!num_act_queues && !has_tx_work) { - + if (!num_act_queues) { + u32 imask; napi_complete(napi); /* Clear the halt bit in RSTAT */ gfar_write(®s->rstat, gfargrp->rstat); - gfar_write(®s->imask, IMASK_DEFAULT); - - /* If we are coalescing interrupts, update the timer - * Otherwise, clear it - */ - gfar_configure_coalescing(priv, gfargrp->rx_bit_map, - gfargrp->tx_bit_map); + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_RX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); } return work_done; } +static int gfar_poll_tx(struct napi_struct *napi, int budget) +{ + struct gfar_priv_grp *gfargrp = + container_of(napi, struct gfar_priv_grp, napi_tx); + struct gfar_private *priv = gfargrp->priv; + struct gfar __iomem *regs = gfargrp->regs; + struct gfar_priv_tx_q *tx_queue = NULL; + int has_tx_work = 0; + int i; + + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived + */ + gfar_write(®s->ievent, IEVENT_TX_MASK); + + for_each_set_bit(i, &gfargrp->tx_bit_map, priv->num_tx_queues) { + tx_queue = priv->tx_queue[i]; + /* run Tx cleanup to completion */ + if (tx_queue->tx_skbuff[tx_queue->skb_dirtytx]) { + gfar_clean_tx_ring(tx_queue); + has_tx_work = 1; + } + } + + if (!has_tx_work) { + u32 imask; + napi_complete(napi); + + spin_lock_irq(&gfargrp->grplock); + imask = gfar_read(®s->imask); + imask |= IMASK_TX_DEFAULT; + gfar_write(®s->imask, imask); + spin_unlock_irq(&gfargrp->grplock); + } + + return 0; +} + + #ifdef CONFIG_NET_POLL_CONTROLLER /* Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while @@ -3101,12 +3111,11 @@ static void adjust_link(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned long flags; struct phy_device *phydev = priv->phydev; int new_state = 0; - local_irq_save(flags); - lock_tx_qs(priv); + if (test_bit(GFAR_RESETTING, &priv->state)) + return; if (phydev->link) { u32 tempval1 = gfar_read(®s->maccfg1); @@ -3178,8 +3187,6 @@ static void adjust_link(struct net_device *dev) if (new_state && netif_msg_link(priv)) phy_print_status(phydev); - unlock_tx_qs(priv); - local_irq_restore(flags); } /* Update the hash table based on the current list of multicast diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 52bb2b0195cc..84632c569f2c 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -9,7 +9,7 @@ * Maintainer: Kumar Gala * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> * - * Copyright 2002-2009, 2011 Freescale Semiconductor, Inc. + * Copyright 2002-2009, 2011-2013 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -377,8 +377,11 @@ extern const char gfar_driver_version[]; IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \ | IMASK_PERR) -#define IMASK_RTX_DISABLED ((~(IMASK_RXFEN0 | IMASK_TXFEN | IMASK_BSY)) \ - & IMASK_DEFAULT) +#define IMASK_RX_DEFAULT (IMASK_RXFEN0 | IMASK_BSY) +#define IMASK_TX_DEFAULT (IMASK_TXFEN | IMASK_TXBEN) + +#define IMASK_RX_DISABLED ((~(IMASK_RX_DEFAULT)) & IMASK_DEFAULT) +#define IMASK_TX_DISABLED ((~(IMASK_TX_DEFAULT)) & IMASK_DEFAULT) /* Fifo management */ #define FIFO_TX_THR_MASK 0x01ff @@ -409,7 +412,9 @@ extern const char gfar_driver_version[]; /* This default RIR value directly corresponds * to the 3-bit hash value generated */ -#define DEFAULT_RIR0 0x05397700 +#define DEFAULT_8RXQ_RIR0 0x05397700 +/* Map even hash values to Q0, and odd ones to Q1 */ +#define DEFAULT_2RXQ_RIR0 0x04104100 /* RQFCR register bits */ #define RQFCR_GPI 0x80000000 @@ -880,7 +885,6 @@ struct gfar { #define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010 #define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020 #define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040 -#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080 #define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100 #define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 #define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 @@ -892,8 +896,8 @@ struct gfar { #define DEFAULT_MAPPING 0xFF #endif -#define ISRG_SHIFT_TX 0x10 -#define ISRG_SHIFT_RX 0x18 +#define ISRG_RR0 0x80000000 +#define ISRG_TR0 0x00800000 /* The same driver can operate in two modes */ /* SQ_SG_MODE: Single Queue Single Group Mode @@ -905,6 +909,22 @@ enum { MQ_MG_MODE }; +/* GFAR_SQ_POLLING: Single Queue NAPI polling mode + * The driver supports a single pair of RX/Tx queues + * per interrupt group (Rx/Tx int line). MQ_MG mode + * devices have 2 interrupt groups, so the device will + * have a total of 2 Tx and 2 Rx queues in this case. + * GFAR_MQ_POLLING: Multi Queue NAPI polling mode + * The driver supports all the 8 Rx and Tx HW queues + * each queue mapped by the Device Tree to one of + * the 2 interrupt groups. This mode implies significant + * processing overhead (CPU and controller level). + */ +enum gfar_poll_mode { + GFAR_SQ_POLLING = 0, + GFAR_MQ_POLLING +}; + /* * Per TX queue stats */ @@ -966,7 +986,6 @@ struct rx_q_stats { /** * struct gfar_priv_rx_q - per rx queue structure - * @rxlock: per queue rx spin lock * @rx_skbuff: skb pointers * @skb_currx: currently use skb pointer * @rx_bd_base: First rx buffer descriptor @@ -979,8 +998,7 @@ struct rx_q_stats { */ struct gfar_priv_rx_q { - spinlock_t rxlock __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct sk_buff ** rx_skbuff; + struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); dma_addr_t rx_bd_dma_base; struct rxbd8 *rx_bd_base; struct rxbd8 *cur_rx; @@ -1016,17 +1034,20 @@ struct gfar_irqinfo { */ struct gfar_priv_grp { - spinlock_t grplock __attribute__ ((aligned (SMP_CACHE_BYTES))); - struct napi_struct napi; - struct gfar_private *priv; + spinlock_t grplock __aligned(SMP_CACHE_BYTES); + struct napi_struct napi_rx; + struct napi_struct napi_tx; struct gfar __iomem *regs; - unsigned int rstat; - unsigned long num_rx_queues; - unsigned long rx_bit_map; - /* cacheline 3 */ + struct gfar_priv_tx_q *tx_queue; + struct gfar_priv_rx_q *rx_queue; unsigned int tstat; + unsigned int rstat; + + struct gfar_private *priv; unsigned long num_tx_queues; unsigned long tx_bit_map; + unsigned long num_rx_queues; + unsigned long rx_bit_map; struct gfar_irqinfo *irqinfo[GFAR_NUM_IRQS]; }; @@ -1041,6 +1062,11 @@ enum gfar_errata { GFAR_ERRATA_12 = 0x08, /* a.k.a errata eTSEC49 */ }; +enum gfar_dev_state { + GFAR_DOWN = 1, + GFAR_RESETTING +}; + /* Struct stolen almost completely (and shamelessly) from the FCC enet source * (Ok, that's not so true anymore, but there is a family resemblance) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base @@ -1051,8 +1077,6 @@ enum gfar_errata { * the buffer descriptor determines the actual condition. */ struct gfar_private { - unsigned int num_rx_queues; - struct device *dev; struct net_device *ndev; enum gfar_errata errata; @@ -1060,6 +1084,7 @@ struct gfar_private { u16 uses_rxfcb; u16 padding; + u32 device_flags; /* HW time stamping enabled flag */ int hwts_rx_en; @@ -1069,10 +1094,12 @@ struct gfar_private { struct gfar_priv_rx_q *rx_queue[MAX_RX_QS]; struct gfar_priv_grp gfargrp[MAXGROUPS]; - u32 device_flags; + unsigned long state; - unsigned int mode; + unsigned short mode; + unsigned short poll_mode; unsigned int num_tx_queues; + unsigned int num_rx_queues; unsigned int num_grps; /* Network Statistics */ @@ -1113,6 +1140,9 @@ struct gfar_private { unsigned int total_tx_ring_size; unsigned int total_rx_ring_size; + u32 rqueue; + u32 tqueue; + /* RX per device parameters */ unsigned int rx_stash_size; unsigned int rx_stash_index; @@ -1127,11 +1157,6 @@ struct gfar_private { u32 __iomem *hash_regs[16]; int hash_width; - /* global parameters */ - unsigned int fifo_threshold; - unsigned int fifo_starve; - unsigned int fifo_starve_off; - /*Filer table*/ unsigned int ftp_rqfpr[MAX_FILER_IDX + 1]; unsigned int ftp_rqfcr[MAX_FILER_IDX + 1]; @@ -1176,21 +1201,42 @@ static inline void gfar_read_filer(struct gfar_private *priv, *fpr = gfar_read(®s->rqfpr); } -void lock_rx_qs(struct gfar_private *priv); -void lock_tx_qs(struct gfar_private *priv); -void unlock_rx_qs(struct gfar_private *priv); -void unlock_tx_qs(struct gfar_private *priv); +static inline void gfar_write_isrg(struct gfar_private *priv) +{ + struct gfar __iomem *regs = priv->gfargrp[0].regs; + u32 __iomem *baddr = ®s->isrg0; + u32 isrg = 0; + int grp_idx, i; + + for (grp_idx = 0; grp_idx < priv->num_grps; grp_idx++) { + struct gfar_priv_grp *grp = &priv->gfargrp[grp_idx]; + + for_each_set_bit(i, &grp->rx_bit_map, priv->num_rx_queues) { + isrg |= (ISRG_RR0 >> i); + } + + for_each_set_bit(i, &grp->tx_bit_map, priv->num_tx_queues) { + isrg |= (ISRG_TR0 >> i); + } + + gfar_write(baddr, isrg); + + baddr++; + isrg = 0; + } +} + irqreturn_t gfar_receive(int irq, void *dev_id); int startup_gfar(struct net_device *dev); void stop_gfar(struct net_device *dev); -void gfar_halt(struct net_device *dev); +void reset_gfar(struct net_device *dev); +void gfar_mac_reset(struct gfar_private *priv); +void gfar_halt(struct gfar_private *priv); +void gfar_start(struct gfar_private *priv); void gfar_phy_test(struct mii_bus *bus, struct phy_device *phydev, int enable, u32 regnum, u32 read); void gfar_configure_coalescing_all(struct gfar_private *priv); -void gfar_init_sysfs(struct net_device *dev); int gfar_set_features(struct net_device *dev, netdev_features_t features); -void gfar_check_rx_parser_mode(struct gfar_private *priv); -void gfar_vlan_mode(struct net_device *dev, netdev_features_t features); extern const struct ethtool_ops gfar_ethtool_ops; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 63d234419cc1..891dbee6e6c1 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -44,10 +44,6 @@ #include "gianfar.h" -extern void gfar_start(struct net_device *dev); -extern int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, - int rx_work_limit); - #define GFAR_MAX_COAL_USECS 0xffff #define GFAR_MAX_COAL_FRAMES 0xff static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, @@ -364,25 +360,11 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { struct gfar_private *priv = netdev_priv(dev); - int i = 0; + int i, err = 0; if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; - /* Set up rx coalescing */ - /* As of now, we will enable/disable coalescing for all - * queues together in case of eTSEC2, this will be modified - * along with the ethtool interface - */ - if ((cvals->rx_coalesce_usecs == 0) || - (cvals->rx_max_coalesced_frames == 0)) { - for (i = 0; i < priv->num_rx_queues; i++) - priv->rx_queue[i]->rxcoalescing = 0; - } else { - for (i = 0; i < priv->num_rx_queues; i++) - priv->rx_queue[i]->rxcoalescing = 1; - } - if (NULL == priv->phydev) return -ENODEV; @@ -399,6 +381,32 @@ static int gfar_scoalesce(struct net_device *dev, return -EINVAL; } + /* Check the bounds of the values */ + if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { + netdev_info(dev, "Coalescing is limited to %d microseconds\n", + GFAR_MAX_COAL_USECS); + return -EINVAL; + } + + if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { + netdev_info(dev, "Coalescing is limited to %d frames\n", + GFAR_MAX_COAL_FRAMES); + return -EINVAL; + } + + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); + + /* Set up rx coalescing */ + if ((cvals->rx_coalesce_usecs == 0) || + (cvals->rx_max_coalesced_frames == 0)) { + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i]->rxcoalescing = 0; + } else { + for (i = 0; i < priv->num_rx_queues; i++) + priv->rx_queue[i]->rxcoalescing = 1; + } + for (i = 0; i < priv->num_rx_queues; i++) { priv->rx_queue[i]->rxic = mk_ic_value( cvals->rx_max_coalesced_frames, @@ -415,28 +423,22 @@ static int gfar_scoalesce(struct net_device *dev, priv->tx_queue[i]->txcoalescing = 1; } - /* Check the bounds of the values */ - if (cvals->tx_coalesce_usecs > GFAR_MAX_COAL_USECS) { - netdev_info(dev, "Coalescing is limited to %d microseconds\n", - GFAR_MAX_COAL_USECS); - return -EINVAL; - } - - if (cvals->tx_max_coalesced_frames > GFAR_MAX_COAL_FRAMES) { - netdev_info(dev, "Coalescing is limited to %d frames\n", - GFAR_MAX_COAL_FRAMES); - return -EINVAL; - } - for (i = 0; i < priv->num_tx_queues; i++) { priv->tx_queue[i]->txic = mk_ic_value( cvals->tx_max_coalesced_frames, gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs)); } - gfar_configure_coalescing_all(priv); + if (dev->flags & IFF_UP) { + stop_gfar(dev); + err = startup_gfar(dev); + } else { + gfar_mac_reset(priv); + } + + clear_bit_unlock(GFAR_RESETTING, &priv->state); - return 0; + return err; } /* Fills in rvals with the current ring parameters. Currently, @@ -467,15 +469,13 @@ static void gfar_gringparam(struct net_device *dev, } /* Change the current ring parameters, stopping the controller if - * necessary so that we don't mess things up while we're in - * motion. We wait for the ring to be clean before reallocating - * the rings. + * necessary so that we don't mess things up while we're in motion. */ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals) { struct gfar_private *priv = netdev_priv(dev); - int err = 0, i = 0; + int err = 0, i; if (rvals->rx_pending > GFAR_RX_MAX_RING_SIZE) return -EINVAL; @@ -493,44 +493,25 @@ static int gfar_sringparam(struct net_device *dev, return -EINVAL; } + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - if (dev->flags & IFF_UP) { - unsigned long flags; - - /* Halt TX and RX, and process the frames which - * have already been received - */ - local_irq_save(flags); - lock_tx_qs(priv); - lock_rx_qs(priv); - - gfar_halt(dev); - - unlock_rx_qs(priv); - unlock_tx_qs(priv); - local_irq_restore(flags); - - for (i = 0; i < priv->num_rx_queues; i++) - gfar_clean_rx_ring(priv->rx_queue[i], - priv->rx_queue[i]->rx_ring_size); - - /* Now we take down the rings to rebuild them */ + if (dev->flags & IFF_UP) stop_gfar(dev); - } - /* Change the size */ - for (i = 0; i < priv->num_rx_queues; i++) { + /* Change the sizes */ + for (i = 0; i < priv->num_rx_queues; i++) priv->rx_queue[i]->rx_ring_size = rvals->rx_pending; + + for (i = 0; i < priv->num_tx_queues; i++) priv->tx_queue[i]->tx_ring_size = rvals->tx_pending; - priv->tx_queue[i]->num_txbdfree = - priv->tx_queue[i]->tx_ring_size; - } /* Rebuild the rings with the new size */ - if (dev->flags & IFF_UP) { + if (dev->flags & IFF_UP) err = startup_gfar(dev); - netif_tx_wake_all_queues(dev); - } + + clear_bit_unlock(GFAR_RESETTING, &priv->state); + return err; } @@ -608,43 +589,29 @@ static int gfar_spauseparam(struct net_device *dev, int gfar_set_features(struct net_device *dev, netdev_features_t features) { - struct gfar_private *priv = netdev_priv(dev); - unsigned long flags; - int err = 0, i = 0; netdev_features_t changed = dev->features ^ features; + struct gfar_private *priv = netdev_priv(dev); + int err = 0; - if (changed & (NETIF_F_HW_VLAN_CTAG_TX|NETIF_F_HW_VLAN_CTAG_RX)) - gfar_vlan_mode(dev, features); - - if (!(changed & NETIF_F_RXCSUM)) + if (!(changed & (NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_RXCSUM))) return 0; - if (dev->flags & IFF_UP) { - /* Halt TX and RX, and process the frames which - * have already been received - */ - local_irq_save(flags); - lock_tx_qs(priv); - lock_rx_qs(priv); - - gfar_halt(dev); + while (test_and_set_bit_lock(GFAR_RESETTING, &priv->state)) + cpu_relax(); - unlock_tx_qs(priv); - unlock_rx_qs(priv); - local_irq_restore(flags); - - for (i = 0; i < priv->num_rx_queues; i++) - gfar_clean_rx_ring(priv->rx_queue[i], - priv->rx_queue[i]->rx_ring_size); + dev->features = features; + if (dev->flags & IFF_UP) { /* Now we take down the rings to rebuild them */ stop_gfar(dev); - - dev->features = features; - err = startup_gfar(dev); - netif_tx_wake_all_queues(dev); + } else { + gfar_mac_reset(priv); } + + clear_bit_unlock(GFAR_RESETTING, &priv->state); + return err; } @@ -1610,9 +1577,6 @@ static int gfar_write_filer_table(struct gfar_private *priv, if (tab->index > MAX_FILER_IDX - 1) return -EBUSY; - /* Avoid inconsistent filer table to be processed */ - lock_rx_qs(priv); - /* Fill regular entries */ for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl); i++) @@ -1625,8 +1589,6 @@ static int gfar_write_filer_table(struct gfar_private *priv, */ gfar_write_filer(priv, i, 0x20, 0x0); - unlock_rx_qs(priv); - return 0; } @@ -1831,6 +1793,9 @@ static int gfar_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd) struct gfar_private *priv = netdev_priv(dev); int ret = 0; + if (test_bit(GFAR_RESETTING, &priv->state)) + return -EBUSY; + mutex_lock(&priv->rx_queue_access); switch (cmd->cmd) { diff --git a/drivers/net/ethernet/freescale/gianfar_sysfs.c b/drivers/net/ethernet/freescale/gianfar_sysfs.c deleted file mode 100644 index e02dd1378751..000000000000 --- a/drivers/net/ethernet/freescale/gianfar_sysfs.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - * drivers/net/ethernet/freescale/gianfar_sysfs.c - * - * Gianfar Ethernet Driver - * This driver is designed for the non-CPM ethernet controllers - * on the 85xx and 83xx family of integrated processors - * Based on 8260_io/fcc_enet.c - * - * Author: Andy Fleming - * Maintainer: Kumar Gala (galak@kernel.crashing.org) - * Modifier: Sandeep Gopalpet <sandeep.kumar@freescale.com> - * - * Copyright 2002-2009 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * Sysfs file creation and management - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/errno.h> -#include <linux/unistd.h> -#include <linux/delay.h> -#include <linux/etherdevice.h> -#include <linux/spinlock.h> -#include <linux/mm.h> -#include <linux/device.h> - -#include <asm/uaccess.h> -#include <linux/module.h> - -#include "gianfar.h" - -static ssize_t gfar_show_bd_stash(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%s\n", priv->bd_stash_en ? "on" : "off"); -} - -static ssize_t gfar_set_bd_stash(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - int new_setting = 0; - u32 temp; - unsigned long flags; - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BD_STASHING)) - return count; - - - /* Find out the new setting */ - if (!strncmp("on", buf, count - 1) || !strncmp("1", buf, count - 1)) - new_setting = 1; - else if (!strncmp("off", buf, count - 1) || - !strncmp("0", buf, count - 1)) - new_setting = 0; - else - return count; - - - local_irq_save(flags); - lock_rx_qs(priv); - - /* Set the new stashing value */ - priv->bd_stash_en = new_setting; - - temp = gfar_read(®s->attr); - - if (new_setting) - temp |= ATTR_BDSTASH; - else - temp &= ~(ATTR_BDSTASH); - - gfar_write(®s->attr, temp); - - unlock_rx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(bd_stash, 0644, gfar_show_bd_stash, gfar_set_bd_stash); - -static ssize_t gfar_show_rx_stash_size(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->rx_stash_size); -} - -static ssize_t gfar_set_rx_stash_size(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int length = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) - return count; - - local_irq_save(flags); - lock_rx_qs(priv); - - if (length > priv->rx_buffer_size) - goto out; - - if (length == priv->rx_stash_size) - goto out; - - priv->rx_stash_size = length; - - temp = gfar_read(®s->attreli); - temp &= ~ATTRELI_EL_MASK; - temp |= ATTRELI_EL(length); - gfar_write(®s->attreli, temp); - - /* Turn stashing on/off as appropriate */ - temp = gfar_read(®s->attr); - - if (length) - temp |= ATTR_BUFSTASH; - else - temp &= ~(ATTR_BUFSTASH); - - gfar_write(®s->attr, temp); - -out: - unlock_rx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(rx_stash_size, 0644, gfar_show_rx_stash_size, - gfar_set_rx_stash_size); - -/* Stashing will only be enabled when rx_stash_size != 0 */ -static ssize_t gfar_show_rx_stash_index(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->rx_stash_index); -} - -static ssize_t gfar_set_rx_stash_index(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned short index = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_BUF_STASHING)) - return count; - - local_irq_save(flags); - lock_rx_qs(priv); - - if (index > priv->rx_stash_size) - goto out; - - if (index == priv->rx_stash_index) - goto out; - - priv->rx_stash_index = index; - - temp = gfar_read(®s->attreli); - temp &= ~ATTRELI_EI_MASK; - temp |= ATTRELI_EI(index); - gfar_write(®s->attreli, temp); - -out: - unlock_rx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(rx_stash_index, 0644, gfar_show_rx_stash_index, - gfar_set_rx_stash_index); - -static ssize_t gfar_show_fifo_threshold(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->fifo_threshold); -} - -static ssize_t gfar_set_fifo_threshold(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int length = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (length > GFAR_MAX_FIFO_THRESHOLD) - return count; - - local_irq_save(flags); - lock_tx_qs(priv); - - priv->fifo_threshold = length; - - temp = gfar_read(®s->fifo_tx_thr); - temp &= ~FIFO_TX_THR_MASK; - temp |= length; - gfar_write(®s->fifo_tx_thr, temp); - - unlock_tx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(fifo_threshold, 0644, gfar_show_fifo_threshold, - gfar_set_fifo_threshold); - -static ssize_t gfar_show_fifo_starve(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->fifo_starve); -} - -static ssize_t gfar_set_fifo_starve(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int num = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (num > GFAR_MAX_FIFO_STARVE) - return count; - - local_irq_save(flags); - lock_tx_qs(priv); - - priv->fifo_starve = num; - - temp = gfar_read(®s->fifo_tx_starve); - temp &= ~FIFO_TX_STARVE_MASK; - temp |= num; - gfar_write(®s->fifo_tx_starve, temp); - - unlock_tx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(fifo_starve, 0644, gfar_show_fifo_starve, - gfar_set_fifo_starve); - -static ssize_t gfar_show_fifo_starve_off(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - - return sprintf(buf, "%d\n", priv->fifo_starve_off); -} - -static ssize_t gfar_set_fifo_starve_off(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gfar_private *priv = netdev_priv(to_net_dev(dev)); - struct gfar __iomem *regs = priv->gfargrp[0].regs; - unsigned int num = simple_strtoul(buf, NULL, 0); - u32 temp; - unsigned long flags; - - if (num > GFAR_MAX_FIFO_STARVE_OFF) - return count; - - local_irq_save(flags); - lock_tx_qs(priv); - - priv->fifo_starve_off = num; - - temp = gfar_read(®s->fifo_tx_starve_shutoff); - temp &= ~FIFO_TX_STARVE_OFF_MASK; - temp |= num; - gfar_write(®s->fifo_tx_starve_shutoff, temp); - - unlock_tx_qs(priv); - local_irq_restore(flags); - - return count; -} - -static DEVICE_ATTR(fifo_starve_off, 0644, gfar_show_fifo_starve_off, - gfar_set_fifo_starve_off); - -void gfar_init_sysfs(struct net_device *dev) -{ - struct gfar_private *priv = netdev_priv(dev); - int rc; - - /* Initialize the default values */ - priv->fifo_threshold = DEFAULT_FIFO_TX_THR; - priv->fifo_starve = DEFAULT_FIFO_TX_STARVE; - priv->fifo_starve_off = DEFAULT_FIFO_TX_STARVE_OFF; - - /* Create our sysfs files */ - rc = device_create_file(&dev->dev, &dev_attr_bd_stash); - rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_size); - rc |= device_create_file(&dev->dev, &dev_attr_rx_stash_index); - rc |= device_create_file(&dev->dev, &dev_attr_fifo_threshold); - rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve); - rc |= device_create_file(&dev->dev, &dev_attr_fifo_starve_off); - if (rc) - dev_err(&dev->dev, "Error creating gianfar sysfs files\n"); -} diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index cbaba4442d4b..bf7a01ef9a57 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -3034,7 +3034,7 @@ static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake) *enable_wake = false; } - pci_disable_device(pdev); + pci_clear_master(pdev); } static int __e100_power_off(struct pci_dev *pdev, bool wake) diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.c b/drivers/net/ethernet/intel/e1000e/80003es2lan.c index ff2d806eaef7..a5f6b11d6992 100644 --- a/drivers/net/ethernet/intel/e1000e/80003es2lan.c +++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* 80003ES2LAN Gigabit Ethernet Controller (Copper) * 80003ES2LAN Gigabit Ethernet Controller (Serdes) diff --git a/drivers/net/ethernet/intel/e1000e/80003es2lan.h b/drivers/net/ethernet/intel/e1000e/80003es2lan.h index 90d363b2d280..535a9430976d 100644 --- a/drivers/net/ethernet/intel/e1000e/80003es2lan.h +++ b/drivers/net/ethernet/intel/e1000e/80003es2lan.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_80003ES2LAN_H_ #define _E1000E_80003ES2LAN_H_ diff --git a/drivers/net/ethernet/intel/e1000e/82571.c b/drivers/net/ethernet/intel/e1000e/82571.c index 8fed74e3fa53..e0aa7f1efb08 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.c +++ b/drivers/net/ethernet/intel/e1000e/82571.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* 82571EB Gigabit Ethernet Controller * 82571EB Gigabit Ethernet Controller (Copper) diff --git a/drivers/net/ethernet/intel/e1000e/82571.h b/drivers/net/ethernet/intel/e1000e/82571.h index 08e24dc3dc0e..2e758f796d60 100644 --- a/drivers/net/ethernet/intel/e1000e/82571.h +++ b/drivers/net/ethernet/intel/e1000e/82571.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_82571_H_ #define _E1000E_82571_H_ diff --git a/drivers/net/ethernet/intel/e1000e/Makefile b/drivers/net/ethernet/intel/e1000e/Makefile index c2dcfcc10857..106de493373c 100644 --- a/drivers/net/ethernet/intel/e1000e/Makefile +++ b/drivers/net/ethernet/intel/e1000e/Makefile @@ -1,7 +1,7 @@ ################################################################################ # # Intel PRO/1000 Linux driver -# Copyright(c) 1999 - 2013 Intel Corporation. +# Copyright(c) 1999 - 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, @@ -12,9 +12,8 @@ # 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, write to the Free Software Foundation, Inc., -# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# 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". diff --git a/drivers/net/ethernet/intel/e1000e/defines.h b/drivers/net/ethernet/intel/e1000e/defines.h index 351c94a0cf74..d18e89212575 100644 --- a/drivers/net/ethernet/intel/e1000e/defines.h +++ b/drivers/net/ethernet/intel/e1000e/defines.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_DEFINES_H_ #define _E1000_DEFINES_H_ @@ -35,9 +28,11 @@ /* Definitions for power management and wakeup registers */ /* Wake Up Control */ -#define E1000_WUC_APME 0x00000001 /* APM Enable */ -#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ -#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ +#define E1000_WUC_APME 0x00000001 /* APM Enable */ +#define E1000_WUC_PME_EN 0x00000002 /* PME Enable */ +#define E1000_WUC_PME_STATUS 0x00000004 /* PME Status */ +#define E1000_WUC_APMPME 0x00000008 /* Assert PME on APM Wakeup */ +#define E1000_WUC_PHY_WAKE 0x00000100 /* if PHY supports wakeup */ /* Wake Up Filter Control */ #define E1000_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */ diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 0150f7fc893d..5325e3e2154e 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* Linux PRO/1000 Ethernet Driver main header file */ @@ -333,7 +326,6 @@ struct e1000_adapter { struct work_struct update_phy_task; struct work_struct print_hang_task; - bool idle_check; int phy_hang_count; u16 tx_ring_count; @@ -476,7 +468,7 @@ void e1000e_check_options(struct e1000_adapter *adapter); void e1000e_set_ethtool_ops(struct net_device *netdev); int e1000e_up(struct e1000_adapter *adapter); -void e1000e_down(struct e1000_adapter *adapter); +void e1000e_down(struct e1000_adapter *adapter, bool reset); void e1000e_reinit_locked(struct e1000_adapter *adapter); void e1000e_reset(struct e1000_adapter *adapter); void e1000e_power_up_phy(struct e1000_adapter *adapter); diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index d14c8f53384c..3c2898d0c2aa 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* ethtool support for e1000 */ @@ -332,7 +325,7 @@ static int e1000_set_settings(struct net_device *netdev, /* reset the link */ if (netif_running(adapter->netdev)) { - e1000e_down(adapter); + e1000e_down(adapter, true); e1000e_up(adapter); } else { e1000e_reset(adapter); @@ -380,7 +373,7 @@ static int e1000_set_pauseparam(struct net_device *netdev, if (adapter->fc_autoneg == AUTONEG_ENABLE) { hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { - e1000e_down(adapter); + e1000e_down(adapter, true); e1000e_up(adapter); } else { e1000e_reset(adapter); @@ -726,7 +719,7 @@ static int e1000_set_ringparam(struct net_device *netdev, pm_runtime_get_sync(netdev->dev.parent); - e1000e_down(adapter); + e1000e_down(adapter, true); /* We can't just free everything and then setup again, because the * ISRs in MSI-X mode get passed pointers to the Tx and Rx ring @@ -924,15 +917,21 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data) } if (mac->type == e1000_pch2lan) { /* SHRAH[0,1,2] different than previous */ - if (i == 7) + if (i == 1) mask &= 0xFFF4FFFF; /* SHRAH[3] different than SHRAH[0,1,2] */ - if (i == 10) + if (i == 4) mask |= (1 << 30); + /* RAR[1-6] owned by management engine - skipping */ + if (i > 0) + i += 6; } REG_PATTERN_TEST_ARRAY(E1000_RA, ((i << 1) + 1), mask, 0xFFFFFFFF); + /* reset index to actual value */ + if ((mac->type == e1000_pch2lan) && (i > 6)) + i -= 6; } for (i = 0; i < mac->mta_reg_count; i++) diff --git a/drivers/net/ethernet/intel/e1000e/hw.h b/drivers/net/ethernet/intel/e1000e/hw.h index b7f38435d1fd..6b3de5f39a97 100644 --- a/drivers/net/ethernet/intel/e1000e/hw.h +++ b/drivers/net/ethernet/intel/e1000e/hw.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000_HW_H_ #define _E1000_HW_H_ @@ -655,12 +648,20 @@ struct e1000_shadow_ram { #define E1000_ICH8_SHADOW_RAM_WORDS 2048 +/* I218 PHY Ultra Low Power (ULP) states */ +enum e1000_ulp_state { + e1000_ulp_state_unknown, + e1000_ulp_state_off, + e1000_ulp_state_on, +}; + struct e1000_dev_spec_ich8lan { bool kmrn_lock_loss_workaround_enabled; struct e1000_shadow_ram shadow_ram[E1000_ICH8_SHADOW_RAM_WORDS]; bool nvm_k1_enabled; bool eee_disable; u16 eee_lp_ability; + enum e1000_ulp_state ulp_state; }; struct e1000_hw { diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 42f0f6717511..9866f264f55e 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* 82562G 10/100 Network Connection * 82562G-2 10/100 Network Connection @@ -53,6 +46,14 @@ * 82578DC Gigabit Network Connection * 82579LM Gigabit Network Connection * 82579V Gigabit Network Connection + * Ethernet Connection I217-LM + * Ethernet Connection I217-V + * Ethernet Connection I218-V + * Ethernet Connection I218-LM + * Ethernet Connection (2) I218-LM + * Ethernet Connection (2) I218-V + * Ethernet Connection (3) I218-LM + * Ethernet Connection (3) I218-V */ #include "e1000.h" @@ -142,7 +143,9 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); static void e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index); static s32 e1000_k1_workaround_lv(struct e1000_hw *hw); static void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); +static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force); static s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw); +static s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state); static inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) { @@ -239,6 +242,47 @@ out: } /** + * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value + * @hw: pointer to the HW structure + * + * Toggling the LANPHYPC pin value fully power-cycles the PHY and is + * used to reset the PHY to a quiescent state when necessary. + **/ +static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) +{ + u32 mac_reg; + + /* Set Phy Config Counter to 50msec */ + mac_reg = er32(FEXTNVM3); + mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; + mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; + ew32(FEXTNVM3, mac_reg); + + /* Toggle LANPHYPC Value bit */ + mac_reg = er32(CTRL); + mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; + mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; + ew32(CTRL, mac_reg); + e1e_flush(); + usleep_range(10, 20); + mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; + ew32(CTRL, mac_reg); + e1e_flush(); + + if (hw->mac.type < e1000_pch_lpt) { + msleep(50); + } else { + u16 count = 20; + + do { + usleep_range(5000, 10000); + } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--); + + msleep(30); + } +} + +/** * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds * @hw: pointer to the HW structure * @@ -247,6 +291,7 @@ out: **/ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) { + struct e1000_adapter *adapter = hw->adapter; u32 mac_reg, fwsm = er32(FWSM); s32 ret_val; @@ -255,6 +300,12 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) */ e1000_gate_hw_phy_config_ich8lan(hw, true); + /* It is not possible to be certain of the current state of ULP + * so forcibly disable it. + */ + hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown; + e1000_disable_ulp_lpt_lp(hw, true); + ret_val = hw->phy.ops.acquire(hw); if (ret_val) { e_dbg("Failed to initialize PHY flow\n"); @@ -300,33 +351,9 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) break; } - e_dbg("Toggling LANPHYPC\n"); - - /* Set Phy Config Counter to 50msec */ - mac_reg = er32(FEXTNVM3); - mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; - mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; - ew32(FEXTNVM3, mac_reg); - /* Toggle LANPHYPC Value bit */ - mac_reg = er32(CTRL); - mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; - mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; - ew32(CTRL, mac_reg); - e1e_flush(); - usleep_range(10, 20); - mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; - ew32(CTRL, mac_reg); - e1e_flush(); - if (hw->mac.type < e1000_pch_lpt) { - msleep(50); - } else { - u16 count = 20; - do { - usleep_range(5000, 10000); - } while (!(er32(CTRL_EXT) & - E1000_CTRL_EXT_LPCD) && count--); - usleep_range(30000, 60000); + e1000_toggle_lanphypc_pch_lpt(hw); + if (hw->mac.type >= e1000_pch_lpt) { if (e1000_phy_is_accessible_pchlan(hw)) break; @@ -349,12 +376,31 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) hw->phy.ops.release(hw); if (!ret_val) { + + /* Check to see if able to reset PHY. Print error if not */ + if (hw->phy.ops.check_reset_block(hw)) { + e_err("Reset blocked by ME\n"); + goto out; + } + /* Reset the PHY before any access to it. Doing so, ensures * that the PHY is in a known good state before we read/write * PHY registers. The generic reset is sufficient here, * because we haven't determined the PHY type yet. */ ret_val = e1000e_phy_hw_reset_generic(hw); + if (ret_val) + goto out; + + /* On a successful reset, possibly need to wait for the PHY + * to quiesce to an accessible state before returning control + * to the calling function. If the PHY does not quiesce, then + * return E1000E_BLK_PHY_RESET, as this is the condition that + * the PHY is in. + */ + ret_val = hw->phy.ops.check_reset_block(hw); + if (ret_val) + e_err("ME blocked access to PHY after reset\n"); } out: @@ -724,8 +770,14 @@ s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data) * Enable/disable EEE based on setting in dev_spec structure, the duplex of * the link and the EEE capabilities of the link partner. The LPI Control * register bits will remain set only if/when link is up. + * + * EEE LPI must not be asserted earlier than one second after link is up. + * On 82579, EEE LPI should not be enabled until such time otherwise there + * can be link issues with some switches. Other devices can have EEE LPI + * enabled immediately upon link up since they have a timer in hardware which + * prevents LPI from being asserted too early. **/ -static s32 e1000_set_eee_pchlan(struct e1000_hw *hw) +s32 e1000_set_eee_pchlan(struct e1000_hw *hw) { struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; s32 ret_val; @@ -979,6 +1031,253 @@ static s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) } /** + * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP + * @hw: pointer to the HW structure + * @to_sx: boolean indicating a system power state transition to Sx + * + * When link is down, configure ULP mode to significantly reduce the power + * to the PHY. If on a Manageability Engine (ME) enabled system, tell the + * ME firmware to start the ULP configuration. If not on an ME enabled + * system, configure the ULP mode by software. + */ +s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx) +{ + u32 mac_reg; + s32 ret_val = 0; + u16 phy_reg; + + if ((hw->mac.type < e1000_pch_lpt) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) || + (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on)) + return 0; + + if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { + /* Request ME configure ULP mode in the PHY */ + mac_reg = er32(H2ME); + mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; + ew32(H2ME, mac_reg); + + goto out; + } + + if (!to_sx) { + int i = 0; + + /* Poll up to 5 seconds for Cable Disconnected indication */ + while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) { + /* Bail if link is re-acquired */ + if (er32(STATUS) & E1000_STATUS_LU) + return -E1000_ERR_PHY; + + if (i++ == 100) + break; + + msleep(50); + } + e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n", + (er32(FEXT) & + E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50); + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + /* Force SMBus mode in PHY */ + ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); + if (ret_val) + goto release; + phy_reg |= CV_SMB_CTRL_FORCE_SMBUS; + e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); + + /* Force SMBus mode in MAC */ + mac_reg = er32(CTRL_EXT); + mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + /* Set Inband ULP Exit, Reset to SMBus mode and + * Disable SMBus Release on PERST# in PHY + */ + ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); + if (ret_val) + goto release; + phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS | + I218_ULP_CONFIG1_DISABLE_SMB_PERST); + if (to_sx) { + if (er32(WUFC) & E1000_WUFC_LNKC) + phy_reg |= I218_ULP_CONFIG1_WOL_HOST; + + phy_reg |= I218_ULP_CONFIG1_STICKY_ULP; + } else { + phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT; + } + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Set Disable SMBus Release on PERST# in MAC */ + mac_reg = er32(FEXTNVM7); + mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST; + ew32(FEXTNVM7, mac_reg); + + /* Commit ULP changes in PHY by starting auto ULP configuration */ + phy_reg |= I218_ULP_CONFIG1_START; + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); +release: + hw->phy.ops.release(hw); +out: + if (ret_val) + e_dbg("Error in ULP enable flow: %d\n", ret_val); + else + hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on; + + return ret_val; +} + +/** + * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP + * @hw: pointer to the HW structure + * @force: boolean indicating whether or not to force disabling ULP + * + * Un-configure ULP mode when link is up, the system is transitioned from + * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled + * system, poll for an indication from ME that ULP has been un-configured. + * If not on an ME enabled system, un-configure the ULP mode by software. + * + * During nominal operation, this function is called when link is acquired + * to disable ULP mode (force=false); otherwise, for example when unloading + * the driver or during Sx->S0 transitions, this is called with force=true + * to forcibly disable ULP. + */ +static s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) +{ + s32 ret_val = 0; + u32 mac_reg; + u16 phy_reg; + int i = 0; + + if ((hw->mac.type < e1000_pch_lpt) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) || + (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) || + (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off)) + return 0; + + if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { + if (force) { + /* Request ME un-configure ULP mode in the PHY */ + mac_reg = er32(H2ME); + mac_reg &= ~E1000_H2ME_ULP; + mac_reg |= E1000_H2ME_ENFORCE_SETTINGS; + ew32(H2ME, mac_reg); + } + + /* Poll up to 100msec for ME to clear ULP_CFG_DONE */ + while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) { + if (i++ == 10) { + ret_val = -E1000_ERR_PHY; + goto out; + } + + usleep_range(10000, 20000); + } + e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); + + if (force) { + mac_reg = er32(H2ME); + mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS; + ew32(H2ME, mac_reg); + } else { + /* Clear H2ME.ULP after ME ULP configuration */ + mac_reg = er32(H2ME); + mac_reg &= ~E1000_H2ME_ULP; + ew32(H2ME, mac_reg); + } + + goto out; + } + + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + goto out; + + if (force) + /* Toggle LANPHYPC Value bit */ + e1000_toggle_lanphypc_pch_lpt(hw); + + /* Unforce SMBus mode in PHY */ + ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); + if (ret_val) { + /* The MAC might be in PCIe mode, so temporarily force to + * SMBus mode in order to access the PHY. + */ + mac_reg = er32(CTRL_EXT); + mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + msleep(50); + + ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, + &phy_reg); + if (ret_val) + goto release; + } + phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; + e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); + + /* Unforce SMBus mode in MAC */ + mac_reg = er32(CTRL_EXT); + mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; + ew32(CTRL_EXT, mac_reg); + + /* When ULP mode was previously entered, K1 was disabled by the + * hardware. Re-Enable K1 in the PHY when exiting ULP. + */ + ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg); + if (ret_val) + goto release; + phy_reg |= HV_PM_CTRL_K1_ENABLE; + e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg); + + /* Clear ULP enabled configuration */ + ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); + if (ret_val) + goto release; + phy_reg &= ~(I218_ULP_CONFIG1_IND | + I218_ULP_CONFIG1_STICKY_ULP | + I218_ULP_CONFIG1_RESET_TO_SMBUS | + I218_ULP_CONFIG1_WOL_HOST | + I218_ULP_CONFIG1_INBAND_EXIT | + I218_ULP_CONFIG1_DISABLE_SMB_PERST); + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Commit ULP changes by starting auto ULP configuration */ + phy_reg |= I218_ULP_CONFIG1_START; + e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); + + /* Clear Disable SMBus Release on PERST# in MAC */ + mac_reg = er32(FEXTNVM7); + mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; + ew32(FEXTNVM7, mac_reg); + +release: + hw->phy.ops.release(hw); + if (force) { + e1000_phy_hw_reset(hw); + msleep(50); + } +out: + if (ret_val) + e_dbg("Error in ULP disable flow: %d\n", ret_val); + else + hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off; + + return ret_val; +} + +/** * e1000_check_for_copper_link_ich8lan - Check for link (Copper) * @hw: pointer to the HW structure * @@ -1106,9 +1405,11 @@ static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) e1000e_check_downshift(hw); /* Enable/Disable EEE after link up */ - ret_val = e1000_set_eee_pchlan(hw); - if (ret_val) - return ret_val; + if (hw->phy.type > e1000_phy_82579) { + ret_val = e1000_set_eee_pchlan(hw); + if (ret_val) + return ret_val; + } /* If we are forcing speed/duplex, then we simply return since * we have already determined whether we have link or not. @@ -1374,7 +1675,7 @@ static void e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) /* RAR[1-6] are owned by manageability. Skip those and program the * next address into the SHRA register array. */ - if (index < (u32)(hw->mac.rar_entry_count - 6)) { + if (index < (u32)(hw->mac.rar_entry_count)) { s32 ret_val; ret_val = e1000_acquire_swflag_ich8lan(hw); @@ -1484,11 +1785,13 @@ out: **/ static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) { - u32 fwsm; + bool blocked = false; + int i = 0; - fwsm = er32(FWSM); - - return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? 0 : E1000_BLK_PHY_RESET; + while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) && + (i++ < 10)) + usleep_range(10000, 20000); + return blocked ? E1000_BLK_PHY_RESET : 0; } /** diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.h b/drivers/net/ethernet/intel/e1000e/ich8lan.h index 217090df33e7..bead50f9187b 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.h +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_ICH8LAN_H_ #define _E1000E_ICH8LAN_H_ @@ -65,11 +58,16 @@ #define E1000_FWSM_WLOCK_MAC_MASK 0x0380 #define E1000_FWSM_WLOCK_MAC_SHIFT 7 +#define E1000_FWSM_ULP_CFG_DONE 0x00000400 /* Low power cfg done */ /* Shared Receive Address Registers */ #define E1000_SHRAL_PCH_LPT(_i) (0x05408 + ((_i) * 8)) #define E1000_SHRAH_PCH_LPT(_i) (0x0540C + ((_i) * 8)) +#define E1000_H2ME 0x05B50 /* Host to ME */ +#define E1000_H2ME_ULP 0x00000800 /* ULP Indication Bit */ +#define E1000_H2ME_ENFORCE_SETTINGS 0x00001000 /* Enforce Settings */ + #define ID_LED_DEFAULT_ICH8LAN ((ID_LED_DEF1_DEF2 << 12) | \ (ID_LED_OFF1_OFF2 << 8) | \ (ID_LED_OFF1_ON2 << 4) | \ @@ -82,6 +80,9 @@ #define E1000_ICH8_LAN_INIT_TIMEOUT 1500 +/* FEXT register bit definition */ +#define E1000_FEXT_PHY_CABLE_DISCONNECTED 0x00000004 + #define E1000_FEXTNVM_SW_CONFIG 1 #define E1000_FEXTNVM_SW_CONFIG_ICH8M (1 << 27) /* different on ICH8M */ @@ -95,10 +96,12 @@ #define E1000_FEXTNVM6_REQ_PLL_CLK 0x00000100 #define E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION 0x00000200 +#define E1000_FEXTNVM7_DISABLE_SMB_PERST 0x00000020 + #define PCIE_ICH8_SNOOP_ALL PCIE_NO_SNOOP_ALL #define E1000_ICH_RAR_ENTRIES 7 -#define E1000_PCH2_RAR_ENTRIES 11 /* RAR[0-6], SHRA[0-3] */ +#define E1000_PCH2_RAR_ENTRIES 5 /* RAR[0], SHRA[0-3] */ #define E1000_PCH_LPT_RAR_ENTRIES 12 /* RAR[0], SHRA[0-10] */ #define PHY_PAGE_SHIFT 5 @@ -161,6 +164,16 @@ #define CV_SMB_CTRL PHY_REG(769, 23) #define CV_SMB_CTRL_FORCE_SMBUS 0x0001 +/* I218 Ultra Low Power Configuration 1 Register */ +#define I218_ULP_CONFIG1 PHY_REG(779, 16) +#define I218_ULP_CONFIG1_START 0x0001 /* Start auto ULP config */ +#define I218_ULP_CONFIG1_IND 0x0004 /* Pwr up from ULP indication */ +#define I218_ULP_CONFIG1_STICKY_ULP 0x0010 /* Set sticky ULP mode */ +#define I218_ULP_CONFIG1_INBAND_EXIT 0x0020 /* Inband on ULP exit */ +#define I218_ULP_CONFIG1_WOL_HOST 0x0040 /* WoL Host on ULP exit */ +#define I218_ULP_CONFIG1_RESET_TO_SMBUS 0x0100 /* Reset to SMBus mode */ +#define I218_ULP_CONFIG1_DISABLE_SMB_PERST 0x1000 /* Disable on PERST# */ + /* SMBus Address Phy Register */ #define HV_SMB_ADDR PHY_REG(768, 26) #define HV_SMB_ADDR_MASK 0x007F @@ -195,6 +208,7 @@ /* PHY Power Management Control */ #define HV_PM_CTRL PHY_REG(770, 17) #define HV_PM_CTRL_PLL_STOP_IN_K1_GIGA 0x100 +#define HV_PM_CTRL_K1_ENABLE 0x4000 #define SW_FLAG_TIMEOUT 1000 /* SW Semaphore flag timeout in ms */ @@ -268,4 +282,6 @@ void e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw); s32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable); s32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data); s32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data); +s32 e1000_set_eee_pchlan(struct e1000_hw *hw); +s32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx); #endif /* _E1000E_ICH8LAN_H_ */ diff --git a/drivers/net/ethernet/intel/e1000e/mac.c b/drivers/net/ethernet/intel/e1000e/mac.c index 2480c1091873..baa0a466d1d0 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.c +++ b/drivers/net/ethernet/intel/e1000e/mac.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/mac.h b/drivers/net/ethernet/intel/e1000e/mac.h index a61fee404ebe..4e81c2825b7a 100644 --- a/drivers/net/ethernet/intel/e1000e/mac.h +++ b/drivers/net/ethernet/intel/e1000e/mac.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_MAC_H_ #define _E1000E_MAC_H_ diff --git a/drivers/net/ethernet/intel/e1000e/manage.c b/drivers/net/ethernet/intel/e1000e/manage.c index e4b0f1ef92f6..cb37ff1f1321 100644 --- a/drivers/net/ethernet/intel/e1000e/manage.c +++ b/drivers/net/ethernet/intel/e1000e/manage.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/manage.h b/drivers/net/ethernet/intel/e1000e/manage.h index 326897c29ea8..a8c27f98f7b0 100644 --- a/drivers/net/ethernet/intel/e1000e/manage.h +++ b/drivers/net/ethernet/intel/e1000e/manage.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_MANAGE_H_ #define _E1000E_MANAGE_H_ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 6d91933c4cdd..5129c4cd14bc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -1701,7 +1694,7 @@ static void e1000_clean_rx_ring(struct e1000_ring *rx_ring) adapter->flags2 &= ~FLAG2_IS_DISCARDING; writel(0, rx_ring->head); - if (rx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) e1000e_update_rdt_wa(rx_ring, 0); else writel(0, rx_ring->tail); @@ -2038,13 +2031,16 @@ void e1000e_set_interrupt_capability(struct e1000_adapter *adapter) msix_entry), GFP_KERNEL); if (adapter->msix_entries) { + struct e1000_adapter *a = adapter; + for (i = 0; i < adapter->num_vectors; i++) adapter->msix_entries[i].entry = i; - err = pci_enable_msix(adapter->pdev, - adapter->msix_entries, - adapter->num_vectors); - if (err == 0) + err = pci_enable_msix_range(a->pdev, + a->msix_entries, + a->num_vectors, + a->num_vectors); + if (err > 0) return; } /* MSI-X failed, so fall through and try MSI */ @@ -2402,7 +2398,7 @@ static void e1000_clean_tx_ring(struct e1000_ring *tx_ring) tx_ring->next_to_clean = 0; writel(0, tx_ring->head); - if (tx_ring->adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) + if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA) e1000e_update_tdt_wa(tx_ring, 0); else writel(0, tx_ring->tail); @@ -3331,6 +3327,9 @@ static void e1000e_set_rx_mode(struct net_device *netdev) struct e1000_hw *hw = &adapter->hw; u32 rctl; + if (pm_runtime_suspended(netdev->dev.parent)) + return; + /* Check for Promiscuous and All Multicast modes */ rctl = er32(RCTL); @@ -3691,10 +3690,6 @@ void e1000e_power_up_phy(struct e1000_adapter *adapter) */ static void e1000_power_down_phy(struct e1000_adapter *adapter) { - /* WoL is enabled */ - if (adapter->wol) - return; - if (adapter->hw.phy.ops.power_down) adapter->hw.phy.ops.power_down(&adapter->hw); } @@ -3911,10 +3906,8 @@ void e1000e_reset(struct e1000_adapter *adapter) } if (!netif_running(adapter->netdev) && - !test_bit(__E1000_TESTING, &adapter->state)) { + !test_bit(__E1000_TESTING, &adapter->state)) e1000_power_down_phy(adapter); - return; - } e1000_get_phy_info(hw); @@ -3981,7 +3974,12 @@ static void e1000e_flush_descriptors(struct e1000_adapter *adapter) static void e1000e_update_stats(struct e1000_adapter *adapter); -void e1000e_down(struct e1000_adapter *adapter) +/** + * e1000e_down - quiesce the device and optionally reset the hardware + * @adapter: board private structure + * @reset: boolean flag to reset the hardware or not + */ +void e1000e_down(struct e1000_adapter *adapter, bool reset) { struct net_device *netdev = adapter->netdev; struct e1000_hw *hw = &adapter->hw; @@ -4035,12 +4033,8 @@ void e1000e_down(struct e1000_adapter *adapter) e1000_lv_jumbo_workaround_ich8lan(hw, false)) e_dbg("failed to disable jumbo frame workaround mode\n"); - if (!pci_channel_offline(adapter->pdev)) + if (reset && !pci_channel_offline(adapter->pdev)) e1000e_reset(adapter); - - /* TODO: for power management, we could drop the link and - * pci_disable_device here. - */ } void e1000e_reinit_locked(struct e1000_adapter *adapter) @@ -4048,7 +4042,7 @@ void e1000e_reinit_locked(struct e1000_adapter *adapter) might_sleep(); while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) usleep_range(1000, 2000); - e1000e_down(adapter); + e1000e_down(adapter, true); e1000e_up(adapter); clear_bit(__E1000_RESETTING, &adapter->state); } @@ -4326,7 +4320,6 @@ static int e1000_open(struct net_device *netdev) adapter->tx_hang_recheck = false; netif_start_queue(netdev); - adapter->idle_check = true; hw->mac.get_link_status = true; pm_runtime_put(&pdev->dev); @@ -4376,14 +4369,15 @@ static int e1000_close(struct net_device *netdev) pm_runtime_get_sync(&pdev->dev); if (!test_bit(__E1000_DOWN, &adapter->state)) { - e1000e_down(adapter); + e1000e_down(adapter, true); e1000_free_irq(adapter); + + /* Link status message must follow this format */ + pr_info("%s NIC Link is Down\n", adapter->netdev->name); } napi_disable(&adapter->napi); - e1000_power_down_phy(adapter); - e1000e_free_tx_resources(adapter->tx_ring); e1000e_free_rx_resources(adapter->rx_ring); @@ -4460,11 +4454,16 @@ static void e1000e_update_phy_task(struct work_struct *work) struct e1000_adapter *adapter = container_of(work, struct e1000_adapter, update_phy_task); + struct e1000_hw *hw = &adapter->hw; if (test_bit(__E1000_DOWN, &adapter->state)) return; - e1000_get_phy_info(&adapter->hw); + e1000_get_phy_info(hw); + + /* Enable EEE on 82579 after link up */ + if (hw->phy.type == e1000_phy_82579) + e1000_set_eee_pchlan(hw); } /** @@ -5684,8 +5683,11 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) adapter->max_frame_size = max_frame; e_info("changing MTU from %d to %d\n", netdev->mtu, new_mtu); netdev->mtu = new_mtu; + + pm_runtime_get_sync(netdev->dev.parent); + if (netif_running(netdev)) - e1000e_down(adapter); + e1000e_down(adapter, true); /* NOTE: netdev_alloc_skb reserves 16 bytes, and typically NET_IP_ALIGN * means we reserve 2 more, this pushes us to allocate from the next @@ -5711,6 +5713,8 @@ static int e1000_change_mtu(struct net_device *netdev, int new_mtu) else e1000e_reset(adapter); + pm_runtime_put_sync(netdev->dev.parent); + clear_bit(__E1000_RESETTING, &adapter->state); return 0; @@ -5852,7 +5856,7 @@ static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) { struct e1000_hw *hw = &adapter->hw; - u32 i, mac_reg; + u32 i, mac_reg, wuc; u16 phy_reg, wuc_enable; int retval; @@ -5899,13 +5903,18 @@ static int e1000_init_phy_wakeup(struct e1000_adapter *adapter, u32 wufc) phy_reg |= BM_RCTL_RFCE; hw->phy.ops.write_reg_page(&adapter->hw, BM_RCTL, phy_reg); + wuc = E1000_WUC_PME_EN; + if (wufc & (E1000_WUFC_MAG | E1000_WUFC_LNKC)) + wuc |= E1000_WUC_APME; + /* enable PHY wakeup in MAC register */ ew32(WUFC, wufc); - ew32(WUC, E1000_WUC_PHY_WAKE | E1000_WUC_PME_EN); + ew32(WUC, (E1000_WUC_PHY_WAKE | E1000_WUC_APMPME | + E1000_WUC_PME_STATUS | wuc)); /* configure and enable PHY wakeup in PHY registers */ hw->phy.ops.write_reg_page(&adapter->hw, BM_WUFC, wufc); - hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, E1000_WUC_PME_EN); + hw->phy.ops.write_reg_page(&adapter->hw, BM_WUC, wuc); /* activate PHY wakeup */ wuc_enable |= BM_WUC_ENABLE_BIT | BM_WUC_HOST_WU_BIT; @@ -5918,15 +5927,10 @@ release: return retval; } -static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) +static int e1000e_pm_freeze(struct device *dev) { - struct net_device *netdev = pci_get_drvdata(pdev); + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; - u32 ctrl, ctrl_ext, rctl, status; - /* Runtime suspend should only enable wakeup for link changes */ - u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol; - int retval = 0; netif_device_detach(netdev); @@ -5937,11 +5941,29 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) usleep_range(10000, 20000); WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); - e1000e_down(adapter); + + /* Quiesce the device without resetting the hardware */ + e1000e_down(adapter, false); e1000_free_irq(adapter); } e1000e_reset_interrupt_capability(adapter); + /* Allow time for pending master requests to run */ + e1000e_disable_pcie_master(&adapter->hw); + + return 0; +} + +static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) +{ + struct net_device *netdev = pci_get_drvdata(pdev); + struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; + u32 ctrl, ctrl_ext, rctl, status; + /* Runtime suspend should only enable wakeup for link changes */ + u32 wufc = runtime ? E1000_WUFC_LNKC : adapter->wol; + int retval = 0; + status = er32(STATUS); if (status & E1000_STATUS_LU) wufc &= ~E1000_WUFC_LNKC; @@ -5972,12 +5994,12 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) ew32(CTRL_EXT, ctrl_ext); } + if (!runtime) + e1000e_power_up_phy(adapter); + if (adapter->flags & FLAG_IS_ICH) e1000_suspend_workarounds_ich8lan(&adapter->hw); - /* Allow time for pending master requests to run */ - e1000e_disable_pcie_master(&adapter->hw); - if (adapter->flags2 & FLAG2_HAS_PHY_WAKEUP) { /* enable wakeup by the PHY */ retval = e1000_init_phy_wakeup(adapter, wufc); @@ -5991,10 +6013,23 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool runtime) } else { ew32(WUC, 0); ew32(WUFC, 0); + + e1000_power_down_phy(adapter); } - if (adapter->hw.phy.type == e1000_phy_igp_3) + if (adapter->hw.phy.type == e1000_phy_igp_3) { e1000e_igp3_phy_powerdown_workaround_ich8lan(&adapter->hw); + } else if (hw->mac.type == e1000_pch_lpt) { + if (!(wufc & (E1000_WUFC_EX | E1000_WUFC_MC | E1000_WUFC_BC))) + /* ULP does not support wake from unicast, multicast + * or broadcast. + */ + retval = e1000_enable_ulp_lpt_lp(hw, !runtime); + + if (retval) + return retval; + } + /* Release control of h/w to f/w. If f/w is AMT enabled, this * would have already happened in close and is redundant. @@ -6102,18 +6137,12 @@ static void e1000e_disable_aspm(struct pci_dev *pdev, u16 state) } #ifdef CONFIG_PM -static bool e1000e_pm_ready(struct e1000_adapter *adapter) -{ - return !!adapter->tx_ring->buffer_info; -} - static int __e1000_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; u16 aspm_disable_flag = 0; - u32 err; if (adapter->flags2 & FLAG2_DISABLE_ASPM_L0S) aspm_disable_flag = PCIE_LINK_STATE_L0S; @@ -6124,13 +6153,6 @@ static int __e1000_resume(struct pci_dev *pdev) pci_set_master(pdev); - e1000e_set_interrupt_capability(adapter); - if (netif_running(netdev)) { - err = e1000_request_irq(adapter); - if (err) - return err; - } - if (hw->mac.type >= e1000_pch2lan) e1000_resume_workarounds_pchlan(&adapter->hw); @@ -6169,11 +6191,6 @@ static int __e1000_resume(struct pci_dev *pdev) e1000_init_manageability_pt(adapter); - if (netif_running(netdev)) - e1000e_up(adapter); - - netif_device_attach(netdev); - /* If the controller has AMT, do not set DRV_LOAD until the interface * is up. For all other cases, let the f/w know that the h/w is now * under the control of the driver. @@ -6184,75 +6201,111 @@ static int __e1000_resume(struct pci_dev *pdev) return 0; } +static int e1000e_pm_thaw(struct device *dev) +{ + struct net_device *netdev = pci_get_drvdata(to_pci_dev(dev)); + struct e1000_adapter *adapter = netdev_priv(netdev); + + e1000e_set_interrupt_capability(adapter); + if (netif_running(netdev)) { + u32 err = e1000_request_irq(adapter); + + if (err) + return err; + + e1000e_up(adapter); + } + + netif_device_attach(netdev); + + return 0; +} + #ifdef CONFIG_PM_SLEEP -static int e1000_suspend(struct device *dev) +static int e1000e_pm_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + e1000e_pm_freeze(dev); + return __e1000_shutdown(pdev, false); } -static int e1000_resume(struct device *dev) +static int e1000e_pm_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); - struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev_priv(netdev); + int rc; - if (e1000e_pm_ready(adapter)) - adapter->idle_check = true; + rc = __e1000_resume(pdev); + if (rc) + return rc; - return __e1000_resume(pdev); + return e1000e_pm_thaw(dev); } #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_RUNTIME -static int e1000_runtime_suspend(struct device *dev) +static int e1000e_pm_runtime_idle(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - if (!e1000e_pm_ready(adapter)) - return 0; + if (!e1000e_has_link(adapter)) + pm_schedule_suspend(dev, 5 * MSEC_PER_SEC); - return __e1000_shutdown(pdev, true); + return -EBUSY; } -static int e1000_idle(struct device *dev) +static int e1000e_pm_runtime_resume(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); + int rc; - if (!e1000e_pm_ready(adapter)) - return 0; + rc = __e1000_resume(pdev); + if (rc) + return rc; - if (adapter->idle_check) { - adapter->idle_check = false; - if (!e1000e_has_link(adapter)) - pm_schedule_suspend(dev, MSEC_PER_SEC); - } + if (netdev->flags & IFF_UP) + rc = e1000e_up(adapter); - return -EBUSY; + return rc; } -static int e1000_runtime_resume(struct device *dev) +static int e1000e_pm_runtime_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); - if (!e1000e_pm_ready(adapter)) - return 0; + if (netdev->flags & IFF_UP) { + int count = E1000_CHECK_RESET_COUNT; + + while (test_bit(__E1000_RESETTING, &adapter->state) && count--) + usleep_range(10000, 20000); + + WARN_ON(test_bit(__E1000_RESETTING, &adapter->state)); + + /* Down the device without resetting the hardware */ + e1000e_down(adapter, false); + } - adapter->idle_check = !dev->power.runtime_auto; - return __e1000_resume(pdev); + if (__e1000_shutdown(pdev, true)) { + e1000e_pm_runtime_resume(dev); + return -EBUSY; + } + + return 0; } #endif /* CONFIG_PM_RUNTIME */ #endif /* CONFIG_PM */ static void e1000_shutdown(struct pci_dev *pdev) { + e1000e_pm_freeze(&pdev->dev); + __e1000_shutdown(pdev, false); } @@ -6338,7 +6391,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, return PCI_ERS_RESULT_DISCONNECT; if (netif_running(netdev)) - e1000e_down(adapter); + e1000e_down(adapter, true); pci_disable_device(pdev); /* Request a slot slot reset. */ @@ -6350,7 +6403,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, * @pdev: Pointer to PCI device * * Restart the card from scratch, as if from a cold-boot. Implementation - * resembles the first-half of the e1000_resume routine. + * resembles the first-half of the e1000e_pm_resume routine. */ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) { @@ -6397,7 +6450,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) * * This callback is called when the error recovery driver tells us that * its OK to resume normal operation. Implementation resembles the - * second-half of the e1000_resume routine. + * second-half of the e1000e_pm_resume routine. */ static void e1000_io_resume(struct pci_dev *pdev) { @@ -6902,9 +6955,6 @@ static void e1000_remove(struct pci_dev *pdev) } } - if (!(netdev->flags & IFF_UP)) - e1000_power_down_phy(adapter); - /* Don't lie to e1000_close() down the road. */ if (!down) clear_bit(__E1000_DOWN, &adapter->state); @@ -7026,9 +7076,14 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = { MODULE_DEVICE_TABLE(pci, e1000_pci_tbl); static const struct dev_pm_ops e1000_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(e1000_suspend, e1000_resume) - SET_RUNTIME_PM_OPS(e1000_runtime_suspend, e1000_runtime_resume, - e1000_idle) + .suspend = e1000e_pm_suspend, + .resume = e1000e_pm_resume, + .freeze = e1000e_pm_freeze, + .thaw = e1000e_pm_thaw, + .poweroff = e1000e_pm_suspend, + .restore = e1000e_pm_resume, + SET_RUNTIME_PM_OPS(e1000e_pm_runtime_suspend, e1000e_pm_runtime_resume, + e1000e_pm_runtime_idle) }; /* PCI Device API Driver */ @@ -7055,7 +7110,7 @@ static int __init e1000_init_module(void) int ret; pr_info("Intel(R) PRO/1000 Network Driver - %s\n", e1000e_driver_version); - pr_info("Copyright(c) 1999 - 2013 Intel Corporation.\n"); + pr_info("Copyright(c) 1999 - 2014 Intel Corporation.\n"); ret = pci_register_driver(&e1000_driver); return ret; diff --git a/drivers/net/ethernet/intel/e1000e/nvm.c b/drivers/net/ethernet/intel/e1000e/nvm.c index d70a03906ac0..a9a976f04bff 100644 --- a/drivers/net/ethernet/intel/e1000e/nvm.c +++ b/drivers/net/ethernet/intel/e1000e/nvm.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/nvm.h b/drivers/net/ethernet/intel/e1000e/nvm.h index 45fc69561627..342bf69efab5 100644 --- a/drivers/net/ethernet/intel/e1000e/nvm.h +++ b/drivers/net/ethernet/intel/e1000e/nvm.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_NVM_H_ #define _E1000E_NVM_H_ diff --git a/drivers/net/ethernet/intel/e1000e/param.c b/drivers/net/ethernet/intel/e1000e/param.c index c16bd75b6caa..d0ac0f3249c8 100644 --- a/drivers/net/ethernet/intel/e1000e/param.c +++ b/drivers/net/ethernet/intel/e1000e/param.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include <linux/netdevice.h> #include <linux/module.h> @@ -381,6 +374,12 @@ void e1000e_check_options(struct e1000_adapter *adapter) "%s set to dynamic mode\n", opt.name); adapter->itr = 20000; break; + case 2: + dev_info(&adapter->pdev->dev, + "%s Invalid mode - setting default\n", + opt.name); + adapter->itr_setting = opt.def; + /* fall-through */ case 3: dev_info(&adapter->pdev->dev, "%s set to dynamic conservative mode\n", diff --git a/drivers/net/ethernet/intel/e1000e/phy.c b/drivers/net/ethernet/intel/e1000e/phy.c index 20e71f4ca426..00b3fc98bf30 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.c +++ b/drivers/net/ethernet/intel/e1000e/phy.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #include "e1000.h" diff --git a/drivers/net/ethernet/intel/e1000e/phy.h b/drivers/net/ethernet/intel/e1000e/phy.h index f4f71b9991e3..3841bccf058c 100644 --- a/drivers/net/ethernet/intel/e1000e/phy.h +++ b/drivers/net/ethernet/intel/e1000e/phy.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_PHY_H_ #define _E1000E_PHY_H_ diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c index 065f8c80d4f2..3bd79a3ff829 100644 --- a/drivers/net/ethernet/intel/e1000e/ptp.c +++ b/drivers/net/ethernet/intel/e1000e/ptp.c @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ /* PTP 1588 Hardware Clock (PHC) * Derived from PTP Hardware Clock driver for Intel 82576 and 82580 (igb) @@ -47,6 +40,7 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) ptp_clock_info); struct e1000_hw *hw = &adapter->hw; bool neg_adj = false; + unsigned long flags; u64 adjustment; u32 timinca, incvalue; s32 ret_val; @@ -64,6 +58,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) if (ret_val) return ret_val; + spin_lock_irqsave(&adapter->systim_lock, flags); + incvalue = timinca & E1000_TIMINCA_INCVALUE_MASK; adjustment = incvalue; @@ -77,6 +73,8 @@ static int e1000e_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) ew32(TIMINCA, timinca); + spin_unlock_irqrestore(&adapter->systim_lock, flags); + return 0; } diff --git a/drivers/net/ethernet/intel/e1000e/regs.h b/drivers/net/ethernet/intel/e1000e/regs.h index a7e6a3e37257..ea235bbe50d3 100644 --- a/drivers/net/ethernet/intel/e1000e/regs.h +++ b/drivers/net/ethernet/intel/e1000e/regs.h @@ -1,30 +1,23 @@ -/******************************************************************************* - - Intel PRO/1000 Linux driver - Copyright(c) 1999 - 2013 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, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - - The full GNU General Public License is included in this distribution in - the file called "COPYING". - - Contact Information: - Linux NICS <linux.nics@intel.com> - e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> - Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 - -*******************************************************************************/ +/* Intel PRO/1000 Linux driver + * Copyright(c) 1999 - 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. + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + * Contact Information: + * Linux NICS <linux.nics@intel.com> + * e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + */ #ifndef _E1000E_REGS_H_ #define _E1000E_REGS_H_ @@ -39,6 +32,7 @@ #define E1000_SCTL 0x00024 /* SerDes Control - RW */ #define E1000_FCAL 0x00028 /* Flow Control Address Low - RW */ #define E1000_FCAH 0x0002C /* Flow Control Address High -RW */ +#define E1000_FEXT 0x0002C /* Future Extended - RW */ #define E1000_FEXTNVM 0x00028 /* Future Extended NVM - RW */ #define E1000_FEXTNVM3 0x0003C /* Future Extended NVM 3 - RW */ #define E1000_FEXTNVM4 0x00024 /* Future Extended NVM 4 - RW */ diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 72dae4d97b43..838b69b74edf 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -86,12 +86,12 @@ #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) -#define I40E_NVM_VERSION_HI_SHIFT 8 -#define I40E_NVM_VERSION_HI_MASK (0xff << I40E_NVM_VERSION_HI_SHIFT) +#define I40E_NVM_VERSION_HI_SHIFT 12 +#define I40E_NVM_VERSION_HI_MASK (0xf << I40E_NVM_VERSION_HI_SHIFT) /* 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 0x30 +#define I40E_CURRENT_NVM_VERSION_LO 0x40 /* magic for getting defines into strings */ #define STRINGIFY(foo) #foo @@ -152,8 +152,18 @@ struct i40e_lump_tracking { }; #define I40E_DEFAULT_ATR_SAMPLE_RATE 20 -#define I40E_FDIR_MAX_RAW_PACKET_LOOKUP 512 -struct i40e_fdir_data { +#define I40E_FDIR_MAX_RAW_PACKET_SIZE 512 +struct i40e_fdir_filter { + struct hlist_node fdir_node; + /* filter ipnut set */ + u8 flow_type; + u8 ip4_proto; + __be32 dst_ip[4]; + __be32 src_ip[4]; + __be16 src_port; + __be16 dst_port; + __be32 sctp_v_tag; + /* filter control */ u16 q_index; u8 flex_off; u8 pctype; @@ -162,7 +172,6 @@ struct i40e_fdir_data { u8 fd_status; u16 cnt_index; u32 fd_id; - u8 *raw_packet; }; #define I40E_ETH_P_LLDP 0x88cc @@ -210,6 +219,9 @@ struct i40e_pf { u8 atr_sample_rate; bool wol_en; + struct hlist_head fdir_filter_list; + u16 fdir_pf_active_filters; + #ifdef CONFIG_I40E_VXLAN __be16 vxlan_ports[I40E_MAX_PF_UDP_OFFLOAD_PORTS]; u16 pending_vxlan_bitmap; @@ -477,10 +489,10 @@ static inline char *i40e_fw_version_str(struct i40e_hw *hw) "f%d.%d a%d.%d n%02x.%02x e%08x", hw->aq.fw_maj_ver, hw->aq.fw_min_ver, hw->aq.api_maj_ver, hw->aq.api_min_ver, - (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) - >> I40E_NVM_VERSION_HI_SHIFT, - (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) - >> I40E_NVM_VERSION_LO_SHIFT, + (hw->nvm.version & I40E_NVM_VERSION_HI_MASK) >> + I40E_NVM_VERSION_HI_SHIFT, + (hw->nvm.version & I40E_NVM_VERSION_LO_MASK) >> + I40E_NVM_VERSION_LO_SHIFT, hw->nvm.eetrack); return buf; @@ -534,9 +546,10 @@ struct rtnl_link_stats64 *i40e_get_vsi_stats_struct(struct i40e_vsi *vsi); int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig); -int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, +int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add); - +int i40e_add_del_fdir(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input, bool add); void i40e_set_ethtool_ops(struct net_device *netdev); struct i40e_mac_filter *i40e_add_filter(struct i40e_vsi *vsi, u8 *macaddr, s16 vlan, diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.c b/drivers/net/ethernet/intel/i40e/i40e_adminq.c index a50e6b3479ae..ed3902bf249b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.c @@ -647,9 +647,8 @@ static u16 i40e_clean_asq(struct i40e_hw *hw) desc_cb = *desc; cb_func(hw, &desc_cb); } - memset((void *)desc, 0, sizeof(struct i40e_aq_desc)); - memset((void *)details, 0, - sizeof(struct i40e_asq_cmd_details)); + memset(desc, 0, sizeof(*desc)); + memset(details, 0, sizeof(*details)); ntc++; if (ntc == asq->count) ntc = 0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index e7f38b57834d..bb948dd92474 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -162,6 +162,372 @@ i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, return status; } +/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the + * hardware to a bit-field that can be used by SW to more easily determine the + * packet type. + * + * Macros are used to shorten the table lines and make this table human + * readable. + * + * We store the PTYPE in the top byte of the bit field - this is just so that + * we can check that the table doesn't have a row missing, as the index into + * the table should be the PTYPE. + * + * Typical work flow: + * + * IF NOT i40e_ptype_lookup[ptype].known + * THEN + * Packet is unknown + * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP + * Use the rest of the fields to look at the tunnels, inner protocols, etc + * ELSE + * Use the enum i40e_rx_l2_ptype to decode the packet type + * ENDIF + */ + +/* macro to make the table lines short */ +#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ + { PTYPE, \ + 1, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \ + I40E_RX_PTYPE_##OUTER_FRAG, \ + I40E_RX_PTYPE_TUNNEL_##T, \ + I40E_RX_PTYPE_TUNNEL_END_##TE, \ + I40E_RX_PTYPE_##TEF, \ + I40E_RX_PTYPE_INNER_PROT_##I, \ + I40E_RX_PTYPE_PAYLOAD_LAYER_##PL } + +#define I40E_PTT_UNUSED_ENTRY(PTYPE) \ + { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +/* shorter macros makes the table fit but are terse */ +#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG +#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG +#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC + +/* Lookup table mapping the HW PTYPE to the bit field for decoding */ +struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = { + /* L2 Packet types */ + I40E_PTT_UNUSED_ENTRY(0), + I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2), + I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(4), + I40E_PTT_UNUSED_ENTRY(5), + I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(8), + I40E_PTT_UNUSED_ENTRY(9), + I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), + I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + + /* Non Tunneled IPv4 */ + I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(25), + I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv4 --> IPv4 */ + I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(32), + I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> IPv6 */ + I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(39), + I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT */ + I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> IPv4 */ + I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(47), + I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> IPv6 */ + I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(54), + I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC */ + I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> MAC --> IPv4 */ + I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(62), + I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT -> MAC --> IPv6 */ + I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(69), + I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC/VLAN */ + I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(77), + I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(84), + I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* Non Tunneled IPv6 */ + I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3), + I40E_PTT_UNUSED_ENTRY(91), + I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv6 --> IPv4 */ + I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(98), + I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> IPv6 */ + I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(105), + I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT */ + I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> IPv4 */ + I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(113), + I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> IPv6 */ + I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(120), + I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC */ + I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC -> IPv4 */ + I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(128), + I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC -> IPv6 */ + I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(135), + I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN */ + I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(143), + I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(150), + I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* unused entries */ + I40E_PTT_UNUSED_ENTRY(154), + I40E_PTT_UNUSED_ENTRY(155), + I40E_PTT_UNUSED_ENTRY(156), + I40E_PTT_UNUSED_ENTRY(157), + I40E_PTT_UNUSED_ENTRY(158), + I40E_PTT_UNUSED_ENTRY(159), + + I40E_PTT_UNUSED_ENTRY(160), + I40E_PTT_UNUSED_ENTRY(161), + I40E_PTT_UNUSED_ENTRY(162), + I40E_PTT_UNUSED_ENTRY(163), + I40E_PTT_UNUSED_ENTRY(164), + I40E_PTT_UNUSED_ENTRY(165), + I40E_PTT_UNUSED_ENTRY(166), + I40E_PTT_UNUSED_ENTRY(167), + I40E_PTT_UNUSED_ENTRY(168), + I40E_PTT_UNUSED_ENTRY(169), + + I40E_PTT_UNUSED_ENTRY(170), + I40E_PTT_UNUSED_ENTRY(171), + I40E_PTT_UNUSED_ENTRY(172), + I40E_PTT_UNUSED_ENTRY(173), + I40E_PTT_UNUSED_ENTRY(174), + I40E_PTT_UNUSED_ENTRY(175), + I40E_PTT_UNUSED_ENTRY(176), + I40E_PTT_UNUSED_ENTRY(177), + I40E_PTT_UNUSED_ENTRY(178), + I40E_PTT_UNUSED_ENTRY(179), + + I40E_PTT_UNUSED_ENTRY(180), + I40E_PTT_UNUSED_ENTRY(181), + I40E_PTT_UNUSED_ENTRY(182), + I40E_PTT_UNUSED_ENTRY(183), + I40E_PTT_UNUSED_ENTRY(184), + I40E_PTT_UNUSED_ENTRY(185), + I40E_PTT_UNUSED_ENTRY(186), + I40E_PTT_UNUSED_ENTRY(187), + I40E_PTT_UNUSED_ENTRY(188), + I40E_PTT_UNUSED_ENTRY(189), + + I40E_PTT_UNUSED_ENTRY(190), + I40E_PTT_UNUSED_ENTRY(191), + I40E_PTT_UNUSED_ENTRY(192), + I40E_PTT_UNUSED_ENTRY(193), + I40E_PTT_UNUSED_ENTRY(194), + I40E_PTT_UNUSED_ENTRY(195), + I40E_PTT_UNUSED_ENTRY(196), + I40E_PTT_UNUSED_ENTRY(197), + I40E_PTT_UNUSED_ENTRY(198), + I40E_PTT_UNUSED_ENTRY(199), + + I40E_PTT_UNUSED_ENTRY(200), + I40E_PTT_UNUSED_ENTRY(201), + I40E_PTT_UNUSED_ENTRY(202), + I40E_PTT_UNUSED_ENTRY(203), + I40E_PTT_UNUSED_ENTRY(204), + I40E_PTT_UNUSED_ENTRY(205), + I40E_PTT_UNUSED_ENTRY(206), + I40E_PTT_UNUSED_ENTRY(207), + I40E_PTT_UNUSED_ENTRY(208), + I40E_PTT_UNUSED_ENTRY(209), + + I40E_PTT_UNUSED_ENTRY(210), + I40E_PTT_UNUSED_ENTRY(211), + I40E_PTT_UNUSED_ENTRY(212), + I40E_PTT_UNUSED_ENTRY(213), + I40E_PTT_UNUSED_ENTRY(214), + I40E_PTT_UNUSED_ENTRY(215), + I40E_PTT_UNUSED_ENTRY(216), + I40E_PTT_UNUSED_ENTRY(217), + I40E_PTT_UNUSED_ENTRY(218), + I40E_PTT_UNUSED_ENTRY(219), + + I40E_PTT_UNUSED_ENTRY(220), + I40E_PTT_UNUSED_ENTRY(221), + I40E_PTT_UNUSED_ENTRY(222), + I40E_PTT_UNUSED_ENTRY(223), + I40E_PTT_UNUSED_ENTRY(224), + I40E_PTT_UNUSED_ENTRY(225), + I40E_PTT_UNUSED_ENTRY(226), + I40E_PTT_UNUSED_ENTRY(227), + I40E_PTT_UNUSED_ENTRY(228), + I40E_PTT_UNUSED_ENTRY(229), + + I40E_PTT_UNUSED_ENTRY(230), + I40E_PTT_UNUSED_ENTRY(231), + I40E_PTT_UNUSED_ENTRY(232), + I40E_PTT_UNUSED_ENTRY(233), + I40E_PTT_UNUSED_ENTRY(234), + I40E_PTT_UNUSED_ENTRY(235), + I40E_PTT_UNUSED_ENTRY(236), + I40E_PTT_UNUSED_ENTRY(237), + I40E_PTT_UNUSED_ENTRY(238), + I40E_PTT_UNUSED_ENTRY(239), + + I40E_PTT_UNUSED_ENTRY(240), + I40E_PTT_UNUSED_ENTRY(241), + I40E_PTT_UNUSED_ENTRY(242), + I40E_PTT_UNUSED_ENTRY(243), + I40E_PTT_UNUSED_ENTRY(244), + I40E_PTT_UNUSED_ENTRY(245), + I40E_PTT_UNUSED_ENTRY(246), + I40E_PTT_UNUSED_ENTRY(247), + I40E_PTT_UNUSED_ENTRY(248), + I40E_PTT_UNUSED_ENTRY(249), + + I40E_PTT_UNUSED_ENTRY(250), + I40E_PTT_UNUSED_ENTRY(251), + I40E_PTT_UNUSED_ENTRY(252), + I40E_PTT_UNUSED_ENTRY(253), + I40E_PTT_UNUSED_ENTRY(254), + I40E_PTT_UNUSED_ENTRY(255) +}; + + /** * i40e_init_shared_code - Initialize the shared code * @hw: pointer to hardware structure diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 50730141bb7b..036570d76176 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -332,6 +332,7 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib, u16 type; u16 length; u16 typelength; + u16 offset = 0; if (!lldpmib || !dcbcfg) return I40E_ERR_PARAM; @@ -339,15 +340,17 @@ i40e_status i40e_lldp_to_dcb_config(u8 *lldpmib, /* set to the start of LLDPDU */ lldpmib += ETH_HLEN; tlv = (struct i40e_lldp_org_tlv *)lldpmib; - while (tlv) { + while (1) { typelength = ntohs(tlv->typelength); type = (u16)((typelength & I40E_LLDP_TLV_TYPE_MASK) >> I40E_LLDP_TLV_TYPE_SHIFT); length = (u16)((typelength & I40E_LLDP_TLV_LEN_MASK) >> I40E_LLDP_TLV_LEN_SHIFT); + offset += sizeof(typelength) + length; - if (type == I40E_TLV_TYPE_END) - break;/* END TLV break out */ + /* END TLV or beyond LLDPDU size */ + if ((type == I40E_TLV_TYPE_END) || (offset > I40E_LLDPDU_SIZE)) + break; switch (type) { case I40E_TLV_TYPE_ORG: diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index da22c3fa2c00..57fc86496f30 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -1663,21 +1663,22 @@ static ssize_t i40e_dbg_command_write(struct file *filp, desc = NULL; } else if ((strncmp(cmd_buf, "add fd_filter", 13) == 0) || (strncmp(cmd_buf, "rem fd_filter", 13) == 0)) { - struct i40e_fdir_data fd_data; + struct i40e_fdir_filter fd_data; u16 packet_len, i, j = 0; char *asc_packet; + u8 *raw_packet; bool add = false; int ret; - asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP, + asc_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); if (!asc_packet) goto command_write_done; - fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP, - GFP_KERNEL); + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, + GFP_KERNEL); - if (!fd_data.raw_packet) { + if (!raw_packet) { kfree(asc_packet); asc_packet = NULL; goto command_write_done; @@ -1698,36 +1699,36 @@ static ssize_t i40e_dbg_command_write(struct file *filp, cnt); kfree(asc_packet); asc_packet = NULL; - kfree(fd_data.raw_packet); + kfree(raw_packet); goto command_write_done; } /* fix packet length if user entered 0 */ if (packet_len == 0) - packet_len = I40E_FDIR_MAX_RAW_PACKET_LOOKUP; + packet_len = I40E_FDIR_MAX_RAW_PACKET_SIZE; /* make sure to check the max as well */ packet_len = min_t(u16, - packet_len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP); + packet_len, I40E_FDIR_MAX_RAW_PACKET_SIZE); for (i = 0; i < packet_len; i++) { sscanf(&asc_packet[j], "%2hhx ", - &fd_data.raw_packet[i]); + &raw_packet[i]); j += 3; } dev_info(&pf->pdev->dev, "FD raw packet dump\n"); print_hex_dump(KERN_INFO, "FD raw packet: ", DUMP_PREFIX_OFFSET, 16, 1, - fd_data.raw_packet, packet_len, true); - ret = i40e_program_fdir_filter(&fd_data, pf, add); + raw_packet, packet_len, true); + ret = i40e_program_fdir_filter(&fd_data, raw_packet, pf, add); if (!ret) { dev_info(&pf->pdev->dev, "Filter command send Status : Success\n"); } else { dev_info(&pf->pdev->dev, "Filter command send failed %d\n", ret); } - kfree(fd_data.raw_packet); - fd_data.raw_packet = NULL; + kfree(raw_packet); + raw_packet = NULL; kfree(asc_packet); asc_packet = NULL; } else if (strncmp(cmd_buf, "fd-atr off", 10) == 0) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index b1d7d8c5cb9b..d34ff31fddd8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -62,6 +62,9 @@ static const struct i40e_stats i40e_gstrings_net_stats[] = { I40E_NETDEV_STAT(rx_crc_errors), }; +static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi, + struct ethtool_rxnfc *cmd, bool add); + /* These PF_STATs might look like duplicates of some NETDEV_STATs, * but they are separate. This device supports Virtualization, and * as such might have several netdevs supporting VMDq and FCoE going @@ -84,6 +87,7 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("illegal_bytes", stats.illegal_bytes), I40E_PF_STAT("mac_local_faults", stats.mac_local_faults), I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults), + I40E_PF_STAT("tx_timeout", tx_timeout_count), I40E_PF_STAT("rx_length_errors", stats.rx_length_errors), I40E_PF_STAT("link_xon_rx", stats.link_xon_rx), I40E_PF_STAT("link_xoff_rx", stats.link_xoff_rx), @@ -1112,6 +1116,84 @@ static int i40e_get_rss_hash_opts(struct i40e_pf *pf, struct ethtool_rxnfc *cmd) } /** + * i40e_get_ethtool_fdir_all - Populates the rule count of a command + * @pf: Pointer to the physical function struct + * @cmd: The command to get or set Rx flow classification rules + * @rule_locs: Array of used rule locations + * + * This function populates both the total and actual rule count of + * the ethtool flow classification command + * + * Returns 0 on success or -EMSGSIZE if entry not found + **/ +static int i40e_get_ethtool_fdir_all(struct i40e_pf *pf, + struct ethtool_rxnfc *cmd, + u32 *rule_locs) +{ + struct i40e_fdir_filter *rule; + struct hlist_node *node2; + int cnt = 0; + + /* report total rule count */ + cmd->data = pf->hw.fdir_shared_filter_count + + pf->fdir_pf_filter_count; + + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + if (cnt == cmd->rule_cnt) + return -EMSGSIZE; + + rule_locs[cnt] = rule->fd_id; + cnt++; + } + + cmd->rule_cnt = cnt; + + return 0; +} + +/** + * i40e_get_ethtool_fdir_entry - Look up a filter based on Rx flow + * @pf: Pointer to the physical function struct + * @cmd: The command to get or set Rx flow classification rules + * + * This function looks up a filter based on the Rx flow classification + * command and fills the flow spec info for it if found + * + * Returns 0 on success or -EINVAL if filter not found + **/ +static int i40e_get_ethtool_fdir_entry(struct i40e_pf *pf, + struct ethtool_rxnfc *cmd) +{ + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; + struct i40e_fdir_filter *rule = NULL; + struct hlist_node *node2; + + /* report total rule count */ + cmd->data = pf->hw.fdir_shared_filter_count + + pf->fdir_pf_filter_count; + + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + if (fsp->location <= rule->fd_id) + break; + } + + if (!rule || fsp->location != rule->fd_id) + return -EINVAL; + + fsp->flow_type = rule->flow_type; + fsp->h_u.tcp_ip4_spec.psrc = rule->src_port; + fsp->h_u.tcp_ip4_spec.pdst = rule->dst_port; + fsp->h_u.tcp_ip4_spec.ip4src = rule->src_ip[0]; + fsp->h_u.tcp_ip4_spec.ip4dst = rule->dst_ip[0]; + fsp->ring_cookie = rule->q_index; + + return 0; +} + +/** * i40e_get_rxnfc - command to get RX flow classification rules * @netdev: network interface device structure * @cmd: ethtool rxnfc command @@ -1135,15 +1217,15 @@ static int i40e_get_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd, ret = i40e_get_rss_hash_opts(pf, cmd); break; case ETHTOOL_GRXCLSRLCNT: - cmd->rule_cnt = 10; + cmd->rule_cnt = pf->fdir_pf_active_filters; ret = 0; break; case ETHTOOL_GRXCLSRULE: - ret = 0; + ret = i40e_get_ethtool_fdir_entry(pf, cmd); break; case ETHTOOL_GRXCLSRLALL: - cmd->data = 500; - ret = 0; + ret = i40e_get_ethtool_fdir_all(pf, cmd, rule_locs); + break; default: break; } @@ -1274,289 +1356,158 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) return 0; } -#define IP_HEADER_OFFSET 14 -#define I40E_UDPIP_DUMMY_PACKET_LEN 42 /** - * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required from the FDir descriptor - * @ethtool_rx_flow_spec: the flow spec - * @add: true adds a filter, false removes it + * i40e_update_ethtool_fdir_entry - Updates the fdir filter entry + * @vsi: Pointer to the targeted VSI + * @input: The filter to update or NULL to indicate deletion + * @sw_idx: Software index to the filter + * @cmd: The command to get or set Rx flow classification rules * - * Returns 0 if the filters were successfully added or removed + * This function updates (or deletes) a Flow Director entry from + * the hlist of the corresponding PF + * + * Returns 0 on success **/ -static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) +static int i40e_update_ethtool_fdir_entry(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input, + u16 sw_idx, + struct ethtool_rxnfc *cmd) { + struct i40e_fdir_filter *rule, *parent; struct i40e_pf *pf = vsi->back; - struct udphdr *udp; - struct iphdr *ip; - bool err = false; - int ret; - int i; - char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, - 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; - - memcpy(fd_data->raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN); - - ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET); - udp = (struct udphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET - + sizeof(struct iphdr)); + struct hlist_node *node2; + int err = -EINVAL; - ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src; - ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst; - udp->source = fsp->h_u.tcp_ip4_spec.psrc; - udp->dest = fsp->h_u.tcp_ip4_spec.pdst; + parent = NULL; + rule = NULL; - for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP; - i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) { - fd_data->pctype = i; - ret = i40e_program_fdir_filter(fd_data, pf, add); - - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, - "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } + hlist_for_each_entry_safe(rule, node2, + &pf->fdir_filter_list, fdir_node) { + /* hash found, or no matching entry */ + if (rule->fd_id >= sw_idx) + break; + parent = rule; } - return err ? -EOPNOTSUPP : 0; -} - -#define I40E_TCPIP_DUMMY_PACKET_LEN 54 -/** - * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required from the FDir descriptor - * @ethtool_rx_flow_spec: the flow spec - * @add: true adds a filter, false removes it - * - * Returns 0 if the filters were successfully added or removed - **/ -static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) -{ - struct i40e_pf *pf = vsi->back; - struct tcphdr *tcp; - struct iphdr *ip; - bool err = false; - int ret; - /* Dummy packet */ - char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, - 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0x80, 0x11, 0x0, 0x72, 0, 0, 0, 0}; - - memcpy(fd_data->raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN); - - ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET); - tcp = (struct tcphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET - + sizeof(struct iphdr)); - - ip->daddr = fsp->h_u.tcp_ip4_spec.ip4dst; - tcp->dest = fsp->h_u.tcp_ip4_spec.pdst; - ip->saddr = fsp->h_u.tcp_ip4_spec.ip4src; - tcp->source = fsp->h_u.tcp_ip4_spec.psrc; - - if (add) { - if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) { - dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); - pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + /* if there is an old rule occupying our place remove it */ + if (rule && (rule->fd_id == sw_idx)) { + if (!input || (rule->fd_id != input->fd_id)) { + cmd->fs.flow_type = rule->flow_type; + err = i40e_add_del_fdir_ethtool(vsi, cmd, false); } + + hlist_del(&rule->fdir_node); + kfree(rule); + pf->fdir_pf_active_filters--; } - fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN; - ret = i40e_program_fdir_filter(fd_data, pf, add); + /* If no input this was a delete, err should be 0 if a rule was + * successfully found and removed from the list else -EINVAL + */ + if (!input) + return err; - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } + /* initialize node and set software index */ + INIT_HLIST_NODE(&input->fdir_node); - fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; + /* add filter to the list */ + if (parent) + hlist_add_after(&parent->fdir_node, &input->fdir_node); + else + hlist_add_head(&input->fdir_node, + &pf->fdir_filter_list); - ret = i40e_program_fdir_filter(fd_data, pf, add); - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } + /* update counts */ + pf->fdir_pf_active_filters++; - return err ? -EOPNOTSUPP : 0; + return 0; } /** - * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required from the FDir descriptor - * @ethtool_rx_flow_spec: the flow spec - * @add: true adds a filter, false removes it + * i40e_del_fdir_entry - Deletes a Flow Director filter entry + * @vsi: Pointer to the targeted VSI + * @cmd: The command to get or set Rx flow classification rules * - * Returns 0 if the filters were successfully added or removed - **/ -static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) -{ - return -EOPNOTSUPP; -} - -#define I40E_IP_DUMMY_PACKET_LEN 34 -/** - * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for - * a specific flow spec - * @vsi: pointer to the targeted VSI - * @fd_data: the flow director data required for the FDir descriptor - * @fsp: the ethtool flow spec - * @add: true adds a filter, false removes it + * The function removes a Flow Director filter entry from the + * hlist of the corresponding PF * - * Returns 0 if the filters were successfully added or removed - **/ -static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, - struct i40e_fdir_data *fd_data, - struct ethtool_rx_flow_spec *fsp, bool add) + * Returns 0 on success + */ +static int i40e_del_fdir_entry(struct i40e_vsi *vsi, + struct ethtool_rxnfc *cmd) { + struct ethtool_rx_flow_spec *fsp = + (struct ethtool_rx_flow_spec *)&cmd->fs; struct i40e_pf *pf = vsi->back; - struct iphdr *ip; - bool err = false; - int ret; - int i; - char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, - 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + int ret = 0; - memcpy(fd_data->raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); - ip = (struct iphdr *)(fd_data->raw_packet + IP_HEADER_OFFSET); - - ip->saddr = fsp->h_u.usr_ip4_spec.ip4src; - ip->daddr = fsp->h_u.usr_ip4_spec.ip4dst; - ip->protocol = fsp->h_u.usr_ip4_spec.proto; - - for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; - i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) { - fd_data->pctype = i; - ret = i40e_program_fdir_filter(fd_data, pf, add); - - if (ret) { - dev_info(&pf->pdev->dev, - "Filter command send failed for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - err = true; - } else { - dev_info(&pf->pdev->dev, - "Filter OK for PCTYPE %d (ret = %d)\n", - fd_data->pctype, ret); - } - } + ret = i40e_update_ethtool_fdir_entry(vsi, NULL, fsp->location, cmd); - return err ? -EOPNOTSUPP : 0; + return ret; } /** - * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters for - * a specific flow spec based on their protocol + * i40e_add_del_fdir_ethtool - Add/Remove Flow Director filters * @vsi: pointer to the targeted VSI * @cmd: command to get or set RX flow classification rules * @add: true adds a filter, false removes it * - * Returns 0 if the filters were successfully added or removed + * Add/Remove Flow Director filters for a specific flow spec based on their + * protocol. Returns 0 if the filters were successfully added or removed. **/ static int i40e_add_del_fdir_ethtool(struct i40e_vsi *vsi, - struct ethtool_rxnfc *cmd, bool add) + struct ethtool_rxnfc *cmd, bool add) { - struct i40e_fdir_data fd_data; - int ret = -EINVAL; + struct ethtool_rx_flow_spec *fsp; + struct i40e_fdir_filter *input; struct i40e_pf *pf; - struct ethtool_rx_flow_spec *fsp = - (struct ethtool_rx_flow_spec *)&cmd->fs; + int ret = -EINVAL; if (!vsi) return -EINVAL; + fsp = (struct ethtool_rx_flow_spec *)&cmd->fs; pf = vsi->back; - if ((fsp->ring_cookie != RX_CLS_FLOW_DISC) && - (fsp->ring_cookie >= vsi->num_queue_pairs)) + if (fsp->location >= (pf->hw.func_caps.fd_filters_best_effort + + pf->hw.func_caps.fd_filters_guaranteed)) { return -EINVAL; + } - /* Populate the Flow Director that we have at the moment - * and allocate the raw packet buffer for the calling functions - */ - fd_data.raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_LOOKUP, - GFP_KERNEL); + if ((fsp->ring_cookie >= vsi->num_queue_pairs) && add) + return -EINVAL; - if (!fd_data.raw_packet) { - dev_info(&pf->pdev->dev, "Could not allocate memory\n"); - return -ENOMEM; - } + input = kzalloc(sizeof(*input), GFP_KERNEL); - fd_data.q_index = fsp->ring_cookie; - fd_data.flex_off = 0; - fd_data.pctype = 0; - fd_data.dest_vsi = vsi->id; - fd_data.dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; - fd_data.fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID; - fd_data.cnt_index = 0; - fd_data.fd_id = 0; + if (!input) + return -ENOMEM; - switch (fsp->flow_type & ~FLOW_EXT) { - case TCP_V4_FLOW: - ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add); - break; - case UDP_V4_FLOW: - ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add); - break; - case SCTP_V4_FLOW: - ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add); - break; - case IPV4_FLOW: - ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add); - break; - case IP_USER_FLOW: - switch (fsp->h_u.usr_ip4_spec.proto) { - case IPPROTO_TCP: - ret = i40e_add_del_fdir_tcpv4(vsi, &fd_data, fsp, add); - break; - case IPPROTO_UDP: - ret = i40e_add_del_fdir_udpv4(vsi, &fd_data, fsp, add); - break; - case IPPROTO_SCTP: - ret = i40e_add_del_fdir_sctpv4(vsi, &fd_data, fsp, add); - break; - default: - ret = i40e_add_del_fdir_ipv4(vsi, &fd_data, fsp, add); - break; - } - break; - default: - dev_info(&pf->pdev->dev, "Could not specify spec type\n"); - ret = -EINVAL; + input->fd_id = fsp->location; + + input->q_index = fsp->ring_cookie; + input->flex_off = 0; + input->pctype = 0; + input->dest_vsi = vsi->id; + input->dest_ctl = I40E_FILTER_PROGRAM_DESC_DEST_DIRECT_PACKET_QINDEX; + input->fd_status = I40E_FILTER_PROGRAM_DESC_FD_STATUS_FD_ID; + input->cnt_index = 0; + input->flow_type = fsp->flow_type; + input->ip4_proto = fsp->h_u.usr_ip4_spec.proto; + input->src_port = fsp->h_u.tcp_ip4_spec.psrc; + input->dst_port = fsp->h_u.tcp_ip4_spec.pdst; + input->src_ip[0] = fsp->h_u.tcp_ip4_spec.ip4src; + input->dst_ip[0] = fsp->h_u.tcp_ip4_spec.ip4dst; + + ret = i40e_add_del_fdir(vsi, input, add); + if (ret) { + kfree(input); + return ret; } - kfree(fd_data.raw_packet); - fd_data.raw_packet = NULL; + if (!ret && add) + i40e_update_ethtool_fdir_entry(vsi, input, fsp->location, NULL); + else + kfree(input); return ret; } @@ -1583,7 +1534,7 @@ static int i40e_set_rxnfc(struct net_device *netdev, struct ethtool_rxnfc *cmd) ret = i40e_add_del_fdir_ethtool(vsi, cmd, true); break; case ETHTOOL_SRXCLSRLDEL: - ret = i40e_add_del_fdir_ethtool(vsi, cmd, false); + ret = i40e_del_fdir_entry(vsi, cmd); break; default: break; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b901371ca361..43d391bb65c4 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 30 +#define DRV_VERSION_BUILD 34 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN @@ -305,6 +305,7 @@ static void i40e_tx_timeout(struct net_device *netdev) break; default: netdev_err(netdev, "tx_timeout recovery unsuccessful\n"); + set_bit(__I40E_DOWN, &vsi->state); i40e_down(vsi); break; } @@ -1964,11 +1965,14 @@ static int i40e_vlan_rx_add_vid(struct net_device *netdev, netdev_info(netdev, "adding %pM vid=%d\n", netdev->dev_addr, vid); - /* If the network stack called us with vid = 0, we should - * indicate to i40e_vsi_add_vlan() that we want to receive - * any traffic (i.e. with any vlan tag, or untagged) + /* If the network stack called us with vid = 0 then + * it is asking to receive priority tagged packets with + * vlan id 0. Our HW receives them by default when configured + * to receive untagged packets so there is no need to add an + * extra filter for vlan 0 tagged packets. */ - ret = i40e_vsi_add_vlan(vsi, vid ? vid : I40E_VLAN_ANY); + if (vid) + ret = i40e_vsi_add_vlan(vsi, vid); if (!ret && (vid < VLAN_N_VID)) set_bit(vid, vsi->active_vlans); @@ -2420,6 +2424,25 @@ static void i40e_set_vsi_rx_mode(struct i40e_vsi *vsi) } /** + * i40e_fdir_filter_restore - Restore the Sideband Flow Director filters + * @vsi: Pointer to the targeted VSI + * + * This function replays the hlist on the hw where all the SB Flow Director + * filters were saved. + **/ +static void i40e_fdir_filter_restore(struct i40e_vsi *vsi) +{ + struct i40e_fdir_filter *filter; + struct i40e_pf *pf = vsi->back; + struct hlist_node *node; + + hlist_for_each_entry_safe(filter, node, + &pf->fdir_filter_list, fdir_node) { + i40e_add_del_fdir(vsi, filter, true); + } +} + +/** * i40e_vsi_configure - Set up the VSI for action * @vsi: the VSI being configured **/ @@ -2430,6 +2453,8 @@ static int i40e_vsi_configure(struct i40e_vsi *vsi) i40e_set_vsi_rx_mode(vsi); i40e_restore_vlan(vsi); i40e_vsi_config_dcb_rings(vsi); + if (vsi->type == I40E_VSI_FDIR) + i40e_fdir_filter_restore(vsi); err = i40e_vsi_configure_tx(vsi); if (!err) err = i40e_vsi_configure_rx(vsi); @@ -3107,13 +3132,13 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) pf_q = vsi->base_queue; for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { - j = 1000; - do { - usleep_range(1000, 2000); + for (j = 0; j < 50; j++) { tx_reg = rd32(hw, I40E_QTX_ENA(pf_q)); - } while (j-- && ((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT) - ^ (tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT)) & 1); - + if (((tx_reg >> I40E_QTX_ENA_QENA_REQ_SHIFT) & 1) == + ((tx_reg >> I40E_QTX_ENA_QENA_STAT_SHIFT) & 1)) + break; + usleep_range(1000, 2000); + } /* Skip if the queue is already in the requested state */ if (enable && (tx_reg & I40E_QTX_ENA_QENA_STAT_MASK)) continue; @@ -3123,8 +3148,7 @@ static int i40e_vsi_control_tx(struct i40e_vsi *vsi, bool enable) /* turn on/off the queue */ if (enable) { wr32(hw, I40E_QTX_HEAD(pf_q), 0); - tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK | - I40E_QTX_ENA_QENA_STAT_MASK; + tx_reg |= I40E_QTX_ENA_QENA_REQ_MASK; } else { tx_reg &= ~I40E_QTX_ENA_QENA_REQ_MASK; } @@ -3171,12 +3195,13 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) pf_q = vsi->base_queue; for (i = 0; i < vsi->num_queue_pairs; i++, pf_q++) { - j = 1000; - do { - usleep_range(1000, 2000); + for (j = 0; j < 50; j++) { rx_reg = rd32(hw, I40E_QRX_ENA(pf_q)); - } while (j-- && ((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT) - ^ (rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT)) & 1); + if (((rx_reg >> I40E_QRX_ENA_QENA_REQ_SHIFT) & 1) == + ((rx_reg >> I40E_QRX_ENA_QENA_STAT_SHIFT) & 1)) + break; + usleep_range(1000, 2000); + } if (enable) { /* is STAT set ? */ @@ -3190,11 +3215,9 @@ static int i40e_vsi_control_rx(struct i40e_vsi *vsi, bool enable) /* turn on/off the queue */ if (enable) - rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK | - I40E_QRX_ENA_QENA_STAT_MASK; + rx_reg |= I40E_QRX_ENA_QENA_REQ_MASK; else - rx_reg &= ~(I40E_QRX_ENA_QENA_REQ_MASK | - I40E_QRX_ENA_QENA_STAT_MASK); + rx_reg &= ~I40E_QRX_ENA_QENA_REQ_MASK; wr32(hw, I40E_QRX_ENA(pf_q), rx_reg); /* wait for the change to finish */ @@ -4269,6 +4292,26 @@ err_setup_tx: } /** + * i40e_fdir_filter_exit - Cleans up the Flow Director accounting + * @pf: Pointer to pf + * + * This function destroys the hlist where all the Flow Director + * filters were saved. + **/ +static void i40e_fdir_filter_exit(struct i40e_pf *pf) +{ + struct i40e_fdir_filter *filter; + struct hlist_node *node2; + + hlist_for_each_entry_safe(filter, node2, + &pf->fdir_filter_list, fdir_node) { + hlist_del(&filter->fdir_node); + kfree(filter); + } + pf->fdir_pf_active_filters = 0; +} + +/** * i40e_close - Disables a network interface * @netdev: network interface device structure * @@ -5053,6 +5096,12 @@ static int i40e_get_capabilities(struct i40e_pf *pf) /* increment MSI-X count because current FW skips one */ pf->hw.func_caps.num_msix_vectors++; + if (((pf->hw.aq.fw_maj_ver == 2) && (pf->hw.aq.fw_min_ver < 22)) || + (pf->hw.aq.fw_maj_ver < 2)) { + pf->hw.func_caps.num_msix_vectors++; + pf->hw.func_caps.num_msix_vectors_vf++; + } + if (pf->hw.debug_mask & I40E_DEBUG_USER) dev_info(&pf->pdev->dev, "pf=%d, num_vfs=%d, msix_pf=%d, msix_vf=%d, fd_g=%d, fd_b=%d, pf_max_q=%d num_vsi=%d\n", @@ -5132,9 +5181,9 @@ static void i40e_fdir_sb_setup(struct i40e_pf *pf) err = i40e_up_complete(vsi); if (err) goto err_up_complete; + clear_bit(__I40E_NEEDS_RESTART, &vsi->state); } - clear_bit(__I40E_NEEDS_RESTART, &vsi->state); return; err_up_complete: @@ -5157,6 +5206,7 @@ static void i40e_fdir_teardown(struct i40e_pf *pf) { int i; + i40e_fdir_filter_exit(pf); for (i = 0; i < pf->hw.func_caps.num_vsis; i++) { if (pf->vsi[i] && pf->vsi[i]->type == I40E_VSI_FDIR) { i40e_vsi_release(pf->vsi[i]); @@ -5331,6 +5381,11 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) /* restart the VSIs that were rebuilt and running before the reset */ i40e_pf_unquiesce_all_vsi(pf); + if (pf->num_alloc_vfs) { + for (v = 0; v < pf->num_alloc_vfs; v++) + i40e_reset_vf(&pf->vf[v], true); + } + /* tell the firmware that we're starting */ dv.major_version = DRV_VERSION_MAJOR; dv.minor_version = DRV_VERSION_MINOR; @@ -5850,37 +5905,16 @@ err_out: **/ static int i40e_reserve_msix_vectors(struct i40e_pf *pf, int vectors) { - int err = 0; - - pf->num_msix_entries = 0; - while (vectors >= I40E_MIN_MSIX) { - err = pci_enable_msix(pf->pdev, pf->msix_entries, vectors); - if (err == 0) { - /* good to go */ - pf->num_msix_entries = vectors; - break; - } else if (err < 0) { - /* total failure */ - dev_info(&pf->pdev->dev, - "MSI-X vector reservation failed: %d\n", err); - vectors = 0; - break; - } else { - /* err > 0 is the hint for retry */ - dev_info(&pf->pdev->dev, - "MSI-X vectors wanted %d, retrying with %d\n", - vectors, err); - vectors = err; - } - } - - if (vectors > 0 && vectors < I40E_MIN_MSIX) { + vectors = pci_enable_msix_range(pf->pdev, pf->msix_entries, + I40E_MIN_MSIX, vectors); + if (vectors < 0) { dev_info(&pf->pdev->dev, - "Couldn't get enough vectors, only %d available\n", - vectors); + "MSI-X vector reservation failed: %d\n", vectors); vectors = 0; } + pf->num_msix_entries = vectors; + return vectors; } @@ -5942,7 +5976,7 @@ static int i40e_init_msix(struct i40e_pf *pf) } else if (vec == I40E_MIN_MSIX) { /* Adjust for minimal MSIX use */ - dev_info(&pf->pdev->dev, "Features disabled, not enough MSIX vectors\n"); + dev_info(&pf->pdev->dev, "Features disabled, not enough MSI-X vectors\n"); pf->flags &= ~I40E_FLAG_VMDQ_ENABLED; pf->num_vmdq_vsis = 0; pf->num_vmdq_qps = 0; @@ -6071,7 +6105,7 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf) if (!(pf->flags & I40E_FLAG_MSIX_ENABLED) && (pf->flags & I40E_FLAG_MSI_ENABLED)) { - dev_info(&pf->pdev->dev, "MSIX not available, trying MSI\n"); + dev_info(&pf->pdev->dev, "MSI-X not available, trying MSI\n"); err = pci_enable_msi(pf->pdev); if (err) { dev_info(&pf->pdev->dev, "MSI init failed - %d\n", err); @@ -6080,7 +6114,7 @@ static void i40e_init_interrupt_scheme(struct i40e_pf *pf) } if (!(pf->flags & (I40E_FLAG_MSIX_ENABLED | I40E_FLAG_MSI_ENABLED))) - dev_info(&pf->pdev->dev, "MSIX and MSI not available, falling back to Legacy IRQ\n"); + dev_info(&pf->pdev->dev, "MSI-X and MSI not available, falling back to Legacy IRQ\n"); /* track first vector for misc interrupts */ err = i40e_get_lump(pf, pf->irq_pile, 1, I40E_PILE_VALID_BIT-1); @@ -6107,7 +6141,8 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf) i40e_intr, 0, pf->misc_int_name, pf); if (err) { dev_info(&pf->pdev->dev, - "request_irq for msix_misc failed: %d\n", err); + "request_irq for %s failed: %d\n", + pf->misc_int_name, err); return -EFAULT; } } @@ -7946,13 +7981,6 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = i40e_init_adminq(hw); dev_info(&pdev->dev, "%s\n", i40e_fw_version_str(hw)); - if (((hw->nvm.version & I40E_NVM_VERSION_HI_MASK) - >> I40E_NVM_VERSION_HI_SHIFT) != I40E_CURRENT_NVM_VERSION_HI) { - dev_info(&pdev->dev, - "warning: NVM version not supported, supported version: %02x.%02x\n", - I40E_CURRENT_NVM_VERSION_HI, - I40E_CURRENT_NVM_VERSION_LO); - } if (err) { dev_info(&pdev->dev, "init_adminq failed: %d expecting API %02x.%02x\n", @@ -8070,6 +8098,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) val &= ~I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK; wr32(hw, I40E_PFGEN_PORTMDIO_NUM, val); i40e_flush(hw); + + if (pci_num_vf(pdev)) { + dev_info(&pdev->dev, + "Active VFs found, allocating resources.\n"); + err = i40e_alloc_vfs(pf, pci_num_vf(pdev)); + if (err) + dev_info(&pdev->dev, + "Error %d allocating resources for existing VFs\n", + err); + } } pfs_found++; @@ -8165,16 +8203,16 @@ static void i40e_remove(struct pci_dev *pdev) i40e_ptp_stop(pf); - if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { - i40e_free_vfs(pf); - pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; - } - /* no more scheduling of any task */ set_bit(__I40E_DOWN, &pf->state); del_timer_sync(&pf->service_timer); cancel_work_sync(&pf->service_task); + if (pf->flags & I40E_FLAG_SRIOV_ENABLED) { + i40e_free_vfs(pf); + pf->flags &= ~I40E_FLAG_SRIOV_ENABLED; + } + i40e_fdir_teardown(pf); /* If there is a switch structure or any orphans, remove them. diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 73f95b081927..262bdf11d221 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -27,14 +27,14 @@ #include "i40e_prototype.h" /** - * i40e_init_nvm_ops - Initialize NVM function pointers. - * @hw: pointer to the HW structure. + * i40e_init_nvm_ops - Initialize NVM function pointers + * @hw: pointer to the HW structure * - * Setups the function pointers and the NVM info structure. Should be called - * once per NVM initialization, e.g. inside the i40e_init_shared_code(). - * Please notice that the NVM term is used here (& in all methods covered - * in this file) as an equivalent of the FLASH part mapped into the SR. - * We are accessing FLASH always thru the Shadow RAM. + * Setup the function pointers and the NVM info structure. Should be called + * once per NVM initialization, e.g. inside the i40e_init_shared_code(). + * Please notice that the NVM term is used here (& in all methods covered + * in this file) as an equivalent of the FLASH part mapped into the SR. + * We are accessing FLASH always thru the Shadow RAM. **/ i40e_status i40e_init_nvm(struct i40e_hw *hw) { @@ -49,16 +49,16 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw) gens = rd32(hw, I40E_GLNVM_GENS); sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> I40E_GLNVM_GENS_SR_SIZE_SHIFT); - /* Switching to words (sr_size contains power of 2KB). */ + /* Switching to words (sr_size contains power of 2KB) */ nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; - /* Check if we are in the normal or blank NVM programming mode. */ + /* Check if we are in the normal or blank NVM programming mode */ fla = rd32(hw, I40E_GLNVM_FLA); - if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode. */ - /* Max NVM timeout. */ + if (fla & I40E_GLNVM_FLA_LOCKED_MASK) { /* Normal programming mode */ + /* Max NVM timeout */ nvm->timeout = I40E_MAX_NVM_TIMEOUT; nvm->blank_nvm_mode = false; - } else { /* Blank programming mode. */ + } else { /* Blank programming mode */ nvm->blank_nvm_mode = true; ret_code = I40E_ERR_NVM_BLANK_MODE; hw_dbg(hw, "NVM init error: unsupported blank mode.\n"); @@ -68,12 +68,12 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw) } /** - * i40e_acquire_nvm - Generic request for acquiring the NVM ownership. - * @hw: pointer to the HW structure. - * @access: NVM access type (read or write). + * i40e_acquire_nvm - Generic request for acquiring the NVM ownership + * @hw: pointer to the HW structure + * @access: NVM access type (read or write) * - * This function will request NVM ownership for reading - * via the proper Admin Command. + * This function will request NVM ownership for reading + * via the proper Admin Command. **/ i40e_status i40e_acquire_nvm(struct i40e_hw *hw, enum i40e_aq_resource_access_type access) @@ -87,20 +87,20 @@ i40e_status i40e_acquire_nvm(struct i40e_hw *hw, ret_code = i40e_aq_request_resource(hw, I40E_NVM_RESOURCE_ID, access, 0, &time, NULL); - /* Reading the Global Device Timer. */ + /* Reading the Global Device Timer */ gtime = rd32(hw, I40E_GLVFGEN_TIMER); - /* Store the timeout. */ + /* Store the timeout */ hw->nvm.hw_semaphore_timeout = I40E_MS_TO_GTIME(time) + gtime; if (ret_code) { - /* Set the polling timeout. */ + /* Set the polling timeout */ if (time > I40E_MAX_NVM_TIMEOUT) timeout = I40E_MS_TO_GTIME(I40E_MAX_NVM_TIMEOUT) + gtime; else timeout = hw->nvm.hw_semaphore_timeout; - /* Poll until the current NVM owner timeouts. */ + /* Poll until the current NVM owner timeouts */ while (gtime < timeout) { usleep_range(10000, 20000); ret_code = i40e_aq_request_resource(hw, @@ -128,10 +128,10 @@ i40e_i40e_acquire_nvm_exit: } /** - * i40e_release_nvm - Generic request for releasing the NVM ownership. - * @hw: pointer to the HW structure. + * i40e_release_nvm - Generic request for releasing the NVM ownership + * @hw: pointer to the HW structure * - * This function will release NVM resource via the proper Admin Command. + * This function will release NVM resource via the proper Admin Command. **/ void i40e_release_nvm(struct i40e_hw *hw) { @@ -140,17 +140,17 @@ void i40e_release_nvm(struct i40e_hw *hw) } /** - * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit. - * @hw: pointer to the HW structure. + * i40e_poll_sr_srctl_done_bit - Polls the GLNVM_SRCTL done bit + * @hw: pointer to the HW structure * - * Polls the SRCTL Shadow RAM register done bit. + * Polls the SRCTL Shadow RAM register done bit. **/ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) { i40e_status ret_code = I40E_ERR_TIMEOUT; u32 srctl, wait_cnt; - /* Poll the I40E_GLNVM_SRCTL until the done bit is set. */ + /* Poll the I40E_GLNVM_SRCTL until the done bit is set */ for (wait_cnt = 0; wait_cnt < I40E_SRRD_SRCTL_ATTEMPTS; wait_cnt++) { srctl = rd32(hw, I40E_GLNVM_SRCTL); if (srctl & I40E_GLNVM_SRCTL_DONE_MASK) { @@ -165,12 +165,12 @@ static i40e_status i40e_poll_sr_srctl_done_bit(struct i40e_hw *hw) } /** - * i40e_read_nvm_word - Reads Shadow RAM - * @hw: pointer to the HW structure. - * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). - * @data: word read from the Shadow RAM. + * i40e_read_nvm_word - Reads Shadow RAM + * @hw: pointer to the HW structure + * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF) + * @data: word read from the Shadow RAM * - * Reads 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. + * Reads one 16 bit word from the Shadow RAM using the GLNVM_SRCTL register. **/ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, u16 *data) @@ -184,15 +184,15 @@ i40e_status i40e_read_nvm_word(struct i40e_hw *hw, u16 offset, goto read_nvm_exit; } - /* Poll the done bit first. */ + /* Poll the done bit first */ ret_code = i40e_poll_sr_srctl_done_bit(hw); if (!ret_code) { - /* Write the address and start reading. */ + /* Write the address and start reading */ sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | (1 << I40E_GLNVM_SRCTL_START_SHIFT); wr32(hw, I40E_GLNVM_SRCTL, sr_reg); - /* Poll I40E_GLNVM_SRCTL until the done bit is set. */ + /* Poll I40E_GLNVM_SRCTL until the done bit is set */ ret_code = i40e_poll_sr_srctl_done_bit(hw); if (!ret_code) { sr_reg = rd32(hw, I40E_GLNVM_SRDATA); @@ -210,16 +210,15 @@ read_nvm_exit: } /** - * i40e_read_nvm_buffer - Reads Shadow RAM buffer. - * @hw: pointer to the HW structure. - * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). - * @words: number of words to read (in) & - * number of words read before the NVM ownership timeout (out). - * @data: words read from the Shadow RAM. + * i40e_read_nvm_buffer - Reads Shadow RAM buffer + * @hw: pointer to the HW structure + * @offset: offset of the Shadow RAM word to read (0x000000 - 0x001FFF). + * @words: (in) number of words to read; (out) number of words actually read + * @data: words read from the Shadow RAM * - * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() - * method. The buffer read is preceded by the NVM ownership take - * and followed by the release. + * Reads 16 bit words (data buffer) from the SR using the i40e_read_nvm_srrd() + * method. The buffer read is preceded by the NVM ownership take + * and followed by the release. **/ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, u16 *words, u16 *data) @@ -227,7 +226,7 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, i40e_status ret_code = 0; u16 index, word; - /* Loop thru the selected region. */ + /* Loop thru the selected region */ for (word = 0; word < *words; word++) { index = offset + word; ret_code = i40e_read_nvm_word(hw, index, &data[word]); @@ -235,21 +234,21 @@ i40e_status i40e_read_nvm_buffer(struct i40e_hw *hw, u16 offset, break; } - /* Update the number of words read from the Shadow RAM. */ + /* Update the number of words read from the Shadow RAM */ *words = word; return ret_code; } /** - * i40e_calc_nvm_checksum - Calculates and returns the checksum - * @hw: pointer to hardware structure - * @checksum: pointer to the checksum + * 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 - * is customer specific and unknown. Therefore, this function skips all maximum - * possible size of VPD (1kB). + * This function calculates SW Checksum that covers the whole 64kB shadow RAM + * except the VPD and PCIe ALT Auto-load modules. The structure and size of VPD + * is customer specific and unknown. Therefore, this function skips all maximum + * possible size of VPD (1kB). **/ static i40e_status i40e_calc_nvm_checksum(struct i40e_hw *hw, u16 *checksum) @@ -311,12 +310,12 @@ i40e_calc_nvm_checksum_exit: } /** - * i40e_validate_nvm_checksum - Validate EEPROM checksum - * @hw: pointer to hardware structure - * @checksum: calculated checksum + * i40e_validate_nvm_checksum - Validate EEPROM checksum + * @hw: pointer to hardware structure + * @checksum: calculated checksum * - * Performs checksum calculation and validates the NVM SW checksum. If the - * caller does not need checksum, the value can be NULL. + * Performs checksum calculation and validates the NVM SW checksum. If the + * caller does not need checksum, the value can be NULL. **/ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 *checksum) diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index ed91f93ede2b..9cd57e617959 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -231,6 +231,13 @@ i40e_status i40e_validate_nvm_checksum(struct i40e_hw *hw, u16 *checksum); void i40e_set_pci_config_data(struct i40e_hw *hw, u16 link_status); +extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; + +static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) +{ + return i40e_ptype_lookup[ptype]; +} + /* prototype for functions used for SW locks */ /* i40e_common for VF drivers*/ diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index d4bb482b1a7f..2081bdb214e5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -25,6 +25,7 @@ ******************************************************************************/ #include "i40e.h" +#include "i40e_prototype.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) @@ -39,11 +40,12 @@ static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, #define I40E_TXD_CMD (I40E_TX_DESC_CMD_EOP | I40E_TX_DESC_CMD_RS) /** * i40e_program_fdir_filter - Program a Flow Director filter - * @fdir_input: Packet data that will be filter parameters + * @fdir_data: Packet data that will be filter parameters + * @raw_packet: the pre-allocated packet buffer for FDir * @pf: The pf pointer * @add: True for add/update, False for remove **/ -int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, +int i40e_program_fdir_filter(struct i40e_fdir_filter *fdir_data, u8 *raw_packet, struct i40e_pf *pf, bool add) { struct i40e_filter_program_desc *fdir_desc; @@ -68,8 +70,8 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, tx_ring = vsi->tx_rings[0]; dev = tx_ring->dev; - dma = dma_map_single(dev, fdir_data->raw_packet, - I40E_FDIR_MAX_RAW_PACKET_LOOKUP, DMA_TO_DEVICE); + dma = dma_map_single(dev, raw_packet, + I40E_FDIR_MAX_RAW_PACKET_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma)) goto dma_fail; @@ -132,14 +134,14 @@ int i40e_program_fdir_filter(struct i40e_fdir_data *fdir_data, tx_ring->next_to_use = (i + 1 < tx_ring->count) ? i + 1 : 0; /* record length, and DMA address */ - dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_LOOKUP); + dma_unmap_len_set(tx_buf, len, I40E_FDIR_MAX_RAW_PACKET_SIZE); dma_unmap_addr_set(tx_buf, dma, dma); tx_desc->buffer_addr = cpu_to_le64(dma); td_cmd = I40E_TXD_CMD | I40E_TX_DESC_CMD_DUMMY; tx_desc->cmd_type_offset_bsz = - build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_LOOKUP, 0); + build_ctob(td_cmd, 0, I40E_FDIR_MAX_RAW_PACKET_SIZE, 0); /* set the timestamp */ tx_buf->time_stamp = jiffies; @@ -161,6 +163,270 @@ dma_fail: return -1; } +#define IP_HEADER_OFFSET 14 +#define I40E_UDPIP_DUMMY_PACKET_LEN 42 +/** + * i40e_add_del_fdir_udpv4 - Add/Remove UDPv4 filters + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_udpv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + struct i40e_pf *pf = vsi->back; + struct udphdr *udp; + struct iphdr *ip; + bool err = false; + int ret; + int i; + static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, + 0x45, 0, 0, 0x1c, 0, 0, 0x40, 0, 0x40, 0x11, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + memcpy(raw_packet, packet, I40E_UDPIP_DUMMY_PACKET_LEN); + + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + udp = (struct udphdr *)(raw_packet + IP_HEADER_OFFSET + + sizeof(struct iphdr)); + + ip->daddr = fd_data->dst_ip[0]; + udp->dest = fd_data->dst_port; + ip->saddr = fd_data->src_ip[0]; + udp->source = fd_data->src_port; + + for (i = I40E_FILTER_PCTYPE_NONF_UNICAST_IPV4_UDP; + i <= I40E_FILTER_PCTYPE_NONF_IPV4_UDP; i++) { + fd_data->pctype = i; + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, + "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + } + + return err ? -EOPNOTSUPP : 0; +} + +#define I40E_TCPIP_DUMMY_PACKET_LEN 54 +/** + * i40e_add_del_fdir_tcpv4 - Add/Remove TCPv4 filters + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_tcpv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + struct i40e_pf *pf = vsi->back; + struct tcphdr *tcp; + struct iphdr *ip; + bool err = false; + int ret; + /* Dummy packet */ + static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, + 0x45, 0, 0, 0x28, 0, 0, 0x40, 0, 0x40, 0x6, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0x11, + 0x0, 0x72, 0, 0, 0, 0}; + + memcpy(raw_packet, packet, I40E_TCPIP_DUMMY_PACKET_LEN); + + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + tcp = (struct tcphdr *)(raw_packet + IP_HEADER_OFFSET + + sizeof(struct iphdr)); + + ip->daddr = fd_data->dst_ip[0]; + tcp->dest = fd_data->dst_port; + ip->saddr = fd_data->src_ip[0]; + tcp->source = fd_data->src_port; + + if (add) { + if (pf->flags & I40E_FLAG_FD_ATR_ENABLED) { + dev_info(&pf->pdev->dev, "Forcing ATR off, sideband rules for TCP/IPv4 flow being applied\n"); + pf->flags &= ~I40E_FLAG_FD_ATR_ENABLED; + } + } + + fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP_SYN; + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + + fd_data->pctype = I40E_FILTER_PCTYPE_NONF_IPV4_TCP; + + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + + return err ? -EOPNOTSUPP : 0; +} + +/** + * i40e_add_del_fdir_sctpv4 - Add/Remove SCTPv4 Flow Director filters for + * a specific flow spec + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_sctpv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + return -EOPNOTSUPP; +} + +#define I40E_IP_DUMMY_PACKET_LEN 34 +/** + * i40e_add_del_fdir_ipv4 - Add/Remove IPv4 Flow Director filters for + * a specific flow spec + * @vsi: pointer to the targeted VSI + * @fd_data: the flow director data required for the FDir descriptor + * @raw_packet: the pre-allocated packet buffer for FDir + * @add: true adds a filter, false removes it + * + * Returns 0 if the filters were successfully added or removed + **/ +static int i40e_add_del_fdir_ipv4(struct i40e_vsi *vsi, + struct i40e_fdir_filter *fd_data, + u8 *raw_packet, bool add) +{ + struct i40e_pf *pf = vsi->back; + struct iphdr *ip; + bool err = false; + int ret; + int i; + static char packet[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x08, 0, + 0x45, 0, 0, 0x14, 0, 0, 0x40, 0, 0x40, 0x10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0}; + + memcpy(raw_packet, packet, I40E_IP_DUMMY_PACKET_LEN); + ip = (struct iphdr *)(raw_packet + IP_HEADER_OFFSET); + + ip->saddr = fd_data->src_ip[0]; + ip->daddr = fd_data->dst_ip[0]; + ip->protocol = 0; + + for (i = I40E_FILTER_PCTYPE_NONF_IPV4_OTHER; + i <= I40E_FILTER_PCTYPE_FRAG_IPV4; i++) { + fd_data->pctype = i; + ret = i40e_program_fdir_filter(fd_data, raw_packet, pf, add); + + if (ret) { + dev_info(&pf->pdev->dev, + "Filter command send failed for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + err = true; + } else { + dev_info(&pf->pdev->dev, + "Filter OK for PCTYPE %d (ret = %d)\n", + fd_data->pctype, ret); + } + } + + return err ? -EOPNOTSUPP : 0; +} + +/** + * i40e_add_del_fdir - Build raw packets to add/del fdir filter + * @vsi: pointer to the targeted VSI + * @cmd: command to get or set RX flow classification rules + * @add: true adds a filter, false removes it + * + **/ +int i40e_add_del_fdir(struct i40e_vsi *vsi, + struct i40e_fdir_filter *input, bool add) +{ + struct i40e_pf *pf = vsi->back; + u8 *raw_packet; + int ret; + + /* Populate the Flow Director that we have at the moment + * and allocate the raw packet buffer for the calling functions + */ + raw_packet = kzalloc(I40E_FDIR_MAX_RAW_PACKET_SIZE, GFP_KERNEL); + if (!raw_packet) + return -ENOMEM; + + switch (input->flow_type & ~FLOW_EXT) { + case TCP_V4_FLOW: + ret = i40e_add_del_fdir_tcpv4(vsi, input, raw_packet, + add); + break; + case UDP_V4_FLOW: + ret = i40e_add_del_fdir_udpv4(vsi, input, raw_packet, + add); + break; + case SCTP_V4_FLOW: + ret = i40e_add_del_fdir_sctpv4(vsi, input, raw_packet, + add); + break; + case IPV4_FLOW: + ret = i40e_add_del_fdir_ipv4(vsi, input, raw_packet, + add); + break; + case IP_USER_FLOW: + switch (input->ip4_proto) { + case IPPROTO_TCP: + ret = i40e_add_del_fdir_tcpv4(vsi, input, + raw_packet, add); + break; + case IPPROTO_UDP: + ret = i40e_add_del_fdir_udpv4(vsi, input, + raw_packet, add); + break; + case IPPROTO_SCTP: + ret = i40e_add_del_fdir_sctpv4(vsi, input, + raw_packet, add); + break; + default: + ret = i40e_add_del_fdir_ipv4(vsi, input, + raw_packet, add); + break; + } + break; + default: + dev_info(&pf->pdev->dev, "Could not specify spec type %d", + input->flow_type); + ret = -EINVAL; + } + + kfree(raw_packet); + return ret; +} + /** * i40e_fd_handle_status - check the Programming Status for FD * @rx_ring: the Rx ring for this descriptor @@ -892,7 +1158,7 @@ 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 */ + /* likely incorrect csum if alternate IP extension headers found */ if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) return; @@ -956,6 +1222,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring, } /** + * i40e_ptype_to_hash - get a hash type + * @ptype: the ptype value from the descriptor + * + * Returns a hash type to be used by skb_set_hash + **/ +static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype) +{ + struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); + + if (!decoded.known) + return PKT_HASH_TYPE_NONE; + + if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4) + return PKT_HASH_TYPE_L4; + else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3) + return PKT_HASH_TYPE_L3; + else + return PKT_HASH_TYPE_L2; +} + +/** * i40e_clean_rx_irq - Reclaim resources after receive completes * @rx_ring: rx ring to clean * @budget: how many cleans we're allowed @@ -972,8 +1261,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) u16 i = rx_ring->next_to_clean; union i40e_rx_desc *rx_desc; u32 rx_error, rx_status; + u8 rx_ptype; u64 qword; - u16 rx_ptype; rx_desc = I40E_RX_DESC(rx_ring, i); qword = le64_to_cpu(rx_desc->wb.qword1.status_error_len); @@ -1087,7 +1376,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) goto next_desc; } - skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); + skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc), + i40e_ptype_to_hash(rx_ptype)); 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) >> @@ -1812,7 +2102,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, - * + 2 desc gap to keep tail from touching head, + * + 4 desc gap to avoid the cache line where head is, * + 1 desc for context descriptor, * otherwise try next time */ @@ -1823,7 +2113,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, count += skb_shinfo(skb)->nr_frags; #endif count += TXD_USE_COUNT(skb_headlen(skb)); - if (i40e_maybe_stop_tx(tx_ring, count + 3)) { + if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) { tx_ring->tx_stats.tx_busy++; return 0; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index b9d1c1c8ca5a..42cc6ba88005 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -408,18 +408,10 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) "Could not allocate VF broadcast filter\n"); } - if (!f) { - dev_err(&pf->pdev->dev, "Unable to add ucast filter\n"); - ret = -ENOMEM; - goto error_alloc_vsi_res; - } - /* program mac filter */ ret = i40e_sync_vsi_filters(vsi); - if (ret) { + if (ret) dev_err(&pf->pdev->dev, "Unable to program ucast filters\n"); - goto error_alloc_vsi_res; - } error_alloc_vsi_res: return ret; @@ -679,9 +671,9 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr) complete_reset: /* reallocate vf resources to reset the VSI state */ i40e_free_vf_res(vf); - mdelay(10); i40e_alloc_vf_res(vf); i40e_enable_vf_mappings(vf); + set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); /* tell the VF the reset is done */ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); @@ -847,7 +839,7 @@ void i40e_free_vfs(struct i40e_pf *pf) * * allocate vf resources **/ -static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) +int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) { struct i40e_vf *vfs; int i, ret = 0; @@ -855,16 +847,18 @@ static int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) /* Disable interrupt 0 so we don't try to handle the VFLR. */ i40e_irq_dynamic_disable_icr0(pf); - ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); - if (ret) { - dev_err(&pf->pdev->dev, - "pci_enable_sriov failed with error %d!\n", ret); - pf->num_alloc_vfs = 0; - goto err_iov; + /* Check to see if we're just allocating resources for extant VFs */ + if (pci_num_vf(pf->pdev) != num_alloc_vfs) { + ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); + if (ret) { + dev_err(&pf->pdev->dev, + "Failed to enable SR-IOV, error %d.\n", ret); + pf->num_alloc_vfs = 0; + goto err_iov; + } } - /* allocate memory */ - vfs = kzalloc(num_alloc_vfs * sizeof(struct i40e_vf), GFP_KERNEL); + vfs = kcalloc(num_alloc_vfs, sizeof(struct i40e_vf), GFP_KERNEL); if (!vfs) { ret = -ENOMEM; goto err_alloc; @@ -1873,7 +1867,8 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) /* clear the bit in GLGEN_VFLRSTAT */ wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); - i40e_reset_vf(vf, true); + if (!test_bit(__I40E_DOWN, &pf->state)) + i40e_reset_vf(vf, true); } } diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index cc1feee36e12..bedf0ba21d74 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -102,6 +102,7 @@ struct i40e_vf { void i40e_free_vfs(struct i40e_pf *pf); int i40e_pci_sriov_configure(struct pci_dev *dev, int num_vfs); +int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs); int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode, u32 v_retval, u8 *msg, u16 msglen); int i40e_vc_process_vflr_event(struct i40e_pf *pf); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index f7cea1bca38d..97662b6bd98a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -1229,7 +1229,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data { #define I40E_AQC_ADD_CLOUD_TNL_TYPE_NGE 2 #define I40E_AQC_ADD_CLOUD_TNL_TYPE_IP 3 - __le32 tenant_id ; + __le32 tenant_id; u8 reserved[4]; __le16 queue_number; #define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 7b13953b28c4..78618af271cf 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -160,6 +160,372 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, } +/* The i40e_ptype_lookup table is used to convert from the 8-bit ptype in the + * hardware to a bit-field that can be used by SW to more easily determine the + * packet type. + * + * Macros are used to shorten the table lines and make this table human + * readable. + * + * We store the PTYPE in the top byte of the bit field - this is just so that + * we can check that the table doesn't have a row missing, as the index into + * the table should be the PTYPE. + * + * Typical work flow: + * + * IF NOT i40e_ptype_lookup[ptype].known + * THEN + * Packet is unknown + * ELSE IF i40e_ptype_lookup[ptype].outer_ip == I40E_RX_PTYPE_OUTER_IP + * Use the rest of the fields to look at the tunnels, inner protocols, etc + * ELSE + * Use the enum i40e_rx_l2_ptype to decode the packet type + * ENDIF + */ + +/* macro to make the table lines short */ +#define I40E_PTT(PTYPE, OUTER_IP, OUTER_IP_VER, OUTER_FRAG, T, TE, TEF, I, PL)\ + { PTYPE, \ + 1, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP, \ + I40E_RX_PTYPE_OUTER_##OUTER_IP_VER, \ + I40E_RX_PTYPE_##OUTER_FRAG, \ + I40E_RX_PTYPE_TUNNEL_##T, \ + I40E_RX_PTYPE_TUNNEL_END_##TE, \ + I40E_RX_PTYPE_##TEF, \ + I40E_RX_PTYPE_INNER_PROT_##I, \ + I40E_RX_PTYPE_PAYLOAD_LAYER_##PL } + +#define I40E_PTT_UNUSED_ENTRY(PTYPE) \ + { PTYPE, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + +/* shorter macros makes the table fit but are terse */ +#define I40E_RX_PTYPE_NOF I40E_RX_PTYPE_NOT_FRAG +#define I40E_RX_PTYPE_FRG I40E_RX_PTYPE_FRAG +#define I40E_RX_PTYPE_INNER_PROT_TS I40E_RX_PTYPE_INNER_PROT_TIMESYNC + +/* Lookup table mapping the HW PTYPE to the bit field for decoding */ +struct i40e_rx_ptype_decoded i40e_ptype_lookup[] = { + /* L2 Packet types */ + I40E_PTT_UNUSED_ENTRY(0), + I40E_PTT(1, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(2, L2, NONE, NOF, NONE, NONE, NOF, TS, PAY2), + I40E_PTT(3, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(4), + I40E_PTT_UNUSED_ENTRY(5), + I40E_PTT(6, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(7, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT_UNUSED_ENTRY(8), + I40E_PTT_UNUSED_ENTRY(9), + I40E_PTT(10, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY2), + I40E_PTT(11, L2, NONE, NOF, NONE, NONE, NOF, NONE, NONE), + I40E_PTT(12, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(13, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(14, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(15, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(16, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(17, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(18, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(19, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(20, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(21, L2, NONE, NOF, NONE, NONE, NOF, NONE, PAY3), + + /* Non Tunneled IPv4 */ + I40E_PTT(22, IP, IPV4, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(23, IP, IPV4, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(24, IP, IPV4, NOF, NONE, NONE, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(25), + I40E_PTT(26, IP, IPV4, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(27, IP, IPV4, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(28, IP, IPV4, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv4 --> IPv4 */ + I40E_PTT(29, IP, IPV4, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(30, IP, IPV4, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(31, IP, IPV4, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(32), + I40E_PTT(33, IP, IPV4, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(34, IP, IPV4, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(35, IP, IPV4, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> IPv6 */ + I40E_PTT(36, IP, IPV4, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(37, IP, IPV4, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(38, IP, IPV4, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(39), + I40E_PTT(40, IP, IPV4, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(41, IP, IPV4, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(42, IP, IPV4, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT */ + I40E_PTT(43, IP, IPV4, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> IPv4 */ + I40E_PTT(44, IP, IPV4, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(45, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(46, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(47), + I40E_PTT(48, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(49, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(50, IP, IPV4, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> IPv6 */ + I40E_PTT(51, IP, IPV4, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(52, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(53, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(54), + I40E_PTT(55, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(56, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(57, IP, IPV4, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC */ + I40E_PTT(58, IP, IPV4, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv4 --> GRE/NAT --> MAC --> IPv4 */ + I40E_PTT(59, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(60, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(61, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(62), + I40E_PTT(63, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(64, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(65, IP, IPV4, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT -> MAC --> IPv6 */ + I40E_PTT(66, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(67, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(68, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(69), + I40E_PTT(70, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(71, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(72, IP, IPV4, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv4 --> GRE/NAT --> MAC/VLAN */ + I40E_PTT(73, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv4 ---> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(74, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(75, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(76, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(77), + I40E_PTT(78, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(79, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(80, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv4 -> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(81, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(82, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(83, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(84), + I40E_PTT(85, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(86, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(87, IP, IPV4, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* Non Tunneled IPv6 */ + I40E_PTT(88, IP, IPV6, FRG, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(89, IP, IPV6, NOF, NONE, NONE, NOF, NONE, PAY3), + I40E_PTT(90, IP, IPV6, NOF, NONE, NONE, NOF, UDP, PAY3), + I40E_PTT_UNUSED_ENTRY(91), + I40E_PTT(92, IP, IPV6, NOF, NONE, NONE, NOF, TCP, PAY4), + I40E_PTT(93, IP, IPV6, NOF, NONE, NONE, NOF, SCTP, PAY4), + I40E_PTT(94, IP, IPV6, NOF, NONE, NONE, NOF, ICMP, PAY4), + + /* IPv6 --> IPv4 */ + I40E_PTT(95, IP, IPV6, NOF, IP_IP, IPV4, FRG, NONE, PAY3), + I40E_PTT(96, IP, IPV6, NOF, IP_IP, IPV4, NOF, NONE, PAY3), + I40E_PTT(97, IP, IPV6, NOF, IP_IP, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(98), + I40E_PTT(99, IP, IPV6, NOF, IP_IP, IPV4, NOF, TCP, PAY4), + I40E_PTT(100, IP, IPV6, NOF, IP_IP, IPV4, NOF, SCTP, PAY4), + I40E_PTT(101, IP, IPV6, NOF, IP_IP, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> IPv6 */ + I40E_PTT(102, IP, IPV6, NOF, IP_IP, IPV6, FRG, NONE, PAY3), + I40E_PTT(103, IP, IPV6, NOF, IP_IP, IPV6, NOF, NONE, PAY3), + I40E_PTT(104, IP, IPV6, NOF, IP_IP, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(105), + I40E_PTT(106, IP, IPV6, NOF, IP_IP, IPV6, NOF, TCP, PAY4), + I40E_PTT(107, IP, IPV6, NOF, IP_IP, IPV6, NOF, SCTP, PAY4), + I40E_PTT(108, IP, IPV6, NOF, IP_IP, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT */ + I40E_PTT(109, IP, IPV6, NOF, IP_GRENAT, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> IPv4 */ + I40E_PTT(110, IP, IPV6, NOF, IP_GRENAT, IPV4, FRG, NONE, PAY3), + I40E_PTT(111, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, NONE, PAY3), + I40E_PTT(112, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(113), + I40E_PTT(114, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, TCP, PAY4), + I40E_PTT(115, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, SCTP, PAY4), + I40E_PTT(116, IP, IPV6, NOF, IP_GRENAT, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> IPv6 */ + I40E_PTT(117, IP, IPV6, NOF, IP_GRENAT, IPV6, FRG, NONE, PAY3), + I40E_PTT(118, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, NONE, PAY3), + I40E_PTT(119, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(120), + I40E_PTT(121, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, TCP, PAY4), + I40E_PTT(122, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, SCTP, PAY4), + I40E_PTT(123, IP, IPV6, NOF, IP_GRENAT, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC */ + I40E_PTT(124, IP, IPV6, NOF, IP_GRENAT_MAC, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC -> IPv4 */ + I40E_PTT(125, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, FRG, NONE, PAY3), + I40E_PTT(126, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, NONE, PAY3), + I40E_PTT(127, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(128), + I40E_PTT(129, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, TCP, PAY4), + I40E_PTT(130, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, SCTP, PAY4), + I40E_PTT(131, IP, IPV6, NOF, IP_GRENAT_MAC, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC -> IPv6 */ + I40E_PTT(132, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, FRG, NONE, PAY3), + I40E_PTT(133, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, NONE, PAY3), + I40E_PTT(134, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(135), + I40E_PTT(136, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, TCP, PAY4), + I40E_PTT(137, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, SCTP, PAY4), + I40E_PTT(138, IP, IPV6, NOF, IP_GRENAT_MAC, IPV6, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN */ + I40E_PTT(139, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, NONE, NOF, NONE, PAY3), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv4 */ + I40E_PTT(140, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, FRG, NONE, PAY3), + I40E_PTT(141, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, NONE, PAY3), + I40E_PTT(142, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(143), + I40E_PTT(144, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, TCP, PAY4), + I40E_PTT(145, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, SCTP, PAY4), + I40E_PTT(146, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV4, NOF, ICMP, PAY4), + + /* IPv6 --> GRE/NAT -> MAC/VLAN --> IPv6 */ + I40E_PTT(147, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, FRG, NONE, PAY3), + I40E_PTT(148, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, NONE, PAY3), + I40E_PTT(149, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, UDP, PAY4), + I40E_PTT_UNUSED_ENTRY(150), + I40E_PTT(151, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, TCP, PAY4), + I40E_PTT(152, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, SCTP, PAY4), + I40E_PTT(153, IP, IPV6, NOF, IP_GRENAT_MAC_VLAN, IPV6, NOF, ICMP, PAY4), + + /* unused entries */ + I40E_PTT_UNUSED_ENTRY(154), + I40E_PTT_UNUSED_ENTRY(155), + I40E_PTT_UNUSED_ENTRY(156), + I40E_PTT_UNUSED_ENTRY(157), + I40E_PTT_UNUSED_ENTRY(158), + I40E_PTT_UNUSED_ENTRY(159), + + I40E_PTT_UNUSED_ENTRY(160), + I40E_PTT_UNUSED_ENTRY(161), + I40E_PTT_UNUSED_ENTRY(162), + I40E_PTT_UNUSED_ENTRY(163), + I40E_PTT_UNUSED_ENTRY(164), + I40E_PTT_UNUSED_ENTRY(165), + I40E_PTT_UNUSED_ENTRY(166), + I40E_PTT_UNUSED_ENTRY(167), + I40E_PTT_UNUSED_ENTRY(168), + I40E_PTT_UNUSED_ENTRY(169), + + I40E_PTT_UNUSED_ENTRY(170), + I40E_PTT_UNUSED_ENTRY(171), + I40E_PTT_UNUSED_ENTRY(172), + I40E_PTT_UNUSED_ENTRY(173), + I40E_PTT_UNUSED_ENTRY(174), + I40E_PTT_UNUSED_ENTRY(175), + I40E_PTT_UNUSED_ENTRY(176), + I40E_PTT_UNUSED_ENTRY(177), + I40E_PTT_UNUSED_ENTRY(178), + I40E_PTT_UNUSED_ENTRY(179), + + I40E_PTT_UNUSED_ENTRY(180), + I40E_PTT_UNUSED_ENTRY(181), + I40E_PTT_UNUSED_ENTRY(182), + I40E_PTT_UNUSED_ENTRY(183), + I40E_PTT_UNUSED_ENTRY(184), + I40E_PTT_UNUSED_ENTRY(185), + I40E_PTT_UNUSED_ENTRY(186), + I40E_PTT_UNUSED_ENTRY(187), + I40E_PTT_UNUSED_ENTRY(188), + I40E_PTT_UNUSED_ENTRY(189), + + I40E_PTT_UNUSED_ENTRY(190), + I40E_PTT_UNUSED_ENTRY(191), + I40E_PTT_UNUSED_ENTRY(192), + I40E_PTT_UNUSED_ENTRY(193), + I40E_PTT_UNUSED_ENTRY(194), + I40E_PTT_UNUSED_ENTRY(195), + I40E_PTT_UNUSED_ENTRY(196), + I40E_PTT_UNUSED_ENTRY(197), + I40E_PTT_UNUSED_ENTRY(198), + I40E_PTT_UNUSED_ENTRY(199), + + I40E_PTT_UNUSED_ENTRY(200), + I40E_PTT_UNUSED_ENTRY(201), + I40E_PTT_UNUSED_ENTRY(202), + I40E_PTT_UNUSED_ENTRY(203), + I40E_PTT_UNUSED_ENTRY(204), + I40E_PTT_UNUSED_ENTRY(205), + I40E_PTT_UNUSED_ENTRY(206), + I40E_PTT_UNUSED_ENTRY(207), + I40E_PTT_UNUSED_ENTRY(208), + I40E_PTT_UNUSED_ENTRY(209), + + I40E_PTT_UNUSED_ENTRY(210), + I40E_PTT_UNUSED_ENTRY(211), + I40E_PTT_UNUSED_ENTRY(212), + I40E_PTT_UNUSED_ENTRY(213), + I40E_PTT_UNUSED_ENTRY(214), + I40E_PTT_UNUSED_ENTRY(215), + I40E_PTT_UNUSED_ENTRY(216), + I40E_PTT_UNUSED_ENTRY(217), + I40E_PTT_UNUSED_ENTRY(218), + I40E_PTT_UNUSED_ENTRY(219), + + I40E_PTT_UNUSED_ENTRY(220), + I40E_PTT_UNUSED_ENTRY(221), + I40E_PTT_UNUSED_ENTRY(222), + I40E_PTT_UNUSED_ENTRY(223), + I40E_PTT_UNUSED_ENTRY(224), + I40E_PTT_UNUSED_ENTRY(225), + I40E_PTT_UNUSED_ENTRY(226), + I40E_PTT_UNUSED_ENTRY(227), + I40E_PTT_UNUSED_ENTRY(228), + I40E_PTT_UNUSED_ENTRY(229), + + I40E_PTT_UNUSED_ENTRY(230), + I40E_PTT_UNUSED_ENTRY(231), + I40E_PTT_UNUSED_ENTRY(232), + I40E_PTT_UNUSED_ENTRY(233), + I40E_PTT_UNUSED_ENTRY(234), + I40E_PTT_UNUSED_ENTRY(235), + I40E_PTT_UNUSED_ENTRY(236), + I40E_PTT_UNUSED_ENTRY(237), + I40E_PTT_UNUSED_ENTRY(238), + I40E_PTT_UNUSED_ENTRY(239), + + I40E_PTT_UNUSED_ENTRY(240), + I40E_PTT_UNUSED_ENTRY(241), + I40E_PTT_UNUSED_ENTRY(242), + I40E_PTT_UNUSED_ENTRY(243), + I40E_PTT_UNUSED_ENTRY(244), + I40E_PTT_UNUSED_ENTRY(245), + I40E_PTT_UNUSED_ENTRY(246), + I40E_PTT_UNUSED_ENTRY(247), + I40E_PTT_UNUSED_ENTRY(248), + I40E_PTT_UNUSED_ENTRY(249), + + I40E_PTT_UNUSED_ENTRY(250), + I40E_PTT_UNUSED_ENTRY(251), + I40E_PTT_UNUSED_ENTRY(252), + I40E_PTT_UNUSED_ENTRY(253), + I40E_PTT_UNUSED_ENTRY(254), + I40E_PTT_UNUSED_ENTRY(255) +}; + + /** * i40e_aq_send_msg_to_pf * @hw: pointer to the hardware structure diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 7841573a58c9..33c99051cc96 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -63,6 +63,13 @@ i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, i40e_status i40e_set_mac_type(struct i40e_hw *hw); +extern struct i40e_rx_ptype_decoded i40e_ptype_lookup[]; + +static inline struct i40e_rx_ptype_decoded decode_rx_desc_ptype(u8 ptype) +{ + return i40e_ptype_lookup[ptype]; +} + /* prototype for functions used for SW locks */ /* i40e_common for VF drivers*/ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index ffdb01d853db..b1d87c6a5c35 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * 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, @@ -24,6 +24,7 @@ #include <linux/prefetch.h> #include "i40evf.h" +#include "i40e_prototype.h" static inline __le64 build_ctob(u32 td_cmd, u32 td_offset, unsigned int size, u32 td_tag) @@ -722,7 +723,7 @@ 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 */ + /* likely incorrect csum if alternate IP extension headers found */ if (rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) return; @@ -786,6 +787,29 @@ static inline u32 i40e_rx_hash(struct i40e_ring *ring, } /** + * i40e_ptype_to_hash - get a hash type + * @ptype: the ptype value from the descriptor + * + * Returns a hash type to be used by skb_set_hash + **/ +static inline enum pkt_hash_types i40e_ptype_to_hash(u8 ptype) +{ + struct i40e_rx_ptype_decoded decoded = decode_rx_desc_ptype(ptype); + + if (!decoded.known) + return PKT_HASH_TYPE_NONE; + + if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY4) + return PKT_HASH_TYPE_L4; + else if (decoded.outer_ip == I40E_RX_PTYPE_OUTER_IP && + decoded.payload_layer == I40E_RX_PTYPE_PAYLOAD_LAYER_PAY3) + return PKT_HASH_TYPE_L3; + else + return PKT_HASH_TYPE_L2; +} + +/** * i40e_clean_rx_irq - Reclaim resources after receive completes * @rx_ring: rx ring to clean * @budget: how many cleans we're allowed @@ -802,13 +826,13 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) u16 i = rx_ring->next_to_clean; union i40e_rx_desc *rx_desc; u32 rx_error, rx_status; + u8 rx_ptype; u64 qword; - u16 rx_ptype; 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; @@ -912,7 +936,8 @@ static int i40e_clean_rx_irq(struct i40e_ring *rx_ring, int budget) goto next_desc; } - skb->rxhash = i40e_rx_hash(rx_ring, rx_desc); + skb_set_hash(skb, i40e_rx_hash(rx_ring, rx_desc), + i40e_ptype_to_hash(rx_ptype)); /* probably a little skewed due to removing CRC */ total_rx_bytes += skb->len; total_rx_packets++; @@ -1457,7 +1482,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, /* need: 1 descriptor per page * PAGE_SIZE/I40E_MAX_DATA_PER_TXD, * + 1 desc for skb_head_len/I40E_MAX_DATA_PER_TXD, - * + 2 desc gap to keep tail from touching head, + * + 4 desc gap to avoid the cache line where head is, * + 1 desc for context descriptor, * otherwise try next time */ @@ -1468,7 +1493,7 @@ static int i40e_xmit_descriptor_count(struct sk_buff *skb, count += skb_shinfo(skb)->nr_frags; #endif count += TXD_USE_COUNT(skb_headlen(skb)); - if (i40e_maybe_stop_tx(tx_ring, count + 3)) { + if (i40e_maybe_stop_tx(tx_ring, count + 4 + 1)) { tx_ring->tx_stats.tx_busy++; return 0; } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 3bffac06592f..092aace2a76c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * 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, @@ -64,8 +64,6 @@ struct i40e_hw; typedef void (*I40E_ADMINQ_CALLBACK)(struct i40e_hw *, struct i40e_aq_desc *); -#define ETH_ALEN 6 - /* Data type manipulation macros. */ #define I40E_DESC_UNUSED(R) \ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index ff6529b288a1..ccb43d343543 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * 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, @@ -38,8 +38,6 @@ #include <linux/ipv6.h> #include <net/ip6_checksum.h> #include <net/udp.h> -#include <linux/sctp.h> - #include "i40e_type.h" #include "i40e_virtchnl.h" @@ -164,15 +162,14 @@ struct i40evf_vlan_filter { /* Driver state. The order of these is important! */ enum i40evf_state_t { __I40EVF_STARTUP, /* driver loaded, probe complete */ - __I40EVF_FAILED, /* PF communication failed. Fatal. */ __I40EVF_REMOVE, /* driver is being unloaded */ __I40EVF_INIT_VERSION_CHECK, /* aq msg sent, awaiting reply */ __I40EVF_INIT_GET_RESOURCES, /* aq msg sent, awaiting reply */ __I40EVF_INIT_SW, /* got resources, setting up structs */ + __I40EVF_RESETTING, /* in reset */ /* Below here, watchdog is running */ __I40EVF_DOWN, /* ready, can be opened */ __I40EVF_TESTING, /* in ethtool self-test */ - __I40EVF_RESETTING, /* in reset */ __I40EVF_RUNNING, /* opened, working */ }; @@ -185,47 +182,25 @@ enum i40evf_critical_section_t { /* board specific private data structure */ struct i40evf_adapter { struct timer_list watchdog_timer; - struct vlan_group *vlgrp; struct work_struct reset_task; struct work_struct adminq_task; struct delayed_work init_task; struct i40e_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; struct list_head vlan_filter_list; - char name[MAX_MSIX_COUNT][IFNAMSIZ + 9]; - - /* Interrupt Throttle Rate */ - u32 itr_setting; - u16 eitr_low; - u16 eitr_high; + char misc_vector_name[IFNAMSIZ + 9]; /* TX */ struct i40e_ring *tx_rings[I40E_MAX_VSI_QP]; - u64 restart_queue; - u64 hw_csum_tx_good; - u64 lsc_int; - u64 hw_tso_ctxt; - u64 hw_tso6_ctxt; u32 tx_timeout_count; struct list_head mac_filter_list; -#ifdef DEBUG - bool detect_tx_hung; -#endif /* DEBUG */ /* RX */ struct i40e_ring *rx_rings[I40E_MAX_VSI_QP]; - int txd_count; - int rxd_count; u64 hw_csum_rx_error; - u64 hw_rx_no_dma_resources; - u64 hw_csum_rx_good; - u64 non_eop_descs; int num_msix_vectors; struct msix_entry *msix_entries; - u64 rx_hdr_split; - - u32 init_state; - volatile unsigned long flags; + u32 flags; #define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1) #define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) #define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2) @@ -234,6 +209,8 @@ struct i40evf_adapter { #define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5) #define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6) #define I40EVF_FLAG_NEED_LINK_UPDATE (u32)(1 << 7) +#define I40EVF_FLAG_PF_COMMS_FAILED (u32)(1 << 8) +#define I40EVF_FLAG_RESET_PENDING (u32)(1 << 9) /* duplcates for common code */ #define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0 @@ -251,21 +228,19 @@ struct i40evf_adapter { #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) #define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) #define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) + /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; struct net_device_stats net_stats; - /* structs defined in i40e_vf.h */ - struct i40e_hw hw; + struct i40e_hw hw; /* defined in i40e_type.h */ enum i40evf_state_t state; volatile unsigned long crit_section; - u64 tx_busy; struct work_struct watchdog_task; bool netdev_registered; - bool dev_closed; bool link_up; enum i40e_virtchnl_ops current_op; struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ @@ -276,11 +251,6 @@ struct i40evf_adapter { u32 aq_wait_count; }; -struct i40evf_info { - enum i40e_mac_type mac; - unsigned int flags; -}; - /* needed by i40evf_ethtool.c */ extern char i40evf_driver_name[]; @@ -315,6 +285,7 @@ void i40evf_add_vlans(struct i40evf_adapter *adapter); void i40evf_del_vlans(struct i40evf_adapter *adapter); void i40evf_set_promiscuous(struct i40evf_adapter *adapter, int flags); void i40evf_request_stats(struct i40evf_adapter *adapter); +void i40evf_request_reset(struct i40evf_adapter *adapter); void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, enum i40e_virtchnl_ops v_opcode, i40e_status v_retval, u8 *msg, u16 msglen); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index b0b1f4bf5ac0..8b0db1ce179c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * 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, @@ -241,6 +241,7 @@ static int i40evf_set_ringparam(struct net_device *netdev, { struct i40evf_adapter *adapter = netdev_priv(netdev); u32 new_rx_count, new_tx_count; + int i; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; @@ -256,12 +257,14 @@ static int i40evf_set_ringparam(struct net_device *netdev, new_rx_count = ALIGN(new_rx_count, I40EVF_REQ_DESCRIPTOR_MULTIPLE); /* if nothing to do return success */ - if ((new_tx_count == adapter->txd_count) && - (new_rx_count == adapter->rxd_count)) + if ((new_tx_count == adapter->tx_rings[0]->count) && + (new_rx_count == adapter->rx_rings[0]->count)) return 0; - adapter->txd_count = new_tx_count; - adapter->rxd_count = new_rx_count; + for (i = 0; i < adapter->vsi_res->num_queue_pairs; i++) { + adapter->tx_rings[0]->count = new_tx_count; + adapter->rx_rings[0]->count = new_rx_count; + } if (netif_running(netdev)) i40evf_reinit_locked(adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f5caf4419243..11d0b61510b0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * 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, @@ -31,10 +31,10 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710 X710 Virtual Function Network Driver"; -#define DRV_VERSION "0.9.11" +#define DRV_VERSION "0.9.14" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = - "Copyright (c) 2013 Intel Corporation."; + "Copyright (c) 2013 - 2014 Intel Corporation."; /* i40evf_pci_tbl - PCI Device ID Table * @@ -167,9 +167,13 @@ static void i40evf_tx_timeout(struct net_device *netdev) struct i40evf_adapter *adapter = netdev_priv(netdev); adapter->tx_timeout_count++; - - /* Do the reset outside of interrupt context */ - schedule_work(&adapter->reset_task); + dev_info(&adapter->pdev->dev, "TX timeout detected.\n"); + if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { + dev_info(&adapter->pdev->dev, "Requesting reset from PF\n"); + i40evf_request_reset(adapter); + adapter->flags |= I40EVF_FLAG_RESET_PENDING; + schedule_work(&adapter->reset_task); + } } /** @@ -211,6 +215,9 @@ static void i40evf_irq_disable(struct i40evf_adapter *adapter) int i; struct i40e_hw *hw = &adapter->hw; + if (!adapter->msix_entries) + return; + for (i = 1; i < adapter->num_msix_vectors; i++) { wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), 0); synchronize_irq(adapter->msix_entries[i].vector); @@ -511,12 +518,14 @@ static int i40evf_request_misc_irq(struct i40evf_adapter *adapter) struct net_device *netdev = adapter->netdev; int err; - sprintf(adapter->name[0], "i40evf:mbx"); + sprintf(adapter->misc_vector_name, "i40evf:mbx"); err = request_irq(adapter->msix_entries[0].vector, - &i40evf_msix_aq, 0, adapter->name[0], netdev); + &i40evf_msix_aq, 0, + adapter->misc_vector_name, netdev); if (err) { dev_err(&adapter->pdev->dev, - "request_irq for msix_aq failed: %d\n", err); + "request_irq for %s failed: %d\n", + adapter->misc_vector_name, err); free_irq(adapter->msix_entries[0].vector, netdev); } return err; @@ -963,16 +972,23 @@ void i40evf_down(struct i40evf_adapter *adapter) struct net_device *netdev = adapter->netdev; struct i40evf_mac_filter *f; - /* remove all MAC filters from the VSI */ + /* remove all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { f->remove = true; } - adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; - /* disable receives */ - adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; - mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); - msleep(20); - + /* remove all VLAN filters */ + list_for_each_entry(f, &adapter->vlan_filter_list, list) { + f->remove = true; + } + if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) && + adapter->state != __I40EVF_RESETTING) { + adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; + adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER; + /* disable receives */ + adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES; + mod_timer_pending(&adapter->watchdog_timer, jiffies + 1); + msleep(20); + } netif_tx_disable(netdev); netif_tx_stop_all_queues(netdev); @@ -1291,19 +1307,47 @@ static void i40evf_watchdog_task(struct work_struct *work) watchdog_task); struct i40e_hw *hw = &adapter->hw; - if (adapter->state < __I40EVF_DOWN) + if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) + goto restart_watchdog; + + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { + dev_info(&adapter->pdev->dev, "Checking for redemption\n"); + if ((rd32(hw, I40E_VFGEN_RSTAT) & 0x3) == I40E_VFR_VFACTIVE) { + /* A chance for redemption! */ + dev_err(&adapter->pdev->dev, "Hardware came out of reset. Attempting reinit.\n"); + adapter->state = __I40EVF_STARTUP; + adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; + schedule_delayed_work(&adapter->init_task, 10); + clear_bit(__I40EVF_IN_CRITICAL_TASK, + &adapter->crit_section); + /* Don't reschedule the watchdog, since we've restarted + * the init task. When init_task contacts the PF and + * gets everything set up again, it'll restart the + * watchdog for us. Down, boy. Sit. Stay. Woof. + */ + return; + } + adapter->aq_pending = 0; + adapter->aq_required = 0; + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; goto watchdog_done; + } - if (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) + if ((adapter->state < __I40EVF_DOWN) || + (adapter->flags & I40EVF_FLAG_RESET_PENDING)) goto watchdog_done; - /* check for unannounced reset */ - if ((adapter->state != __I40EVF_RESETTING) && + /* check for reset */ + if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING) && (rd32(hw, I40E_VFGEN_RSTAT) & 0x3) != I40E_VFR_VFACTIVE) { adapter->state = __I40EVF_RESETTING; + adapter->flags |= I40EVF_FLAG_RESET_PENDING; + dev_err(&adapter->pdev->dev, "Hardware reset detected.\n"); + dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); schedule_work(&adapter->reset_task); - dev_info(&adapter->pdev->dev, "%s: hardware reset detected\n", - __func__); + adapter->aq_pending = 0; + adapter->aq_required = 0; + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; goto watchdog_done; } @@ -1358,13 +1402,15 @@ static void i40evf_watchdog_task(struct work_struct *work) i40evf_irq_enable(adapter, true); i40evf_fire_sw_int(adapter, 0xFF); + watchdog_done: + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); +restart_watchdog: if (adapter->aq_required) mod_timer(&adapter->watchdog_timer, jiffies + msecs_to_jiffies(20)); else mod_timer(&adapter->watchdog_timer, jiffies + (HZ * 2)); - clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); schedule_work(&adapter->adminq_task); } @@ -1411,6 +1457,8 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) i40e_flush(hw); } +#define I40EVF_RESET_WAIT_MS 100 +#define I40EVF_RESET_WAIT_COUNT 200 /** * i40evf_reset_task - Call-back task to handle hardware reset * @work: pointer to work_struct @@ -1421,8 +1469,9 @@ static void i40evf_configure_rss(struct i40evf_adapter *adapter) **/ static void i40evf_reset_task(struct work_struct *work) { - struct i40evf_adapter *adapter = - container_of(work, struct i40evf_adapter, reset_task); + struct i40evf_adapter *adapter = container_of(work, + struct i40evf_adapter, + reset_task); struct i40e_hw *hw = &adapter->hw; int i = 0, err; uint32_t rstat_val; @@ -1430,22 +1479,56 @@ static void i40evf_reset_task(struct work_struct *work) while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section)) udelay(500); + /* poll until we see the reset actually happen */ + for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { + rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & + I40E_VFGEN_RSTAT_VFR_STATE_MASK; + if (rstat_val != I40E_VFR_VFACTIVE) { + dev_info(&adapter->pdev->dev, "Reset now occurring\n"); + break; + } else { + msleep(I40EVF_RESET_WAIT_MS); + } + } + if (i == I40EVF_RESET_WAIT_COUNT) { + dev_err(&adapter->pdev->dev, "Reset was not detected\n"); + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + goto continue_reset; /* act like the reset happened */ + } - /* wait until the reset is complete */ - for (i = 0; i < 20; i++) { + /* wait until the reset is complete and the PF is responding to us */ + for (i = 0; i < I40EVF_RESET_WAIT_COUNT; i++) { rstat_val = rd32(hw, I40E_VFGEN_RSTAT) & I40E_VFGEN_RSTAT_VFR_STATE_MASK; - if (rstat_val == I40E_VFR_COMPLETED) + if (rstat_val == I40E_VFR_VFACTIVE) { + dev_info(&adapter->pdev->dev, "Reset is complete. Reinitializing.\n"); break; - else - mdelay(100); + } else { + msleep(I40EVF_RESET_WAIT_MS); + } } - if (i == 20) { + if (i == I40EVF_RESET_WAIT_COUNT) { /* reset never finished */ - dev_info(&adapter->pdev->dev, "%s: reset never finished: %x\n", - __func__, rstat_val); - /* carry on anyway */ + dev_err(&adapter->pdev->dev, "Reset never finished (%x). PF driver is dead, and so am I.\n", + rstat_val); + adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; + + if (netif_running(adapter->netdev)) + i40evf_close(adapter->netdev); + + i40evf_free_misc_irq(adapter); + i40evf_reset_interrupt_capability(adapter); + i40evf_free_queues(adapter); + kfree(adapter->vf_res); + i40evf_shutdown_adminq(hw); + adapter->netdev->flags &= ~IFF_UP; + clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); + return; /* Do not attempt to reinit. It's dead, Jim. */ } + +continue_reset: + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; + i40evf_down(adapter); adapter->state = __I40EVF_RESETTING; @@ -1505,6 +1588,9 @@ static void i40evf_adminq_task(struct work_struct *work) i40e_status ret; u16 pending; + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) + return; + event.msg_size = I40EVF_MAX_AQ_BUF_SIZE; event.msg_buf = kzalloc(event.msg_size, GFP_KERNEL); if (!event.msg_buf) { @@ -1636,6 +1722,10 @@ static int i40evf_open(struct net_device *netdev) struct i40evf_adapter *adapter = netdev_priv(netdev); int err; + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) { + dev_err(&adapter->pdev->dev, "Unable to open device due to PF driver failure.\n"); + return -EIO; + } if (adapter->state != __I40EVF_DOWN) return -EBUSY; @@ -1690,8 +1780,12 @@ static int i40evf_close(struct net_device *netdev) { struct i40evf_adapter *adapter = netdev_priv(netdev); + if (adapter->state <= __I40EVF_DOWN) + return 0; + /* signal that we are down to the interrupt handler */ adapter->state = __I40EVF_DOWN; + set_bit(__I40E_DOWN, &adapter->vsi.state); i40evf_down(adapter); @@ -1842,16 +1936,18 @@ static void i40evf_init_task(struct work_struct *work) switch (adapter->state) { case __I40EVF_STARTUP: /* driver loaded, probe complete */ + adapter->flags &= ~I40EVF_FLAG_PF_COMMS_FAILED; + adapter->flags &= ~I40EVF_FLAG_RESET_PENDING; err = i40e_set_mac_type(hw); if (err) { - dev_info(&pdev->dev, "%s: set_mac_type failed: %d\n", - __func__, err); + dev_err(&pdev->dev, "Failed to set MAC type (%d)\n", + err); goto err; } err = i40evf_check_reset_complete(hw); if (err) { - dev_info(&pdev->dev, "%s: device is still in reset (%d).\n", - __func__, err); + dev_err(&pdev->dev, "Device is still in reset (%d)\n", + err); goto err; } hw->aq.num_arq_entries = I40EVF_AQ_LEN; @@ -1861,14 +1957,14 @@ static void i40evf_init_task(struct work_struct *work) err = i40evf_init_adminq(hw); if (err) { - dev_info(&pdev->dev, "%s: init_adminq failed: %d\n", - __func__, err); + dev_err(&pdev->dev, "Failed to init Admin Queue (%d)\n", + err); goto err; } err = i40evf_send_api_ver(adapter); if (err) { - dev_info(&pdev->dev, "%s: unable to send to PF (%d)\n", - __func__, err); + dev_err(&pdev->dev, "Unable to send to PF (%d)\n", + err); i40evf_shutdown_adminq(hw); goto err; } @@ -1882,13 +1978,13 @@ static void i40evf_init_task(struct work_struct *work) /* aq msg sent, awaiting reply */ err = i40evf_verify_api_ver(adapter); if (err) { - dev_err(&pdev->dev, "Unable to verify API version, error %d\n", + dev_err(&pdev->dev, "Unable to verify API version (%d)\n", err); goto err; } err = i40evf_send_vf_config_msg(adapter); if (err) { - dev_err(&pdev->dev, "Unable send config request, error %d\n", + dev_err(&pdev->dev, "Unable send config request (%d)\n", err); goto err; } @@ -1902,18 +1998,15 @@ static void i40evf_init_task(struct work_struct *work) (I40E_MAX_VF_VSI * sizeof(struct i40e_virtchnl_vsi_resource)); adapter->vf_res = kzalloc(bufsz, GFP_KERNEL); - if (!adapter->vf_res) { - dev_err(&pdev->dev, "%s: unable to allocate memory\n", - __func__); + if (!adapter->vf_res) goto err; - } } err = i40evf_get_vf_config(adapter); if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) goto restart; if (err) { - dev_info(&pdev->dev, "%s: unable to get VF config (%d)\n", - __func__, err); + dev_err(&pdev->dev, "Unable to get VF config (%d)\n", + err); goto err_alloc; } adapter->state = __I40EVF_INIT_SW; @@ -1927,25 +2020,23 @@ static void i40evf_init_task(struct work_struct *work) adapter->vsi_res = &adapter->vf_res->vsi_res[i]; } if (!adapter->vsi_res) { - dev_info(&pdev->dev, "%s: no LAN VSI found\n", __func__); + dev_err(&pdev->dev, "No LAN VSI found\n"); goto err_alloc; } adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; - adapter->txd_count = I40EVF_DEFAULT_TXD; - adapter->rxd_count = I40EVF_DEFAULT_RXD; - netdev->netdev_ops = &i40evf_netdev_ops; i40evf_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; - - netdev->features |= NETIF_F_SG | + netdev->features |= NETIF_F_HIGHDMA | + NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_SCTP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_TSO | NETIF_F_TSO6 | + NETIF_F_RXCSUM | NETIF_F_GRO; if (adapter->vf_res->vf_offload_flags @@ -1956,11 +2047,13 @@ static void i40evf_init_task(struct work_struct *work) NETIF_F_HW_VLAN_CTAG_FILTER; } - /* The HW MAC address was set and/or determined in sw_init */ + /* copy netdev features into list of user selectable features */ + netdev->hw_features |= netdev->features; + netdev->hw_features &= ~NETIF_F_RXCSUM; + if (!is_valid_ether_addr(adapter->hw.mac.addr)) { - dev_info(&pdev->dev, - "Invalid MAC address %pMAC, using random\n", - adapter->hw.mac.addr); + dev_info(&pdev->dev, "Invalid MAC address %pMAC, using random\n", + adapter->hw.mac.addr); random_ether_addr(adapter->hw.mac.addr); } memcpy(netdev->dev_addr, adapter->hw.mac.addr, netdev->addr_len); @@ -1994,8 +2087,6 @@ static void i40evf_init_task(struct work_struct *work) netif_carrier_off(netdev); - strcpy(netdev->name, "eth%d"); - adapter->vsi.id = adapter->vsi_res->vsi_id; adapter->vsi.seid = adapter->vsi_res->vsi_id; /* dummy */ adapter->vsi.back = adapter; @@ -2005,9 +2096,11 @@ static void i40evf_init_task(struct work_struct *work) adapter->vsi.tx_itr_setting = I40E_ITR_DYNAMIC; adapter->vsi.netdev = adapter->netdev; - err = register_netdev(netdev); - if (err) - goto err_register; + if (!adapter->netdev_registered) { + err = register_netdev(netdev); + if (err) + goto err_register; + } adapter->netdev_registered = true; @@ -2031,17 +2124,16 @@ err_register: i40evf_free_misc_irq(adapter); err_sw_init: i40evf_reset_interrupt_capability(adapter); - adapter->state = __I40EVF_FAILED; err_alloc: kfree(adapter->vf_res); adapter->vf_res = NULL; err: + if (hw->aq.asq.count) + i40evf_shutdown_adminq(hw); /* ignore error */ /* Things went into the weeds, so try again later */ if (++adapter->aq_wait_count > I40EVF_AQ_MAX_ERR) { dev_err(&pdev->dev, "Failed to communicate with PF; giving up.\n"); - if (hw->aq.asq.count) - i40evf_shutdown_adminq(hw); /* ignore error */ - adapter->state = __I40EVF_FAILED; + adapter->flags |= I40EVF_FLAG_PF_COMMS_FAILED; return; /* do not reschedule */ } schedule_delayed_work(&adapter->init_task, HZ * 3); @@ -2084,20 +2176,18 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *netdev; struct i40evf_adapter *adapter = NULL; struct i40e_hw *hw = NULL; - int err, pci_using_dac; + int err; err = pci_enable_device(pdev); if (err) return err; if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(64))) { - pci_using_dac = true; /* coherent mask for the same size will always succeed if * dma_set_mask does */ dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(64)); } else if (!dma_set_mask(&pdev->dev, DMA_BIT_MASK(32))) { - pci_using_dac = false; dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); } else { dev_err(&pdev->dev, "%s: DMA configuration failed: %d\n", @@ -2128,8 +2218,6 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, netdev); adapter = netdev_priv(netdev); - if (pci_using_dac) - netdev->features |= NETIF_F_HIGHDMA; adapter->netdev = netdev; adapter->pdev = pdev; @@ -2271,6 +2359,7 @@ static void i40evf_remove(struct pci_dev *pdev) struct i40e_hw *hw = &adapter->hw; cancel_delayed_work_sync(&adapter->init_task); + cancel_work_sync(&adapter->reset_task); if (adapter->netdev_registered) { unregister_netdev(netdev); @@ -2278,17 +2367,15 @@ static void i40evf_remove(struct pci_dev *pdev) } adapter->state = __I40EVF_REMOVE; - if (adapter->num_msix_vectors) { + if (adapter->msix_entries) { i40evf_misc_irq_disable(adapter); - del_timer_sync(&adapter->watchdog_timer); - - flush_scheduled_work(); - i40evf_free_misc_irq(adapter); - i40evf_reset_interrupt_capability(adapter); } + del_timer_sync(&adapter->watchdog_timer); + flush_scheduled_work(); + if (hw->aq.asq.count) i40evf_shutdown_adminq(hw); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index e6978d79e62b..e294f012647d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -1,7 +1,7 @@ /******************************************************************************* * * Intel Ethernet Controller XL710 Family Linux Virtual Function Driver - * Copyright(c) 2013 Intel Corporation. + * 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, @@ -43,6 +43,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, struct i40e_hw *hw = &adapter->hw; i40e_status err; + if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) + return 0; /* nothing to see here, move along */ + err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); if (err) dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n", @@ -651,6 +654,18 @@ void i40evf_request_stats(struct i40evf_adapter *adapter) /* if the request failed, don't lock out others */ adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; } +/** + * i40evf_request_reset + * @adapter: adapter structure + * + * Request that the PF reset this VF. No response is expected. + **/ +void i40evf_request_reset(struct i40evf_adapter *adapter) +{ + /* Don't check CURRENT_OP - this is always higher priority */ + i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0); + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; +} /** * i40evf_virtchnl_completion @@ -689,10 +704,12 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, } break; case I40E_VIRTCHNL_EVENT_RESET_IMPENDING: - adapter->state = __I40EVF_RESETTING; - schedule_work(&adapter->reset_task); - dev_info(&adapter->pdev->dev, - "%s: hardware reset pending\n", __func__); + dev_info(&adapter->pdev->dev, "PF reset warning received\n"); + if (!(adapter->flags & I40EVF_FLAG_RESET_PENDING)) { + adapter->flags |= I40EVF_FLAG_RESET_PENDING; + dev_info(&adapter->pdev->dev, "Scheduling reset task\n"); + schedule_work(&adapter->reset_task); + } break; default: dev_err(&adapter->pdev->dev, diff --git a/drivers/net/ethernet/intel/igb/Makefile b/drivers/net/ethernet/intel/igb/Makefile index f19700e285bb..5bcb2de75933 100644 --- a/drivers/net/ethernet/intel/igb/Makefile +++ b/drivers/net/ethernet/intel/igb/Makefile @@ -1,7 +1,7 @@ ################################################################################ # # Intel 82575 PCI-Express Ethernet Linux driver -# Copyright(c) 1999 - 2013 Intel Corporation. +# Copyright(c) 1999 - 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, @@ -13,8 +13,7 @@ # more details. # # You should have received a copy of the GNU General Public License along with -# this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. +# 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index 06df6928f44c..fa36fe12e775 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -77,8 +76,6 @@ static s32 igb_update_nvm_checksum_i350(struct e1000_hw *hw); static const u16 e1000_82580_rxpbs_table[] = { 36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 }; -#define E1000_82580_RXPBS_TABLE_SIZE \ - (sizeof(e1000_82580_rxpbs_table)/sizeof(u16)) /** * igb_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO @@ -2308,7 +2305,7 @@ u16 igb_rxpbs_adjust_82580(u32 data) { u16 ret_val = 0; - if (data < E1000_82580_RXPBS_TABLE_SIZE) + if (data < ARRAY_SIZE(e1000_82580_rxpbs_table)) ret_val = e1000_82580_rxpbs_table[data]; return ret_val; @@ -2714,13 +2711,14 @@ static const u8 e1000_emc_therm_limit[4] = { E1000_EMC_DIODE3_THERM_LIMIT }; +#ifdef CONFIG_IGB_HWMON /** * igb_get_thermal_sensor_data_generic - Gathers thermal sensor data * @hw: pointer to hardware structure * * Updates the temperatures in mac.thermal_sensor_data **/ -s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw) +static s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw) { s32 status = E1000_SUCCESS; u16 ets_offset; @@ -2774,7 +2772,7 @@ s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw) * Sets the thermal sensor thresholds according to the NVM map * and save off the threshold and location values into mac.thermal_sensor_data **/ -s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw) +static s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw) { s32 status = E1000_SUCCESS; u16 ets_offset; @@ -2836,6 +2834,7 @@ s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *hw) return status; } +#endif static struct e1000_mac_operations e1000_mac_ops_82575 = { .init_hw = igb_init_hw_82575, .check_for_link = igb_check_for_link_82575, diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.h b/drivers/net/ethernet/intel/igb/e1000_82575.h index 8c2437722aad..f12b086e578d 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.h +++ b/drivers/net/ethernet/intel/igb/e1000_82575.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -266,8 +265,6 @@ u16 igb_rxpbs_adjust_82580(u32 data); s32 igb_read_emi_reg(struct e1000_hw *, u16 addr, u16 *data); s32 igb_set_eee_i350(struct e1000_hw *); s32 igb_set_eee_i354(struct e1000_hw *); -s32 igb_init_thermal_sensor_thresh_generic(struct e1000_hw *); -s32 igb_get_thermal_sensor_data_generic(struct e1000_hw *hw); #define E1000_I2C_THERMAL_SENSOR_ADDR 0xF8 #define E1000_EMC_INTERNAL_DATA 0x00 diff --git a/drivers/net/ethernet/intel/igb/e1000_defines.h b/drivers/net/ethernet/intel/igb/e1000_defines.h index 0571b973be80..393c896ac7e7 100644 --- a/drivers/net/ethernet/intel/igb/e1000_defines.h +++ b/drivers/net/ethernet/intel/igb/e1000_defines.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_hw.h b/drivers/net/ethernet/intel/igb/e1000_hw.h index ab99e2b582a8..10741d170f2d 100644 --- a/drivers/net/ethernet/intel/igb/e1000_hw.h +++ b/drivers/net/ethernet/intel/igb/e1000_hw.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.c b/drivers/net/ethernet/intel/igb/e1000_i210.c index 0c0393316a3a..db963397cc27 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.c +++ b/drivers/net/ethernet/intel/igb/e1000_i210.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -35,6 +34,8 @@ #include "e1000_hw.h" #include "e1000_i210.h" +static s32 igb_update_flash_i210(struct e1000_hw *hw); + /** * igb_get_hw_semaphore_i210 - Acquire hardware semaphore * @hw: pointer to the HW structure @@ -111,7 +112,7 @@ static s32 igb_get_hw_semaphore_i210(struct e1000_hw *hw) * Return successful if access grant bit set, else clear the request for * EEPROM access and return -E1000_ERR_NVM (-1). **/ -s32 igb_acquire_nvm_i210(struct e1000_hw *hw) +static s32 igb_acquire_nvm_i210(struct e1000_hw *hw) { return igb_acquire_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); } @@ -123,7 +124,7 @@ s32 igb_acquire_nvm_i210(struct e1000_hw *hw) * Stop any current commands to the EEPROM and clear the EEPROM request bit, * then release the semaphores acquired. **/ -void igb_release_nvm_i210(struct e1000_hw *hw) +static void igb_release_nvm_i210(struct e1000_hw *hw) { igb_release_swfw_sync_i210(hw, E1000_SWFW_EEP_SM); } @@ -206,8 +207,8 @@ void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask) * Reads a 16 bit word from the Shadow Ram using the EERD register. * Uses necessary synchronization semaphores. **/ -s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) +static s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) { s32 status = E1000_SUCCESS; u16 i, count; @@ -306,8 +307,8 @@ out: * If error code is returned, data and Shadow RAM may be inconsistent - buffer * partially written. **/ -s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data) +static s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, + u16 *data) { s32 status = E1000_SUCCESS; u16 i, count; @@ -555,7 +556,7 @@ s32 igb_read_invm_version(struct e1000_hw *hw, * Calculates the EEPROM checksum by reading/adding each word of the EEPROM * and then verifies that the sum of the EEPROM is equal to 0xBABA. **/ -s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) +static s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) { s32 status = E1000_SUCCESS; s32 (*read_op_ptr)(struct e1000_hw *, u16, u16, u16 *); @@ -590,7 +591,7 @@ s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw) * up to the checksum. Then calculates the EEPROM checksum and writes the * value to the EEPROM. Next commit EEPROM data onto the Flash. **/ -s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw) +static s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; u16 checksum = 0; @@ -684,7 +685,7 @@ bool igb_get_flash_presence_i210(struct e1000_hw *hw) * @hw: pointer to the HW structure * **/ -s32 igb_update_flash_i210(struct e1000_hw *hw) +static s32 igb_update_flash_i210(struct e1000_hw *hw) { s32 ret_val = E1000_SUCCESS; u32 flup; diff --git a/drivers/net/ethernet/intel/igb/e1000_i210.h b/drivers/net/ethernet/intel/igb/e1000_i210.h index 2d913716573a..907fe99a9813 100644 --- a/drivers/net/ethernet/intel/igb/e1000_i210.h +++ b/drivers/net/ethernet/intel/igb/e1000_i210.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -28,17 +27,8 @@ #ifndef _E1000_I210_H_ #define _E1000_I210_H_ -s32 igb_update_flash_i210(struct e1000_hw *hw); -s32 igb_update_nvm_checksum_i210(struct e1000_hw *hw); -s32 igb_validate_nvm_checksum_i210(struct e1000_hw *hw); -s32 igb_write_nvm_srwr_i210(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); -s32 igb_read_nvm_srrd_i210(struct e1000_hw *hw, u16 offset, u16 words, - u16 *data); s32 igb_acquire_swfw_sync_i210(struct e1000_hw *hw, u16 mask); void igb_release_swfw_sync_i210(struct e1000_hw *hw, u16 mask); -s32 igb_acquire_nvm_i210(struct e1000_hw *hw); -void igb_release_nvm_i210(struct e1000_hw *hw); s32 igb_valid_led_default_i210(struct e1000_hw *hw, u16 *data); s32 igb_read_invm_version(struct e1000_hw *hw, struct e1000_fw_version *invm_ver); diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.c b/drivers/net/ethernet/intel/igb/e1000_mac.c index 298f0ed50670..5910a932ea7c 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.c +++ b/drivers/net/ethernet/intel/igb/e1000_mac.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_mac.h b/drivers/net/ethernet/intel/igb/e1000_mac.h index e4cbe8ef67b3..99299ba8ee3a 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mac.h +++ b/drivers/net/ethernet/intel/igb/e1000_mac.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.c b/drivers/net/ethernet/intel/igb/e1000_mbx.c index dac1447fabf7..d5b121771c31 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mbx.c +++ b/drivers/net/ethernet/intel/igb/e1000_mbx.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_mbx.h b/drivers/net/ethernet/intel/igb/e1000_mbx.h index de9bba41acf3..f52f5515e5a8 100644 --- a/drivers/net/ethernet/intel/igb/e1000_mbx.h +++ b/drivers/net/ethernet/intel/igb/e1000_mbx.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.c b/drivers/net/ethernet/intel/igb/e1000_nvm.c index a7db7f3db914..9abf82919c65 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.c +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_nvm.h b/drivers/net/ethernet/intel/igb/e1000_nvm.h index 433b7419cb98..5b101170b17e 100644 --- a/drivers/net/ethernet/intel/igb/e1000_nvm.h +++ b/drivers/net/ethernet/intel/igb/e1000_nvm.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index ad2b74d95138..4009bbab7407 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -394,77 +393,6 @@ s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data) } /** - * e1000_write_sfp_data_byte - Writes SFP module data. - * @hw: pointer to the HW structure - * @offset: byte location offset to write to - * @data: data to write - * - * Writes one byte to SFP module data stored - * in SFP resided EEPROM memory or SFP diagnostic area. - * Function should be called with - * E1000_I2CCMD_SFP_DATA_ADDR(<byte offset>) for SFP module database access - * E1000_I2CCMD_SFP_DIAG_ADDR(<byte offset>) for SFP diagnostics parameters - * access - **/ -s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data) -{ - u32 i = 0; - u32 i2ccmd = 0; - u32 data_local = 0; - - if (offset > E1000_I2CCMD_SFP_DIAG_ADDR(255)) { - hw_dbg("I2CCMD command address exceeds upper limit\n"); - return -E1000_ERR_PHY; - } - /* The programming interface is 16 bits wide - * so we need to read the whole word first - * then update appropriate byte lane and write - * the updated word back. - */ - /* Set up Op-code, EEPROM Address,in the I2CCMD - * register. The MAC will take care of interfacing - * with an EEPROM to write the data given. - */ - i2ccmd = ((offset << E1000_I2CCMD_REG_ADDR_SHIFT) | - E1000_I2CCMD_OPCODE_READ); - /* Set a command to read single word */ - wr32(E1000_I2CCMD, i2ccmd); - for (i = 0; i < E1000_I2CCMD_PHY_TIMEOUT; i++) { - udelay(50); - /* Poll the ready bit to see if lastly - * launched I2C operation completed - */ - i2ccmd = rd32(E1000_I2CCMD); - if (i2ccmd & E1000_I2CCMD_READY) { - /* Check if this is READ or WRITE phase */ - if ((i2ccmd & E1000_I2CCMD_OPCODE_READ) == - E1000_I2CCMD_OPCODE_READ) { - /* Write the selected byte - * lane and update whole word - */ - data_local = i2ccmd & 0xFF00; - data_local |= data; - i2ccmd = ((offset << - E1000_I2CCMD_REG_ADDR_SHIFT) | - E1000_I2CCMD_OPCODE_WRITE | data_local); - wr32(E1000_I2CCMD, i2ccmd); - } else { - break; - } - } - } - if (!(i2ccmd & E1000_I2CCMD_READY)) { - hw_dbg("I2CCMD Write did not complete\n"); - return -E1000_ERR_PHY; - } - if (i2ccmd & E1000_I2CCMD_ERROR) { - hw_dbg("I2CCMD Error bit set\n"); - return -E1000_ERR_PHY; - } - return 0; -} - -/** * igb_read_phy_reg_igp - Read igp PHY register * @hw: pointer to the HW structure * @offset: register offset to be read diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.h b/drivers/net/ethernet/intel/igb/e1000_phy.h index 6a0873f2095a..4c2c36c46a73 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.h +++ b/drivers/net/ethernet/intel/igb/e1000_phy.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -70,7 +69,6 @@ s32 igb_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data); s32 igb_read_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 *data); s32 igb_write_phy_reg_i2c(struct e1000_hw *hw, u32 offset, u16 data); s32 igb_read_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 *data); -s32 e1000_write_sfp_data_byte(struct e1000_hw *hw, u16 offset, u8 data); s32 igb_copper_link_setup_82580(struct e1000_hw *hw); s32 igb_get_phy_info_82580(struct e1000_hw *hw); s32 igb_phy_force_speed_duplex_82580(struct e1000_hw *hw); diff --git a/drivers/net/ethernet/intel/igb/e1000_regs.h b/drivers/net/ethernet/intel/igb/e1000_regs.h index 82632c6c53af..abdd935a9dad 100644 --- a/drivers/net/ethernet/intel/igb/e1000_regs.h +++ b/drivers/net/ethernet/intel/igb/e1000_regs.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index ccf472f073dd..fc3fc2c6fe40 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -525,9 +524,7 @@ void igb_set_fw_version(struct igb_adapter *); void igb_ptp_init(struct igb_adapter *adapter); void igb_ptp_stop(struct igb_adapter *adapter); void igb_ptp_reset(struct igb_adapter *adapter); -void igb_ptp_tx_work(struct work_struct *work); void igb_ptp_rx_hang(struct igb_adapter *adapter); -void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter); void igb_ptp_rx_rgtstamp(struct igb_q_vector *q_vector, struct sk_buff *skb); void igb_ptp_rx_pktstamp(struct igb_q_vector *q_vector, unsigned char *va, struct sk_buff *skb); diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 1df02378de69..c7f574165298 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/igb_hwmon.c b/drivers/net/ethernet/intel/igb/igb_hwmon.c index e0af5bc61613..8333f67acf96 100644 --- a/drivers/net/ethernet/intel/igb/igb_hwmon.c +++ b/drivers/net/ethernet/intel/igb/igb_hwmon.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 46d31a49f5ea..3384156cf1b5 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel(R) Gigabit Ethernet Linux driver - Copyright(c) 2007-2013 Intel Corporation. + Copyright(c) 2007-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, @@ -13,8 +13,7 @@ more details. You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., - 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + 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". @@ -70,7 +69,7 @@ char igb_driver_version[] = DRV_VERSION; static const char igb_driver_string[] = "Intel(R) Gigabit Ethernet Network Driver"; static const char igb_copyright[] = - "Copyright (c) 2007-2013 Intel Corporation."; + "Copyright (c) 2007-2014 Intel Corporation."; static const struct e1000_info *igb_info_tbl[] = { [board_82575] = &e1000_82575_info, @@ -1111,10 +1110,11 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter, bool msix) for (i = 0; i < numvecs; i++) adapter->msix_entries[i].entry = i; - err = pci_enable_msix(adapter->pdev, - adapter->msix_entries, - numvecs); - if (err == 0) + err = pci_enable_msix_range(adapter->pdev, + adapter->msix_entries, + numvecs, + numvecs); + if (err > 0) return; igb_reset_interrupt_capability(adapter); diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c index 5a54e3dc535d..9c9c141f089a 100644 --- a/drivers/net/ethernet/intel/igb/igb_ptp.c +++ b/drivers/net/ethernet/intel/igb/igb_ptp.c @@ -12,9 +12,8 @@ * 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, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * You should have received a copy of the GNU General Public License along with + * this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> #include <linux/device.h> @@ -75,6 +74,8 @@ #define INCVALUE_82576 (16 << IGB_82576_TSYNC_SHIFT) #define IGB_NBITS_82580 40 +static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter); + /* SYSTIM read access for the 82576 */ static cycle_t igb_ptp_read_82576(const struct cyclecounter *cc) { @@ -372,7 +373,7 @@ static int igb_ptp_enable(struct ptp_clock_info *ptp, * This work function polls the TSYNCTXCTL valid bit to determine when a * timestamp has been taken for the current stored skb. **/ -void igb_ptp_tx_work(struct work_struct *work) +static void igb_ptp_tx_work(struct work_struct *work) { struct igb_adapter *adapter = container_of(work, struct igb_adapter, ptp_tx_work); @@ -466,7 +467,7 @@ void igb_ptp_rx_hang(struct igb_adapter *adapter) * available, then it must have been for this skb here because we only * allow only one such packet into the queue. **/ -void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) +static void igb_ptp_tx_hwtstamp(struct igb_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; struct skb_shared_hwtstamps shhwtstamps; diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c index 675435fc2e53..e2c6d8059b74 100644 --- a/drivers/net/ethernet/intel/igbvf/netdev.c +++ b/drivers/net/ethernet/intel/igbvf/netdev.c @@ -1043,11 +1043,11 @@ static void igbvf_set_interrupt_capability(struct igbvf_adapter *adapter) for (i = 0; i < 3; i++) adapter->msix_entries[i].entry = i; - err = pci_enable_msix(adapter->pdev, - adapter->msix_entries, 3); + err = pci_enable_msix_range(adapter->pdev, + adapter->msix_entries, 3, 3); } - if (err) { + if (err < 0) { /* MSI-X failed */ dev_err(&adapter->pdev->dev, "Failed to initialize MSI-X interrupts.\n"); diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c index 57e390cbe6d0..f42c201f727f 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c @@ -1521,12 +1521,12 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) int tso; if (test_bit(__IXGB_DOWN, &adapter->flags)) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } if (skb->len <= 0) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } @@ -1543,7 +1543,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tso = ixgb_tso(adapter, skb); if (tso < 0) { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 0186ea2969fe..4371ef0ed4a0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -765,6 +765,7 @@ struct ixgbe_adapter { struct ptp_clock_info ptp_caps; struct work_struct ptp_tx_work; struct sk_buff *ptp_tx_skb; + struct hwtstamp_config tstamp_config; unsigned long ptp_tx_start; unsigned long last_overflow_check; unsigned long last_rx_ptp_check; @@ -884,7 +885,6 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, u16 soft_id); void ixgbe_atr_compute_perfect_hash_82599(union ixgbe_atr_input *input, union ixgbe_atr_input *mask); -bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); void ixgbe_set_rx_mode(struct net_device *netdev); #ifdef CONFIG_IXGBE_DCB void ixgbe_set_rx_drop_en(struct ixgbe_adapter *adapter); @@ -958,8 +958,8 @@ static inline void ixgbe_ptp_rx_hwtstamp(struct ixgbe_ring *rx_ring, rx_ring->last_rx_timestamp = jiffies; } -int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, struct ifreq *ifr, - int cmd); +int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr); +int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr); void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter); void ixgbe_ptp_reset(struct ixgbe_adapter *adapter); void ixgbe_ptp_check_pps_event(struct ixgbe_adapter *adapter, u32 eicr); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c index a26f3fee4f35..15506f0780b2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82598.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -61,6 +61,9 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) u32 gcr = IXGBE_READ_REG(hw, IXGBE_GCR); u16 pcie_devctl2; + if (ixgbe_removed(hw->hw_addr)) + return; + /* only take action if timeout value is defaulted to 0 */ if (gcr & IXGBE_GCR_CMPL_TMOUT_MASK) goto out; @@ -79,8 +82,9 @@ static void ixgbe_set_pcie_completion_timeout(struct ixgbe_hw *hw) * directly in order to set the completion timeout value for * 16ms to 55ms */ - pci_read_config_word(adapter->pdev, - IXGBE_PCI_DEVICE_CONTROL2, &pcie_devctl2); + pcie_devctl2 = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_CONTROL2); + if (ixgbe_removed(hw->hw_addr)) + return; pcie_devctl2 |= IXGBE_PCI_DEVICE_CONTROL2_16ms; pci_write_config_word(adapter->pdev, IXGBE_PCI_DEVICE_CONTROL2, pcie_devctl2); @@ -1316,6 +1320,8 @@ static struct ixgbe_mac_operations mac_ops_82598 = { .get_thermal_sensor_data = NULL, .init_thermal_sensor_thresh = NULL, .mng_fw_enabled = NULL, + .prot_autoc_read = &prot_autoc_read_generic, + .prot_autoc_write = &prot_autoc_write_generic, }; static struct ixgbe_eeprom_operations eeprom_ops_82598 = { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index edda6814108c..b96cefd5a2eb 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -63,6 +63,8 @@ static s32 ixgbe_read_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 *data); static s32 ixgbe_write_i2c_byte_82599(struct ixgbe_hw *hw, u8 byte_offset, u8 dev_addr, u8 data); +static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw); static bool ixgbe_mng_enabled(struct ixgbe_hw *hw) { @@ -122,7 +124,6 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) { s32 ret_val = 0; u16 list_offset, data_offset, data_value; - bool got_lock = false; if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) { ixgbe_init_mac_link_ops_82599(hw); @@ -160,30 +161,10 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw) usleep_range(hw->eeprom.semaphore_delay * 1000, hw->eeprom.semaphore_delay * 2000); - /* Need SW/FW semaphore around AUTOC writes if LESM on, - * likewise reset_pipeline requires lock as it also writes - * AUTOC. - */ - if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { - ret_val = hw->mac.ops.acquire_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - if (ret_val) - goto setup_sfp_out; - - got_lock = true; - } - /* Restart DSP and set SFI mode */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((hw->mac.orig_autoc) | - IXGBE_AUTOC_LMS_10G_SERIAL)); - hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); - ret_val = ixgbe_reset_pipeline_82599(hw); - - if (got_lock) { - hw->mac.ops.release_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - got_lock = false; - } + ret_val = hw->mac.ops.prot_autoc_write(hw, + hw->mac.orig_autoc | IXGBE_AUTOC_LMS_10G_SERIAL, + false); if (ret_val) { hw_dbg(hw, " sfp module setup not complete\n"); @@ -207,6 +188,79 @@ setup_sfp_err: return IXGBE_ERR_SFP_SETUP_NOT_COMPLETE; } +/** + * prot_autoc_read_82599 - Hides MAC differences needed for AUTOC read + * @hw: pointer to hardware structure + * @locked: Return the if we locked for this read. + * @reg_val: Value we read from AUTOC + * + * For this part (82599) we need to wrap read-modify-writes with a possible + * FW/SW lock. It is assumed this lock will be freed with the next + * prot_autoc_write_82599(). Note, that locked can only be true in cases + * where this function doesn't return an error. + **/ +static s32 prot_autoc_read_82599(struct ixgbe_hw *hw, bool *locked, + u32 *reg_val) +{ + s32 ret_val; + + *locked = false; + /* If LESM is on then we need to hold the SW/FW semaphore. */ + if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (!ret_val) + return IXGBE_ERR_SWFW_SYNC; + + *locked = true; + } + + *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC); + return 0; +} + +/** + * prot_autoc_write_82599 - Hides MAC differences needed for AUTOC write + * @hw: pointer to hardware structure + * @reg_val: value to write to AUTOC + * @locked: bool to indicate whether the SW/FW lock was already taken by + * previous proc_autoc_read_82599. + * + * This part (82599) may need to hold a the SW/FW lock around all writes to + * AUTOC. Likewise after a write we need to do a pipeline reset. + **/ +static s32 prot_autoc_write_82599(struct ixgbe_hw *hw, u32 autoc, bool locked) +{ + s32 ret_val = 0; + + /* Blocked by MNG FW so bail */ + if (ixgbe_check_reset_blocked(hw)) + goto out; + + /* We only need to get the lock if: + * - We didn't do it already (in the read part of a read-modify-write) + * - LESM is enabled. + */ + if (!locked && ixgbe_verify_lesm_fw_enabled_82599(hw)) { + ret_val = hw->mac.ops.acquire_swfw_sync(hw, + IXGBE_GSSR_MAC_CSR_SM); + if (!ret_val) + return IXGBE_ERR_SWFW_SYNC; + } + + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); + ret_val = ixgbe_reset_pipeline_82599(hw); + +out: + /* Free the SW/FW semaphore as we either grabbed it here or + * already had it when this function was called. + */ + if (locked) + hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + + return ret_val; +} + static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; @@ -542,6 +596,10 @@ static void ixgbe_disable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) { u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP); + /* Blocked by MNG FW so bail */ + if (ixgbe_check_reset_blocked(hw)) + return; + /* Disable tx laser; allow 100us to go dark per spec */ esdp_reg |= IXGBE_ESDP_SDP3; IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg); @@ -582,6 +640,10 @@ static void ixgbe_enable_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) **/ static void ixgbe_flap_tx_laser_multispeed_fiber(struct ixgbe_hw *hw) { + /* Blocked by MNG FW so bail */ + if (ixgbe_check_reset_blocked(hw)) + return; + if (hw->mac.autotry_restart) { ixgbe_disable_tx_laser_multispeed_fiber(hw); ixgbe_enable_tx_laser_multispeed_fiber(hw); @@ -966,7 +1028,6 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, u32 links_reg; u32 i; ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN; - bool got_lock = false; bool autoneg = false; /* Check to see if speed passed in is supported. */ @@ -989,7 +1050,7 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); orig_autoc = autoc; - start_autoc = hw->mac.cached_autoc; + start_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); link_mode = autoc & IXGBE_AUTOC_LMS_MASK; pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK; @@ -1030,27 +1091,10 @@ static s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw, } if (autoc != start_autoc) { - /* Need SW/FW semaphore around AUTOC writes if LESM is on, - * likewise reset_pipeline requires us to hold this lock as - * it also writes to AUTOC. - */ - if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { - status = hw->mac.ops.acquire_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - if (status != 0) - goto out; - - got_lock = true; - } - /* Restart link */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc); - hw->mac.cached_autoc = autoc; - ixgbe_reset_pipeline_82599(hw); - - if (got_lock) - hw->mac.ops.release_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); + status = hw->mac.ops.prot_autoc_write(hw, autoc, false); + if (!status) + goto out; /* Only poll for autoneg to complete if specified to do so */ if (autoneg_wait_to_complete) { @@ -1117,7 +1161,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) { ixgbe_link_speed link_speed; s32 status; - u32 ctrl, i, autoc2; + u32 ctrl, i, autoc, autoc2; u32 curr_lms; bool link_up = false; @@ -1151,11 +1195,7 @@ static s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw) hw->phy.ops.reset(hw); /* remember AUTOC from before we reset */ - if (hw->mac.cached_autoc) - curr_lms = hw->mac.cached_autoc & IXGBE_AUTOC_LMS_MASK; - else - curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) & - IXGBE_AUTOC_LMS_MASK; + curr_lms = IXGBE_READ_REG(hw, IXGBE_AUTOC) & IXGBE_AUTOC_LMS_MASK; mac_reset_top: /* @@ -1205,7 +1245,7 @@ mac_reset_top: * stored off yet. Otherwise restore the stored original * values since the reset operation sets back to defaults. */ - hw->mac.cached_autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); + autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC); autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2); /* Enable link if disabled in NVM */ @@ -1216,7 +1256,7 @@ mac_reset_top: } if (hw->mac.orig_link_settings_stored == false) { - hw->mac.orig_autoc = hw->mac.cached_autoc; + hw->mac.orig_autoc = autoc; hw->mac.orig_autoc2 = autoc2; hw->mac.orig_link_settings_stored = true; } else { @@ -1233,28 +1273,12 @@ mac_reset_top: (hw->mac.orig_autoc & ~IXGBE_AUTOC_LMS_MASK) | curr_lms; - if (hw->mac.cached_autoc != hw->mac.orig_autoc) { - /* Need SW/FW semaphore around AUTOC writes if LESM is - * on, likewise reset_pipeline requires us to hold - * this lock as it also writes to AUTOC. - */ - bool got_lock = false; - if (ixgbe_verify_lesm_fw_enabled_82599(hw)) { - status = hw->mac.ops.acquire_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - if (status) - goto reset_hw_out; - - got_lock = true; - } - - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, hw->mac.orig_autoc); - hw->mac.cached_autoc = hw->mac.orig_autoc; - ixgbe_reset_pipeline_82599(hw); - - if (got_lock) - hw->mac.ops.release_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); + if (autoc != hw->mac.orig_autoc) { + status = hw->mac.ops.prot_autoc_write(hw, + hw->mac.orig_autoc, + false); + if (!status) + goto reset_hw_out; } if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) != @@ -2260,7 +2284,7 @@ fw_version_err: * Returns true if the LESM FW module is present and enabled. Otherwise * returns false. Smart Speed must be disabled if LESM FW module is enabled. **/ -bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) +static bool ixgbe_verify_lesm_fw_enabled_82599(struct ixgbe_hw *hw) { bool lesm_enabled = false; u16 fw_offset, fw_lesm_param_offset, fw_lesm_state; @@ -2366,7 +2390,7 @@ static s32 ixgbe_read_eeprom_82599(struct ixgbe_hw *hw, * full pipeline reset. Note - We must hold the SW/FW semaphore before writing * to AUTOC, so this function assumes the semaphore is held. **/ -s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) +static s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) { s32 ret_val; u32 anlp1_reg = 0; @@ -2380,11 +2404,12 @@ s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw) IXGBE_WRITE_FLUSH(hw); } - autoc_reg = hw->mac.cached_autoc; + autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); autoc_reg |= IXGBE_AUTOC_AN_RESTART; /* Write AUTOC register with toggled LMS[2] bit and Restart_AN */ - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg ^ IXGBE_AUTOC_LMS_1G_AN); + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, + autoc_reg ^ (0x4 << IXGBE_AUTOC_LMS_SHIFT)); /* Wait for AN to leave state 0 */ for (i = 0; i < 10; i++) { @@ -2566,6 +2591,8 @@ static struct ixgbe_mac_operations mac_ops_82599 = { .get_thermal_sensor_data = &ixgbe_get_thermal_sensor_data_generic, .init_thermal_sensor_thresh = &ixgbe_init_thermal_sensor_thresh_generic, .mng_fw_enabled = &ixgbe_mng_enabled, + .prot_autoc_read = &prot_autoc_read_82599, + .prot_autoc_write = &prot_autoc_write_82599, }; static struct ixgbe_eeprom_operations eeprom_ops_82599 = { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index b5c434b617b1..4456c235a44a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -114,7 +114,7 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) s32 ret_val = 0; u32 reg = 0, reg_bp = 0; u16 reg_cu = 0; - bool got_lock = false; + bool locked = false; /* * Validate the requested mode. Strict IEEE mode does not allow @@ -139,11 +139,17 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) * we link at 10G, the 1G advertisement is harmless and vice versa. */ switch (hw->phy.media_type) { + case ixgbe_media_type_backplane: + /* some MAC's need RMW protection on AUTOC */ + ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, ®_bp); + if (!ret_val) + goto out; + + /* only backplane uses autoc so fall though */ case ixgbe_media_type_fiber_fixed: case ixgbe_media_type_fiber: - case ixgbe_media_type_backplane: reg = IXGBE_READ_REG(hw, IXGBE_PCS1GANA); - reg_bp = IXGBE_READ_REG(hw, IXGBE_AUTOC); + break; case ixgbe_media_type_copper: hw->phy.ops.read_reg(hw, MDIO_AN_ADVERTISE, @@ -240,27 +246,12 @@ static s32 ixgbe_setup_fc(struct ixgbe_hw *hw) * LESM is on, likewise reset_pipeline requries the lock as * it also writes AUTOC. */ - if ((hw->mac.type == ixgbe_mac_82599EB) && - ixgbe_verify_lesm_fw_enabled_82599(hw)) { - ret_val = hw->mac.ops.acquire_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - if (ret_val) - goto out; - - got_lock = true; - } - - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_bp); - - if (hw->mac.type == ixgbe_mac_82599EB) - ixgbe_reset_pipeline_82599(hw); - - if (got_lock) - hw->mac.ops.release_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); + ret_val = hw->mac.ops.prot_autoc_write(hw, reg_bp, locked); + if (ret_val) + goto out; } else if ((hw->phy.media_type == ixgbe_media_type_copper) && - ixgbe_device_supports_autoneg_fc(hw)) { + ixgbe_device_supports_autoneg_fc(hw)) { hw->phy.ops.write_reg(hw, MDIO_AN_ADVERTISE, MDIO_MMD_AN, reg_cu); } @@ -2437,6 +2428,55 @@ out: } /** + * ixgbe_pcie_timeout_poll - Return number of times to poll for completion + * @hw: pointer to hardware structure + * + * System-wide timeout range is encoded in PCIe Device Control2 register. + * + * Add 10% to specified maximum and return the number of times to poll for + * completion timeout, in units of 100 microsec. Never return less than + * 800 = 80 millisec. + **/ +static u32 ixgbe_pcie_timeout_poll(struct ixgbe_hw *hw) +{ + struct ixgbe_adapter *adapter = hw->back; + s16 devctl2; + u32 pollcnt; + + pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_CONTROL2, + &devctl2); + devctl2 &= IXGBE_PCIDEVCTRL2_TIMEO_MASK; + + switch (devctl2) { + case IXGBE_PCIDEVCTRL2_65_130ms: + pollcnt = 1300; /* 130 millisec */ + break; + case IXGBE_PCIDEVCTRL2_260_520ms: + pollcnt = 5200; /* 520 millisec */ + break; + case IXGBE_PCIDEVCTRL2_1_2s: + pollcnt = 20000; /* 2 sec */ + break; + case IXGBE_PCIDEVCTRL2_4_8s: + pollcnt = 80000; /* 8 sec */ + break; + case IXGBE_PCIDEVCTRL2_17_34s: + pollcnt = 34000; /* 34 sec */ + break; + case IXGBE_PCIDEVCTRL2_50_100us: /* 100 microsecs */ + case IXGBE_PCIDEVCTRL2_1_2ms: /* 2 millisecs */ + case IXGBE_PCIDEVCTRL2_16_32ms: /* 32 millisec */ + case IXGBE_PCIDEVCTRL2_16_32ms_def: /* 32 millisec default */ + default: + pollcnt = 800; /* 80 millisec minimum */ + break; + } + + /* add 10% to spec maximum */ + return (pollcnt * 11) / 10; +} + +/** * ixgbe_disable_pcie_master - Disable PCI-express master access * @hw: pointer to hardware structure * @@ -2447,16 +2487,16 @@ out: **/ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) { - struct ixgbe_adapter *adapter = hw->back; s32 status = 0; - u32 i; + u32 i, poll; u16 value; /* Always set this bit to ensure any future transactions are blocked */ IXGBE_WRITE_REG(hw, IXGBE_CTRL, IXGBE_CTRL_GIO_DIS); /* Exit if master requests are blocked */ - if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO)) + if (!(IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_GIO) || + ixgbe_removed(hw->hw_addr)) goto out; /* Poll for master request bit to clear */ @@ -2481,10 +2521,12 @@ static s32 ixgbe_disable_pcie_master(struct ixgbe_hw *hw) * Before proceeding, make sure that the PCIe block does not have * transactions pending. */ - for (i = 0; i < IXGBE_PCI_MASTER_DISABLE_TIMEOUT; i++) { + poll = ixgbe_pcie_timeout_poll(hw); + for (i = 0; i < poll; i++) { udelay(100); - pci_read_config_word(adapter->pdev, IXGBE_PCI_DEVICE_STATUS, - &value); + value = ixgbe_read_pci_cfg_word(hw, IXGBE_PCI_DEVICE_STATUS); + if (ixgbe_removed(hw->hw_addr)) + goto out; if (!(value & IXGBE_PCI_DEVICE_STATUS_TRANSACTION_PENDING)) goto out; } @@ -2564,6 +2606,35 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask) } /** + * prot_autoc_read_generic - Hides MAC differences needed for AUTOC read + * @hw: pointer to hardware structure + * @reg_val: Value we read from AUTOC + * @locked: bool to indicate whether the SW/FW lock should be taken. Never + * true in this the generic case. + * + * The default case requires no protection so just to the register read. + **/ +s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *locked, u32 *reg_val) +{ + *locked = false; + *reg_val = IXGBE_READ_REG(hw, IXGBE_AUTOC); + return 0; +} + +/** + * prot_autoc_write_generic - Hides MAC differences needed for AUTOC write + * @hw: pointer to hardware structure + * @reg_val: value to write to AUTOC + * @locked: bool to indicate whether the SW/FW lock was already taken by + * previous read. + **/ +s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked) +{ + IXGBE_WRITE_REG(hw, IXGBE_AUTOC, reg_val); + return 0; +} + +/** * ixgbe_disable_rx_buff_generic - Stops the receive data path * @hw: pointer to hardware structure * @@ -2641,6 +2712,7 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); s32 ret_val = 0; + bool locked = false; /* * Link must be up to auto-blink the LEDs; @@ -2649,28 +2721,19 @@ s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index) hw->mac.ops.check_link(hw, &speed, &link_up, false); if (!link_up) { - /* Need the SW/FW semaphore around AUTOC writes if 82599 and - * LESM is on. - */ - bool got_lock = false; - - if ((hw->mac.type == ixgbe_mac_82599EB) && - ixgbe_verify_lesm_fw_enabled_82599(hw)) { - ret_val = hw->mac.ops.acquire_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - if (ret_val) - goto out; + ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); + if (!ret_val) + goto out; - got_lock = true; - } autoc_reg |= IXGBE_AUTOC_AN_RESTART; autoc_reg |= IXGBE_AUTOC_FLU; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); + + ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked); + if (!ret_val) + goto out; + IXGBE_WRITE_FLUSH(hw); - if (got_lock) - hw->mac.ops.release_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); usleep_range(10000, 20000); } @@ -2690,33 +2753,21 @@ out: **/ s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index) { - u32 autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC); + u32 autoc_reg = 0; u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL); s32 ret_val = 0; - bool got_lock = false; + bool locked = false; - /* Need the SW/FW semaphore around AUTOC writes if 82599 and - * LESM is on. - */ - if ((hw->mac.type == ixgbe_mac_82599EB) && - ixgbe_verify_lesm_fw_enabled_82599(hw)) { - ret_val = hw->mac.ops.acquire_swfw_sync(hw, - IXGBE_GSSR_MAC_CSR_SM); - if (ret_val) - goto out; - - got_lock = true; - } + ret_val = hw->mac.ops.prot_autoc_read(hw, &locked, &autoc_reg); + if (!ret_val) + goto out; autoc_reg &= ~IXGBE_AUTOC_FLU; autoc_reg |= IXGBE_AUTOC_AN_RESTART; - IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg); - - if (hw->mac.type == ixgbe_mac_82599EB) - ixgbe_reset_pipeline_82599(hw); - if (got_lock) - hw->mac.ops.release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM); + ret_val = hw->mac.ops.prot_autoc_write(hw, autoc_reg, locked); + if (!ret_val) + goto out; led_reg &= ~IXGBE_LED_MODE_MASK(index); led_reg &= ~IXGBE_LED_BLINK(index); @@ -2817,7 +2868,6 @@ san_mac_addr_clr: **/ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) { - struct ixgbe_adapter *adapter = hw->back; u16 msix_count = 1; u16 max_msix_count; u16 pcie_offset; @@ -2836,7 +2886,9 @@ u16 ixgbe_get_pcie_msix_count_generic(struct ixgbe_hw *hw) return msix_count; } - pci_read_config_word(adapter->pdev, pcie_offset, &msix_count); + msix_count = ixgbe_read_pci_cfg_word(hw, pcie_offset); + if (ixgbe_removed(hw->hw_addr)) + msix_count = 0; msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK; /* MSI-X count is zero-based in HW */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index f2e3919750ec..ef0fd4cef5df 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -98,6 +98,10 @@ s32 ixgbe_check_mac_link_generic(struct ixgbe_hw *hw, bool *link_up, bool link_up_wait_to_complete); s32 ixgbe_get_wwn_prefix_generic(struct ixgbe_hw *hw, u16 *wwnn_prefix, u16 *wwpn_prefix); + +s32 prot_autoc_read_generic(struct ixgbe_hw *hw, bool *, u32 *reg_val); +s32 prot_autoc_write_generic(struct ixgbe_hw *hw, u32 reg_val, bool locked); + s32 ixgbe_blink_led_start_generic(struct ixgbe_hw *hw, u32 index); s32 ixgbe_blink_led_stop_generic(struct ixgbe_hw *hw, u32 index); void ixgbe_set_mac_anti_spoofing(struct ixgbe_hw *hw, bool enable, int pf); @@ -109,7 +113,6 @@ void ixgbe_clear_tx_pending(struct ixgbe_hw *hw); void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb, u32 headroom, int strategy); -s32 ixgbe_reset_pipeline_82599(struct ixgbe_hw *hw); #define IXGBE_I2C_THERMAL_SENSOR_ADDR 0xF8 #define IXGBE_EMC_INTERNAL_DATA 0x00 @@ -125,6 +128,10 @@ s32 ixgbe_get_thermal_sensor_data_generic(struct ixgbe_hw *hw); s32 ixgbe_init_thermal_sensor_thresh_generic(struct ixgbe_hw *hw); #define IXGBE_FAILED_READ_REG 0xffffffffU +#define IXGBE_FAILED_READ_CFG_DWORD 0xffffffffU +#define IXGBE_FAILED_READ_CFG_WORD 0xffffU + +u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg); static inline bool ixgbe_removed(void __iomem *addr) { diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index 043307024c4a..f2d35c04159c 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -1247,6 +1247,11 @@ static int ixgbe_link_test(struct ixgbe_adapter *adapter, u64 *data) struct ixgbe_hw *hw = &adapter->hw; bool link_up; u32 link_speed = 0; + + if (ixgbe_removed(hw->hw_addr)) { + *data = 1; + return 1; + } *data = 0; hw->mac.ops.check_link(hw, &link_speed, &link_up, true); @@ -1969,6 +1974,7 @@ static void ixgbe_diag_test(struct net_device *netdev, data[1] = 1; data[2] = 1; data[3] = 1; + data[4] = 1; eth_test->flags |= ETH_TEST_FL_FAILED; return; } @@ -1988,6 +1994,7 @@ static void ixgbe_diag_test(struct net_device *netdev, data[1] = 1; data[2] = 1; data[3] = 1; + data[4] = 1; eth_test->flags |= ETH_TEST_FL_FAILED; clear_bit(__IXGBE_TESTING, &adapter->state); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c index 32e3eaaa160a..0834e1ea44bc 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_lib.c @@ -698,7 +698,7 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, int vectors) { - int err, vector_threshold; + int vector_threshold; /* We'll want at least 2 (vector_threshold): * 1) TxQ[0] + RxQ[0] handler @@ -712,18 +712,10 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, * Right now, we simply care about how many we'll get; we'll * set them up later while requesting irq's. */ - while (vectors >= vector_threshold) { - err = pci_enable_msix(adapter->pdev, adapter->msix_entries, - vectors); - if (!err) /* Success in acquiring all requested vectors. */ - break; - else if (err < 0) - vectors = 0; /* Nasty failure, quit now */ - else /* err == number of vectors we should try again with */ - vectors = err; - } + vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + vector_threshold, vectors); - if (vectors < vector_threshold) { + if (vectors < 0) { /* Can't allocate enough MSI-X interrupts? Oh well. * This just means we'll go with either a single MSI * vector or fall back to legacy interrupts. diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 6d4ada72dfd0..10b35d82e309 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -67,7 +67,7 @@ static char ixgbe_default_device_descr[] = #define DRV_VERSION "3.19.1-k" const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = - "Copyright (c) 1999-2013 Intel Corporation."; + "Copyright (c) 1999-2014 Intel Corporation."; static const struct ixgbe_info *ixgbe_info_tbl[] = { [board_82598] = &ixgbe_82598_info, @@ -151,6 +151,8 @@ MODULE_DESCRIPTION("Intel(R) 10 Gigabit PCI Express Network Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev); + static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter, u32 reg, u16 *value) { @@ -169,6 +171,9 @@ static int ixgbe_read_pci_cfg_word_parent(struct ixgbe_adapter *adapter, return -1; pcie_capability_read_word(parent_dev, reg, value); + if (*value == IXGBE_FAILED_READ_CFG_WORD && + ixgbe_check_cfg_remove(&adapter->hw, parent_dev)) + return -1; return 0; } @@ -313,6 +318,48 @@ void ixgbe_check_remove(struct ixgbe_hw *hw, u32 reg) ixgbe_remove_adapter(hw); } +static bool ixgbe_check_cfg_remove(struct ixgbe_hw *hw, struct pci_dev *pdev) +{ + u16 value; + + pci_read_config_word(pdev, PCI_VENDOR_ID, &value); + if (value == IXGBE_FAILED_READ_CFG_WORD) { + ixgbe_remove_adapter(hw); + return true; + } + return false; +} + +u16 ixgbe_read_pci_cfg_word(struct ixgbe_hw *hw, u32 reg) +{ + struct ixgbe_adapter *adapter = hw->back; + u16 value; + + if (ixgbe_removed(hw->hw_addr)) + return IXGBE_FAILED_READ_CFG_WORD; + pci_read_config_word(adapter->pdev, reg, &value); + if (value == IXGBE_FAILED_READ_CFG_WORD && + ixgbe_check_cfg_remove(hw, adapter->pdev)) + return IXGBE_FAILED_READ_CFG_WORD; + return value; +} + +#ifdef CONFIG_PCI_IOV +static u32 ixgbe_read_pci_cfg_dword(struct ixgbe_hw *hw, u32 reg) +{ + struct ixgbe_adapter *adapter = hw->back; + u32 value; + + if (ixgbe_removed(hw->hw_addr)) + return IXGBE_FAILED_READ_CFG_DWORD; + pci_read_config_dword(adapter->pdev, reg, &value); + if (value == IXGBE_FAILED_READ_CFG_DWORD && + ixgbe_check_cfg_remove(hw, adapter->pdev)) + return IXGBE_FAILED_READ_CFG_DWORD; + return value; +} +#endif /* CONFIG_PCI_IOV */ + static void ixgbe_service_event_complete(struct ixgbe_adapter *adapter) { BUG_ON(!test_bit(__IXGBE_SERVICE_SCHED, &adapter->state)); @@ -2630,9 +2677,12 @@ static irqreturn_t ixgbe_msix_other(int irq, void *data) switch (hw->mac.type) { case ixgbe_mac_82599EB: case ixgbe_mac_X540: - if (eicr & IXGBE_EICR_ECC) - e_info(link, "Received unrecoverable ECC Err, please " - "reboot\n"); + if (eicr & IXGBE_EICR_ECC) { + e_info(link, "Received ECC Err, initiating reset\n"); + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + ixgbe_service_event_schedule(adapter); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); + } /* Handle Flow Director Full threshold interrupt */ if (eicr & IXGBE_EICR_FLOW_DIR) { int reinit_count = 0; @@ -2846,9 +2896,12 @@ static irqreturn_t ixgbe_intr(int irq, void *data) ixgbe_check_sfp_event(adapter, eicr); /* Fall through */ case ixgbe_mac_X540: - if (eicr & IXGBE_EICR_ECC) - e_info(link, "Received unrecoverable ECC err, please " - "reboot\n"); + if (eicr & IXGBE_EICR_ECC) { + e_info(link, "Received ECC Err, initiating reset\n"); + adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED; + ixgbe_service_event_schedule(adapter); + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_ECC); + } ixgbe_check_overtemp_event(adapter, eicr); break; default: @@ -5502,6 +5555,7 @@ static int ixgbe_resume(struct pci_dev *pdev) struct net_device *netdev = adapter->netdev; u32 err; + adapter->hw.hw_addr = adapter->io_addr; pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* @@ -6881,7 +6935,7 @@ static inline int ixgbe_maybe_stop_tx(struct ixgbe_ring *tx_ring, u16 size) } static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { struct ixgbe_fwd_adapter *fwd_adapter = accel_priv; #ifdef IXGBE_FCOE @@ -6907,7 +6961,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) break; default: - return __netdev_pick_tx(dev, skb); + return fallback(dev, skb); } f = &adapter->ring_feature[RING_F_FCOE]; @@ -6920,7 +6974,7 @@ static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb, return txq + f->offset; #else - return __netdev_pick_tx(dev, skb); + return fallback(dev, skb); #endif } @@ -7143,7 +7197,9 @@ static int ixgbe_ioctl(struct net_device *netdev, struct ifreq *req, int cmd) switch (cmd) { case SIOCSHWTSTAMP: - return ixgbe_ptp_hwtstamp_ioctl(adapter, req, cmd); + return ixgbe_ptp_set_ts_config(adapter, req); + case SIOCGHWTSTAMP: + return ixgbe_ptp_get_ts_config(adapter, req); default: return mdio_mii_ioctl(&adapter->hw.phy.mdio, if_mii(req), cmd); } @@ -7792,6 +7848,7 @@ int ixgbe_wol_supported(struct ixgbe_adapter *adapter, u16 device_id, case IXGBE_DEV_ID_82599_SFP: /* Only these subdevices could supports WOL */ switch (subdevice_id) { + case IXGBE_SUBDEV_ID_82599_SFP_WOL0: case IXGBE_SUBDEV_ID_82599_560FLR: /* only support first port */ if (hw->bus.func != 0) @@ -8331,6 +8388,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, struct net_device *netdev = adapter->netdev; #ifdef CONFIG_PCI_IOV + struct ixgbe_hw *hw = &adapter->hw; struct pci_dev *bdev, *vfdev; u32 dw0, dw1, dw2, dw3; int vf, pos; @@ -8351,10 +8409,12 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, if (!pos) goto skip_bad_vf_detection; - pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG, &dw0); - pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 4, &dw1); - pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 8, &dw2); - pci_read_config_dword(bdev, pos + PCI_ERR_HEADER_LOG + 12, &dw3); + dw0 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG); + dw1 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 4); + dw2 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 8); + dw3 = ixgbe_read_pci_cfg_dword(hw, pos + PCI_ERR_HEADER_LOG + 12); + if (ixgbe_removed(hw->hw_addr)) + goto skip_bad_vf_detection; req_id = dw1 >> 16; /* On the 82599 if bit 7 of the requestor ID is set then it's a VF */ @@ -8446,6 +8506,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) e_err(probe, "Cannot re-enable PCI device after reset.\n"); result = PCI_ERS_RESULT_DISCONNECT; } else { + adapter->hw.hw_addr = adapter->io_addr; pci_set_master(pdev); pci_restore_state(pdev); pci_save_state(pdev); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 132557c318f8..d2caae4750e0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -98,6 +98,32 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) } /** + * ixgbe_check_reset_blocked - check status of MNG FW veto bit + * @hw: pointer to the hardware structure + * + * This function checks the MMNGC.MNG_VETO bit to see if there are + * any constraints on link from manageability. For MAC's that don't + * have this bit just return false since the link can not be blocked + * via this method. + **/ +s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw) +{ + u32 mmngc; + + /* If we don't have this bit, it can't be blocking */ + if (hw->mac.type == ixgbe_mac_82598EB) + return false; + + mmngc = IXGBE_READ_REG(hw, IXGBE_MMNGC); + if (mmngc & IXGBE_MMNGC_MNG_VETO) { + hw_dbg(hw, "MNG_VETO bit detected.\n"); + return true; + } + + return false; +} + +/** * ixgbe_get_phy_id - Get the phy type * @hw: pointer to hardware structure * @@ -172,6 +198,10 @@ s32 ixgbe_reset_phy_generic(struct ixgbe_hw *hw) (IXGBE_ERR_OVERTEMP == hw->phy.ops.check_overtemp(hw))) goto out; + /* Blocked by MNG FW so bail */ + if (ixgbe_check_reset_blocked(hw)) + goto out; + /* * Perform soft PHY reset to the PHY_XS. * This will cause a soft reset to the PHY @@ -476,6 +506,10 @@ s32 ixgbe_setup_phy_link_generic(struct ixgbe_hw *hw) autoneg_reg); } + /* Blocked by MNG FW so don't reset PHY */ + if (ixgbe_check_reset_blocked(hw)) + return status; + /* Restart PHY autonegotiation and wait for completion */ hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, &autoneg_reg); @@ -682,6 +716,10 @@ s32 ixgbe_setup_phy_link_tnx(struct ixgbe_hw *hw) autoneg_reg); } + /* Blocked by MNG FW so don't reset PHY */ + if (ixgbe_check_reset_blocked(hw)) + return status; + /* Restart PHY autonegotiation and wait for completion */ hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_AN, &autoneg_reg); @@ -759,6 +797,10 @@ s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) s32 ret_val = 0; u32 i; + /* Blocked by MNG FW so bail */ + if (ixgbe_check_reset_blocked(hw)) + goto out; + hw->phy.ops.read_reg(hw, MDIO_CTRL1, MDIO_MMD_PHYXS, &phy_data); /* reset the PHY and poll for completion */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h index fffcbdd2bf0e..b4d4323666b8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -131,6 +131,7 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, ixgbe_link_speed *speed, bool *autoneg); +s32 ixgbe_check_reset_blocked(struct ixgbe_hw *hw); /* PHY specific */ s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c index 5184e2a1a7d8..9ef730f2916a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c @@ -576,14 +576,21 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector, shhwtstamps->hwtstamp = ns_to_ktime(ns); } +int ixgbe_ptp_get_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr) +{ + struct hwtstamp_config *config = &adapter->tstamp_config; + + return copy_to_user(ifr->ifr_data, config, + sizeof(*config)) ? -EFAULT : 0; +} + /** - * ixgbe_ptp_hwtstamp_ioctl - control hardware time stamping + * ixgbe_ptp_set_ts_config - control hardware time stamping * @adapter: pointer to adapter struct * @ifreq: ioctl data - * @cmd: particular ioctl requested * * Outgoing time stamping can be enabled and disabled. Play nice and - * disable it when requested, although it shouldn't case any overhead + * disable it when requested, although it shouldn't cause any overhead * when no packet needs it. At most one packet in the queue may be * marked for time stamping, otherwise it would be impossible to tell * for sure to which packet the hardware time stamp belongs. @@ -599,8 +606,7 @@ void __ixgbe_ptp_rx_hwtstamp(struct ixgbe_q_vector *q_vector, * Event mode. This more accurately tells the user what the hardware is going * to do anyways. */ -int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, - struct ifreq *ifr, int cmd) +int ixgbe_ptp_set_ts_config(struct ixgbe_adapter *adapter, struct ifreq *ifr) { struct ixgbe_hw *hw = &adapter->hw; struct hwtstamp_config config; @@ -702,6 +708,10 @@ int ixgbe_ptp_hwtstamp_ioctl(struct ixgbe_adapter *adapter, regval = IXGBE_READ_REG(hw, IXGBE_TXSTMPH); regval = IXGBE_READ_REG(hw, IXGBE_RXSTMPH); + /* save these settings for future reference */ + memcpy(&adapter->tstamp_config, &config, + sizeof(adapter->tstamp_config)); + return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0; } @@ -809,6 +819,9 @@ void ixgbe_ptp_reset(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_SYSTIMH, 0x00000000); IXGBE_WRITE_FLUSH(hw); + /* Reset the saved tstamp_config */ + memset(&adapter->tstamp_config, 0, sizeof(adapter->tstamp_config)); + ixgbe_ptp_start_cyclecounter(adapter); spin_lock_irqsave(&adapter->tmreg_lock, flags); @@ -840,7 +853,9 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter) switch (adapter->hw.mac.type) { case ixgbe_mac_X540: - snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name); + snprintf(adapter->ptp_caps.name, + sizeof(adapter->ptp_caps.name), + "%s", netdev->name); adapter->ptp_caps.owner = THIS_MODULE; adapter->ptp_caps.max_adj = 250000000; adapter->ptp_caps.n_alarm = 0; @@ -854,7 +869,9 @@ void ixgbe_ptp_init(struct ixgbe_adapter *adapter) adapter->ptp_caps.enable = ixgbe_ptp_enable; break; case ixgbe_mac_82599EB: - snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name); + snprintf(adapter->ptp_caps.name, + sizeof(adapter->ptp_caps.name), + "%s", netdev->name); adapter->ptp_caps.owner = THIS_MODULE; adapter->ptp_caps.max_adj = 250000000; adapter->ptp_caps.n_alarm = 0; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 0d39cfc4a3bf..c10382e5aabc 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2013 Intel Corporation. + Copyright(c) 1999 - 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, @@ -54,6 +54,7 @@ #define IXGBE_DEV_ID_82599_BACKPLANE_FCOE 0x152a #define IXGBE_DEV_ID_82599_SFP_FCOE 0x1529 #define IXGBE_SUBDEV_ID_82599_SFP 0x11A9 +#define IXGBE_SUBDEV_ID_82599_SFP_WOL0 0x1071 #define IXGBE_SUBDEV_ID_82599_RNDC 0x1F72 #define IXGBE_SUBDEV_ID_82599_560FLR 0x17D0 #define IXGBE_SUBDEV_ID_82599_SP_560FLR 0x211B @@ -1609,6 +1610,9 @@ enum { #define IXGBE_MACC_FS 0x00040000 #define IXGBE_MAC_RX2TX_LPBK 0x00000002 +/* Veto Bit definiton */ +#define IXGBE_MMNGC_MNG_VETO 0x00000001 + /* LINKS Bit Masks */ #define IXGBE_LINKS_KX_AN_COMP 0x80000000 #define IXGBE_LINKS_UP 0x40000000 @@ -1853,8 +1857,19 @@ enum { #define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80 #define IXGBE_PCI_DEVICE_CONTROL2_16ms 0x0005 +#define IXGBE_PCIDEVCTRL2_TIMEO_MASK 0xf +#define IXGBE_PCIDEVCTRL2_16_32ms_def 0x0 +#define IXGBE_PCIDEVCTRL2_50_100us 0x1 +#define IXGBE_PCIDEVCTRL2_1_2ms 0x2 +#define IXGBE_PCIDEVCTRL2_16_32ms 0x5 +#define IXGBE_PCIDEVCTRL2_65_130ms 0x6 +#define IXGBE_PCIDEVCTRL2_260_520ms 0x9 +#define IXGBE_PCIDEVCTRL2_1_2s 0xa +#define IXGBE_PCIDEVCTRL2_4_8s 0xd +#define IXGBE_PCIDEVCTRL2_17_34s 0xe + /* Number of 100 microseconds we wait for PCI Express master disable */ -#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 +#define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800 /* RAH */ #define IXGBE_RAH_VIND_MASK 0x003C0000 @@ -2858,6 +2873,8 @@ struct ixgbe_mac_operations { s32 (*enable_rx_dma)(struct ixgbe_hw *, u32); s32 (*acquire_swfw_sync)(struct ixgbe_hw *, u16); void (*release_swfw_sync)(struct ixgbe_hw *, u16); + s32 (*prot_autoc_read)(struct ixgbe_hw *, bool *, u32 *); + s32 (*prot_autoc_write)(struct ixgbe_hw *, u32, bool); /* Link */ void (*disable_tx_laser)(struct ixgbe_hw *); @@ -2957,7 +2974,6 @@ struct ixgbe_mac_info { u32 max_tx_queues; u32 max_rx_queues; u32 orig_autoc; - u32 cached_autoc; u32 orig_autoc2; bool orig_link_settings_stored; bool autotry_restart; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 24b80a6cfca4..c870f37f15d3 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -855,6 +855,8 @@ static struct ixgbe_mac_operations mac_ops_X540 = { .get_thermal_sensor_data = NULL, .init_thermal_sensor_thresh = NULL, .mng_fw_enabled = NULL, + .prot_autoc_read = &prot_autoc_read_generic, + .prot_autoc_write = &prot_autoc_write_generic, }; static struct ixgbe_eeprom_operations eeprom_ops_X540 = { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 9df28985eba7..6ac5da219150 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -516,7 +516,8 @@ static int ixgbevf_clean_rx_irq(struct ixgbevf_q_vector *q_vector, /* Workaround hardware that can't do proper VEPA multicast * source pruning. */ - if ((skb->pkt_type & (PACKET_BROADCAST | PACKET_MULTICAST)) && + if ((skb->pkt_type == PACKET_BROADCAST || + skb->pkt_type == PACKET_MULTICAST) && ether_addr_equal(rx_ring->netdev->dev_addr, eth_hdr(skb)->h_source)) { dev_kfree_skb_irq(skb); @@ -1817,7 +1818,6 @@ void ixgbevf_reset(struct ixgbevf_adapter *adapter) static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter, int vectors) { - int err = 0; int vector_threshold; /* We'll want at least 2 (vector_threshold): @@ -1831,33 +1831,24 @@ static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter, * Right now, we simply care about how many we'll get; we'll * set them up later while requesting irq's. */ - while (vectors >= vector_threshold) { - err = pci_enable_msix(adapter->pdev, adapter->msix_entries, - vectors); - if (!err || err < 0) /* Success or a nasty failure. */ - break; - else /* err == number of vectors we should try again with */ - vectors = err; - } - - if (vectors < vector_threshold) - err = -ENOMEM; + vectors = pci_enable_msix_range(adapter->pdev, adapter->msix_entries, + vector_threshold, vectors); - if (err) { + if (vectors < 0) { dev_err(&adapter->pdev->dev, "Unable to allocate MSI-X interrupts\n"); kfree(adapter->msix_entries); adapter->msix_entries = NULL; - } else { - /* - * Adjust for only the vectors we'll use, which is minimum - * of max_msix_q_vectors + NON_Q_VECTORS, or the number of - * vectors we were allocated. - */ - adapter->num_msix_vectors = vectors; + return vectors; } - return err; + /* Adjust for only the vectors we'll use, which is minimum + * of max_msix_q_vectors + NON_Q_VECTORS, or the number of + * vectors we were allocated. + */ + adapter->num_msix_vectors = vectors; + + return 0; } /** @@ -2787,6 +2778,9 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring, u32 vlan_macip_lens, type_tucmd; u32 mss_l4len_idx, l4len; + if (skb->ip_summed != CHECKSUM_PARTIAL) + return 0; + if (!skb_is_gso(skb)) return 0; @@ -3165,7 +3159,7 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev) tso = ixgbevf_tso(tx_ring, first, &hdr_len); if (tso < 0) goto out_drop; - else + else if (!tso) ixgbevf_tx_csum(tx_ring, first); ixgbevf_tx_map(tx_ring, first, hdr_len); diff --git a/drivers/net/ethernet/lantiq_etop.c b/drivers/net/ethernet/lantiq_etop.c index 8f9266c64c75..fd4b6aecf6ee 100644 --- a/drivers/net/ethernet/lantiq_etop.c +++ b/drivers/net/ethernet/lantiq_etop.c @@ -619,7 +619,7 @@ ltq_etop_set_multicast_list(struct net_device *dev) static u16 ltq_etop_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { /* 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 6300fd27f2db..68e6a6613e9a 100644 --- a/drivers/net/ethernet/marvell/Kconfig +++ b/drivers/net/ethernet/marvell/Kconfig @@ -43,12 +43,12 @@ config MVMDIO This driver is used by the MV643XX_ETH and MVNETA drivers. config MVNETA - tristate "Marvell Armada 370/XP network interface support" - depends on MACH_ARMADA_370_XP + tristate "Marvell Armada 370/38x/XP network interface support" + depends on PLAT_ORION select MVMDIO ---help--- This driver supports the network interface units in the - Marvell ARMADA XP and ARMADA 370 SoC family. + Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family. Note that this driver is distinct from the mv643xx_eth driver, which should be used for the older Marvell SoCs diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index f418f4f20f94..12c6a66e54d1 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -2784,7 +2784,6 @@ static int mvneta_probe(struct platform_device *pdev) const char *mac_from; int phy_mode; int err; - int cpu; /* Our multiqueue support is not complete, so for now, only * allow the usage of the first RX queue @@ -2845,18 +2844,12 @@ static int mvneta_probe(struct platform_device *pdev) } /* Alloc per-cpu stats */ - pp->stats = alloc_percpu(struct mvneta_pcpu_stats); + pp->stats = netdev_alloc_pcpu_stats(struct mvneta_pcpu_stats); if (!pp->stats) { err = -ENOMEM; goto err_unmap; } - for_each_possible_cpu(cpu) { - struct mvneta_pcpu_stats *stats; - stats = per_cpu_ptr(pp->stats, cpu); - u64_stats_init(&stats->syncp); - } - dt_mac_addr = of_get_mac_address(dn); if (dt_mac_addr) { mac_from = "device tree"; diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c index 55a37ae11440..2434611d1b4e 100644 --- a/drivers/net/ethernet/marvell/sky2.c +++ b/drivers/net/ethernet/marvell/sky2.c @@ -44,6 +44,8 @@ #include <linux/prefetch.h> #include <linux/debugfs.h> #include <linux/mii.h> +#include <linux/of_device.h> +#include <linux/of_net.h> #include <asm/irq.h> @@ -4748,6 +4750,7 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port, { struct sky2_port *sky2; struct net_device *dev = alloc_etherdev(sizeof(*sky2)); + const void *iap; if (!dev) return NULL; @@ -4805,8 +4808,16 @@ static struct net_device *sky2_init_netdev(struct sky2_hw *hw, unsigned port, dev->features |= dev->hw_features; - /* read the mac address */ - memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, ETH_ALEN); + /* try to get mac address in the following order: + * 1) from device tree data + * 2) from internal registers set by bootloader + */ + iap = of_get_mac_address(hw->pdev->dev.of_node); + if (iap) + memcpy(dev->dev_addr, iap, ETH_ALEN); + else + memcpy_fromio(dev->dev_addr, hw->regs + B2_MAC_1 + port * 8, + ETH_ALEN); return dev; } diff --git a/drivers/net/ethernet/mellanox/mlx4/Kconfig b/drivers/net/ethernet/mellanox/mlx4/Kconfig index 563495d8975a..1a6e1887a171 100644 --- a/drivers/net/ethernet/mellanox/mlx4/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx4/Kconfig @@ -3,7 +3,7 @@ # config MLX4_EN - tristate "Mellanox Technologies 10Gbit Ethernet support" + tristate "Mellanox Technologies 1/10/40Gbit Ethernet support" depends on PCI select MLX4_CORE select PTP_1588_CLOCK diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c index 0d02fba94536..2b0b45ece14b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/cmd.c +++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c @@ -2289,6 +2289,30 @@ int mlx4_set_vf_vlan(struct mlx4_dev *dev, int port, int vf, u16 vlan, u8 qos) } EXPORT_SYMBOL_GPL(mlx4_set_vf_vlan); + /* mlx4_get_slave_default_vlan - + * return true if VST ( default vlan) + * if VST, will return vlan & qos (if not NULL) + */ +bool mlx4_get_slave_default_vlan(struct mlx4_dev *dev, int port, int slave, + u16 *vlan, u8 *qos) +{ + struct mlx4_vport_oper_state *vp_oper; + struct mlx4_priv *priv; + + priv = mlx4_priv(dev); + vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; + + if (MLX4_VGT != vp_oper->state.default_vlan) { + if (vlan) + *vlan = vp_oper->state.default_vlan; + if (qos) + *qos = vp_oper->state.default_qos; + return true; + } + return false; +} +EXPORT_SYMBOL_GPL(mlx4_get_slave_default_vlan); + int mlx4_set_vf_spoofchk(struct mlx4_dev *dev, int port, int vf, bool setting) { struct mlx4_priv *priv = mlx4_priv(dev); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c index b4881b686159..c95ca252187c 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_dcb_nl.c @@ -62,7 +62,7 @@ static int mlx4_en_ets_validate(struct mlx4_en_priv *priv, struct ieee_ets *ets) int has_ets_tc = 0; for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { - if (ets->prio_tc[i] > MLX4_EN_NUM_UP) { + if (ets->prio_tc[i] >= MLX4_EN_NUM_UP) { en_err(priv, "Bad priority in UP <=> TC mapping. TC: %d, UP: %d\n", i, ets->prio_tc[i]); return -EINVAL; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index d357bf5a4686..0c59d4fe7e3a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -72,6 +72,12 @@ MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." " Per priority bit mask"); +MLX4_EN_PARM_INT(inline_thold, MAX_INLINE, + "Threshold for using inline data (range: 17-104, default: 104)"); + +#define MAX_PFC_TX 0xff +#define MAX_PFC_RX 0xff + int en_print(const char *level, const struct mlx4_en_priv *priv, const char *format, ...) { @@ -140,6 +146,7 @@ static int mlx4_en_get_profile(struct mlx4_en_dev *mdev) params->prof[i].tx_ring_num = params->num_tx_rings_p_up * MLX4_EN_NUM_UP; params->prof[i].rss_rings = 0; + params->prof[i].inline_thold = inline_thold; } return 0; @@ -274,19 +281,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev) if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_TS) mlx4_en_init_timestamp(mdev); - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - if (!dev->caps.comp_pool) { - mdev->profile.prof[i].rx_ring_num = - rounddown_pow_of_two(max_t(int, MIN_RX_RINGS, - min_t(int, - dev->caps.num_comp_vectors, - DEF_RX_RINGS))); - } else { - mdev->profile.prof[i].rx_ring_num = rounddown_pow_of_two( - min_t(int, dev->caps.comp_pool/ - dev->caps.num_ports - 1 , MAX_MSIX_P_PORT - 1)); - } - } + /* Set default number of RX rings*/ + mlx4_en_set_num_rx_rings(mdev); /* Create our own workqueue for reset/multicast tasks * Note: we cannot use the shared workqueue because of deadlocks caused @@ -336,8 +332,31 @@ static struct mlx4_interface mlx4_en_interface = { .protocol = MLX4_PROT_ETH, }; +static void mlx4_en_verify_params(void) +{ + if (pfctx > MAX_PFC_TX) { + pr_warn("mlx4_en: WARNING: illegal module parameter pfctx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n", + pfctx, MAX_PFC_TX); + pfctx = 0; + } + + if (pfcrx > MAX_PFC_RX) { + pr_warn("mlx4_en: WARNING: illegal module parameter pfcrx 0x%x - should be in range 0-0x%x, will be changed to default (0)\n", + pfcrx, MAX_PFC_RX); + pfcrx = 0; + } + + if (inline_thold < MIN_PKT_LEN || inline_thold > MAX_INLINE) { + pr_warn("mlx4_en: WARNING: illegal module parameter inline_thold %d - should be in range %d-%d, will be changed to default (%d)\n", + inline_thold, MIN_PKT_LEN, MAX_INLINE, MAX_INLINE); + inline_thold = MAX_INLINE; + } +} + static int __init mlx4_en_init(void) { + mlx4_en_verify_params(); + return mlx4_register_interface(&mlx4_en_interface); } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index fad45316200a..3db594614fd3 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -603,7 +603,7 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv) int err = 0; u64 reg_id; int *qpn = &priv->base_qpn; - u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); + u64 mac = mlx4_mac_to_u64(priv->dev->dev_addr); en_dbg(DRV, priv, "Registering MAC: %pM for adding\n", priv->dev->dev_addr); @@ -672,7 +672,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv) u64 mac; if (dev->caps.steering_mode == MLX4_STEERING_MODE_A0) { - mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); + mac = mlx4_mac_to_u64(priv->dev->dev_addr); en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", priv->dev->dev_addr); mlx4_unregister_mac(dev, priv->port, mac); @@ -685,7 +685,7 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv) for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) { bucket = &priv->mac_hash[i]; hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { - mac = mlx4_en_mac_to_u64(entry->mac); + mac = mlx4_mac_to_u64(entry->mac); en_dbg(DRV, priv, "Registering MAC: %pM for deleting\n", entry->mac); mlx4_en_uc_steer_release(priv, entry->mac, @@ -715,14 +715,14 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_dev *dev = mdev->dev; int err = 0; - u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac); + u64 new_mac_u64 = mlx4_mac_to_u64(new_mac); if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { struct hlist_head *bucket; unsigned int mac_hash; struct mlx4_mac_entry *entry; struct hlist_node *tmp; - u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac); + u64 prev_mac_u64 = mlx4_mac_to_u64(prev_mac); bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]]; hlist_for_each_entry_safe(entry, tmp, bucket, hlist) { @@ -751,18 +751,6 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); } -u64 mlx4_en_mac_to_u64(u8 *addr) -{ - u64 mac = 0; - int i; - - for (i = 0; i < ETH_ALEN; i++) { - mac <<= 8; - mac |= addr[i]; - } - return mac; -} - static int mlx4_en_do_set_mac(struct mlx4_en_priv *priv) { int err = 0; @@ -1081,7 +1069,7 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv, mlx4_en_cache_mclist(dev); netif_addr_unlock_bh(dev); list_for_each_entry(mclist, &priv->mc_list, list) { - mcast_addr = mlx4_en_mac_to_u64(mclist->addr); + mcast_addr = mlx4_mac_to_u64(mclist->addr); mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, mcast_addr, 0, MLX4_MCAST_CONFIG); } @@ -1173,7 +1161,7 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv, found = true; if (!found) { - mac = mlx4_en_mac_to_u64(entry->mac); + mac = mlx4_mac_to_u64(entry->mac); mlx4_en_uc_steer_release(priv, entry->mac, priv->base_qpn, entry->reg_id); @@ -1216,7 +1204,7 @@ static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv, priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC; break; } - mac = mlx4_en_mac_to_u64(ha->addr); + mac = mlx4_mac_to_u64(ha->addr); memcpy(entry->mac, ha->addr, ETH_ALEN); err = mlx4_register_mac(mdev->dev, priv->port, mac); if (err < 0) { @@ -2206,7 +2194,7 @@ static int mlx4_en_set_vf_mac(struct net_device *dev, int queue, u8 *mac) { struct mlx4_en_priv *en_priv = netdev_priv(dev); struct mlx4_en_dev *mdev = en_priv->mdev; - u64 mac_u64 = mlx4_en_mac_to_u64(mac); + u64 mac_u64 = mlx4_mac_to_u64(mac); if (!is_valid_ether_addr(mac)) return -EINVAL; @@ -2341,7 +2329,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, netif_set_real_num_rx_queues(dev, prof->rx_ring_num); SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev); - dev->dev_id = port - 1; + dev->dev_port = port - 1; /* * Initialize driver private data @@ -2407,7 +2395,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, if (mlx4_is_slave(priv->mdev->dev)) { eth_hw_addr_random(dev); en_warn(priv, "Assigned random MAC address %pM\n", dev->dev_addr); - mac_u64 = mlx4_en_mac_to_u64(dev->dev_addr); + mac_u64 = mlx4_mac_to_u64(dev->dev_addr); mdev->dev->caps.def_mac[priv->port] = mac_u64; } else { en_err(priv, "Port: %d, invalid mac burned: %pM, quiting\n", diff --git a/drivers/net/ethernet/mellanox/mlx4/en_port.c b/drivers/net/ethernet/mellanox/mlx4/en_port.c index dae1a1f4ae55..c2cfb05e7290 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_port.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_port.c @@ -148,10 +148,16 @@ int mlx4_en_DUMP_ETH_STATS(struct mlx4_en_dev *mdev, u8 port, u8 reset) stats->tx_packets = 0; stats->tx_bytes = 0; priv->port_stats.tx_chksum_offload = 0; + priv->port_stats.queue_stopped = 0; + priv->port_stats.wake_queue = 0; + for (i = 0; i < priv->tx_ring_num; i++) { stats->tx_packets += priv->tx_ring[i]->packets; stats->tx_bytes += priv->tx_ring[i]->bytes; priv->port_stats.tx_chksum_offload += priv->tx_ring[i]->tx_csum; + priv->port_stats.queue_stopped += + priv->tx_ring[i]->queue_stopped; + priv->port_stats.wake_queue += priv->tx_ring[i]->wake_queue; } stats->rx_errors = be64_to_cpu(mlx4_en_stats->PCS) + diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 890922c1c8ee..8afb72ec957d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -318,6 +318,31 @@ static void mlx4_en_free_rx_buf(struct mlx4_en_priv *priv, } } +void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev) +{ + int i; + int num_of_eqs; + int num_rx_rings; + struct mlx4_dev *dev = mdev->dev; + + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + if (!dev->caps.comp_pool) + num_of_eqs = max_t(int, MIN_RX_RINGS, + min_t(int, + dev->caps.num_comp_vectors, + DEF_RX_RINGS)); + else + num_of_eqs = min_t(int, MAX_MSIX_P_PORT, + dev->caps.comp_pool/ + dev->caps.num_ports) - 1; + + num_rx_rings = min_t(int, num_of_eqs, + netif_get_num_default_rss_queues()); + mdev->profile.prof[i].rx_ring_num = + rounddown_pow_of_two(num_rx_rings); + } +} + int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring **pring, u32 size, u16 stride, int node) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c index c11d063473e5..03e5f6ac67e7 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_selftest.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_selftest.c @@ -129,8 +129,10 @@ static int mlx4_en_test_speed(struct mlx4_en_priv *priv) if (mlx4_en_QUERY_PORT(priv->mdev, priv->port)) return -ENOMEM; - /* The device currently only supports 10G speed */ - if (priv->port_state.link_speed != SPEED_10000) + /* The device supports 1G, 10G and 40G speeds */ + if (priv->port_state.link_speed != 1000 && + priv->port_state.link_speed != 10000 && + priv->port_state.link_speed != 40000) return priv->port_state.link_speed; return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 8e8a7eb43a2c..dd1f6d346459 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -44,16 +44,6 @@ #include "mlx4_en.h" -enum { - MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ - MAX_BF = 256, -}; - -static int inline_thold __read_mostly = MAX_INLINE; - -module_param_named(inline_thold, inline_thold, int, 0444); -MODULE_PARM_DESC(inline_thold, "threshold for using inline data"); - int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring **pring, int qpn, u32 size, u16 stride, int node, int queue_index) @@ -75,8 +65,7 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv, ring->size = size; ring->size_mask = size - 1; ring->stride = stride; - - inline_thold = min(inline_thold, MAX_INLINE); + ring->inline_thold = priv->prof->inline_thold; tmp = size * sizeof(struct mlx4_en_tx_info); ring->tx_info = vmalloc_node(tmp, node); @@ -325,7 +314,7 @@ static u32 mlx4_en_free_tx_desc(struct mlx4_en_priv *priv, } } } - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); return tx_info->nr_txbb; } @@ -456,7 +445,7 @@ static int mlx4_en_process_tx_cq(struct net_device *dev, */ if (netif_tx_queue_stopped(ring->tx_queue) && txbbs_skipped > 0) { netif_tx_wake_queue(ring->tx_queue); - priv->port_stats.wake_queue++; + ring->wake_queue++; } return done; } @@ -520,7 +509,7 @@ static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, return ring->buf + index * TXBB_SIZE; } -static int is_inline(struct sk_buff *skb, void **pfrag) +static int is_inline(int inline_thold, struct sk_buff *skb, void **pfrag) { void *ptr; @@ -580,7 +569,7 @@ static int get_real_size(struct sk_buff *skb, struct net_device *dev, } } else { *lso_header_size = 0; - if (!is_inline(skb, NULL)) + if (!is_inline(priv->prof->inline_thold, skb, NULL)) real_size = CTRL_SIZE + (skb_shinfo(skb)->nr_frags + 1) * DS_SIZE; else real_size = inline_size(skb); @@ -596,7 +585,13 @@ static void build_inline_wqe(struct mlx4_en_tx_desc *tx_desc, struct sk_buff *sk int spc = MLX4_INLINE_ALIGN - CTRL_SIZE - sizeof *inl; if (skb->len <= spc) { - inl->byte_count = cpu_to_be32(1 << 31 | skb->len); + if (likely(skb->len >= MIN_PKT_LEN)) { + inl->byte_count = cpu_to_be32(1 << 31 | skb->len); + } else { + inl->byte_count = cpu_to_be32(1 << 31 | MIN_PKT_LEN); + memset(((void *)(inl + 1)) + skb->len, 0, + MIN_PKT_LEN - skb->len); + } skb_copy_from_linear_data(skb, inl + 1, skb_headlen(skb)); if (skb_shinfo(skb)->nr_frags) memcpy(((void *)(inl + 1)) + skb_headlen(skb), fragptr, @@ -629,7 +624,7 @@ 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, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { struct mlx4_en_priv *priv = netdev_priv(dev); u16 rings_p_up = priv->num_tx_rings_p_up; @@ -641,7 +636,7 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb, if (vlan_tx_tag_present(skb)) up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT; - return __netdev_pick_tx(dev, skb) % rings_p_up + up * rings_p_up; + return fallback(dev, skb) % rings_p_up + up * rings_p_up; } static void mlx4_bf_copy(void __iomem *dst, unsigned long *src, unsigned bytecnt) @@ -696,7 +691,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->size - HEADROOM - MAX_DESC_TXBBS)) { /* every full Tx ring stops queue */ netif_tx_stop_queue(ring->tx_queue); - priv->port_stats.queue_stopped++; + ring->queue_stopped++; /* If queue was emptied after the if, and before the * stop_queue - need to wake the queue, or else it will remain @@ -709,7 +704,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(((int)(ring->prod - ring->cons)) <= ring->size - HEADROOM - MAX_DESC_TXBBS)) { netif_tx_wake_queue(ring->tx_queue); - priv->port_stats.wake_queue++; + ring->wake_queue++; } else { return NETDEV_TX_BUSY; } @@ -747,11 +742,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) tx_info->data_offset = (void *)data - (void *)tx_desc; tx_info->linear = (lso_header_size < skb_headlen(skb) && - !is_inline(skb, NULL)) ? 1 : 0; + !is_inline(ring->inline_thold, skb, NULL)) ? 1 : 0; data += skb_shinfo(skb)->nr_frags + tx_info->linear - 1; - if (is_inline(skb, &fragptr)) { + if (is_inline(ring->inline_thold, skb, &fragptr)) { tx_info->inl = 1; } else { /* Map fragments */ @@ -881,7 +876,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) skb_tx_timestamp(skb); if (ring->bf_enabled && desc_size <= MAX_BF && !bounce && !vlan_tx_tag_present(skb)) { - *(__be32 *) (&tx_desc->ctrl.vlan_tag) |= cpu_to_be32(ring->doorbell_qpn); + tx_desc->ctrl.bf_qpn |= cpu_to_be32(ring->doorbell_qpn); + op_own |= htonl((bf_index & 0xffff) << 8); /* Ensure new descirptor hits memory * before setting ownership of this descriptor to HW */ diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index 91b69ff4b4a2..6e1ee2170a39 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -934,7 +934,10 @@ int mlx4_QUERY_PORT_wrapper(struct mlx4_dev *dev, int slave, MLX4_PUT(outbox->buf, port_type, QUERY_PORT_SUPPORTED_TYPE_OFFSET); - short_field = 1; /* slave max gids */ + if (dev->caps.port_type[vhcr->in_modifier] == MLX4_PORT_TYPE_ETH) + short_field = mlx4_get_slave_num_gids(dev, slave); + else + short_field = 1; /* slave max gids */ MLX4_PUT(outbox->buf, short_field, QUERY_PORT_CUR_MAX_GID_OFFSET); @@ -1890,7 +1893,8 @@ void mlx4_opreq_action(struct work_struct *work) err = EINVAL; break; } - err = mlx4_cmd(dev, 0, ((u32) err | cpu_to_be32(token) << 16), + err = mlx4_cmd(dev, 0, ((u32) err | + (__force u32)cpu_to_be32(token) << 16), 1, MLX4_CMD_GET_OP_REQ, MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE); if (err) { diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index d711158b0d4b..4c441aa83016 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -41,7 +41,6 @@ #include <linux/slab.h> #include <linux/io-mapping.h> #include <linux/delay.h> -#include <linux/netdevice.h> #include <linux/kmod.h> #include <linux/mlx4/device.h> @@ -1463,7 +1462,11 @@ static void mlx4_parav_master_pf_caps(struct mlx4_dev *dev) int i; for (i = 1; i <= dev->caps.num_ports; i++) { - dev->caps.gid_table_len[i] = 1; + if (dev->caps.port_type[i] == MLX4_PORT_TYPE_ETH) + dev->caps.gid_table_len[i] = + mlx4_get_slave_num_gids(dev, 0); + else + dev->caps.gid_table_len[i] = 1; dev->caps.pkey_table_len[i] = dev->phys_caps.pkey_phys_table_len[i] - 1; } @@ -1974,9 +1977,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) struct mlx4_priv *priv = mlx4_priv(dev); struct msix_entry *entries; int nreq = min_t(int, dev->caps.num_ports * - min_t(int, netif_get_num_default_rss_queues() + 1, + min_t(int, num_online_cpus() + 1, MAX_MSIX_P_PORT) + MSIX_LEGACY_SZ, MAX_MSIX); - int err; int i; if (msi_x) { @@ -1990,23 +1992,13 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) for (i = 0; i < nreq; ++i) entries[i].entry = i; - retry: - err = pci_enable_msix(dev->pdev, entries, nreq); - if (err) { - /* Try again if at least 2 vectors are available */ - if (err > 1) { - mlx4_info(dev, "Requested %d vectors, " - "but only %d MSI-X vectors available, " - "trying again\n", nreq, err); - nreq = err; - goto retry; - } + nreq = pci_enable_msix_range(dev->pdev, entries, 2, nreq); + + if (nreq < 0) { kfree(entries); goto no_msi; - } - - if (nreq < - MSIX_LEGACY_SZ + dev->caps.num_ports * MIN_MSIX_P_PORT) { + } else if (nreq < MSIX_LEGACY_SZ + + dev->caps.num_ports * MIN_MSIX_P_PORT) { /*Working in legacy mode , all EQ's shared*/ dev->caps.comp_pool = 0; dev->caps.num_comp_vectors = nreq - 1; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index 6b65f7795215..6ba38c98c492 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -51,8 +51,8 @@ #define DRV_NAME "mlx4_core" #define PFX DRV_NAME ": " -#define DRV_VERSION "1.1" -#define DRV_RELDATE "Dec, 2011" +#define DRV_VERSION "2.2-1" +#define DRV_RELDATE "Feb, 2014" #define MLX4_FS_UDP_UC_EN (1 << 1) #define MLX4_FS_TCP_UC_EN (1 << 2) @@ -788,6 +788,10 @@ enum { MLX4_USE_RR = 1, }; +struct mlx4_roce_gid_entry { + u8 raw[16]; +}; + struct mlx4_priv { struct mlx4_dev dev; @@ -834,6 +838,7 @@ struct mlx4_priv { int fs_hash_mode; u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS]; __be64 slave_node_guids[MLX4_MFUNC_MAX]; + struct mlx4_roce_gid_entry roce_gids[MLX4_MAX_PORTS][MLX4_ROCE_MAX_GIDS]; atomic_t opreq_count; struct work_struct opreq_task; @@ -1282,4 +1287,7 @@ void mlx4_vf_immed_vlan_work_handler(struct work_struct *_work); void mlx4_init_quotas(struct mlx4_dev *dev); +int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave); +int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave); + #endif /* MLX4_H */ diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 3af04c3f42ea..69e1f36858e0 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -57,8 +57,8 @@ #include "en_port.h" #define DRV_NAME "mlx4_en" -#define DRV_VERSION "2.0" -#define DRV_RELDATE "Dec 2011" +#define DRV_VERSION "2.2-1" +#define DRV_RELDATE "Feb 2014" #define MLX4_EN_MSG_LEVEL (NETIF_MSG_LINK | NETIF_MSG_IFDOWN) @@ -187,6 +187,13 @@ enum { #define GET_AVG_PERF_COUNTER(cnt) (0) #endif /* MLX4_EN_PERF_STAT */ +/* Constants for TX flow */ +enum { + MAX_INLINE = 104, /* 128 - 16 - 4 - 4 */ + MAX_BF = 256, + MIN_PKT_LEN = 17, +}; + /* * Configurables */ @@ -267,10 +274,13 @@ struct mlx4_en_tx_ring { unsigned long bytes; unsigned long packets; unsigned long tx_csum; + unsigned long queue_stopped; + unsigned long wake_queue; struct mlx4_bf bf; bool bf_enabled; struct netdev_queue *tx_queue; int hwtstamp_tx_type; + int inline_thold; }; struct mlx4_en_rx_desc { @@ -346,6 +356,7 @@ struct mlx4_en_port_profile { u8 tx_pause; u8 tx_ppp; int rss_rings; + int inline_thold; }; struct mlx4_en_profile { @@ -723,7 +734,7 @@ 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, - void *accel_priv); + void *accel_priv, select_queue_fallback_t fallback); 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, @@ -737,7 +748,7 @@ int mlx4_en_activate_tx_ring(struct mlx4_en_priv *priv, int cq, int user_prio); void mlx4_en_deactivate_tx_ring(struct mlx4_en_priv *priv, struct mlx4_en_tx_ring *ring); - +void mlx4_en_set_num_rx_rings(struct mlx4_en_dev *mdev); int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring **pring, u32 size, u16 stride, int node); @@ -786,7 +797,6 @@ void mlx4_en_cleanup_filters(struct mlx4_en_priv *priv); #define MLX4_EN_NUM_SELF_TEST 5 void mlx4_en_ex_selftest(struct net_device *dev, u32 *flags, u64 *buf); -u64 mlx4_en_mac_to_u64(u8 *addr); void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev); /* diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c index a58bcbf1b806..ece328166e94 100644 --- a/drivers/net/ethernet/mellanox/mlx4/port.c +++ b/drivers/net/ethernet/mellanox/mlx4/port.c @@ -505,6 +505,32 @@ int mlx4_get_port_ib_caps(struct mlx4_dev *dev, u8 port, __be32 *caps) mlx4_free_cmd_mailbox(dev, outmailbox); return err; } +static struct mlx4_roce_gid_entry zgid_entry; + +int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave) +{ + if (slave == 0) + return MLX4_ROCE_PF_GIDS; + if (slave <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % dev->num_vfs)) + return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs) + 1; + return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / dev->num_vfs; +} + +int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave) +{ + int gids; + int vfs; + + gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; + vfs = dev->num_vfs; + + if (slave == 0) + return 0; + if (slave <= gids % vfs) + return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave - 1); + + return MLX4_ROCE_PF_GIDS + (gids % vfs) + ((gids / vfs) * (slave - 1)); +} static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, u8 op_mod, struct mlx4_cmd_mailbox *inbox) @@ -515,14 +541,18 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, struct mlx4_slave_state *slave_st = &master->slave_state[slave]; struct mlx4_set_port_rqp_calc_context *qpn_context; struct mlx4_set_port_general_context *gen_context; + struct mlx4_roce_gid_entry *gid_entry_tbl, *gid_entry_mbox, *gid_entry_mb1; int reset_qkey_viols; int port; int is_eth; + int num_gids; + int base; u32 in_modifier; u32 promisc; u16 mtu, prev_mtu; int err; - int i; + int i, j; + int offset; __be32 agg_cap_mask; __be32 slave_cap_mask; __be32 new_cap_mask; @@ -535,7 +565,8 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, /* Slaves cannot perform SET_PORT operations except changing MTU */ if (is_eth) { if (slave != dev->caps.function && - in_modifier != MLX4_SET_PORT_GENERAL) { + in_modifier != MLX4_SET_PORT_GENERAL && + in_modifier != MLX4_SET_PORT_GID_TABLE) { mlx4_warn(dev, "denying SET_PORT for slave:%d\n", slave); return -EINVAL; @@ -581,6 +612,67 @@ static int mlx4_common_set_port(struct mlx4_dev *dev, int slave, u32 in_mod, gen_context->mtu = cpu_to_be16(master->max_mtu[port]); break; + case MLX4_SET_PORT_GID_TABLE: + /* change to MULTIPLE entries: number of guest's gids + * need a FOR-loop here over number of gids the guest has. + * 1. Check no duplicates in gids passed by slave + */ + num_gids = mlx4_get_slave_num_gids(dev, slave); + base = mlx4_get_base_gid_ix(dev, slave); + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (i = 0; i < num_gids; gid_entry_mbox++, i++) { + if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, + sizeof(zgid_entry))) + continue; + gid_entry_mb1 = gid_entry_mbox + 1; + for (j = i + 1; j < num_gids; gid_entry_mb1++, j++) { + if (!memcmp(gid_entry_mb1->raw, + zgid_entry.raw, sizeof(zgid_entry))) + continue; + if (!memcmp(gid_entry_mb1->raw, gid_entry_mbox->raw, + sizeof(gid_entry_mbox->raw))) { + /* found duplicate */ + return -EINVAL; + } + } + } + + /* 2. Check that do not have duplicates in OTHER + * entries in the port GID table + */ + for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { + if (i >= base && i < base + num_gids) + continue; /* don't compare to slave's current gids */ + gid_entry_tbl = &priv->roce_gids[port - 1][i]; + if (!memcmp(gid_entry_tbl->raw, zgid_entry.raw, sizeof(zgid_entry))) + continue; + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (j = 0; j < num_gids; gid_entry_mbox++, j++) { + if (!memcmp(gid_entry_mbox->raw, zgid_entry.raw, + sizeof(zgid_entry))) + continue; + if (!memcmp(gid_entry_mbox->raw, gid_entry_tbl->raw, + sizeof(gid_entry_tbl->raw))) { + /* found duplicate */ + mlx4_warn(dev, "requested gid entry for slave:%d " + "is a duplicate of gid at index %d\n", + slave, i); + return -EINVAL; + } + } + } + + /* insert slave GIDs with memcpy, starting at slave's base index */ + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (i = 0, offset = base; i < num_gids; gid_entry_mbox++, offset++, i++) + memcpy(priv->roce_gids[port - 1][offset].raw, gid_entry_mbox->raw, 16); + + /* Now, copy roce port gids table to current mailbox for passing to FW */ + gid_entry_mbox = (struct mlx4_roce_gid_entry *)(inbox->buf); + for (i = 0; i < MLX4_ROCE_MAX_GIDS; gid_entry_mbox++, i++) + memcpy(gid_entry_mbox->raw, priv->roce_gids[port - 1][i].raw, 16); + + break; } return mlx4_cmd(dev, inbox->dma, in_mod, op_mod, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, @@ -927,3 +1019,51 @@ void mlx4_set_stats_bitmap(struct mlx4_dev *dev, u64 *stats_bitmap) *stats_bitmap |= MLX4_STATS_ERROR_COUNTERS_MASK; } EXPORT_SYMBOL(mlx4_set_stats_bitmap); + +int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid, + int *slave_id) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + int i, found_ix = -1; + int vf_gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS; + + if (!mlx4_is_mfunc(dev)) + return -EINVAL; + + for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) { + if (!memcmp(priv->roce_gids[port - 1][i].raw, gid, 16)) { + found_ix = i; + break; + } + } + + if (found_ix >= 0) { + if (found_ix < MLX4_ROCE_PF_GIDS) + *slave_id = 0; + else if (found_ix < MLX4_ROCE_PF_GIDS + (vf_gids % dev->num_vfs) * + (vf_gids / dev->num_vfs + 1)) + *slave_id = ((found_ix - MLX4_ROCE_PF_GIDS) / + (vf_gids / dev->num_vfs + 1)) + 1; + else + *slave_id = + ((found_ix - MLX4_ROCE_PF_GIDS - + ((vf_gids % dev->num_vfs) * ((vf_gids / dev->num_vfs + 1)))) / + (vf_gids / dev->num_vfs)) + vf_gids % dev->num_vfs + 1; + } + + return (found_ix >= 0) ? 0 : -EINVAL; +} +EXPORT_SYMBOL(mlx4_get_slave_from_roce_gid); + +int mlx4_get_roce_gid_from_slave(struct mlx4_dev *dev, int port, int slave_id, + u8 *gid) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + + if (!mlx4_is_master(dev)) + return -EINVAL; + + memcpy(gid, priv->roce_gids[port - 1][slave_id].raw, 16); + return 0; +} +EXPORT_SYMBOL(mlx4_get_roce_gid_from_slave); diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 57428a0cb9dd..74e490d70184 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -52,6 +52,8 @@ struct mac_res { struct list_head list; u64 mac; + int ref_count; + u8 smac_index; u8 port; }; @@ -219,6 +221,11 @@ struct res_fs_rule { int qpn; }; +static int mlx4_is_eth(struct mlx4_dev *dev, int port) +{ + return dev->caps.port_mask[port] == MLX4_PORT_TYPE_IB ? 0 : 1; +} + static void *res_tracker_lookup(struct rb_root *root, u64 res_id) { struct rb_node *node = root->rb_node; @@ -600,15 +607,34 @@ static void update_gid(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *inbox, struct mlx4_qp_context *qp_ctx = inbox->buf + 8; enum mlx4_qp_optpar optpar = be32_to_cpu(*(__be32 *) inbox->buf); u32 ts = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; + int port; - if (MLX4_QP_ST_UD == ts) - qp_ctx->pri_path.mgid_index = 0x80 | slave; - - if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_UC == ts) { - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) - qp_ctx->pri_path.mgid_index = slave & 0x7F; - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) - qp_ctx->alt_path.mgid_index = slave & 0x7F; + if (MLX4_QP_ST_UD == ts) { + port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port)) + qp_ctx->pri_path.mgid_index = mlx4_get_base_gid_ix(dev, slave) | 0x80; + else + qp_ctx->pri_path.mgid_index = slave | 0x80; + + } else if (MLX4_QP_ST_RC == ts || MLX4_QP_ST_XRC == ts || MLX4_QP_ST_UC == ts) { + if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { + port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port)) { + qp_ctx->pri_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); + qp_ctx->pri_path.mgid_index &= 0x7f; + } else { + qp_ctx->pri_path.mgid_index = slave & 0x7F; + } + } + if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { + port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port)) { + qp_ctx->alt_path.mgid_index += mlx4_get_base_gid_ix(dev, slave); + qp_ctx->alt_path.mgid_index &= 0x7f; + } else { + qp_ctx->alt_path.mgid_index = slave & 0x7F; + } + } } } @@ -619,7 +645,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev, struct mlx4_qp_context *qpc = inbox->buf + 8; struct mlx4_vport_oper_state *vp_oper; struct mlx4_priv *priv; - u32 qp_type; int port; port = (qpc->pri_path.sched_queue & 0x40) ? 2 : 1; @@ -627,12 +652,6 @@ static int update_vport_qp_param(struct mlx4_dev *dev, vp_oper = &priv->mfunc.master.vf_oper[slave].vport[port]; if (MLX4_VGT != vp_oper->state.default_vlan) { - qp_type = (be32_to_cpu(qpc->flags) >> 16) & 0xff; - if (MLX4_QP_ST_RC == qp_type || - (MLX4_QP_ST_UD == qp_type && - !mlx4_is_qp_reserved(dev, qpn))) - return -EINVAL; - /* the reserved QPs (special, proxy, tunnel) * do not operate over vlans */ @@ -1659,11 +1678,39 @@ static int srq_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, return err; } -static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) +static int mac_find_smac_ix_in_slave(struct mlx4_dev *dev, int slave, int port, + u8 smac_index, u64 *mac) { struct mlx4_priv *priv = mlx4_priv(dev); struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; - struct mac_res *res; + struct list_head *mac_list = + &tracker->slave_list[slave].res_list[RES_MAC]; + struct mac_res *res, *tmp; + + list_for_each_entry_safe(res, tmp, mac_list, list) { + if (res->smac_index == smac_index && res->port == (u8) port) { + *mac = res->mac; + return 0; + } + } + return -ENOENT; +} + +static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port, u8 smac_index) +{ + struct mlx4_priv *priv = mlx4_priv(dev); + struct mlx4_resource_tracker *tracker = &priv->mfunc.master.res_tracker; + struct list_head *mac_list = + &tracker->slave_list[slave].res_list[RES_MAC]; + struct mac_res *res, *tmp; + + list_for_each_entry_safe(res, tmp, mac_list, list) { + if (res->mac == mac && res->port == (u8) port) { + /* mac found. update ref count */ + ++res->ref_count; + return 0; + } + } if (mlx4_grant_resource(dev, slave, RES_MAC, 1, port)) return -EINVAL; @@ -1674,6 +1721,8 @@ static int mac_add_to_slave(struct mlx4_dev *dev, int slave, u64 mac, int port) } res->mac = mac; res->port = (u8) port; + res->smac_index = smac_index; + res->ref_count = 1; list_add_tail(&res->list, &tracker->slave_list[slave].res_list[RES_MAC]); return 0; @@ -1690,9 +1739,11 @@ static void mac_del_from_slave(struct mlx4_dev *dev, int slave, u64 mac, list_for_each_entry_safe(res, tmp, mac_list, list) { if (res->mac == mac && res->port == (u8) port) { - list_del(&res->list); - mlx4_release_resource(dev, slave, RES_MAC, 1, port); - kfree(res); + if (!--res->ref_count) { + list_del(&res->list); + mlx4_release_resource(dev, slave, RES_MAC, 1, port); + kfree(res); + } break; } } @@ -1705,10 +1756,13 @@ static void rem_slave_macs(struct mlx4_dev *dev, int slave) struct list_head *mac_list = &tracker->slave_list[slave].res_list[RES_MAC]; struct mac_res *res, *tmp; + int i; list_for_each_entry_safe(res, tmp, mac_list, list) { list_del(&res->list); - __mlx4_unregister_mac(dev, res->port, res->mac); + /* dereference the mac the num times the slave referenced it */ + for (i = 0; i < res->ref_count; i++) + __mlx4_unregister_mac(dev, res->port, res->mac); mlx4_release_resource(dev, slave, RES_MAC, 1, res->port); kfree(res); } @@ -1720,6 +1774,7 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, int err = -EINVAL; int port; u64 mac; + u8 smac_index; if (op != RES_OP_RESERVE_AND_MAP) return err; @@ -1729,12 +1784,13 @@ static int mac_alloc_res(struct mlx4_dev *dev, int slave, int op, int cmd, err = __mlx4_register_mac(dev, port, mac); if (err >= 0) { + smac_index = err; set_param_l(out_param, err); err = 0; } if (!err) { - err = mac_add_to_slave(dev, slave, mac, port); + err = mac_add_to_slave(dev, slave, mac, port, smac_index); if (err) __mlx4_unregister_mac(dev, port, mac); } @@ -2734,6 +2790,8 @@ static int verify_qp_parameters(struct mlx4_dev *dev, u32 qp_type; struct mlx4_qp_context *qp_ctx; enum mlx4_qp_optpar optpar; + int port; + int num_gids; qp_ctx = inbox->buf + 8; qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff; @@ -2741,6 +2799,7 @@ static int verify_qp_parameters(struct mlx4_dev *dev, switch (qp_type) { case MLX4_QP_ST_RC: + case MLX4_QP_ST_XRC: case MLX4_QP_ST_UC: switch (transition) { case QP_TRANS_INIT2RTR: @@ -2749,13 +2808,24 @@ static int verify_qp_parameters(struct mlx4_dev *dev, case QP_TRANS_SQD2SQD: case QP_TRANS_SQD2RTS: if (slave != mlx4_master_func_num(dev)) - /* slaves have only gid index 0 */ - if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) - if (qp_ctx->pri_path.mgid_index) + if (optpar & MLX4_QP_OPTPAR_PRIMARY_ADDR_PATH) { + port = (qp_ctx->pri_path.sched_queue >> 6 & 1) + 1; + if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) + num_gids = mlx4_get_slave_num_gids(dev, slave); + else + num_gids = 1; + if (qp_ctx->pri_path.mgid_index >= num_gids) return -EINVAL; - if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) - if (qp_ctx->alt_path.mgid_index) + } + if (optpar & MLX4_QP_OPTPAR_ALT_ADDR_PATH) { + port = (qp_ctx->alt_path.sched_queue >> 6 & 1) + 1; + if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) + num_gids = mlx4_get_slave_num_gids(dev, slave); + else + num_gids = 1; + if (qp_ctx->alt_path.mgid_index >= num_gids) return -EINVAL; + } break; default: break; @@ -3268,6 +3338,25 @@ int mlx4_INIT2INIT_QP_wrapper(struct mlx4_dev *dev, int slave, return mlx4_GEN_QP_wrapper(dev, slave, vhcr, inbox, outbox, cmd); } +static int roce_verify_mac(struct mlx4_dev *dev, int slave, + struct mlx4_qp_context *qpc, + struct mlx4_cmd_mailbox *inbox) +{ + u64 mac; + int port; + u32 ts = (be32_to_cpu(qpc->flags) >> 16) & 0xff; + u8 sched = *(u8 *)(inbox->buf + 64); + u8 smac_ix; + + port = (sched >> 6 & 1) + 1; + if (mlx4_is_eth(dev, port) && (ts != MLX4_QP_ST_MLX)) { + smac_ix = qpc->pri_path.grh_mylmc & 0x7f; + if (mac_find_smac_ix_in_slave(dev, slave, port, smac_ix, &mac)) + return -ENOENT; + } + return 0; +} + int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, struct mlx4_vhcr *vhcr, struct mlx4_cmd_mailbox *inbox, @@ -3290,6 +3379,9 @@ int mlx4_INIT2RTR_QP_wrapper(struct mlx4_dev *dev, int slave, if (err) return err; + if (roce_verify_mac(dev, slave, qpc, inbox)) + return -EINVAL; + update_pkey_index(dev, slave, inbox); update_gid(dev, inbox, (u8)slave); adjust_proxy_tun_qkey(dev, vhcr, qpc); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig index 157fe8df2c3e..8ff57e8e3e91 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ b/drivers/net/ethernet/mellanox/mlx5/core/Kconfig @@ -4,5 +4,5 @@ config MLX5_CORE tristate - depends on PCI && X86 + depends on PCI default n diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index a064f06e0cb8..77ac95f052da 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -46,8 +46,8 @@ #include "mlx5_core.h" #define DRIVER_NAME "mlx5_core" -#define DRIVER_VERSION "1.0" -#define DRIVER_RELDATE "June 2013" +#define DRIVER_VERSION "2.2-1" +#define DRIVER_RELDATE "Feb 2014" MODULE_AUTHOR("Eli Cohen <eli@mellanox.com>"); MODULE_DESCRIPTION("Mellanox ConnectX-IB HCA core library"); @@ -116,7 +116,6 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev) struct mlx5_eq_table *table = &dev->priv.eq_table; int num_eqs = 1 << dev->caps.log_max_eq; int nvec; - int err; int i; nvec = dev->caps.num_ports * num_online_cpus() + MLX5_EQ_VEC_COMP_BASE; @@ -131,17 +130,12 @@ static int mlx5_enable_msix(struct mlx5_core_dev *dev) for (i = 0; i < nvec; i++) table->msix_arr[i].entry = i; -retry: - table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE; - err = pci_enable_msix(dev->pdev, table->msix_arr, nvec); - if (err <= 0) { - return err; - } else if (err > 2) { - nvec = err; - goto retry; - } + nvec = pci_enable_msix_range(dev->pdev, table->msix_arr, + MLX5_EQ_VEC_COMP_BASE, nvec); + if (nvec < 0) + return nvec; - mlx5_core_dbg(dev, "received %d MSI vectors out of %d requested\n", err, nvec); + table->num_comp_vectors = nvec - MLX5_EQ_VEC_COMP_BASE; return 0; } @@ -537,7 +531,6 @@ static int __init init(void) return 0; - mlx5_health_cleanup(); err_debug: mlx5_unregister_debugfs(); return err; diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c index 68026f7e8ba3..130f6b204efa 100644 --- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c +++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c @@ -2329,16 +2329,14 @@ static int myri10ge_request_irq(struct myri10ge_priv *mgp) status = 0; if (myri10ge_msi) { if (mgp->num_slices > 1) { - status = - pci_enable_msix(pdev, mgp->msix_vectors, - mgp->num_slices); - if (status == 0) { - mgp->msix_enabled = 1; - } else { + status = pci_enable_msix_range(pdev, mgp->msix_vectors, + mgp->num_slices, mgp->num_slices); + if (status < 0) { dev_err(&pdev->dev, "Error %d setting up MSI-X\n", status); return status; } + mgp->msix_enabled = 1; } if (mgp->msix_enabled == 0) { status = pci_enable_msi(pdev); @@ -3895,32 +3893,34 @@ static void myri10ge_probe_slices(struct myri10ge_priv *mgp) mgp->msix_vectors = kcalloc(mgp->num_slices, sizeof(*mgp->msix_vectors), GFP_KERNEL); if (mgp->msix_vectors == NULL) - goto disable_msix; + goto no_msix; for (i = 0; i < mgp->num_slices; i++) { mgp->msix_vectors[i].entry = i; } while (mgp->num_slices > 1) { - /* make sure it is a power of two */ - while (!is_power_of_2(mgp->num_slices)) - mgp->num_slices--; + mgp->num_slices = rounddown_pow_of_two(mgp->num_slices); if (mgp->num_slices == 1) - goto disable_msix; - status = pci_enable_msix(pdev, mgp->msix_vectors, - mgp->num_slices); - if (status == 0) { - pci_disable_msix(pdev); + goto no_msix; + status = pci_enable_msix_range(pdev, + mgp->msix_vectors, + mgp->num_slices, + mgp->num_slices); + if (status < 0) + goto no_msix; + + pci_disable_msix(pdev); + + if (status == mgp->num_slices) { if (old_allocated) kfree(old_fw); return; - } - if (status > 0) + } else { mgp->num_slices = status; - else - goto disable_msix; + } } -disable_msix: +no_msix: if (mgp->msix_vectors != NULL) { kfree(mgp->msix_vectors); mgp->msix_vectors = NULL; diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index 9eeddbd0b2c7..56e3a9d42bb2 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -3792,9 +3792,10 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) writeq(rx_mat, &bar0->rx_mat); readq(&bar0->rx_mat); - ret = pci_enable_msix(nic->pdev, nic->entries, nic->num_entries); + ret = pci_enable_msix_range(nic->pdev, nic->entries, + nic->num_entries, nic->num_entries); /* We fail init if error or we get less vectors than min required */ - if (ret) { + if (ret < 0) { DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n"); kfree(nic->entries); swstats->mem_freed += nic->num_entries * diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c index 1ded50ca1600..c83cedd26dec 100644 --- a/drivers/net/ethernet/neterion/vxge/vxge-main.c +++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c @@ -726,9 +726,6 @@ static int vxge_learn_mac(struct vxgedev *vdev, u8 *mac_header) int vpath_idx = 0; enum vxge_hw_status status = VXGE_HW_OK; struct vxge_vpath *vpath = NULL; - struct __vxge_hw_device *hldev; - - hldev = pci_get_drvdata(vdev->pdev); mac_address = (u8 *)&mac_addr; memcpy(mac_address, mac_header, ETH_ALEN); @@ -2352,12 +2349,18 @@ start: vdev->vxge_entries[j].entry = VXGE_ALARM_MSIX_ID; vdev->vxge_entries[j].in_use = 0; - ret = pci_enable_msix(vdev->pdev, vdev->entries, vdev->intr_cnt); - if (ret > 0) { + ret = pci_enable_msix_range(vdev->pdev, + vdev->entries, 3, vdev->intr_cnt); + if (ret < 0) { + ret = -ENODEV; + goto enable_msix_failed; + } else if (ret < vdev->intr_cnt) { + pci_disable_msix(vdev->pdev); + vxge_debug_init(VXGE_ERR, "%s: MSI-X enable failed for %d vectors, ret: %d", VXGE_DRIVER_NAME, vdev->intr_cnt, ret); - if ((max_config_vpath != VXGE_USE_DEFAULT) || (ret < 3)) { + if (max_config_vpath != VXGE_USE_DEFAULT) { ret = -ENODEV; goto enable_msix_failed; } @@ -2371,9 +2374,6 @@ start: vxge_close_vpaths(vdev, temp); vdev->no_of_vpath = temp; goto start; - } else if (ret < 0) { - ret = -ENODEV; - goto enable_msix_failed; } return 0; @@ -2443,9 +2443,6 @@ static void vxge_rem_msix_isr(struct vxgedev *vdev) static void vxge_rem_isr(struct vxgedev *vdev) { - struct __vxge_hw_device *hldev; - hldev = pci_get_drvdata(vdev->pdev); - #ifdef CONFIG_PCI_MSI if (vdev->config.intr_type == MSI_X) { vxge_rem_msix_isr(vdev); diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c index 70cf97fe67f2..bad3c057ee8a 100644 --- a/drivers/net/ethernet/nvidia/forcedeth.c +++ b/drivers/net/ethernet/nvidia/forcedeth.c @@ -3930,7 +3930,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test) { struct fe_priv *np = get_nvpriv(dev); u8 __iomem *base = get_hwbase(dev); - int ret = 1; + int ret; int i; irqreturn_t (*handler)(int foo, void *data); @@ -3946,14 +3946,18 @@ static int nv_request_irq(struct net_device *dev, int intr_test) if (np->msi_flags & NV_MSI_X_CAPABLE) { for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) np->msi_x_entry[i].entry = i; - ret = pci_enable_msix(np->pci_dev, np->msi_x_entry, (np->msi_flags & NV_MSI_X_VECTORS_MASK)); - if (ret == 0) { + ret = pci_enable_msix_range(np->pci_dev, + np->msi_x_entry, + np->msi_flags & NV_MSI_X_VECTORS_MASK, + np->msi_flags & NV_MSI_X_VECTORS_MASK); + if (ret > 0) { np->msi_flags |= NV_MSI_X_ENABLED; if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT && !intr_test) { /* Request irq for rx handling */ sprintf(np->name_rx, "%s-rx", dev->name); - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, - nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev) != 0) { + ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector, + nv_nic_irq_rx, IRQF_SHARED, np->name_rx, dev); + if (ret) { netdev_info(dev, "request_irq failed for rx %d\n", ret); @@ -3963,8 +3967,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test) } /* Request irq for tx handling */ sprintf(np->name_tx, "%s-tx", dev->name); - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, - nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev) != 0) { + ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector, + nv_nic_irq_tx, IRQF_SHARED, np->name_tx, dev); + if (ret) { netdev_info(dev, "request_irq failed for tx %d\n", ret); @@ -3974,8 +3979,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test) } /* Request irq for link and timer handling */ sprintf(np->name_other, "%s-other", dev->name); - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, - nv_nic_irq_other, IRQF_SHARED, np->name_other, dev) != 0) { + ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector, + nv_nic_irq_other, IRQF_SHARED, np->name_other, dev); + if (ret) { netdev_info(dev, "request_irq failed for link %d\n", ret); @@ -3991,7 +3997,9 @@ static int nv_request_irq(struct net_device *dev, int intr_test) set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER); } else { /* Request irq for all interrupts */ - if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) { + ret = request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, + handler, IRQF_SHARED, dev->name, dev); + if (ret) { netdev_info(dev, "request_irq failed %d\n", ret); @@ -4005,13 +4013,15 @@ static int nv_request_irq(struct net_device *dev, int intr_test) writel(0, base + NvRegMSIXMap1); } netdev_info(dev, "MSI-X enabled\n"); + return 0; } } - if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) { + if (np->msi_flags & NV_MSI_CAPABLE) { ret = pci_enable_msi(np->pci_dev); if (ret == 0) { np->msi_flags |= NV_MSI_ENABLED; - if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) { + ret = request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev); + if (ret) { netdev_info(dev, "request_irq failed %d\n", ret); pci_disable_msi(np->pci_dev); @@ -4025,13 +4035,12 @@ static int nv_request_irq(struct net_device *dev, int intr_test) /* enable msi vector 0 */ writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask); netdev_info(dev, "MSI enabled\n"); + return 0; } } - if (ret != 0) { - if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) - goto out_err; - } + if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) + goto out_err; return 0; out_free_tx: diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c index 70849dea32b1..f09c35d669b3 100644 --- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c +++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c @@ -643,8 +643,9 @@ static int netxen_setup_msi_interrupts(struct netxen_adapter *adapter, if (adapter->msix_supported) { netxen_init_msix_entries(adapter, num_msix); - err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err == 0) { + err = pci_enable_msix_range(pdev, adapter->msix_entries, + num_msix, num_msix); + if (err > 0) { adapter->flags |= NETXEN_NIC_MSIX_ENABLED; netxen_set_msix_bit(pdev, 1); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h index f19f81cde134..df9daa335292 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 55 -#define QLCNIC_LINUX_VERSIONID "5.3.55" +#define _QLCNIC_LINUX_SUBVERSION 56 +#define QLCNIC_LINUX_VERSIONID "5.3.56" #define QLCNIC_DRV_IDC_VER 0x01 #define QLCNIC_DRIVER_VERSION ((_QLCNIC_LINUX_MAJOR << 16) |\ (_QLCNIC_LINUX_MINOR << 8) | (_QLCNIC_LINUX_SUBVERSION)) @@ -394,7 +394,7 @@ struct qlcnic_nic_intr_coalesce { u32 timer_out; }; -struct qlcnic_dump_template_hdr { +struct qlcnic_83xx_dump_template_hdr { u32 type; u32 offset; u32 size; @@ -411,15 +411,42 @@ struct qlcnic_dump_template_hdr { u32 rsvd[0]; }; +struct qlcnic_82xx_dump_template_hdr { + u32 type; + u32 offset; + u32 size; + u32 cap_mask; + u32 num_entries; + u32 version; + u32 timestamp; + u32 checksum; + u32 drv_cap_mask; + u32 sys_info[3]; + u32 saved_state[16]; + u32 cap_sizes[8]; + u32 rsvd[7]; + u32 capabilities; + u32 rsvd1[0]; +}; + struct qlcnic_fw_dump { u8 clr; /* flag to indicate if dump is cleared */ bool enable; /* enable/disable dump */ u32 size; /* total size of the dump */ + u32 cap_mask; /* Current capture mask */ void *data; /* dump data area */ - struct qlcnic_dump_template_hdr *tmpl_hdr; + void *tmpl_hdr; dma_addr_t phys_addr; void *dma_buffer; bool use_pex_dma; + /* Read only elements which are common between 82xx and 83xx + * template header. Update these values immediately after we read + * template header from Firmware + */ + u32 tmpl_hdr_size; + u32 version; + u32 num_entries; + u32 offset; }; /* @@ -1769,6 +1796,12 @@ struct qlcnic_hardware_ops { struct qlcnic_host_tx_ring *); void (*disable_tx_intr) (struct qlcnic_adapter *, struct qlcnic_host_tx_ring *); + u32 (*get_saved_state)(void *, u32); + void (*set_saved_state)(void *, u32, u32); + void (*cache_tmpl_hdr_values)(struct qlcnic_fw_dump *); + u32 (*get_cap_size)(void *, int); + void (*set_sys_info)(void *, int, u32); + void (*store_cap_mask)(void *, u32); }; extern struct qlcnic_nic_template qlcnic_vf_ops; @@ -2007,6 +2040,42 @@ static inline void qlcnic_read_phys_port_id(struct qlcnic_adapter *adapter) adapter->ahw->hw_ops->read_phys_port_id(adapter); } +static inline u32 qlcnic_get_saved_state(struct qlcnic_adapter *adapter, + void *t_hdr, u32 index) +{ + return adapter->ahw->hw_ops->get_saved_state(t_hdr, index); +} + +static inline void qlcnic_set_saved_state(struct qlcnic_adapter *adapter, + void *t_hdr, u32 index, u32 value) +{ + adapter->ahw->hw_ops->set_saved_state(t_hdr, index, value); +} + +static inline void qlcnic_cache_tmpl_hdr_values(struct qlcnic_adapter *adapter, + struct qlcnic_fw_dump *fw_dump) +{ + adapter->ahw->hw_ops->cache_tmpl_hdr_values(fw_dump); +} + +static inline u32 qlcnic_get_cap_size(struct qlcnic_adapter *adapter, + void *tmpl_hdr, int index) +{ + return adapter->ahw->hw_ops->get_cap_size(tmpl_hdr, index); +} + +static inline void qlcnic_set_sys_info(struct qlcnic_adapter *adapter, + void *tmpl_hdr, int idx, u32 value) +{ + adapter->ahw->hw_ops->set_sys_info(tmpl_hdr, idx, value); +} + +static inline void qlcnic_store_cap_mask(struct qlcnic_adapter *adapter, + void *tmpl_hdr, u32 mask) +{ + adapter->ahw->hw_ops->store_cap_mask(tmpl_hdr, mask); +} + static inline void qlcnic_dev_request_reset(struct qlcnic_adapter *adapter, u32 key) { diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 4146664d4d6a..3b83fbde4975 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -203,7 +203,12 @@ static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = { .disable_sds_intr = qlcnic_83xx_disable_sds_intr, .enable_tx_intr = qlcnic_83xx_enable_tx_intr, .disable_tx_intr = qlcnic_83xx_disable_tx_intr, - + .get_saved_state = qlcnic_83xx_get_saved_state, + .set_saved_state = qlcnic_83xx_set_saved_state, + .cache_tmpl_hdr_values = qlcnic_83xx_cache_tmpl_hdr_values, + .get_cap_size = qlcnic_83xx_get_cap_size, + .set_sys_info = qlcnic_83xx_set_sys_info, + .store_cap_mask = qlcnic_83xx_store_cap_mask, }; static struct qlcnic_nic_template qlcnic_83xx_ops = { @@ -340,6 +345,7 @@ int qlcnic_83xx_setup_intr(struct qlcnic_adapter *adapter) if (qlcnic_sriov_vf_check(adapter)) return -EINVAL; num_msix = 1; + adapter->drv_sds_rings = QLCNIC_SINGLE_RING; adapter->drv_tx_rings = QLCNIC_SINGLE_RING; } } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h index f92485ca21d1..81c1889f6f3e 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h @@ -308,6 +308,8 @@ struct qlc_83xx_reset { #define QLC_83XX_IDC_FLASH_PARAM_ADDR 0x3e8020 struct qlcnic_adapter; +struct qlcnic_fw_dump; + struct qlc_83xx_idc { int (*state_entry) (struct qlcnic_adapter *); u64 sec_counter; @@ -650,4 +652,10 @@ int qlcnic_83xx_check_vnic_state(struct qlcnic_adapter *); void qlcnic_83xx_aer_stop_poll_work(struct qlcnic_adapter *); int qlcnic_83xx_aer_reset(struct qlcnic_adapter *); void qlcnic_83xx_aer_start_poll_work(struct qlcnic_adapter *); +u32 qlcnic_83xx_get_saved_state(void *, u32); +void qlcnic_83xx_set_saved_state(void *, u32, u32); +void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *); +u32 qlcnic_83xx_get_cap_size(void *, int); +void qlcnic_83xx_set_sys_info(void *, int, u32); +void qlcnic_83xx_store_cap_mask(void *, u32); #endif diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c index 77f1bce432d2..7d4f54912bad 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_dcb.c @@ -807,7 +807,7 @@ qlcnic_dcb_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, u8 *prio, !type->tc_param_valid) return; - if (tc < 0 || (tc > QLC_DCB_MAX_TC)) + if (tc < 0 || (tc >= QLC_DCB_MAX_TC)) return; tc_cfg = &type->tc_cfg[tc]; @@ -843,7 +843,7 @@ static void qlcnic_dcb_get_pg_bwg_cfg_tx(struct net_device *netdev, int pgid, !type->tc_param_valid) return; - if (pgid < 0 || pgid > QLC_DCB_MAX_PG) + if (pgid < 0 || pgid >= QLC_DCB_MAX_PG) return; pgcfg = &type->pg_cfg[pgid]; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c index acee1a5d80c6..1960609481ce 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ethtool.c @@ -1639,14 +1639,14 @@ qlcnic_get_dump_flag(struct net_device *netdev, struct ethtool_dump *dump) } if (fw_dump->clr) - dump->len = fw_dump->tmpl_hdr->size + fw_dump->size; + dump->len = fw_dump->tmpl_hdr_size + fw_dump->size; else dump->len = 0; if (!qlcnic_check_fw_dump_state(adapter)) dump->flag = ETH_FW_DUMP_DISABLE; else - dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->flag = fw_dump->cap_mask; dump->version = adapter->fw_version; return 0; @@ -1671,9 +1671,10 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, netdev_info(netdev, "Dump not available\n"); return -EINVAL; } + /* Copy template header first */ - copy_sz = fw_dump->tmpl_hdr->size; - hdr_ptr = (u32 *) fw_dump->tmpl_hdr; + copy_sz = fw_dump->tmpl_hdr_size; + hdr_ptr = (u32 *)fw_dump->tmpl_hdr; data = buffer; for (i = 0; i < copy_sz/sizeof(u32); i++) *data++ = cpu_to_le32(*hdr_ptr++); @@ -1681,7 +1682,7 @@ qlcnic_get_dump_data(struct net_device *netdev, struct ethtool_dump *dump, /* Copy captured dump data */ memcpy(buffer + copy_sz, fw_dump->data, fw_dump->size); dump->len = copy_sz + fw_dump->size; - dump->flag = fw_dump->tmpl_hdr->drv_cap_mask; + dump->flag = fw_dump->cap_mask; /* Free dump area once data has been captured */ vfree(fw_dump->data); @@ -1703,7 +1704,11 @@ static int qlcnic_set_dump_mask(struct qlcnic_adapter *adapter, u32 mask) return -EOPNOTSUPP; } - fw_dump->tmpl_hdr->drv_cap_mask = mask; + fw_dump->cap_mask = mask; + + /* Store new capture mask in template header as well*/ + qlcnic_store_cap_mask(adapter, fw_dump->tmpl_hdr, mask); + netdev_info(netdev, "Driver mask changed to: 0x%x\n", mask); return 0; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c index 03d18a0be6ce..9f3adf4e70b5 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c @@ -317,9 +317,7 @@ static void qlcnic_write_window_reg(u32 addr, void __iomem *bar0, u32 data) int qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) { - int timeout = 0; - int err = 0; - u32 done = 0; + int timeout = 0, err = 0, done = 0; while (!done) { done = QLCRD32(adapter, QLCNIC_PCIE_REG(PCIE_SEM_LOCK(sem)), @@ -327,10 +325,20 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) if (done == 1) break; if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { - dev_err(&adapter->pdev->dev, - "Failed to acquire sem=%d lock; holdby=%d\n", - sem, - id_reg ? QLCRD32(adapter, id_reg, &err) : -1); + if (id_reg) { + done = QLCRD32(adapter, id_reg, &err); + if (done != -1) + dev_err(&adapter->pdev->dev, + "Failed to acquire sem=%d lock held by=%d\n", + sem, done); + else + dev_err(&adapter->pdev->dev, + "Failed to acquire sem=%d lock", + sem); + } else { + dev_err(&adapter->pdev->dev, + "Failed to acquire sem=%d lock", sem); + } return -EIO; } msleep(1); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h index 63d75617d445..576b301b11ef 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.h @@ -161,6 +161,7 @@ struct qlcnic_host_sds_ring; struct qlcnic_host_tx_ring; struct qlcnic_hardware_context; struct qlcnic_adapter; +struct qlcnic_fw_dump; int qlcnic_82xx_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong, int *); int qlcnic_82xx_hw_write_wx_2M(struct qlcnic_adapter *, ulong, u32); @@ -213,4 +214,11 @@ int qlcnic_82xx_shutdown(struct pci_dev *); int qlcnic_82xx_resume(struct qlcnic_adapter *); void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8 failed); void qlcnic_fw_poll_work(struct work_struct *work); + +u32 qlcnic_82xx_get_saved_state(void *, u32); +void qlcnic_82xx_set_saved_state(void *, u32, u32); +void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *); +u32 qlcnic_82xx_get_cap_size(void *, int); +void qlcnic_82xx_set_sys_info(void *, int, u32); +void qlcnic_82xx_store_cap_mask(void *, u32); #endif /* __QLCNIC_HW_H_ */ diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index ba78c7481fa3..4b92d9d90267 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -90,7 +90,6 @@ static void qlcnic_82xx_io_resume(struct pci_dev *); static void qlcnic_82xx_set_mac_filter_count(struct qlcnic_adapter *); static pci_ers_result_t qlcnic_82xx_io_error_detected(struct pci_dev *, pci_channel_state_t); - static u32 qlcnic_vlan_tx_check(struct qlcnic_adapter *adapter) { struct qlcnic_hardware_context *ahw = adapter->ahw; @@ -561,6 +560,12 @@ static struct qlcnic_hardware_ops qlcnic_hw_ops = { .disable_sds_intr = qlcnic_82xx_disable_sds_intr, .enable_tx_intr = qlcnic_82xx_enable_tx_intr, .disable_tx_intr = qlcnic_82xx_disable_tx_intr, + .get_saved_state = qlcnic_82xx_get_saved_state, + .set_saved_state = qlcnic_82xx_set_saved_state, + .cache_tmpl_hdr_values = qlcnic_82xx_cache_tmpl_hdr_values, + .get_cap_size = qlcnic_82xx_get_cap_size, + .set_sys_info = qlcnic_82xx_set_sys_info, + .store_cap_mask = qlcnic_82xx_store_cap_mask, }; static int qlcnic_check_multi_tx_capability(struct qlcnic_adapter *adapter) @@ -684,7 +689,7 @@ restore: int qlcnic_enable_msix(struct qlcnic_adapter *adapter, u32 num_msix) { struct pci_dev *pdev = adapter->pdev; - int err = -1, vector; + int err, vector; if (!adapter->msix_entries) { adapter->msix_entries = kcalloc(num_msix, @@ -701,13 +706,17 @@ enable_msix: for (vector = 0; vector < num_msix; vector++) adapter->msix_entries[vector].entry = vector; - err = pci_enable_msix(pdev, adapter->msix_entries, num_msix); - if (err == 0) { + err = pci_enable_msix_range(pdev, + adapter->msix_entries, 1, num_msix); + + if (err == num_msix) { adapter->flags |= QLCNIC_MSIX_ENABLED; adapter->ahw->num_msix = num_msix; dev_info(&pdev->dev, "using msi-x interrupts\n"); - return err; + return 0; } else if (err > 0) { + pci_disable_msix(pdev); + dev_info(&pdev->dev, "Unable to allocate %d MSI-X vectors, Available vectors %d\n", num_msix, err); @@ -715,12 +724,12 @@ enable_msix: if (qlcnic_82xx_check(adapter)) { num_msix = rounddown_pow_of_two(err); if (err < QLCNIC_82XX_MINIMUM_VECTOR) - return -EIO; + return -ENOSPC; } else { num_msix = rounddown_pow_of_two(err - 1); num_msix += 1; if (err < QLCNIC_83XX_MINIMUM_VECTOR) - return -EIO; + return -ENOSPC; } if (qlcnic_82xx_check(adapter) && @@ -747,7 +756,7 @@ enable_msix: } } - return err; + return -EIO; } static int qlcnic_82xx_calculate_msix_vector(struct qlcnic_adapter *adapter) @@ -816,9 +825,10 @@ static int qlcnic_82xx_setup_intr(struct qlcnic_adapter *adapter) if (!(adapter->flags & QLCNIC_MSIX_ENABLED)) { qlcnic_disable_multi_tx(adapter); + adapter->drv_sds_rings = QLCNIC_SINGLE_RING; err = qlcnic_enable_msi_legacy(adapter); - if (!err) + if (err) return err; } } @@ -2441,8 +2451,8 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) { switch (err) { case -ENOTRECOVERABLE: - dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware. Please reboot\n"); - dev_err(&pdev->dev, "If reboot doesn't help, please replace the adapter with new one and return the faulty adapter for repair\n"); + dev_err(&pdev->dev, "Adapter initialization failed due to a faulty hardware\n"); + dev_err(&pdev->dev, "Please replace the adapter with new one and return the faulty adapter for repair\n"); goto err_out_free_hw; case -ENOMEM: dev_err(&pdev->dev, "Adapter initialization failed. Please reboot\n"); @@ -3863,7 +3873,7 @@ int qlcnic_validate_rings(struct qlcnic_adapter *adapter, __u32 ring_cnt, strcpy(buf, "Tx"); } - if (!qlcnic_use_msi_x && !qlcnic_use_msi) { + if (!QLCNIC_IS_MSI_FAMILY(adapter)) { netdev_err(netdev, "No RSS/TSS support in INT-x mode\n"); return -EINVAL; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c index 7763962e2ec4..37b979b1266b 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c @@ -211,6 +211,107 @@ enum qlcnic_minidump_opcode { QLCNIC_DUMP_RDEND = 255 }; +inline u32 qlcnic_82xx_get_saved_state(void *t_hdr, u32 index) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + return hdr->saved_state[index]; +} + +inline void qlcnic_82xx_set_saved_state(void *t_hdr, u32 index, + u32 value) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + hdr->saved_state[index] = value; +} + +void qlcnic_82xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump) +{ + struct qlcnic_82xx_dump_template_hdr *hdr; + + hdr = fw_dump->tmpl_hdr; + fw_dump->tmpl_hdr_size = hdr->size; + fw_dump->version = hdr->version; + fw_dump->num_entries = hdr->num_entries; + fw_dump->offset = hdr->offset; + + hdr->drv_cap_mask = hdr->cap_mask; + fw_dump->cap_mask = hdr->cap_mask; +} + +inline u32 qlcnic_82xx_get_cap_size(void *t_hdr, int index) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + return hdr->cap_sizes[index]; +} + +void qlcnic_82xx_set_sys_info(void *t_hdr, int idx, u32 value) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = t_hdr; + + hdr->sys_info[idx] = value; +} + +void qlcnic_82xx_store_cap_mask(void *tmpl_hdr, u32 mask) +{ + struct qlcnic_82xx_dump_template_hdr *hdr = tmpl_hdr; + + hdr->drv_cap_mask = mask; +} + +inline u32 qlcnic_83xx_get_saved_state(void *t_hdr, u32 index) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + return hdr->saved_state[index]; +} + +inline void qlcnic_83xx_set_saved_state(void *t_hdr, u32 index, + u32 value) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + hdr->saved_state[index] = value; +} + +void qlcnic_83xx_cache_tmpl_hdr_values(struct qlcnic_fw_dump *fw_dump) +{ + struct qlcnic_83xx_dump_template_hdr *hdr; + + hdr = fw_dump->tmpl_hdr; + fw_dump->tmpl_hdr_size = hdr->size; + fw_dump->version = hdr->version; + fw_dump->num_entries = hdr->num_entries; + fw_dump->offset = hdr->offset; + + hdr->drv_cap_mask = hdr->cap_mask; + fw_dump->cap_mask = hdr->cap_mask; +} + +inline u32 qlcnic_83xx_get_cap_size(void *t_hdr, int index) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + return hdr->cap_sizes[index]; +} + +void qlcnic_83xx_set_sys_info(void *t_hdr, int idx, u32 value) +{ + struct qlcnic_83xx_dump_template_hdr *hdr = t_hdr; + + hdr->sys_info[idx] = value; +} + +void qlcnic_83xx_store_cap_mask(void *tmpl_hdr, u32 mask) +{ + struct qlcnic_83xx_dump_template_hdr *hdr; + + hdr = tmpl_hdr; + hdr->drv_cap_mask = mask; +} + struct qlcnic_dump_operations { enum qlcnic_minidump_opcode opcode; u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *, @@ -238,11 +339,11 @@ static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter, static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, __le32 *buffer) { + void *hdr = adapter->ahw->fw_dump.tmpl_hdr; + struct __ctrl *ctr = &entry->region.ctrl; int i, k, timeout = 0; - u32 addr, data; + u32 addr, data, temp; u8 no_ops; - struct __ctrl *ctr = &entry->region.ctrl; - struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr; addr = ctr->addr; no_ops = ctr->no_ops; @@ -285,29 +386,42 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, } break; case QLCNIC_DUMP_RD_SAVE: - if (ctr->index_a) - addr = t_hdr->saved_state[ctr->index_a]; + temp = ctr->index_a; + if (temp) + addr = qlcnic_get_saved_state(adapter, + hdr, + temp); data = qlcnic_ind_rd(adapter, addr); - t_hdr->saved_state[ctr->index_v] = data; + qlcnic_set_saved_state(adapter, hdr, + ctr->index_v, data); break; case QLCNIC_DUMP_WRT_SAVED: - if (ctr->index_v) - data = t_hdr->saved_state[ctr->index_v]; + temp = ctr->index_v; + if (temp) + data = qlcnic_get_saved_state(adapter, + hdr, + temp); else data = ctr->val1; - if (ctr->index_a) - addr = t_hdr->saved_state[ctr->index_a]; + + temp = ctr->index_a; + if (temp) + addr = qlcnic_get_saved_state(adapter, + hdr, + temp); qlcnic_ind_wr(adapter, addr, data); break; case QLCNIC_DUMP_MOD_SAVE_ST: - data = t_hdr->saved_state[ctr->index_v]; + data = qlcnic_get_saved_state(adapter, hdr, + ctr->index_v); data <<= ctr->shl_val; data >>= ctr->shr_val; if (ctr->val2) data &= ctr->val2; data |= ctr->val3; data += ctr->val1; - t_hdr->saved_state[ctr->index_v] = data; + qlcnic_set_saved_state(adapter, hdr, + ctr->index_v, data); break; default: dev_info(&adapter->pdev->dev, @@ -544,7 +658,7 @@ out: static int qlcnic_start_pex_dma(struct qlcnic_adapter *adapter, struct __mem *mem) { - struct qlcnic_dump_template_hdr *tmpl_hdr; + struct qlcnic_83xx_dump_template_hdr *tmpl_hdr; struct device *dev = &adapter->pdev->dev; u32 dma_no, dma_base_addr, temp_addr; int i, ret, dma_sts; @@ -596,7 +710,7 @@ static u32 qlcnic_read_memory_pexdma(struct qlcnic_adapter *adapter, struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; u32 temp, dma_base_addr, size = 0, read_size = 0; struct qlcnic_pex_dma_descriptor *dma_descr; - struct qlcnic_dump_template_hdr *tmpl_hdr; + struct qlcnic_83xx_dump_template_hdr *tmpl_hdr; struct device *dev = &adapter->pdev->dev; dma_addr_t dma_phys_addr; void *dma_buffer; @@ -938,8 +1052,8 @@ static int qlcnic_fw_flash_get_minidump_temp_size(struct qlcnic_adapter *adapter, struct qlcnic_cmd_args *cmd) { - struct qlcnic_dump_template_hdr tmp_hdr; - u32 size = sizeof(struct qlcnic_dump_template_hdr) / sizeof(u32); + struct qlcnic_83xx_dump_template_hdr tmp_hdr; + u32 size = sizeof(tmp_hdr) / sizeof(u32); int ret = 0; if (qlcnic_82xx_check(adapter)) @@ -1027,17 +1141,19 @@ free_mem: return err; } +#define QLCNIC_TEMPLATE_VERSION (0x20001) + int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) { - int err; - u32 temp_size = 0; - u32 version, csum, *tmp_buf; struct qlcnic_hardware_context *ahw; - struct qlcnic_dump_template_hdr *tmpl_hdr; + struct qlcnic_fw_dump *fw_dump; + u32 version, csum, *tmp_buf; u8 use_flash_temp = 0; + u32 temp_size = 0; + int err; ahw = adapter->ahw; - + fw_dump = &ahw->fw_dump; err = qlcnic_fw_get_minidump_temp_size(adapter, &version, &temp_size, &use_flash_temp); if (err) { @@ -1046,11 +1162,11 @@ int qlcnic_fw_cmd_get_minidump_temp(struct qlcnic_adapter *adapter) return -EIO; } - ahw->fw_dump.tmpl_hdr = vzalloc(temp_size); - if (!ahw->fw_dump.tmpl_hdr) + fw_dump->tmpl_hdr = vzalloc(temp_size); + if (!fw_dump->tmpl_hdr) return -ENOMEM; - tmp_buf = (u32 *)ahw->fw_dump.tmpl_hdr; + tmp_buf = (u32 *)fw_dump->tmpl_hdr; if (use_flash_temp) goto flash_temp; @@ -1065,8 +1181,8 @@ flash_temp: dev_err(&adapter->pdev->dev, "Failed to get minidump template header %d\n", err); - vfree(ahw->fw_dump.tmpl_hdr); - ahw->fw_dump.tmpl_hdr = NULL; + vfree(fw_dump->tmpl_hdr); + fw_dump->tmpl_hdr = NULL; return -EIO; } } @@ -1076,21 +1192,22 @@ flash_temp: if (csum) { dev_err(&adapter->pdev->dev, "Template header checksum validation failed\n"); - vfree(ahw->fw_dump.tmpl_hdr); - ahw->fw_dump.tmpl_hdr = NULL; + vfree(fw_dump->tmpl_hdr); + fw_dump->tmpl_hdr = NULL; return -EIO; } - tmpl_hdr = ahw->fw_dump.tmpl_hdr; - tmpl_hdr->drv_cap_mask = tmpl_hdr->cap_mask; + qlcnic_cache_tmpl_hdr_values(adapter, fw_dump); + dev_info(&adapter->pdev->dev, "Default minidump capture mask 0x%x\n", - tmpl_hdr->cap_mask); + fw_dump->cap_mask); - if ((tmpl_hdr->version & 0xfffff) >= 0x20001) - ahw->fw_dump.use_pex_dma = true; + if (qlcnic_83xx_check(adapter) && + (fw_dump->version & 0xfffff) >= QLCNIC_TEMPLATE_VERSION) + fw_dump->use_pex_dma = true; else - ahw->fw_dump.use_pex_dma = false; + fw_dump->use_pex_dma = false; qlcnic_enable_fw_dump_state(adapter); @@ -1099,21 +1216,22 @@ flash_temp: int qlcnic_dump_fw(struct qlcnic_adapter *adapter) { - __le32 *buffer; - u32 ocm_window; - char mesg[64]; - char *msg[] = {mesg, NULL}; - int i, k, ops_cnt, ops_index, dump_size = 0; - u32 entry_offset, dump, no_entries, buf_offset = 0; - struct qlcnic_dump_entry *entry; struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; - struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr; static const struct qlcnic_dump_operations *fw_dump_ops; + struct qlcnic_83xx_dump_template_hdr *hdr_83xx; + u32 entry_offset, dump, no_entries, buf_offset = 0; + int i, k, ops_cnt, ops_index, dump_size = 0; struct device *dev = &adapter->pdev->dev; struct qlcnic_hardware_context *ahw; - void *temp_buffer; + struct qlcnic_dump_entry *entry; + void *temp_buffer, *tmpl_hdr; + u32 ocm_window; + __le32 *buffer; + char mesg[64]; + char *msg[] = {mesg, NULL}; ahw = adapter->ahw; + tmpl_hdr = fw_dump->tmpl_hdr; /* Return if we don't have firmware dump template header */ if (!tmpl_hdr) @@ -1133,8 +1251,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) netif_info(adapter->ahw, drv, adapter->netdev, "Take FW dump\n"); /* Calculate the size for dump data area only */ for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++) - if (i & tmpl_hdr->drv_cap_mask) - dump_size += tmpl_hdr->cap_sizes[k]; + if (i & fw_dump->cap_mask) + dump_size += qlcnic_get_cap_size(adapter, tmpl_hdr, k); + if (!dump_size) return -EIO; @@ -1144,10 +1263,10 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) buffer = fw_dump->data; fw_dump->size = dump_size; - no_entries = tmpl_hdr->num_entries; - entry_offset = tmpl_hdr->offset; - tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION; - tmpl_hdr->sys_info[1] = adapter->fw_version; + no_entries = fw_dump->num_entries; + entry_offset = fw_dump->offset; + qlcnic_set_sys_info(adapter, tmpl_hdr, 0, QLCNIC_DRIVER_VERSION); + qlcnic_set_sys_info(adapter, tmpl_hdr, 1, adapter->fw_version); if (fw_dump->use_pex_dma) { temp_buffer = dma_alloc_coherent(dev, QLC_PEX_DMA_READ_SIZE, @@ -1163,16 +1282,17 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) ops_cnt = ARRAY_SIZE(qlcnic_fw_dump_ops); fw_dump_ops = qlcnic_fw_dump_ops; } else { + hdr_83xx = tmpl_hdr; ops_cnt = ARRAY_SIZE(qlcnic_83xx_fw_dump_ops); fw_dump_ops = qlcnic_83xx_fw_dump_ops; - ocm_window = tmpl_hdr->ocm_wnd_reg[adapter->ahw->pci_func]; - tmpl_hdr->saved_state[QLC_83XX_OCM_INDEX] = ocm_window; - tmpl_hdr->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func; + ocm_window = hdr_83xx->ocm_wnd_reg[ahw->pci_func]; + hdr_83xx->saved_state[QLC_83XX_OCM_INDEX] = ocm_window; + hdr_83xx->saved_state[QLC_83XX_PCI_INDEX] = ahw->pci_func; } for (i = 0; i < no_entries; i++) { - entry = (void *)tmpl_hdr + entry_offset; - if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) { + entry = tmpl_hdr + entry_offset; + if (!(entry->hdr.mask & fw_dump->cap_mask)) { entry->hdr.flags |= QLCNIC_DUMP_SKIP; entry_offset += entry->hdr.offset; continue; @@ -1209,8 +1329,9 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter) fw_dump->clr = 1; snprintf(mesg, sizeof(mesg), "FW_DUMP=%s", adapter->netdev->name); - dev_info(dev, "%s: Dump data %d bytes captured, template header size %d bytes\n", - adapter->netdev->name, fw_dump->size, tmpl_hdr->size); + netdev_info(adapter->netdev, + "Dump data %d bytes captured, template header size %d bytes\n", + fw_dump->size, fw_dump->tmpl_hdr_size); /* Send a udev event to notify availability of FW dump */ kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, msg); diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c index 09acf15c3a56..14f748cbf0de 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_pf.c @@ -13,10 +13,9 @@ #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 +#define QLC_SRIOV_ALLOW_VLAN0 BIT_19 static int qlcnic_sriov_pf_get_vport_handle(struct qlcnic_adapter *, u8); @@ -337,8 +336,11 @@ static int qlcnic_sriov_pf_cfg_vlan_filtering(struct qlcnic_adapter *adapter, return err; cmd.req.arg[1] = 0x4; - if (enable) + if (enable) { cmd.req.arg[1] |= BIT_16; + if (qlcnic_84xx_check(adapter)) + cmd.req.arg[1] |= QLC_SRIOV_ALLOW_VLAN0; + } err = qlcnic_issue_cmd(adapter, &cmd); if (err) @@ -1206,13 +1208,6 @@ 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 3d64113a35af..448d156c3d08 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c @@ -350,33 +350,15 @@ static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj, return size; } -static u32 qlcnic_get_pci_func_count(struct qlcnic_adapter *adapter) -{ - struct qlcnic_hardware_context *ahw = adapter->ahw; - u32 count = 0; - - if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED)) - return ahw->total_nic_func; - - if (ahw->total_pci_func <= QLC_DEFAULT_VNIC_COUNT) - count = QLC_DEFAULT_VNIC_COUNT; - else - count = ahw->max_vnic_func; - - return count; -} - int qlcnic_is_valid_nic_func(struct qlcnic_adapter *adapter, u8 pci_func) { - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); int i; - for (i = 0; i < pci_func_count; i++) { + for (i = 0; i < adapter->ahw->max_vnic_func; i++) { if (adapter->npars[i].pci_func == pci_func) return i; } - - return -1; + return -EINVAL; } static int validate_pm_config(struct qlcnic_adapter *adapter, @@ -464,23 +446,21 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_pm_func_cfg *pm_cfg; - int i, pm_cfg_size; u8 pci_func; + u32 count; + int i; - pm_cfg_size = pci_func_count * sizeof(*pm_cfg); - if (size != pm_cfg_size) - return QL_STATUS_INVALID_PARAM; - - memset(buf, 0, pm_cfg_size); + memset(buf, 0, size); pm_cfg = (struct qlcnic_pm_func_cfg *)buf; - - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_pm_func_cfg); + for (i = 0; i < adapter->ahw->total_nic_func; i++) { pci_func = adapter->npars[i].pci_func; - if (!adapter->npars[i].active) + if (pci_func >= count) { + dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", + __func__, adapter->ahw->total_nic_func, count); continue; - + } if (!adapter->npars[i].eswitch_status) continue; @@ -494,7 +474,6 @@ static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp, static int validate_esw_config(struct qlcnic_adapter *adapter, struct qlcnic_esw_func_cfg *esw_cfg, int count) { - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_hardware_context *ahw = adapter->ahw; int i, ret; u32 op_mode; @@ -507,7 +486,7 @@ static int validate_esw_config(struct qlcnic_adapter *adapter, for (i = 0; i < count; i++) { pci_func = esw_cfg[i].pci_func; - if (pci_func >= pci_func_count) + if (pci_func >= ahw->max_vnic_func) return QL_STATUS_INVALID_PARAM; if (adapter->ahw->op_mode == QLCNIC_MGMT_FUNC) @@ -642,23 +621,21 @@ static ssize_t qlcnic_sysfs_read_esw_config(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_esw_func_cfg *esw_cfg; - size_t esw_cfg_size; - u8 i, pci_func; - - esw_cfg_size = pci_func_count * sizeof(*esw_cfg); - if (size != esw_cfg_size) - return QL_STATUS_INVALID_PARAM; + u8 pci_func; + u32 count; + int i; - memset(buf, 0, esw_cfg_size); + memset(buf, 0, size); esw_cfg = (struct qlcnic_esw_func_cfg *)buf; - - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_esw_func_cfg); + for (i = 0; i < adapter->ahw->total_nic_func; i++) { pci_func = adapter->npars[i].pci_func; - if (!adapter->npars[i].active) + if (pci_func >= count) { + dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", + __func__, adapter->ahw->total_nic_func, count); continue; - + } if (!adapter->npars[i].eswitch_status) continue; @@ -741,23 +718,24 @@ static ssize_t qlcnic_sysfs_read_npar_config(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_npar_func_cfg *np_cfg; struct qlcnic_info nic_info; - size_t np_cfg_size; int i, ret; - - np_cfg_size = pci_func_count * sizeof(*np_cfg); - if (size != np_cfg_size) - return QL_STATUS_INVALID_PARAM; + u32 count; memset(&nic_info, 0, sizeof(struct qlcnic_info)); - memset(buf, 0, np_cfg_size); + memset(buf, 0, size); np_cfg = (struct qlcnic_npar_func_cfg *)buf; - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_npar_func_cfg); + for (i = 0; i < adapter->ahw->total_nic_func; i++) { if (qlcnic_is_valid_nic_func(adapter, i) < 0) continue; + if (adapter->npars[i].pci_func >= count) { + dev_dbg(dev, "%s: Total nic functions[%d], App sent function count[%d]\n", + __func__, adapter->ahw->total_nic_func, count); + continue; + } ret = qlcnic_get_nic_info(adapter, &nic_info, i); if (ret) return ret; @@ -783,7 +761,6 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); struct qlcnic_esw_statistics port_stats; int ret; @@ -793,7 +770,7 @@ static ssize_t qlcnic_sysfs_get_port_stats(struct file *file, if (size != sizeof(struct qlcnic_esw_statistics)) return QL_STATUS_INVALID_PARAM; - if (offset >= pci_func_count) + if (offset >= adapter->ahw->max_vnic_func) return QL_STATUS_INVALID_PARAM; memset(&port_stats, 0, size); @@ -884,13 +861,12 @@ static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file, struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - u32 pci_func_count = qlcnic_get_pci_func_count(adapter); int ret; if (qlcnic_83xx_check(adapter)) return QLC_STATUS_UNSUPPORTED_CMD; - if (offset >= pci_func_count) + if (offset >= adapter->ahw->max_vnic_func) return QL_STATUS_INVALID_PARAM; ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset, @@ -914,17 +890,12 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, { struct device *dev = container_of(kobj, struct device, kobj); struct qlcnic_adapter *adapter = dev_get_drvdata(dev); - 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_cfg_sz; int i, ret; + u32 count; - pci_cfg_sz = pci_func_count * sizeof(*pci_cfg); - if (size != pci_cfg_sz) - return QL_STATUS_INVALID_PARAM; - - pci_info = kcalloc(pci_func_count, sizeof(*pci_info), GFP_KERNEL); + pci_info = kcalloc(size, sizeof(*pci_info), GFP_KERNEL); if (!pci_info) return -ENOMEM; @@ -935,7 +906,8 @@ static ssize_t qlcnic_sysfs_read_pci_config(struct file *file, } pci_cfg = (struct qlcnic_pci_func_cfg *)buf; - for (i = 0; i < pci_func_count; i++) { + count = size / sizeof(struct qlcnic_pci_func_cfg); + for (i = 0; i < 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; diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c index ce2cfddbed50..adf87d26e68f 100644 --- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c +++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c @@ -3331,24 +3331,16 @@ static void ql_enable_msix(struct ql_adapter *qdev) for (i = 0; i < qdev->intr_count; i++) qdev->msi_x_entry[i].entry = i; - /* Loop to get our vectors. We start with - * what we want and settle for what we get. - */ - do { - err = pci_enable_msix(qdev->pdev, - qdev->msi_x_entry, qdev->intr_count); - if (err > 0) - qdev->intr_count = err; - } while (err > 0); - + err = pci_enable_msix_range(qdev->pdev, qdev->msi_x_entry, + 1, qdev->intr_count); if (err < 0) { kfree(qdev->msi_x_entry); qdev->msi_x_entry = NULL; netif_warn(qdev, ifup, qdev->ndev, "MSI-X Enable failed, trying MSI.\n"); - qdev->intr_count = 1; qlge_irq_type = MSI_IRQ; - } else if (err == 0) { + } else { + qdev->intr_count = err; set_bit(QL_MSIX_ENABLED, &qdev->flags); netif_info(qdev, ifup, qdev->ndev, "MSI-X Enabled, got %d vectors.\n", diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index 737c1a881f78..a3c1daa7ad5c 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -899,7 +899,7 @@ out_unlock: return NETDEV_TX_OK; out_dma_error: - kfree_skb(skb); + dev_kfree_skb_any(skb); cp->dev->stats.tx_dropped++; goto out_unlock; } diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index da5972eefdd2..8cb2f357026e 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -1717,9 +1717,9 @@ static netdev_tx_t rtl8139_start_xmit (struct sk_buff *skb, if (len < ETH_ZLEN) memset(tp->tx_buf[entry], 0, ETH_ZLEN); skb_copy_and_csum_dev(skb, tp->tx_buf[entry]); - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); } else { - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; } diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 91a67ae8f17b..cf947337e0d6 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -5834,7 +5834,7 @@ static void rtl8169_tx_clear_range(struct rtl8169_private *tp, u32 start, tp->TxDescArray + entry); if (skb) { tp->dev->stats.tx_dropped++; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); tx_skb->skb = NULL; } } @@ -6059,7 +6059,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, err_dma_1: rtl8169_unmap_tx_skb(d, tp->tx_skb + entry, txd); err_dma_0: - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); err_update_stats: dev->stats.tx_dropped++; return NETDEV_TX_OK; @@ -6142,7 +6142,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp) tp->tx_stats.packets++; tp->tx_stats.bytes += tx_skb->skb->len; u64_stats_update_end(&tp->tx_stats.syncp); - dev_kfree_skb(tx_skb->skb); + dev_kfree_skb_any(tx_skb->skb); tx_skb->skb = NULL; } dirty_tx++; @@ -7118,6 +7118,8 @@ rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } mutex_init(&tp->wk.mutex); + u64_stats_init(&tp->rx_stats.syncp); + u64_stats_init(&tp->tx_stats.syncp); /* Get MAC address */ for (i = 0; i < ETH_ALEN; i++) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 040cb94e8219..b1e6554f44bc 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -1,8 +1,8 @@ /* SuperH Ethernet device driver * * Copyright (C) 2006-2012 Nobuhiro Iwamatsu - * Copyright (C) 2008-2013 Renesas Solutions Corp. - * Copyright (C) 2013 Cogent Embedded, Inc. + * Copyright (C) 2008-2014 Renesas Solutions Corp. + * Copyright (C) 2013-2014 Cogent Embedded, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -27,6 +27,10 @@ #include <linux/platform_device.h> #include <linux/mdio-bitbang.h> #include <linux/netdevice.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/of_net.h> #include <linux/phy.h> #include <linux/cache.h> #include <linux/io.h> @@ -2098,8 +2102,8 @@ static int sh_eth_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb->len + 2); txdesc->addr = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE); - if (skb->len < ETHERSMALL) - txdesc->buffer_length = ETHERSMALL; + if (skb->len < ETH_ZLEN) + txdesc->buffer_length = ETH_ZLEN; else txdesc->buffer_length = skb->len; @@ -2710,6 +2714,54 @@ static const struct net_device_ops sh_eth_netdev_ops_tsu = { .ndo_change_mtu = eth_change_mtu, }; +#ifdef CONFIG_OF +static struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) +{ + struct device_node *np = dev->of_node; + struct sh_eth_plat_data *pdata; + struct device_node *phy; + const char *mac_addr; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; + + pdata->phy_interface = of_get_phy_mode(np); + + phy = of_parse_phandle(np, "phy-handle", 0); + if (of_property_read_u32(phy, "reg", &pdata->phy)) + return NULL; + pdata->phy_irq = irq_of_parse_and_map(phy, 0); + + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(pdata->mac_addr, mac_addr, ETH_ALEN); + + pdata->no_ether_link = + of_property_read_bool(np, "renesas,no-ether-link"); + pdata->ether_link_active_low = + of_property_read_bool(np, "renesas,ether-link-active-low"); + + return pdata; +} + +static const struct of_device_id sh_eth_match_table[] = { + { .compatible = "renesas,gether-r8a7740", .data = &r8a7740_data }, + { .compatible = "renesas,ether-r8a7778", .data = &r8a777x_data }, + { .compatible = "renesas,ether-r8a7779", .data = &r8a777x_data }, + { .compatible = "renesas,ether-r8a7790", .data = &r8a779x_data }, + { .compatible = "renesas,ether-r8a7791", .data = &r8a779x_data }, + { .compatible = "renesas,ether-r7s72100", .data = &r7s72100_data }, + { } +}; +MODULE_DEVICE_TABLE(of, sh_eth_match_table); +#else +static inline struct sh_eth_plat_data *sh_eth_parse_dt(struct device *dev) +{ + return NULL; +} +#endif + static int sh_eth_drv_probe(struct platform_device *pdev) { int ret, devno = 0; @@ -2763,6 +2815,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); + if (pdev->dev.of_node) + pd = sh_eth_parse_dt(&pdev->dev); if (!pd) { dev_err(&pdev->dev, "no platform data\n"); ret = -EINVAL; @@ -2778,7 +2832,15 @@ static int sh_eth_drv_probe(struct platform_device *pdev) mdp->ether_link_active_low = pd->ether_link_active_low; /* set cpu data */ - mdp->cd = (struct sh_eth_cpu_data *)id->driver_data; + if (id) { + mdp->cd = (struct sh_eth_cpu_data *)id->driver_data; + } else { + const struct of_device_id *match; + + match = of_match_device(of_match_ptr(sh_eth_match_table), + &pdev->dev); + mdp->cd = (struct sh_eth_cpu_data *)match->data; + } mdp->reg_offset = sh_eth_get_register_offset(mdp->cd->register_type); sh_eth_set_default_cpu_data(mdp->cd); @@ -2920,6 +2982,7 @@ static struct platform_driver sh_eth_driver = { .driver = { .name = CARDNAME, .pm = SH_ETH_PM_OPS, + .of_match_table = of_match_ptr(sh_eth_match_table), }, }; diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h index 6075915b88ec..d55e37cd5fec 100644 --- a/drivers/net/ethernet/renesas/sh_eth.h +++ b/drivers/net/ethernet/renesas/sh_eth.h @@ -27,8 +27,7 @@ #define RX_RING_MIN 64 #define TX_RING_MAX 1024 #define RX_RING_MAX 1024 -#define ETHERSMALL 60 -#define PKT_BUF_SZ 1538 +#define PKT_BUF_SZ 1538 #define SH_ETH_TSU_TIMEOUT_MS 500 #define SH_ETH_TSU_CAM_ENTRIES 32 diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 174a92f5fe51..eb75675f6e32 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -162,8 +162,8 @@ static int efx_ef10_get_mac_address(struct efx_nic *efx, u8 *mac_address) if (outlen < MC_CMD_GET_MAC_ADDRESSES_OUT_LEN) return -EIO; - memcpy(mac_address, - MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE), ETH_ALEN); + ether_addr_copy(mac_address, + MCDI_PTR(outbuf, GET_MAC_ADDRESSES_OUT_MAC_ADDR_BASE)); return 0; } @@ -172,8 +172,8 @@ static int efx_ef10_probe(struct efx_nic *efx) struct efx_ef10_nic_data *nic_data; int i, rc; - /* We can have one VI for each 8K region. However we need - * multiple TX queues per channel. + /* We can have one VI for each 8K region. However, until we + * use TX option descriptors we need two TX queues per channel. */ efx->max_channels = min_t(unsigned int, @@ -3145,12 +3145,10 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) table->dev_uc_count = -1; } else { table->dev_uc_count = 1 + netdev_uc_count(net_dev); - memcpy(table->dev_uc_list[0].addr, net_dev->dev_addr, - ETH_ALEN); + ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); i = 1; netdev_for_each_uc_addr(uc, net_dev) { - memcpy(table->dev_uc_list[i].addr, - uc->addr, ETH_ALEN); + ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); i++; } } @@ -3162,8 +3160,7 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) eth_broadcast_addr(table->dev_mc_list[0].addr); i = 1; netdev_for_each_mc_addr(mc, net_dev) { - memcpy(table->dev_mc_list[i].addr, - mc->addr, ETH_ALEN); + ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); i++; } } diff --git a/drivers/net/ethernet/sfc/ef10_regs.h b/drivers/net/ethernet/sfc/ef10_regs.h index 207ac9a1e3de..62a55dde61d5 100644 --- a/drivers/net/ethernet/sfc/ef10_regs.h +++ b/drivers/net/ethernet/sfc/ef10_regs.h @@ -227,36 +227,6 @@ #define ESF_DZ_RX_KER_BUF_ADDR_LBN 0 #define ESF_DZ_RX_KER_BUF_ADDR_WIDTH 48 -/* RX_USER_DESC */ -#define ESF_DZ_RX_USR_RESERVED_LBN 62 -#define ESF_DZ_RX_USR_RESERVED_WIDTH 2 -#define ESF_DZ_RX_USR_BYTE_CNT_LBN 48 -#define ESF_DZ_RX_USR_BYTE_CNT_WIDTH 14 -#define ESF_DZ_RX_USR_BUF_PAGE_SIZE_LBN 44 -#define ESF_DZ_RX_USR_BUF_PAGE_SIZE_WIDTH 4 -#define ESE_DZ_USR_BUF_PAGE_SZ_4MB 10 -#define ESE_DZ_USR_BUF_PAGE_SZ_1MB 8 -#define ESE_DZ_USR_BUF_PAGE_SZ_64KB 4 -#define ESE_DZ_USR_BUF_PAGE_SZ_4KB 0 -#define ESF_DZ_RX_USR_BUF_ID_OFFSET_LBN 0 -#define ESF_DZ_RX_USR_BUF_ID_OFFSET_WIDTH 44 -#define ESF_DZ_RX_USR_4KBPS_BUF_ID_LBN 12 -#define ESF_DZ_RX_USR_4KBPS_BUF_ID_WIDTH 32 -#define ESF_DZ_RX_USR_64KBPS_BUF_ID_LBN 16 -#define ESF_DZ_RX_USR_64KBPS_BUF_ID_WIDTH 28 -#define ESF_DZ_RX_USR_1MBPS_BUF_ID_LBN 20 -#define ESF_DZ_RX_USR_1MBPS_BUF_ID_WIDTH 24 -#define ESF_DZ_RX_USR_4MBPS_BUF_ID_LBN 22 -#define ESF_DZ_RX_USR_4MBPS_BUF_ID_WIDTH 22 -#define ESF_DZ_RX_USR_4MBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_RX_USR_4MBPS_BYTE_OFFSET_WIDTH 22 -#define ESF_DZ_RX_USR_1MBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_RX_USR_1MBPS_BYTE_OFFSET_WIDTH 20 -#define ESF_DZ_RX_USR_64KBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_RX_USR_64KBPS_BYTE_OFFSET_WIDTH 16 -#define ESF_DZ_RX_USR_4KBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_RX_USR_4KBPS_BYTE_OFFSET_WIDTH 12 - /* TX_CSUM_TSTAMP_DESC */ #define ESF_DZ_TX_DESC_IS_OPT_LBN 63 #define ESF_DZ_TX_DESC_IS_OPT_WIDTH 1 @@ -338,37 +308,6 @@ #define ESF_DZ_TX_TSO_TCP_SEQNO_LBN 0 #define ESF_DZ_TX_TSO_TCP_SEQNO_WIDTH 32 -/* TX_USER_DESC */ -#define ESF_DZ_TX_USR_TYPE_LBN 63 -#define ESF_DZ_TX_USR_TYPE_WIDTH 1 -#define ESF_DZ_TX_USR_CONT_LBN 62 -#define ESF_DZ_TX_USR_CONT_WIDTH 1 -#define ESF_DZ_TX_USR_BYTE_CNT_LBN 48 -#define ESF_DZ_TX_USR_BYTE_CNT_WIDTH 14 -#define ESF_DZ_TX_USR_BUF_PAGE_SIZE_LBN 44 -#define ESF_DZ_TX_USR_BUF_PAGE_SIZE_WIDTH 4 -#define ESE_DZ_USR_BUF_PAGE_SZ_4MB 10 -#define ESE_DZ_USR_BUF_PAGE_SZ_1MB 8 -#define ESE_DZ_USR_BUF_PAGE_SZ_64KB 4 -#define ESE_DZ_USR_BUF_PAGE_SZ_4KB 0 -#define ESF_DZ_TX_USR_BUF_ID_OFFSET_LBN 0 -#define ESF_DZ_TX_USR_BUF_ID_OFFSET_WIDTH 44 -#define ESF_DZ_TX_USR_4KBPS_BUF_ID_LBN 12 -#define ESF_DZ_TX_USR_4KBPS_BUF_ID_WIDTH 32 -#define ESF_DZ_TX_USR_64KBPS_BUF_ID_LBN 16 -#define ESF_DZ_TX_USR_64KBPS_BUF_ID_WIDTH 28 -#define ESF_DZ_TX_USR_1MBPS_BUF_ID_LBN 20 -#define ESF_DZ_TX_USR_1MBPS_BUF_ID_WIDTH 24 -#define ESF_DZ_TX_USR_4MBPS_BUF_ID_LBN 22 -#define ESF_DZ_TX_USR_4MBPS_BUF_ID_WIDTH 22 -#define ESF_DZ_TX_USR_4MBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_TX_USR_4MBPS_BYTE_OFFSET_WIDTH 22 -#define ESF_DZ_TX_USR_1MBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_TX_USR_1MBPS_BYTE_OFFSET_WIDTH 20 -#define ESF_DZ_TX_USR_64KBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_TX_USR_64KBPS_BYTE_OFFSET_WIDTH 16 -#define ESF_DZ_TX_USR_4KBPS_BYTE_OFFSET_LBN 0 -#define ESF_DZ_TX_USR_4KBPS_BYTE_OFFSET_WIDTH 12 /*************************************************************************/ /* TX_DESC_UPD_REG: Transmit descriptor update register. diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 83d464347021..52589f6a8beb 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -503,8 +503,6 @@ static int efx_probe_channel(struct efx_channel *channel) goto fail; } - channel->n_rx_frm_trunc = 0; - return 0; fail: @@ -1014,7 +1012,7 @@ static int efx_probe_port(struct efx_nic *efx) return rc; /* Initialise MAC address to permanent address */ - memcpy(efx->net_dev->dev_addr, efx->net_dev->perm_addr, ETH_ALEN); + ether_addr_copy(efx->net_dev->dev_addr, efx->net_dev->perm_addr); return 0; } @@ -1346,20 +1344,23 @@ static int efx_probe_interrupts(struct efx_nic *efx) for (i = 0; i < n_channels; i++) xentries[i].entry = i; - rc = pci_enable_msix(efx->pci_dev, xentries, n_channels); - if (rc > 0) { + rc = pci_enable_msix_range(efx->pci_dev, + xentries, 1, n_channels); + if (rc < 0) { + /* Fall back to single channel MSI */ + efx->interrupt_mode = EFX_INT_MODE_MSI; + netif_err(efx, drv, efx->net_dev, + "could not enable MSI-X\n"); + } else if (rc < n_channels) { netif_err(efx, drv, efx->net_dev, "WARNING: Insufficient MSI-X vectors" " available (%d < %u).\n", rc, n_channels); netif_err(efx, drv, efx->net_dev, "WARNING: Performance may be reduced.\n"); - EFX_BUG_ON_PARANOID(rc >= n_channels); n_channels = rc; - rc = pci_enable_msix(efx->pci_dev, xentries, - n_channels); } - if (rc == 0) { + if (rc > 0) { efx->n_channels = n_channels; if (n_channels > extra_channels) n_channels -= extra_channels; @@ -1375,11 +1376,6 @@ static int efx_probe_interrupts(struct efx_nic *efx) for (i = 0; i < efx->n_channels; i++) efx_get_channel(efx, i)->irq = xentries[i].vector; - } else { - /* Fall back to single channel MSI */ - efx->interrupt_mode = EFX_INT_MODE_MSI; - netif_err(efx, drv, efx->net_dev, - "could not enable MSI-X\n"); } } @@ -2115,7 +2111,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) { struct efx_nic *efx = netdev_priv(net_dev); struct sockaddr *addr = data; - char *new_addr = addr->sa_data; + u8 *new_addr = addr->sa_data; if (!is_valid_ether_addr(new_addr)) { netif_err(efx, drv, efx->net_dev, @@ -2124,7 +2120,7 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) return -EADDRNOTAVAIL; } - memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len); + ether_addr_copy(net_dev->dev_addr, new_addr); efx_sriov_mac_address_changed(efx); /* Reconfigure the MAC */ @@ -3273,6 +3269,6 @@ module_exit(efx_exit_module); MODULE_AUTHOR("Solarflare Communications and " "Michael Brown <mbrown@fensystems.co.uk>"); -MODULE_DESCRIPTION("Solarflare Communications network driver"); +MODULE_DESCRIPTION("Solarflare network driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, efx_pci_table); diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index dbd7b78fe01c..99032581336f 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -14,7 +14,7 @@ #include "net_driver.h" #include "filter.h" -/* Solarstorm controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ +/* All controllers use BAR 0 for I/O space and BAR 2(&3) for memory */ #define EFX_MEM_BAR 2 /* TX */ diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index 229428915aa8..0de8b07c24c2 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -251,6 +251,9 @@ static void efx_fill_test(unsigned int test_index, u8 *strings, u64 *data, * @test_index: Starting index of the test * @strings: Ethtool strings, or %NULL * @data: Ethtool test results, or %NULL + * + * Fill in a block of loopback self-test entries. Return new test + * index. */ static int efx_fill_loopback_test(struct efx_nic *efx, struct efx_loopback_self_tests *lb_tests, @@ -290,6 +293,12 @@ static int efx_fill_loopback_test(struct efx_nic *efx, * @tests: Efx self-test results structure, or %NULL * @strings: Ethtool strings, or %NULL * @data: Ethtool test results, or %NULL + * + * Get self-test number of strings, strings, and/or test results. + * Return number of strings (== number of test results). + * + * The reason for merging these three functions is to make sure that + * they can never be inconsistent. */ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, struct efx_self_tests *tests, @@ -444,7 +453,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_self_tests *efx_tests; - int already_up; + bool already_up; int rc = -ENOMEM; efx_tests = kzalloc(sizeof(*efx_tests), GFP_KERNEL); @@ -452,8 +461,8 @@ static void efx_ethtool_self_test(struct net_device *net_dev, goto fail; if (efx->state != STATE_READY) { - rc = -EIO; - goto fail1; + rc = -EBUSY; + goto out; } netif_info(efx, drv, efx->net_dev, "starting %sline testing\n", @@ -466,7 +475,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev, if (rc) { netif_err(efx, drv, efx->net_dev, "failed opening device.\n"); - goto fail1; + goto out; } } @@ -479,8 +488,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev, rc == 0 ? "passed" : "failed", (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); -fail1: - /* Fill ethtool results structures */ +out: efx_ethtool_fill_self_tests(efx, efx_tests, NULL, data); kfree(efx_tests); fail: @@ -691,7 +699,6 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); } - static void efx_ethtool_get_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) { @@ -720,7 +727,7 @@ static int efx_ethtool_reset(struct net_device *net_dev, u32 *flags) } /* MAC address mask including only I/G bit */ -static const u8 mac_addr_ig_mask[ETH_ALEN] = { 0x01, 0, 0, 0, 0, 0 }; +static const u8 mac_addr_ig_mask[ETH_ALEN] __aligned(2) = {0x01, 0, 0, 0, 0, 0}; #define IP4_ADDR_FULL_MASK ((__force __be32)~0) #define PORT_FULL_MASK ((__force __be16)~0) @@ -780,16 +787,16 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx, rule->flow_type = ETHER_FLOW; if (spec.match_flags & (EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_MAC_IG)) { - memcpy(mac_entry->h_dest, spec.loc_mac, ETH_ALEN); + ether_addr_copy(mac_entry->h_dest, spec.loc_mac); if (spec.match_flags & EFX_FILTER_MATCH_LOC_MAC) - memset(mac_mask->h_dest, ~0, ETH_ALEN); + eth_broadcast_addr(mac_mask->h_dest); else - memcpy(mac_mask->h_dest, mac_addr_ig_mask, - ETH_ALEN); + ether_addr_copy(mac_mask->h_dest, + mac_addr_ig_mask); } if (spec.match_flags & EFX_FILTER_MATCH_REM_MAC) { - memcpy(mac_entry->h_source, spec.rem_mac, ETH_ALEN); - memset(mac_mask->h_source, ~0, ETH_ALEN); + ether_addr_copy(mac_entry->h_source, spec.rem_mac); + eth_broadcast_addr(mac_mask->h_source); } if (spec.match_flags & EFX_FILTER_MATCH_ETHER_TYPE) { mac_entry->h_proto = spec.ether_type; @@ -961,13 +968,13 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx, spec.match_flags |= EFX_FILTER_MATCH_LOC_MAC; else return -EINVAL; - memcpy(spec.loc_mac, mac_entry->h_dest, ETH_ALEN); + ether_addr_copy(spec.loc_mac, mac_entry->h_dest); } if (!is_zero_ether_addr(mac_mask->h_source)) { if (!is_broadcast_ether_addr(mac_mask->h_source)) return -EINVAL; spec.match_flags |= EFX_FILTER_MATCH_REM_MAC; - memcpy(spec.rem_mac, mac_entry->h_source, ETH_ALEN); + ether_addr_copy(spec.rem_mac, mac_entry->h_source); } if (mac_mask->h_proto) { if (mac_mask->h_proto != ETHER_TYPE_FULL_MASK) diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 18d6f761f4d0..8ec20b713cc6 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -422,7 +422,6 @@ static inline void falcon_irq_ack_a1(struct efx_nic *efx) efx_readd(efx, ®, FR_AA_WORK_AROUND_BROKEN_PCI_READS); } - static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) { struct efx_nic *efx = dev_id; @@ -467,6 +466,7 @@ static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id) efx_schedule_channel_irq(efx_get_channel(efx, 1)); return IRQ_HANDLED; } + /************************************************************************** * * RSS @@ -1358,6 +1358,7 @@ static void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) case 100: link_speed = 1; break; default: link_speed = 0; break; } + /* MAC_LINK_STATUS controls MAC backpressure but doesn't work * as advertised. Disable to ensure packets are not * indefinitely held and TX queue can be flushed at any point @@ -2182,7 +2183,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) } /* Read the MAC addresses */ - memcpy(efx->net_dev->perm_addr, nvconfig->mac_address[0], ETH_ALEN); + ether_addr_copy(efx->net_dev->perm_addr, nvconfig->mac_address[0]); netif_dbg(efx, probe, efx->net_dev, "PHY is %d phy_id %d\n", efx->phy_type, efx->mdio.prtad); @@ -2868,4 +2869,3 @@ const struct efx_nic_type falcon_b0_nic_type = { .mcdi_max_ver = -1, .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS, }; - diff --git a/drivers/net/ethernet/sfc/farch.c b/drivers/net/ethernet/sfc/farch.c index f72489a105ca..aa1b169f45ec 100644 --- a/drivers/net/ethernet/sfc/farch.c +++ b/drivers/net/ethernet/sfc/farch.c @@ -311,7 +311,6 @@ static inline void efx_farch_push_tx_desc(struct efx_tx_queue *tx_queue, */ void efx_farch_tx_write(struct efx_tx_queue *tx_queue) { - struct efx_tx_buffer *buffer; efx_qword_t *txd; unsigned write_ptr; @@ -1609,7 +1608,6 @@ irqreturn_t efx_farch_msi_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } - /* Setup RSS indirection table. * This maps from the hash value of the packet to RXQ */ diff --git a/drivers/net/ethernet/sfc/filter.h b/drivers/net/ethernet/sfc/filter.h index 3ef298d3c47e..d0ed7f71ea7e 100644 --- a/drivers/net/ethernet/sfc/filter.h +++ b/drivers/net/ethernet/sfc/filter.h @@ -243,7 +243,7 @@ static inline int efx_filter_set_eth_local(struct efx_filter_spec *spec, } if (addr != NULL) { spec->match_flags |= EFX_FILTER_MATCH_LOC_MAC; - memcpy(spec->loc_mac, addr, ETH_ALEN); + ether_addr_copy(spec->loc_mac, addr); } return 0; } diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index eb59abb57e85..7bd4b14bf3b3 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1187,6 +1187,9 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, int rc; BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_IN_LEN != 0); + /* we need __aligned(2) for ether_addr_copy */ + BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0_OFST & 1); + BUILD_BUG_ON(MC_CMD_GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1_OFST & 1); rc = efx_mcdi_rpc(efx, MC_CMD_GET_BOARD_CFG, NULL, 0, outbuf, sizeof(outbuf), &outlen); @@ -1199,11 +1202,10 @@ int efx_mcdi_get_board_cfg(struct efx_nic *efx, u8 *mac_address, } if (mac_address) - memcpy(mac_address, - port_num ? - MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) : - MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0), - ETH_ALEN); + ether_addr_copy(mac_address, + port_num ? + MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT1) : + MCDI_PTR(outbuf, GET_BOARD_CFG_OUT_MAC_ADDR_BASE_PORT0)); if (fw_subtype_list) { for (i = 0; i < MCDI_VAR_ARRAY_LEN(outlen, @@ -1532,7 +1534,7 @@ static int efx_mcdi_wol_filter_set(struct efx_nic *efx, u32 type, MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_WOL_TYPE, type); MCDI_SET_DWORD(inbuf, WOL_FILTER_SET_IN_FILTER_MODE, MC_CMD_FILTER_MODE_SIMPLE); - memcpy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac, ETH_ALEN); + ether_addr_copy(MCDI_PTR(inbuf, WOL_FILTER_SET_IN_MAGIC_MAC), mac); rc = efx_mcdi_rpc(efx, MC_CMD_WOL_FILTER_SET, inbuf, sizeof(inbuf), outbuf, sizeof(outbuf), &outlen); diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c index 91d23252f8fa..e5fc4e1574b5 100644 --- a/drivers/net/ethernet/sfc/mcdi_port.c +++ b/drivers/net/ethernet/sfc/mcdi_port.c @@ -854,8 +854,8 @@ int efx_mcdi_set_mac(struct efx_nic *efx) BUILD_BUG_ON(MC_CMD_SET_MAC_OUT_LEN != 0); - memcpy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR), - efx->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(MCDI_PTR(cmdbytes, SET_MAC_IN_ADDR), + efx->net_dev->dev_addr); MCDI_SET_DWORD(cmdbytes, SET_MAC_IN_MTU, EFX_MAX_FRAME_LEN(efx->net_dev->mtu)); diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index af2b8c59a903..8a400a0595eb 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -1323,7 +1323,6 @@ static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue, return &rx_queue->buffer[index]; } - /** * EFX_MAX_FRAME_LEN - calculate maximum frame length * diff --git a/drivers/net/ethernet/sfc/nic.c b/drivers/net/ethernet/sfc/nic.c index 79226b19e3c4..32d969e857f7 100644 --- a/drivers/net/ethernet/sfc/nic.c +++ b/drivers/net/ethernet/sfc/nic.c @@ -530,4 +530,3 @@ void efx_nic_fix_nodesc_drop_stat(struct efx_nic *efx, u64 *rx_nodesc_drops) efx->rx_nodesc_drops_prev_state = !!(efx->net_dev->flags & IFF_UP); *rx_nodesc_drops -= efx->rx_nodesc_drops_while_down; } - diff --git a/drivers/net/ethernet/sfc/ptp.c b/drivers/net/ethernet/sfc/ptp.c index eb75fbd11a01..722344fcd155 100644 --- a/drivers/net/ethernet/sfc/ptp.c +++ b/drivers/net/ethernet/sfc/ptp.c @@ -223,7 +223,6 @@ struct efx_ptp_timeset { * @evt_list: List of MC receive events awaiting packets * @evt_free_list: List of free events * @evt_lock: Lock for manipulating evt_list and evt_free_list - * @evt_overflow: Boolean indicating that event list has overflowed * @rx_evts: Instantiated events (on evt_list and evt_free_list) * @workwq: Work queue for processing pending PTP operations * @work: Work task @@ -275,7 +274,6 @@ struct efx_ptp_data { struct list_head evt_list; struct list_head evt_free_list; spinlock_t evt_lock; - bool evt_overflow; struct efx_ptp_event_rx rx_evts[MAX_RECEIVE_EVENTS]; struct workqueue_struct *workwq; struct work_struct work; @@ -768,37 +766,36 @@ efx_ptp_process_times(struct efx_nic *efx, MCDI_DECLARE_STRUCT_PTR(synch_buf), return -EAGAIN; } - /* Convert the NIC time into kernel time. No correction is required- - * this time is the output of a firmware process. - */ - mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major, - ptp->timeset[last_good].minor, 0); - - /* Calculate delay from actual PPS to last_time */ - delta = ktime_to_timespec(mc_time); - delta.tv_nsec += - last_time->ts_real.tv_nsec - - (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK); - - /* It is possible that the seconds rolled over between taking + /* Calculate delay from last good sync (host time) to last_time. + * It is possible that the seconds rolled over between taking * the start reading and the last value written by the host. The * timescales are such that a gap of more than one second is never - * expected. + * expected. delta is *not* normalised. */ start_sec = ptp->timeset[last_good].host_start >> MC_NANOSECOND_BITS; last_sec = last_time->ts_real.tv_sec & MC_SECOND_MASK; - if (start_sec != last_sec) { - if (((start_sec + 1) & MC_SECOND_MASK) != last_sec) { - netif_warn(efx, hw, efx->net_dev, - "PTP bad synchronisation seconds\n"); - return -EAGAIN; - } else { - delta.tv_sec = 1; - } - } else { - delta.tv_sec = 0; + if (start_sec != last_sec && + ((start_sec + 1) & MC_SECOND_MASK) != last_sec) { + netif_warn(efx, hw, efx->net_dev, + "PTP bad synchronisation seconds\n"); + return -EAGAIN; } + delta.tv_sec = (last_sec - start_sec) & 1; + delta.tv_nsec = + last_time->ts_real.tv_nsec - + (ptp->timeset[last_good].host_start & MC_NANOSECOND_MASK); + + /* Convert the NIC time at last good sync into kernel time. + * No correction is required - this time is the output of a + * firmware process. + */ + mc_time = ptp->nic_to_kernel_time(ptp->timeset[last_good].major, + ptp->timeset[last_good].minor, 0); + + /* Calculate delay from NIC top of second to last_time */ + delta.tv_nsec += ktime_to_timespec(mc_time).tv_nsec; + /* Set PPS timestamp to match NIC top of second */ ptp->host_time_pps = *last_time; pps_sub_ts(&ptp->host_time_pps, delta); @@ -941,11 +938,6 @@ static void efx_ptp_drop_time_expired_events(struct efx_nic *efx) } } } - /* If the event overflow flag is set and the event list is now empty - * clear the flag to re-enable the overflow warning message. - */ - if (ptp->evt_overflow && list_empty(&ptp->evt_list)) - ptp->evt_overflow = false; spin_unlock_bh(&ptp->evt_lock); } @@ -989,11 +981,6 @@ static enum ptp_packet_state efx_ptp_match_rx(struct efx_nic *efx, break; } } - /* If the event overflow flag is set and the event list is now empty - * clear the flag to re-enable the overflow warning message. - */ - if (ptp->evt_overflow && list_empty(&ptp->evt_list)) - ptp->evt_overflow = false; spin_unlock_bh(&ptp->evt_lock); return rc; @@ -1147,7 +1134,6 @@ static int efx_ptp_stop(struct efx_nic *efx) list_for_each_safe(cursor, next, &efx->ptp_data->evt_list) { list_move(cursor, &efx->ptp_data->evt_free_list); } - ptp->evt_overflow = false; spin_unlock_bh(&efx->ptp_data->evt_lock); return rc; @@ -1253,7 +1239,6 @@ int efx_ptp_probe(struct efx_nic *efx, struct efx_channel *channel) spin_lock_init(&ptp->evt_lock); for (pos = 0; pos < MAX_RECEIVE_EVENTS; pos++) list_add(&ptp->rx_evts[pos].link, &ptp->evt_free_list); - ptp->evt_overflow = false; /* Get the NIC PTP attributes and set up time conversions */ rc = efx_ptp_get_attributes(efx); @@ -1380,6 +1365,7 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb) struct efx_ptp_match *match = (struct efx_ptp_match *)skb->cb; u8 *match_data_012, *match_data_345; unsigned int version; + u8 *data; match->expiry = jiffies + msecs_to_jiffies(PKT_EVENT_LIFETIME_MS); @@ -1388,7 +1374,8 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb) if (!pskb_may_pull(skb, PTP_V1_MIN_LENGTH)) { return false; } - version = ntohs(*(__be16 *)&skb->data[PTP_V1_VERSION_OFFSET]); + data = skb->data; + version = ntohs(*(__be16 *)&data[PTP_V1_VERSION_OFFSET]); if (version != PTP_VERSION_V1) { return false; } @@ -1396,13 +1383,14 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb) /* PTP V1 uses all six bytes of the UUID to match the packet * to the timestamp */ - match_data_012 = skb->data + PTP_V1_UUID_OFFSET; - match_data_345 = skb->data + PTP_V1_UUID_OFFSET + 3; + match_data_012 = data + PTP_V1_UUID_OFFSET; + match_data_345 = data + PTP_V1_UUID_OFFSET + 3; } else { if (!pskb_may_pull(skb, PTP_V2_MIN_LENGTH)) { return false; } - version = skb->data[PTP_V2_VERSION_OFFSET]; + data = skb->data; + version = data[PTP_V2_VERSION_OFFSET]; if ((version & PTP_VERSION_V2_MASK) != PTP_VERSION_V2) { return false; } @@ -1414,17 +1402,17 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb) * enhanced mode fixes this issue and uses bytes 0-2 * and byte 5-7 of the UUID. */ - match_data_345 = skb->data + PTP_V2_UUID_OFFSET + 5; + match_data_345 = data + PTP_V2_UUID_OFFSET + 5; if (ptp->mode == MC_CMD_PTP_MODE_V2) { - match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 2; + match_data_012 = data + PTP_V2_UUID_OFFSET + 2; } else { - match_data_012 = skb->data + PTP_V2_UUID_OFFSET + 0; + match_data_012 = data + PTP_V2_UUID_OFFSET + 0; BUG_ON(ptp->mode != MC_CMD_PTP_MODE_V2_ENHANCED); } } /* Does this packet require timestamping? */ - if (ntohs(*(__be16 *)&skb->data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) { + if (ntohs(*(__be16 *)&data[PTP_DPORT_OFFSET]) == PTP_EVENT_PORT) { match->state = PTP_PACKET_STATE_UNMATCHED; /* We expect the sequence number to be in the same position in @@ -1440,8 +1428,8 @@ static bool efx_ptp_rx(struct efx_channel *channel, struct sk_buff *skb) (match_data_345[0] << 24)); match->words[1] = (match_data_345[1] | (match_data_345[2] << 8) | - (skb->data[PTP_V1_SEQUENCE_OFFSET + - PTP_V1_SEQUENCE_LENGTH - 1] << + (data[PTP_V1_SEQUENCE_OFFSET + + PTP_V1_SEQUENCE_LENGTH - 1] << 16)); } else { match->state = PTP_PACKET_STATE_MATCH_UNWANTED; @@ -1635,13 +1623,9 @@ static void ptp_event_rx(struct efx_nic *efx, struct efx_ptp_data *ptp) list_add_tail(&evt->link, &ptp->evt_list); queue_work(ptp->workwq, &ptp->work); - } else if (!ptp->evt_overflow) { - /* Log a warning message and set the event overflow flag. - * The message won't be logged again until the event queue - * becomes empty. - */ + } else if (net_ratelimit()) { + /* Log a rate-limited warning message. */ netif_err(efx, rx_err, efx->net_dev, "PTP event queue overflow\n"); - ptp->evt_overflow = true; } spin_unlock_bh(&ptp->evt_lock); } @@ -1668,6 +1652,13 @@ void efx_ptp_event(struct efx_nic *efx, efx_qword_t *ev) struct efx_ptp_data *ptp = efx->ptp_data; int code = EFX_QWORD_FIELD(*ev, MCDI_EVENT_CODE); + if (!ptp) { + if (net_ratelimit()) + netif_warn(efx, drv, efx->net_dev, + "Received PTP event but PTP not set up\n"); + return; + } + if (!ptp->enabled) return; diff --git a/drivers/net/ethernet/sfc/selftest.c b/drivers/net/ethernet/sfc/selftest.c index 26641817a9c7..0fc5baef45b1 100644 --- a/drivers/net/ethernet/sfc/selftest.c +++ b/drivers/net/ethernet/sfc/selftest.c @@ -50,7 +50,7 @@ struct efx_loopback_payload { } __packed; /* Loopback test source MAC address */ -static const unsigned char payload_source[ETH_ALEN] = { +static const u8 payload_source[ETH_ALEN] __aligned(2) = { 0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b, }; @@ -366,8 +366,8 @@ static void efx_iterate_state(struct efx_nic *efx) struct efx_loopback_payload *payload = &state->payload; /* Initialise the layerII header */ - memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN); - memcpy(&payload->header.h_source, &payload_source, ETH_ALEN); + ether_addr_copy((u8 *)&payload->header.h_dest, net_dev->dev_addr); + ether_addr_copy((u8 *)&payload->header.h_source, payload_source); payload->header.h_proto = htons(ETH_P_IP); /* saddr set later and used as incrementing count */ diff --git a/drivers/net/ethernet/sfc/siena_sriov.c b/drivers/net/ethernet/sfc/siena_sriov.c index 0c38f926871e..9a9205e77896 100644 --- a/drivers/net/ethernet/sfc/siena_sriov.c +++ b/drivers/net/ethernet/sfc/siena_sriov.c @@ -1095,7 +1095,7 @@ static void efx_sriov_peer_work(struct work_struct *data) /* Fill the remaining addresses */ list_for_each_entry(local_addr, &efx->local_addr_list, link) { - memcpy(peer->mac_addr, local_addr->addr, ETH_ALEN); + ether_addr_copy(peer->mac_addr, local_addr->addr); peer->tci = 0; ++peer; ++peer_count; @@ -1303,8 +1303,7 @@ int efx_sriov_init(struct efx_nic *efx) goto fail_vfs; rtnl_lock(); - memcpy(vfdi_status->peers[0].mac_addr, - net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(vfdi_status->peers[0].mac_addr, net_dev->dev_addr); efx->vf_init_count = efx->vf_count; rtnl_unlock(); @@ -1452,8 +1451,8 @@ void efx_sriov_mac_address_changed(struct efx_nic *efx) if (!efx->vf_init_count) return; - memcpy(vfdi_status->peers[0].mac_addr, - efx->net_dev->dev_addr, ETH_ALEN); + ether_addr_copy(vfdi_status->peers[0].mac_addr, + efx->net_dev->dev_addr); queue_work(vfdi_workqueue, &efx->peer_work); } @@ -1570,7 +1569,7 @@ int efx_sriov_set_vf_mac(struct net_device *net_dev, int vf_i, u8 *mac) vf = efx->vf + vf_i; mutex_lock(&vf->status_lock); - memcpy(vf->addr.mac_addr, mac, ETH_ALEN); + ether_addr_copy(vf->addr.mac_addr, mac); __efx_sriov_update_vf_addr(vf); mutex_unlock(&vf->status_lock); @@ -1633,7 +1632,7 @@ int efx_sriov_get_vf_config(struct net_device *net_dev, int vf_i, vf = efx->vf + vf_i; ivi->vf = vf_i; - memcpy(ivi->mac, vf->addr.mac_addr, ETH_ALEN); + ether_addr_copy(ivi->mac, vf->addr.mac_addr); ivi->tx_rate = 0; tci = ntohs(vf->addr.tci); ivi->vlan = tci & VLAN_VID_MASK; diff --git a/drivers/net/ethernet/sfc/tx.c b/drivers/net/ethernet/sfc/tx.c index c49d1fb16965..fa9475300411 100644 --- a/drivers/net/ethernet/sfc/tx.c +++ b/drivers/net/ethernet/sfc/tx.c @@ -429,7 +429,9 @@ netdev_tx_t efx_enqueue_skb(struct efx_tx_queue *tx_queue, struct sk_buff *skb) } /* Transfer ownership of the skb to the final buffer */ +#ifdef EFX_USE_PIO finish_packet: +#endif buffer->skb = skb; buffer->flags = EFX_TX_BUF_SKB | dma_flags; @@ -785,15 +787,6 @@ void efx_remove_tx_queue(struct efx_tx_queue *tx_queue) * Requires TX checksum offload support. */ -/* Number of bytes inserted at the start of a TSO header buffer, - * similar to NET_IP_ALIGN. - */ -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS -#define TSOH_OFFSET 0 -#else -#define TSOH_OFFSET NET_IP_ALIGN -#endif - #define PTR_DIFF(p1, p2) ((u8 *)(p1) - (u8 *)(p2)) /** @@ -880,13 +873,13 @@ static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue, EFX_BUG_ON_PARANOID(buffer->flags); EFX_BUG_ON_PARANOID(buffer->unmap_len); - if (likely(len <= TSOH_STD_SIZE - TSOH_OFFSET)) { + if (likely(len <= TSOH_STD_SIZE - NET_IP_ALIGN)) { unsigned index = (tx_queue->insert_count & tx_queue->ptr_mask) / 2; struct efx_buffer *page_buf = &tx_queue->tsoh_page[index / TSOH_PER_PAGE]; unsigned offset = - TSOH_STD_SIZE * (index % TSOH_PER_PAGE) + TSOH_OFFSET; + TSOH_STD_SIZE * (index % TSOH_PER_PAGE) + NET_IP_ALIGN; if (unlikely(!page_buf->addr) && efx_nic_alloc_buffer(tx_queue->efx, page_buf, PAGE_SIZE, @@ -899,10 +892,10 @@ static u8 *efx_tsoh_get_buffer(struct efx_tx_queue *tx_queue, } else { tx_queue->tso_long_headers++; - buffer->heap_buf = kmalloc(TSOH_OFFSET + len, GFP_ATOMIC); + buffer->heap_buf = kmalloc(NET_IP_ALIGN + len, GFP_ATOMIC); if (unlikely(!buffer->heap_buf)) return NULL; - result = (u8 *)buffer->heap_buf + TSOH_OFFSET; + result = (u8 *)buffer->heap_buf + NET_IP_ALIGN; buffer->flags = EFX_TX_BUF_CONT | EFX_TX_BUF_HEAP; } @@ -1009,7 +1002,7 @@ static void efx_enqueue_unwind(struct efx_tx_queue *tx_queue) static int tso_start(struct tso_state *st, struct efx_nic *efx, const struct sk_buff *skb) { - bool use_options = efx_nic_rev(efx) >= EFX_REV_HUNT_A0; + bool use_opt_desc = efx_nic_rev(efx) >= EFX_REV_HUNT_A0; struct device *dma_dev = &efx->pci_dev->dev; unsigned int header_len, in_len; dma_addr_t dma_addr; @@ -1035,7 +1028,7 @@ static int tso_start(struct tso_state *st, struct efx_nic *efx, st->out_len = skb->len - header_len; - if (!use_options) { + if (!use_opt_desc) { st->header_unmap_len = 0; if (likely(in_len == 0)) { diff --git a/drivers/net/ethernet/stmicro/stmmac/Kconfig b/drivers/net/ethernet/stmicro/stmmac/Kconfig index e2f202e3932f..f2d7c702c77f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig @@ -37,6 +37,17 @@ config DWMAC_SUNXI stmmac device driver. This driver is used for A20/A31 GMAC ethernet controller. +config DWMAC_STI + bool "STi GMAC support" + depends on STMMAC_PLATFORM && ARCH_STI + default y + ---help--- + Support for ethernet controller on STi SOCs. + + This selects STi SoC glue layer support for the stmmac + device driver. This driver is used on for the STi series + SOCs GMAC ethernet controller. + config STMMAC_PCI bool "STMMAC PCI bus support" depends on STMMAC_ETH && PCI diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index ecadecea79b2..dcef28775dad 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -2,6 +2,7 @@ obj-$(CONFIG_STMMAC_ETH) += stmmac.o stmmac-$(CONFIG_STMMAC_PLATFORM) += stmmac_platform.o stmmac-$(CONFIG_STMMAC_PCI) += stmmac_pci.o stmmac-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o +stmmac-$(CONFIG_DWMAC_STI) += dwmac-sti.o stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \ chain_mode.o dwmac_lib.o dwmac1000_core.o dwmac1000_dma.o \ dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \ diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c new file mode 100644 index 000000000000..552bbc17863c --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c @@ -0,0 +1,330 @@ +/** + * dwmac-sti.c - STMicroelectronics DWMAC Specific Glue layer + * + * Copyright (C) 2003-2014 STMicroelectronics (R&D) Limited + * Author: Srinivas Kandagatla <srinivas.kandagatla@st.com> + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/platform_device.h> +#include <linux/stmmac.h> +#include <linux/phy.h> +#include <linux/mfd/syscon.h> +#include <linux/regmap.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_net.h> + +/** + * STi GMAC glue logic. + * -------------------- + * + * _ + * | \ + * --------|0 \ ETH_SEL_INTERNAL_NOTEXT_PHYCLK + * phyclk | |___________________________________________ + * | | | (phyclk-in) + * --------|1 / | + * int-clk |_ / | + * | _ + * | | \ + * |_______|1 \ ETH_SEL_TX_RETIME_CLK + * | |___________________________ + * | | (tx-retime-clk) + * _______|0 / + * | |_ / + * _ | + * | \ | + * --------|0 \ | + * clk_125 | |__| + * | | ETH_SEL_TXCLK_NOT_CLK125 + * --------|1 / + * txclk |_ / + * + * + * ETH_SEL_INTERNAL_NOTEXT_PHYCLK is valid only for RMII where PHY can + * generate 50MHz clock or MAC can generate it. + * This bit is configured by "st,ext-phyclk" property. + * + * ETH_SEL_TXCLK_NOT_CLK125 is only valid for gigabit modes, where the 125Mhz + * clock either comes from clk-125 pin or txclk pin. This configuration is + * totally driven by the board wiring. This bit is configured by + * "st,tx-retime-src" property. + * + * TXCLK configuration is different for different phy interface modes + * and changes according to link speed in modes like RGMII. + * + * Below table summarizes the clock requirement and clock sources for + * supported phy interface modes with link speeds. + * ________________________________________________ + *| PHY_MODE | 1000 Mbit Link | 100 Mbit Link | + * ------------------------------------------------ + *| MII | n/a | 25Mhz | + *| | | txclk | + * ------------------------------------------------ + *| GMII | 125Mhz | 25Mhz | + *| | clk-125/txclk | txclk | + * ------------------------------------------------ + *| RGMII | 125Mhz | 25Mhz | + *| | clk-125/txclk | clkgen | + * ------------------------------------------------ + *| RMII | n/a | 25Mhz | + *| | |clkgen/phyclk-in | + * ------------------------------------------------ + * + * TX lines are always retimed with a clk, which can vary depending + * on the board configuration. Below is the table of these bits + * in eth configuration register depending on source of retime clk. + * + *--------------------------------------------------------------- + * src | tx_rt_clk | int_not_ext_phyclk | txclk_n_clk125| + *--------------------------------------------------------------- + * txclk | 0 | n/a | 1 | + *--------------------------------------------------------------- + * ck_125| 0 | n/a | 0 | + *--------------------------------------------------------------- + * phyclk| 1 | 0 | n/a | + *--------------------------------------------------------------- + * clkgen| 1 | 1 | n/a | + *--------------------------------------------------------------- + */ + + /* Register definition */ + + /* 3 bits [8:6] + * [6:6] ETH_SEL_TXCLK_NOT_CLK125 + * [7:7] ETH_SEL_INTERNAL_NOTEXT_PHYCLK + * [8:8] ETH_SEL_TX_RETIME_CLK + * + */ + +#define TX_RETIME_SRC_MASK GENMASK(8, 6) +#define ETH_SEL_TX_RETIME_CLK BIT(8) +#define ETH_SEL_INTERNAL_NOTEXT_PHYCLK BIT(7) +#define ETH_SEL_TXCLK_NOT_CLK125 BIT(6) + +#define ENMII_MASK GENMASK(5, 5) +#define ENMII BIT(5) + +/** + * 3 bits [4:2] + * 000-GMII/MII + * 001-RGMII + * 010-SGMII + * 100-RMII +*/ +#define MII_PHY_SEL_MASK GENMASK(4, 2) +#define ETH_PHY_SEL_RMII BIT(4) +#define ETH_PHY_SEL_SGMII BIT(3) +#define ETH_PHY_SEL_RGMII BIT(2) +#define ETH_PHY_SEL_GMII 0x0 +#define ETH_PHY_SEL_MII 0x0 + +#define IS_PHY_IF_MODE_RGMII(iface) (iface == PHY_INTERFACE_MODE_RGMII || \ + iface == PHY_INTERFACE_MODE_RGMII_ID || \ + iface == PHY_INTERFACE_MODE_RGMII_RXID || \ + iface == PHY_INTERFACE_MODE_RGMII_TXID) + +#define IS_PHY_IF_MODE_GBIT(iface) (IS_PHY_IF_MODE_RGMII(iface) || \ + iface == PHY_INTERFACE_MODE_GMII) + +struct sti_dwmac { + int interface; + bool ext_phyclk; + bool is_tx_retime_src_clk_125; + struct clk *clk; + int reg; + struct device *dev; + struct regmap *regmap; +}; + +static u32 phy_intf_sels[] = { + [PHY_INTERFACE_MODE_MII] = ETH_PHY_SEL_MII, + [PHY_INTERFACE_MODE_GMII] = ETH_PHY_SEL_GMII, + [PHY_INTERFACE_MODE_RGMII] = ETH_PHY_SEL_RGMII, + [PHY_INTERFACE_MODE_RGMII_ID] = ETH_PHY_SEL_RGMII, + [PHY_INTERFACE_MODE_SGMII] = ETH_PHY_SEL_SGMII, + [PHY_INTERFACE_MODE_RMII] = ETH_PHY_SEL_RMII, +}; + +enum { + TX_RETIME_SRC_NA = 0, + TX_RETIME_SRC_TXCLK = 1, + TX_RETIME_SRC_CLK_125, + TX_RETIME_SRC_PHYCLK, + TX_RETIME_SRC_CLKGEN, +}; + +static const char *const tx_retime_srcs[] = { + [TX_RETIME_SRC_NA] = "", + [TX_RETIME_SRC_TXCLK] = "txclk", + [TX_RETIME_SRC_CLK_125] = "clk_125", + [TX_RETIME_SRC_PHYCLK] = "phyclk", + [TX_RETIME_SRC_CLKGEN] = "clkgen", +}; + +static u32 tx_retime_val[] = { + [TX_RETIME_SRC_TXCLK] = ETH_SEL_TXCLK_NOT_CLK125, + [TX_RETIME_SRC_CLK_125] = 0x0, + [TX_RETIME_SRC_PHYCLK] = ETH_SEL_TX_RETIME_CLK, + [TX_RETIME_SRC_CLKGEN] = ETH_SEL_TX_RETIME_CLK | + ETH_SEL_INTERNAL_NOTEXT_PHYCLK, +}; + +static void setup_retime_src(struct sti_dwmac *dwmac, u32 spd) +{ + u32 src = 0, freq = 0; + + if (spd == SPEED_100) { + if (dwmac->interface == PHY_INTERFACE_MODE_MII || + dwmac->interface == PHY_INTERFACE_MODE_GMII) { + src = TX_RETIME_SRC_TXCLK; + } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) { + if (dwmac->ext_phyclk) { + src = TX_RETIME_SRC_PHYCLK; + } else { + src = TX_RETIME_SRC_CLKGEN; + freq = 50000000; + } + + } else if (IS_PHY_IF_MODE_RGMII(dwmac->interface)) { + src = TX_RETIME_SRC_CLKGEN; + freq = 25000000; + } + + if (src == TX_RETIME_SRC_CLKGEN && dwmac->clk) + clk_set_rate(dwmac->clk, freq); + + } else if (spd == SPEED_1000) { + if (dwmac->is_tx_retime_src_clk_125) + src = TX_RETIME_SRC_CLK_125; + else + src = TX_RETIME_SRC_TXCLK; + } + + regmap_update_bits(dwmac->regmap, dwmac->reg, + TX_RETIME_SRC_MASK, tx_retime_val[src]); +} + +static void sti_dwmac_exit(struct platform_device *pdev, void *priv) +{ + struct sti_dwmac *dwmac = priv; + + if (dwmac->clk) + clk_disable_unprepare(dwmac->clk); +} + +static void sti_fix_mac_speed(void *priv, unsigned int spd) +{ + struct sti_dwmac *dwmac = priv; + + setup_retime_src(dwmac, spd); + + return; +} + +static int sti_dwmac_parse_data(struct sti_dwmac *dwmac, + struct platform_device *pdev) +{ + struct resource *res; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct regmap *regmap; + int err; + + if (!np) + return -EINVAL; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf"); + if (!res) + return -ENODATA; + + regmap = syscon_regmap_lookup_by_phandle(np, "st,syscon"); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + dwmac->dev = dev; + dwmac->interface = of_get_phy_mode(np); + dwmac->regmap = regmap; + dwmac->reg = res->start; + dwmac->ext_phyclk = of_property_read_bool(np, "st,ext-phyclk"); + dwmac->is_tx_retime_src_clk_125 = false; + + if (IS_PHY_IF_MODE_GBIT(dwmac->interface)) { + const char *rs; + + err = of_property_read_string(np, "st,tx-retime-src", &rs); + if (err < 0) { + dev_err(dev, "st,tx-retime-src not specified\n"); + return err; + } + + if (!strcasecmp(rs, "clk_125")) + dwmac->is_tx_retime_src_clk_125 = true; + } + + dwmac->clk = devm_clk_get(dev, "sti-ethclk"); + + if (IS_ERR(dwmac->clk)) + dwmac->clk = NULL; + + return 0; +} + +static int sti_dwmac_init(struct platform_device *pdev, void *priv) +{ + struct sti_dwmac *dwmac = priv; + struct regmap *regmap = dwmac->regmap; + int iface = dwmac->interface; + u32 reg = dwmac->reg; + u32 val, spd; + + if (dwmac->clk) + clk_prepare_enable(dwmac->clk); + + regmap_update_bits(regmap, reg, MII_PHY_SEL_MASK, phy_intf_sels[iface]); + + val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII; + regmap_update_bits(regmap, reg, ENMII_MASK, val); + + if (IS_PHY_IF_MODE_GBIT(iface)) + spd = SPEED_1000; + else + spd = SPEED_100; + + setup_retime_src(dwmac, spd); + + return 0; +} + +static void *sti_dwmac_setup(struct platform_device *pdev) +{ + struct sti_dwmac *dwmac; + int ret; + + dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); + if (!dwmac) + return ERR_PTR(-ENOMEM); + + ret = sti_dwmac_parse_data(dwmac, pdev); + if (ret) { + dev_err(&pdev->dev, "Unable to parse OF data\n"); + return ERR_PTR(ret); + } + + return dwmac; +} + +const struct stmmac_of_data sti_gmac_data = { + .fix_mac_speed = sti_fix_mac_speed, + .setup = sti_dwmac_setup, + .init = sti_dwmac_init, + .exit = sti_dwmac_exit, +}; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h index d9af26ed58ee..f9e60d7918c4 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h @@ -133,6 +133,9 @@ bool stmmac_eee_init(struct stmmac_priv *priv); #ifdef CONFIG_DWMAC_SUNXI extern const struct stmmac_of_data sun7i_gmac_data; #endif +#ifdef CONFIG_DWMAC_STI +extern const struct stmmac_of_data sti_gmac_data; +#endif extern struct platform_driver stmmac_pltfr_driver; static inline int stmmac_register_platform(void) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index a2e7d2c96e36..078ad0ec8593 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -1705,7 +1705,7 @@ static int stmmac_open(struct net_device *dev) priv->dma_rx_size = STMMAC_ALIGN(dma_rxsize); priv->dma_buf_sz = STMMAC_ALIGN(buf_sz); - alloc_dma_desc_resources(priv); + ret = alloc_dma_desc_resources(priv); if (ret < 0) { pr_err("%s: DMA descriptors allocation failed\n", __func__); goto dma_desc_error; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 5884a7d2063b..c61bc72b8e90 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -33,6 +33,11 @@ static const struct of_device_id stmmac_dt_ids[] = { #ifdef CONFIG_DWMAC_SUNXI { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data}, #endif +#ifdef CONFIG_DWMAC_STI + { .compatible = "st,stih415-dwmac", .data = &sti_gmac_data}, + { .compatible = "st,stih416-dwmac", .data = &sti_gmac_data}, + { .compatible = "st,stih127-dwmac", .data = &sti_gmac_data}, +#endif /* SoC specific glue layers should come before generic bindings */ { .compatible = "st,spear600-gmac"}, { .compatible = "snps,dwmac-3.610"}, diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c index 8e2266e1f260..79606f47a08e 100644 --- a/drivers/net/ethernet/sun/niu.c +++ b/drivers/net/ethernet/sun/niu.c @@ -9041,7 +9041,7 @@ static void niu_try_msix(struct niu *np, u8 *ldg_num_map) struct msix_entry msi_vec[NIU_NUM_LDG]; struct niu_parent *parent = np->parent; struct pci_dev *pdev = np->pdev; - int i, num_irqs, err; + int i, num_irqs; u8 first_ldg; first_ldg = (NIU_NUM_LDG / parent->num_ports) * np->port; @@ -9053,21 +9053,16 @@ static void niu_try_msix(struct niu *np, u8 *ldg_num_map) (np->port == 0 ? 3 : 1)); BUG_ON(num_irqs > (NIU_NUM_LDG / parent->num_ports)); -retry: for (i = 0; i < num_irqs; i++) { msi_vec[i].vector = 0; msi_vec[i].entry = i; } - err = pci_enable_msix(pdev, msi_vec, num_irqs); - if (err < 0) { + num_irqs = pci_enable_msix_range(pdev, msi_vec, 1, num_irqs); + if (num_irqs < 0) { np->flags &= ~NIU_FLAGS_MSIX; return; } - if (err > 0) { - num_irqs = err; - goto retry; - } np->flags |= NIU_FLAGS_MSIX; for (i = 0; i < num_irqs; i++) diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c index bde63e3af96f..543a0813c9e0 100644 --- a/drivers/net/ethernet/ti/cpsw.c +++ b/drivers/net/ethernet/ti/cpsw.c @@ -378,7 +378,6 @@ struct cpsw_priv { u32 version; u32 coal_intvl; u32 bus_freq_mhz; - struct net_device_stats stats; int rx_packet_max; int host_port; struct clk *clk; @@ -554,7 +553,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) * common for both the interface as the interface shares * the same hardware resource. */ - for (i = 0; i <= priv->data.slaves; i++) + for (i = 0; i < priv->data.slaves; i++) if (priv->slaves[i].ndev->flags & IFF_PROMISC) flag = true; @@ -578,7 +577,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) unsigned long timeout = jiffies + HZ; /* Disable Learn for all ports */ - for (i = 0; i <= priv->data.slaves; i++) { + for (i = 0; i < priv->data.slaves; i++) { cpsw_ale_control_set(ale, i, ALE_PORT_NOLEARN, 1); cpsw_ale_control_set(ale, i, @@ -606,7 +605,7 @@ static void cpsw_set_promiscious(struct net_device *ndev, bool enable) cpsw_ale_control_set(ale, 0, ALE_P0_UNI_FLOOD, 0); /* Enable Learn for all ports */ - for (i = 0; i <= priv->data.slaves; i++) { + for (i = 0; i < priv->data.slaves; i++) { cpsw_ale_control_set(ale, i, ALE_PORT_NOLEARN, 0); cpsw_ale_control_set(ale, i, @@ -673,8 +672,8 @@ static void cpsw_tx_handler(void *token, int len, int status) if (unlikely(netif_queue_stopped(ndev))) netif_wake_queue(ndev); cpts_tx_timestamp(priv->cpts, skb); - priv->stats.tx_packets++; - priv->stats.tx_bytes += len; + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += len; dev_kfree_skb_any(skb); } @@ -700,10 +699,10 @@ static void cpsw_rx_handler(void *token, int len, int status) cpts_rx_timestamp(priv->cpts, skb); skb->protocol = eth_type_trans(skb, ndev); netif_receive_skb(skb); - priv->stats.rx_bytes += len; - priv->stats.rx_packets++; + ndev->stats.rx_bytes += len; + ndev->stats.rx_packets++; } else { - priv->stats.rx_dropped++; + ndev->stats.rx_dropped++; new_skb = skb; } @@ -1164,11 +1163,17 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) { + u32 slave_port; + + slave_port = cpsw_get_slave_port(priv, slave->slave_num); + if (!slave->phy) return; phy_stop(slave->phy); phy_disconnect(slave->phy); slave->phy = NULL; + cpsw_ale_control_set(priv->ale, slave_port, + ALE_PORT_STATE, ALE_PORT_STATE_DISABLE); } static int cpsw_ndo_open(struct net_device *ndev) @@ -1307,7 +1312,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, if (skb_padto(skb, CPSW_MIN_PACKET_SIZE)) { cpsw_err(priv, tx_err, "packet pad failed\n"); - priv->stats.tx_dropped++; + ndev->stats.tx_dropped++; return NETDEV_TX_OK; } @@ -1331,7 +1336,7 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; fail: - priv->stats.tx_dropped++; + ndev->stats.tx_dropped++; netif_stop_queue(ndev); return NETDEV_TX_BUSY; } @@ -1471,7 +1476,6 @@ static int cpsw_hwtstamp_get(struct net_device *dev, struct ifreq *ifr) static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct cpsw_priv *priv = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(req); int slave_no = cpsw_slave_index(priv); if (!netif_running(dev)) @@ -1484,14 +1488,11 @@ static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) case SIOCGHWTSTAMP: return cpsw_hwtstamp_get(dev, req); #endif - case SIOCGMIIPHY: - data->phy_id = priv->slaves[slave_no].phy->addr; - break; - default: - return -ENOTSUPP; } - return 0; + if (!priv->slaves[slave_no].phy) + return -EOPNOTSUPP; + return phy_mii_ioctl(priv->slaves[slave_no].phy, req, cmd); } static void cpsw_ndo_tx_timeout(struct net_device *ndev) @@ -1499,7 +1500,7 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev) struct cpsw_priv *priv = netdev_priv(ndev); cpsw_err(priv, tx_err, "transmit timeout, restarting dma\n"); - priv->stats.tx_errors++; + ndev->stats.tx_errors++; cpsw_intr_disable(priv); cpdma_ctlr_int_ctrl(priv->dma, false); cpdma_chan_stop(priv->txch); @@ -1538,12 +1539,6 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p) return 0; } -static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev) -{ - struct cpsw_priv *priv = netdev_priv(ndev); - return &priv->stats; -} - #ifdef CONFIG_NET_POLL_CONTROLLER static void cpsw_ndo_poll_controller(struct net_device *ndev) { @@ -1636,7 +1631,6 @@ static const struct net_device_ops cpsw_netdev_ops = { .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, .ndo_tx_timeout = cpsw_ndo_tx_timeout, - .ndo_get_stats = cpsw_ndo_get_stats, .ndo_set_rx_mode = cpsw_ndo_set_rx_mode, #ifdef CONFIG_NET_POLL_CONTROLLER .ndo_poll_controller = cpsw_ndo_poll_controller, @@ -1878,14 +1872,29 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, mdio_node = of_find_node_by_phandle(be32_to_cpup(parp)); phyid = be32_to_cpup(parp+1); mdio = of_find_device_by_node(mdio_node); - snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), - PHY_ID_FMT, mdio->name, phyid); + + if (strncmp(mdio->name, "gpio", 4) == 0) { + /* GPIO bitbang MDIO driver attached */ + struct mii_bus *bus = dev_get_drvdata(&mdio->dev); + + snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), + PHY_ID_FMT, bus->id, phyid); + } else { + /* davinci MDIO driver attached */ + snprintf(slave_data->phy_id, sizeof(slave_data->phy_id), + PHY_ID_FMT, mdio->name, phyid); + } mac_addr = of_get_mac_address(slave_node); if (mac_addr) memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); slave_data->phy_if = of_get_phy_mode(slave_node); + if (slave_data->phy_if < 0) { + pr_err("Missing or malformed slave[%d] phy-mode property\n", + i); + return slave_data->phy_if; + } if (data->dual_emac) { if (of_property_read_u32(slave_node, "dual_emac_res_vlan", diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c index 023237a65720..17503da9f7a5 100644 --- a/drivers/net/ethernet/tile/tilegx.c +++ b/drivers/net/ethernet/tile/tilegx.c @@ -2071,7 +2071,7 @@ 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, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { return smp_processor_id(); } diff --git a/drivers/net/ethernet/wiznet/w5100.c b/drivers/net/ethernet/wiznet/w5100.c index 0df36c6ec7f4..104d46f37969 100644 --- a/drivers/net/ethernet/wiznet/w5100.c +++ b/drivers/net/ethernet/wiznet/w5100.c @@ -641,11 +641,10 @@ static int w5100_hw_probe(struct platform_device *pdev) if (!mem) return -ENXIO; mem_size = resource_size(mem); - if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name)) - return -EBUSY; - priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size); - if (!priv->base) - return -EBUSY; + + priv->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); spin_lock_init(&priv->reg_lock); priv->indirect = mem_size < W5100_BUS_DIRECT_SIZE; diff --git a/drivers/net/ethernet/wiznet/w5300.c b/drivers/net/ethernet/wiznet/w5300.c index 71c27b3292f1..1f33c4c86c20 100644 --- a/drivers/net/ethernet/wiznet/w5300.c +++ b/drivers/net/ethernet/wiznet/w5300.c @@ -561,11 +561,10 @@ static int w5300_hw_probe(struct platform_device *pdev) if (!mem) return -ENXIO; mem_size = resource_size(mem); - if (!devm_request_mem_region(&pdev->dev, mem->start, mem_size, name)) - return -EBUSY; - priv->base = devm_ioremap(&pdev->dev, mem->start, mem_size); - if (!priv->base) - return -EBUSY; + + priv->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); spin_lock_init(&priv->reg_lock); priv->indirect = mem_size < W5300_BUS_DIRECT_SIZE; diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index a4347508031c..fa193c4688da 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -771,8 +771,8 @@ static void ll_temac_recv(struct net_device *ndev) /* if we're doing rx csum offload, set it up */ if (((lp->temac_features & TEMAC_FEATURE_RX_CSUM) != 0) && - (skb->protocol == __constant_htons(ETH_P_IP)) && - (skb->len > 64)) { + (skb->protocol == htons(ETH_P_IP)) && + (skb->len > 64)) { skb->csum = cur_p->app3 & 0xFFFF; skb->ip_summed = CHECKSUM_COMPLETE; diff --git a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c index 1ec65feebb9e..7b0a73556264 100644 --- a/drivers/net/ethernet/xilinx/xilinx_axienet_main.c +++ b/drivers/net/ethernet/xilinx/xilinx_axienet_main.c @@ -26,6 +26,7 @@ #include <linux/netdevice.h> #include <linux/of_mdio.h> #include <linux/of_platform.h> +#include <linux/of_irq.h> #include <linux/of_address.h> #include <linux/skbuff.h> #include <linux/spinlock.h> @@ -600,7 +601,8 @@ static void axienet_start_xmit_done(struct net_device *ndev) size += status & XAXIDMA_BD_STS_ACTUAL_LEN_MASK; packets++; - lp->tx_bd_ci = ++lp->tx_bd_ci % TX_BD_NUM; + ++lp->tx_bd_ci; + lp->tx_bd_ci %= TX_BD_NUM; cur_p = &lp->tx_bd_v[lp->tx_bd_ci]; status = cur_p->status; } @@ -686,7 +688,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) skb_headlen(skb), DMA_TO_DEVICE); for (ii = 0; ii < num_frag; ii++) { - lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM; + ++lp->tx_bd_tail; + lp->tx_bd_tail %= TX_BD_NUM; cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; frag = &skb_shinfo(skb)->frags[ii]; cur_p->phys = dma_map_single(ndev->dev.parent, @@ -702,7 +705,8 @@ static int axienet_start_xmit(struct sk_buff *skb, struct net_device *ndev) tail_p = lp->tx_bd_p + sizeof(*lp->tx_bd_v) * lp->tx_bd_tail; /* Start the transfer */ axienet_dma_out32(lp, XAXIDMA_TX_TDESC_OFFSET, tail_p); - lp->tx_bd_tail = ++lp->tx_bd_tail % TX_BD_NUM; + ++lp->tx_bd_tail; + lp->tx_bd_tail %= TX_BD_NUM; return NETDEV_TX_OK; } @@ -752,7 +756,7 @@ static void axienet_recv(struct net_device *ndev) skb->ip_summed = CHECKSUM_UNNECESSARY; } } else if ((lp->features & XAE_FEATURE_PARTIAL_RX_CSUM) != 0 && - skb->protocol == __constant_htons(ETH_P_IP) && + skb->protocol == htons(ETH_P_IP) && skb->len > 64) { skb->csum = be32_to_cpu(cur_p->app3 & 0xFFFF); skb->ip_summed = CHECKSUM_COMPLETE; @@ -774,7 +778,8 @@ static void axienet_recv(struct net_device *ndev) cur_p->status = 0; cur_p->sw_id_offset = (u32) new_skb; - lp->rx_bd_ci = ++lp->rx_bd_ci % RX_BD_NUM; + ++lp->rx_bd_ci; + lp->rx_bd_ci %= RX_BD_NUM; cur_p = &lp->rx_bd_v[lp->rx_bd_ci]; } diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 7b594ce3f21d..13010b4dae5b 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -30,6 +30,7 @@ /* Fwd declaration */ struct hv_netvsc_packet; +struct ndis_tcp_ip_checksum_info; /* Represent the xfer page packet which contains 1 or more netvsc packet */ struct xferpage_packet { @@ -73,7 +74,7 @@ struct hv_netvsc_packet { } completion; /* This points to the memory after page_buf */ - void *extension; + struct rndis_message *rndis_msg; u32 total_data_buflen; /* Points to the send/receive buffer where the ethernet frame is */ @@ -117,7 +118,8 @@ int netvsc_send(struct hv_device *device, void netvsc_linkstatus_callback(struct hv_device *device_obj, unsigned int status); int netvsc_recv_callback(struct hv_device *device_obj, - struct hv_netvsc_packet *packet); + struct hv_netvsc_packet *packet, + struct ndis_tcp_ip_checksum_info *csum_info); int rndis_filter_open(struct hv_device *dev); int rndis_filter_close(struct hv_device *dev); int rndis_filter_device_add(struct hv_device *dev, @@ -126,11 +128,6 @@ void rndis_filter_device_remove(struct hv_device *dev); int rndis_filter_receive(struct hv_device *dev, struct hv_netvsc_packet *pkt); - - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt); - int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter); int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); @@ -139,6 +136,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac); #define NVSP_PROTOCOL_VERSION_1 2 #define NVSP_PROTOCOL_VERSION_2 0x30002 +#define NVSP_PROTOCOL_VERSION_4 0x40000 +#define NVSP_PROTOCOL_VERSION_5 0x50000 enum { NVSP_MSG_TYPE_NONE = 0, @@ -193,6 +192,23 @@ enum { NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE, NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, + + NVSP_MSG2_MAX = NVSP_MSG2_TYPE_ALLOC_CHIMNEY_HANDLE_COMP, + + /* Version 4 messages */ + NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION, + NVSP_MSG4_TYPE_SWITCH_DATA_PATH, + NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED, + + NVSP_MSG4_MAX = NVSP_MSG4_TYPE_UPLINK_CONNECT_STATE_DEPRECATED, + + /* Version 5 messages */ + NVSP_MSG5_TYPE_OID_QUERY_EX, + NVSP_MSG5_TYPE_OID_QUERY_EX_COMP, + NVSP_MSG5_TYPE_SUBCHANNEL, + NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE, + + NVSP_MSG5_MAX = NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE, }; enum { @@ -447,10 +463,44 @@ union nvsp_2_message_uber { struct nvsp_2_free_rxbuf free_rxbuf; } __packed; +enum nvsp_subchannel_operation { + NVSP_SUBCHANNEL_NONE = 0, + NVSP_SUBCHANNEL_ALLOCATE, + NVSP_SUBCHANNEL_MAX +}; + +struct nvsp_5_subchannel_request { + u32 op; + u32 num_subchannels; +} __packed; + +struct nvsp_5_subchannel_complete { + u32 status; + u32 num_subchannels; /* Actual number of subchannels allocated */ +} __packed; + +struct nvsp_5_send_indirect_table { + /* The number of entries in the send indirection table */ + u32 count; + + /* The offset of the send indireciton table from top of this struct. + * The send indirection table tells which channel to put the send + * traffic on. Each entry is a channel number. + */ + u32 offset; +} __packed; + +union nvsp_5_message_uber { + struct nvsp_5_subchannel_request subchn_req; + struct nvsp_5_subchannel_complete subchn_comp; + struct nvsp_5_send_indirect_table send_table; +} __packed; + union nvsp_all_messages { union nvsp_message_init_uber init_msg; union nvsp_1_message_uber v1_msg; union nvsp_2_message_uber v2_msg; + union nvsp_5_message_uber v5_msg; } __packed; /* ALL Messages */ @@ -463,6 +513,7 @@ struct nvsp_message { #define NETVSC_MTU 65536 #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ +#define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ #define NETVSC_RECEIVE_BUFFER_ID 0xcafe @@ -506,6 +557,8 @@ struct netvsc_device { /* Holds rndis device info */ void *extension; + /* The recive buffer for this device */ + unsigned char cb_buffer[NETVSC_PACKET_SIZE]; }; /* NdisInitialize message */ @@ -671,9 +724,133 @@ struct ndis_pkt_8021q_info { }; }; +struct ndis_oject_header { + u8 type; + u8 revision; + u16 size; +}; + +#define NDIS_OBJECT_TYPE_DEFAULT 0x80 +#define NDIS_OFFLOAD_PARAMETERS_REVISION_3 3 +#define NDIS_OFFLOAD_PARAMETERS_NO_CHANGE 0 +#define NDIS_OFFLOAD_PARAMETERS_LSOV2_DISABLED 1 +#define NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_LSOV1_ENABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_RSC_DISABLED 1 +#define NDIS_OFFLOAD_PARAMETERS_RSC_ENABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_TX_RX_DISABLED 1 +#define NDIS_OFFLOAD_PARAMETERS_TX_ENABLED_RX_DISABLED 2 +#define NDIS_OFFLOAD_PARAMETERS_RX_ENABLED_TX_DISABLED 3 +#define NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED 4 + +#define NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE 1 +#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4 0 +#define NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6 1 + +/* + * New offload OIDs for NDIS 6 + */ +#define OID_TCP_OFFLOAD_CURRENT_CONFIG 0xFC01020B /* query only */ +#define OID_TCP_OFFLOAD_PARAMETERS 0xFC01020C /* set only */ +#define OID_TCP_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020D/* query only */ +#define OID_TCP_CONNECTION_OFFLOAD_CURRENT_CONFIG 0xFC01020E /* query only */ +#define OID_TCP_CONNECTION_OFFLOAD_HARDWARE_CAPABILITIES 0xFC01020F /* query */ +#define OID_OFFLOAD_ENCAPSULATION 0x0101010A /* set/query */ + +struct ndis_offload_params { + struct ndis_oject_header header; + u8 ip_v4_csum; + u8 tcp_ip_v4_csum; + u8 udp_ip_v4_csum; + u8 tcp_ip_v6_csum; + u8 udp_ip_v6_csum; + u8 lso_v1; + u8 ip_sec_v1; + u8 lso_v2_ipv4; + u8 lso_v2_ipv6; + u8 tcp_connection_ip_v4; + u8 tcp_connection_ip_v6; + u32 flags; + u8 ip_sec_v2; + u8 ip_sec_v2_ip_v4; + struct { + u8 rsc_ip_v4; + u8 rsc_ip_v6; + }; + struct { + u8 encapsulated_packet_task_offload; + u8 encapsulation_types; + }; +}; + +struct ndis_tcp_ip_checksum_info { + union { + struct { + u32 is_ipv4:1; + u32 is_ipv6:1; + u32 tcp_checksum:1; + u32 udp_checksum:1; + u32 ip_header_checksum:1; + u32 reserved:11; + u32 tcp_header_offset:10; + } transmit; + struct { + u32 tcp_checksum_failed:1; + u32 udp_checksum_failed:1; + u32 ip_checksum_failed:1; + u32 tcp_checksum_succeeded:1; + u32 udp_checksum_succeeded:1; + u32 ip_checksum_succeeded:1; + u32 loopback:1; + u32 tcp_checksum_value_invalid:1; + u32 ip_checksum_value_invalid:1; + } receive; + u32 value; + }; +}; + +struct ndis_tcp_lso_info { + union { + struct { + u32 unused:30; + u32 type:1; + u32 reserved2:1; + } transmit; + struct { + u32 mss:20; + u32 tcp_header_offset:10; + u32 type:1; + u32 reserved2:1; + } lso_v1_transmit; + struct { + u32 tcp_payload:30; + u32 type:1; + u32 reserved2:1; + } lso_v1_transmit_complete; + struct { + u32 mss:20; + u32 tcp_header_offset:10; + u32 type:1; + u32 ip_version:1; + } lso_v2_transmit; + struct { + u32 reserved:30; + u32 type:1; + u32 reserved2:1; + } lso_v2_transmit_complete; + u32 value; + }; +}; + #define NDIS_VLAN_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ sizeof(struct ndis_pkt_8021q_info)) +#define NDIS_CSUM_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ + sizeof(struct ndis_tcp_ip_checksum_info)) + +#define NDIS_LSO_PPI_SIZE (sizeof(struct rndis_per_packet_info) + \ + sizeof(struct ndis_tcp_lso_info)) + /* Format of Information buffer passed in a SetRequest for the OID */ /* OID_GEN_RNDIS_CONFIG_PARAMETER. */ struct rndis_config_parameter_info { @@ -846,12 +1023,6 @@ struct rndis_message { }; -struct rndis_filter_packet { - void *completion_ctx; - void (*completion)(void *context); - struct rndis_message msg; -}; - /* Handy macros */ /* get the size of an RNDIS message. Pass in the message type, */ @@ -905,6 +1076,16 @@ struct rndis_filter_packet { #define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 #define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 +#define INFO_IPV4 2 +#define INFO_IPV6 4 +#define INFO_TCP 2 +#define INFO_UDP 4 + +#define TRANSPORT_INFO_NOT_IP 0 +#define TRANSPORT_INFO_IPV4_TCP ((INFO_IPV4 << 16) | INFO_TCP) +#define TRANSPORT_INFO_IPV4_UDP ((INFO_IPV4 << 16) | INFO_UDP) +#define TRANSPORT_INFO_IPV6_TCP ((INFO_IPV6 << 16) | INFO_TCP) +#define TRANSPORT_INFO_IPV6_UDP ((INFO_IPV6 << 16) | INFO_UDP) #endif /* _HYPERV_NET_H */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 03a2c6e17158..daddea2654ce 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -290,7 +290,7 @@ static int negotiate_nvsp_ver(struct hv_device *device, NVSP_STAT_SUCCESS) return -EINVAL; - if (nvsp_ver != NVSP_PROTOCOL_VERSION_2) + if (nvsp_ver == NVSP_PROTOCOL_VERSION_1) return 0; /* NVSPv2 only: Send NDIS config */ @@ -314,6 +314,9 @@ static int netvsc_connect_vsp(struct hv_device *device) struct nvsp_message *init_packet; int ndis_version; struct net_device *ndev; + u32 ver_list[] = { NVSP_PROTOCOL_VERSION_1, NVSP_PROTOCOL_VERSION_2, + NVSP_PROTOCOL_VERSION_4, NVSP_PROTOCOL_VERSION_5 }; + int i, num_ver = 4; /* number of different NVSP versions */ net_device = get_outbound_net_device(device); if (!net_device) @@ -323,13 +326,14 @@ static int netvsc_connect_vsp(struct hv_device *device) init_packet = &net_device->channel_init_pkt; /* Negotiate the latest NVSP protocol supported */ - if (negotiate_nvsp_ver(device, net_device, init_packet, - NVSP_PROTOCOL_VERSION_2) == 0) { - net_device->nvsp_version = NVSP_PROTOCOL_VERSION_2; - } else if (negotiate_nvsp_ver(device, net_device, init_packet, - NVSP_PROTOCOL_VERSION_1) == 0) { - net_device->nvsp_version = NVSP_PROTOCOL_VERSION_1; - } else { + for (i = num_ver - 1; i >= 0; i--) + if (negotiate_nvsp_ver(device, net_device, init_packet, + ver_list[i]) == 0) { + net_device->nvsp_version = ver_list[i]; + break; + } + + if (i < 0) { ret = -EPROTO; goto cleanup; } @@ -339,7 +343,10 @@ static int netvsc_connect_vsp(struct hv_device *device) /* Send the ndis version */ memset(init_packet, 0, sizeof(struct nvsp_message)); - ndis_version = 0x00050001; + if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_4) + ndis_version = 0x00050001; + else + ndis_version = 0x0006001e; init_packet->hdr.msg_type = NVSP_MSG1_TYPE_SEND_NDIS_VER; init_packet->msg.v1_msg. @@ -358,6 +365,11 @@ static int netvsc_connect_vsp(struct hv_device *device) goto cleanup; /* Post the big receive buffer to NetVSP */ + if (net_device->nvsp_version <= NVSP_PROTOCOL_VERSION_2) + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE_LEGACY; + else + net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; + ret = netvsc_init_recv_buf(device); cleanup: @@ -432,17 +444,14 @@ static inline u32 hv_ringbuf_avail_percent( return avail_write * 100 / ring_info->ring_datasize; } -static void netvsc_send_completion(struct hv_device *device, +static void netvsc_send_completion(struct netvsc_device *net_device, + struct hv_device *device, struct vmpacket_descriptor *packet) { - struct netvsc_device *net_device; struct nvsp_message *nvsp_packet; struct hv_netvsc_packet *nvsc_packet; struct net_device *ndev; - net_device = get_inbound_net_device(device); - if (!net_device) - return; ndev = net_device->ndev; nvsp_packet = (struct nvsp_message *)((unsigned long)packet + @@ -561,13 +570,13 @@ int netvsc_send(struct hv_device *device, } static void netvsc_send_recv_completion(struct hv_device *device, + struct netvsc_device *net_device, u64 transaction_id, u32 status) { struct nvsp_message recvcompMessage; int retries = 0; int ret; struct net_device *ndev; - struct netvsc_device *net_device = hv_get_drvdata(device); ndev = net_device->ndev; @@ -653,14 +662,15 @@ static void netvsc_receive_completion(void *context) /* Send a receive completion for the xfer page packet */ if (fsend_receive_comp) - netvsc_send_recv_completion(device, transaction_id, status); + netvsc_send_recv_completion(device, net_device, transaction_id, + status); } -static void netvsc_receive(struct hv_device *device, - struct vmpacket_descriptor *packet) +static void netvsc_receive(struct netvsc_device *net_device, + struct hv_device *device, + struct vmpacket_descriptor *packet) { - struct netvsc_device *net_device; struct vmtransfer_page_packet_header *vmxferpage_packet; struct nvsp_message *nvsp_packet; struct hv_netvsc_packet *netvsc_packet = NULL; @@ -673,9 +683,6 @@ static void netvsc_receive(struct hv_device *device, LIST_HEAD(listHead); - net_device = get_inbound_net_device(device); - if (!net_device) - return; ndev = net_device->ndev; /* @@ -741,7 +748,7 @@ static void netvsc_receive(struct hv_device *device, spin_unlock_irqrestore(&net_device->recv_pkt_list_lock, flags); - netvsc_send_recv_completion(device, + netvsc_send_recv_completion(device, net_device, vmxferpage_packet->d.trans_id, NVSP_STAT_FAIL); @@ -800,22 +807,16 @@ static void netvsc_channel_cb(void *context) struct netvsc_device *net_device; u32 bytes_recvd; u64 request_id; - unsigned char *packet; struct vmpacket_descriptor *desc; unsigned char *buffer; int bufferlen = NETVSC_PACKET_SIZE; struct net_device *ndev; - packet = kzalloc(NETVSC_PACKET_SIZE * sizeof(unsigned char), - GFP_ATOMIC); - if (!packet) - return; - buffer = packet; - net_device = get_inbound_net_device(device); if (!net_device) - goto out; + return; ndev = net_device->ndev; + buffer = net_device->cb_buffer; do { ret = vmbus_recvpacket_raw(device->channel, buffer, bufferlen, @@ -825,11 +826,13 @@ static void netvsc_channel_cb(void *context) desc = (struct vmpacket_descriptor *)buffer; switch (desc->type) { case VM_PKT_COMP: - netvsc_send_completion(device, desc); + netvsc_send_completion(net_device, + device, desc); break; case VM_PKT_DATA_USING_XFER_PAGES: - netvsc_receive(device, desc); + netvsc_receive(net_device, + device, desc); break; default: @@ -841,23 +844,16 @@ static void netvsc_channel_cb(void *context) break; } - /* reset */ - if (bufferlen > NETVSC_PACKET_SIZE) { - kfree(buffer); - buffer = packet; - bufferlen = NETVSC_PACKET_SIZE; - } } else { - /* reset */ - if (bufferlen > NETVSC_PACKET_SIZE) { - kfree(buffer); - buffer = packet; - bufferlen = NETVSC_PACKET_SIZE; - } - + /* + * We are done for this pass. + */ break; } + } else if (ret == -ENOBUFS) { + if (bufferlen > NETVSC_PACKET_SIZE) + kfree(buffer); /* Handle large packet */ buffer = kmalloc(bytes_recvd, GFP_ATOMIC); if (buffer == NULL) { @@ -872,8 +868,8 @@ static void netvsc_channel_cb(void *context) } } while (1); -out: - kfree(buffer); + if (bufferlen > NETVSC_PACKET_SIZE) + kfree(buffer); return; } @@ -907,7 +903,6 @@ int netvsc_device_add(struct hv_device *device, void *additional_info) ndev = net_device->ndev; /* Initialize the NetVSC channel extension */ - net_device->recv_buf_size = NETVSC_RECEIVE_BUFFER_SIZE; spin_lock_init(&net_device->recv_pkt_list_lock); INIT_LIST_HEAD(&net_device->recv_pkt_list); diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 7756118c2f0a..3d069901e6d9 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -88,8 +88,12 @@ static int netvsc_open(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = net_device_ctx->device_ctx; + struct netvsc_device *nvdev; + struct rndis_device *rdev; int ret = 0; + netif_carrier_off(net); + /* Open up the device */ ret = rndis_filter_open(device_obj); if (ret != 0) { @@ -99,6 +103,11 @@ static int netvsc_open(struct net_device *net) netif_start_queue(net); + nvdev = hv_get_drvdata(device_obj); + rdev = nvdev->extension; + if (!rdev->link_state) + netif_carrier_on(net); + return ret; } @@ -119,6 +128,27 @@ static int netvsc_close(struct net_device *net) return ret; } +static void *init_ppi_data(struct rndis_message *msg, u32 ppi_size, + int pkt_type) +{ + struct rndis_packet *rndis_pkt; + struct rndis_per_packet_info *ppi; + + rndis_pkt = &msg->msg.pkt; + rndis_pkt->data_offset += ppi_size; + + ppi = (struct rndis_per_packet_info *)((void *)rndis_pkt + + rndis_pkt->per_pkt_info_offset + rndis_pkt->per_pkt_info_len); + + ppi->size = ppi_size; + ppi->type = pkt_type; + ppi->ppi_offset = sizeof(struct rndis_per_packet_info); + + rndis_pkt->per_pkt_info_len += ppi_size; + + return ppi; +} + static void netvsc_xmit_completion(void *context) { struct hv_netvsc_packet *packet = (struct hv_netvsc_packet *)context; @@ -131,22 +161,164 @@ static void netvsc_xmit_completion(void *context) dev_kfree_skb_any(skb); } +static u32 fill_pg_buf(struct page *page, u32 offset, u32 len, + struct hv_page_buffer *pb) +{ + int j = 0; + + /* Deal with compund pages by ignoring unused part + * of the page. + */ + page += (offset >> PAGE_SHIFT); + offset &= ~PAGE_MASK; + + while (len > 0) { + unsigned long bytes; + + bytes = PAGE_SIZE - offset; + if (bytes > len) + bytes = len; + pb[j].pfn = page_to_pfn(page); + pb[j].offset = offset; + pb[j].len = bytes; + + offset += bytes; + len -= bytes; + + if (offset == PAGE_SIZE && len) { + page++; + offset = 0; + j++; + } + } + + return j + 1; +} + +static u32 init_page_array(void *hdr, u32 len, struct sk_buff *skb, + struct hv_page_buffer *pb) +{ + u32 slots_used = 0; + char *data = skb->data; + int frags = skb_shinfo(skb)->nr_frags; + int i; + + /* The packet is laid out thus: + * 1. hdr + * 2. skb linear data + * 3. skb fragment data + */ + if (hdr != NULL) + slots_used += fill_pg_buf(virt_to_page(hdr), + offset_in_page(hdr), + len, &pb[slots_used]); + + slots_used += fill_pg_buf(virt_to_page(data), + offset_in_page(data), + skb_headlen(skb), &pb[slots_used]); + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + + slots_used += fill_pg_buf(skb_frag_page(frag), + frag->page_offset, + skb_frag_size(frag), &pb[slots_used]); + } + return slots_used; +} + +static int count_skb_frag_slots(struct sk_buff *skb) +{ + int i, frags = skb_shinfo(skb)->nr_frags; + int pages = 0; + + for (i = 0; i < frags; i++) { + skb_frag_t *frag = skb_shinfo(skb)->frags + i; + unsigned long size = skb_frag_size(frag); + unsigned long offset = frag->page_offset; + + /* Skip unused frames from start of page */ + offset &= ~PAGE_MASK; + pages += PFN_UP(offset + size); + } + return pages; +} + +static int netvsc_get_slots(struct sk_buff *skb) +{ + char *data = skb->data; + unsigned int offset = offset_in_page(data); + unsigned int len = skb_headlen(skb); + int slots; + int frag_slots; + + slots = DIV_ROUND_UP(offset + len, PAGE_SIZE); + frag_slots = count_skb_frag_slots(skb); + return slots + frag_slots; +} + +static u32 get_net_transport_info(struct sk_buff *skb, u32 *trans_off) +{ + u32 ret_val = TRANSPORT_INFO_NOT_IP; + + if ((eth_hdr(skb)->h_proto != htons(ETH_P_IP)) && + (eth_hdr(skb)->h_proto != htons(ETH_P_IPV6))) { + goto not_ip; + } + + *trans_off = skb_transport_offset(skb); + + if ((eth_hdr(skb)->h_proto == htons(ETH_P_IP))) { + struct iphdr *iphdr = ip_hdr(skb); + + if (iphdr->protocol == IPPROTO_TCP) + ret_val = TRANSPORT_INFO_IPV4_TCP; + else if (iphdr->protocol == IPPROTO_UDP) + ret_val = TRANSPORT_INFO_IPV4_UDP; + } else { + if (ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) + ret_val = TRANSPORT_INFO_IPV6_TCP; + else if (ipv6_hdr(skb)->nexthdr == IPPROTO_UDP) + ret_val = TRANSPORT_INFO_IPV6_UDP; + } + +not_ip: + return ret_val; +} + static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_netvsc_packet *packet; int ret; - unsigned int i, num_pages, npg_data; - - /* Add multipages for skb->data and additional 2 for RNDIS */ - npg_data = (((unsigned long)skb->data + skb_headlen(skb) - 1) - >> PAGE_SHIFT) - ((unsigned long)skb->data >> PAGE_SHIFT) + 1; - num_pages = skb_shinfo(skb)->nr_frags + npg_data + 2; + unsigned int num_data_pgs; + struct rndis_message *rndis_msg; + struct rndis_packet *rndis_pkt; + u32 rndis_msg_size; + bool isvlan; + struct rndis_per_packet_info *ppi; + struct ndis_tcp_ip_checksum_info *csum_info; + struct ndis_tcp_lso_info *lso_info; + int hdr_offset; + u32 net_trans_info; + + + /* We will atmost need two pages to describe the rndis + * header. We can only transmit MAX_PAGE_BUFFER_COUNT number + * of pages in a single packet. + */ + num_data_pgs = netvsc_get_slots(skb) + 2; + if (num_data_pgs > MAX_PAGE_BUFFER_COUNT) { + netdev_err(net, "Packet too big: %u\n", skb->len); + dev_kfree_skb(skb); + net->stats.tx_dropped++; + return NETDEV_TX_OK; + } /* Allocate a netvsc packet based on # of frags. */ packet = kzalloc(sizeof(struct hv_netvsc_packet) + - (num_pages * sizeof(struct hv_page_buffer)) + - sizeof(struct rndis_filter_packet) + + (num_data_pgs * sizeof(struct hv_page_buffer)) + + sizeof(struct rndis_message) + NDIS_VLAN_PPI_SIZE, GFP_ATOMIC); if (!packet) { /* out of memory, drop packet */ @@ -159,53 +331,111 @@ static int netvsc_start_xmit(struct sk_buff *skb, struct net_device *net) packet->vlan_tci = skb->vlan_tci; - packet->extension = (void *)(unsigned long)packet + + packet->is_data_pkt = true; + packet->total_data_buflen = skb->len; + + packet->rndis_msg = (struct rndis_message *)((unsigned long)packet + sizeof(struct hv_netvsc_packet) + - (num_pages * sizeof(struct hv_page_buffer)); + (num_data_pgs * sizeof(struct hv_page_buffer))); - /* If the rndis msg goes beyond 1 page, we will add 1 later */ - packet->page_buf_cnt = num_pages - 1; + /* Set the completion routine */ + packet->completion.send.send_completion = netvsc_xmit_completion; + packet->completion.send.send_completion_ctx = packet; + packet->completion.send.send_completion_tid = (unsigned long)skb; - /* Initialize it from the skb */ - packet->total_data_buflen = skb->len; + isvlan = packet->vlan_tci & VLAN_TAG_PRESENT; + + /* Add the rndis header */ + rndis_msg = packet->rndis_msg; + rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; + rndis_msg->msg_len = packet->total_data_buflen; + rndis_pkt = &rndis_msg->msg.pkt; + rndis_pkt->data_offset = sizeof(struct rndis_packet); + rndis_pkt->data_len = packet->total_data_buflen; + rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); + + rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); + + if (isvlan) { + struct ndis_pkt_8021q_info *vlan; + + rndis_msg_size += NDIS_VLAN_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_VLAN_PPI_SIZE, + IEEE_8021Q_INFO); + vlan = (struct ndis_pkt_8021q_info *)((void *)ppi + + ppi->ppi_offset); + vlan->vlanid = packet->vlan_tci & VLAN_VID_MASK; + vlan->pri = (packet->vlan_tci & VLAN_PRIO_MASK) >> + VLAN_PRIO_SHIFT; + } + + net_trans_info = get_net_transport_info(skb, &hdr_offset); + if (net_trans_info == TRANSPORT_INFO_NOT_IP) + goto do_send; + + /* + * Setup the sendside checksum offload only if this is not a + * GSO packet. + */ + if (skb_is_gso(skb)) + goto do_lso; - /* Start filling in the page buffers starting after RNDIS buffer. */ - packet->page_buf[1].pfn = virt_to_phys(skb->data) >> PAGE_SHIFT; - packet->page_buf[1].offset - = (unsigned long)skb->data & (PAGE_SIZE - 1); - if (npg_data == 1) - packet->page_buf[1].len = skb_headlen(skb); + rndis_msg_size += NDIS_CSUM_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_CSUM_PPI_SIZE, + TCPIP_CHKSUM_PKTINFO); + + csum_info = (struct ndis_tcp_ip_checksum_info *)((void *)ppi + + ppi->ppi_offset); + + if (net_trans_info & (INFO_IPV4 << 16)) + csum_info->transmit.is_ipv4 = 1; else - packet->page_buf[1].len = PAGE_SIZE - - packet->page_buf[1].offset; - - for (i = 2; i <= npg_data; i++) { - packet->page_buf[i].pfn = virt_to_phys(skb->data - + PAGE_SIZE * (i-1)) >> PAGE_SHIFT; - packet->page_buf[i].offset = 0; - packet->page_buf[i].len = PAGE_SIZE; + csum_info->transmit.is_ipv6 = 1; + + if (net_trans_info & INFO_TCP) { + csum_info->transmit.tcp_checksum = 1; + csum_info->transmit.tcp_header_offset = hdr_offset; + } else if (net_trans_info & INFO_UDP) { + csum_info->transmit.udp_checksum = 1; } - if (npg_data > 1) - packet->page_buf[npg_data].len = (((unsigned long)skb->data - + skb_headlen(skb) - 1) & (PAGE_SIZE - 1)) + 1; - - /* Additional fragments are after SKB data */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - const skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - - packet->page_buf[i+npg_data+1].pfn = - page_to_pfn(skb_frag_page(f)); - packet->page_buf[i+npg_data+1].offset = f->page_offset; - packet->page_buf[i+npg_data+1].len = skb_frag_size(f); + goto do_send; + +do_lso: + rndis_msg_size += NDIS_LSO_PPI_SIZE; + ppi = init_ppi_data(rndis_msg, NDIS_LSO_PPI_SIZE, + TCP_LARGESEND_PKTINFO); + + lso_info = (struct ndis_tcp_lso_info *)((void *)ppi + + ppi->ppi_offset); + + lso_info->lso_v2_transmit.type = NDIS_TCP_LARGE_SEND_OFFLOAD_V2_TYPE; + if (net_trans_info & (INFO_IPV4 << 16)) { + lso_info->lso_v2_transmit.ip_version = + NDIS_TCP_LARGE_SEND_OFFLOAD_IPV4; + ip_hdr(skb)->tot_len = 0; + ip_hdr(skb)->check = 0; + tcp_hdr(skb)->check = + ~csum_tcpudp_magic(ip_hdr(skb)->saddr, + ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); + } else { + lso_info->lso_v2_transmit.ip_version = + NDIS_TCP_LARGE_SEND_OFFLOAD_IPV6; + ipv6_hdr(skb)->payload_len = 0; + tcp_hdr(skb)->check = + ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, + &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } + lso_info->lso_v2_transmit.tcp_header_offset = hdr_offset; + lso_info->lso_v2_transmit.mss = skb_shinfo(skb)->gso_size; - /* Set the completion routine */ - packet->completion.send.send_completion = netvsc_xmit_completion; - packet->completion.send.send_completion_ctx = packet; - packet->completion.send.send_completion_tid = (unsigned long)skb; +do_send: + /* Start filling in the page buffers with the rndis hdr */ + rndis_msg->msg_len += rndis_msg_size; + packet->page_buf_cnt = init_page_array(rndis_msg, rndis_msg_size, + skb, &packet->page_buf[0]); + + ret = netvsc_send(net_device_ctx->device_ctx, packet); - ret = rndis_filter_send(net_device_ctx->device_ctx, - packet); if (ret == 0) { net->stats.tx_bytes += skb->len; net->stats.tx_packets++; @@ -229,23 +459,24 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, struct net_device *net; struct net_device_context *ndev_ctx; struct netvsc_device *net_device; + struct rndis_device *rdev; net_device = hv_get_drvdata(device_obj); + rdev = net_device->extension; + + rdev->link_state = status != 1; + net = net_device->ndev; - if (!net) { - netdev_err(net, "got link status but net device " - "not initialized yet\n"); + if (!net || net->reg_state != NETREG_REGISTERED) return; - } + ndev_ctx = netdev_priv(net); if (status == 1) { - netif_carrier_on(net); - ndev_ctx = netdev_priv(net); schedule_delayed_work(&ndev_ctx->dwork, 0); schedule_delayed_work(&ndev_ctx->dwork, msecs_to_jiffies(20)); } else { - netif_carrier_off(net); + schedule_delayed_work(&ndev_ctx->dwork, 0); } } @@ -254,7 +485,8 @@ void netvsc_linkstatus_callback(struct hv_device *device_obj, * "wire" on the specified device. */ int netvsc_recv_callback(struct hv_device *device_obj, - struct hv_netvsc_packet *packet) + struct hv_netvsc_packet *packet, + struct ndis_tcp_ip_checksum_info *csum_info) { struct net_device *net; struct sk_buff *skb; @@ -281,7 +513,17 @@ int netvsc_recv_callback(struct hv_device *device_obj, packet->total_data_buflen); skb->protocol = eth_type_trans(skb, net); - skb->ip_summed = CHECKSUM_NONE; + if (csum_info) { + /* We only look at the IP checksum here. + * Should we be dropping the packet if checksum + * failed? How do we deal with other checksums - TCP/UDP? + */ + if (csum_info->receive.ip_checksum_succeeded) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } + if (packet->vlan_tci & VLAN_TAG_PRESENT) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), packet->vlan_tci); @@ -317,7 +559,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) if (nvdev == NULL || nvdev->destroy) return -ENODEV; - if (nvdev->nvsp_version == NVSP_PROTOCOL_VERSION_2) + if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) limit = NETVSC_MTU; if (mtu < 68 || mtu > limit) @@ -388,17 +630,35 @@ static const struct net_device_ops device_ops = { * current context when receiving RNDIS_STATUS_MEDIA_CONNECT event. So, add * another netif_notify_peers() into a delayed work, otherwise GARP packet * will not be sent after quick migration, and cause network disconnection. + * Also, we update the carrier status here. */ -static void netvsc_send_garp(struct work_struct *w) +static void netvsc_link_change(struct work_struct *w) { struct net_device_context *ndev_ctx; struct net_device *net; struct netvsc_device *net_device; + struct rndis_device *rdev; + bool notify; + + rtnl_lock(); ndev_ctx = container_of(w, struct net_device_context, dwork.work); net_device = hv_get_drvdata(ndev_ctx->device_ctx); + rdev = net_device->extension; net = net_device->ndev; - netdev_notify_peers(net); + + if (rdev->link_state) { + netif_carrier_off(net); + notify = false; + } else { + netif_carrier_on(net); + notify = true; + } + + rtnl_unlock(); + + if (notify) + netdev_notify_peers(net); } @@ -414,20 +674,18 @@ static int netvsc_probe(struct hv_device *dev, if (!net) return -ENOMEM; - /* Set initial state */ - netif_carrier_off(net); - net_device_ctx = netdev_priv(net); net_device_ctx->device_ctx = dev; hv_set_drvdata(dev, net); - INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_send_garp); + INIT_DELAYED_WORK(&net_device_ctx->dwork, netvsc_link_change); INIT_WORK(&net_device_ctx->work, do_set_multicast); net->netdev_ops = &device_ops; - /* TODO: Add GSO and Checksum offload */ - net->hw_features = 0; - net->features = NETIF_F_HW_VLAN_CTAG_TX; + net->hw_features = NETIF_F_RXCSUM | NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO; + net->features = NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_SG | NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | NETIF_F_TSO; SET_ETHTOOL_OPS(net, ðtool_ops); SET_NETDEV_DEV(net, &dev->device); @@ -443,8 +701,6 @@ static int netvsc_probe(struct hv_device *dev, } memcpy(net->dev_addr, device_info.mac_adr, ETH_ALEN); - netif_carrier_on(net); - ret = register_netdev(net); if (ret != 0) { pr_err("Unable to register netdev.\n"); diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 1084e5de3ceb..54553df74cd2 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -58,9 +58,6 @@ struct rndis_request { u8 request_ext[RNDIS_EXT_LEN]; }; -static void rndis_filter_send_completion(void *ctx); - - static struct rndis_device *get_rndis_device(void) { struct rndis_device *device; @@ -277,7 +274,7 @@ static void rndis_filter_receive_response(struct rndis_device *dev, "rndis response buffer overflow " "detected (size %u max %zu)\n", resp->msg_len, - sizeof(struct rndis_filter_packet)); + sizeof(struct rndis_message)); if (resp->ndis_msg_type == RNDIS_MSG_RESET_C) { @@ -353,6 +350,7 @@ static void rndis_filter_receive_data(struct rndis_device *dev, struct rndis_packet *rndis_pkt; u32 data_offset; struct ndis_pkt_8021q_info *vlan; + struct ndis_tcp_ip_checksum_info *csum_info; rndis_pkt = &msg->msg.pkt; @@ -391,7 +389,8 @@ static void rndis_filter_receive_data(struct rndis_device *dev, pkt->vlan_tci = 0; } - netvsc_recv_callback(dev->net_dev->dev, pkt); + csum_info = rndis_get_ppi(rndis_pkt, TCPIP_CHKSUM_PKTINFO); + netvsc_recv_callback(dev->net_dev->dev, pkt, csum_info); } int rndis_filter_receive(struct hv_device *dev, @@ -610,6 +609,61 @@ cleanup: return ret; } +int rndis_filter_set_offload_params(struct hv_device *hdev, + struct ndis_offload_params *req_offloads) +{ + struct netvsc_device *nvdev = hv_get_drvdata(hdev); + struct rndis_device *rdev = nvdev->extension; + struct net_device *ndev = nvdev->ndev; + struct rndis_request *request; + struct rndis_set_request *set; + struct ndis_offload_params *offload_params; + struct rndis_set_complete *set_complete; + u32 extlen = sizeof(struct ndis_offload_params); + int ret, t; + + request = get_rndis_request(rdev, RNDIS_MSG_SET, + RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen); + if (!request) + return -ENOMEM; + + set = &request->request_msg.msg.set_req; + set->oid = OID_TCP_OFFLOAD_PARAMETERS; + set->info_buflen = extlen; + set->info_buf_offset = sizeof(struct rndis_set_request); + set->dev_vc_handle = 0; + + offload_params = (struct ndis_offload_params *)((ulong)set + + set->info_buf_offset); + *offload_params = *req_offloads; + offload_params->header.type = NDIS_OBJECT_TYPE_DEFAULT; + offload_params->header.revision = NDIS_OFFLOAD_PARAMETERS_REVISION_3; + offload_params->header.size = extlen; + + ret = rndis_filter_send_request(rdev, request); + if (ret != 0) + goto cleanup; + + t = wait_for_completion_timeout(&request->wait_event, 5*HZ); + if (t == 0) { + netdev_err(ndev, "timeout before we got aOFFLOAD set response...\n"); + /* can't put_rndis_request, since we may still receive a + * send-completion. + */ + return -EBUSY; + } else { + set_complete = &request->response_msg.msg.set_complete; + if (set_complete->status != RNDIS_STATUS_SUCCESS) { + netdev_err(ndev, "Fail to set MAC on host side:0x%x\n", + set_complete->status); + ret = -EINVAL; + } + } + +cleanup: + put_rndis_request(rdev, request); + return ret; +} static int rndis_filter_query_device_link_status(struct rndis_device *dev) { @@ -810,6 +864,7 @@ int rndis_filter_device_add(struct hv_device *dev, struct netvsc_device *net_device; struct rndis_device *rndis_device; struct netvsc_device_info *device_info = additional_info; + struct ndis_offload_params offloads; rndis_device = get_rndis_device(); if (!rndis_device) @@ -849,6 +904,26 @@ int rndis_filter_device_add(struct hv_device *dev, memcpy(device_info->mac_adr, rndis_device->hw_mac_adr, ETH_ALEN); + /* Turn on the offloads; the host supports all of the relevant + * offloads. + */ + memset(&offloads, 0, sizeof(struct ndis_offload_params)); + /* A value of zero means "no change"; now turn on what we + * want. + */ + offloads.ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.tcp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.udp_ip_v4_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.tcp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.udp_ip_v6_csum = NDIS_OFFLOAD_PARAMETERS_TX_RX_ENABLED; + offloads.lso_v2_ipv4 = NDIS_OFFLOAD_PARAMETERS_LSOV2_ENABLED; + + + ret = rndis_filter_set_offload_params(dev, &offloads); + if (ret) + goto err_dev_remv; + + rndis_filter_query_device_link_status(rndis_device); device_info->link_state = rndis_device->link_state; @@ -858,6 +933,10 @@ int rndis_filter_device_add(struct hv_device *dev, device_info->link_state ? "down" : "up"); return ret; + +err_dev_remv: + rndis_filter_device_remove(dev); + return ret; } void rndis_filter_device_remove(struct hv_device *dev) @@ -894,101 +973,3 @@ int rndis_filter_close(struct hv_device *dev) return rndis_filter_close_device(nvdev->extension); } - -int rndis_filter_send(struct hv_device *dev, - struct hv_netvsc_packet *pkt) -{ - int ret; - struct rndis_filter_packet *filter_pkt; - struct rndis_message *rndis_msg; - struct rndis_packet *rndis_pkt; - u32 rndis_msg_size; - bool isvlan = pkt->vlan_tci & VLAN_TAG_PRESENT; - - /* Add the rndis header */ - filter_pkt = (struct rndis_filter_packet *)pkt->extension; - - rndis_msg = &filter_pkt->msg; - rndis_msg_size = RNDIS_MESSAGE_SIZE(struct rndis_packet); - if (isvlan) - rndis_msg_size += NDIS_VLAN_PPI_SIZE; - - rndis_msg->ndis_msg_type = RNDIS_MSG_PACKET; - rndis_msg->msg_len = pkt->total_data_buflen + - rndis_msg_size; - - rndis_pkt = &rndis_msg->msg.pkt; - rndis_pkt->data_offset = sizeof(struct rndis_packet); - if (isvlan) - rndis_pkt->data_offset += NDIS_VLAN_PPI_SIZE; - rndis_pkt->data_len = pkt->total_data_buflen; - - if (isvlan) { - struct rndis_per_packet_info *ppi; - struct ndis_pkt_8021q_info *vlan; - - rndis_pkt->per_pkt_info_offset = sizeof(struct rndis_packet); - rndis_pkt->per_pkt_info_len = NDIS_VLAN_PPI_SIZE; - - ppi = (struct rndis_per_packet_info *)((ulong)rndis_pkt + - rndis_pkt->per_pkt_info_offset); - ppi->size = NDIS_VLAN_PPI_SIZE; - ppi->type = IEEE_8021Q_INFO; - ppi->ppi_offset = sizeof(struct rndis_per_packet_info); - - vlan = (struct ndis_pkt_8021q_info *)((ulong)ppi + - ppi->ppi_offset); - vlan->vlanid = pkt->vlan_tci & VLAN_VID_MASK; - vlan->pri = (pkt->vlan_tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; - } - - pkt->is_data_pkt = true; - pkt->page_buf[0].pfn = virt_to_phys(rndis_msg) >> PAGE_SHIFT; - pkt->page_buf[0].offset = - (unsigned long)rndis_msg & (PAGE_SIZE-1); - pkt->page_buf[0].len = rndis_msg_size; - - /* Add one page_buf if the rndis msg goes beyond page boundary */ - if (pkt->page_buf[0].offset + rndis_msg_size > PAGE_SIZE) { - int i; - for (i = pkt->page_buf_cnt; i > 1; i--) - pkt->page_buf[i] = pkt->page_buf[i-1]; - pkt->page_buf_cnt++; - pkt->page_buf[0].len = PAGE_SIZE - pkt->page_buf[0].offset; - pkt->page_buf[1].pfn = virt_to_phys((void *)((ulong) - rndis_msg + pkt->page_buf[0].len)) >> PAGE_SHIFT; - pkt->page_buf[1].offset = 0; - pkt->page_buf[1].len = rndis_msg_size - pkt->page_buf[0].len; - } - - /* Save the packet send completion and context */ - filter_pkt->completion = pkt->completion.send.send_completion; - filter_pkt->completion_ctx = - pkt->completion.send.send_completion_ctx; - - /* Use ours */ - pkt->completion.send.send_completion = rndis_filter_send_completion; - pkt->completion.send.send_completion_ctx = filter_pkt; - - ret = netvsc_send(dev, pkt); - if (ret != 0) { - /* - * Reset the completion to originals to allow retries from - * above - */ - pkt->completion.send.send_completion = - filter_pkt->completion; - pkt->completion.send.send_completion_ctx = - filter_pkt->completion_ctx; - } - - return ret; -} - -static void rndis_filter_send_completion(void *ctx) -{ - struct rndis_filter_packet *filter_pkt = ctx; - - /* Pass it back to the original handler */ - filter_pkt->completion(filter_pkt->completion_ctx); -} diff --git a/drivers/net/ieee802154/Kconfig b/drivers/net/ieee802154/Kconfig index 08ae4655423a..3e89beab64fd 100644 --- a/drivers/net/ieee802154/Kconfig +++ b/drivers/net/ieee802154/Kconfig @@ -15,9 +15,9 @@ config IEEE802154_FAKEHARD depends on IEEE802154_DRIVERS ---help--- Say Y here to enable the fake driver that serves as an example - of HardMAC device driver. + of HardMAC device driver. - This driver can also be built as a module. To do so say M here. + This driver can also be built as a module. To do so say M here. The module will be called 'fakehard'. config IEEE802154_FAKELB @@ -31,17 +31,23 @@ config IEEE802154_FAKELB The module will be called 'fakelb'. config IEEE802154_AT86RF230 - depends on IEEE802154_DRIVERS && MAC802154 - tristate "AT86RF230/231 transceiver driver" - depends on SPI + depends on IEEE802154_DRIVERS && MAC802154 + tristate "AT86RF230/231/233/212 transceiver driver" + depends on SPI + ---help--- + Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless + controller. + + This driver can also be built as a module. To do so, say M here. + the module will be called 'at86rf230'. config IEEE802154_MRF24J40 - tristate "Microchip MRF24J40 transceiver driver" - depends on IEEE802154_DRIVERS && MAC802154 - depends on SPI - ---help--- - Say Y here to enable the MRF24J20 SPI 802.15.4 wireless - controller. - - This driver can also be built as a module. To do so, say M here. - the module will be called 'mrf24j40'. + tristate "Microchip MRF24J40 transceiver driver" + depends on IEEE802154_DRIVERS && MAC802154 + depends on SPI + ---help--- + Say Y here to enable the MRF24J20 SPI 802.15.4 wireless + controller. + + This driver can also be built as a module. To do so, say M here. + the module will be called 'mrf24j40'. diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index ab31544bc254..b8e732121a85 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -37,7 +37,6 @@ struct at86rf230_local { struct spi_device *spi; - int rstn, slp_tr, dig2; u8 part; u8 vers; @@ -53,8 +52,16 @@ struct at86rf230_local { spinlock_t lock; bool irq_busy; bool is_tx; + bool tx_aret; + + int rssi_base_val; }; +static bool is_rf212(struct at86rf230_local *local) +{ + return local->part == 7; +} + #define RG_TRX_STATUS (0x01) #define SR_TRX_STATUS 0x01, 0x1f, 0 #define SR_RESERVED_01_3 0x01, 0x20, 5 @@ -100,7 +107,10 @@ struct at86rf230_local { #define SR_SFD_VALUE 0x0b, 0xff, 0 #define RG_TRX_CTRL_2 (0x0c) #define SR_OQPSK_DATA_RATE 0x0c, 0x03, 0 -#define SR_RESERVED_0c_2 0x0c, 0x7c, 2 +#define SR_SUB_MODE 0x0c, 0x04, 2 +#define SR_BPSK_QPSK 0x0c, 0x08, 3 +#define SR_OQPSK_SUB1_RC_EN 0x0c, 0x10, 4 +#define SR_RESERVED_0c_5 0x0c, 0x60, 5 #define SR_RX_SAFE_MODE 0x0c, 0x80, 7 #define RG_ANT_DIV (0x0d) #define SR_ANT_CTRL 0x0d, 0x03, 0 @@ -145,7 +155,7 @@ struct at86rf230_local { #define SR_RESERVED_17_5 0x17, 0x08, 3 #define SR_AACK_UPLD_RES_FT 0x17, 0x10, 4 #define SR_AACK_FLTR_RES_FT 0x17, 0x20, 5 -#define SR_RESERVED_17_2 0x17, 0x40, 6 +#define SR_CSMA_LBT_MODE 0x17, 0x40, 6 #define SR_RESERVED_17_1 0x17, 0x80, 7 #define RG_FTN_CTRL (0x18) #define SR_RESERVED_18_2 0x18, 0x7f, 0 @@ -234,6 +244,7 @@ struct at86rf230_local { #define STATE_TX_ON 0x09 /* 0x0a - 0x0e */ /* 0x0a - UNSUPPORTED_ATTRIBUTE */ #define STATE_SLEEP 0x0F +#define STATE_PREP_DEEP_SLEEP 0x10 #define STATE_BUSY_RX_AACK 0x11 #define STATE_BUSY_TX_ARET 0x12 #define STATE_RX_AACK_ON 0x16 @@ -244,6 +255,57 @@ struct at86rf230_local { #define STATE_TRANSITION_IN_PROGRESS 0x1F static int +__at86rf230_detect_device(struct spi_device *spi, u16 *man_id, u8 *part, + u8 *version) +{ + u8 data[4]; + u8 *buf = kmalloc(2, GFP_KERNEL); + int status; + struct spi_message msg; + struct spi_transfer xfer = { + .len = 2, + .tx_buf = buf, + .rx_buf = buf, + }; + u8 reg; + + if (!buf) + return -ENOMEM; + + for (reg = RG_PART_NUM; reg <= RG_MAN_ID_1; reg++) { + buf[0] = (reg & CMD_REG_MASK) | CMD_REG; + buf[1] = 0xff; + dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]); + spi_message_init(&msg); + spi_message_add_tail(&xfer, &msg); + + status = spi_sync(spi, &msg); + dev_vdbg(&spi->dev, "status = %d\n", status); + if (msg.status) + status = msg.status; + + dev_vdbg(&spi->dev, "status = %d\n", status); + dev_vdbg(&spi->dev, "buf[0] = %02x\n", buf[0]); + dev_vdbg(&spi->dev, "buf[1] = %02x\n", buf[1]); + + if (status == 0) + data[reg - RG_PART_NUM] = buf[1]; + else + break; + } + + if (status == 0) { + *part = data[0]; + *version = data[1]; + *man_id = (data[3] << 8) | data[2]; + } + + kfree(buf); + + return status; +} + +static int __at86rf230_write(struct at86rf230_local *lp, u8 addr, u8 data) { u8 *buf = lp->buf; @@ -489,7 +551,9 @@ at86rf230_state(struct ieee802154_dev *dev, int state) } while (val == STATE_TRANSITION_IN_PROGRESS); - if (val == desired_status) + if (val == desired_status || + (desired_status == STATE_RX_ON && val == STATE_BUSY_RX) || + (desired_status == STATE_RX_AACK_ON && val == STATE_BUSY_RX_AACK)) return 0; pr_err("unexpected state change: %d, asked for %d\n", val, state); @@ -510,7 +574,11 @@ at86rf230_start(struct ieee802154_dev *dev) if (rc) return rc; - return at86rf230_state(dev, STATE_RX_ON); + rc = at86rf230_state(dev, STATE_FORCE_TX_ON); + if (rc) + return rc; + + return at86rf230_state(dev, STATE_RX_AACK_ON); } static void @@ -520,6 +588,39 @@ at86rf230_stop(struct ieee802154_dev *dev) } static int +at86rf230_set_channel(struct at86rf230_local *lp, int page, int channel) +{ + lp->rssi_base_val = -91; + + return at86rf230_write_subreg(lp, SR_CHANNEL, channel); +} + +static int +at86rf212_set_channel(struct at86rf230_local *lp, int page, int channel) +{ + int rc; + + if (channel == 0) + rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 0); + else + rc = at86rf230_write_subreg(lp, SR_SUB_MODE, 1); + if (rc < 0) + return rc; + + if (page == 0) { + rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 0); + lp->rssi_base_val = -100; + } else { + rc = at86rf230_write_subreg(lp, SR_BPSK_QPSK, 1); + lp->rssi_base_val = -98; + } + if (rc < 0) + return rc; + + return at86rf230_write_subreg(lp, SR_CHANNEL, channel); +} + +static int at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) { struct at86rf230_local *lp = dev->priv; @@ -527,14 +628,22 @@ at86rf230_channel(struct ieee802154_dev *dev, int page, int channel) might_sleep(); - if (page != 0 || channel < 11 || channel > 26) { + if (page < 0 || page > 31 || + !(lp->dev->phy->channels_supported[page] & BIT(channel))) { WARN_ON(1); return -EINVAL; } - rc = at86rf230_write_subreg(lp, SR_CHANNEL, channel); + if (is_rf212(lp)) + rc = at86rf212_set_channel(lp, page, channel); + else + rc = at86rf230_set_channel(lp, page, channel); + if (rc < 0) + return rc; + msleep(1); /* Wait for PLL */ dev->phy->current_channel = channel; + dev->phy->current_page = page; return 0; } @@ -568,6 +677,12 @@ at86rf230_xmit(struct ieee802154_dev *dev, struct sk_buff *skb) if (rc) goto err_rx; + if (lp->tx_aret) { + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ARET_ON); + if (rc) + goto err_rx; + } + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_BUSY_TX); if (rc) goto err_rx; @@ -668,6 +783,93 @@ at86rf230_set_hw_addr_filt(struct ieee802154_dev *dev, return 0; } +static int +at86rf212_set_txpower(struct ieee802154_dev *dev, int db) +{ + struct at86rf230_local *lp = dev->priv; + + /* typical maximum output is 5dBm with RG_PHY_TX_PWR 0x60, lower five + * bits decrease power in 1dB steps. 0x60 represents extra PA gain of + * 0dB. + * thus, supported values for db range from -26 to 5, for 31dB of + * reduction to 0dB of reduction. + */ + if (db > 5 || db < -26) + return -EINVAL; + + db = -(db - 5); + + return __at86rf230_write(lp, RG_PHY_TX_PWR, 0x60 | db); +} + +static int +at86rf212_set_lbt(struct ieee802154_dev *dev, bool on) +{ + struct at86rf230_local *lp = dev->priv; + + return at86rf230_write_subreg(lp, SR_CSMA_LBT_MODE, on); +} + +static int +at86rf212_set_cca_mode(struct ieee802154_dev *dev, u8 mode) +{ + struct at86rf230_local *lp = dev->priv; + + return at86rf230_write_subreg(lp, SR_CCA_MODE, mode); +} + +static int +at86rf212_set_cca_ed_level(struct ieee802154_dev *dev, s32 level) +{ + struct at86rf230_local *lp = dev->priv; + int desens_steps; + + if (level < lp->rssi_base_val || level > 30) + return -EINVAL; + + desens_steps = (level - lp->rssi_base_val) * 100 / 207; + + return at86rf230_write_subreg(lp, SR_CCA_ED_THRES, desens_steps); +} + +static int +at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be, + u8 retries) +{ + struct at86rf230_local *lp = dev->priv; + int rc; + + if (min_be > max_be || max_be > 8 || retries > 5) + return -EINVAL; + + rc = at86rf230_write_subreg(lp, SR_MIN_BE, min_be); + if (rc) + return rc; + + rc = at86rf230_write_subreg(lp, SR_MAX_BE, max_be); + if (rc) + return rc; + + return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, max_be); +} + +static int +at86rf212_set_frame_retries(struct ieee802154_dev *dev, s8 retries) +{ + struct at86rf230_local *lp = dev->priv; + int rc = 0; + + if (retries < -1 || retries > 15) + return -EINVAL; + + lp->tx_aret = retries >= 0; + + if (retries >= 0) + rc = at86rf230_write_subreg(lp, SR_MAX_FRAME_RETRIES, retries); + + return rc; +} + static struct ieee802154_ops at86rf230_ops = { .owner = THIS_MODULE, .xmit = at86rf230_xmit, @@ -678,6 +880,22 @@ static struct ieee802154_ops at86rf230_ops = { .set_hw_addr_filt = at86rf230_set_hw_addr_filt, }; +static struct ieee802154_ops at86rf212_ops = { + .owner = THIS_MODULE, + .xmit = at86rf230_xmit, + .ed = at86rf230_ed, + .set_channel = at86rf230_channel, + .start = at86rf230_start, + .stop = at86rf230_stop, + .set_hw_addr_filt = at86rf230_set_hw_addr_filt, + .set_txpower = at86rf212_set_txpower, + .set_lbt = at86rf212_set_lbt, + .set_cca_mode = at86rf212_set_cca_mode, + .set_cca_ed_level = at86rf212_set_cca_ed_level, + .set_csma_params = at86rf212_set_csma_params, + .set_frame_retries = at86rf212_set_frame_retries, +}; + static void at86rf230_irqwork(struct work_struct *work) { struct at86rf230_local *lp = @@ -752,22 +970,15 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) struct at86rf230_platform_data *pdata = lp->spi->dev.platform_data; int rc, irq_pol; u8 status; + u8 csma_seed[2]; rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); if (rc) return rc; - dev_info(&lp->spi->dev, "Status: %02x\n", status); - if (status == STATE_P_ON) { - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TRX_OFF); - if (rc) - return rc; - msleep(1); - rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); - if (rc) - return rc; - dev_info(&lp->spi->dev, "Status: %02x\n", status); - } + rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_FORCE_TRX_OFF); + if (rc) + return rc; /* configure irq polarity, defaults to high active */ if (pdata->irq_type & (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW)) @@ -783,6 +994,14 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) if (rc) return rc; + get_random_bytes(csma_seed, ARRAY_SIZE(csma_seed)); + rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_0, csma_seed[0]); + if (rc) + return rc; + rc = at86rf230_write_subreg(lp, SR_CSMA_SEED_1, csma_seed[1]); + if (rc) + return rc; + /* CLKM changes are applied immediately */ rc = at86rf230_write_subreg(lp, SR_CLKM_SHA_SEL, 0x00); if (rc) @@ -795,16 +1014,6 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) /* Wait the next SLEEP cycle */ msleep(100); - rc = at86rf230_write_subreg(lp, SR_TRX_CMD, STATE_TX_ON); - if (rc) - return rc; - msleep(1); - - rc = at86rf230_read_subreg(lp, SR_TRX_STATUS, &status); - if (rc) - return rc; - dev_info(&lp->spi->dev, "Status: %02x\n", status); - rc = at86rf230_read_subreg(lp, SR_DVDD_OK, &status); if (rc) return rc; @@ -824,26 +1033,18 @@ static int at86rf230_hw_init(struct at86rf230_local *lp) return 0; } -static void at86rf230_fill_data(struct spi_device *spi) -{ - struct at86rf230_local *lp = spi_get_drvdata(spi); - struct at86rf230_platform_data *pdata = spi->dev.platform_data; - - lp->rstn = pdata->rstn; - lp->slp_tr = pdata->slp_tr; - lp->dig2 = pdata->dig2; -} - static int at86rf230_probe(struct spi_device *spi) { struct at86rf230_platform_data *pdata; struct ieee802154_dev *dev; struct at86rf230_local *lp; - u8 man_id_0, man_id_1, status; + u16 man_id = 0; + u8 part = 0, version = 0, status; irq_handler_t irq_handler; work_func_t irq_worker; - int rc, supported = 0; + int rc; const char *chip; + struct ieee802154_ops *ops = NULL; if (!spi->irq) { dev_err(&spi->dev, "no IRQ specified\n"); @@ -856,116 +1057,121 @@ static int at86rf230_probe(struct spi_device *spi) return -EINVAL; } - dev = ieee802154_alloc_device(sizeof(*lp), &at86rf230_ops); - if (!dev) - return -ENOMEM; - - lp = dev->priv; - lp->dev = dev; - - lp->spi = spi; - - dev->parent = &spi->dev; - dev->extra_tx_headroom = 0; - /* We do support only 2.4 Ghz */ - dev->phy->channels_supported[0] = 0x7FFF800; - dev->flags = IEEE802154_HW_OMIT_CKSUM; - - if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { - irq_worker = at86rf230_irqwork; - irq_handler = at86rf230_isr; - } else { - irq_worker = at86rf230_irqwork_level; - irq_handler = at86rf230_isr_level; - } - - mutex_init(&lp->bmux); - INIT_WORK(&lp->irqwork, irq_worker); - spin_lock_init(&lp->lock); - init_completion(&lp->tx_complete); - - spi_set_drvdata(spi, lp); - - at86rf230_fill_data(spi); - - rc = gpio_request(lp->rstn, "rstn"); + rc = gpio_request(pdata->rstn, "rstn"); if (rc) - goto err_rstn; + return rc; - if (gpio_is_valid(lp->slp_tr)) { - rc = gpio_request(lp->slp_tr, "slp_tr"); + if (gpio_is_valid(pdata->slp_tr)) { + rc = gpio_request(pdata->slp_tr, "slp_tr"); if (rc) goto err_slp_tr; } - rc = gpio_direction_output(lp->rstn, 1); + rc = gpio_direction_output(pdata->rstn, 1); if (rc) goto err_gpio_dir; - if (gpio_is_valid(lp->slp_tr)) { - rc = gpio_direction_output(lp->slp_tr, 0); + if (gpio_is_valid(pdata->slp_tr)) { + rc = gpio_direction_output(pdata->slp_tr, 0); if (rc) goto err_gpio_dir; } /* Reset */ msleep(1); - gpio_set_value(lp->rstn, 0); + gpio_set_value(pdata->rstn, 0); msleep(1); - gpio_set_value(lp->rstn, 1); + gpio_set_value(pdata->rstn, 1); msleep(1); - rc = at86rf230_read_subreg(lp, SR_MAN_ID_0, &man_id_0); - if (rc) - goto err_gpio_dir; - rc = at86rf230_read_subreg(lp, SR_MAN_ID_1, &man_id_1); - if (rc) + rc = __at86rf230_detect_device(spi, &man_id, &part, &version); + if (rc < 0) goto err_gpio_dir; - if (man_id_1 != 0x00 || man_id_0 != 0x1f) { + if (man_id != 0x001f) { dev_err(&spi->dev, "Non-Atmel dev found (MAN_ID %02x %02x)\n", - man_id_1, man_id_0); + man_id >> 8, man_id & 0xFF); rc = -EINVAL; goto err_gpio_dir; } - rc = at86rf230_read_subreg(lp, SR_PART_NUM, &lp->part); - if (rc) - goto err_gpio_dir; - - rc = at86rf230_read_subreg(lp, SR_VERSION_NUM, &lp->vers); - if (rc) - goto err_gpio_dir; - - switch (lp->part) { + switch (part) { case 2: chip = "at86rf230"; - /* supported = 1; FIXME: should be easy to support; */ + /* FIXME: should be easy to support; */ break; case 3: chip = "at86rf231"; - supported = 1; + ops = &at86rf230_ops; + break; + case 7: + chip = "at86rf212"; + if (version == 1) + ops = &at86rf212_ops; + break; + case 11: + chip = "at86rf233"; + ops = &at86rf230_ops; break; default: chip = "UNKNOWN"; break; } - dev_info(&spi->dev, "Detected %s chip version %d\n", chip, lp->vers); - if (!supported) { + dev_info(&spi->dev, "Detected %s chip version %d\n", chip, version); + if (!ops) { rc = -ENOTSUPP; goto err_gpio_dir; } + dev = ieee802154_alloc_device(sizeof(*lp), ops); + if (!dev) { + rc = -ENOMEM; + goto err_gpio_dir; + } + + lp = dev->priv; + lp->dev = dev; + lp->part = part; + lp->vers = version; + + lp->spi = spi; + + dev->parent = &spi->dev; + dev->extra_tx_headroom = 0; + dev->flags = IEEE802154_HW_OMIT_CKSUM | IEEE802154_HW_AACK; + + if (pdata->irq_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) { + irq_worker = at86rf230_irqwork; + irq_handler = at86rf230_isr; + } else { + irq_worker = at86rf230_irqwork_level; + irq_handler = at86rf230_isr_level; + } + + mutex_init(&lp->bmux); + INIT_WORK(&lp->irqwork, irq_worker); + spin_lock_init(&lp->lock); + init_completion(&lp->tx_complete); + + spi_set_drvdata(spi, lp); + + if (is_rf212(lp)) { + dev->phy->channels_supported[0] = 0x00007FF; + dev->phy->channels_supported[2] = 0x00007FF; + } else { + dev->phy->channels_supported[0] = 0x7FFF800; + } + rc = at86rf230_hw_init(lp); if (rc) - goto err_gpio_dir; + goto err_hw_init; rc = request_irq(spi->irq, irq_handler, IRQF_SHARED | pdata->irq_type, dev_name(&spi->dev), lp); if (rc) - goto err_gpio_dir; + goto err_hw_init; /* Read irq status register to reset irq line */ rc = at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &status); @@ -980,30 +1186,33 @@ static int at86rf230_probe(struct spi_device *spi) err_irq: free_irq(spi->irq, lp); +err_hw_init: flush_work(&lp->irqwork); -err_gpio_dir: - if (gpio_is_valid(lp->slp_tr)) - gpio_free(lp->slp_tr); -err_slp_tr: - gpio_free(lp->rstn); -err_rstn: + spi_set_drvdata(spi, NULL); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); + +err_gpio_dir: + if (gpio_is_valid(pdata->slp_tr)) + gpio_free(pdata->slp_tr); +err_slp_tr: + gpio_free(pdata->rstn); return rc; } static int at86rf230_remove(struct spi_device *spi) { struct at86rf230_local *lp = spi_get_drvdata(spi); + struct at86rf230_platform_data *pdata = spi->dev.platform_data; ieee802154_unregister_device(lp->dev); free_irq(spi->irq, lp); flush_work(&lp->irqwork); - if (gpio_is_valid(lp->slp_tr)) - gpio_free(lp->slp_tr); - gpio_free(lp->rstn); + if (gpio_is_valid(pdata->slp_tr)) + gpio_free(pdata->slp_tr); + gpio_free(pdata->rstn); mutex_destroy(&lp->bmux); ieee802154_free_device(lp->dev); diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 2dc82f1d2e70..3da44d5d9149 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig @@ -210,13 +210,6 @@ config KINGSUN_DONGLE To compile it as a module, choose M here: the module will be called kingsun-sir. -config EP7211_DONGLE - tristate "Cirrus Logic clps711x I/R support" - depends on IRTTY_SIR && ARCH_CLPS711X && IRDA - help - Say Y here if you want to build support for the Cirrus logic - EP7211 chipset's infrared module. - config KSDAZZLE_DONGLE tristate "KingSun Dazzle IrDA-USB dongle" depends on IRDA && USB diff --git a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile index dfc64537f62f..be8ab5b9a4a2 100644 --- a/drivers/net/irda/Makefile +++ b/drivers/net/irda/Makefile @@ -35,7 +35,6 @@ obj-$(CONFIG_MCP2120_DONGLE) += mcp2120-sir.o obj-$(CONFIG_ACT200L_DONGLE) += act200l-sir.o obj-$(CONFIG_MA600_DONGLE) += ma600-sir.o obj-$(CONFIG_TOIM3232_DONGLE) += toim3232-sir.o -obj-$(CONFIG_EP7211_DONGLE) += ep7211-sir.o obj-$(CONFIG_KINGSUN_DONGLE) += kingsun-sir.o obj-$(CONFIG_KSDAZZLE_DONGLE) += ksdazzle-sir.o obj-$(CONFIG_KS959_DONGLE) += ks959-sir.o diff --git a/drivers/net/irda/ep7211-sir.c b/drivers/net/irda/ep7211-sir.c deleted file mode 100644 index 5fe1f4dd3369..000000000000 --- a/drivers/net/irda/ep7211-sir.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - * IR port driver for the Cirrus Logic CLPS711X processors - * - * Copyright 2001, Blue Mug Inc. All rights reserved. - * Copyright 2007, Samuel Ortiz <samuel@sortiz.org> - */ - -#include <linux/module.h> -#include <linux/platform_device.h> - -#include <mach/hardware.h> - -#include "sir-dev.h" - -static int clps711x_dongle_open(struct sir_dev *dev) -{ - unsigned int syscon; - - /* Turn on the SIR encoder. */ - syscon = clps_readl(SYSCON1); - syscon |= SYSCON1_SIREN; - clps_writel(syscon, SYSCON1); - - return 0; -} - -static int clps711x_dongle_close(struct sir_dev *dev) -{ - unsigned int syscon; - - /* Turn off the SIR encoder. */ - syscon = clps_readl(SYSCON1); - syscon &= ~SYSCON1_SIREN; - clps_writel(syscon, SYSCON1); - - return 0; -} - -static struct dongle_driver clps711x_dongle = { - .owner = THIS_MODULE, - .driver_name = "EP7211 IR driver", - .type = IRDA_EP7211_DONGLE, - .open = clps711x_dongle_open, - .close = clps711x_dongle_close, -}; - -static int clps711x_sir_probe(struct platform_device *pdev) -{ - return irda_register_dongle(&clps711x_dongle); -} - -static int clps711x_sir_remove(struct platform_device *pdev) -{ - return irda_unregister_dongle(&clps711x_dongle); -} - -static struct platform_driver clps711x_sir_driver = { - .driver = { - .name = "sir-clps711x", - .owner = THIS_MODULE, - }, - .probe = clps711x_sir_probe, - .remove = clps711x_sir_remove, -}; -module_platform_driver(clps711x_sir_driver); - -MODULE_AUTHOR("Samuel Ortiz <samuel@sortiz.org>"); -MODULE_DESCRIPTION("EP7211 IR dongle driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("irda-dongle-13"); /* IRDA_EP7211_DONGLE */ diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 177441afeb96..24b6dddd7f2f 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -522,7 +522,6 @@ static void irtty_close(struct tty_struct *tty) sirdev_put_instance(priv->dev); /* Stop tty */ - irtty_stop_receiver(tty, TRUE); clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (tty->ops->stop) tty->ops->stop(tty); diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index c5011e078e1b..282effee7e1c 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -136,16 +136,9 @@ static const struct ethtool_ops loopback_ethtool_ops = { static int loopback_dev_init(struct net_device *dev) { - int i; - dev->lstats = alloc_percpu(struct pcpu_lstats); + dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); if (!dev->lstats) return -ENOMEM; - - for_each_possible_cpu(i) { - struct pcpu_lstats *lb_stats; - lb_stats = per_cpu_ptr(dev->lstats, i); - u64_stats_init(&lb_stats->syncp); - } return 0; } @@ -160,6 +153,7 @@ static const struct net_device_ops loopback_ops = { .ndo_init = loopback_dev_init, .ndo_start_xmit= loopback_xmit, .ndo_get_stats64 = loopback_get_stats64, + .ndo_set_mac_address = eth_mac_addr, }; /* @@ -174,6 +168,7 @@ static void loopback_setup(struct net_device *dev) dev->tx_queue_len = 0; dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ dev->flags = IFF_LOOPBACK; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; dev->priv_flags &= ~IFF_XMIT_DST_RELEASE; dev->hw_features = NETIF_F_ALL_TSO | NETIF_F_UFO; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST @@ -181,6 +176,7 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_UFO | NETIF_F_HW_CSUM | NETIF_F_RXCSUM + | NETIF_F_SCTP_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX | NETIF_F_NETNS_LOCAL diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 8433de4509c7..c683ac2c8c94 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -506,6 +506,9 @@ static int macvlan_change_mtu(struct net_device *dev, int new_mtu) static struct lock_class_key macvlan_netdev_xmit_lock_key; static struct lock_class_key macvlan_netdev_addr_lock_key; +#define ALWAYS_ON_FEATURES \ + (NETIF_F_SG | NETIF_F_GEN_CSUM | NETIF_F_GSO_SOFTWARE | NETIF_F_LLTX) + #define MACVLAN_FEATURES \ (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \ NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \ @@ -534,28 +537,21 @@ static int macvlan_init(struct net_device *dev) { struct macvlan_dev *vlan = netdev_priv(dev); const struct net_device *lowerdev = vlan->lowerdev; - int i; dev->state = (dev->state & ~MACVLAN_STATE_MASK) | (lowerdev->state & MACVLAN_STATE_MASK); dev->features = lowerdev->features & MACVLAN_FEATURES; - dev->features |= NETIF_F_LLTX; + dev->features |= ALWAYS_ON_FEATURES; dev->gso_max_size = lowerdev->gso_max_size; dev->iflink = lowerdev->ifindex; dev->hard_header_len = lowerdev->hard_header_len; macvlan_set_lockdep_class(dev); - vlan->pcpu_stats = alloc_percpu(struct vlan_pcpu_stats); + vlan->pcpu_stats = netdev_alloc_pcpu_stats(struct vlan_pcpu_stats); if (!vlan->pcpu_stats) return -ENOMEM; - for_each_possible_cpu(i) { - struct vlan_pcpu_stats *mvlstats; - mvlstats = per_cpu_ptr(vlan->pcpu_stats, i); - u64_stats_init(&mvlstats->syncp); - } - return 0; } @@ -699,7 +695,7 @@ static netdev_features_t macvlan_fix_features(struct net_device *dev, features = netdev_increment_features(vlan->lowerdev->features, features, mask); - features |= NETIF_F_LLTX; + features |= ALWAYS_ON_FEATURES; return features; } @@ -879,14 +875,15 @@ int macvlan_common_newlink(struct net *src_net, struct net_device *dev, dev->priv_flags |= IFF_MACVLAN; err = netdev_upper_dev_link(lowerdev, dev); if (err) - goto destroy_port; - + goto unregister_netdev; list_add_tail_rcu(&vlan->list, &port->vlans); netif_stacked_transfer_operstate(lowerdev, dev); return 0; +unregister_netdev: + unregister_netdevice(dev); destroy_port: port->count -= 1; if (!port->count) diff --git a/drivers/net/nlmon.c b/drivers/net/nlmon.c index d2bb12bfabd5..14ce7de6a933 100644 --- a/drivers/net/nlmon.c +++ b/drivers/net/nlmon.c @@ -47,16 +47,7 @@ static int nlmon_change_mtu(struct net_device *dev, int new_mtu) static int nlmon_dev_init(struct net_device *dev) { - int i; - - dev->lstats = alloc_percpu(struct pcpu_lstats); - - for_each_possible_cpu(i) { - struct pcpu_lstats *nlmstats; - nlmstats = per_cpu_ptr(dev->lstats, i); - u64_stats_init(&nlmstats->syncp); - } - + dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); return dev->lstats == NULL ? -ENOMEM : 0; } diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index 9b5d46c03eed..6a17f92153b3 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -71,6 +71,12 @@ config BCM63XX_PHY ---help--- Currently supports the 6348 and 6358 PHYs. +config BCM7XXX_PHY + tristate "Drivers for Broadcom 7xxx SOCs internal PHYs" + ---help--- + Currently supports the BCM7366, BCM7439, BCM7445, and + 40nm and 65nm generation of BCM7xxx Set Top Box SoCs. + config BCM87XX_PHY tristate "Driver for Broadcom BCM8706 and BCM8727 PHYs" help diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9013dfa12aa3..07d24024863e 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o +obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o obj-$(CONFIG_BCM87XX_PHY) += bcm87xx.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o diff --git a/drivers/net/phy/bcm7xxx.c b/drivers/net/phy/bcm7xxx.c new file mode 100644 index 000000000000..697337220016 --- /dev/null +++ b/drivers/net/phy/bcm7xxx.c @@ -0,0 +1,343 @@ +/* + * Broadcom BCM7xxx internal transceivers support. + * + * Copyright (C) 2014, Broadcom Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/phy.h> +#include <linux/delay.h> +#include <linux/bitops.h> +#include <linux/brcmphy.h> + +/* Broadcom BCM7xxx internal PHY registers */ +#define MII_BCM7XXX_CHANNEL_WIDTH 0x2000 + +/* 40nm only register definitions */ +#define MII_BCM7XXX_100TX_AUX_CTL 0x10 +#define MII_BCM7XXX_100TX_FALSE_CAR 0x13 +#define MII_BCM7XXX_100TX_DISC 0x14 +#define MII_BCM7XXX_AUX_MODE 0x1d +#define MII_BCM7XX_64CLK_MDIO BIT(12) +#define MII_BCM7XXX_CORE_BASE1E 0x1e +#define MII_BCM7XXX_TEST 0x1f +#define MII_BCM7XXX_SHD_MODE_2 BIT(2) + +static int bcm7445_config_init(struct phy_device *phydev) +{ + int ret; + const struct bcm7445_regs { + int reg; + u16 value; + } bcm7445_regs_cfg[] = { + /* increases ADC latency by 24ns */ + { MII_BCM54XX_EXP_SEL, 0x0038 }, + { MII_BCM54XX_EXP_DATA, 0xAB95 }, + /* increases internal 1V LDO voltage by 5% */ + { MII_BCM54XX_EXP_SEL, 0x2038 }, + { MII_BCM54XX_EXP_DATA, 0xBB22 }, + /* reduce RX low pass filter corner frequency */ + { MII_BCM54XX_EXP_SEL, 0x6038 }, + { MII_BCM54XX_EXP_DATA, 0xFFC5 }, + /* reduce RX high pass filter corner frequency */ + { MII_BCM54XX_EXP_SEL, 0x003a }, + { MII_BCM54XX_EXP_DATA, 0x2002 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bcm7445_regs_cfg); i++) { + ret = phy_write(phydev, + bcm7445_regs_cfg[i].reg, + bcm7445_regs_cfg[i].value); + if (ret) + return ret; + } + + return 0; +} + +static void phy_write_exp(struct phy_device *phydev, + u16 reg, u16 value) +{ + phy_write(phydev, MII_BCM54XX_EXP_SEL, MII_BCM54XX_EXP_SEL_ER | reg); + phy_write(phydev, MII_BCM54XX_EXP_DATA, value); +} + +static void phy_write_misc(struct phy_device *phydev, + u16 reg, u16 chl, u16 value) +{ + int tmp; + + phy_write(phydev, MII_BCM54XX_AUX_CTL, MII_BCM54XX_AUXCTL_SHDWSEL_MISC); + + tmp = phy_read(phydev, MII_BCM54XX_AUX_CTL); + tmp |= MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA; + phy_write(phydev, MII_BCM54XX_AUX_CTL, tmp); + + tmp = (chl * MII_BCM7XXX_CHANNEL_WIDTH) | reg; + phy_write(phydev, MII_BCM54XX_EXP_SEL, tmp); + + phy_write(phydev, MII_BCM54XX_EXP_DATA, value); +} + +static int bcm7xxx_28nm_afe_config_init(struct phy_device *phydev) +{ + /* write AFE_RXCONFIG_0 */ + phy_write_misc(phydev, 0x38, 0x0000, 0xeb19); + + /* write AFE_RXCONFIG_1 */ + phy_write_misc(phydev, 0x38, 0x0001, 0x9a3f); + + /* write AFE_RX_LP_COUNTER */ + phy_write_misc(phydev, 0x38, 0x0003, 0x7fc7); + + /* write AFE_HPF_TRIM_OTHERS */ + phy_write_misc(phydev, 0x3A, 0x0000, 0x000b); + + /* write AFTE_TX_CONFIG */ + phy_write_misc(phydev, 0x39, 0x0000, 0x0800); + + /* Increase VCO range to prevent unlocking problem of PLL at low + * temp + */ + phy_write_misc(phydev, 0x0032, 0x0001, 0x0048); + + /* Change Ki to 011 */ + phy_write_misc(phydev, 0x0032, 0x0002, 0x021b); + + /* Disable loading of TVCO buffer to bandgap, set bandgap trim + * to 111 + */ + phy_write_misc(phydev, 0x0033, 0x0000, 0x0e20); + + /* Adjust bias current trim by -3 */ + phy_write_misc(phydev, 0x000a, 0x0000, 0x690b); + + /* Switch to CORE_BASE1E */ + phy_write(phydev, MII_BCM7XXX_CORE_BASE1E, 0xd); + + /* Reset R_CAL/RC_CAL Engine */ + phy_write_exp(phydev, 0x00b0, 0x0010); + + /* Disable Reset R_CAL/RC_CAL Engine */ + phy_write_exp(phydev, 0x00b0, 0x0000); + + return 0; +} + +static int bcm7xxx_28nm_config_init(struct phy_device *phydev) +{ + int ret; + + ret = bcm7445_config_init(phydev); + if (ret) + return ret; + + return bcm7xxx_28nm_afe_config_init(phydev); +} + +static int phy_set_clr_bits(struct phy_device *dev, int location, + int set_mask, int clr_mask) +{ + int v, ret; + + v = phy_read(dev, location); + if (v < 0) + return v; + + v &= ~clr_mask; + v |= set_mask; + + ret = phy_write(dev, location, v); + if (ret < 0) + return ret; + + return v; +} + +static int bcm7xxx_config_init(struct phy_device *phydev) +{ + int ret; + + /* Enable 64 clock MDIO */ + phy_write(phydev, MII_BCM7XXX_AUX_MODE, MII_BCM7XX_64CLK_MDIO); + phy_read(phydev, MII_BCM7XXX_AUX_MODE); + + /* Workaround only required for 100Mbits/sec */ + if (!(phydev->dev_flags & PHY_BRCM_100MBPS_WAR)) + return 0; + + /* set shadow mode 2 */ + ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, + MII_BCM7XXX_SHD_MODE_2, MII_BCM7XXX_SHD_MODE_2); + if (ret < 0) + return ret; + + /* set iddq_clkbias */ + phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0F00); + udelay(10); + + /* reset iddq_clkbias */ + phy_write(phydev, MII_BCM7XXX_100TX_DISC, 0x0C00); + + phy_write(phydev, MII_BCM7XXX_100TX_FALSE_CAR, 0x7555); + + /* reset shadow mode 2 */ + ret = phy_set_clr_bits(phydev, MII_BCM7XXX_TEST, MII_BCM7XXX_SHD_MODE_2, 0); + if (ret < 0) + return ret; + + return 0; +} + +/* Workaround for putting the PHY in IDDQ mode, required + * for all BCM7XXX PHYs + */ +static int bcm7xxx_suspend(struct phy_device *phydev) +{ + int ret; + const struct bcm7xxx_regs { + int reg; + u16 value; + } bcm7xxx_suspend_cfg[] = { + { MII_BCM7XXX_TEST, 0x008b }, + { MII_BCM7XXX_100TX_AUX_CTL, 0x01c0 }, + { MII_BCM7XXX_100TX_DISC, 0x7000 }, + { MII_BCM7XXX_TEST, 0x000f }, + { MII_BCM7XXX_100TX_AUX_CTL, 0x20d0 }, + { MII_BCM7XXX_TEST, 0x000b }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(bcm7xxx_suspend_cfg); i++) { + ret = phy_write(phydev, + bcm7xxx_suspend_cfg[i].reg, + bcm7xxx_suspend_cfg[i].value); + if (ret) + return ret; + } + + return 0; +} + +static int bcm7xxx_dummy_config_init(struct phy_device *phydev) +{ + return 0; +} + +static struct phy_driver bcm7xxx_driver[] = { +{ + .phy_id = PHY_ID_BCM7366, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM7366", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_28nm_afe_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_28nm_afe_config_init, + .driver = { .owner = THIS_MODULE }, +}, { + .phy_id = PHY_ID_BCM7439, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM7439", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_28nm_afe_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_28nm_afe_config_init, + .driver = { .owner = THIS_MODULE }, +}, { + .phy_id = PHY_ID_BCM7445, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM7445", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_28nm_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_28nm_config_init, + .driver = { .owner = THIS_MODULE }, +}, { + .name = "Broadcom BCM7XXX 28nm", + .phy_id = PHY_ID_BCM7XXX_28, + .phy_id_mask = PHY_BCM_OUI_MASK, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_28nm_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_28nm_config_init, + .driver = { .owner = THIS_MODULE }, +}, { + .phy_id = PHY_BCM_OUI_4, + .phy_id_mask = 0xffff0000, + .name = "Broadcom BCM7XXX 40nm", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_config_init, + .driver = { .owner = THIS_MODULE }, +}, { + .phy_id = PHY_BCM_OUI_5, + .phy_id_mask = 0xffffff00, + .name = "Broadcom BCM7XXX 65nm", + .features = PHY_BASIC_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_IS_INTERNAL, + .config_init = bcm7xxx_dummy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .suspend = bcm7xxx_suspend, + .resume = bcm7xxx_config_init, + .driver = { .owner = THIS_MODULE }, +} }; + +static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = { + { PHY_ID_BCM7366, 0xfffffff0, }, + { PHY_ID_BCM7439, 0xfffffff0, }, + { PHY_ID_BCM7445, 0xfffffff0, }, + { PHY_ID_BCM7XXX_28, 0xfffffc00 }, + { PHY_BCM_OUI_4, 0xffff0000 }, + { PHY_BCM_OUI_5, 0xffffff00 }, + { } +}; + +static int __init bcm7xxx_phy_init(void) +{ + return phy_drivers_register(bcm7xxx_driver, + ARRAY_SIZE(bcm7xxx_driver)); +} + +static void __exit bcm7xxx_phy_exit(void) +{ + phy_drivers_unregister(bcm7xxx_driver, + ARRAY_SIZE(bcm7xxx_driver)); +} + +module_init(bcm7xxx_phy_init); +module_exit(bcm7xxx_phy_exit); + +MODULE_DEVICE_TABLE(mdio, bcm7xxx_tbl); + +MODULE_DESCRIPTION("Broadcom BCM7xxx internal PHY driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Broadcom Corporation"); diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index f8c90ea75108..34088d60da74 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -25,58 +25,6 @@ #define BRCM_PHY_REV(phydev) \ ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask)) - -#define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ -#define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ -#define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ - -#define MII_BCM54XX_ESR 0x11 /* BCM54xx extended status register */ -#define MII_BCM54XX_ESR_IS 0x1000 /* Interrupt status */ - -#define MII_BCM54XX_EXP_DATA 0x15 /* Expansion register data */ -#define MII_BCM54XX_EXP_SEL 0x17 /* Expansion register select */ -#define MII_BCM54XX_EXP_SEL_SSD 0x0e00 /* Secondary SerDes select */ -#define MII_BCM54XX_EXP_SEL_ER 0x0f00 /* Expansion register select */ - -#define MII_BCM54XX_AUX_CTL 0x18 /* Auxiliary control register */ -#define MII_BCM54XX_ISR 0x1a /* BCM54xx interrupt status register */ -#define MII_BCM54XX_IMR 0x1b /* BCM54xx interrupt mask register */ -#define MII_BCM54XX_INT_CRCERR 0x0001 /* CRC error */ -#define MII_BCM54XX_INT_LINK 0x0002 /* Link status changed */ -#define MII_BCM54XX_INT_SPEED 0x0004 /* Link speed change */ -#define MII_BCM54XX_INT_DUPLEX 0x0008 /* Duplex mode changed */ -#define MII_BCM54XX_INT_LRS 0x0010 /* Local receiver status changed */ -#define MII_BCM54XX_INT_RRS 0x0020 /* Remote receiver status changed */ -#define MII_BCM54XX_INT_SSERR 0x0040 /* Scrambler synchronization error */ -#define MII_BCM54XX_INT_UHCD 0x0080 /* Unsupported HCD negotiated */ -#define MII_BCM54XX_INT_NHCD 0x0100 /* No HCD */ -#define MII_BCM54XX_INT_NHCDL 0x0200 /* No HCD link */ -#define MII_BCM54XX_INT_ANPR 0x0400 /* Auto-negotiation page received */ -#define MII_BCM54XX_INT_LC 0x0800 /* All counters below 128 */ -#define MII_BCM54XX_INT_HC 0x1000 /* Counter above 32768 */ -#define MII_BCM54XX_INT_MDIX 0x2000 /* MDIX status change */ -#define MII_BCM54XX_INT_PSERR 0x4000 /* Pair swap error */ - -#define MII_BCM54XX_SHD 0x1c /* 0x1c shadow registers */ -#define MII_BCM54XX_SHD_WRITE 0x8000 -#define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) -#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) - -/* - * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18) - */ -#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 -#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400 -#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800 - -#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000 -#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200 -#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000 -#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007 - -#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 - - /* * Broadcom LED source encodings. These are used in BCM5461, BCM5481, * BCM5482, and possibly some others. diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 547725fa8671..98e7cbf720a5 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -437,7 +437,10 @@ static int ptp_dp83640_enable(struct ptp_clock_info *ptp, if (on) { gpio_num = gpio_tab[EXTTS0_GPIO + index]; evnt |= (gpio_num & EVNT_GPIO_MASK) << EVNT_GPIO_SHIFT; - evnt |= EVNT_RISE; + if (rq->extts.flags & PTP_FALLING_EDGE) + evnt |= EVNT_FALL; + else + evnt |= EVNT_RISE; } ext_write(0, phydev, PAGE5, PTP_EVNT, evnt); return 0; @@ -1003,11 +1006,6 @@ static int dp83640_probe(struct phy_device *phydev) } else list_add_tail(&dp83640->list, &clock->phylist); - if (clock->chosen && !list_empty(&clock->phylist)) - recalibrate(clock); - else - enable_broadcast(dp83640->phydev, clock->page, 1); - dp83640_clock_put(clock); return 0; @@ -1058,6 +1056,21 @@ static void dp83640_remove(struct phy_device *phydev) kfree(dp83640); } +static int dp83640_config_init(struct phy_device *phydev) +{ + struct dp83640_private *dp83640 = phydev->priv; + struct dp83640_clock *clock = dp83640->clock; + + if (clock->chosen && !list_empty(&clock->phylist)) + recalibrate(clock); + else + enable_broadcast(phydev, clock->page, 1); + + enable_status_frames(phydev, true); + ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE); + return 0; +} + static int dp83640_ack_interrupt(struct phy_device *phydev) { int err = phy_read(phydev, MII_DP83640_MISR); @@ -1195,11 +1208,6 @@ static int dp83640_hwtstamp(struct phy_device *phydev, struct ifreq *ifr) mutex_lock(&dp83640->clock->extreg_lock); - if (dp83640->hwts_tx_en || dp83640->hwts_rx_en) { - enable_status_frames(phydev, true); - ext_write(0, phydev, PAGE4, PTP_CTL, PTP_ENABLE); - } - ext_write(0, phydev, PAGE5, PTP_TXCFG0, txcfg0); ext_write(0, phydev, PAGE5, PTP_RXCFG0, rxcfg0); @@ -1281,6 +1289,7 @@ static void dp83640_txtstamp(struct phy_device *phydev, } /* fall through */ case HWTSTAMP_TX_ON: + skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; skb_queue_tail(&dp83640->tx_queue, skb); schedule_work(&dp83640->ts_work); break; @@ -1330,6 +1339,7 @@ static struct phy_driver dp83640_driver = { .flags = PHY_HAS_INTERRUPT, .probe = dp83640_probe, .remove = dp83640_remove, + .config_init = dp83640_config_init, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = dp83640_ack_interrupt, diff --git a/drivers/net/phy/mdio-sun4i.c b/drivers/net/phy/mdio-sun4i.c index bb88bc7d81fb..9367acc84fbb 100644 --- a/drivers/net/phy/mdio-sun4i.c +++ b/drivers/net/phy/mdio-sun4i.c @@ -170,6 +170,9 @@ static int sun4i_mdio_remove(struct platform_device *pdev) } static const struct of_device_id sun4i_mdio_dt_ids[] = { + { .compatible = "allwinner,sun4i-a10-mdio" }, + + /* Deprecated */ { .compatible = "allwinner,sun4i-mdio" }, { } }; diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 71e49000fbf3..76f54b32a120 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -432,8 +432,28 @@ phy_id_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(phy_id); +static ssize_t +phy_interface_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct phy_device *phydev = to_phy_device(dev); + + return sprintf(buf, "%s\n", phy_modes(phydev->interface)); +} +static DEVICE_ATTR_RO(phy_interface); + +static ssize_t +phy_has_fixups_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct phy_device *phydev = to_phy_device(dev); + + return sprintf(buf, "%d\n", phydev->has_fixups); +} +static DEVICE_ATTR_RO(phy_has_fixups); + static struct attribute *mdio_dev_attrs[] = { &dev_attr_phy_id.attr, + &dev_attr_phy_interface.attr, + &dev_attr_phy_has_fixups.attr, NULL, }; ATTRIBUTE_GROUPS(mdio_dev); diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c index 5a8993b0cafc..0c9e4342f11d 100644 --- a/drivers/net/phy/micrel.c +++ b/drivers/net/phy/micrel.c @@ -148,15 +148,52 @@ static int ks8737_config_intr(struct phy_device *phydev) return rc < 0 ? rc : 0; } +static int kszphy_setup_led(struct phy_device *phydev, + unsigned int reg, unsigned int shift) +{ + + struct device *dev = &phydev->dev; + struct device_node *of_node = dev->of_node; + int rc, temp; + u32 val; + + if (!of_node && dev->parent->of_node) + of_node = dev->parent->of_node; + + if (of_property_read_u32(of_node, "micrel,led-mode", &val)) + return 0; + + temp = phy_read(phydev, reg); + if (temp < 0) + return temp; + + temp &= 3 << shift; + temp |= val << shift; + rc = phy_write(phydev, reg, temp); + + return rc < 0 ? rc : 0; +} + static int kszphy_config_init(struct phy_device *phydev) { return 0; } +static int kszphy_config_init_led8041(struct phy_device *phydev) +{ + /* single led control, register 0x1e bits 15..14 */ + return kszphy_setup_led(phydev, 0x1e, 14); +} + static int ksz8021_config_init(struct phy_device *phydev) { - int rc; const u16 val = KSZPHY_OMSO_B_CAST_OFF | KSZPHY_OMSO_RMII_OVERRIDE; + int rc; + + rc = kszphy_setup_led(phydev, 0x1f, 4); + if (rc) + dev_err(&phydev->dev, "failed to set led mode\n"); + phy_write(phydev, MII_KSZPHY_OMSO, val); rc = ksz_config_flags(phydev); return rc < 0 ? rc : 0; @@ -166,6 +203,10 @@ static int ks8051_config_init(struct phy_device *phydev) { int rc; + rc = kszphy_setup_led(phydev, 0x1f, 4); + if (rc) + dev_err(&phydev->dev, "failed to set led mode\n"); + rc = ksz_config_flags(phydev); return rc < 0 ? rc : 0; } @@ -327,7 +368,7 @@ static struct phy_driver ksphy_driver[] = { .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = kszphy_config_init, + .config_init = kszphy_config_init_led8041, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, @@ -342,7 +383,7 @@ static struct phy_driver ksphy_driver[] = { .features = PHY_BASIC_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = kszphy_config_init, + .config_init = kszphy_config_init_led8041, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, @@ -371,7 +412,7 @@ static struct phy_driver ksphy_driver[] = { .phy_id_mask = 0x00ffffff, .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause), .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, - .config_init = kszphy_config_init, + .config_init = kszphy_config_init_led8041, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, .ack_interrupt = kszphy_ack_interrupt, diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 19c9eca0ef26..643b5d665f41 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -38,6 +38,26 @@ #include <asm/irq.h> +static const char *phy_speed_to_str(int speed) +{ + switch (speed) { + case SPEED_10: + return "10Mbps"; + case SPEED_100: + return "100Mbps"; + case SPEED_1000: + return "1Gbps"; + case SPEED_2500: + return "2.5Gbps"; + case SPEED_10000: + return "10Gbps"; + case SPEED_UNKNOWN: + return "Unknown"; + default: + return "Unsupported (update phy.c)"; + } +} + /** * phy_print_status - Convenience function to print out the current phy status * @phydev: the phy_device struct @@ -45,12 +65,13 @@ void phy_print_status(struct phy_device *phydev) { if (phydev->link) { - pr_info("%s - Link is Up - %d/%s\n", - dev_name(&phydev->dev), - phydev->speed, - DUPLEX_FULL == phydev->duplex ? "Full" : "Half"); + netdev_info(phydev->attached_dev, + "Link is Up - %s/%s - flow control %s\n", + phy_speed_to_str(phydev->speed), + DUPLEX_FULL == phydev->duplex ? "Full" : "Half", + phydev->pause ? "rx/tx" : "off"); } else { - pr_info("%s - Link is Down\n", dev_name(&phydev->dev)); + netdev_info(phydev->attached_dev, "Link is Down\n"); } } EXPORT_SYMBOL(phy_print_status); @@ -62,7 +83,7 @@ EXPORT_SYMBOL(phy_print_status); * If the @phydev driver has an ack_interrupt function, call it to * ack and clear the phy device's interrupt. * - * Returns 0 on success on < 0 on error. + * Returns 0 on success or < 0 on error. */ static int phy_clear_interrupt(struct phy_device *phydev) { @@ -77,7 +98,7 @@ static int phy_clear_interrupt(struct phy_device *phydev) * @phydev: the phy_device struct * @interrupts: interrupt flags to configure for this @phydev * - * Returns 0 on success on < 0 on error. + * Returns 0 on success or < 0 on error. */ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) { @@ -93,15 +114,16 @@ static int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) * phy_aneg_done - return auto-negotiation status * @phydev: target phy_device struct * - * Description: Reads the status register and returns 0 either if - * auto-negotiation is incomplete, or if there was an error. - * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + * Description: Return the auto-negotiation status from this @phydev + * Returns > 0 on success or < 0 on error. 0 means that auto-negotiation + * is still pending. */ static inline int phy_aneg_done(struct phy_device *phydev) { - int retval = phy_read(phydev, MII_BMSR); + if (phydev->drv->aneg_done) + return phydev->drv->aneg_done(phydev); - return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); + return genphy_aneg_done(phydev); } /* A structure for mapping a particular speed and duplex @@ -283,7 +305,10 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) ethtool_cmd_speed_set(cmd, phydev->speed); cmd->duplex = phydev->duplex; - cmd->port = PORT_MII; + if (phydev->interface == PHY_INTERFACE_MODE_MOCA) + cmd->port = PORT_BNC; + else + cmd->port = PORT_MII; cmd->phy_address = phydev->addr; cmd->transceiver = phy_is_internal(phydev) ? XCVR_INTERNAL : XCVR_EXTERNAL; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 4b03e63639b7..a2fbb3e1db9a 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -139,6 +139,7 @@ static int phy_scan_fixups(struct phy_device *phydev) mutex_unlock(&phy_fixup_lock); return err; } + phydev->has_fixups = true; } } mutex_unlock(&phy_fixup_lock); @@ -534,16 +535,16 @@ static int phy_poll_reset(struct phy_device *phydev) int phy_init_hw(struct phy_device *phydev) { - int ret; + int ret = 0; if (!phydev->drv || !phydev->drv->config_init) return 0; - ret = phy_write(phydev, MII_BMCR, BMCR_RESET); - if (ret < 0) - return ret; + if (phydev->drv->soft_reset) + ret = phydev->drv->soft_reset(phydev); + else + ret = genphy_soft_reset(phydev); - ret = phy_poll_reset(phydev); if (ret < 0) return ret; @@ -719,7 +720,7 @@ int phy_resume(struct phy_device *phydev) static int genphy_config_advert(struct phy_device *phydev) { u32 advertise; - int oldadv, adv; + int oldadv, adv, bmsr; int err, changed = 0; /* Only allow advertising what this PHY supports */ @@ -744,26 +745,36 @@ static int genphy_config_advert(struct phy_device *phydev) changed = 1; } + bmsr = phy_read(phydev, MII_BMSR); + if (bmsr < 0) + return bmsr; + + /* Per 802.3-2008, Section 22.2.4.2.16 Extended status all + * 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a + * logical 1. + */ + if (!(bmsr & BMSR_ESTATEN)) + return changed; + /* Configure gigabit if it's supported */ + adv = phy_read(phydev, MII_CTRL1000); + if (adv < 0) + return adv; + + oldadv = adv; + adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + if (phydev->supported & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) { - adv = phy_read(phydev, MII_CTRL1000); - if (adv < 0) - return adv; - - oldadv = adv; - adv &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); adv |= ethtool_adv_to_mii_ctrl1000_t(advertise); - - if (adv != oldadv) { - err = phy_write(phydev, MII_CTRL1000, adv); - - if (err < 0) - return err; + if (adv != oldadv) changed = 1; - } } + err = phy_write(phydev, MII_CTRL1000, adv); + if (err < 0) + return err; + return changed; } @@ -855,6 +866,22 @@ int genphy_config_aneg(struct phy_device *phydev) } EXPORT_SYMBOL(genphy_config_aneg); +/** + * genphy_aneg_done - return auto-negotiation status + * @phydev: target phy_device struct + * + * Description: Reads the status register and returns 0 either if + * auto-negotiation is incomplete, or if there was an error. + * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. + */ +int genphy_aneg_done(struct phy_device *phydev) +{ + int retval = phy_read(phydev, MII_BMSR); + + return (retval < 0) ? retval : (retval & BMSR_ANEGCOMPLETE); +} +EXPORT_SYMBOL(genphy_aneg_done); + static int gen10g_config_aneg(struct phy_device *phydev) { return 0; @@ -906,6 +933,8 @@ int genphy_read_status(struct phy_device *phydev) int err; int lpa; int lpagb = 0; + int common_adv; + int common_adv_gb = 0; /* Update the link, but return if there was an error */ err = genphy_update_link(phydev); @@ -927,7 +956,7 @@ int genphy_read_status(struct phy_device *phydev) phydev->lp_advertising = mii_stat1000_to_ethtool_lpa_t(lpagb); - lpagb &= adv << 2; + common_adv_gb = lpagb & adv << 2; } lpa = phy_read(phydev, MII_LPA); @@ -940,25 +969,25 @@ int genphy_read_status(struct phy_device *phydev) if (adv < 0) return adv; - lpa &= adv; + common_adv = lpa & adv; phydev->speed = SPEED_10; phydev->duplex = DUPLEX_HALF; phydev->pause = 0; phydev->asym_pause = 0; - if (lpagb & (LPA_1000FULL | LPA_1000HALF)) { + if (common_adv_gb & (LPA_1000FULL | LPA_1000HALF)) { phydev->speed = SPEED_1000; - if (lpagb & LPA_1000FULL) + if (common_adv_gb & LPA_1000FULL) phydev->duplex = DUPLEX_FULL; - } else if (lpa & (LPA_100FULL | LPA_100HALF)) { + } else if (common_adv & (LPA_100FULL | LPA_100HALF)) { phydev->speed = SPEED_100; - if (lpa & LPA_100FULL) + if (common_adv & LPA_100FULL) phydev->duplex = DUPLEX_FULL; } else - if (lpa & LPA_10FULL) + if (common_adv & LPA_10FULL) phydev->duplex = DUPLEX_FULL; if (phydev->duplex == DUPLEX_FULL) { @@ -1018,6 +1047,27 @@ static int gen10g_read_status(struct phy_device *phydev) return 0; } +/** + * genphy_soft_reset - software reset the PHY via BMCR_RESET bit + * @phydev: target phy_device struct + * + * Description: Perform a software PHY reset using the standard + * BMCR_RESET bit and poll for the reset bit to be cleared. + * + * Returns: 0 on success, < 0 on failure + */ +int genphy_soft_reset(struct phy_device *phydev) +{ + int ret; + + ret = phy_write(phydev, MII_BMCR, BMCR_RESET); + if (ret < 0) + return ret; + + return phy_poll_reset(phydev); +} +EXPORT_SYMBOL(genphy_soft_reset); + static int genphy_config_init(struct phy_device *phydev) { int val; @@ -1064,6 +1114,12 @@ static int genphy_config_init(struct phy_device *phydev) return 0; } +static int gen10g_soft_reset(struct phy_device *phydev) +{ + /* Do nothing for now */ + return 0; +} + static int gen10g_config_init(struct phy_device *phydev) { /* Temporarily just say we support everything */ @@ -1238,9 +1294,11 @@ static struct phy_driver genphy_driver[] = { .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, .name = "Generic PHY", + .soft_reset = genphy_soft_reset, .config_init = genphy_config_init, .features = 0, .config_aneg = genphy_config_aneg, + .aneg_done = genphy_aneg_done, .read_status = genphy_read_status, .suspend = genphy_suspend, .resume = genphy_resume, @@ -1249,6 +1307,7 @@ static struct phy_driver genphy_driver[] = { .phy_id = 0xffffffff, .phy_id_mask = 0xffffffff, .name = "Generic 10G PHY", + .soft_reset = gen10g_soft_reset, .config_init = gen10g_config_init, .features = 0, .config_aneg = gen10g_config_aneg, diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c index 28407426fd6f..aea92f02401b 100644 --- a/drivers/net/team/team.c +++ b/drivers/net/team/team.c @@ -1540,16 +1540,10 @@ static int team_init(struct net_device *dev) mutex_init(&team->lock); team_set_no_mode(team); - team->pcpu_stats = alloc_percpu(struct team_pcpu_stats); + team->pcpu_stats = netdev_alloc_pcpu_stats(struct team_pcpu_stats); if (!team->pcpu_stats) return -ENOMEM; - for_each_possible_cpu(i) { - struct team_pcpu_stats *team_stats; - team_stats = per_cpu_ptr(team->pcpu_stats, i); - u64_stats_init(&team_stats->syncp); - } - for (i = 0; i < TEAM_PORT_HASHENTRIES; i++) INIT_HLIST_HEAD(&team->en_port_hlist[i]); INIT_LIST_HEAD(&team->port_list); @@ -1648,7 +1642,7 @@ static netdev_tx_t team_xmit(struct sk_buff *skb, struct net_device *dev) } static u16 team_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { /* * 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 44c4db8450f0..26f8635b027d 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -366,7 +366,7 @@ static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash) * hope the rxq no. may help here. */ static u16 tun_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { struct tun_struct *tun = netdev_priv(dev); struct tun_flow_entry *e; @@ -1686,7 +1686,9 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) TUN_USER_FEATURES | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX; dev->features = dev->hw_features; - dev->vlan_features = dev->features; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_STAG_TX); INIT_LIST_HEAD(&tun->disabled); err = tun_attach(tun, file, false); diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 6b638a066c1d..7e7269fd3707 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -292,6 +292,21 @@ config USB_NET_SR9700 This option adds support for CoreChip-sz SR9700 based USB 1.1 10/100 Ethernet adapters. +config USB_NET_SR9800 + tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices" + depends on USB_USBNET + select CRC32 + ---help--- + Say Y if you want to use one of the following 100Mbps USB Ethernet + device based on the CoreChip-sz SR9800 chip. + + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + + To compile this driver as a module, choose M here: the + module will be called sr9800. + config USB_NET_SMSC75XX tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" depends on USB_USBNET diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index b17b5e88bbaf..433f0a00c683 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o obj-$(CONFIG_USB_NET_SR9700) += sr9700.o +obj-$(CONFIG_USB_NET_SR9800) += sr9800.o obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 9765a7d4766d..5d194093f3e1 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -917,7 +917,8 @@ static const struct driver_info ax88178_info = { .status = asix_status, .link_reset = ax88178_link_reset, .reset = ax88178_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | + FLAG_MULTI_PACKET, .rx_fixup = asix_rx_fixup_common, .tx_fixup = asix_tx_fixup, }; diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index d6f64dad05bc..d2e6fdb25e28 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -1118,6 +1118,10 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) u16 hdr_off; u32 *pkt_hdr; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + skb_trim(skb, skb->len - 4); memcpy(&rx_hdr, skb_tail_pointer(skb), 4); le32_to_cpus(&rx_hdr); @@ -1391,6 +1395,19 @@ static const struct driver_info ax88178a_info = { .tx_fixup = ax88179_tx_fixup, }; +static const struct driver_info dlink_dub1312_info = { + .description = "D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter", + .bind = ax88179_bind, + .unbind = ax88179_unbind, + .status = ax88179_status, + .link_reset = ax88179_link_reset, + .reset = ax88179_reset, + .stop = ax88179_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88179_rx_fixup, + .tx_fixup = ax88179_tx_fixup, +}; + static const struct driver_info sitecom_info = { .description = "Sitecom USB 3.0 to Gigabit Adapter", .bind = ax88179_bind, @@ -1417,6 +1434,19 @@ static const struct driver_info samsung_info = { .tx_fixup = ax88179_tx_fixup, }; +static const struct driver_info lenovo_info = { + .description = "Lenovo OneLinkDock Gigabit LAN", + .bind = ax88179_bind, + .unbind = ax88179_unbind, + .status = ax88179_status, + .link_reset = ax88179_link_reset, + .reset = ax88179_reset, + .stop = ax88179_stop, + .flags = FLAG_ETHER | FLAG_FRAMING_AX, + .rx_fixup = ax88179_rx_fixup, + .tx_fixup = ax88179_tx_fixup, +}; + static const struct usb_device_id products[] = { { /* ASIX AX88179 10/100/1000 */ @@ -1427,6 +1457,10 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0b95, 0x178a), .driver_info = (unsigned long)&ax88178a_info, }, { + /* D-Link DUB-1312 USB 3.0 to Gigabit Ethernet Adapter */ + USB_DEVICE(0x2001, 0x4a00), + .driver_info = (unsigned long)&dlink_dub1312_info, +}, { /* Sitecom USB 3.0 to Gigabit Adapter */ USB_DEVICE(0x0df6, 0x0072), .driver_info = (unsigned long)&sitecom_info, @@ -1434,6 +1468,10 @@ static const struct usb_device_id products[] = { /* Samsung USB Ethernet Adapter */ USB_DEVICE(0x04e8, 0xa100), .driver_info = (unsigned long)&samsung_info, +}, { + /* Lenovo OneLinkDock Gigabit LAN */ + USB_DEVICE(0x17ef, 0x304b), + .driver_info = (unsigned long)&lenovo_info, }, { }, }; diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index e4a8a93fbaf7..1cc24e6f23e2 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -84,6 +84,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) u32 size; u32 count; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + header = (struct gl_header *) skb->data; // get the packet count of the received skb diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 1a482344b3f5..660bd5ea9fc0 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -1201,16 +1201,18 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) struct hso_serial *serial = urb->context; int status = urb->status; + D4("\n--- Got serial_read_bulk callback %02x ---", status); + /* sanity check */ if (!serial) { D1("serial == NULL"); return; - } else if (status) { + } + if (status) { handle_usb_error(status, __func__, serial->parent); return; } - D4("\n--- Got serial_read_bulk callback %02x ---", status); D1("Actual length = %d\n", urb->actual_length); DUMP1(urb->transfer_buffer, urb->actual_length); @@ -1218,25 +1220,13 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) if (serial->port.count == 0) return; - if (status == 0) { - if (serial->parent->port_spec & HSO_INFO_CRC_BUG) - fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); - /* Valid data, handle RX data */ - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; - put_rxbuf_data_and_resubmit_bulk_urb(serial); - spin_unlock(&serial->serial_lock); - } else if (status == -ENOENT || status == -ECONNRESET) { - /* Unlinked - check for throttled port. */ - D2("Port %d, successfully unlinked urb", serial->minor); - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - hso_resubmit_rx_bulk_urb(serial, urb); - spin_unlock(&serial->serial_lock); - } else { - D2("Port %d, status = %d for read urb", serial->minor, status); - return; - } + if (serial->parent->port_spec & HSO_INFO_CRC_BUG) + fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); + /* Valid data, handle RX data */ + spin_lock(&serial->serial_lock); + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; + put_rxbuf_data_and_resubmit_bulk_urb(serial); + spin_unlock(&serial->serial_lock); } /* diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index acfcc32b323d..8f37efd2d2fb 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -210,7 +210,7 @@ static int vl600_rx_fixup(struct usbnet *dev, struct sk_buff *skb) * (0x86dd) so Linux can understand it. */ if ((buf->data[sizeof(*ethhdr)] & 0xf0) == 0x60) - ethhdr->h_proto = __constant_htons(ETH_P_IPV6); + ethhdr->h_proto = htons(ETH_P_IPV6); } if (count) { diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index a305a7b2dae6..82d844a8ebd0 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -526,8 +526,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { u8 status; - if (skb->len == 0) { - dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) { + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); return 0; } diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 0a85d9227775..4cbdb1307f3e 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -364,6 +364,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) struct nc_trailer *trailer; u16 hdr_len, packet_len; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + if (!(skb->len & 0x01)) { netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n", skb->len, dev->net->hard_header_len, dev->hard_mtu, diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 23bdd5b9274d..313cb6cd4848 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { __be16 proto; - /* usbnet rx_complete guarantees that skb->len is at least - * hard_header_len, so we can inspect the dest address without - * checking skb->len - */ + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + switch (skb->data[0] & 0xf0) { case 0x40: proto = htons(ETH_P_IP); @@ -712,6 +712,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x1255, 3)}, {QMI_FIXED_INTF(0x19d2, 0x1255, 4)}, {QMI_FIXED_INTF(0x19d2, 0x1256, 4)}, + {QMI_FIXED_INTF(0x19d2, 0x1270, 5)}, /* ZTE MF667 */ {QMI_FIXED_INTF(0x19d2, 0x1401, 2)}, {QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */ {QMI_FIXED_INTF(0x19d2, 0x1424, 2)}, @@ -723,6 +724,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ + {QMI_FIXED_INTF(0x1199, 0x9051, 8)}, /* Netgear AirCard 340U */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ @@ -730,6 +732,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */ {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */ + {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index e8fac732c6f1..aa1d5b2e9c30 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -21,9 +21,10 @@ #include <linux/list.h> #include <linux/ip.h> #include <linux/ipv6.h> +#include <net/ip6_checksum.h> /* Version Information */ -#define DRIVER_VERSION "v1.04.0 (2014/01/15)" +#define DRIVER_VERSION "v1.06.0 (2014/03/03)" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" @@ -59,9 +60,11 @@ #define PLA_TCR0 0xe610 #define PLA_TCR1 0xe612 #define PLA_TXFIFO_CTRL 0xe618 -#define PLA_RSTTELLY 0xe800 +#define PLA_RSTTALLY 0xe800 #define PLA_CR 0xe813 #define PLA_CRWECR 0xe81c +#define PLA_CONFIG12 0xe81e /* CONFIG1, CONFIG2 */ +#define PLA_CONFIG34 0xe820 /* CONFIG3, CONFIG4 */ #define PLA_CONFIG5 0xe822 #define PLA_PHY_PWR 0xe84c #define PLA_OOB_CTRL 0xe84f @@ -69,7 +72,7 @@ #define PLA_MISC_0 0xe858 #define PLA_MISC_1 0xe85a #define PLA_OCP_GPHY_BASE 0xe86c -#define PLA_TELLYCNT 0xe890 +#define PLA_TALLYCNT 0xe890 #define PLA_SFF_STS_7 0xe8de #define PLA_PHYSTATUS 0xe908 #define PLA_BP_BA 0xfc26 @@ -177,6 +180,9 @@ /* PLA_TCR1 */ #define VERSION_MASK 0x7cf0 +/* PLA_RSTTALLY */ +#define TALLY_RESET 0x0001 + /* PLA_CR */ #define CR_RST 0x10 #define CR_RE 0x08 @@ -216,7 +222,14 @@ /* PAL_BDC_CR */ #define ALDPS_PROXY_MODE 0x0001 +/* PLA_CONFIG34 */ +#define LINK_ON_WAKE_EN 0x0010 +#define LINK_OFF_WAKE_EN 0x0008 + /* PLA_CONFIG5 */ +#define BWF_EN 0x0040 +#define MWF_EN 0x0020 +#define UWF_EN 0x0010 #define LAN_WAKE_EN 0x0002 /* PLA_LED_FEATURE */ @@ -436,6 +449,9 @@ enum rtl8152_flags { RTL8152_SET_RX_MODE, WORK_ENABLE, RTL8152_LINK_CHG, + SELECTIVE_SUSPEND, + PHY_RESET, + SCHEDULE_TASKLET, }; /* Define these values to match your device */ @@ -452,11 +468,37 @@ enum rtl8152_flags { #define REALTEK_USB_DEVICE(vend, prod) \ USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC) +struct tally_counter { + __le64 tx_packets; + __le64 rx_packets; + __le64 tx_errors; + __le32 rx_errors; + __le16 rx_missed; + __le16 align_errors; + __le32 tx_one_collision; + __le32 tx_multi_collision; + __le64 rx_unicast; + __le64 rx_broadcast; + __le32 rx_multicast; + __le16 tx_aborted; + __le16 tx_underun; +}; + struct rx_desc { __le32 opts1; #define RX_LEN_MASK 0x7fff + __le32 opts2; +#define RD_UDP_CS (1 << 23) +#define RD_TCP_CS (1 << 22) +#define RD_IPV6_CS (1 << 20) +#define RD_IPV4_CS (1 << 19) + __le32 opts3; +#define IPF (1 << 23) /* IP checksum fail */ +#define UDPF (1 << 22) /* UDP checksum fail */ +#define TCPF (1 << 21) /* TCP checksum fail */ + __le32 opts4; __le32 opts5; __le32 opts6; @@ -466,13 +508,21 @@ struct tx_desc { __le32 opts1; #define TX_FS (1 << 31) /* First segment of a packet */ #define TX_LS (1 << 30) /* Final segment of a packet */ -#define TX_LEN_MASK 0x3ffff +#define GTSENDV4 (1 << 28) +#define GTSENDV6 (1 << 27) +#define GTTCPHO_SHIFT 18 +#define GTTCPHO_MAX 0x7fU +#define TX_LEN_MAX 0x3ffffU __le32 opts2; #define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */ #define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */ #define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */ #define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */ +#define MSS_SHIFT 17 +#define MSS_MAX 0x7ffU +#define TCPHO_SHIFT 17 +#define TCPHO_MAX 0x7ffU }; struct r8152; @@ -514,11 +564,13 @@ struct r8152 { void (*init)(struct r8152 *); int (*enable)(struct r8152 *); void (*disable)(struct r8152 *); + void (*up)(struct r8152 *); void (*down)(struct r8152 *); void (*unload)(struct r8152 *); } rtl_ops; int intr_interval; + u32 saved_wolopts; u32 msg_enable; u32 tx_qlen; u16 ocp_base; @@ -537,12 +589,21 @@ enum rtl_version { RTL_VER_MAX }; +enum tx_csum_stat { + TX_CSUM_SUCCESS = 0, + TX_CSUM_TSO, + TX_CSUM_NONE +}; + /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). * The RTL chips use a 64 element hash table based on the Ethernet CRC. */ static const int multicast_filter_limit = 32; static unsigned int rx_buf_sz = 16384; +#define RTL_LIMITED_TSO_SIZE (rx_buf_sz - sizeof(struct tx_desc) - \ + VLAN_ETH_HLEN - VLAN_HLEN) + static int get_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) { @@ -580,6 +641,7 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) value, index, tmp, size, 500); kfree(tmp); + return ret; } @@ -865,11 +927,21 @@ static u16 sram_read(struct r8152 *tp, u16 addr) static int read_mii_word(struct net_device *netdev, int phy_id, int reg) { struct r8152 *tp = netdev_priv(netdev); + int ret; if (phy_id != R8152_PHY_ID) return -EINVAL; - return r8152_mdio_read(tp, reg); + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out; + + ret = r8152_mdio_read(tp, reg); + + usb_autopm_put_interface(tp->intf); + +out: + return ret; } static @@ -880,7 +952,12 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) if (phy_id != R8152_PHY_ID) return; + if (usb_autopm_get_interface(tp->intf) < 0) + return; + r8152_mdio_write(tp, reg, val); + + usb_autopm_put_interface(tp->intf); } static @@ -889,11 +966,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); static inline void set_ethernet_addr(struct r8152 *tp) { struct net_device *dev = tp->netdev; + int ret; u8 node_id[8] = {0}; - if (pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id) < 0) + if (tp->version == RTL_VER_01) + ret = pla_ocp_read(tp, PLA_IDR, sizeof(node_id), node_id); + else + ret = pla_ocp_read(tp, PLA_BACKUP, sizeof(node_id), node_id); + + if (ret < 0) { netif_notice(tp, probe, dev, "inet addr fail\n"); - else { + } else { + if (tp->version != RTL_VER_01) { + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, + CRWECR_CONFIG); + pla_ocp_write(tp, PLA_IDR, BYTE_EN_SIX_BYTES, + sizeof(node_id), node_id); + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, + CRWECR_NORAML); + } + memcpy(dev->dev_addr, node_id, dev->addr_len); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); } @@ -916,15 +1008,9 @@ static int rtl8152_set_mac_address(struct net_device *netdev, void *p) return 0; } -static struct net_device_stats *rtl8152_get_stats(struct net_device *dev) -{ - return &dev->stats; -} - static void read_bulk_callback(struct urb *urb) { struct net_device *netdev; - unsigned long flags; int status = urb->status; struct rx_agg *agg; struct r8152 *tp; @@ -951,14 +1037,16 @@ static void read_bulk_callback(struct urb *urb) if (!netif_carrier_ok(netdev)) return; + usb_mark_last_busy(tp->udev); + switch (status) { case 0: if (urb->actual_length < ETH_ZLEN) break; - spin_lock_irqsave(&tp->rx_lock, flags); + spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); - spin_unlock_irqrestore(&tp->rx_lock, flags); + spin_unlock(&tp->rx_lock); tasklet_schedule(&tp->tl); return; case -ESHUTDOWN: @@ -981,9 +1069,9 @@ static void read_bulk_callback(struct urb *urb) if (result == -ENODEV) { netif_device_detach(tp->netdev); } else if (result) { - spin_lock_irqsave(&tp->rx_lock, flags); + spin_lock(&tp->rx_lock); list_add_tail(&agg->list, &tp->rx_done); - spin_unlock_irqrestore(&tp->rx_lock, flags); + spin_unlock(&tp->rx_lock); tasklet_schedule(&tp->tl); } } @@ -991,7 +1079,7 @@ static void read_bulk_callback(struct urb *urb) static void write_bulk_callback(struct urb *urb) { struct net_device_stats *stats; - unsigned long flags; + struct net_device *netdev; struct tx_agg *agg; struct r8152 *tp; int status = urb->status; @@ -1004,21 +1092,24 @@ static void write_bulk_callback(struct urb *urb) if (!tp) return; - stats = rtl8152_get_stats(tp->netdev); + netdev = tp->netdev; + stats = &netdev->stats; if (status) { if (net_ratelimit()) - netdev_warn(tp->netdev, "Tx status %d\n", status); + netdev_warn(netdev, "Tx status %d\n", status); stats->tx_errors += agg->skb_num; } else { stats->tx_packets += agg->skb_num; stats->tx_bytes += agg->skb_len; } - spin_lock_irqsave(&tp->tx_lock, flags); + spin_lock(&tp->tx_lock); list_add_tail(&agg->list, &tp->tx_free); - spin_unlock_irqrestore(&tp->tx_lock, flags); + spin_unlock(&tp->tx_lock); - if (!netif_carrier_ok(tp->netdev)) + usb_autopm_put_interface_async(tp->intf); + + if (!netif_carrier_ok(netdev)) return; if (!test_bit(WORK_ENABLE, &tp->flags)) @@ -1223,6 +1314,9 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) struct tx_agg *agg = NULL; unsigned long flags; + if (list_empty(&tp->tx_free)) + return NULL; + spin_lock_irqsave(&tp->tx_lock, flags); if (!list_empty(&tp->tx_free)) { struct list_head *cursor; @@ -1236,24 +1330,138 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp) return agg; } -static void -r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) +static inline __be16 get_protocol(struct sk_buff *skb) +{ + __be16 protocol; + + if (skb->protocol == htons(ETH_P_8021Q)) + protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; + else + protocol = skb->protocol; + + return protocol; +} + +/* + * r8152_csum_workaround() + * The hw limites the value the transport offset. When the offset is out of the + * range, calculate the checksum by sw. + */ +static void r8152_csum_workaround(struct r8152 *tp, struct sk_buff *skb, + struct sk_buff_head *list) +{ + if (skb_shinfo(skb)->gso_size) { + netdev_features_t features = tp->netdev->features; + struct sk_buff_head seg_list; + struct sk_buff *segs, *nskb; + + features &= ~(NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO); + segs = skb_gso_segment(skb, features); + if (IS_ERR(segs) || !segs) + goto drop; + + __skb_queue_head_init(&seg_list); + + do { + nskb = segs; + segs = segs->next; + nskb->next = NULL; + __skb_queue_tail(&seg_list, nskb); + } while (segs); + + skb_queue_splice(&seg_list, list); + dev_kfree_skb(skb); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + if (skb_checksum_help(skb) < 0) + goto drop; + + __skb_queue_head(list, skb); + } else { + struct net_device_stats *stats; + +drop: + stats = &tp->netdev->stats; + stats->tx_dropped++; + dev_kfree_skb(skb); + } +} + +/* + * msdn_giant_send_check() + * According to the document of microsoft, the TCP Pseudo Header excludes the + * packet length for IPv6 TCP large packets. + */ +static int msdn_giant_send_check(struct sk_buff *skb) { - memset(desc, 0, sizeof(*desc)); + const struct ipv6hdr *ipv6h; + struct tcphdr *th; + int ret; - desc->opts1 = cpu_to_le32((skb->len & TX_LEN_MASK) | TX_FS | TX_LS); + ret = skb_cow_head(skb, 0); + if (ret) + return ret; - if (skb->ip_summed == CHECKSUM_PARTIAL) { - __be16 protocol; + ipv6h = ipv6_hdr(skb); + th = tcp_hdr(skb); + + th->check = 0; + th->check = ~tcp_v6_check(0, &ipv6h->saddr, &ipv6h->daddr, 0); + + return ret; +} + +static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, + struct sk_buff *skb, u32 len, u32 transport_offset) +{ + u32 mss = skb_shinfo(skb)->gso_size; + u32 opts1, opts2 = 0; + int ret = TX_CSUM_SUCCESS; + + WARN_ON_ONCE(len > TX_LEN_MAX); + + opts1 = len | TX_FS | TX_LS; + + if (mss) { + if (transport_offset > GTTCPHO_MAX) { + netif_warn(tp, tx_err, tp->netdev, + "Invalid transport offset 0x%x for TSO\n", + transport_offset); + ret = TX_CSUM_TSO; + goto unavailable; + } + + switch (get_protocol(skb)) { + case htons(ETH_P_IP): + opts1 |= GTSENDV4; + break; + + case htons(ETH_P_IPV6): + if (msdn_giant_send_check(skb)) { + ret = TX_CSUM_TSO; + goto unavailable; + } + opts1 |= GTSENDV6; + break; + + default: + WARN_ON_ONCE(1); + break; + } + + opts1 |= transport_offset << GTTCPHO_SHIFT; + opts2 |= min(mss, MSS_MAX) << MSS_SHIFT; + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { u8 ip_protocol; - u32 opts2 = 0; - if (skb->protocol == htons(ETH_P_8021Q)) - protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto; - else - protocol = skb->protocol; + if (transport_offset > TCPHO_MAX) { + netif_warn(tp, tx_err, tp->netdev, + "Invalid transport offset 0x%x\n", + transport_offset); + ret = TX_CSUM_NONE; + goto unavailable; + } - switch (protocol) { + switch (get_protocol(skb)) { case htons(ETH_P_IP): opts2 |= IPV4_CS; ip_protocol = ip_hdr(skb)->protocol; @@ -1269,24 +1477,34 @@ r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc, struct sk_buff *skb) break; } - if (ip_protocol == IPPROTO_TCP) { + if (ip_protocol == IPPROTO_TCP) opts2 |= TCP_CS; - opts2 |= (skb_transport_offset(skb) & 0x7fff) << 17; - } else if (ip_protocol == IPPROTO_UDP) { + else if (ip_protocol == IPPROTO_UDP) opts2 |= UDP_CS; - } else { + else WARN_ON_ONCE(1); - } - desc->opts2 = cpu_to_le32(opts2); + opts2 |= transport_offset << TCPHO_SHIFT; } + + desc->opts2 = cpu_to_le32(opts2); + desc->opts1 = cpu_to_le32(opts1); + +unavailable: + return ret; } static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) { - int remain; + struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; + int remain, ret; u8 *tx_data; + __skb_queue_head_init(&skb_head); + spin_lock(&tx_queue->lock); + skb_queue_splice_init(tx_queue, &skb_head); + spin_unlock(&tx_queue->lock); + tx_data = agg->head; agg->skb_num = agg->skb_len = 0; remain = rx_buf_sz; @@ -1295,32 +1513,56 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) struct tx_desc *tx_desc; struct sk_buff *skb; unsigned int len; + u32 offset; - skb = skb_dequeue(&tp->tx_queue); + skb = __skb_dequeue(&skb_head); if (!skb) break; - remain -= sizeof(*tx_desc); - len = skb->len; - if (remain < len) { - skb_queue_head(&tp->tx_queue, skb); + len = skb->len + sizeof(*tx_desc); + + if (len > remain) { + __skb_queue_head(&skb_head, skb); break; } tx_data = tx_agg_align(tx_data); tx_desc = (struct tx_desc *)tx_data; + + offset = (u32)skb_transport_offset(skb); + + if (r8152_tx_csum(tp, tx_desc, skb, skb->len, offset)) { + r8152_csum_workaround(tp, skb, &skb_head); + continue; + } + tx_data += sizeof(*tx_desc); - r8152_tx_csum(tp, tx_desc, skb); - memcpy(tx_data, skb->data, len); - agg->skb_num++; + len = skb->len; + if (skb_copy_bits(skb, 0, tx_data, len) < 0) { + struct net_device_stats *stats = &tp->netdev->stats; + + stats->tx_dropped++; + dev_kfree_skb_any(skb); + tx_data -= sizeof(*tx_desc); + continue; + } + + tx_data += len; agg->skb_len += len; + agg->skb_num++; + dev_kfree_skb_any(skb); - tx_data += len; remain = rx_buf_sz - (int)(tx_agg_align(tx_data) - agg->head); } + if (!skb_queue_empty(&skb_head)) { + spin_lock(&tx_queue->lock); + skb_queue_splice(&skb_head, tx_queue); + spin_unlock(&tx_queue->lock); + } + netif_tx_lock(tp->netdev); if (netif_queue_stopped(tp->netdev) && @@ -1329,20 +1571,67 @@ static int r8152_tx_agg_fill(struct r8152 *tp, struct tx_agg *agg) netif_tx_unlock(tp->netdev); + ret = usb_autopm_get_interface_async(tp->intf); + if (ret < 0) + goto out_tx_fill; + usb_fill_bulk_urb(agg->urb, tp->udev, usb_sndbulkpipe(tp->udev, 2), agg->head, (int)(tx_data - (u8 *)agg->head), (usb_complete_t)write_bulk_callback, agg); - return usb_submit_urb(agg->urb, GFP_ATOMIC); + ret = usb_submit_urb(agg->urb, GFP_ATOMIC); + if (ret < 0) + usb_autopm_put_interface_async(tp->intf); + +out_tx_fill: + return ret; +} + +static u8 r8152_rx_csum(struct r8152 *tp, struct rx_desc *rx_desc) +{ + u8 checksum = CHECKSUM_NONE; + u32 opts2, opts3; + + if (tp->version == RTL_VER_01) + goto return_result; + + opts2 = le32_to_cpu(rx_desc->opts2); + opts3 = le32_to_cpu(rx_desc->opts3); + + if (opts2 & RD_IPV4_CS) { + if (opts3 & IPF) + checksum = CHECKSUM_NONE; + else if ((opts2 & RD_UDP_CS) && (opts3 & UDPF)) + checksum = CHECKSUM_NONE; + else if ((opts2 & RD_TCP_CS) && (opts3 & TCPF)) + checksum = CHECKSUM_NONE; + else + checksum = CHECKSUM_UNNECESSARY; + } else if (RD_IPV6_CS) { + if ((opts2 & RD_UDP_CS) && !(opts3 & UDPF)) + checksum = CHECKSUM_UNNECESSARY; + else if ((opts2 & RD_TCP_CS) && !(opts3 & TCPF)) + checksum = CHECKSUM_UNNECESSARY; + } + +return_result: + return checksum; } static void rx_bottom(struct r8152 *tp) { unsigned long flags; - struct list_head *cursor, *next; + struct list_head *cursor, *next, rx_queue; + if (list_empty(&tp->rx_done)) + return; + + INIT_LIST_HEAD(&rx_queue); spin_lock_irqsave(&tp->rx_lock, flags); - list_for_each_safe(cursor, next, &tp->rx_done) { + list_splice_init(&tp->rx_done, &rx_queue); + spin_unlock_irqrestore(&tp->rx_lock, flags); + + list_for_each_safe(cursor, next, &rx_queue) { struct rx_desc *rx_desc; struct rx_agg *agg; int len_used = 0; @@ -1351,7 +1640,6 @@ static void rx_bottom(struct r8152 *tp) int ret; list_del_init(cursor); - spin_unlock_irqrestore(&tp->rx_lock, flags); agg = list_entry(cursor, struct rx_agg, list); urb = agg->urb; @@ -1364,7 +1652,7 @@ static void rx_bottom(struct r8152 *tp) while (urb->actual_length > len_used) { struct net_device *netdev = tp->netdev; - struct net_device_stats *stats; + struct net_device_stats *stats = &netdev->stats; unsigned int pkt_len; struct sk_buff *skb; @@ -1376,23 +1664,24 @@ static void rx_bottom(struct r8152 *tp) if (urb->actual_length < len_used) break; - stats = rtl8152_get_stats(netdev); - pkt_len -= CRC_SIZE; rx_data += sizeof(struct rx_desc); skb = netdev_alloc_skb_ip_align(netdev, pkt_len); if (!skb) { stats->rx_dropped++; - break; + goto find_next_rx; } + + skb->ip_summed = r8152_rx_csum(tp, rx_desc); memcpy(skb->data, rx_data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, netdev); - netif_rx(skb); + netif_receive_skb(skb); stats->rx_packets++; stats->rx_bytes += pkt_len; +find_next_rx: rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); rx_desc = (struct rx_desc *)rx_data; len_used = (int)(rx_data - (u8 *)agg->head); @@ -1401,13 +1690,13 @@ static void rx_bottom(struct r8152 *tp) submit: ret = r8152_submit_rx(tp, agg, GFP_ATOMIC); - spin_lock_irqsave(&tp->rx_lock, flags); if (ret && ret != -ENODEV) { - list_add_tail(&agg->list, next); + spin_lock_irqsave(&tp->rx_lock, flags); + list_add_tail(&agg->list, &tp->rx_done); + spin_unlock_irqrestore(&tp->rx_lock, flags); tasklet_schedule(&tp->tl); } } - spin_unlock_irqrestore(&tp->rx_lock, flags); } static void tx_bottom(struct r8152 *tp) @@ -1426,19 +1715,18 @@ static void tx_bottom(struct r8152 *tp) res = r8152_tx_agg_fill(tp, agg); if (res) { - struct net_device_stats *stats; - struct net_device *netdev; - unsigned long flags; - - netdev = tp->netdev; - stats = rtl8152_get_stats(netdev); + struct net_device *netdev = tp->netdev; if (res == -ENODEV) { netif_device_detach(netdev); } else { + struct net_device_stats *stats = &netdev->stats; + unsigned long flags; + netif_warn(tp, tx_err, netdev, "failed tx_urb %d\n", res); stats->tx_dropped += agg->skb_num; + spin_lock_irqsave(&tp->tx_lock, flags); list_add_tail(&agg->list, &tp->tx_free); spin_unlock_irqrestore(&tp->tx_lock, flags); @@ -1478,6 +1766,26 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags) return usb_submit_urb(agg->urb, mem_flags); } +static void rtl_drop_queued_tx(struct r8152 *tp) +{ + struct net_device_stats *stats = &tp->netdev->stats; + struct sk_buff_head skb_head, *tx_queue = &tp->tx_queue; + struct sk_buff *skb; + + if (skb_queue_empty(tx_queue)) + return; + + __skb_queue_head_init(&skb_head); + spin_lock_bh(&tx_queue->lock); + skb_queue_splice_init(tx_queue, &skb_head); + spin_unlock_bh(&tx_queue->lock); + + while ((skb = __skb_dequeue(&skb_head))) { + dev_kfree_skb(skb); + stats->tx_dropped++; + } +} + static void rtl8152_tx_timeout(struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); @@ -1541,7 +1849,7 @@ static void _rtl8152_set_rx_mode(struct net_device *netdev) } static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, - struct net_device *netdev) + struct net_device *netdev) { struct r8152 *tp = netdev_priv(netdev); @@ -1549,13 +1857,17 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb, skb_queue_tail(&tp->tx_queue, skb); - if (list_empty(&tp->tx_free) && - skb_queue_len(&tp->tx_queue) > tp->tx_qlen) + if (!list_empty(&tp->tx_free)) { + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + set_bit(SCHEDULE_TASKLET, &tp->flags); + schedule_delayed_work(&tp->schedule, 0); + } else { + usb_mark_last_busy(tp->udev); + tasklet_schedule(&tp->tl); + } + } else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) netif_stop_queue(netdev); - if (!list_empty(&tp->tx_free)) - tasklet_schedule(&tp->tl); - return NETDEV_TX_OK; } @@ -1613,6 +1925,18 @@ static void rtl_set_eee_plus(struct r8152 *tp) } } +static void rxdy_gated_en(struct r8152 *tp, bool enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); + if (enable) + ocp_data |= RXDY_GATED_EN; + else + ocp_data &= ~RXDY_GATED_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); +} + static int rtl_enable(struct r8152 *tp) { u32 ocp_data; @@ -1624,9 +1948,7 @@ static int rtl_enable(struct r8152 *tp) ocp_data |= CR_RE | CR_TE; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, false); INIT_LIST_HEAD(&tp->rx_done); ret = 0; @@ -1681,8 +2003,6 @@ static int rtl8153_enable(struct r8152 *tp) static void rtl8152_disable(struct r8152 *tp) { - struct net_device_stats *stats = rtl8152_get_stats(tp->netdev); - struct sk_buff *skb; u32 ocp_data; int i; @@ -1690,17 +2010,12 @@ static void rtl8152_disable(struct r8152 *tp) ocp_data &= ~RCR_ACPT_ALL; ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - while ((skb = skb_dequeue(&tp->tx_queue))) { - dev_kfree_skb(skb); - stats->tx_dropped++; - } + rtl_drop_queued_tx(tp); for (i = 0; i < RTL8152_MAX_TX; i++) usb_kill_urb(tp->tx_info[i].urb); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data |= RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, true); for (i = 0; i < 1000; i++) { ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); @@ -1721,18 +2036,209 @@ static void rtl8152_disable(struct r8152 *tp) rtl8152_nic_reset(tp); } +static void r8152_power_cut_en(struct r8152 *tp, bool enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); + if (enable) + ocp_data |= POWER_CUT; + else + ocp_data &= ~POWER_CUT; + ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); + ocp_data &= ~RESUME_INDICATE; + ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); +} + +#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST) + +static u32 __rtl_get_wol(struct r8152 *tp) +{ + u32 ocp_data; + u32 wolopts = 0; + + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5); + if (!(ocp_data & LAN_WAKE_EN)) + return 0; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); + if (ocp_data & LINK_ON_WAKE_EN) + wolopts |= WAKE_PHY; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); + if (ocp_data & UWF_EN) + wolopts |= WAKE_UCAST; + if (ocp_data & BWF_EN) + wolopts |= WAKE_BCAST; + if (ocp_data & MWF_EN) + wolopts |= WAKE_MCAST; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); + if (ocp_data & MAGIC_EN) + wolopts |= WAKE_MAGIC; + + return wolopts; +} + +static void __rtl_set_wol(struct r8152 *tp, u32 wolopts) +{ + u32 ocp_data; + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); + ocp_data &= ~LINK_ON_WAKE_EN; + if (wolopts & WAKE_PHY) + ocp_data |= LINK_ON_WAKE_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG5); + ocp_data &= ~(UWF_EN | BWF_EN | MWF_EN | LAN_WAKE_EN); + if (wolopts & WAKE_UCAST) + ocp_data |= UWF_EN; + if (wolopts & WAKE_BCAST) + ocp_data |= BWF_EN; + if (wolopts & WAKE_MCAST) + ocp_data |= MWF_EN; + if (wolopts & WAKE_ANY) + ocp_data |= LAN_WAKE_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG5, ocp_data); + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); + ocp_data &= ~MAGIC_EN; + if (wolopts & WAKE_MAGIC) + ocp_data |= MAGIC_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); + + if (wolopts & WAKE_ANY) + device_set_wakeup_enable(&tp->udev->dev, true); + else + device_set_wakeup_enable(&tp->udev->dev, false); +} + +static void rtl_runtime_suspend_enable(struct r8152 *tp, bool enable) +{ + if (enable) { + u32 ocp_data; + + __rtl_set_wol(tp, WAKE_ANY); + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_CONFIG); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CONFIG34); + ocp_data |= LINK_OFF_WAKE_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CONFIG34, ocp_data); + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); + } else { + __rtl_set_wol(tp, tp->saved_wolopts); + } +} + +static void rtl_phy_reset(struct r8152 *tp) +{ + u16 data; + int i; + + clear_bit(PHY_RESET, &tp->flags); + + data = r8152_mdio_read(tp, MII_BMCR); + + /* don't reset again before the previous one complete */ + if (data & BMCR_RESET) + return; + + data |= BMCR_RESET; + r8152_mdio_write(tp, MII_BMCR, data); + + for (i = 0; i < 50; i++) { + msleep(20); + if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) + break; + } +} + +static void rtl_clear_bp(struct r8152 *tp) +{ + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); + ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); + mdelay(3); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); + ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); +} + +static void r8153_clear_bp(struct r8152 *tp) +{ + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); + ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); + rtl_clear_bp(tp); +} + +static void r8153_teredo_off(struct r8152 *tp) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); + ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0); +} + +static void r8152b_disable_aldps(struct r8152 *tp) +{ + ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE); + msleep(20); +} + +static inline void r8152b_enable_aldps(struct r8152 *tp) +{ + ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | + LINKENA | DIS_SDSAVE); +} + +static void r8152b_hw_phy_cfg(struct r8152 *tp) +{ + u16 data; + + data = r8152_mdio_read(tp, MII_BMCR); + if (data & BMCR_PDOWN) { + data &= ~BMCR_PDOWN; + r8152_mdio_write(tp, MII_BMCR, data); + } + + r8152b_disable_aldps(tp); + + rtl_clear_bp(tp); + + r8152b_enable_aldps(tp); + set_bit(PHY_RESET, &tp->flags); +} + static void r8152b_exit_oob(struct r8152 *tp) { - u32 ocp_data; - int i; + u32 ocp_data; + int i; ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data &= ~RCR_ACPT_ALL; ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data |= RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, true); + r8153_teredo_off(tp); + r8152b_hw_phy_cfg(tp); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CRWECR, CRWECR_NORAML); ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CR, 0x00); @@ -1838,10 +2344,6 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); - ocp_data |= MAGIC_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); ocp_data |= CPCR_RX_VLAN; ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); @@ -1854,36 +2356,26 @@ static void r8152b_enter_oob(struct r8152 *tp) ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, false); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data |= RCR_APM | RCR_AM | RCR_AB; ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); } -static void r8152b_disable_aldps(struct r8152 *tp) -{ - ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPDNPS | LINKENA | DIS_SDSAVE); - msleep(20); -} - -static inline void r8152b_enable_aldps(struct r8152 *tp) -{ - ocp_reg_write(tp, OCP_ALDPS_CONFIG, ENPWRSAVE | ENPDNPS | - LINKENA | DIS_SDSAVE); -} - static void r8153_hw_phy_cfg(struct r8152 *tp) { u32 ocp_data; u16 data; ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); - r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); + data = r8152_mdio_read(tp, MII_BMCR); + if (data & BMCR_PDOWN) { + data &= ~BMCR_PDOWN; + r8152_mdio_write(tp, MII_BMCR, data); + } + + r8153_clear_bp(tp); if (tp->version == RTL_VER_03) { data = ocp_reg_read(tp, OCP_EEE_CFG); @@ -1919,9 +2411,11 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) data = sram_read(tp, SRAM_10M_AMP2); data |= AMP_DN; sram_write(tp, SRAM_10M_AMP2, data); + + set_bit(PHY_RESET, &tp->flags); } -static void r8153_u1u2en(struct r8152 *tp, int enable) +static void r8153_u1u2en(struct r8152 *tp, bool enable) { u8 u1u2[8]; @@ -1933,7 +2427,7 @@ static void r8153_u1u2en(struct r8152 *tp, int enable) usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); } -static void r8153_u2p3en(struct r8152 *tp, int enable) +static void r8153_u2p3en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -1945,7 +2439,7 @@ static void r8153_u2p3en(struct r8152 *tp, int enable) ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); } -static void r8153_power_cut_en(struct r8152 *tp, int enable) +static void r8153_power_cut_en(struct r8152 *tp, bool enable) { u32 ocp_data; @@ -1961,28 +2455,12 @@ static void r8153_power_cut_en(struct r8152 *tp, int enable) ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); } -static void r8153_teredo_off(struct r8152 *tp) -{ - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); - ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); - - ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0); -} - static void r8153_first_init(struct r8152 *tp) { u32 ocp_data; int i; - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data |= RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); - + rxdy_gated_en(tp, true); r8153_teredo_off(tp); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); @@ -2075,10 +2553,6 @@ static void r8153_enter_oob(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); - ocp_data |= MAGIC_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); ocp_data &= ~TEREDO_WAKE_MASK; ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); @@ -2095,11 +2569,7 @@ static void r8153_enter_oob(struct r8152 *tp) ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); - - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); - ocp_data &= ~RXDY_GATED_EN; - ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + rxdy_gated_en(tp, false); ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); ocp_data |= RCR_APM | RCR_AM | RCR_AB; @@ -2190,12 +2660,26 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) bmcr = BMCR_ANENABLE | BMCR_ANRESTART; } + if (test_bit(PHY_RESET, &tp->flags)) + bmcr |= BMCR_RESET; + if (tp->mii.supports_gmii) r8152_mdio_write(tp, MII_CTRL1000, gbcr); r8152_mdio_write(tp, MII_ADVERTISE, anar); r8152_mdio_write(tp, MII_BMCR, bmcr); + if (test_bit(PHY_RESET, &tp->flags)) { + int i; + + clear_bit(PHY_RESET, &tp->flags); + for (i = 0; i < 50; i++) { + msleep(20); + if ((r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET) == 0) + break; + } + } + out: return ret; @@ -2203,12 +2687,7 @@ out: static void rtl8152_down(struct r8152 *tp) { - u32 ocp_data; - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - ocp_data &= ~POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); - + r8152_power_cut_en(tp, false); r8152b_disable_aldps(tp); r8152b_enter_oob(tp); r8152b_enable_aldps(tp); @@ -2216,8 +2695,8 @@ static void rtl8152_down(struct r8152 *tp) static void rtl8153_down(struct r8152 *tp) { - r8153_u1u2en(tp, 0); - r8153_power_cut_en(tp, 0); + r8153_u1u2en(tp, false); + r8153_power_cut_en(tp, false); r8153_disable_aldps(tp); r8153_enter_oob(tp); r8153_enable_aldps(tp); @@ -2252,6 +2731,9 @@ static void rtl_work_func_t(struct work_struct *work) { struct r8152 *tp = container_of(work, struct r8152, schedule.work); + if (usb_autopm_get_interface(tp->intf) < 0) + return; + if (!test_bit(WORK_ENABLE, &tp->flags)) goto out1; @@ -2264,8 +2746,17 @@ static void rtl_work_func_t(struct work_struct *work) if (test_bit(RTL8152_SET_RX_MODE, &tp->flags)) _rtl8152_set_rx_mode(tp->netdev); + if (test_bit(SCHEDULE_TASKLET, &tp->flags) && + (tp->speed & LINK_STATUS)) { + clear_bit(SCHEDULE_TASKLET, &tp->flags); + tasklet_schedule(&tp->tl); + } + + if (test_bit(PHY_RESET, &tp->flags)) + rtl_phy_reset(tp); + out1: - return; + usb_autopm_put_interface(tp->intf); } static int rtl8152_open(struct net_device *netdev) @@ -2273,15 +2764,27 @@ static int rtl8152_open(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; - res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); - if (res) { - if (res == -ENODEV) - netif_device_detach(tp->netdev); - netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", - res); - return res; + res = alloc_all_mem(tp); + if (res) + goto out; + + res = usb_autopm_get_interface(tp->intf); + if (res < 0) { + free_all_mem(tp); + goto out; } + /* The WORK_ENABLE may be set when autoresume occurs */ + if (test_bit(WORK_ENABLE, &tp->flags)) { + clear_bit(WORK_ENABLE, &tp->flags); + usb_kill_urb(tp->intr_urb); + cancel_delayed_work_sync(&tp->schedule); + if (tp->speed & LINK_STATUS) + tp->rtl_ops.disable(tp); + } + + tp->rtl_ops.up(tp); + rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); @@ -2290,6 +2793,18 @@ static int rtl8152_open(struct net_device *netdev) netif_start_queue(netdev); set_bit(WORK_ENABLE, &tp->flags); + res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); + if (res) { + if (res == -ENODEV) + netif_device_detach(tp->netdev); + netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", + res); + free_all_mem(tp); + } + + usb_autopm_put_interface(tp->intf); + +out: return res; } @@ -2298,37 +2813,34 @@ static int rtl8152_close(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; - usb_kill_urb(tp->intr_urb); clear_bit(WORK_ENABLE, &tp->flags); + usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); netif_stop_queue(netdev); - tasklet_disable(&tp->tl); - tp->rtl_ops.disable(tp); - tasklet_enable(&tp->tl); - return res; -} + res = usb_autopm_get_interface(tp->intf); + if (res < 0) { + rtl_drop_queued_tx(tp); + } else { + /* + * The autosuspend may have been enabled and wouldn't + * be disable when autoresume occurs, because the + * netif_running() would be false. + */ + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_runtime_suspend_enable(tp, false); + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + } -static void rtl_clear_bp(struct r8152 *tp) -{ - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_BP_6, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_0, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_2, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_4, 0); - ocp_write_dword(tp, MCU_TYPE_USB, USB_BP_6, 0); - mdelay(3); - ocp_write_word(tp, MCU_TYPE_PLA, PLA_BP_BA, 0); - ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); -} + tasklet_disable(&tp->tl); + tp->rtl_ops.down(tp); + tasklet_enable(&tp->tl); + usb_autopm_put_interface(tp->intf); + } -static void r8153_clear_bp(struct r8152 *tp) -{ - ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); - ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); - rtl_clear_bp(tp); + free_all_mem(tp); + + return res; } static void r8152b_enable_eee(struct r8152 *tp) @@ -2379,18 +2891,18 @@ static void r8152b_enable_fc(struct r8152 *tp) r8152_mdio_write(tp, MII_ADVERTISE, anar); } -static void r8152b_hw_phy_cfg(struct r8152 *tp) +static void rtl_tally_reset(struct r8152 *tp) { - r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); - r8152b_disable_aldps(tp); + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY); + ocp_data |= TALLY_RESET; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RSTTALLY, ocp_data); } static void r8152b_init(struct r8152 *tp) { u32 ocp_data; - int i; - - rtl_clear_bp(tp); if (tp->version == RTL_VER_01) { ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); @@ -2398,17 +2910,7 @@ static void r8152b_init(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); } - r8152b_hw_phy_cfg(tp); - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - ocp_data &= ~POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); - ocp_data &= ~RESUME_INDICATE; - ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); - - r8152b_exit_oob(tp); + r8152_power_cut_en(tp, false); ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); ocp_data |= TX_10M_IDLE_EN | PFM_PWM_SWITCH; @@ -2424,14 +2926,7 @@ static void r8152b_init(struct r8152 *tp) r8152b_enable_eee(tp); r8152b_enable_aldps(tp); r8152b_enable_fc(tp); - - r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE | - BMCR_ANRESTART); - for (i = 0; i < 100; i++) { - udelay(100); - if (!(r8152_mdio_read(tp, MII_BMCR) & BMCR_RESET)) - break; - } + rtl_tally_reset(tp); /* enable rx aggregation */ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); @@ -2444,7 +2939,7 @@ static void r8153_init(struct r8152 *tp) u32 ocp_data; int i; - r8153_u1u2en(tp, 0); + r8153_u1u2en(tp, false); for (i = 0; i < 500; i++) { if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & @@ -2460,14 +2955,12 @@ static void r8153_init(struct r8152 *tp) msleep(20); } - r8153_u2p3en(tp, 0); + r8153_u2p3en(tp, false); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); ocp_data &= ~TIMER11_EN; ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); - r8153_clear_bp(tp); - ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); ocp_data &= ~LED_MODE_MASK; ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); @@ -2485,10 +2978,8 @@ static void r8153_init(struct r8152 *tp) ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); - r8153_power_cut_en(tp, 0); - r8153_u1u2en(tp, 1); - - r8153_first_init(tp); + r8153_power_cut_en(tp, false); + r8153_u1u2en(tp, true); ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO); ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO); @@ -2503,26 +2994,31 @@ static void r8153_init(struct r8152 *tp) r8153_enable_eee(tp); r8153_enable_aldps(tp); r8152b_enable_fc(tp); - - r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE | - BMCR_ANRESTART); + rtl_tally_reset(tp); } static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) { struct r8152 *tp = usb_get_intfdata(intf); - netif_device_detach(tp->netdev); + if (PMSG_IS_AUTO(message)) + set_bit(SELECTIVE_SUSPEND, &tp->flags); + else + netif_device_detach(tp->netdev); if (netif_running(tp->netdev)) { clear_bit(WORK_ENABLE, &tp->flags); usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); - tasklet_disable(&tp->tl); + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_runtime_suspend_enable(tp, true); + } else { + tasklet_disable(&tp->tl); + tp->rtl_ops.down(tp); + tasklet_enable(&tp->tl); + } } - tp->rtl_ops.down(tp); - return 0; } @@ -2530,22 +3026,77 @@ static int rtl8152_resume(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); - tp->rtl_ops.init(tp); - netif_device_attach(tp->netdev); + if (!test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + tp->rtl_ops.init(tp); + netif_device_attach(tp->netdev); + } + if (netif_running(tp->netdev)) { - rtl8152_set_speed(tp, AUTONEG_ENABLE, + if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) { + rtl_runtime_suspend_enable(tp, false); + clear_bit(SELECTIVE_SUSPEND, &tp->flags); + if (tp->speed & LINK_STATUS) + tp->rtl_ops.disable(tp); + } else { + tp->rtl_ops.up(tp); + rtl8152_set_speed(tp, AUTONEG_ENABLE, tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, DUPLEX_FULL); + } tp->speed = 0; netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); usb_submit_urb(tp->intr_urb, GFP_KERNEL); - tasklet_enable(&tp->tl); } return 0; } +static void rtl8152_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct r8152 *tp = netdev_priv(dev); + + if (usb_autopm_get_interface(tp->intf) < 0) + return; + + wol->supported = WAKE_ANY; + wol->wolopts = __rtl_get_wol(tp); + + usb_autopm_put_interface(tp->intf); +} + +static int rtl8152_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) +{ + struct r8152 *tp = netdev_priv(dev); + int ret; + + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out_set_wol; + + __rtl_set_wol(tp, wol->wolopts); + tp->saved_wolopts = wol->wolopts & WAKE_ANY; + + usb_autopm_put_interface(tp->intf); + +out_set_wol: + return ret; +} + +static u32 rtl8152_get_msglevel(struct net_device *dev) +{ + struct r8152 *tp = netdev_priv(dev); + + return tp->msg_enable; +} + +static void rtl8152_set_msglevel(struct net_device *dev, u32 value) +{ + struct r8152 *tp = netdev_priv(dev); + + tp->msg_enable = value; +} + static void rtl8152_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info) { @@ -2570,8 +3121,76 @@ int rtl8152_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) static int rtl8152_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct r8152 *tp = netdev_priv(dev); + int ret; - return rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); + ret = usb_autopm_get_interface(tp->intf); + if (ret < 0) + goto out; + + ret = rtl8152_set_speed(tp, cmd->autoneg, cmd->speed, cmd->duplex); + + usb_autopm_put_interface(tp->intf); + +out: + return ret; +} + +static const char rtl8152_gstrings[][ETH_GSTRING_LEN] = { + "tx_packets", + "rx_packets", + "tx_errors", + "rx_errors", + "rx_missed", + "align_errors", + "tx_single_collisions", + "tx_multi_collisions", + "rx_unicast", + "rx_broadcast", + "rx_multicast", + "tx_aborted", + "tx_underrun", +}; + +static int rtl8152_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(rtl8152_gstrings); + default: + return -EOPNOTSUPP; + } +} + +static void rtl8152_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct r8152 *tp = netdev_priv(dev); + struct tally_counter tally; + + generic_ocp_read(tp, PLA_TALLYCNT, sizeof(tally), &tally, MCU_TYPE_PLA); + + data[0] = le64_to_cpu(tally.tx_packets); + data[1] = le64_to_cpu(tally.rx_packets); + data[2] = le64_to_cpu(tally.tx_errors); + data[3] = le32_to_cpu(tally.rx_errors); + data[4] = le16_to_cpu(tally.rx_missed); + data[5] = le16_to_cpu(tally.align_errors); + data[6] = le32_to_cpu(tally.tx_one_collision); + data[7] = le32_to_cpu(tally.tx_multi_collision); + data[8] = le64_to_cpu(tally.rx_unicast); + data[9] = le64_to_cpu(tally.rx_broadcast); + data[10] = le32_to_cpu(tally.rx_multicast); + data[11] = le16_to_cpu(tally.tx_aborted); + data[12] = le16_to_cpu(tally.tx_underun); +} + +static void rtl8152_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + switch (stringset) { + case ETH_SS_STATS: + memcpy(data, *rtl8152_gstrings, sizeof(rtl8152_gstrings)); + break; + } } static struct ethtool_ops ops = { @@ -2579,13 +3198,24 @@ static struct ethtool_ops ops = { .get_settings = rtl8152_get_settings, .set_settings = rtl8152_set_settings, .get_link = ethtool_op_get_link, + .get_msglevel = rtl8152_get_msglevel, + .set_msglevel = rtl8152_set_msglevel, + .get_wol = rtl8152_get_wol, + .set_wol = rtl8152_set_wol, + .get_strings = rtl8152_get_strings, + .get_sset_count = rtl8152_get_sset_count, + .get_ethtool_stats = rtl8152_get_ethtool_stats, }; static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) { struct r8152 *tp = netdev_priv(netdev); struct mii_ioctl_data *data = if_mii(rq); - int res = 0; + int res; + + res = usb_autopm_get_interface(tp->intf); + if (res < 0) + goto out; switch (cmd) { case SIOCGMIIPHY: @@ -2608,6 +3238,9 @@ static int rtl8152_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) res = -EOPNOTSUPP; } + usb_autopm_put_interface(tp->intf); + +out: return res; } @@ -2660,22 +3293,13 @@ static void r8152b_get_version(struct r8152 *tp) static void rtl8152_unload(struct r8152 *tp) { - u32 ocp_data; - - if (tp->version != RTL_VER_01) { - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - ocp_data |= POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); - ocp_data &= ~RESUME_INDICATE; - ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); + if (tp->version != RTL_VER_01) + r8152_power_cut_en(tp, true); } static void rtl8153_unload(struct r8152 *tp) { - r8153_power_cut_en(tp, 1); + r8153_power_cut_en(tp, true); } static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) @@ -2690,6 +3314,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->init = r8152b_init; ops->enable = rtl8152_enable; ops->disable = rtl8152_disable; + ops->up = r8152b_exit_oob; ops->down = rtl8152_down; ops->unload = rtl8152_unload; ret = 0; @@ -2698,6 +3323,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->init = r8153_init; ops->enable = rtl8153_enable; ops->disable = rtl8152_disable; + ops->up = r8153_first_init; ops->down = rtl8153_down; ops->unload = rtl8153_unload; ret = 0; @@ -2713,6 +3339,7 @@ static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) ops->init = r8153_init; ops->enable = rtl8153_enable; ops->disable = rtl8152_disable; + ops->up = r8153_first_init; ops->down = rtl8153_down; ops->unload = rtl8153_unload; ret = 0; @@ -2764,9 +3391,15 @@ static int rtl8152_probe(struct usb_interface *intf, netdev->netdev_ops = &rtl8152_netdev_ops; netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; - netdev->features |= NETIF_F_IP_CSUM; - netdev->hw_features = NETIF_F_IP_CSUM; + netdev->features |= NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_FRAGLIST | NETIF_F_IPV6_CSUM | + NETIF_F_TSO6; + netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_FRAGLIST | + NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + SET_ETHTOOL_OPS(netdev, &ops); + netif_set_gso_max_size(netdev, RTL_LIMITED_TSO_SIZE); tp->mii.dev = netdev; tp->mii.mdio_read = read_mii_word; @@ -2776,14 +3409,12 @@ static int rtl8152_probe(struct usb_interface *intf, tp->mii.phy_id = R8152_PHY_ID; tp->mii.supports_gmii = 0; + intf->needs_remote_wakeup = 1; + r8152b_get_version(tp); tp->rtl_ops.init(tp); set_ethernet_addr(tp); - ret = alloc_all_mem(tp); - if (ret) - goto out; - usb_set_intfdata(intf, tp); ret = register_netdev(netdev); @@ -2792,6 +3423,12 @@ static int rtl8152_probe(struct usb_interface *intf, goto out1; } + tp->saved_wolopts = __rtl_get_wol(tp); + if (tp->saved_wolopts) + device_set_wakeup_enable(&udev->dev, true); + else + device_set_wakeup_enable(&udev->dev, false); + netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); return 0; @@ -2813,7 +3450,6 @@ static void rtl8152_disconnect(struct usb_interface *intf) tasklet_kill(&tp->tl); unregister_netdev(tp->netdev); tp->rtl_ops.unload(tp); - free_all_mem(tp); free_netdev(tp->netdev); } } @@ -2836,6 +3472,8 @@ static struct usb_driver rtl8152_driver = { .suspend = rtl8152_suspend, .resume = rtl8152_resume, .reset_resume = rtl8152_resume, + .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(rtl8152_driver); diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index a48bc0f20c1a..524a47a28120 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -492,6 +492,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind); */ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + /* peripheral may have batched packets to us... */ while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index f17b9e02dd34..d9e7892262fa 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -2106,6 +2106,10 @@ static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 rx_cmd_a, rx_cmd_b, align_count, size; struct sk_buff *ax_skb; diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 8dd54a0f7b29..424db65e4396 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -1723,6 +1723,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c new file mode 100644 index 000000000000..b94a0fbb8b3b --- /dev/null +++ b/drivers/net/usb/sr9800.c @@ -0,0 +1,874 @@ +/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices + * + * Author : Liu Junliang <liujunliang_ljl@163.com> + * + * Based on asix_common.c, asix_devices.c + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied.* + */ + +#include <linux/module.h> +#include <linux/kmod.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/ethtool.h> +#include <linux/workqueue.h> +#include <linux/mii.h> +#include <linux/usb.h> +#include <linux/crc32.h> +#include <linux/usb/usbnet.h> +#include <linux/slab.h> +#include <linux/if_vlan.h> + +#include "sr9800.h" + +static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int err; + + err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index, + data, size); + if ((err != size) && (err >= 0)) + err = -EINVAL; + + return err; +} + +static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int err; + + err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index, + data, size); + if ((err != size) && (err >= 0)) + err = -EINVAL; + + return err; +} + +static void +sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data, + size); +} + +static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + int offset = 0; + + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + + while (offset + sizeof(u32) < skb->len) { + struct sk_buff *sr_skb; + u16 size; + u32 header = get_unaligned_le32(skb->data + offset); + + offset += sizeof(u32); + /* get the packet length */ + size = (u16) (header & 0x7ff); + if (size != ((~header >> 16) & 0x07ff)) { + netdev_err(dev->net, "%s : Bad Header Length\n", + __func__); + return 0; + } + + if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || + (size + offset > skb->len)) { + netdev_err(dev->net, "%s : Bad RX Length %d\n", + __func__, size); + return 0; + } + sr_skb = netdev_alloc_skb_ip_align(dev->net, size); + if (!sr_skb) + return 0; + + skb_put(sr_skb, size); + memcpy(sr_skb->data, skb->data + offset, size); + usbnet_skb_return(dev, sr_skb); + + offset += (size + 1) & 0xfffe; + } + + if (skb->len != offset) { + netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__, + skb->len); + return 0; + } + + return 1; +} + +static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + gfp_t flags) +{ + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + u32 padbytes = 0xffff0000; + u32 packet_len; + int padlen; + + padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4; + + if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { + if ((headroom < 4) || (tailroom < padlen)) { + skb->data = memmove(skb->head + 4, skb->data, + skb->len); + skb_set_tail_pointer(skb, skb->len); + } + } else { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, 4, padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + skb_push(skb, 4); + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + cpu_to_le32s(&packet_len); + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); + + if (padlen) { + cpu_to_le32s(&padbytes); + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); + skb_put(skb, sizeof(padbytes)); + } + + return skb; +} + +static void sr_status(struct usbnet *dev, struct urb *urb) +{ + struct sr9800_int_data *event; + int link; + + if (urb->actual_length < 8) + return; + + event = urb->transfer_buffer; + link = event->link & 0x01; + if (netif_carrier_ok(dev->net) != link) { + usbnet_link_change(dev, link, 1); + netdev_dbg(dev->net, "Link Status is: %d\n", link); + } + + return; +} + +static inline int sr_set_sw_mii(struct usbnet *dev) +{ + int ret; + + ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to enable software MII access\n"); + return ret; +} + +static inline int sr_set_hw_mii(struct usbnet *dev) +{ + int ret; + + ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to enable hardware MII access\n"); + return ret; +} + +static inline int sr_get_phy_addr(struct usbnet *dev) +{ + u8 buf[2]; + int ret; + + ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf); + if (ret < 0) { + netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n", + __func__, ret); + goto out; + } + netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__, + *((__le16 *)buf)); + + ret = buf[1]; + +out: + return ret; +} + +static int sr_sw_reset(struct usbnet *dev, u8 flags) +{ + int ret; + + ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to send software reset:%02x\n", + ret); + + return ret; +} + +static u16 sr_read_rx_ctl(struct usbnet *dev) +{ + __le16 v; + int ret; + + ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v); + if (ret < 0) { + netdev_err(dev->net, "Error reading RX_CTL register:%02x\n", + ret); + goto out; + } + + ret = le16_to_cpu(v); +out: + return ret; +} + +static int sr_write_rx_ctl(struct usbnet *dev, u16 mode) +{ + int ret; + + netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); + ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, + "Failed to write RX_CTL mode to 0x%04x:%02x\n", + mode, ret); + + return ret; +} + +static u16 sr_read_medium_status(struct usbnet *dev) +{ + __le16 v; + int ret; + + ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); + if (ret < 0) { + netdev_err(dev->net, + "Error reading Medium Status register:%02x\n", ret); + return ret; /* TODO: callers not checking for error ret */ + } + + return le16_to_cpu(v); +} + +static int sr_write_medium_mode(struct usbnet *dev, u16 mode) +{ + int ret; + + netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); + ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, + "Failed to write Medium Mode mode to 0x%04x:%02x\n", + mode, ret); + return ret; +} + +static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep) +{ + int ret; + + netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value); + ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n", + value, ret); + if (sleep) + msleep(sleep); + + return ret; +} + +/* SR9800 have a 16-bit RX_CTL value */ +static void sr_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + u16 rx_ctl = SR_DEFAULT_RX_CTL; + + if (net->flags & IFF_PROMISC) { + rx_ctl |= SR_RX_CTL_PRO; + } else if (net->flags & IFF_ALLMULTI || + netdev_mc_count(net) > SR_MAX_MCAST) { + rx_ctl |= SR_RX_CTL_AMALL; + } else if (netdev_mc_empty(net)) { + /* just broadcast and directed */ + } else { + /* We use the 20 byte dev->data + * for our 8 byte filter buffer + * to avoid allocating memory that + * is tricky to free later + */ + struct netdev_hw_addr *ha; + u32 crc_bits; + + memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE); + + /* Build the multicast hash filter. */ + netdev_for_each_mc_addr(ha, net) { + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + } + + sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0, + SR_MCAST_FILTER_SIZE, data->multi_filter); + + rx_ctl |= SR_RX_CTL_AM; + } + + sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); +} + +static int sr_mdio_read(struct net_device *net, int phy_id, int loc) +{ + struct usbnet *dev = netdev_priv(net); + __le16 res; + + mutex_lock(&dev->phy_mutex); + sr_set_sw_mii(dev); + sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res); + sr_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); + + netdev_dbg(dev->net, + "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__, + phy_id, loc, le16_to_cpu(res)); + + return le16_to_cpu(res); +} + +static void +sr_mdio_write(struct net_device *net, int phy_id, int loc, int val) +{ + struct usbnet *dev = netdev_priv(net); + __le16 res = cpu_to_le16(val); + + netdev_dbg(dev->net, + "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__, + phy_id, loc, val); + mutex_lock(&dev->phy_mutex); + sr_set_sw_mii(dev); + sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); + sr_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); +} + +/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ +static u32 sr_get_phyid(struct usbnet *dev) +{ + int phy_reg; + u32 phy_id; + int i; + + /* Poll for the rare case the FW or phy isn't ready yet. */ + for (i = 0; i < 100; i++) { + phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); + if (phy_reg != 0 && phy_reg != 0xFFFF) + break; + mdelay(1); + } + + if (phy_reg <= 0 || phy_reg == 0xFFFF) + return 0; + + phy_id = (phy_reg & 0xffff) << 16; + + phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); + if (phy_reg < 0) + return 0; + + phy_id |= (phy_reg & 0xffff); + + return phy_id; +} + +static void +sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt; + + if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { + wolinfo->supported = 0; + wolinfo->wolopts = 0; + return; + } + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; + wolinfo->wolopts = 0; + if (opt & SR_MONITOR_LINK) + wolinfo->wolopts |= WAKE_PHY; + if (opt & SR_MONITOR_MAGIC) + wolinfo->wolopts |= WAKE_MAGIC; +} + +static int +sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt = 0; + + if (wolinfo->wolopts & WAKE_PHY) + opt |= SR_MONITOR_LINK; + if (wolinfo->wolopts & WAKE_MAGIC) + opt |= SR_MONITOR_MAGIC; + + if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE, + opt, 0, 0, NULL) < 0) + return -EINVAL; + + return 0; +} + +static int sr_get_eeprom_len(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + + return data->eeprom_len; +} + +static int sr_get_eeprom(struct net_device *net, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct usbnet *dev = netdev_priv(net); + __le16 *ebuf = (__le16 *)data; + int ret; + int i; + + /* Crude hack to ensure that we don't overwrite memory + * if an odd length is supplied + */ + if (eeprom->len % 2) + return -EINVAL; + + eeprom->magic = SR_EEPROM_MAGIC; + + /* sr9800 returns 2 bytes from eeprom on read */ + for (i = 0; i < eeprom->len / 2; i++) { + ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i, + 0, 2, &ebuf[i]); + if (ret < 0) + return -EINVAL; + } + return 0; +} + +static void sr_get_drvinfo(struct net_device *net, + struct ethtool_drvinfo *info) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + + /* Inherit standard device info */ + usbnet_get_drvinfo(net, info); + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); + info->eedump_len = data->eeprom_len; +} + +static u32 sr_get_link(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + return mii_link_ok(&dev->mii); +} + +static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd) +{ + struct usbnet *dev = netdev_priv(net); + + return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); +} + +static int sr_set_mac_address(struct net_device *net, void *p) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + struct sockaddr *addr = p; + + if (netif_running(net)) + return -EBUSY; + if (!is_valid_ether_addr(addr->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(net->dev_addr, addr->sa_data, ETH_ALEN); + + /* We use the 20 byte dev->data + * for our 6 byte mac buffer + * to avoid allocating memory that + * is tricky to free later + */ + memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); + sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + + return 0; +} + +static const struct ethtool_ops sr9800_ethtool_ops = { + .get_drvinfo = sr_get_drvinfo, + .get_link = sr_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_wol = sr_get_wol, + .set_wol = sr_set_wol, + .get_eeprom_len = sr_get_eeprom_len, + .get_eeprom = sr_get_eeprom, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, +}; + +static int sr9800_link_reset(struct usbnet *dev) +{ + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + u16 mode; + + mii_check_media(&dev->mii, 1, 1); + mii_ethtool_gset(&dev->mii, &ecmd); + mode = SR9800_MEDIUM_DEFAULT; + + if (ethtool_cmd_speed(&ecmd) != SPEED_100) + mode &= ~SR_MEDIUM_PS; + + if (ecmd.duplex != DUPLEX_FULL) + mode &= ~SR_MEDIUM_FD; + + netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n", + __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); + + sr_write_medium_mode(dev, mode); + + return 0; +} + + +static int sr9800_set_default_mode(struct usbnet *dev) +{ + u16 rx_ctl; + int ret; + + sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA); + mii_nway_restart(&dev->mii); + + ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT); + if (ret < 0) + goto out; + + ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012, + SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT, + SR9800_IPG2_DEFAULT, 0, NULL); + if (ret < 0) { + netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); + goto out; + } + + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ + ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", + rx_ctl); + + rx_ctl = sr_read_medium_status(dev); + netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n", + rx_ctl); + + return 0; +out: + return ret; +} + +static int sr9800_reset(struct usbnet *dev) +{ + struct sr_data *data = (struct sr_data *)&dev->data; + int ret, embd_phy; + u16 rx_ctl; + + ret = sr_write_gpio(dev, + SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5); + if (ret < 0) + goto out; + + embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); + + ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); + if (ret < 0) { + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); + goto out; + } + + ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL); + if (ret < 0) + goto out; + + msleep(150); + + ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); + if (ret < 0) + goto out; + + msleep(150); + + if (embd_phy) { + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); + if (ret < 0) + goto out; + } else { + ret = sr_sw_reset(dev, SR_SWRESET_PRTE); + if (ret < 0) + goto out; + } + + msleep(150); + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); + ret = sr_write_rx_ctl(dev, 0x0000); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); + + ret = sr_sw_reset(dev, SR_SWRESET_PRL); + if (ret < 0) + goto out; + + msleep(150); + + ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL); + if (ret < 0) + goto out; + + msleep(150); + + ret = sr9800_set_default_mode(dev); + if (ret < 0) + goto out; + + /* Rewrite MAC address */ + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); + ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + if (ret < 0) + goto out; + + return 0; + +out: + return ret; +} + +static const struct net_device_ops sr9800_netdev_ops = { + .ndo_open = usbnet_open, + .ndo_stop = usbnet_stop, + .ndo_start_xmit = usbnet_start_xmit, + .ndo_tx_timeout = usbnet_tx_timeout, + .ndo_change_mtu = usbnet_change_mtu, + .ndo_set_mac_address = sr_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = sr_ioctl, + .ndo_set_rx_mode = sr_set_multicast, +}; + +static int sr9800_phy_powerup(struct usbnet *dev) +{ + int ret; + + /* set the embedded Ethernet PHY in power-down state */ + ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL); + if (ret < 0) { + netdev_err(dev->net, "Failed to power down PHY : %d\n", ret); + return ret; + } + msleep(20); + + /* set the embedded Ethernet PHY in power-up state */ + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); + if (ret < 0) { + netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); + return ret; + } + msleep(600); + + /* set the embedded Ethernet PHY in reset state */ + ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); + if (ret < 0) { + netdev_err(dev->net, "Failed to power up PHY: %d\n", ret); + return ret; + } + msleep(20); + + /* set the embedded Ethernet PHY in power-up state */ + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); + if (ret < 0) { + netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); + return ret; + } + + return 0; +} + +static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf) +{ + struct sr_data *data = (struct sr_data *)&dev->data; + u16 led01_mux, led23_mux; + int ret, embd_phy; + u32 phyid; + u16 rx_ctl; + + data->eeprom_len = SR9800_EEPROM_LEN; + + usbnet_get_endpoints(dev, intf); + + /* LED Setting Rule : + * AABB:CCDD + * AA : MFA0(LED0) + * BB : MFA1(LED1) + * CC : MFA2(LED2), Reserved for SR9800 + * DD : MFA3(LED3), Reserved for SR9800 + */ + led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK; + led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE; + ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL); + if (ret < 0) { + netdev_err(dev->net, "set LINK LED failed : %d\n", ret); + goto out; + } + + /* Get the MAC address */ + ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, + dev->net->dev_addr); + if (ret < 0) { + netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); + return ret; + } + netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr); + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = sr_mdio_read; + dev->mii.mdio_write = sr_mdio_write; + dev->mii.phy_id_mask = 0x1f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = sr_get_phy_addr(dev); + + dev->net->netdev_ops = &sr9800_netdev_ops; + dev->net->ethtool_ops = &sr9800_ethtool_ops; + + embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); + /* Reset the PHY to normal operation mode */ + ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); + if (ret < 0) { + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); + return ret; + } + + /* Init PHY routine */ + ret = sr9800_phy_powerup(dev); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); + ret = sr_write_rx_ctl(dev, 0x0000); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); + + /* Read PHYID register *AFTER* the PHY was reset properly */ + phyid = sr_get_phyid(dev); + netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); + + /* medium mode setting */ + ret = sr9800_set_default_mode(dev); + if (ret < 0) + goto out; + + if (dev->udev->speed == USB_SPEED_HIGH) { + ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold, + 0, NULL); + if (ret < 0) { + netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); + goto out; + } + dev->rx_urb_size = + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size; + } else { + ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold, + 0, NULL); + if (ret < 0) { + netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); + goto out; + } + dev->rx_urb_size = + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size; + } + netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__, + dev->rx_urb_size); + return 0; + +out: + return ret; +} + +static const struct driver_info sr9800_driver_info = { + .description = "CoreChip SR9800 USB 2.0 Ethernet", + .bind = sr9800_bind, + .status = sr_status, + .link_reset = sr9800_link_reset, + .reset = sr9800_reset, + .flags = DRIVER_FLAG, + .rx_fixup = sr_rx_fixup, + .tx_fixup = sr_tx_fixup, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */ + .driver_info = (unsigned long) &sr9800_driver_info, + }, + {}, /* END */ +}; + +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver sr_driver = { + .name = DRIVER_NAME, + .id_table = products, + .probe = usbnet_probe, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disconnect = usbnet_disconnect, + .supports_autosuspend = 1, +}; + +module_usb_driver(sr_driver); + +MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/sr9800.h b/drivers/net/usb/sr9800.h new file mode 100644 index 000000000000..18f670251275 --- /dev/null +++ b/drivers/net/usb/sr9800.h @@ -0,0 +1,202 @@ +/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices + * + * Author : Liu Junliang <liujunliang_ljl@163.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef _SR9800_H +#define _SR9800_H + +/* SR9800 spec. command table on Linux Platform */ + +/* command : Software Station Management Control Reg */ +#define SR_CMD_SET_SW_MII 0x06 +/* command : PHY Read Reg */ +#define SR_CMD_READ_MII_REG 0x07 +/* command : PHY Write Reg */ +#define SR_CMD_WRITE_MII_REG 0x08 +/* command : Hardware Station Management Control Reg */ +#define SR_CMD_SET_HW_MII 0x0a +/* command : SROM Read Reg */ +#define SR_CMD_READ_EEPROM 0x0b +/* command : SROM Write Reg */ +#define SR_CMD_WRITE_EEPROM 0x0c +/* command : SROM Write Enable Reg */ +#define SR_CMD_WRITE_ENABLE 0x0d +/* command : SROM Write Disable Reg */ +#define SR_CMD_WRITE_DISABLE 0x0e +/* command : RX Control Read Reg */ +#define SR_CMD_READ_RX_CTL 0x0f +#define SR_RX_CTL_PRO (1 << 0) +#define SR_RX_CTL_AMALL (1 << 1) +#define SR_RX_CTL_SEP (1 << 2) +#define SR_RX_CTL_AB (1 << 3) +#define SR_RX_CTL_AM (1 << 4) +#define SR_RX_CTL_AP (1 << 5) +#define SR_RX_CTL_ARP (1 << 6) +#define SR_RX_CTL_SO (1 << 7) +#define SR_RX_CTL_RH1M (1 << 8) +#define SR_RX_CTL_RH2M (1 << 9) +#define SR_RX_CTL_RH3M (1 << 10) +/* command : RX Control Write Reg */ +#define SR_CMD_WRITE_RX_CTL 0x10 +/* command : IPG0/IPG1/IPG2 Control Read Reg */ +#define SR_CMD_READ_IPG012 0x11 +/* command : IPG0/IPG1/IPG2 Control Write Reg */ +#define SR_CMD_WRITE_IPG012 0x12 +/* command : Node ID Read Reg */ +#define SR_CMD_READ_NODE_ID 0x13 +/* command : Node ID Write Reg */ +#define SR_CMD_WRITE_NODE_ID 0x14 +/* command : Multicast Filter Array Read Reg */ +#define SR_CMD_READ_MULTI_FILTER 0x15 +/* command : Multicast Filter Array Write Reg */ +#define SR_CMD_WRITE_MULTI_FILTER 0x16 +/* command : Eth/HomePNA PHY Address Reg */ +#define SR_CMD_READ_PHY_ID 0x19 +/* command : Medium Status Read Reg */ +#define SR_CMD_READ_MEDIUM_STATUS 0x1a +#define SR_MONITOR_LINK (1 << 1) +#define SR_MONITOR_MAGIC (1 << 2) +#define SR_MONITOR_HSFS (1 << 4) +/* command : Medium Status Write Reg */ +#define SR_CMD_WRITE_MEDIUM_MODE 0x1b +#define SR_MEDIUM_GM (1 << 0) +#define SR_MEDIUM_FD (1 << 1) +#define SR_MEDIUM_AC (1 << 2) +#define SR_MEDIUM_ENCK (1 << 3) +#define SR_MEDIUM_RFC (1 << 4) +#define SR_MEDIUM_TFC (1 << 5) +#define SR_MEDIUM_JFE (1 << 6) +#define SR_MEDIUM_PF (1 << 7) +#define SR_MEDIUM_RE (1 << 8) +#define SR_MEDIUM_PS (1 << 9) +#define SR_MEDIUM_RSV (1 << 10) +#define SR_MEDIUM_SBP (1 << 11) +#define SR_MEDIUM_SM (1 << 12) +/* command : Monitor Mode Status Read Reg */ +#define SR_CMD_READ_MONITOR_MODE 0x1c +/* command : Monitor Mode Status Write Reg */ +#define SR_CMD_WRITE_MONITOR_MODE 0x1d +/* command : GPIO Status Read Reg */ +#define SR_CMD_READ_GPIOS 0x1e +#define SR_GPIO_GPO0EN (1 << 0) /* GPIO0 Output enable */ +#define SR_GPIO_GPO_0 (1 << 1) /* GPIO0 Output value */ +#define SR_GPIO_GPO1EN (1 << 2) /* GPIO1 Output enable */ +#define SR_GPIO_GPO_1 (1 << 3) /* GPIO1 Output value */ +#define SR_GPIO_GPO2EN (1 << 4) /* GPIO2 Output enable */ +#define SR_GPIO_GPO_2 (1 << 5) /* GPIO2 Output value */ +#define SR_GPIO_RESERVED (1 << 6) /* Reserved */ +#define SR_GPIO_RSE (1 << 7) /* Reload serial EEPROM */ +/* command : GPIO Status Write Reg */ +#define SR_CMD_WRITE_GPIOS 0x1f +/* command : Eth PHY Power and Reset Control Reg */ +#define SR_CMD_SW_RESET 0x20 +#define SR_SWRESET_CLEAR 0x00 +#define SR_SWRESET_RR (1 << 0) +#define SR_SWRESET_RT (1 << 1) +#define SR_SWRESET_PRTE (1 << 2) +#define SR_SWRESET_PRL (1 << 3) +#define SR_SWRESET_BZ (1 << 4) +#define SR_SWRESET_IPRL (1 << 5) +#define SR_SWRESET_IPPD (1 << 6) +/* command : Software Interface Selection Status Read Reg */ +#define SR_CMD_SW_PHY_STATUS 0x21 +/* command : Software Interface Selection Status Write Reg */ +#define SR_CMD_SW_PHY_SELECT 0x22 +/* command : BULK in Buffer Size Reg */ +#define SR_CMD_BULKIN_SIZE 0x2A +/* command : LED_MUX Control Reg */ +#define SR_CMD_LED_MUX 0x70 +#define SR_LED_MUX_TX_ACTIVE (1 << 0) +#define SR_LED_MUX_RX_ACTIVE (1 << 1) +#define SR_LED_MUX_COLLISION (1 << 2) +#define SR_LED_MUX_DUP_COL (1 << 3) +#define SR_LED_MUX_DUP (1 << 4) +#define SR_LED_MUX_SPEED (1 << 5) +#define SR_LED_MUX_LINK_ACTIVE (1 << 6) +#define SR_LED_MUX_LINK (1 << 7) + +/* Register Access Flags */ +#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) + +/* Multicast Filter Array size & Max Number */ +#define SR_MCAST_FILTER_SIZE 8 +#define SR_MAX_MCAST 64 + +/* IPG0/1/2 Default Value */ +#define SR9800_IPG0_DEFAULT 0x15 +#define SR9800_IPG1_DEFAULT 0x0c +#define SR9800_IPG2_DEFAULT 0x12 + +/* Medium Status Default Mode */ +#define SR9800_MEDIUM_DEFAULT \ + (SR_MEDIUM_FD | SR_MEDIUM_RFC | \ + SR_MEDIUM_TFC | SR_MEDIUM_PS | \ + SR_MEDIUM_AC | SR_MEDIUM_RE) + +/* RX Control Default Setting */ +#define SR_DEFAULT_RX_CTL \ + (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M) + +/* EEPROM Magic Number & EEPROM Size */ +#define SR_EEPROM_MAGIC 0xdeadbeef +#define SR9800_EEPROM_LEN 0xff + +/* SR9800 Driver Version and Driver Name */ +#define DRIVER_VERSION "11-Nov-2013" +#define DRIVER_NAME "CoreChips" +#define DRIVER_FLAG \ + (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET) + +/* SR9800 BULKIN Buffer Size */ +#define SR9800_MAX_BULKIN_2K 0 +#define SR9800_MAX_BULKIN_4K 1 +#define SR9800_MAX_BULKIN_6K 2 +#define SR9800_MAX_BULKIN_8K 3 +#define SR9800_MAX_BULKIN_16K 4 +#define SR9800_MAX_BULKIN_20K 5 +#define SR9800_MAX_BULKIN_24K 6 +#define SR9800_MAX_BULKIN_32K 7 + +struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = { + /* 2k */ + {2048, 0x8000, 0x8001}, + /* 4k */ + {4096, 0x8100, 0x8147}, + /* 6k */ + {6144, 0x8200, 0x81EB}, + /* 8k */ + {8192, 0x8300, 0x83D7}, + /* 16 */ + {16384, 0x8400, 0x851E}, + /* 20k */ + {20480, 0x8500, 0x8666}, + /* 24k */ + {24576, 0x8600, 0x87AE}, + /* 32k */ + {32768, 0x8700, 0x8A3D}, +}; + +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ +struct sr_data { + u8 multi_filter[SR_MCAST_FILTER_SIZE]; + u8 mac_addr[ETH_ALEN]; + u8 phymode; + u8 ledmode; + u8 eeprom_len; +}; + +struct sr9800_int_data { + __le16 res1; + u8 link; + __le16 res2; + u8 status; + __le16 res3; +} __packed; + +#endif /* _SR9800_H */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 4671da755e7b..dd10d5817d2a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -542,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) } // else network stack removes extra byte if we forced a short packet - if (skb->len) { - /* all data was already cloned from skb inside the driver */ - if (dev->driver_info->flags & FLAG_MULTI_PACKET) - dev_kfree_skb_any(skb); - else - usbnet_skb_return(dev, skb); + /* all data was already cloned from skb inside the driver */ + if (dev->driver_info->flags & FLAG_MULTI_PACKET) + goto done; + + if (skb->len < ETH_HLEN) { + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len); + } else { + usbnet_skb_return(dev, skb); return; } - netif_dbg(dev, rx_err, dev->net, "drop\n"); - dev->net->stats.rx_errors++; done: skb_queue_tail(&dev->done, skb); } @@ -574,13 +576,6 @@ static void rx_complete (struct urb *urb) switch (urb_status) { /* success */ case 0: - if (skb->len < dev->net->hard_header_len) { - state = rx_cleanup; - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - netif_dbg(dev, rx_err, dev->net, - "rx length %d\n", skb->len); - } break; /* stalls need manual reset. this is rare ... except that diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 2ec2041b62d4..3aca92e80e1e 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -14,6 +14,7 @@ #include <linux/etherdevice.h> #include <linux/u64_stats_sync.h> +#include <net/rtnetlink.h> #include <net/dst.h> #include <net/xfrm.h> #include <linux/veth.h> @@ -235,18 +236,9 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu) static int veth_dev_init(struct net_device *dev) { - int i; - - dev->vstats = alloc_percpu(struct pcpu_vstats); + dev->vstats = netdev_alloc_pcpu_stats(struct pcpu_vstats); if (!dev->vstats) return -ENOMEM; - - for_each_possible_cpu(i) { - struct pcpu_vstats *veth_stats; - veth_stats = per_cpu_ptr(dev->vstats, i); - u64_stats_init(&veth_stats->syncp); - } - return 0; } @@ -285,7 +277,8 @@ static void veth_setup(struct net_device *dev) dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; dev->features |= VETH_FEATURES; - dev->vlan_features = dev->features; + dev->vlan_features = dev->features & + ~(NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_STAG_TX); dev->destructor = veth_dev_free; dev->hw_features = VETH_FEATURES; @@ -332,10 +325,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev, nla_peer = data[VETH_INFO_PEER]; ifmp = nla_data(nla_peer); - err = nla_parse(peer_tb, IFLA_MAX, - nla_data(nla_peer) + sizeof(struct ifinfomsg), - nla_len(nla_peer) - sizeof(struct ifinfomsg), - ifla_policy); + err = rtnl_nla_parse_ifla(peer_tb, + nla_data(nla_peer) + sizeof(struct ifinfomsg), + nla_len(nla_peer) - sizeof(struct ifinfomsg)); if (err < 0) return err; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index d75f8edf4fb3..5632a99cbbd2 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1711,7 +1711,8 @@ static int virtnet_probe(struct virtio_device *vdev) /* If we can receive ANY GSO packets, we must allocate large ones. */ if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) || + virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO)) vi->big_packets = true; if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c index 3be786faaaec..9275c8c423b1 100644 --- a/drivers/net/vmxnet3/vmxnet3_drv.c +++ b/drivers/net/vmxnet3/vmxnet3_drv.c @@ -2729,47 +2729,35 @@ vmxnet3_read_mac_addr(struct vmxnet3_adapter *adapter, u8 *mac) /* * Enable MSIx vectors. * Returns : - * 0 on successful enabling of required vectors, * VMXNET3_LINUX_MIN_MSIX_VECT when only minimum number of vectors required - * could be enabled. - * number of vectors which can be enabled otherwise (this number is smaller + * were enabled. + * number of vectors which were enabled otherwise (this number is greater * than VMXNET3_LINUX_MIN_MSIX_VECT) */ static int -vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter, - int vectors) -{ - int err = 0, vector_threshold; - vector_threshold = VMXNET3_LINUX_MIN_MSIX_VECT; - - while (vectors >= vector_threshold) { - err = pci_enable_msix(adapter->pdev, adapter->intr.msix_entries, - vectors); - if (!err) { - adapter->intr.num_intrs = vectors; - return 0; - } else if (err < 0) { - dev_err(&adapter->netdev->dev, - "Failed to enable MSI-X, error: %d\n", err); - vectors = 0; - } else if (err < vector_threshold) { - break; - } else { - /* If fails to enable required number of MSI-x vectors - * try enabling minimum number of vectors required. - */ - dev_err(&adapter->netdev->dev, - "Failed to enable %d MSI-X, trying %d instead\n", - vectors, vector_threshold); - vectors = vector_threshold; - } +vmxnet3_acquire_msix_vectors(struct vmxnet3_adapter *adapter, int nvec) +{ + int ret = pci_enable_msix_range(adapter->pdev, + adapter->intr.msix_entries, nvec, nvec); + + if (ret == -ENOSPC && nvec > VMXNET3_LINUX_MIN_MSIX_VECT) { + dev_err(&adapter->netdev->dev, + "Failed to enable %d MSI-X, trying %d\n", + nvec, VMXNET3_LINUX_MIN_MSIX_VECT); + + ret = pci_enable_msix_range(adapter->pdev, + adapter->intr.msix_entries, + VMXNET3_LINUX_MIN_MSIX_VECT, + VMXNET3_LINUX_MIN_MSIX_VECT); } - dev_info(&adapter->pdev->dev, - "Number of MSI-X interrupts which can be allocated " - "is lower than min threshold required.\n"); - return err; + if (ret < 0) { + dev_err(&adapter->netdev->dev, + "Failed to enable MSI-X, error: %d\n", ret); + } + + return ret; } @@ -2796,56 +2784,50 @@ vmxnet3_alloc_intr_resources(struct vmxnet3_adapter *adapter) #ifdef CONFIG_PCI_MSI if (adapter->intr.type == VMXNET3_IT_MSIX) { - int vector, err = 0; - - adapter->intr.num_intrs = (adapter->share_intr == - VMXNET3_INTR_TXSHARE) ? 1 : - adapter->num_tx_queues; - adapter->intr.num_intrs += (adapter->share_intr == - VMXNET3_INTR_BUDDYSHARE) ? 0 : - adapter->num_rx_queues; - adapter->intr.num_intrs += 1; /* for link event */ - - adapter->intr.num_intrs = (adapter->intr.num_intrs > - VMXNET3_LINUX_MIN_MSIX_VECT - ? adapter->intr.num_intrs : - VMXNET3_LINUX_MIN_MSIX_VECT); - - for (vector = 0; vector < adapter->intr.num_intrs; vector++) - adapter->intr.msix_entries[vector].entry = vector; - - err = vmxnet3_acquire_msix_vectors(adapter, - adapter->intr.num_intrs); + int i, nvec; + + nvec = adapter->share_intr == VMXNET3_INTR_TXSHARE ? + 1 : adapter->num_tx_queues; + nvec += adapter->share_intr == VMXNET3_INTR_BUDDYSHARE ? + 0 : adapter->num_rx_queues; + nvec += 1; /* for link event */ + nvec = nvec > VMXNET3_LINUX_MIN_MSIX_VECT ? + nvec : VMXNET3_LINUX_MIN_MSIX_VECT; + + for (i = 0; i < nvec; i++) + adapter->intr.msix_entries[i].entry = i; + + nvec = vmxnet3_acquire_msix_vectors(adapter, nvec); + if (nvec < 0) + goto msix_err; + /* If we cannot allocate one MSIx vector per queue * then limit the number of rx queues to 1 */ - if (err == VMXNET3_LINUX_MIN_MSIX_VECT) { + if (nvec == VMXNET3_LINUX_MIN_MSIX_VECT) { if (adapter->share_intr != VMXNET3_INTR_BUDDYSHARE || adapter->num_rx_queues != 1) { adapter->share_intr = VMXNET3_INTR_TXSHARE; netdev_err(adapter->netdev, "Number of rx queues : 1\n"); adapter->num_rx_queues = 1; - adapter->intr.num_intrs = - VMXNET3_LINUX_MIN_MSIX_VECT; } - return; } - if (!err) - return; + adapter->intr.num_intrs = nvec; + return; + +msix_err: /* If we cannot allocate MSIx vectors use only one rx queue */ dev_info(&adapter->pdev->dev, "Failed to enable MSI-X, error %d. " - "Limiting #rx queues to 1, try MSI.\n", err); + "Limiting #rx queues to 1, try MSI.\n", nvec); adapter->intr.type = VMXNET3_IT_MSI; } if (adapter->intr.type == VMXNET3_IT_MSI) { - int err; - err = pci_enable_msi(adapter->pdev); - if (!err) { + if (!pci_enable_msi(adapter->pdev)) { adapter->num_rx_queues = 1; adapter->intr.num_intrs = 1; return; diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 026a313c2d2d..eb59b14d5ee0 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -469,7 +469,6 @@ static inline struct hlist_head *vxlan_fdb_head(struct vxlan_dev *vxlan, /* Look up Ethernet address in forwarding table */ static struct vxlan_fdb *__vxlan_find_mac(struct vxlan_dev *vxlan, const u8 *mac) - { struct hlist_head *head = vxlan_fdb_head(vxlan, mac); struct vxlan_fdb *f; @@ -596,10 +595,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff NAPI_GRO_CB(p)->same_flow = 0; continue; } - goto found; } -found: type = eh->h_proto; rcu_read_lock(); @@ -1135,7 +1132,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { struct vxlan_sock *vs; struct vxlanhdr *vxh; - __be16 port; /* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull(skb, VXLAN_HLEN)) @@ -1153,8 +1149,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB))) goto drop; - port = inet_sk(sk)->inet_sport; - vs = rcu_dereference_sk_user_data(sk); if (!vs) goto drop; @@ -1981,19 +1975,11 @@ static int vxlan_init(struct net_device *dev) struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_net *vn = net_generic(dev_net(dev), vxlan_net_id); struct vxlan_sock *vs; - int i; - dev->tstats = alloc_percpu(struct pcpu_sw_netstats); + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; - for_each_possible_cpu(i) { - struct pcpu_sw_netstats *vxlan_stats; - vxlan_stats = per_cpu_ptr(dev->tstats, i); - u64_stats_init(&vxlan_stats->syncp); - } - - spin_lock(&vn->sock_lock); vs = vxlan_find_sock(dev_net(dev), vxlan->dst_port); if (vs) { diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index 0d1c7592efa0..19f7cb2cdef3 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -71,12 +71,9 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev, const void *saddr, unsigned len) { struct frhdr hdr; - struct dlci_local *dlp; unsigned int hlen; char *dest; - dlp = netdev_priv(dev); - hdr.control = FRAD_I_UI; switch (type) { @@ -107,11 +104,9 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev, static void dlci_receive(struct sk_buff *skb, struct net_device *dev) { - struct dlci_local *dlp; struct frhdr *hdr; int process, header; - dlp = netdev_priv(dev); if (!pskb_may_pull(skb, sizeof(*hdr))) { netdev_notice(dev, "invalid data no header\n"); dev->stats.rx_errors++; diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index eeceab39cda2..e1c8cc4a4b92 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -41,30 +41,28 @@ static int wil_if_pcie_enable(struct wil6210_priv *wil) switch (use_msi) { case 3: case 1: + wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); + break; case 0: + wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); break; default: - wil_err(wil, "Invalid use_msi=%d, default to 1\n", - use_msi); + wil_err(wil, "Invalid use_msi=%d, default to 1\n", use_msi); use_msi = 1; } - wil->n_msi = use_msi; - if (wil->n_msi) { - wil_dbg_misc(wil, "Setup %d MSI interrupts\n", use_msi); - rc = pci_enable_msi_block(pdev, wil->n_msi); - if (rc && (wil->n_msi == 3)) { - wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); - wil->n_msi = 1; - rc = pci_enable_msi_block(pdev, wil->n_msi); - } - if (rc) { - wil_err(wil, "pci_enable_msi failed, use INTx\n"); - wil->n_msi = 0; - } - } else { - wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); + + if (use_msi == 3 && pci_enable_msi_range(pdev, 3, 3) < 0) { + wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); + use_msi = 1; + } + + if (use_msi == 1 && pci_enable_msi(pdev)) { + wil_err(wil, "pci_enable_msi failed, use INTx\n"); + use_msi = 0; } + wil->n_msi = use_msi; + rc = wil6210_init_irq(wil, pdev->irq); if (rc) goto stop_master; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 5397ee0ad652..7b4502fefec3 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -748,7 +748,7 @@ 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, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { skb->priority = cfg80211_classify8021d(skb, NULL); return mwifiex_1d_to_wmm_queue[skb->priority]; diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 4c76bcb9a879..bef37be402b8 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -48,37 +48,19 @@ typedef unsigned int pending_ring_idx_t; #define INVALID_PENDING_RING_IDX (~0U) -/* For the head field in pending_tx_info: it is used to indicate - * whether this tx info is the head of one or more coalesced requests. - * - * When head != INVALID_PENDING_RING_IDX, it means the start of a new - * tx requests queue and the end of previous queue. - * - * An example sequence of head fields (I = INVALID_PENDING_RING_IDX): - * - * ...|0 I I I|5 I|9 I I I|... - * -->|<-INUSE---------------- - * - * After consuming the first slot(s) we have: - * - * ...|V V V V|5 I|9 I I I|... - * -----FREE->|<-INUSE-------- - * - * where V stands for "valid pending ring index". Any number other - * than INVALID_PENDING_RING_IDX is OK. These entries are considered - * free and can contain any number other than - * INVALID_PENDING_RING_IDX. In practice we use 0. - * - * The in use non-INVALID_PENDING_RING_IDX (say 0, 5 and 9 in the - * above example) number is the index into pending_tx_info and - * mmap_pages arrays. - */ struct pending_tx_info { - struct xen_netif_tx_request req; /* coalesced tx request */ - pending_ring_idx_t head; /* head != INVALID_PENDING_RING_IDX - * if it is head of one or more tx - * reqs - */ + struct xen_netif_tx_request req; /* tx request */ + /* Callback data for released SKBs. The callback is always + * xenvif_zerocopy_callback, desc contains the pending_idx, which is + * also an index in pending_tx_info array. It is initialized in + * xenvif_alloc and it never changes. + * skb_shinfo(skb)->destructor_arg points to the first mapped slot's + * callback_struct in this array of struct pending_tx_info's, then ctx + * to the next, or NULL if there is no more slot for this skb. + * ubuf_to_vif is a helper which finds the struct xenvif from a pointer + * to this field. + */ + struct ubuf_info callback_struct; }; #define XEN_NETIF_TX_RING_SIZE __CONST_RING_SIZE(xen_netif_tx, PAGE_SIZE) @@ -108,6 +90,15 @@ struct xenvif_rx_meta { */ #define MAX_GRANT_COPY_OPS (MAX_SKB_FRAGS * XEN_NETIF_RX_RING_SIZE) +#define NETBACK_INVALID_HANDLE -1 + +/* To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating + * the maximum slots a valid packet can use. Now this value is defined + * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by + * all backend. + */ +#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN + struct xenvif { /* Unique identifier for this interface. */ domid_t domid; @@ -126,13 +117,28 @@ struct xenvif { pending_ring_idx_t pending_cons; u16 pending_ring[MAX_PENDING_REQS]; struct pending_tx_info pending_tx_info[MAX_PENDING_REQS]; - - /* Coalescing tx requests before copying makes number of grant - * copy ops greater or equal to number of slots required. In - * worst case a tx request consumes 2 gnttab_copy. + grant_handle_t grant_tx_handle[MAX_PENDING_REQS]; + + struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS]; + struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS]; + /* passed to gnttab_[un]map_refs with pages under (un)mapping */ + struct page *pages_to_map[MAX_PENDING_REQS]; + struct page *pages_to_unmap[MAX_PENDING_REQS]; + + /* This prevents zerocopy callbacks to race over dealloc_ring */ + spinlock_t callback_lock; + /* This prevents dealloc thread and NAPI instance to race over response + * creation and pending_ring in xenvif_idx_release. In xenvif_tx_err + * it only protect response creation */ - struct gnttab_copy tx_copy_ops[2*MAX_PENDING_REQS]; - + spinlock_t response_lock; + pending_ring_idx_t dealloc_prod; + pending_ring_idx_t dealloc_cons; + u16 dealloc_ring[MAX_PENDING_REQS]; + struct task_struct *dealloc_task; + wait_queue_head_t dealloc_wq; + struct timer_list dealloc_delay; + bool dealloc_delay_timed_out; /* Use kthread for guest RX */ struct task_struct *task; @@ -143,11 +149,10 @@ struct xenvif { char rx_irq_name[IFNAMSIZ+4]; /* DEVNAME-rx */ struct xen_netif_rx_back_ring rx; struct sk_buff_head rx_queue; - bool rx_queue_stopped; - /* Set when the RX interrupt is triggered by the frontend. - * The worker thread may need to wake the queue. - */ - bool rx_event; + RING_IDX rx_last_skb_slots; + bool rx_queue_purge; + + struct timer_list wake_queue; /* This array is allocated seperately as it is large */ struct gnttab_copy *grant_copy_op; @@ -179,6 +184,10 @@ struct xenvif { /* Statistics */ unsigned long rx_gso_checksum_fixup; + unsigned long tx_zerocopy_sent; + unsigned long tx_zerocopy_success; + unsigned long tx_zerocopy_fail; + unsigned long tx_frag_overflow; /* Miscellaneous private stuff. */ struct net_device *dev; @@ -220,9 +229,11 @@ void xenvif_carrier_off(struct xenvif *vif); int xenvif_tx_action(struct xenvif *vif, int budget); -int xenvif_kthread(void *data); +int xenvif_kthread_guest_rx(void *data); void xenvif_kick_thread(struct xenvif *vif); +int xenvif_dealloc_kthread(void *data); + /* Determine whether the needed number of slots (req) are available, * and set req_event if not. */ @@ -230,6 +241,30 @@ bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed); void xenvif_stop_queue(struct xenvif *vif); +/* Callback from stack when TX packet can be released */ +void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); + +/* Unmap a pending page and release it back to the guest */ +void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx); + +static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif) +{ + return MAX_PENDING_REQS - + vif->pending_prod + vif->pending_cons; +} + +static inline bool xenvif_tx_pending_slots_available(struct xenvif *vif) +{ + return nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX + < MAX_PENDING_REQS; +} + +/* Callback from stack when TX packet can be released */ +void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); + extern bool separate_tx_rx_irq; +extern unsigned int rx_drain_timeout_msecs; +extern unsigned int rx_drain_timeout_jiffies; + #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index b9de31ea7fc4..83a71ac5b93a 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -38,6 +38,7 @@ #include <xen/events.h> #include <asm/xen/hypercall.h> +#include <xen/balloon.h> #define XENVIF_QUEUE_LENGTH 32 #define XENVIF_NAPI_WEIGHT 64 @@ -87,7 +88,8 @@ static int xenvif_poll(struct napi_struct *napi, int budget) local_irq_save(flags); RING_FINAL_CHECK_FOR_REQUESTS(&vif->tx, more_to_do); - if (!more_to_do) + if (!(more_to_do && + xenvif_tx_pending_slots_available(vif))) __napi_complete(napi); local_irq_restore(flags); @@ -100,7 +102,6 @@ static irqreturn_t xenvif_rx_interrupt(int irq, void *dev_id) { struct xenvif *vif = dev_id; - vif->rx_event = true; xenvif_kick_thread(vif); return IRQ_HANDLED; @@ -114,6 +115,18 @@ static irqreturn_t xenvif_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +static void xenvif_wake_queue(unsigned long data) +{ + struct xenvif *vif = (struct xenvif *)data; + + if (netif_queue_stopped(vif->dev)) { + netdev_err(vif->dev, "draining TX queue\n"); + vif->rx_queue_purge = true; + xenvif_kick_thread(vif); + netif_wake_queue(vif->dev); + } +} + static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct xenvif *vif = netdev_priv(dev); @@ -122,7 +135,9 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) BUG_ON(skb->dev != dev); /* Drop the packet if vif is not ready */ - if (vif->task == NULL || !xenvif_schedulable(vif)) + if (vif->task == NULL || + vif->dealloc_task == NULL || + !xenvif_schedulable(vif)) goto drop; /* At best we'll need one slot for the header and one for each @@ -141,8 +156,13 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) * then turn off the queue to give the ring a chance to * drain. */ - if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) + if (!xenvif_rx_ring_slots_available(vif, min_slots_needed)) { + vif->wake_queue.function = xenvif_wake_queue; + vif->wake_queue.data = (unsigned long)vif; xenvif_stop_queue(vif); + mod_timer(&vif->wake_queue, + jiffies + rx_drain_timeout_jiffies); + } skb_queue_tail(&vif->rx_queue, skb); xenvif_kick_thread(vif); @@ -235,6 +255,28 @@ static const struct xenvif_stat { "rx_gso_checksum_fixup", offsetof(struct xenvif, rx_gso_checksum_fixup) }, + /* If (sent != success + fail), there are probably packets never + * freed up properly! + */ + { + "tx_zerocopy_sent", + offsetof(struct xenvif, tx_zerocopy_sent), + }, + { + "tx_zerocopy_success", + offsetof(struct xenvif, tx_zerocopy_success), + }, + { + "tx_zerocopy_fail", + offsetof(struct xenvif, tx_zerocopy_fail) + }, + /* Number of packets exceeding MAX_SKB_FRAG slots. You should use + * a guest with the same MAX_SKB_FRAG + */ + { + "tx_frag_overflow", + offsetof(struct xenvif, tx_frag_overflow) + }, }; static int xenvif_get_sset_count(struct net_device *dev, int string_set) @@ -328,6 +370,8 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, init_timer(&vif->credit_timeout); vif->credit_window_start = get_jiffies_64(); + init_timer(&vif->wake_queue); + dev->netdev_ops = &xenvif_netdev_ops; dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | @@ -344,8 +388,27 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->pending_prod = MAX_PENDING_REQS; for (i = 0; i < MAX_PENDING_REQS; i++) vif->pending_ring[i] = i; - for (i = 0; i < MAX_PENDING_REQS; i++) - vif->mmap_pages[i] = NULL; + spin_lock_init(&vif->callback_lock); + spin_lock_init(&vif->response_lock); + /* If ballooning is disabled, this will consume real memory, so you + * better enable it. The long term solution would be to use just a + * bunch of valid page descriptors, without dependency on ballooning + */ + err = alloc_xenballooned_pages(MAX_PENDING_REQS, + vif->mmap_pages, + false); + if (err) { + netdev_err(dev, "Could not reserve mmap_pages\n"); + return ERR_PTR(-ENOMEM); + } + for (i = 0; i < MAX_PENDING_REQS; i++) { + vif->pending_tx_info[i].callback_struct = (struct ubuf_info) + { .callback = xenvif_zerocopy_callback, + .ctx = NULL, + .desc = i }; + vif->grant_tx_handle[i] = NETBACK_INVALID_HANDLE; + } + init_timer(&vif->dealloc_delay); /* * Initialise a dummy MAC address. We choose the numerically @@ -383,12 +446,14 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, BUG_ON(vif->tx_irq); BUG_ON(vif->task); + BUG_ON(vif->dealloc_task); err = xenvif_map_frontend_rings(vif, tx_ring_ref, rx_ring_ref); if (err < 0) goto err; init_waitqueue_head(&vif->wq); + init_waitqueue_head(&vif->dealloc_wq); if (tx_evtchn == rx_evtchn) { /* feature-split-event-channels == 0 */ @@ -422,8 +487,8 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, disable_irq(vif->rx_irq); } - task = kthread_create(xenvif_kthread, - (void *)vif, "%s", vif->dev->name); + task = kthread_create(xenvif_kthread_guest_rx, + (void *)vif, "%s-guest-rx", vif->dev->name); if (IS_ERR(task)) { pr_warn("Could not allocate kthread for %s\n", vif->dev->name); err = PTR_ERR(task); @@ -432,6 +497,16 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, vif->task = task; + task = kthread_create(xenvif_dealloc_kthread, + (void *)vif, "%s-dealloc", vif->dev->name); + if (IS_ERR(task)) { + pr_warn("Could not allocate kthread for %s\n", vif->dev->name); + err = PTR_ERR(task); + goto err_rx_unbind; + } + + vif->dealloc_task = task; + rtnl_lock(); if (!vif->can_sg && vif->dev->mtu > ETH_DATA_LEN) dev_set_mtu(vif->dev, ETH_DATA_LEN); @@ -442,6 +517,7 @@ int xenvif_connect(struct xenvif *vif, unsigned long tx_ring_ref, rtnl_unlock(); wake_up_process(vif->task); + wake_up_process(vif->dealloc_task); return 0; @@ -475,10 +551,17 @@ void xenvif_disconnect(struct xenvif *vif) xenvif_carrier_off(vif); if (vif->task) { + del_timer_sync(&vif->wake_queue); kthread_stop(vif->task); vif->task = NULL; } + if (vif->dealloc_task) { + del_timer_sync(&vif->dealloc_delay); + kthread_stop(vif->dealloc_task); + vif->dealloc_task = NULL; + } + if (vif->tx_irq) { if (vif->tx_irq == vif->rx_irq) unbind_from_irqhandler(vif->tx_irq, vif); @@ -494,6 +577,36 @@ void xenvif_disconnect(struct xenvif *vif) void xenvif_free(struct xenvif *vif) { + int i, unmap_timeout = 0; + /* Here we want to avoid timeout messages if an skb can be legitimatly + * stucked somewhere else. Realisticly this could be an another vif's + * internal or QDisc queue. That another vif also has this + * rx_drain_timeout_msecs timeout, but the timer only ditches the + * internal queue. After that, the QDisc queue can put in worst case + * XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS skbs into that another vif's + * internal queue, so we need several rounds of such timeouts until we + * can be sure that no another vif should have skb's from us. We are + * not sending more skb's, so newly stucked packets are not interesting + * for us here. + */ + unsigned int worst_case_skb_lifetime = (rx_drain_timeout_msecs/1000) * + DIV_ROUND_UP(XENVIF_QUEUE_LENGTH, (XEN_NETIF_RX_RING_SIZE / MAX_SKB_FRAGS)); + + for (i = 0; i < MAX_PENDING_REQS; ++i) { + if (vif->grant_tx_handle[i] != NETBACK_INVALID_HANDLE) { + unmap_timeout++; + schedule_timeout(msecs_to_jiffies(1000)); + if (unmap_timeout > worst_case_skb_lifetime && + net_ratelimit()) + netdev_err(vif->dev, + "Page still granted! Index: %x\n", + i); + i = -1; + } + } + + free_xenballooned_pages(MAX_PENDING_REQS, vif->mmap_pages); + netif_napi_del(&vif->napi); unregister_netdev(vif->dev); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 6b62c3eb8e18..bc943205a691 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -37,6 +37,7 @@ #include <linux/kthread.h> #include <linux/if_vlan.h> #include <linux/udp.h> +#include <linux/highmem.h> #include <net/tcp.h> @@ -54,6 +55,13 @@ bool separate_tx_rx_irq = 1; module_param(separate_tx_rx_irq, bool, 0644); +/* When guest ring is filled up, qdisc queues the packets for us, but we have + * to timeout them, otherwise other guests' packets can get stucked there + */ +unsigned int rx_drain_timeout_msecs = 10000; +module_param(rx_drain_timeout_msecs, uint, 0444); +unsigned int rx_drain_timeout_jiffies; + /* * This is the maximum slots a skb can have. If a guest sends a skb * which exceeds this limit it is considered malicious. @@ -62,24 +70,6 @@ module_param(separate_tx_rx_irq, bool, 0644); static unsigned int fatal_skb_slots = FATAL_SKB_SLOTS_DEFAULT; module_param(fatal_skb_slots, uint, 0444); -/* - * To avoid confusion, we define XEN_NETBK_LEGACY_SLOTS_MAX indicating - * the maximum slots a valid packet can use. Now this value is defined - * to be XEN_NETIF_NR_SLOTS_MIN, which is supposed to be supported by - * all backend. - */ -#define XEN_NETBK_LEGACY_SLOTS_MAX XEN_NETIF_NR_SLOTS_MIN - -/* - * If head != INVALID_PENDING_RING_IDX, it means this tx request is head of - * one or more merged tx requests, otherwise it is the continuation of - * previous tx request. - */ -static inline int pending_tx_is_head(struct xenvif *vif, RING_IDX idx) -{ - return vif->pending_tx_info[idx].head != INVALID_PENDING_RING_IDX; -} - static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx, u8 status); @@ -109,6 +99,18 @@ static inline unsigned long idx_to_kaddr(struct xenvif *vif, return (unsigned long)pfn_to_kaddr(idx_to_pfn(vif, idx)); } +/* Find the containing VIF's structure from a pointer in pending_tx_info array + */ +static inline struct xenvif* ubuf_to_vif(struct ubuf_info *ubuf) +{ + u16 pending_idx = ubuf->desc; + struct pending_tx_info *temp = + container_of(ubuf, struct pending_tx_info, callback_struct); + return container_of(temp - pending_idx, + struct xenvif, + pending_tx_info[0]); +} + /* This is a miniumum size for the linear area to avoid lots of * calls to __pskb_pull_tail() as we set up checksum offsets. The * value 128 was chosen as it covers all IPv4 and most likely @@ -131,10 +133,9 @@ static inline pending_ring_idx_t pending_index(unsigned i) return i & (MAX_PENDING_REQS-1); } -static inline pending_ring_idx_t nr_pending_reqs(struct xenvif *vif) +static inline pending_ring_idx_t nr_free_slots(struct xen_netif_tx_back_ring *ring) { - return MAX_PENDING_REQS - - vif->pending_prod + vif->pending_cons; + return ring->nr_ents - (ring->sring->req_prod - ring->rsp_prod_pvt); } bool xenvif_rx_ring_slots_available(struct xenvif *vif, int needed) @@ -235,7 +236,9 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif *vif, static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, struct netrx_pending_operations *npo, struct page *page, unsigned long size, - unsigned long offset, int *head) + unsigned long offset, int *head, + struct xenvif *foreign_vif, + grant_ref_t foreign_gref) { struct gnttab_copy *copy_gop; struct xenvif_rx_meta *meta; @@ -277,8 +280,15 @@ static void xenvif_gop_frag_copy(struct xenvif *vif, struct sk_buff *skb, copy_gop->flags = GNTCOPY_dest_gref; copy_gop->len = bytes; - copy_gop->source.domid = DOMID_SELF; - copy_gop->source.u.gmfn = virt_to_mfn(page_address(page)); + if (foreign_vif) { + copy_gop->source.domid = foreign_vif->domid; + copy_gop->source.u.ref = foreign_gref; + copy_gop->flags |= GNTCOPY_source_gref; + } else { + copy_gop->source.domid = DOMID_SELF; + copy_gop->source.u.gmfn = + virt_to_mfn(page_address(page)); + } copy_gop->source.offset = offset; copy_gop->dest.domid = vif->domid; @@ -339,6 +349,9 @@ static int xenvif_gop_skb(struct sk_buff *skb, int old_meta_prod; int gso_type; int gso_size; + struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg; + grant_ref_t foreign_grefs[MAX_SKB_FRAGS]; + struct xenvif *foreign_vif = NULL; old_meta_prod = npo->meta_prod; @@ -379,6 +392,19 @@ static int xenvif_gop_skb(struct sk_buff *skb, npo->copy_off = 0; npo->copy_gref = req->gref; + if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) && + (ubuf->callback == &xenvif_zerocopy_callback)) { + int i = 0; + foreign_vif = ubuf_to_vif(ubuf); + + do { + u16 pending_idx = ubuf->desc; + foreign_grefs[i++] = + foreign_vif->pending_tx_info[pending_idx].req.gref; + ubuf = (struct ubuf_info *) ubuf->ctx; + } while (ubuf); + } + data = skb->data; while (data < skb_tail_pointer(skb)) { unsigned int offset = offset_in_page(data); @@ -388,7 +414,9 @@ static int xenvif_gop_skb(struct sk_buff *skb, len = skb_tail_pointer(skb) - data; xenvif_gop_frag_copy(vif, skb, npo, - virt_to_page(data), len, offset, &head); + virt_to_page(data), len, offset, &head, + NULL, + 0); data += len; } @@ -397,7 +425,9 @@ static int xenvif_gop_skb(struct sk_buff *skb, skb_frag_page(&skb_shinfo(skb)->frags[i]), skb_frag_size(&skb_shinfo(skb)->frags[i]), skb_shinfo(skb)->frags[i].page_offset, - &head); + &head, + foreign_vif, + foreign_grefs[i]); } return npo->meta_prod - old_meta_prod; @@ -455,10 +485,12 @@ static void xenvif_add_frag_responses(struct xenvif *vif, int status, } } -struct skb_cb_overlay { +struct xenvif_rx_cb { int meta_slots_used; }; +#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb) + void xenvif_kick_thread(struct xenvif *vif) { wake_up(&vif->wq); @@ -474,9 +506,7 @@ static void xenvif_rx_action(struct xenvif *vif) LIST_HEAD(notify); int ret; unsigned long offset; - struct skb_cb_overlay *sco; bool need_to_notify = false; - bool ring_full = false; struct netrx_pending_operations npo = { .copy = vif->grant_copy_op, @@ -486,7 +516,7 @@ static void xenvif_rx_action(struct xenvif *vif) skb_queue_head_init(&rxq); while ((skb = skb_dequeue(&vif->rx_queue)) != NULL) { - int max_slots_needed; + RING_IDX max_slots_needed; int i; /* We need a cheap worse case estimate for the number of @@ -509,21 +539,19 @@ static void xenvif_rx_action(struct xenvif *vif) if (!xenvif_rx_ring_slots_available(vif, max_slots_needed)) { skb_queue_head(&vif->rx_queue, skb); need_to_notify = true; - ring_full = true; + vif->rx_last_skb_slots = max_slots_needed; break; - } + } else + vif->rx_last_skb_slots = 0; - sco = (struct skb_cb_overlay *)skb->cb; - sco->meta_slots_used = xenvif_gop_skb(skb, &npo); - BUG_ON(sco->meta_slots_used > max_slots_needed); + XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo); + BUG_ON(XENVIF_RX_CB(skb)->meta_slots_used > max_slots_needed); __skb_queue_tail(&rxq, skb); } BUG_ON(npo.meta_prod > ARRAY_SIZE(vif->meta)); - vif->rx_queue_stopped = !npo.copy_prod && ring_full; - if (!npo.copy_prod) goto done; @@ -531,7 +559,6 @@ static void xenvif_rx_action(struct xenvif *vif) gnttab_batch_copy(vif->grant_copy_op, npo.copy_prod); while ((skb = __skb_dequeue(&rxq)) != NULL) { - sco = (struct skb_cb_overlay *)skb->cb; if ((1 << vif->meta[npo.meta_cons].gso_type) & vif->gso_prefix_mask) { @@ -542,19 +569,21 @@ static void xenvif_rx_action(struct xenvif *vif) resp->offset = vif->meta[npo.meta_cons].gso_size; resp->id = vif->meta[npo.meta_cons].id; - resp->status = sco->meta_slots_used; + resp->status = XENVIF_RX_CB(skb)->meta_slots_used; npo.meta_cons++; - sco->meta_slots_used--; + XENVIF_RX_CB(skb)->meta_slots_used--; } vif->dev->stats.tx_bytes += skb->len; vif->dev->stats.tx_packets++; - status = xenvif_check_gop(vif, sco->meta_slots_used, &npo); + status = xenvif_check_gop(vif, + XENVIF_RX_CB(skb)->meta_slots_used, + &npo); - if (sco->meta_slots_used == 1) + if (XENVIF_RX_CB(skb)->meta_slots_used == 1) flags = 0; else flags = XEN_NETRXF_more_data; @@ -591,13 +620,13 @@ static void xenvif_rx_action(struct xenvif *vif) xenvif_add_frag_responses(vif, status, vif->meta + npo.meta_cons + 1, - sco->meta_slots_used); + XENVIF_RX_CB(skb)->meta_slots_used); RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&vif->rx, ret); need_to_notify |= !!ret; - npo.meta_cons += sco->meta_slots_used; + npo.meta_cons += XENVIF_RX_CB(skb)->meta_slots_used; dev_kfree_skb(skb); } @@ -647,9 +676,12 @@ static void xenvif_tx_err(struct xenvif *vif, struct xen_netif_tx_request *txp, RING_IDX end) { RING_IDX cons = vif->tx.req_cons; + unsigned long flags; do { + spin_lock_irqsave(&vif->response_lock, flags); make_tx_response(vif, txp, XEN_NETIF_RSP_ERROR); + spin_unlock_irqrestore(&vif->response_lock, flags); if (cons == end) break; txp = RING_GET_REQUEST(&vif->tx, cons++); @@ -761,180 +793,168 @@ static int xenvif_count_requests(struct xenvif *vif, return slots; } -static struct page *xenvif_alloc_page(struct xenvif *vif, - u16 pending_idx) + +struct xenvif_tx_cb { + u16 pending_idx; +}; + +#define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb) + +static inline void xenvif_tx_create_gop(struct xenvif *vif, + u16 pending_idx, + struct xen_netif_tx_request *txp, + struct gnttab_map_grant_ref *gop) { - struct page *page; + vif->pages_to_map[gop-vif->tx_map_ops] = vif->mmap_pages[pending_idx]; + gnttab_set_map_op(gop, idx_to_kaddr(vif, pending_idx), + GNTMAP_host_map | GNTMAP_readonly, + txp->gref, vif->domid); + + memcpy(&vif->pending_tx_info[pending_idx].req, txp, + sizeof(*txp)); +} - page = alloc_page(GFP_ATOMIC|__GFP_COLD); - if (!page) +static inline struct sk_buff *xenvif_alloc_skb(unsigned int size) +{ + struct sk_buff *skb = + alloc_skb(size + NET_SKB_PAD + NET_IP_ALIGN, + GFP_ATOMIC | __GFP_NOWARN); + if (unlikely(skb == NULL)) return NULL; - vif->mmap_pages[pending_idx] = page; - return page; + /* Packets passed to netif_rx() must have some headroom. */ + skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); + + /* Initialize it here to avoid later surprises */ + skb_shinfo(skb)->destructor_arg = NULL; + + return skb; } -static struct gnttab_copy *xenvif_get_requests(struct xenvif *vif, - struct sk_buff *skb, - struct xen_netif_tx_request *txp, - struct gnttab_copy *gop) +static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif, + struct sk_buff *skb, + struct xen_netif_tx_request *txp, + struct gnttab_map_grant_ref *gop) { struct skb_shared_info *shinfo = skb_shinfo(skb); skb_frag_t *frags = shinfo->frags; - u16 pending_idx = *((u16 *)skb->data); - u16 head_idx = 0; - int slot, start; - struct page *page; - pending_ring_idx_t index, start_idx = 0; - uint16_t dst_offset; - unsigned int nr_slots; - struct pending_tx_info *first = NULL; + u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; + int start; + pending_ring_idx_t index; + unsigned int nr_slots, frag_overflow = 0; /* At this point shinfo->nr_frags is in fact the number of * slots, which can be as large as XEN_NETBK_LEGACY_SLOTS_MAX. */ + if (shinfo->nr_frags > MAX_SKB_FRAGS) { + frag_overflow = shinfo->nr_frags - MAX_SKB_FRAGS; + BUG_ON(frag_overflow > MAX_SKB_FRAGS); + shinfo->nr_frags = MAX_SKB_FRAGS; + } nr_slots = shinfo->nr_frags; /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); - /* Coalesce tx requests, at this point the packet passed in - * should be <= 64K. Any packets larger than 64K have been - * handled in xenvif_count_requests(). - */ - for (shinfo->nr_frags = slot = start; slot < nr_slots; - shinfo->nr_frags++) { - struct pending_tx_info *pending_tx_info = - vif->pending_tx_info; + for (shinfo->nr_frags = start; shinfo->nr_frags < nr_slots; + shinfo->nr_frags++, txp++, gop++) { + index = pending_index(vif->pending_cons++); + pending_idx = vif->pending_ring[index]; + xenvif_tx_create_gop(vif, pending_idx, txp, gop); + frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx); + } - page = alloc_page(GFP_ATOMIC|__GFP_COLD); - if (!page) - goto err; - - dst_offset = 0; - first = NULL; - while (dst_offset < PAGE_SIZE && slot < nr_slots) { - gop->flags = GNTCOPY_source_gref; - - gop->source.u.ref = txp->gref; - gop->source.domid = vif->domid; - gop->source.offset = txp->offset; - - gop->dest.domid = DOMID_SELF; - - gop->dest.offset = dst_offset; - gop->dest.u.gmfn = virt_to_mfn(page_address(page)); - - if (dst_offset + txp->size > PAGE_SIZE) { - /* This page can only merge a portion - * of tx request. Do not increment any - * pointer / counter here. The txp - * will be dealt with in future - * rounds, eventually hitting the - * `else` branch. - */ - gop->len = PAGE_SIZE - dst_offset; - txp->offset += gop->len; - txp->size -= gop->len; - dst_offset += gop->len; /* quit loop */ - } else { - /* This tx request can be merged in the page */ - gop->len = txp->size; - dst_offset += gop->len; - - index = pending_index(vif->pending_cons++); - - pending_idx = vif->pending_ring[index]; - - memcpy(&pending_tx_info[pending_idx].req, txp, - sizeof(*txp)); - - /* Poison these fields, corresponding - * fields for head tx req will be set - * to correct values after the loop. - */ - vif->mmap_pages[pending_idx] = (void *)(~0UL); - pending_tx_info[pending_idx].head = - INVALID_PENDING_RING_IDX; - - if (!first) { - first = &pending_tx_info[pending_idx]; - start_idx = index; - head_idx = pending_idx; - } - - txp++; - slot++; - } + if (frag_overflow) { + struct sk_buff *nskb = xenvif_alloc_skb(0); + if (unlikely(nskb == NULL)) { + if (net_ratelimit()) + netdev_err(vif->dev, + "Can't allocate the frag_list skb.\n"); + return NULL; + } + + shinfo = skb_shinfo(nskb); + frags = shinfo->frags; - gop++; + for (shinfo->nr_frags = 0; shinfo->nr_frags < frag_overflow; + shinfo->nr_frags++, txp++, gop++) { + index = pending_index(vif->pending_cons++); + pending_idx = vif->pending_ring[index]; + xenvif_tx_create_gop(vif, pending_idx, txp, gop); + frag_set_pending_idx(&frags[shinfo->nr_frags], + pending_idx); } - first->req.offset = 0; - first->req.size = dst_offset; - first->head = start_idx; - vif->mmap_pages[head_idx] = page; - frag_set_pending_idx(&frags[shinfo->nr_frags], head_idx); + skb_shinfo(skb)->frag_list = nskb; } - BUG_ON(shinfo->nr_frags > MAX_SKB_FRAGS); - return gop; -err: - /* Unwind, freeing all pages and sending error responses. */ - while (shinfo->nr_frags-- > start) { - xenvif_idx_release(vif, - frag_get_pending_idx(&frags[shinfo->nr_frags]), - XEN_NETIF_RSP_ERROR); +} + +static inline void xenvif_grant_handle_set(struct xenvif *vif, + u16 pending_idx, + grant_handle_t handle) +{ + if (unlikely(vif->grant_tx_handle[pending_idx] != + NETBACK_INVALID_HANDLE)) { + netdev_err(vif->dev, + "Trying to overwrite active handle! pending_idx: %x\n", + pending_idx); + BUG(); } - /* The head too, if necessary. */ - if (start) - xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); + vif->grant_tx_handle[pending_idx] = handle; +} - return NULL; +static inline void xenvif_grant_handle_reset(struct xenvif *vif, + u16 pending_idx) +{ + if (unlikely(vif->grant_tx_handle[pending_idx] == + NETBACK_INVALID_HANDLE)) { + netdev_err(vif->dev, + "Trying to unmap invalid handle! pending_idx: %x\n", + pending_idx); + BUG(); + } + vif->grant_tx_handle[pending_idx] = NETBACK_INVALID_HANDLE; } static int xenvif_tx_check_gop(struct xenvif *vif, struct sk_buff *skb, - struct gnttab_copy **gopp) + struct gnttab_map_grant_ref **gopp) { - struct gnttab_copy *gop = *gopp; - u16 pending_idx = *((u16 *)skb->data); + struct gnttab_map_grant_ref *gop = *gopp; + u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx; struct skb_shared_info *shinfo = skb_shinfo(skb); struct pending_tx_info *tx_info; int nr_frags = shinfo->nr_frags; int i, err, start; - u16 peek; /* peek into next tx request */ + struct sk_buff *first_skb = NULL; /* Check status of header. */ err = gop->status; if (unlikely(err)) xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR); + else + xenvif_grant_handle_set(vif, pending_idx , gop->handle); /* Skip first skb fragment if it is on same page as header fragment. */ start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); +check_frags: for (i = start; i < nr_frags; i++) { int j, newerr; - pending_ring_idx_t head; pending_idx = frag_get_pending_idx(&shinfo->frags[i]); tx_info = &vif->pending_tx_info[pending_idx]; - head = tx_info->head; /* Check error status: if okay then remember grant handle. */ - do { - newerr = (++gop)->status; - if (newerr) - break; - peek = vif->pending_ring[pending_index(++head)]; - } while (!pending_tx_is_head(vif, peek)); + newerr = (++gop)->status; if (likely(!newerr)) { + xenvif_grant_handle_set(vif, pending_idx , gop->handle); /* Had a previous error? Invalidate this fragment. */ if (unlikely(err)) - xenvif_idx_release(vif, pending_idx, - XEN_NETIF_RSP_OKAY); + xenvif_idx_unmap(vif, pending_idx); continue; } @@ -944,20 +964,45 @@ static int xenvif_tx_check_gop(struct xenvif *vif, /* Not the first error? Preceding frags already invalidated. */ if (err) continue; - /* First error: invalidate header and preceding fragments. */ - pending_idx = *((u16 *)skb->data); - xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); + if (!first_skb) + pending_idx = XENVIF_TX_CB(skb)->pending_idx; + else + pending_idx = XENVIF_TX_CB(skb)->pending_idx; + xenvif_idx_unmap(vif, pending_idx); for (j = start; j < i; j++) { pending_idx = frag_get_pending_idx(&shinfo->frags[j]); - xenvif_idx_release(vif, pending_idx, - XEN_NETIF_RSP_OKAY); + xenvif_idx_unmap(vif, pending_idx); } /* Remember the error: invalidate all subsequent fragments. */ err = newerr; } + if (skb_has_frag_list(skb)) { + first_skb = skb; + skb = shinfo->frag_list; + shinfo = skb_shinfo(skb); + nr_frags = shinfo->nr_frags; + start = 0; + + goto check_frags; + } + + /* There was a mapping error in the frag_list skb. We have to unmap + * the first skb's frags + */ + if (first_skb && err) { + int j; + shinfo = skb_shinfo(first_skb); + pending_idx = XENVIF_TX_CB(skb)->pending_idx; + start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx); + for (j = start; j < shinfo->nr_frags; j++) { + pending_idx = frag_get_pending_idx(&shinfo->frags[j]); + xenvif_idx_unmap(vif, pending_idx); + } + } + *gopp = gop + 1; return err; } @@ -967,6 +1012,10 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) struct skb_shared_info *shinfo = skb_shinfo(skb); int nr_frags = shinfo->nr_frags; int i; + u16 prev_pending_idx = INVALID_PENDING_IDX; + + if (skb_shinfo(skb)->destructor_arg) + prev_pending_idx = XENVIF_TX_CB(skb)->pending_idx; for (i = 0; i < nr_frags; i++) { skb_frag_t *frag = shinfo->frags + i; @@ -976,6 +1025,17 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) pending_idx = frag_get_pending_idx(frag); + /* If this is not the first frag, chain it to the previous*/ + if (unlikely(prev_pending_idx == INVALID_PENDING_IDX)) + skb_shinfo(skb)->destructor_arg = + &vif->pending_tx_info[pending_idx].callback_struct; + else if (likely(pending_idx != prev_pending_idx)) + vif->pending_tx_info[prev_pending_idx].callback_struct.ctx = + &(vif->pending_tx_info[pending_idx].callback_struct); + + vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL; + prev_pending_idx = pending_idx; + txp = &vif->pending_tx_info[pending_idx].req; page = virt_to_page(idx_to_kaddr(vif, pending_idx)); __skb_fill_page_desc(skb, i, page, txp->offset, txp->size); @@ -983,10 +1043,15 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb) skb->data_len += txp->size; skb->truesize += txp->size; - /* Take an extra reference to offset xenvif_idx_release */ + /* Take an extra reference to offset network stack's put_page */ get_page(vif->mmap_pages[pending_idx]); - xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); } + /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc + * overlaps with "index", and "mapping" is not set. I think mapping + * should be set. If delivered to local stack, it would drop this + * skb in sk_filter unless the socket has the right to use it. + */ + skb->pfmemalloc = false; } static int xenvif_get_extras(struct xenvif *vif, @@ -1106,16 +1171,14 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size) static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) { - struct gnttab_copy *gop = vif->tx_copy_ops, *request_gop; + struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop; struct sk_buff *skb; int ret; - while ((nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX - < MAX_PENDING_REQS) && + while (xenvif_tx_pending_slots_available(vif) && (skb_queue_len(&vif->tx_queue) < budget)) { struct xen_netif_tx_request txreq; struct xen_netif_tx_request txfrags[XEN_NETBK_LEGACY_SLOTS_MAX]; - struct page *page; struct xen_netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX-1]; u16 pending_idx; RING_IDX idx; @@ -1191,8 +1254,7 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) ret < XEN_NETBK_LEGACY_SLOTS_MAX) ? PKT_PROT_LEN : txreq.size; - skb = alloc_skb(data_len + NET_SKB_PAD + NET_IP_ALIGN, - GFP_ATOMIC | __GFP_NOWARN); + skb = xenvif_alloc_skb(data_len); if (unlikely(skb == NULL)) { netdev_dbg(vif->dev, "Can't allocate a skb in start_xmit.\n"); @@ -1200,9 +1262,6 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) break; } - /* Packets passed to netif_rx() must have some headroom. */ - skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); - if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) { struct xen_netif_extra_info *gso; gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1]; @@ -1214,31 +1273,11 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) } } - /* XXX could copy straight to head */ - page = xenvif_alloc_page(vif, pending_idx); - if (!page) { - kfree_skb(skb); - xenvif_tx_err(vif, &txreq, idx); - break; - } - - gop->source.u.ref = txreq.gref; - gop->source.domid = vif->domid; - gop->source.offset = txreq.offset; - - gop->dest.u.gmfn = virt_to_mfn(page_address(page)); - gop->dest.domid = DOMID_SELF; - gop->dest.offset = txreq.offset; - - gop->len = txreq.size; - gop->flags = GNTCOPY_source_gref; + xenvif_tx_create_gop(vif, pending_idx, &txreq, gop); gop++; - memcpy(&vif->pending_tx_info[pending_idx].req, - &txreq, sizeof(txreq)); - vif->pending_tx_info[pending_idx].head = index; - *((u16 *)skb->data) = pending_idx; + XENVIF_TX_CB(skb)->pending_idx = pending_idx; __skb_put(skb, data_len); @@ -1266,17 +1305,82 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget) vif->tx.req_cons = idx; - if ((gop-vif->tx_copy_ops) >= ARRAY_SIZE(vif->tx_copy_ops)) + if ((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops)) break; } - return gop - vif->tx_copy_ops; + return gop - vif->tx_map_ops; } +/* Consolidate skb with a frag_list into a brand new one with local pages on + * frags. Returns 0 or -ENOMEM if can't allocate new pages. + */ +static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb) +{ + unsigned int offset = skb_headlen(skb); + skb_frag_t frags[MAX_SKB_FRAGS]; + int i; + struct ubuf_info *uarg; + struct sk_buff *nskb = skb_shinfo(skb)->frag_list; + + vif->tx_zerocopy_sent += 2; + vif->tx_frag_overflow++; + + xenvif_fill_frags(vif, nskb); + /* Subtract frags size, we will correct it later */ + skb->truesize -= skb->data_len; + skb->len += nskb->len; + skb->data_len += nskb->len; + + /* create a brand new frags array and coalesce there */ + for (i = 0; offset < skb->len; i++) { + struct page *page; + unsigned int len; + + BUG_ON(i >= MAX_SKB_FRAGS); + page = alloc_page(GFP_ATOMIC|__GFP_COLD); + if (!page) { + int j; + skb->truesize += skb->data_len; + for (j = 0; j < i; j++) + put_page(frags[j].page.p); + return -ENOMEM; + } + + if (offset + PAGE_SIZE < skb->len) + len = PAGE_SIZE; + else + len = skb->len - offset; + if (skb_copy_bits(skb, offset, page_address(page), len)) + BUG(); + + offset += len; + frags[i].page.p = page; + frags[i].page_offset = 0; + skb_frag_size_set(&frags[i], len); + } + /* swap out with old one */ + memcpy(skb_shinfo(skb)->frags, + frags, + i * sizeof(skb_frag_t)); + skb_shinfo(skb)->nr_frags = i; + skb->truesize += i * PAGE_SIZE; + + /* remove traces of mapped pages and frag_list */ + skb_frag_list_init(skb); + uarg = skb_shinfo(skb)->destructor_arg; + uarg->callback(uarg, true); + skb_shinfo(skb)->destructor_arg = NULL; + + skb_shinfo(nskb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + kfree_skb(nskb); + + return 0; +} static int xenvif_tx_submit(struct xenvif *vif) { - struct gnttab_copy *gop = vif->tx_copy_ops; + struct gnttab_map_grant_ref *gop = vif->tx_map_ops; struct sk_buff *skb; int work_done = 0; @@ -1285,7 +1389,7 @@ static int xenvif_tx_submit(struct xenvif *vif) u16 pending_idx; unsigned data_len; - pending_idx = *((u16 *)skb->data); + pending_idx = XENVIF_TX_CB(skb)->pending_idx; txp = &vif->pending_tx_info[pending_idx].req; /* Check the remap error code. */ @@ -1300,14 +1404,16 @@ static int xenvif_tx_submit(struct xenvif *vif) memcpy(skb->data, (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset), data_len); + vif->pending_tx_info[pending_idx].callback_struct.ctx = NULL; if (data_len < txp->size) { /* Append the packet payload as a fragment. */ txp->offset += data_len; txp->size -= data_len; + skb_shinfo(skb)->destructor_arg = + &vif->pending_tx_info[pending_idx].callback_struct; } else { /* Schedule a response immediately. */ - xenvif_idx_release(vif, pending_idx, - XEN_NETIF_RSP_OKAY); + xenvif_idx_unmap(vif, pending_idx); } if (txp->flags & XEN_NETTXF_csum_blank) @@ -1317,6 +1423,17 @@ static int xenvif_tx_submit(struct xenvif *vif) xenvif_fill_frags(vif, skb); + if (unlikely(skb_has_frag_list(skb))) { + if (xenvif_handle_frag_list(vif, skb)) { + if (net_ratelimit()) + netdev_err(vif->dev, + "Not enough memory to consolidate frag_list!\n"); + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + kfree_skb(skb); + continue; + } + } + if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) { int target = min_t(int, skb->len, PKT_PROT_LEN); __pskb_pull_tail(skb, target - skb_headlen(skb)); @@ -1329,6 +1446,9 @@ static int xenvif_tx_submit(struct xenvif *vif) if (checksum_setup(vif, skb)) { netdev_dbg(vif->dev, "Can't setup checksum in net_tx_action\n"); + /* We have to set this flag to trigger the callback */ + if (skb_shinfo(skb)->destructor_arg) + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; kfree_skb(skb); continue; } @@ -1354,17 +1474,134 @@ static int xenvif_tx_submit(struct xenvif *vif) work_done++; + /* Set this flag right before netif_receive_skb, otherwise + * someone might think this packet already left netback, and + * do a skb_copy_ubufs while we are still in control of the + * skb. E.g. the __pskb_pull_tail earlier can do such thing. + */ + if (skb_shinfo(skb)->destructor_arg) { + skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; + vif->tx_zerocopy_sent++; + } + netif_receive_skb(skb); } return work_done; } +void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success) +{ + unsigned long flags; + pending_ring_idx_t index; + struct xenvif *vif = ubuf_to_vif(ubuf); + + /* This is the only place where we grab this lock, to protect callbacks + * from each other. + */ + spin_lock_irqsave(&vif->callback_lock, flags); + do { + u16 pending_idx = ubuf->desc; + ubuf = (struct ubuf_info *) ubuf->ctx; + BUG_ON(vif->dealloc_prod - vif->dealloc_cons >= + MAX_PENDING_REQS); + index = pending_index(vif->dealloc_prod); + vif->dealloc_ring[index] = pending_idx; + /* Sync with xenvif_tx_dealloc_action: + * insert idx then incr producer. + */ + smp_wmb(); + vif->dealloc_prod++; + } while (ubuf); + wake_up(&vif->dealloc_wq); + spin_unlock_irqrestore(&vif->callback_lock, flags); + + if (RING_HAS_UNCONSUMED_REQUESTS(&vif->tx) && + xenvif_tx_pending_slots_available(vif)) { + local_bh_disable(); + napi_schedule(&vif->napi); + local_bh_enable(); + } + + if (likely(zerocopy_success)) + vif->tx_zerocopy_success++; + else + vif->tx_zerocopy_fail++; +} + +static inline void xenvif_tx_dealloc_action(struct xenvif *vif) +{ + struct gnttab_unmap_grant_ref *gop; + pending_ring_idx_t dc, dp; + u16 pending_idx, pending_idx_release[MAX_PENDING_REQS]; + unsigned int i = 0; + + dc = vif->dealloc_cons; + gop = vif->tx_unmap_ops; + + /* Free up any grants we have finished using */ + do { + dp = vif->dealloc_prod; + + /* Ensure we see all indices enqueued by all + * xenvif_zerocopy_callback(). + */ + smp_rmb(); + + while (dc != dp) { + BUG_ON(gop - vif->tx_unmap_ops > MAX_PENDING_REQS); + pending_idx = + vif->dealloc_ring[pending_index(dc++)]; + + pending_idx_release[gop-vif->tx_unmap_ops] = + pending_idx; + vif->pages_to_unmap[gop-vif->tx_unmap_ops] = + vif->mmap_pages[pending_idx]; + gnttab_set_unmap_op(gop, + idx_to_kaddr(vif, pending_idx), + GNTMAP_host_map, + vif->grant_tx_handle[pending_idx]); + /* Btw. already unmapped? */ + xenvif_grant_handle_reset(vif, pending_idx); + ++gop; + } + + } while (dp != vif->dealloc_prod); + + vif->dealloc_cons = dc; + + if (gop - vif->tx_unmap_ops > 0) { + int ret; + ret = gnttab_unmap_refs(vif->tx_unmap_ops, + NULL, + vif->pages_to_unmap, + gop - vif->tx_unmap_ops); + if (ret) { + netdev_err(vif->dev, "Unmap fail: nr_ops %x ret %d\n", + gop - vif->tx_unmap_ops, ret); + for (i = 0; i < gop - vif->tx_unmap_ops; ++i) { + if (gop[i].status != GNTST_okay) + netdev_err(vif->dev, + " host_addr: %llx handle: %x status: %d\n", + gop[i].host_addr, + gop[i].handle, + gop[i].status); + } + BUG(); + } + } + + for (i = 0; i < gop - vif->tx_unmap_ops; ++i) + xenvif_idx_release(vif, pending_idx_release[i], + XEN_NETIF_RSP_OKAY); +} + + /* Called after netfront has transmitted */ int xenvif_tx_action(struct xenvif *vif, int budget) { unsigned nr_gops; - int work_done; + int work_done, ret; if (unlikely(!tx_work_todo(vif))) return 0; @@ -1374,7 +1611,11 @@ int xenvif_tx_action(struct xenvif *vif, int budget) if (nr_gops == 0) return 0; - gnttab_batch_copy(vif->tx_copy_ops, nr_gops); + ret = gnttab_map_refs(vif->tx_map_ops, + NULL, + vif->pages_to_map, + nr_gops); + BUG_ON(ret); work_done = xenvif_tx_submit(vif); @@ -1385,45 +1626,18 @@ static void xenvif_idx_release(struct xenvif *vif, u16 pending_idx, u8 status) { struct pending_tx_info *pending_tx_info; - pending_ring_idx_t head; - u16 peek; /* peek into next tx request */ - - BUG_ON(vif->mmap_pages[pending_idx] == (void *)(~0UL)); - - /* Already complete? */ - if (vif->mmap_pages[pending_idx] == NULL) - return; + pending_ring_idx_t index; + unsigned long flags; pending_tx_info = &vif->pending_tx_info[pending_idx]; - - head = pending_tx_info->head; - - BUG_ON(!pending_tx_is_head(vif, head)); - BUG_ON(vif->pending_ring[pending_index(head)] != pending_idx); - - do { - pending_ring_idx_t index; - pending_ring_idx_t idx = pending_index(head); - u16 info_idx = vif->pending_ring[idx]; - - pending_tx_info = &vif->pending_tx_info[info_idx]; - make_tx_response(vif, &pending_tx_info->req, status); - - /* Setting any number other than - * INVALID_PENDING_RING_IDX indicates this slot is - * starting a new packet / ending a previous packet. - */ - pending_tx_info->head = 0; - - index = pending_index(vif->pending_prod++); - vif->pending_ring[index] = vif->pending_ring[info_idx]; - - peek = vif->pending_ring[pending_index(++head)]; - - } while (!pending_tx_is_head(vif, peek)); - - put_page(vif->mmap_pages[pending_idx]); - vif->mmap_pages[pending_idx] = NULL; + spin_lock_irqsave(&vif->response_lock, flags); + make_tx_response(vif, &pending_tx_info->req, status); + index = pending_index(vif->pending_prod); + vif->pending_ring[index] = pending_idx; + /* TX shouldn't use the index before we give it back here */ + mb(); + vif->pending_prod++; + spin_unlock_irqrestore(&vif->response_lock, flags); } @@ -1471,23 +1685,74 @@ static struct xen_netif_rx_response *make_rx_response(struct xenvif *vif, return resp; } +void xenvif_idx_unmap(struct xenvif *vif, u16 pending_idx) +{ + int ret; + struct gnttab_unmap_grant_ref tx_unmap_op; + + gnttab_set_unmap_op(&tx_unmap_op, + idx_to_kaddr(vif, pending_idx), + GNTMAP_host_map, + vif->grant_tx_handle[pending_idx]); + /* Btw. already unmapped? */ + xenvif_grant_handle_reset(vif, pending_idx); + + ret = gnttab_unmap_refs(&tx_unmap_op, NULL, + &vif->mmap_pages[pending_idx], 1); + BUG_ON(ret); + + xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); +} + static inline int rx_work_todo(struct xenvif *vif) { - return (!skb_queue_empty(&vif->rx_queue) && !vif->rx_queue_stopped) || - vif->rx_event; + return (!skb_queue_empty(&vif->rx_queue) && + xenvif_rx_ring_slots_available(vif, vif->rx_last_skb_slots)) || + vif->rx_queue_purge; } static inline int tx_work_todo(struct xenvif *vif) { if (likely(RING_HAS_UNCONSUMED_REQUESTS(&vif->tx)) && - (nr_pending_reqs(vif) + XEN_NETBK_LEGACY_SLOTS_MAX - < MAX_PENDING_REQS)) + xenvif_tx_pending_slots_available(vif)) return 1; return 0; } +static void xenvif_dealloc_delay(unsigned long data) +{ + struct xenvif *vif = (struct xenvif *)data; + + vif->dealloc_delay_timed_out = true; + wake_up(&vif->dealloc_wq); +} + +static inline bool tx_dealloc_work_todo(struct xenvif *vif) +{ + if (vif->dealloc_cons != vif->dealloc_prod) { + if ((nr_free_slots(&vif->tx) > 2 * XEN_NETBK_LEGACY_SLOTS_MAX) && + (vif->dealloc_prod - vif->dealloc_cons < MAX_PENDING_REQS / 4) && + !vif->dealloc_delay_timed_out) { + if (!timer_pending(&vif->dealloc_delay)) { + vif->dealloc_delay.function = + xenvif_dealloc_delay; + vif->dealloc_delay.data = (unsigned long)vif; + mod_timer(&vif->dealloc_delay, + jiffies + msecs_to_jiffies(1)); + + } + return false; + } + del_timer_sync(&vif->dealloc_delay); + vif->dealloc_delay_timed_out = false; + return true; + } + + return false; +} + void xenvif_unmap_frontend_rings(struct xenvif *vif) { if (vif->tx.sring) @@ -1545,7 +1810,7 @@ static void xenvif_start_queue(struct xenvif *vif) netif_wake_queue(vif->dev); } -int xenvif_kthread(void *data) +int xenvif_kthread_guest_rx(void *data) { struct xenvif *vif = data; struct sk_buff *skb; @@ -1557,14 +1822,19 @@ int xenvif_kthread(void *data) if (kthread_should_stop()) break; + if (vif->rx_queue_purge) { + skb_queue_purge(&vif->rx_queue); + vif->rx_queue_purge = false; + } + if (!skb_queue_empty(&vif->rx_queue)) xenvif_rx_action(vif); - vif->rx_event = false; - if (skb_queue_empty(&vif->rx_queue) && - netif_queue_stopped(vif->dev)) + netif_queue_stopped(vif->dev)) { + del_timer_sync(&vif->wake_queue); xenvif_start_queue(vif); + } cond_resched(); } @@ -1576,6 +1846,28 @@ int xenvif_kthread(void *data) return 0; } +int xenvif_dealloc_kthread(void *data) +{ + struct xenvif *vif = data; + + while (!kthread_should_stop()) { + wait_event_interruptible(vif->dealloc_wq, + tx_dealloc_work_todo(vif) || + kthread_should_stop()); + if (kthread_should_stop()) + break; + + xenvif_tx_dealloc_action(vif); + cond_resched(); + } + + /* Unmap anything remaining*/ + if (tx_dealloc_work_todo(vif)) + xenvif_tx_dealloc_action(vif); + + return 0; +} + static int __init netback_init(void) { int rc = 0; @@ -1593,6 +1885,8 @@ static int __init netback_init(void) if (rc) goto failed_init; + rx_drain_timeout_jiffies = msecs_to_jiffies(rx_drain_timeout_msecs); + return 0; failed_init: diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index ff04d4f95baa..a38f03ded5a4 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -907,6 +907,7 @@ static int handle_incoming_queue(struct net_device *dev, /* Ethernet work: Delayed to here as it peeks the header. */ skb->protocol = eth_type_trans(skb, dev); + skb_reset_network_header(skb); if (checksum_setup(dev, skb)) { kfree_skb(skb); @@ -1281,16 +1282,10 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev) np->rx_refill_timer.function = rx_refill_timeout; err = -ENOMEM; - np->stats = alloc_percpu(struct netfront_stats); + np->stats = netdev_alloc_pcpu_stats(struct netfront_stats); if (np->stats == NULL) goto exit; - for_each_possible_cpu(i) { - struct netfront_stats *xen_nf_stats; - xen_nf_stats = per_cpu_ptr(np->stats, i); - u64_stats_init(&xen_nf_stats->syncp); - } - /* Initialise tx_skbs as a free chain containing every entry. */ np->tx_skb_freelist = 0; for (i = 0; i < NET_TX_RING_SIZE; i++) { @@ -1832,7 +1827,6 @@ static void netback_changed(struct xenbus_device *dev, case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: - case XenbusStateClosed: break; case XenbusStateInitWait: @@ -1847,6 +1841,10 @@ static void netback_changed(struct xenbus_device *dev, netdev_notify_peers(netdev); break; + case XenbusStateClosed: + if (dev->state == XenbusStateClosed) + break; + /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; diff --git a/drivers/of/address.c b/drivers/of/address.c index d3dd41c840f1..1a54f1ffaadb 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -99,11 +99,12 @@ static unsigned int of_bus_default_get_flags(const __be32 *addr) static int of_bus_pci_match(struct device_node *np) { /* + * "pciex" is PCI Express * "vci" is for the /chaos bridge on 1st-gen PCI powermacs * "ht" is hypertransport */ - return !strcmp(np->type, "pci") || !strcmp(np->type, "vci") || - !strcmp(np->type, "ht"); + return !strcmp(np->type, "pci") || !strcmp(np->type, "pciex") || + !strcmp(np->type, "vci") || !strcmp(np->type, "ht"); } static void of_bus_pci_count_cells(struct device_node *np, diff --git a/drivers/of/base.c b/drivers/of/base.c index ff85450d5683..89e888a78899 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -342,27 +342,72 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) } EXPORT_SYMBOL(of_get_cpu_node); -/** Checks if the given "compat" string matches one of the strings in - * the device's "compatible" property +/** + * __of_device_is_compatible() - Check if the node matches given constraints + * @device: pointer to node + * @compat: required compatible string, NULL or "" for any match + * @type: required device_type value, NULL or "" for any match + * @name: required node name, NULL or "" for any match + * + * Checks if the given @compat, @type and @name strings match the + * properties of the given @device. A constraints can be skipped by + * passing NULL or an empty string as the constraint. + * + * Returns 0 for no match, and a positive integer on match. The return + * value is a relative score with larger values indicating better + * matches. The score is weighted for the most specific compatible value + * to get the highest score. Matching type is next, followed by matching + * name. Practically speaking, this results in the following priority + * order for matches: + * + * 1. specific compatible && type && name + * 2. specific compatible && type + * 3. specific compatible && name + * 4. specific compatible + * 5. general compatible && type && name + * 6. general compatible && type + * 7. general compatible && name + * 8. general compatible + * 9. type && name + * 10. type + * 11. name */ static int __of_device_is_compatible(const struct device_node *device, - const char *compat) + const char *compat, const char *type, const char *name) { - const char* cp; - int cplen, l; + struct property *prop; + const char *cp; + int index = 0, score = 0; + + /* Compatible match has highest priority */ + if (compat && compat[0]) { + prop = __of_find_property(device, "compatible", NULL); + for (cp = of_prop_next_string(prop, NULL); cp; + cp = of_prop_next_string(prop, cp), index++) { + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { + score = INT_MAX/2 - (index << 2); + break; + } + } + if (!score) + return 0; + } - cp = __of_get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; + /* Matching type is better than matching name */ + if (type && type[0]) { + if (!device->type || of_node_cmp(type, device->type)) + return 0; + score += 2; } - return 0; + /* Matching name is a bit better than not */ + if (name && name[0]) { + if (!device->name || of_node_cmp(name, device->name)) + return 0; + score++; + } + + return score; } /** Checks if the given "compat" string matches one of the strings in @@ -375,7 +420,7 @@ int of_device_is_compatible(const struct device_node *device, int res; raw_spin_lock_irqsave(&devtree_lock, flags); - res = __of_device_is_compatible(device, compat); + res = __of_device_is_compatible(device, compat, NULL, NULL); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res; } @@ -681,10 +726,7 @@ struct device_node *of_find_compatible_node(struct device_node *from, raw_spin_lock_irqsave(&devtree_lock, flags); np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) { - if (type - && !(np->type && (of_node_cmp(np->type, type) == 0))) - continue; - if (__of_device_is_compatible(np, compatible) && + if (__of_device_is_compatible(np, compatible, type, NULL) && of_node_get(np)) break; } @@ -734,43 +776,22 @@ static const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { - const char *cp; - int cplen, l; + const struct of_device_id *best_match = NULL; + int score, best_score = 0; if (!matches) return NULL; - cp = __of_get_property(node, "compatible", &cplen); - do { - const struct of_device_id *m = matches; - - /* Check against matches with current compatible string */ - while (m->name[0] || m->type[0] || m->compatible[0]) { - int match = 1; - if (m->name[0]) - match &= node->name - && !strcmp(m->name, node->name); - if (m->type[0]) - match &= node->type - && !strcmp(m->type, node->type); - if (m->compatible[0]) - match &= cp - && !of_compat_cmp(m->compatible, cp, - strlen(m->compatible)); - if (match) - return m; - m++; - } - - /* Get node's next compatible string */ - if (cp) { - l = strlen(cp) + 1; - cp += l; - cplen -= l; + for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { + score = __of_device_is_compatible(node, matches->compatible, + matches->type, matches->name); + if (score > best_score) { + best_match = matches; + best_score = score; } - } while (cp && (cplen > 0)); + } - return NULL; + return best_match; } /** @@ -778,10 +799,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches, * @matches: array of of device match structures to search in * @node: the of device structure to match against * - * Low level utility function used by device matching. Matching order - * is to compare each of the node's compatibles with all given matches - * first. This implies node's compatible is sorted from specific to - * generic while matches can be in any order. + * Low level utility function used by device matching. */ const struct of_device_id *of_match_node(const struct of_device_id *matches, const struct device_node *node) diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 875b7b6f0d2a..5b3c24f3cde5 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -24,7 +24,11 @@ MODULE_LICENSE("GPL"); static void of_set_phy_supported(struct phy_device *phydev, u32 max_speed) { - phydev->supported |= PHY_DEFAULT_FEATURES; + /* The default values for phydev->supported are provided by the PHY + * driver "features" member, we want to reset to sane defaults fist + * before supporting higher speeds. + */ + phydev->supported &= PHY_DEFAULT_FEATURES; switch (max_speed) { default: @@ -44,7 +48,7 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi { struct phy_device *phy; bool is_c45; - int rc, prev_irq; + int rc; u32 max_speed = 0; is_c45 = of_device_is_compatible(child, @@ -54,12 +58,14 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi if (!phy || IS_ERR(phy)) return 1; - if (mdio->irq) { - prev_irq = mdio->irq[addr]; - mdio->irq[addr] = - irq_of_parse_and_map(child, 0); - if (!mdio->irq[addr]) - mdio->irq[addr] = prev_irq; + rc = irq_of_parse_and_map(child, 0); + if (rc > 0) { + phy->irq = rc; + if (mdio->irq) + mdio->irq[addr] = rc; + } else { + if (mdio->irq) + phy->irq = mdio->irq[addr]; } /* Associate the OF node with the device structure so it diff --git a/drivers/of/of_net.c b/drivers/of/of_net.c index a208a457558c..84215c1929c4 100644 --- a/drivers/of/of_net.c +++ b/drivers/of/of_net.c @@ -12,28 +12,6 @@ #include <linux/export.h> /** - * It maps 'enum phy_interface_t' found in include/linux/phy.h - * into the device tree binding of 'phy-mode', so that Ethernet - * device driver can get phy interface from device tree. - */ -static const char *phy_modes[] = { - [PHY_INTERFACE_MODE_NA] = "", - [PHY_INTERFACE_MODE_MII] = "mii", - [PHY_INTERFACE_MODE_GMII] = "gmii", - [PHY_INTERFACE_MODE_SGMII] = "sgmii", - [PHY_INTERFACE_MODE_TBI] = "tbi", - [PHY_INTERFACE_MODE_REVMII] = "rev-mii", - [PHY_INTERFACE_MODE_RMII] = "rmii", - [PHY_INTERFACE_MODE_RGMII] = "rgmii", - [PHY_INTERFACE_MODE_RGMII_ID] = "rgmii-id", - [PHY_INTERFACE_MODE_RGMII_RXID] = "rgmii-rxid", - [PHY_INTERFACE_MODE_RGMII_TXID] = "rgmii-txid", - [PHY_INTERFACE_MODE_RTBI] = "rtbi", - [PHY_INTERFACE_MODE_SMII] = "smii", - [PHY_INTERFACE_MODE_XGMII] = "xgmii", -}; - -/** * of_get_phy_mode - Get phy mode for given device_node * @np: Pointer to the given device_node * @@ -49,8 +27,8 @@ int of_get_phy_mode(struct device_node *np) if (err < 0) return err; - for (i = 0; i < ARRAY_SIZE(phy_modes); i++) - if (!strcasecmp(pm, phy_modes[i])) + for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) + if (!strcasecmp(pm, phy_modes(i))) return i; return -ENODEV; diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index e21012bde639..6643d1920985 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c @@ -300,6 +300,72 @@ static void __init of_selftest_parse_interrupts_extended(void) of_node_put(np); } +static struct of_device_id match_node_table[] = { + { .data = "A", .name = "name0", }, /* Name alone is lowest priority */ + { .data = "B", .type = "type1", }, /* followed by type alone */ + + { .data = "Ca", .name = "name2", .type = "type1", }, /* followed by both together */ + { .data = "Cb", .name = "name2", }, /* Only match when type doesn't match */ + { .data = "Cc", .name = "name2", .type = "type2", }, + + { .data = "E", .compatible = "compat3" }, + { .data = "G", .compatible = "compat2", }, + { .data = "H", .compatible = "compat2", .name = "name5", }, + { .data = "I", .compatible = "compat2", .type = "type1", }, + { .data = "J", .compatible = "compat2", .type = "type1", .name = "name8", }, + { .data = "K", .compatible = "compat2", .name = "name9", }, + {} +}; + +static struct { + const char *path; + const char *data; +} match_node_tests[] = { + { .path = "/testcase-data/match-node/name0", .data = "A", }, + { .path = "/testcase-data/match-node/name1", .data = "B", }, + { .path = "/testcase-data/match-node/a/name2", .data = "Ca", }, + { .path = "/testcase-data/match-node/b/name2", .data = "Cb", }, + { .path = "/testcase-data/match-node/c/name2", .data = "Cc", }, + { .path = "/testcase-data/match-node/name3", .data = "E", }, + { .path = "/testcase-data/match-node/name4", .data = "G", }, + { .path = "/testcase-data/match-node/name5", .data = "H", }, + { .path = "/testcase-data/match-node/name6", .data = "G", }, + { .path = "/testcase-data/match-node/name7", .data = "I", }, + { .path = "/testcase-data/match-node/name8", .data = "J", }, + { .path = "/testcase-data/match-node/name9", .data = "K", }, +}; + +static void __init of_selftest_match_node(void) +{ + struct device_node *np; + const struct of_device_id *match; + int i; + + for (i = 0; i < ARRAY_SIZE(match_node_tests); i++) { + np = of_find_node_by_path(match_node_tests[i].path); + if (!np) { + selftest(0, "missing testcase node %s\n", + match_node_tests[i].path); + continue; + } + + match = of_match_node(match_node_table, np); + if (!match) { + selftest(0, "%s didn't match anything\n", + match_node_tests[i].path); + continue; + } + + if (strcmp(match->data, match_node_tests[i].data) != 0) { + selftest(0, "%s got wrong match. expected %s, got %s\n", + match_node_tests[i].path, match_node_tests[i].data, + (const char *)match->data); + continue; + } + selftest(1, "passed"); + } +} + static int __init of_selftest(void) { struct device_node *np; @@ -316,6 +382,7 @@ static int __init of_selftest(void) of_selftest_property_match_string(); of_selftest_parse_interrupts(); of_selftest_parse_interrupts_extended(); + of_selftest_match_node(); pr_info("end of selftest - %i passed, %i failed\n", selftest_results.passed, selftest_results.failed); return 0; diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi new file mode 100644 index 000000000000..3a5b75a8e4d7 --- /dev/null +++ b/drivers/of/testcase-data/testcases.dtsi @@ -0,0 +1,3 @@ +#include "tests-phandle.dtsi" +#include "tests-interrupts.dtsi" +#include "tests-match.dtsi" diff --git a/drivers/of/testcase-data/tests-interrupts.dtsi b/drivers/of/testcase-data/tests-interrupts.dtsi new file mode 100644 index 000000000000..c843720bd3e5 --- /dev/null +++ b/drivers/of/testcase-data/tests-interrupts.dtsi @@ -0,0 +1,58 @@ + +/ { + testcase-data { + interrupts { + #address-cells = <1>; + #size-cells = <1>; + test_intc0: intc0 { + interrupt-controller; + #interrupt-cells = <1>; + }; + + test_intc1: intc1 { + interrupt-controller; + #interrupt-cells = <3>; + }; + + test_intc2: intc2 { + interrupt-controller; + #interrupt-cells = <2>; + }; + + test_intmap0: intmap0 { + #interrupt-cells = <1>; + #address-cells = <0>; + interrupt-map = <1 &test_intc0 9>, + <2 &test_intc1 10 11 12>, + <3 &test_intc2 13 14>, + <4 &test_intc2 15 16>; + }; + + test_intmap1: intmap1 { + #interrupt-cells = <2>; + interrupt-map = <0x5000 1 2 &test_intc0 15>; + }; + + interrupts0 { + interrupt-parent = <&test_intc0>; + interrupts = <1>, <2>, <3>, <4>; + }; + + interrupts1 { + interrupt-parent = <&test_intmap0>; + interrupts = <1>, <2>, <3>, <4>; + }; + + interrupts-extended0 { + reg = <0x5000 0x100>; + interrupts-extended = <&test_intc0 1>, + <&test_intc1 2 3 4>, + <&test_intc2 5 6>, + <&test_intmap0 1>, + <&test_intmap0 2>, + <&test_intmap0 3>, + <&test_intmap1 1 2>; + }; + }; + }; +}; diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/testcase-data/tests-match.dtsi new file mode 100644 index 000000000000..c9e541129534 --- /dev/null +++ b/drivers/of/testcase-data/tests-match.dtsi @@ -0,0 +1,19 @@ + +/ { + testcase-data { + match-node { + name0 { }; + name1 { device_type = "type1"; }; + a { name2 { device_type = "type1"; }; }; + b { name2 { }; }; + c { name2 { device_type = "type2"; }; }; + name3 { compatible = "compat3"; }; + name4 { compatible = "compat2", "compat3"; }; + name5 { compatible = "compat2", "compat3"; }; + name6 { compatible = "compat1", "compat2", "compat3"; }; + name7 { compatible = "compat2"; device_type = "type1"; }; + name8 { compatible = "compat2"; device_type = "type1"; }; + name9 { compatible = "compat2"; }; + }; + }; +}; diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi new file mode 100644 index 000000000000..0007d3cd7dc2 --- /dev/null +++ b/drivers/of/testcase-data/tests-phandle.dtsi @@ -0,0 +1,39 @@ + +/ { + testcase-data { + phandle-tests { + provider0: provider0 { + #phandle-cells = <0>; + }; + + provider1: provider1 { + #phandle-cells = <1>; + }; + + provider2: provider2 { + #phandle-cells = <2>; + }; + + provider3: provider3 { + #phandle-cells = <3>; + }; + + consumer-a { + phandle-list = <&provider1 1>, + <&provider2 2 0>, + <0>, + <&provider3 4 4 3>, + <&provider2 5 100>, + <&provider0>, + <&provider1 7>; + phandle-list-names = "first", "second", "third"; + + phandle-list-bad-phandle = <12345678 0 0>; + phandle-list-bad-args = <&provider2 1 0>, + <&provider3 0>; + empty-property; + unterminated-string = [40 41 42 43]; + }; + }; + }; +}; diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c index 13478ecd4113..0e79665afd44 100644 --- a/drivers/pci/host/pci-mvebu.c +++ b/drivers/pci/host/pci-mvebu.c @@ -60,14 +60,6 @@ #define PCIE_DEBUG_CTRL 0x1a60 #define PCIE_DEBUG_SOFT_RESET BIT(20) -/* - * This product ID is registered by Marvell, and used when the Marvell - * SoC is not the root complex, but an endpoint on the PCIe bus. It is - * therefore safe to re-use this PCI ID for our emulated PCI-to-PCI - * bridge. - */ -#define MARVELL_EMULATED_PCI_PCI_BRIDGE_ID 0x7846 - /* PCI configuration space of a PCI-to-PCI bridge */ struct mvebu_sw_pci_bridge { u16 vendor; @@ -388,7 +380,8 @@ static void mvebu_sw_pci_bridge_init(struct mvebu_pcie_port *port) bridge->class = PCI_CLASS_BRIDGE_PCI; bridge->vendor = PCI_VENDOR_ID_MARVELL; - bridge->device = MARVELL_EMULATED_PCI_PCI_BRIDGE_ID; + bridge->device = mvebu_readl(port, PCIE_DEV_ID_OFF) >> 16; + bridge->revision = mvebu_readl(port, PCIE_DEV_REV_OFF) & 0xff; bridge->header_type = PCI_HEADER_TYPE_BRIDGE; bridge->cache_line_size = 0x10; diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index e2a783fdb98f..7c7a388c85ab 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -730,6 +730,17 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot) return (unsigned int)sta; } +static inline bool device_status_valid(unsigned int sta) +{ + /* + * ACPI spec says that _STA may return bit 0 clear with bit 3 set + * if the device is valid but does not require a device driver to be + * loaded (Section 6.3.7 of ACPI 5.0A). + */ + unsigned int mask = ACPI_STA_DEVICE_ENABLED | ACPI_STA_DEVICE_FUNCTIONING; + return (sta & mask) == mask; +} + /** * trim_stale_devices - remove PCI devices that are not responding. * @dev: PCI device to start walking the hierarchy from. @@ -745,7 +756,7 @@ 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) && device_status_valid(sta)) || acpiphp_no_hotplug(handle); } if (!alive) { @@ -792,7 +803,7 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge) mutex_lock(&slot->crit_sect); if (slot_no_hotplug(slot)) { ; /* do nothing */ - } else if (get_slot_status(slot) == ACPI_STA_ALL) { + } else if (device_status_valid(get_slot_status(slot))) { /* remove stale devices if any */ list_for_each_entry_safe_reverse(dev, tmp, &bus->devices, bus_list) diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index 7a0fec6ce571..955ab7990c5b 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -545,9 +545,15 @@ static int populate_msi_sysfs(struct pci_dev *pdev) return -ENOMEM; list_for_each_entry(entry, &pdev->msi_list, list) { char *name = kmalloc(20, GFP_KERNEL); + if (!name) + goto error_attrs; + msi_dev_attr = kzalloc(sizeof(*msi_dev_attr), GFP_KERNEL); - if (!msi_dev_attr) + if (!msi_dev_attr) { + kfree(name); goto error_attrs; + } + sprintf(name, "%d", entry->irq); sysfs_attr_init(&msi_dev_attr->attr); msi_dev_attr->attr.name = name; @@ -589,6 +595,7 @@ error_attrs: ++count; msi_attr = msi_attrs[count]; } + kfree(msi_attrs); return ret; } @@ -959,7 +966,6 @@ EXPORT_SYMBOL(pci_disable_msi); /** * pci_msix_vec_count - return the number of device's MSI-X table entries * @dev: pointer to the pci_dev data structure of MSI-X device function - * This function returns the number of device's MSI-X table entries and * therefore the number of MSI-X vectors device is capable of sending. * It returns a negative errno if the device is not capable of sending MSI-X diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 1febe90831b4..6b05f6134b68 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1181,6 +1181,8 @@ EXPORT_SYMBOL_GPL(pci_load_and_free_saved_state); static int do_pci_enable_device(struct pci_dev *dev, int bars) { int err; + u16 cmd; + u8 pin; err = pci_set_power_state(dev, PCI_D0); if (err < 0 && err != -EIO) @@ -1190,6 +1192,14 @@ static int do_pci_enable_device(struct pci_dev *dev, int bars) return err; pci_fixup_device(pci_fixup_enable, dev); + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); + if (pin) { + pci_read_config_word(dev, PCI_COMMAND, &cmd); + if (cmd & PCI_COMMAND_INTX_DISABLE) + pci_write_config_word(dev, PCI_COMMAND, + cmd & ~PCI_COMMAND_INTX_DISABLE); + } + return 0; } diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index afa2354f6600..c7a551c2d5f1 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -5,7 +5,7 @@ menu "PHY Subsystem" config GENERIC_PHY - tristate "PHY Core" + bool "PHY Core" help Generic PHY support. @@ -61,6 +61,7 @@ config PHY_EXYNOS_DP_VIDEO config BCM_KONA_USB2_PHY tristate "Broadcom Kona USB2 PHY Driver" depends on GENERIC_PHY + depends on HAS_IOMEM help Enable this to support the Broadcom Kona USB 2.0 PHY. diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c index 645c867c1257..6c738376daff 100644 --- a/drivers/phy/phy-core.c +++ b/drivers/phy/phy-core.c @@ -162,6 +162,9 @@ int phy_init(struct phy *phy) { int ret; + if (!phy) + return 0; + ret = phy_pm_runtime_get_sync(phy); if (ret < 0 && ret != -ENOTSUPP) return ret; @@ -173,6 +176,8 @@ int phy_init(struct phy *phy) dev_err(&phy->dev, "phy init failed --> %d\n", ret); goto out; } + } else { + ret = 0; /* Override possible ret == -ENOTSUPP */ } ++phy->init_count; @@ -187,6 +192,9 @@ int phy_exit(struct phy *phy) { int ret; + if (!phy) + return 0; + ret = phy_pm_runtime_get_sync(phy); if (ret < 0 && ret != -ENOTSUPP) return ret; @@ -212,6 +220,9 @@ int phy_power_on(struct phy *phy) { int ret; + if (!phy) + return 0; + ret = phy_pm_runtime_get_sync(phy); if (ret < 0 && ret != -ENOTSUPP) return ret; @@ -223,6 +234,8 @@ int phy_power_on(struct phy *phy) dev_err(&phy->dev, "phy poweron failed --> %d\n", ret); goto out; } + } else { + ret = 0; /* Override possible ret == -ENOTSUPP */ } ++phy->power_count; mutex_unlock(&phy->mutex); @@ -240,6 +253,9 @@ int phy_power_off(struct phy *phy) { int ret; + if (!phy) + return 0; + mutex_lock(&phy->mutex); if (phy->power_count == 1 && phy->ops->power_off) { ret = phy->ops->power_off(phy); @@ -308,7 +324,7 @@ err0: */ void phy_put(struct phy *phy) { - if (IS_ERR(phy)) + if (!phy || IS_ERR(phy)) return; module_put(phy->ops->owner); @@ -328,6 +344,9 @@ void devm_phy_put(struct device *dev, struct phy *phy) { int r; + if (!phy) + return; + r = devres_destroy(dev, devm_phy_release, devm_phy_match, phy); dev_WARN_ONCE(dev, r, "couldn't find PHY resource\n"); } @@ -389,17 +408,11 @@ struct phy *phy_get(struct device *dev, const char *string) index = of_property_match_string(dev->of_node, "phy-names", string); phy = of_phy_get(dev, index); - if (IS_ERR(phy)) { - dev_err(dev, "unable to find phy\n"); - return phy; - } } else { phy = phy_lookup(dev, string); - if (IS_ERR(phy)) { - dev_err(dev, "unable to find phy\n"); - return phy; - } } + if (IS_ERR(phy)) + return phy; if (!try_module_get(phy->ops->owner)) return ERR_PTR(-EPROBE_DEFER); @@ -411,6 +424,27 @@ struct phy *phy_get(struct device *dev, const char *string) EXPORT_SYMBOL_GPL(phy_get); /** + * phy_optional_get() - lookup and obtain a reference to an optional phy. + * @dev: device that requests this phy + * @string: the phy name as given in the dt data or the name of the controller + * port for non-dt case + * + * Returns the phy driver, after getting a refcount to it; or + * NULL if there is no such phy. The caller is responsible for + * calling phy_put() to release that count. + */ +struct phy *phy_optional_get(struct device *dev, const char *string) +{ + struct phy *phy = phy_get(dev, string); + + if (PTR_ERR(phy) == -ENODEV) + phy = NULL; + + return phy; +} +EXPORT_SYMBOL_GPL(phy_optional_get); + +/** * devm_phy_get() - lookup and obtain a reference to a phy. * @dev: device that requests this phy * @string: the phy name as given in the dt data or phy device name @@ -441,6 +475,30 @@ struct phy *devm_phy_get(struct device *dev, const char *string) EXPORT_SYMBOL_GPL(devm_phy_get); /** + * devm_phy_optional_get() - lookup and obtain a reference to an optional phy. + * @dev: device that requests this phy + * @string: the phy name as given in the dt data or phy device name + * for non-dt case + * + * Gets the phy using phy_get(), and associates a device with it using + * devres. On driver detach, release function is invoked on the devres + * data, then, devres data is freed. This differs to devm_phy_get() in + * that if the phy does not exist, it is not considered an error and + * -ENODEV will not be returned. Instead the NULL phy is returned, + * which can be passed to all other phy consumer calls. + */ +struct phy *devm_phy_optional_get(struct device *dev, const char *string) +{ + struct phy *phy = devm_phy_get(dev, string); + + if (PTR_ERR(phy) == -ENODEV) + phy = NULL; + + return phy; +} +EXPORT_SYMBOL_GPL(devm_phy_optional_get); + +/** * phy_create() - create a new phy * @dev: device that is creating the new phy * @ops: function pointers for performing phy operations diff --git a/drivers/phy/phy-exynos-dp-video.c b/drivers/phy/phy-exynos-dp-video.c index 1dbe6ce7b2ce..0786fef842e7 100644 --- a/drivers/phy/phy-exynos-dp-video.c +++ b/drivers/phy/phy-exynos-dp-video.c @@ -76,10 +76,6 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) if (IS_ERR(state->regs)) return PTR_ERR(state->regs); - phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - phy = devm_phy_create(dev, &exynos_dp_video_phy_ops, NULL); if (IS_ERR(phy)) { dev_err(dev, "failed to create Display Port PHY\n"); @@ -87,6 +83,10 @@ static int exynos_dp_video_phy_probe(struct platform_device *pdev) } phy_set_drvdata(phy, state); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + return 0; } diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c index 0c5efab11af1..7f139326a642 100644 --- a/drivers/phy/phy-exynos-mipi-video.c +++ b/drivers/phy/phy-exynos-mipi-video.c @@ -134,11 +134,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) dev_set_drvdata(dev, state); spin_lock_init(&state->slock); - phy_provider = devm_of_phy_provider_register(dev, - exynos_mipi_video_phy_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) { struct phy *phy = devm_phy_create(dev, &exynos_mipi_video_phy_ops, NULL); @@ -152,6 +147,11 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev) phy_set_drvdata(phy, &state->phys[i]); } + phy_provider = devm_of_phy_provider_register(dev, + exynos_mipi_video_phy_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + return 0; } diff --git a/drivers/phy/phy-mvebu-sata.c b/drivers/phy/phy-mvebu-sata.c index d43786f62437..d70ecd6a1b3f 100644 --- a/drivers/phy/phy-mvebu-sata.c +++ b/drivers/phy/phy-mvebu-sata.c @@ -99,17 +99,17 @@ static int phy_mvebu_sata_probe(struct platform_device *pdev) if (IS_ERR(priv->clk)) return PTR_ERR(priv->clk); - phy_provider = devm_of_phy_provider_register(&pdev->dev, - of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - phy = devm_phy_create(&pdev->dev, &phy_mvebu_sata_ops, NULL); if (IS_ERR(phy)) return PTR_ERR(phy); phy_set_drvdata(phy, priv); + phy_provider = devm_of_phy_provider_register(&pdev->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + /* The boot loader may of left it on. Turn it off. */ phy_mvebu_sata_power_off(phy); diff --git a/drivers/phy/phy-omap-usb2.c b/drivers/phy/phy-omap-usb2.c index bfc5c337f99a..7699752fba11 100644 --- a/drivers/phy/phy-omap-usb2.c +++ b/drivers/phy/phy-omap-usb2.c @@ -177,11 +177,6 @@ static int omap_usb2_probe(struct platform_device *pdev) phy->phy.otg = otg; phy->phy.type = USB_PHY_TYPE_USB2; - phy_provider = devm_of_phy_provider_register(phy->dev, - of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - control_node = of_parse_phandle(node, "ctrl-module", 0); if (!control_node) { dev_err(&pdev->dev, "Failed to get control device phandle\n"); @@ -214,6 +209,11 @@ static int omap_usb2_probe(struct platform_device *pdev) phy_set_drvdata(generic_phy, phy); + phy_provider = devm_of_phy_provider_register(phy->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); if (IS_ERR(phy->wkupclk)) { dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); diff --git a/drivers/phy/phy-twl4030-usb.c b/drivers/phy/phy-twl4030-usb.c index daf65e68aaab..c3ace1db8136 100644 --- a/drivers/phy/phy-twl4030-usb.c +++ b/drivers/phy/phy-twl4030-usb.c @@ -695,11 +695,6 @@ static int twl4030_usb_probe(struct platform_device *pdev) otg->set_host = twl4030_set_host; otg->set_peripheral = twl4030_set_peripheral; - phy_provider = devm_of_phy_provider_register(twl->dev, - of_phy_simple_xlate); - if (IS_ERR(phy_provider)) - return PTR_ERR(phy_provider); - phy = devm_phy_create(twl->dev, &ops, init_data); if (IS_ERR(phy)) { dev_dbg(&pdev->dev, "Failed to create PHY\n"); @@ -708,6 +703,11 @@ static int twl4030_usb_probe(struct platform_device *pdev) phy_set_drvdata(phy, twl); + phy_provider = devm_of_phy_provider_register(twl->dev, + of_phy_simple_xlate); + if (IS_ERR(phy_provider)) + return PTR_ERR(phy_provider); + /* init spinlock for workqueue */ spin_lock_init(&twl->lock); diff --git a/drivers/power/ds2782_battery.c b/drivers/power/ds2782_battery.c index 563174891c90..041f9b638d28 100644 --- a/drivers/power/ds2782_battery.c +++ b/drivers/power/ds2782_battery.c @@ -192,7 +192,7 @@ static int ds2786_get_voltage(struct ds278x_info *info, int *voltage_uV) /* * Voltage is measured in units of 1.22mV. The voltage is stored as - * a 10-bit number plus sign, in the upper bits of a 16-bit register + * a 12-bit number plus sign, in the upper bits of a 16-bit register */ err = ds278x_read_reg16(info, DS278x_REG_VOLT_MSB, &raw); if (err) diff --git a/drivers/power/isp1704_charger.c b/drivers/power/isp1704_charger.c index 80edb7d8cb54..0b4cf9d63291 100644 --- a/drivers/power/isp1704_charger.c +++ b/drivers/power/isp1704_charger.c @@ -444,8 +444,6 @@ static int isp1704_charger_probe(struct platform_device *pdev) ret = PTR_ERR(isp->phy); goto fail0; } - if (!isp->phy) - goto fail0; isp->dev = &pdev->dev; platform_set_drvdata(pdev, isp); diff --git a/drivers/power/max17040_battery.c b/drivers/power/max17040_battery.c index c7ff6d67f158..0fbac861080d 100644 --- a/drivers/power/max17040_battery.c +++ b/drivers/power/max17040_battery.c @@ -148,7 +148,7 @@ static void max17040_get_online(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - if (chip->pdata->battery_online) + if (chip->pdata && chip->pdata->battery_online) chip->online = chip->pdata->battery_online(); else chip->online = 1; @@ -158,7 +158,8 @@ static void max17040_get_status(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - if (!chip->pdata->charger_online || !chip->pdata->charger_enable) { + if (!chip->pdata || !chip->pdata->charger_online + || !chip->pdata->charger_enable) { chip->status = POWER_SUPPLY_STATUS_UNKNOWN; return; } diff --git a/drivers/pwm/pwm-lp3943.c b/drivers/pwm/pwm-lp3943.c index 8a843a04c224..a40b9c34e9ff 100644 --- a/drivers/pwm/pwm-lp3943.c +++ b/drivers/pwm/pwm-lp3943.c @@ -52,8 +52,10 @@ lp3943_pwm_request_map(struct lp3943_pwm *lp3943_pwm, int hwpwm) offset = pwm_map->output[i]; /* Return an error if the pin is already assigned */ - if (test_and_set_bit(offset, &lp3943->pin_used)) + if (test_and_set_bit(offset, &lp3943->pin_used)) { + kfree(pwm_map); return ERR_PTR(-EBUSY); + } } return pwm_map; diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h index b4b0d83f9ef6..7061ac0ad428 100644 --- a/drivers/rapidio/devices/tsi721.h +++ b/drivers/rapidio/devices/tsi721.h @@ -678,6 +678,7 @@ struct tsi721_bdma_chan { struct list_head free_list; dma_cookie_t completed_cookie; struct tasklet_struct tasklet; + bool active; }; #endif /* CONFIG_RAPIDIO_DMA_ENGINE */ diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c index 502663f5f7c6..91245f5dbe81 100644 --- a/drivers/rapidio/devices/tsi721_dma.c +++ b/drivers/rapidio/devices/tsi721_dma.c @@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan) { /* Disable BDMA channel interrupts */ iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE); - - tasklet_schedule(&bdma_chan->tasklet); + if (bdma_chan->active) + tasklet_schedule(&bdma_chan->tasklet); } #ifdef CONFIG_PCI_MSI @@ -562,7 +562,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan) } #endif /* CONFIG_PCI_MSI */ - tasklet_enable(&bdma_chan->tasklet); + bdma_chan->active = true; tsi721_bdma_interrupt_enable(bdma_chan, 1); return bdma_chan->bd_num - 1; @@ -576,9 +576,7 @@ err_out: static void tsi721_free_chan_resources(struct dma_chan *dchan) { struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan); -#ifdef CONFIG_PCI_MSI struct tsi721_device *priv = to_tsi721(dchan->device); -#endif LIST_HEAD(list); dev_dbg(dchan->device->dev, "%s: Entry\n", __func__); @@ -589,14 +587,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan) BUG_ON(!list_empty(&bdma_chan->active_list)); BUG_ON(!list_empty(&bdma_chan->queue)); - tasklet_disable(&bdma_chan->tasklet); + tsi721_bdma_interrupt_enable(bdma_chan, 0); + bdma_chan->active = false; + +#ifdef CONFIG_PCI_MSI + if (priv->flags & TSI721_USING_MSIX) { + synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE + + bdma_chan->id].vector); + synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT + + bdma_chan->id].vector); + } else +#endif + synchronize_irq(priv->pdev->irq); + + tasklet_kill(&bdma_chan->tasklet); spin_lock_bh(&bdma_chan->lock); list_splice_init(&bdma_chan->free_list, &list); spin_unlock_bh(&bdma_chan->lock); - tsi721_bdma_interrupt_enable(bdma_chan, 0); - #ifdef CONFIG_PCI_MSI if (priv->flags & TSI721_USING_MSIX) { free_irq(priv->msix[TSI721_VECT_DMA0_DONE + @@ -790,6 +799,7 @@ int tsi721_register_dma(struct tsi721_device *priv) bdma_chan->dchan.cookie = 1; bdma_chan->dchan.chan_id = i; bdma_chan->id = i; + bdma_chan->active = false; spin_lock_init(&bdma_chan->lock); @@ -799,7 +809,6 @@ int tsi721_register_dma(struct tsi721_device *priv) tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet, (unsigned long)bdma_chan); - tasklet_disable(&bdma_chan->tasklet); list_add_tail(&bdma_chan->dchan.device_node, &mport->dma.channels); } diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 16a309e5c024..afca1bc24f26 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -953,6 +953,8 @@ static int machine_constraints_current(struct regulator_dev *rdev, return 0; } +static int _regulator_do_enable(struct regulator_dev *rdev); + /** * set_machine_constraints - sets regulator constraints * @rdev: regulator source @@ -1013,10 +1015,9 @@ static int set_machine_constraints(struct regulator_dev *rdev, /* If the constraints say the regulator should be on at this point * and we have control then make sure it is enabled. */ - if ((rdev->constraints->always_on || rdev->constraints->boot_on) && - ops->enable) { - ret = ops->enable(rdev); - if (ret < 0) { + if (rdev->constraints->always_on || rdev->constraints->boot_on) { + ret = _regulator_do_enable(rdev); + if (ret < 0 && ret != -EINVAL) { rdev_err(rdev, "failed to enable\n"); goto out; } @@ -1359,7 +1360,7 @@ static struct regulator *_regulator_get(struct device *dev, const char *id, goto found; /* Don't log an error when called from regulator_get_optional() */ } else if (!have_full_constraints() || exclusive) { - dev_err(dev, "dummy supplies not allowed\n"); + dev_warn(dev, "dummy supplies not allowed\n"); } mutex_unlock(®ulator_list_mutex); @@ -1907,8 +1908,6 @@ static int _regulator_do_disable(struct regulator_dev *rdev) trace_regulator_disable_complete(rdev_get_name(rdev)); - _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, - NULL); return 0; } @@ -1932,6 +1931,8 @@ static int _regulator_disable(struct regulator_dev *rdev) rdev_err(rdev, "failed to disable\n"); return ret; } + _notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE, + NULL); } rdev->use_count = 0; @@ -1984,20 +1985,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev) { int ret = 0; - /* force disable */ - if (rdev->desc->ops->disable) { - /* ah well, who wants to live forever... */ - ret = rdev->desc->ops->disable(rdev); - if (ret < 0) { - rdev_err(rdev, "failed to force disable\n"); - return ret; - } - /* notify other consumers that power has been forced off */ - _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | - REGULATOR_EVENT_DISABLE, NULL); + ret = _regulator_do_disable(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to force disable\n"); + return ret; } - return ret; + _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE | + REGULATOR_EVENT_DISABLE, NULL); + + return 0; } /** @@ -3630,23 +3627,18 @@ int regulator_suspend_finish(void) mutex_lock(®ulator_list_mutex); list_for_each_entry(rdev, ®ulator_list, list) { - struct regulator_ops *ops = rdev->desc->ops; - mutex_lock(&rdev->mutex); - if ((rdev->use_count > 0 || rdev->constraints->always_on) && - ops->enable) { - error = ops->enable(rdev); + if (rdev->use_count > 0 || rdev->constraints->always_on) { + error = _regulator_do_enable(rdev); if (error) ret = error; } else { if (!have_full_constraints()) goto unlock; - if (!ops->disable) - goto unlock; if (!_regulator_is_enabled(rdev)) goto unlock; - error = ops->disable(rdev); + error = _regulator_do_disable(rdev); if (error) ret = error; } @@ -3820,7 +3812,7 @@ static int __init regulator_init_complete(void) ops = rdev->desc->ops; c = rdev->constraints; - if (!ops->disable || (c && c->always_on)) + if (c && c->always_on) continue; mutex_lock(&rdev->mutex); @@ -3841,7 +3833,7 @@ static int __init regulator_init_complete(void) /* We log since this may kill the system if it * goes wrong. */ rdev_info(rdev, "disabling\n"); - ret = ops->disable(rdev); + ret = _regulator_do_disable(rdev); if (ret != 0) rdev_err(rdev, "couldn't disable: %d\n", ret); } else { diff --git a/drivers/regulator/da9055-regulator.c b/drivers/regulator/da9055-regulator.c index 7f340206d329..b14ebdad5dd2 100644 --- a/drivers/regulator/da9055-regulator.c +++ b/drivers/regulator/da9055-regulator.c @@ -576,7 +576,9 @@ static int da9055_regulator_probe(struct platform_device *pdev) /* Only LDO 5 and 6 has got the over current interrupt */ if (pdev->id == DA9055_ID_LDO5 || pdev->id == DA9055_ID_LDO6) { irq = platform_get_irq_byname(pdev, "REGULATOR"); - irq = regmap_irq_get_virq(da9055->irq_data, irq); + if (irq < 0) + return irq; + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, da9055_ldo5_6_oc_irq, IRQF_TRIGGER_HIGH | diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c index 56727eb745df..91e99a2c8dc1 100644 --- a/drivers/regulator/da9063-regulator.c +++ b/drivers/regulator/da9063-regulator.c @@ -1,3 +1,4 @@ + /* * Regulator driver for DA9063 PMIC series * @@ -60,7 +61,8 @@ struct da9063_regulator_info { .desc.ops = &da9063_ldo_ops, \ .desc.min_uV = (min_mV) * 1000, \ .desc.uV_step = (step_mV) * 1000, \ - .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1), \ + .desc.n_voltages = (((max_mV) - (min_mV))/(step_mV) + 1 \ + + (DA9063_V##regl_name##_BIAS)), \ .desc.enable_reg = DA9063_REG_##regl_name##_CONT, \ .desc.enable_mask = DA9063_LDO_EN, \ .desc.vsel_reg = DA9063_REG_V##regl_name##_A, \ diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c index b1078ba3f393..e0619526708c 100644 --- a/drivers/regulator/max14577.c +++ b/drivers/regulator/max14577.c @@ -166,12 +166,14 @@ static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev) ret = of_regulator_match(&pdev->dev, np, max14577_regulator_matches, MAX14577_REG_MAX); - if (ret < 0) { + if (ret < 0) dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret); - return ret; - } + else + ret = 0; - return 0; + of_node_put(np); + + return ret; } static inline struct regulator_init_data *match_init_data(int index) diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c index d7164bb75d3e..d958dfa05125 100644 --- a/drivers/regulator/s5m8767.c +++ b/drivers/regulator/s5m8767.c @@ -535,7 +535,7 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, return -ENODEV; } - regulators_np = of_find_node_by_name(pmic_np, "regulators"); + regulators_np = of_get_child_by_name(pmic_np, "regulators"); if (!regulators_np) { dev_err(iodev->dev, "could not find regulators sub-node\n"); return -EINVAL; @@ -591,6 +591,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev, rmode++; } + of_node_put(regulators_np); + if (of_get_property(pmic_np, "s5m8767,pmic-buck2-uses-gpio-dvs", NULL)) { pdata->buck2_gpiodvs = true; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7afd373b9595..c4cde9c08f1f 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev) clk_enable(rtc_clk); /* save TICNT for anyone using periodic interrupts */ - ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); if (s3c_rtc_cpu_type == TYPE_S3C64XX) { ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON); ticnt_en_save &= S3C64XX_RTCCON_TICEN; + ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT); + } else { + ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT); } s3c_rtc_enable(pdev, 0); @@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev) clk_enable(rtc_clk); s3c_rtc_enable(pdev, 1); - writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); - if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { - tmp = readw(s3c_rtc_base + S3C2410_RTCCON); - writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); + if (s3c_rtc_cpu_type == TYPE_S3C64XX) { + writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT); + if (ticnt_en_save) { + tmp = readw(s3c_rtc_base + S3C2410_RTCCON); + writew(tmp | ticnt_en_save, + s3c_rtc_base + S3C2410_RTCCON); + } + } else { + writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); } if (device_may_wakeup(dev) && wake_en) { diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index f6b9188c5af5..9f0ea6cb6922 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -610,6 +610,7 @@ void chsc_chp_online(struct chp_id chpid) css_wait_for_slow_path(); for_each_subchannel_staged(__s390_process_res_acc, NULL, &link); + css_schedule_reprobe(); } } diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c index 88e35d85d205..8ee88c4ebd83 100644 --- a/drivers/s390/cio/cio.c +++ b/drivers/s390/cio/cio.c @@ -342,8 +342,9 @@ static int cio_check_config(struct subchannel *sch, struct schib *schib) */ int cio_commit_config(struct subchannel *sch) { - struct schib schib; int ccode, retry, ret = 0; + struct schib schib; + struct irb irb; if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; @@ -367,7 +368,10 @@ int cio_commit_config(struct subchannel *sch) ret = -EAGAIN; break; case 1: /* status pending */ - return -EBUSY; + ret = -EBUSY; + if (tsch(sch->schid, &irb)) + return ret; + break; case 2: /* busy */ udelay(100); /* allow for recovery */ ret = -EBUSY; @@ -403,7 +407,6 @@ EXPORT_SYMBOL_GPL(cio_update_schib); */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { - int retry; int ret; CIO_TRACE_EVENT(2, "ensch"); @@ -418,20 +421,14 @@ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) sch->config.isc = sch->isc; sch->config.intparm = intparm; - for (retry = 0; retry < 3; retry++) { + ret = cio_commit_config(sch); + if (ret == -EIO) { + /* + * Got a program check in msch. Try without + * the concurrent sense bit the next time. + */ + sch->config.csense = 0; ret = cio_commit_config(sch); - if (ret == -EIO) { - /* - * Got a program check in msch. Try without - * the concurrent sense bit the next time. - */ - sch->config.csense = 0; - } else if (ret == -EBUSY) { - struct irb irb; - if (tsch(sch->schid, &irb) != 0) - break; - } else - break; } CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; @@ -444,7 +441,6 @@ EXPORT_SYMBOL_GPL(cio_enable_subchannel); */ int cio_disable_subchannel(struct subchannel *sch) { - int retry; int ret; CIO_TRACE_EVENT(2, "dissch"); @@ -456,16 +452,8 @@ int cio_disable_subchannel(struct subchannel *sch) return -ENODEV; sch->config.ena = 0; + ret = cio_commit_config(sch); - for (retry = 0; retry < 3; retry++) { - ret = cio_commit_config(sch); - if (ret == -EBUSY) { - struct irb irb; - if (tsch(sch->schid, &irb) != 0) - break; - } else - break; - } CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; } diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 8acaae18bd11..a563e4c00590 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -359,14 +359,12 @@ static inline int multicast_outbound(struct qdio_q *q) #define need_siga_sync_out_after_pci(q) \ (unlikely(q->irq_ptr->siga_flag.sync_out_after_pci)) -#define for_each_input_queue(irq_ptr, q, i) \ - for (i = 0, q = irq_ptr->input_qs[0]; \ - i < irq_ptr->nr_input_qs; \ - q = irq_ptr->input_qs[++i]) -#define for_each_output_queue(irq_ptr, q, i) \ - for (i = 0, q = irq_ptr->output_qs[0]; \ - i < irq_ptr->nr_output_qs; \ - q = irq_ptr->output_qs[++i]) +#define for_each_input_queue(irq_ptr, q, i) \ + for (i = 0; i < irq_ptr->nr_input_qs && \ + ({ q = irq_ptr->input_qs[i]; 1; }); i++) +#define for_each_output_queue(irq_ptr, q, i) \ + for (i = 0; i < irq_ptr->nr_output_qs && \ + ({ q = irq_ptr->output_qs[i]; 1; }); i++) #define prev_buf(bufnr) \ ((bufnr + QDIO_MAX_BUFFERS_MASK) & QDIO_MAX_BUFFERS_MASK) diff --git a/drivers/s390/cio/qdio_main.c b/drivers/s390/cio/qdio_main.c index c883a085c059..77466c4faabb 100644 --- a/drivers/s390/cio/qdio_main.c +++ b/drivers/s390/cio/qdio_main.c @@ -996,7 +996,7 @@ static void qdio_int_handler_pci(struct qdio_irq *irq_ptr) } } - if (!pci_out_supported(q)) + if (!(irq_ptr->qib.ac & QIB_AC_OUTBOUND_PCI_SUPPORTED)) return; for_each_output_queue(irq_ptr, q, i) { diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index dc542e0a3055..0bc91e46395a 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -311,7 +311,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, } __packed * msg = ap_msg->message; int rcblen = CEIL4(xcRB->request_control_blk_length); - int replylen; + int replylen, req_sumlen, resp_sumlen; char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen; char *function_code; @@ -321,12 +321,34 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, xcRB->request_data_length; if (ap_msg->length > MSGTYPE06_MAX_MSG_SIZE) return -EINVAL; + + /* Overflow check + sum must be greater (or equal) than the largest operand */ + req_sumlen = CEIL4(xcRB->request_control_blk_length) + + xcRB->request_data_length; + if ((CEIL4(xcRB->request_control_blk_length) <= + xcRB->request_data_length) ? + (req_sumlen < xcRB->request_data_length) : + (req_sumlen < CEIL4(xcRB->request_control_blk_length))) { + return -EINVAL; + } + replylen = sizeof(struct type86_fmt2_msg) + CEIL4(xcRB->reply_control_blk_length) + xcRB->reply_data_length; if (replylen > MSGTYPE06_MAX_MSG_SIZE) return -EINVAL; + /* Overflow check + sum must be greater (or equal) than the largest operand */ + resp_sumlen = CEIL4(xcRB->reply_control_blk_length) + + xcRB->reply_data_length; + if ((CEIL4(xcRB->reply_control_blk_length) <= xcRB->reply_data_length) ? + (resp_sumlen < xcRB->reply_data_length) : + (resp_sumlen < CEIL4(xcRB->reply_control_blk_length))) { + return -EINVAL; + } + /* prepare type6 header */ msg->hdr = static_type6_hdrX; memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID)); diff --git a/drivers/s390/net/qeth_core_main.c b/drivers/s390/net/qeth_core_main.c index c3a83df07894..795ed61a5496 100644 --- a/drivers/s390/net/qeth_core_main.c +++ b/drivers/s390/net/qeth_core_main.c @@ -1660,7 +1660,6 @@ int qeth_qdio_clear_card(struct qeth_card *card, int use_halt) QDIO_FLAG_CLEANUP_USING_CLEAR); if (rc) QETH_CARD_TEXT_(card, 3, "1err%d", rc); - qdio_free(CARD_DDEV(card)); atomic_set(&card->qdio.state, QETH_QDIO_ALLOCATED); break; case QETH_QDIO_CLEANING: @@ -2605,6 +2604,7 @@ static int qeth_mpc_initialize(struct qeth_card *card) return 0; out_qdio: qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); + qdio_free(CARD_DDEV(card)); return rc; } @@ -4906,9 +4906,11 @@ retry: if (retries < 3) QETH_DBF_MESSAGE(2, "%s Retrying to do IDX activates.\n", dev_name(&card->gdev->dev)); + rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); + qdio_free(CARD_DDEV(card)); rc = ccw_device_set_online(CARD_RDEV(card)); if (rc) goto retriable; @@ -4918,7 +4920,6 @@ retry: rc = ccw_device_set_online(CARD_DDEV(card)); if (rc) goto retriable; - rc = qeth_qdio_clear_card(card, card->info.type != QETH_CARD_TYPE_IQD); retriable: if (rc == -ERESTARTSYS) { QETH_DBF_TEXT(SETUP, 2, "break1"); diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index 0710550093ce..908d82529ee9 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -1091,6 +1091,7 @@ out_remove: ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); + qdio_free(CARD_DDEV(card)); if (recover_flag == CARD_STATE_RECOVER) card->state = CARD_STATE_RECOVER; else @@ -1132,6 +1133,7 @@ static int __qeth_l2_set_offline(struct ccwgroup_device *cgdev, rc = (rc2) ? rc2 : rc3; if (rc) QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); + qdio_free(CARD_DDEV(card)); if (recover_flag == CARD_STATE_UP) card->state = CARD_STATE_RECOVER; /* let user_space know that device is offline */ @@ -1194,6 +1196,7 @@ static void qeth_l2_shutdown(struct ccwgroup_device *gdev) qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); + qdio_free(CARD_DDEV(card)); } static int qeth_l2_pm_suspend(struct ccwgroup_device *gdev) diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c index 0f430424c3b8..3524d34ff694 100644 --- a/drivers/s390/net/qeth_l3_main.c +++ b/drivers/s390/net/qeth_l3_main.c @@ -3447,6 +3447,7 @@ out_remove: ccw_device_set_offline(CARD_DDEV(card)); ccw_device_set_offline(CARD_WDEV(card)); ccw_device_set_offline(CARD_RDEV(card)); + qdio_free(CARD_DDEV(card)); if (recover_flag == CARD_STATE_RECOVER) card->state = CARD_STATE_RECOVER; else @@ -3493,6 +3494,7 @@ static int __qeth_l3_set_offline(struct ccwgroup_device *cgdev, rc = (rc2) ? rc2 : rc3; if (rc) QETH_DBF_TEXT_(SETUP, 2, "1err%d", rc); + qdio_free(CARD_DDEV(card)); if (recover_flag == CARD_STATE_UP) card->state = CARD_STATE_RECOVER; /* let user_space know that device is offline */ @@ -3545,6 +3547,7 @@ static void qeth_l3_shutdown(struct ccwgroup_device *gdev) qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM); qeth_qdio_clear_card(card, 0); qeth_clear_qdio_buffers(card); + qdio_free(CARD_DDEV(card)); } static int qeth_l3_pm_suspend(struct ccwgroup_device *gdev) diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index 6b4678a7900a..4ccb5d869389 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -507,7 +507,6 @@ static int jsflash_init(void) } /* Let us be really paranoid for modifications to probing code. */ - /* extern enum sparc_cpu sparc_cpu_model; */ /* in <asm/system.h> */ if (sparc_cpu_model != sun4m) { /* We must be on sun4m because we use MMU Bypass ASI. */ return -ENXIO; diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 9e80d61e5a3a..0cb73074c199 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -790,17 +790,32 @@ static inline int test_tgt_sess_count(struct qla_tgt *tgt) } /* Called by tcm_qla2xxx configfs code */ -void qlt_stop_phase1(struct qla_tgt *tgt) +int qlt_stop_phase1(struct qla_tgt *tgt) { struct scsi_qla_host *vha = tgt->vha; struct qla_hw_data *ha = tgt->ha; unsigned long flags; + mutex_lock(&qla_tgt_mutex); + if (!vha->fc_vport) { + struct Scsi_Host *sh = vha->host; + struct fc_host_attrs *fc_host = shost_to_fc_host(sh); + bool npiv_vports; + + spin_lock_irqsave(sh->host_lock, flags); + npiv_vports = (fc_host->npiv_vports_inuse); + spin_unlock_irqrestore(sh->host_lock, flags); + + if (npiv_vports) { + mutex_unlock(&qla_tgt_mutex); + return -EPERM; + } + } if (tgt->tgt_stop || tgt->tgt_stopped) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e, "Already in tgt->tgt_stop or tgt_stopped state\n"); - dump_stack(); - return; + mutex_unlock(&qla_tgt_mutex); + return -EPERM; } ql_dbg(ql_dbg_tgt, vha, 0xe003, "Stopping target for host %ld(%p)\n", @@ -815,6 +830,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt) qlt_clear_tgt_db(tgt, true); spin_unlock_irqrestore(&ha->hardware_lock, flags); mutex_unlock(&vha->vha_tgt.tgt_mutex); + mutex_unlock(&qla_tgt_mutex); flush_delayed_work(&tgt->sess_del_work); @@ -841,6 +857,7 @@ void qlt_stop_phase1(struct qla_tgt *tgt) /* Wait for sessions to clear out (just in case) */ wait_event(tgt->waitQ, test_tgt_sess_count(tgt)); + return 0; } EXPORT_SYMBOL(qlt_stop_phase1); @@ -2595,8 +2612,6 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha, return -ENOMEM; } - INIT_LIST_HEAD(&cmd->cmd_list); - memcpy(&cmd->atio, atio, sizeof(*atio)); cmd->state = QLA_TGT_STATE_NEW; cmd->tgt = vha->vha_tgt.qla_tgt; @@ -3187,7 +3202,8 @@ restart: ql_dbg(ql_dbg_tgt_mgt, vha, 0xf02c, "SRR cmd %p (se_cmd %p, tag %d, op %x), " "sg_cnt=%d, offset=%d", cmd, &cmd->se_cmd, cmd->tag, - se_cmd->t_task_cdb[0], cmd->sg_cnt, cmd->offset); + se_cmd->t_task_cdb ? se_cmd->t_task_cdb[0] : 0, + cmd->sg_cnt, cmd->offset); qlt_handle_srr(vha, sctio, imm); @@ -4183,6 +4199,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha) tgt->datasegs_per_cmd = QLA_TGT_DATASEGS_PER_CMD_24XX; tgt->datasegs_per_cont = QLA_TGT_DATASEGS_PER_CONT_24XX; + if (base_vha->fc_vport) + return 0; + mutex_lock(&qla_tgt_mutex); list_add_tail(&tgt->tgt_list_entry, &qla_tgt_glist); mutex_unlock(&qla_tgt_mutex); @@ -4196,6 +4215,10 @@ int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha) if (!vha->vha_tgt.qla_tgt) return 0; + if (vha->fc_vport) { + qlt_release(vha->vha_tgt.qla_tgt); + return 0; + } mutex_lock(&qla_tgt_mutex); list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry); mutex_unlock(&qla_tgt_mutex); @@ -4267,6 +4290,12 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, spin_unlock_irqrestore(&ha->hardware_lock, flags); continue; } + if (tgt->tgt_stop) { + pr_debug("MODE_TARGET in shutdown on qla2xxx(%d)\n", + host->host_no); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + continue; + } spin_unlock_irqrestore(&ha->hardware_lock, flags); if (!scsi_host_get(host)) { @@ -4281,12 +4310,11 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, scsi_host_put(host); continue; } - mutex_unlock(&qla_tgt_mutex); - rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn); if (rc != 0) scsi_host_put(host); + mutex_unlock(&qla_tgt_mutex); return rc; } mutex_unlock(&qla_tgt_mutex); diff --git a/drivers/scsi/qla2xxx/qla_target.h b/drivers/scsi/qla2xxx/qla_target.h index 1d10eecad499..ce33d8c26406 100644 --- a/drivers/scsi/qla2xxx/qla_target.h +++ b/drivers/scsi/qla2xxx/qla_target.h @@ -855,7 +855,6 @@ struct qla_tgt_cmd { uint16_t loop_id; /* to save extra sess dereferences */ struct qla_tgt *tgt; /* to save extra sess dereferences */ struct scsi_qla_host *vha; - struct list_head cmd_list; struct atio_from_isp atio; }; @@ -1002,7 +1001,7 @@ extern void qlt_modify_vp_config(struct scsi_qla_host *, extern void qlt_probe_one_stage1(struct scsi_qla_host *, struct qla_hw_data *); extern int qlt_mem_alloc(struct qla_hw_data *); extern void qlt_mem_free(struct qla_hw_data *); -extern void qlt_stop_phase1(struct qla_tgt *); +extern int qlt_stop_phase1(struct qla_tgt *); extern void qlt_stop_phase2(struct qla_tgt *); extern irqreturn_t qla83xx_msix_atio_q(int, void *); extern void qlt_83xx_iospace_config(struct qla_hw_data *); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index 75a141bbe74d..788c4fe2b0c9 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -182,20 +182,6 @@ static int tcm_qla2xxx_npiv_parse_wwn( return 0; } -static ssize_t tcm_qla2xxx_npiv_format_wwn(char *buf, size_t len, - u64 wwpn, u64 wwnn) -{ - u8 b[8], b2[8]; - - put_unaligned_be64(wwpn, b); - put_unaligned_be64(wwnn, b2); - return snprintf(buf, len, - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x," - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x", - b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], - b2[0], b2[1], b2[2], b2[3], b2[4], b2[5], b2[6], b2[7]); -} - static char *tcm_qla2xxx_npiv_get_fabric_name(void) { return "qla2xxx_npiv"; @@ -227,15 +213,6 @@ static char *tcm_qla2xxx_get_fabric_wwn(struct se_portal_group *se_tpg) return lport->lport_naa_name; } -static char *tcm_qla2xxx_npiv_get_fabric_wwn(struct se_portal_group *se_tpg) -{ - struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, - struct tcm_qla2xxx_tpg, se_tpg); - struct tcm_qla2xxx_lport *lport = tpg->lport; - - return &lport->lport_npiv_name[0]; -} - static u16 tcm_qla2xxx_get_tag(struct se_portal_group *se_tpg) { struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, @@ -941,15 +918,41 @@ static ssize_t tcm_qla2xxx_tpg_show_enable( atomic_read(&tpg->lport_tpg_enabled)); } +static void tcm_qla2xxx_depend_tpg(struct work_struct *work) +{ + struct tcm_qla2xxx_tpg *base_tpg = container_of(work, + struct tcm_qla2xxx_tpg, tpg_base_work); + struct se_portal_group *se_tpg = &base_tpg->se_tpg; + struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha; + + if (!configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys, + &se_tpg->tpg_group.cg_item)) { + atomic_set(&base_tpg->lport_tpg_enabled, 1); + qlt_enable_vha(base_vha); + } + complete(&base_tpg->tpg_base_comp); +} + +static void tcm_qla2xxx_undepend_tpg(struct work_struct *work) +{ + struct tcm_qla2xxx_tpg *base_tpg = container_of(work, + struct tcm_qla2xxx_tpg, tpg_base_work); + struct se_portal_group *se_tpg = &base_tpg->se_tpg; + struct scsi_qla_host *base_vha = base_tpg->lport->qla_vha; + + if (!qlt_stop_phase1(base_vha->vha_tgt.qla_tgt)) { + atomic_set(&base_tpg->lport_tpg_enabled, 0); + configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys, + &se_tpg->tpg_group.cg_item); + } + complete(&base_tpg->tpg_base_comp); +} + static ssize_t tcm_qla2xxx_tpg_store_enable( struct se_portal_group *se_tpg, const char *page, size_t count) { - struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; - struct tcm_qla2xxx_lport *lport = container_of(se_wwn, - struct tcm_qla2xxx_lport, lport_wwn); - struct scsi_qla_host *vha = lport->qla_vha; struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, struct tcm_qla2xxx_tpg, se_tpg); unsigned long op; @@ -964,19 +967,28 @@ static ssize_t tcm_qla2xxx_tpg_store_enable( pr_err("Illegal value for tpg_enable: %lu\n", op); return -EINVAL; } - if (op) { - atomic_set(&tpg->lport_tpg_enabled, 1); - qlt_enable_vha(vha); + if (atomic_read(&tpg->lport_tpg_enabled)) + return -EEXIST; + + INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_depend_tpg); } else { - if (!vha->vha_tgt.qla_tgt) { - pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n"); - return -ENODEV; - } - atomic_set(&tpg->lport_tpg_enabled, 0); - qlt_stop_phase1(vha->vha_tgt.qla_tgt); + if (!atomic_read(&tpg->lport_tpg_enabled)) + return count; + + INIT_WORK(&tpg->tpg_base_work, tcm_qla2xxx_undepend_tpg); } + init_completion(&tpg->tpg_base_comp); + schedule_work(&tpg->tpg_base_work); + wait_for_completion(&tpg->tpg_base_comp); + if (op) { + if (!atomic_read(&tpg->lport_tpg_enabled)) + return -ENODEV; + } else { + if (atomic_read(&tpg->lport_tpg_enabled)) + return -EPERM; + } return count; } @@ -1053,11 +1065,64 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg) /* * Clear local TPG=1 pointer for non NPIV mode. */ - lport->tpg_1 = NULL; - + lport->tpg_1 = NULL; kfree(tpg); } +static ssize_t tcm_qla2xxx_npiv_tpg_show_enable( + struct se_portal_group *se_tpg, + char *page) +{ + return tcm_qla2xxx_tpg_show_enable(se_tpg, page); +} + +static ssize_t tcm_qla2xxx_npiv_tpg_store_enable( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct se_wwn *se_wwn = se_tpg->se_tpg_wwn; + struct tcm_qla2xxx_lport *lport = container_of(se_wwn, + struct tcm_qla2xxx_lport, lport_wwn); + struct scsi_qla_host *vha = lport->qla_vha; + struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg, + struct tcm_qla2xxx_tpg, se_tpg); + unsigned long op; + int rc; + + rc = kstrtoul(page, 0, &op); + if (rc < 0) { + pr_err("kstrtoul() returned %d\n", rc); + return -EINVAL; + } + if ((op != 1) && (op != 0)) { + pr_err("Illegal value for tpg_enable: %lu\n", op); + return -EINVAL; + } + if (op) { + if (atomic_read(&tpg->lport_tpg_enabled)) + return -EEXIST; + + atomic_set(&tpg->lport_tpg_enabled, 1); + qlt_enable_vha(vha); + } else { + if (!atomic_read(&tpg->lport_tpg_enabled)) + return count; + + atomic_set(&tpg->lport_tpg_enabled, 0); + qlt_stop_phase1(vha->vha_tgt.qla_tgt); + } + + return count; +} + +TF_TPG_BASE_ATTR(tcm_qla2xxx_npiv, enable, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *tcm_qla2xxx_npiv_tpg_attrs[] = { + &tcm_qla2xxx_npiv_tpg_enable.attr, + NULL, +}; + static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg( struct se_wwn *wwn, struct config_group *group, @@ -1650,6 +1715,9 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, struct scsi_qla_host *npiv_vha; struct tcm_qla2xxx_lport *lport = (struct tcm_qla2xxx_lport *)target_lport_ptr; + struct tcm_qla2xxx_lport *base_lport = + (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr; + struct tcm_qla2xxx_tpg *base_tpg; struct fc_vport_identifiers vport_id; if (!qla_tgt_mode_enabled(base_vha)) { @@ -1657,6 +1725,13 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, return -EPERM; } + if (!base_lport || !base_lport->tpg_1 || + !atomic_read(&base_lport->tpg_1->lport_tpg_enabled)) { + pr_err("qla2xxx base_lport or tpg_1 not available\n"); + return -EPERM; + } + base_tpg = base_lport->tpg_1; + memset(&vport_id, 0, sizeof(vport_id)); vport_id.port_name = npiv_wwpn; vport_id.node_name = npiv_wwnn; @@ -1675,7 +1750,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, npiv_vha = (struct scsi_qla_host *)vport->dd_data; npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr; lport->qla_vha = npiv_vha; - scsi_host_get(npiv_vha->host); return 0; } @@ -1714,8 +1788,6 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport( } lport->lport_npiv_wwpn = npiv_wwpn; lport->lport_npiv_wwnn = npiv_wwnn; - tcm_qla2xxx_npiv_format_wwn(&lport->lport_npiv_name[0], - TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn); sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn); ret = tcm_qla2xxx_init_lport(lport); @@ -1824,7 +1896,7 @@ static struct target_core_fabric_ops tcm_qla2xxx_ops = { static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = { .get_fabric_name = tcm_qla2xxx_npiv_get_fabric_name, .get_fabric_proto_ident = tcm_qla2xxx_get_fabric_proto_ident, - .tpg_get_wwn = tcm_qla2xxx_npiv_get_fabric_wwn, + .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, .tpg_get_default_depth = tcm_qla2xxx_get_default_depth, .tpg_get_pr_transport_id = tcm_qla2xxx_get_pr_transport_id, @@ -1935,7 +2007,7 @@ static int tcm_qla2xxx_register_configfs(void) */ npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs; npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = - tcm_qla2xxx_tpg_attrs; + tcm_qla2xxx_npiv_tpg_attrs; npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL; npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL; npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL; diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.h b/drivers/scsi/qla2xxx/tcm_qla2xxx.h index 275d8b9a7a34..33aaac8c7d59 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.h +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.h @@ -4,8 +4,6 @@ #define TCM_QLA2XXX_VERSION "v0.1" /* length of ASCII WWPNs including pad */ #define TCM_QLA2XXX_NAMELEN 32 -/* lenth of ASCII NPIV 'WWPN+WWNN' including pad */ -#define TCM_QLA2XXX_NPIV_NAMELEN 66 #include "qla_target.h" @@ -43,6 +41,9 @@ struct tcm_qla2xxx_tpg { struct tcm_qla2xxx_tpg_attrib tpg_attrib; /* Returned by tcm_qla2xxx_make_tpg() */ struct se_portal_group se_tpg; + /* Items for dealing with configfs_depend_item */ + struct completion tpg_base_comp; + struct work_struct tpg_base_work; }; struct tcm_qla2xxx_fc_loopid { @@ -62,8 +63,6 @@ struct tcm_qla2xxx_lport { char lport_name[TCM_QLA2XXX_NAMELEN]; /* ASCII formatted naa WWPN for VPD page 83 etc */ char lport_naa_name[TCM_QLA2XXX_NAMELEN]; - /* ASCII formatted WWPN+WWNN for NPIV FC Target Lport */ - char lport_npiv_name[TCM_QLA2XXX_NPIV_NAMELEN]; /* map for fc_port pointers in 24-bit FC Port ID space */ struct btree_head32 lport_fcport_map; /* vmalloc-ed memory for fc_port pointers for 16-bit FC loop ID */ diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7bd7f0d5f050..62ec84b42e31 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1684,7 +1684,7 @@ u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) host_dev = scsi_get_device(shost); if (host_dev && host_dev->dma_mask) - bounce_limit = dma_max_pfn(host_dev) << PAGE_SHIFT; + bounce_limit = (u64)dma_max_pfn(host_dev) << PAGE_SHIFT; return bounce_limit; } diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ba9310bc9acb..581ee2a8856b 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -376,10 +376,10 @@ config SPI_PXA2XX_PCI def_tristate SPI_PXA2XX && PCI config SPI_RSPI - tristate "Renesas RSPI controller" + tristate "Renesas RSPI/QSPI controller" depends on (SUPERH && SH_DMAE_BASE) || ARCH_SHMOBILE help - SPI driver for Renesas RSPI blocks. + SPI driver for Renesas RSPI and QSPI blocks. config SPI_S3C24XX tristate "Samsung S3C24XX series SPI" diff --git a/drivers/spi/spi-nuc900.c b/drivers/spi/spi-nuc900.c index 50406306bc20..bae97ffec4b9 100644 --- a/drivers/spi/spi-nuc900.c +++ b/drivers/spi/spi-nuc900.c @@ -361,6 +361,8 @@ static int nuc900_spi_probe(struct platform_device *pdev) init_completion(&hw->done); master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + if (hw->pdata->lsb) + master->mode_bits |= SPI_LSB_FIRST; master->num_chipselect = hw->pdata->num_cs; master->bus_num = hw->pdata->bus_num; hw->bitbang.master = hw->master; diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 23756b0f9036..d0b28bba38be 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -755,9 +755,7 @@ static void spi_pump_messages(struct kthread_work *work) ret = master->transfer_one_message(master, master->cur_msg); if (ret) { dev_err(&master->dev, - "failed to transfer one message from queue: %d\n", ret); - master->cur_msg->status = ret; - spi_finalize_current_message(master); + "failed to transfer one message from queue\n"); return; } } diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 23948f167012..713a97226787 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -295,21 +295,29 @@ static ssize_t ashmem_read(struct file *file, char __user *buf, /* If size is not set, or set to 0, always return EOF. */ if (asma->size == 0) - goto out; + goto out_unlock; if (!asma->file) { ret = -EBADF; - goto out; + goto out_unlock; } - ret = asma->file->f_op->read(asma->file, buf, len, pos); - if (ret < 0) - goto out; + mutex_unlock(&ashmem_mutex); - /** Update backing file pos, since f_ops->read() doesn't */ - asma->file->f_pos = *pos; + /* + * asma and asma->file are used outside the lock here. We assume + * once asma->file is set it will never be changed, and will not + * be destroyed until all references to the file are dropped and + * ashmem_release is called. + */ + ret = asma->file->f_op->read(asma->file, buf, len, pos); + if (ret >= 0) { + /** Update backing file pos, since f_ops->read() doesn't */ + asma->file->f_pos = *pos; + } + return ret; -out: +out_unlock: mutex_unlock(&ashmem_mutex); return ret; } @@ -498,6 +506,7 @@ out: static int set_name(struct ashmem_area *asma, void __user *name) { + int len; int ret = 0; char local_name[ASHMEM_NAME_LEN]; @@ -510,21 +519,19 @@ static int set_name(struct ashmem_area *asma, void __user *name) * variable that does not need protection and later copy the local * variable to the structure member with lock held. */ - if (copy_from_user(local_name, name, ASHMEM_NAME_LEN)) - return -EFAULT; - + len = strncpy_from_user(local_name, name, ASHMEM_NAME_LEN); + if (len < 0) + return len; + if (len == ASHMEM_NAME_LEN) + local_name[ASHMEM_NAME_LEN - 1] = '\0'; mutex_lock(&ashmem_mutex); /* cannot change an existing mapping's name */ - if (unlikely(asma->file)) { + if (unlikely(asma->file)) ret = -EINVAL; - goto out; - } - memcpy(asma->name + ASHMEM_NAME_PREFIX_LEN, - local_name, ASHMEM_NAME_LEN); - asma->name[ASHMEM_FULL_NAME_LEN-1] = '\0'; -out: - mutex_unlock(&ashmem_mutex); + else + strcpy(asma->name + ASHMEM_NAME_PREFIX_LEN, local_name); + mutex_unlock(&ashmem_mutex); return ret; } diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index eaec1dab7fe4..1432d956769c 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -2904,7 +2904,7 @@ static int binder_node_release(struct binder_node *node, int refs) refs++; if (!ref->death) - goto out; + continue; death++; @@ -2917,7 +2917,6 @@ static int binder_node_release(struct binder_node *node, int refs) BUG(); } -out: binder_debug(BINDER_DEBUG_DEAD_BINDER, "node %d now dead, refs %d, death %d\n", node->debug_id, refs, death); diff --git a/drivers/staging/android/ion/compat_ion.c b/drivers/staging/android/ion/compat_ion.c index af6cd370b30f..ee3a7380e53b 100644 --- a/drivers/staging/android/ion/compat_ion.c +++ b/drivers/staging/android/ion/compat_ion.c @@ -35,9 +35,14 @@ struct compat_ion_custom_data { compat_ulong_t arg; }; +struct compat_ion_handle_data { + compat_int_t handle; +}; + #define COMPAT_ION_IOC_ALLOC _IOWR(ION_IOC_MAGIC, 0, \ struct compat_ion_allocation_data) -#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, struct ion_handle_data) +#define COMPAT_ION_IOC_FREE _IOWR(ION_IOC_MAGIC, 1, \ + struct compat_ion_handle_data) #define COMPAT_ION_IOC_CUSTOM _IOWR(ION_IOC_MAGIC, 6, \ struct compat_ion_custom_data) @@ -64,6 +69,19 @@ static int compat_get_ion_allocation_data( return err; } +static int compat_get_ion_handle_data( + struct compat_ion_handle_data __user *data32, + struct ion_handle_data __user *data) +{ + compat_int_t i; + int err; + + err = get_user(i, &data32->handle); + err |= put_user(i, &data->handle); + + return err; +} + static int compat_put_ion_allocation_data( struct compat_ion_allocation_data __user *data32, struct ion_allocation_data __user *data) @@ -132,8 +150,8 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } case COMPAT_ION_IOC_FREE: { - struct compat_ion_allocation_data __user *data32; - struct ion_allocation_data __user *data; + struct compat_ion_handle_data __user *data32; + struct ion_handle_data __user *data; int err; data32 = compat_ptr(arg); @@ -141,7 +159,7 @@ long compat_ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (data == NULL) return -EFAULT; - err = compat_get_ion_allocation_data(data32, data); + err = compat_get_ion_handle_data(data32, data); if (err) return err; diff --git a/drivers/staging/android/ion/ion_dummy_driver.c b/drivers/staging/android/ion/ion_dummy_driver.c index 55b2002753f2..01cdc8aee898 100644 --- a/drivers/staging/android/ion/ion_dummy_driver.c +++ b/drivers/staging/android/ion/ion_dummy_driver.c @@ -17,9 +17,11 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/slab.h> +#include <linux/init.h> #include <linux/bootmem.h> #include <linux/memblock.h> #include <linux/sizes.h> +#include <linux/io.h> #include "ion.h" #include "ion_priv.h" @@ -57,7 +59,7 @@ struct ion_platform_heap dummy_heaps[] = { }; struct ion_platform_data dummy_ion_pdata = { - .nr = 4, + .nr = ARRAY_SIZE(dummy_heaps), .heaps = dummy_heaps, }; @@ -69,7 +71,7 @@ static int __init ion_dummy_init(void) heaps = kzalloc(sizeof(struct ion_heap *) * dummy_ion_pdata.nr, GFP_KERNEL); if (!heaps) - return PTR_ERR(heaps); + return -ENOMEM; /* Allocate a dummy carveout heap */ @@ -128,6 +130,7 @@ err: } return err; } +device_initcall(ion_dummy_init); static void __exit ion_dummy_exit(void) { @@ -152,7 +155,4 @@ static void __exit ion_dummy_exit(void) return; } - -module_init(ion_dummy_init); -module_exit(ion_dummy_exit); - +__exitcall(ion_dummy_exit); diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c index 296c74f98dc0..37e64d51394c 100644 --- a/drivers/staging/android/ion/ion_heap.c +++ b/drivers/staging/android/ion/ion_heap.c @@ -243,12 +243,12 @@ int ion_heap_init_deferred_free(struct ion_heap *heap) init_waitqueue_head(&heap->waitqueue); heap->task = kthread_run(ion_heap_deferred_free, heap, "%s", heap->name); - sched_setscheduler(heap->task, SCHED_IDLE, ¶m); if (IS_ERR(heap->task)) { pr_err("%s: creating thread for deferred free failed\n", __func__); return PTR_RET(heap->task); } + sched_setscheduler(heap->task, SCHED_IDLE, ¶m); return 0; } diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index d98673981cc4..fc2e4fccf69d 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -17,6 +17,7 @@ #ifndef _ION_PRIV_H #define _ION_PRIV_H +#include <linux/device.h> #include <linux/dma-direction.h> #include <linux/kref.h> #include <linux/mm_types.h> diff --git a/drivers/staging/android/ion/ion_system_heap.c b/drivers/staging/android/ion/ion_system_heap.c index 7f0729130d65..9849f3963e75 100644 --- a/drivers/staging/android/ion/ion_system_heap.c +++ b/drivers/staging/android/ion/ion_system_heap.c @@ -124,6 +124,7 @@ static struct page_info *alloc_largest_available(struct ion_system_heap *heap, info->page = page; info->order = orders[i]; + INIT_LIST_HEAD(&info->list); return info; } kfree(info); @@ -145,12 +146,15 @@ static int ion_system_heap_allocate(struct ion_heap *heap, struct list_head pages; struct page_info *info, *tmp_info; int i = 0; - long size_remaining = PAGE_ALIGN(size); + unsigned long size_remaining = PAGE_ALIGN(size); unsigned int max_order = orders[0]; if (align > PAGE_SIZE) return -EINVAL; + if (size / PAGE_SIZE > totalram_pages / 2) + return -ENOMEM; + INIT_LIST_HEAD(&pages); while (size_remaining > 0) { info = alloc_largest_available(sys_heap, buffer, size_remaining, diff --git a/drivers/staging/android/sw_sync.h b/drivers/staging/android/sw_sync.h index 585040be5f18..5aaf71d6974b 100644 --- a/drivers/staging/android/sw_sync.h +++ b/drivers/staging/android/sw_sync.h @@ -35,10 +35,27 @@ struct sw_sync_pt { u32 value; }; +#if IS_ENABLED(CONFIG_SW_SYNC) struct sw_sync_timeline *sw_sync_timeline_create(const char *name); void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc); struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, u32 value); +#else +static inline struct sw_sync_timeline *sw_sync_timeline_create(const char *name) +{ + return NULL; +} + +static inline void sw_sync_timeline_inc(struct sw_sync_timeline *obj, u32 inc) +{ +} + +static inline struct sync_pt *sw_sync_pt_create(struct sw_sync_timeline *obj, + u32 value) +{ + return NULL; +} +#endif /* IS_ENABLED(CONFIG_SW_SYNC) */ #endif /* __KERNEL __ */ diff --git a/drivers/staging/android/sync.c b/drivers/staging/android/sync.c index 38e5d3b5ed9b..3d05f662110b 100644 --- a/drivers/staging/android/sync.c +++ b/drivers/staging/android/sync.c @@ -79,27 +79,27 @@ static void sync_timeline_free(struct kref *kref) container_of(kref, struct sync_timeline, kref); unsigned long flags; - if (obj->ops->release_obj) - obj->ops->release_obj(obj); - spin_lock_irqsave(&sync_timeline_list_lock, flags); list_del(&obj->sync_timeline_list); spin_unlock_irqrestore(&sync_timeline_list_lock, flags); + if (obj->ops->release_obj) + obj->ops->release_obj(obj); + kfree(obj); } void sync_timeline_destroy(struct sync_timeline *obj) { obj->destroyed = true; + smp_wmb(); /* - * If this is not the last reference, signal any children - * that their parent is going away. + * signal any children that their parent is going away. */ + sync_timeline_signal(obj); - if (!kref_put(&obj->kref, sync_timeline_free)) - sync_timeline_signal(obj); + kref_put(&obj->kref, sync_timeline_free); } EXPORT_SYMBOL(sync_timeline_destroy); diff --git a/drivers/staging/bcm/Bcmnet.c b/drivers/staging/bcm/Bcmnet.c index 8dfdd2732bdc..95a2358267ba 100644 --- a/drivers/staging/bcm/Bcmnet.c +++ b/drivers/staging/bcm/Bcmnet.c @@ -40,7 +40,7 @@ static INT bcm_close(struct net_device *dev) } static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { return ClassifyPacket(netdev_priv(dev), skb); } diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 246080316c90..5b15033a94bf 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -616,8 +616,6 @@ int comedi_auto_config(struct device *hardware_device, ret = driver->auto_attach(dev, context); if (ret >= 0) ret = comedi_device_postconfig(dev); - if (ret < 0) - comedi_device_detach(dev); mutex_unlock(&dev->mutex); if (ret < 0) { diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 593676cf706a..d9ad2c0fdda2 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -494,6 +494,7 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, chan, range, ofs; chan = CR_CHAN(insn->chanspec); @@ -509,11 +510,14 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); ofs = PCI171x_DA1; } + val = devpriv->ao_data[chan]; - for (n = 0; n < insn->n; n++) - outw(data[n], dev->iobase + ofs); + for (n = 0; n < insn->n; n++) { + val = data[n]; + outw(val, dev->iobase + ofs); + } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; @@ -679,6 +683,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, rangereg, chan; chan = CR_CHAN(insn->chanspec); @@ -688,13 +693,15 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, outb(rangereg, dev->iobase + PCI1720_RANGE); devpriv->da_ranges = rangereg; } + val = devpriv->ao_data[chan]; for (n = 0; n < insn->n; n++) { - outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); + val = data[n]; + outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; } diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index 3beeb1254152..88c60b6020c4 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -48,6 +48,7 @@ #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> +#include <asm/unaligned.h> #include "comedi_fc.h" #include "../comedidev.h" @@ -792,7 +793,8 @@ static int usbduxsigma_ai_insn_read(struct comedi_device *dev, } /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf) + 1))); + val = be32_to_cpu(get_unaligned((uint32_t + *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ @@ -1357,7 +1359,7 @@ static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) return ret; /* 32 bits big endian from the A/D converter */ - val = be32_to_cpu(*((uint32_t *)((devpriv->insn_buf)+1))); + val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1))); val &= 0x00ffffff; /* strip status byte */ val ^= 0x00800000; /* convert to unsigned */ diff --git a/drivers/staging/dgrp/dgrp_net_ops.c b/drivers/staging/dgrp/dgrp_net_ops.c index 1f61b89eca44..33ac7fb88cbd 100644 --- a/drivers/staging/dgrp/dgrp_net_ops.c +++ b/drivers/staging/dgrp/dgrp_net_ops.c @@ -2232,177 +2232,6 @@ done: return rtn; } -/* - * Common Packet Handling code - */ - -static void handle_data_in_packet(struct nd_struct *nd, struct ch_struct *ch, - long dlen, long plen, int n1, u8 *dbuf) -{ - char *error; - long n; - long remain; - u8 *buf; - u8 *b; - - remain = nd->nd_remain; - nd->nd_tx_work = 1; - - /* - * Otherwise data should appear only when we are - * in the CS_READY state. - */ - - if (ch->ch_state < CS_READY) { - error = "Data received before RWIN established"; - nd->nd_remain = 0; - nd->nd_state = NS_SEND_ERROR; - nd->nd_error = error; - } - - /* - * Assure that the data received is within the - * allowable window. - */ - - n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff; - - if (dlen > n) { - error = "Receive data overrun"; - nd->nd_remain = 0; - nd->nd_state = NS_SEND_ERROR; - nd->nd_error = error; - } - - /* - * If we received 3 or less characters, - * assume it is a human typing, and set RTIME - * to 10 milliseconds. - * - * If we receive 10 or more characters, - * assume its not a human typing, and set RTIME - * to 100 milliseconds. - */ - - if (ch->ch_edelay != DGRP_RTIME) { - if (ch->ch_rtime != ch->ch_edelay) { - ch->ch_rtime = ch->ch_edelay; - ch->ch_flag |= CH_PARAM; - } - } else if (dlen <= 3) { - if (ch->ch_rtime != 10) { - ch->ch_rtime = 10; - ch->ch_flag |= CH_PARAM; - } - } else { - if (ch->ch_rtime != DGRP_RTIME) { - ch->ch_rtime = DGRP_RTIME; - ch->ch_flag |= CH_PARAM; - } - } - - /* - * If a portion of the packet is outside the - * buffer, shorten the effective length of the - * data packet to be the amount of data received. - */ - - if (remain < plen) - dlen -= plen - remain; - - /* - * Detect if receive flush is now complete. - */ - - if ((ch->ch_flag & CH_RX_FLUSH) != 0 && - ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >= - ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) { - ch->ch_flag &= ~CH_RX_FLUSH; - } - - /* - * If we are ready to receive, move the data into - * the receive buffer. - */ - - ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff; - - if (ch->ch_state == CS_READY && - (ch->ch_tun.un_open_count != 0) && - (ch->ch_tun.un_flag & UN_CLOSING) == 0 && - (ch->ch_cflag & CF_CREAD) != 0 && - (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 && - (ch->ch_send & RR_RX_FLUSH) == 0) { - - if (ch->ch_rin + dlen >= RBUF_MAX) { - n = RBUF_MAX - ch->ch_rin; - - memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n); - - ch->ch_rin = 0; - dbuf += n; - dlen -= n; - } - - memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen); - - ch->ch_rin += dlen; - - - /* - * If we are not in fastcook mode, or - * if there is a fastcook thread - * waiting for data, send the data to - * the line discipline. - */ - - if ((ch->ch_flag & CH_FAST_READ) == 0 || - ch->ch_inwait != 0) { - dgrp_input(ch); - } - - /* - * If there is a read thread waiting - * in select, and we are in fastcook - * mode, wake him up. - */ - - if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) && - (ch->ch_flag & CH_FAST_READ) != 0) - wake_up_interruptible(&ch->ch_tun.un_tty->read_wait); - - /* - * Wake any thread waiting in the - * fastcook loop. - */ - - if ((ch->ch_flag & CH_INPUT) != 0) { - ch->ch_flag &= ~CH_INPUT; - wake_up_interruptible(&ch->ch_flag_wait); - } - } - - /* - * Fabricate and insert a data packet header to - * preced the remaining data when it comes in. - */ - - if (remain < plen) { - dlen = plen - remain; - b = buf; - - b[0] = 0x90 + n1; - put_unaligned_be16(dlen, b + 1); - - remain = 3; - if (remain > 0 && b != buf) - memcpy(buf, b, remain); - - nd->nd_remain = remain; - return; - } -} - /** * dgrp_receive() -- decode data packets received from the remote PortServer. * @nd: pointer to a node structure @@ -2477,8 +2306,7 @@ static void dgrp_receive(struct nd_struct *nd) plen = dlen + 1; dbuf = b + 1; - handle_data_in_packet(nd, ch, dlen, plen, n1, dbuf); - break; + goto data; /* * Process 2-byte header data packet. @@ -2492,8 +2320,7 @@ static void dgrp_receive(struct nd_struct *nd) plen = dlen + 2; dbuf = b + 2; - handle_data_in_packet(nd, ch, dlen, plen, n1, dbuf); - break; + goto data; /* * Process 3-byte header data packet. @@ -2508,6 +2335,159 @@ static void dgrp_receive(struct nd_struct *nd) dbuf = b + 3; + /* + * Common packet handling code. + */ + +data: + nd->nd_tx_work = 1; + + /* + * Otherwise data should appear only when we are + * in the CS_READY state. + */ + + if (ch->ch_state < CS_READY) { + error = "Data received before RWIN established"; + goto prot_error; + } + + /* + * Assure that the data received is within the + * allowable window. + */ + + n = (ch->ch_s_rwin - ch->ch_s_rin) & 0xffff; + + if (dlen > n) { + error = "Receive data overrun"; + goto prot_error; + } + + /* + * If we received 3 or less characters, + * assume it is a human typing, and set RTIME + * to 10 milliseconds. + * + * If we receive 10 or more characters, + * assume its not a human typing, and set RTIME + * to 100 milliseconds. + */ + + if (ch->ch_edelay != DGRP_RTIME) { + if (ch->ch_rtime != ch->ch_edelay) { + ch->ch_rtime = ch->ch_edelay; + ch->ch_flag |= CH_PARAM; + } + } else if (dlen <= 3) { + if (ch->ch_rtime != 10) { + ch->ch_rtime = 10; + ch->ch_flag |= CH_PARAM; + } + } else { + if (ch->ch_rtime != DGRP_RTIME) { + ch->ch_rtime = DGRP_RTIME; + ch->ch_flag |= CH_PARAM; + } + } + + /* + * If a portion of the packet is outside the + * buffer, shorten the effective length of the + * data packet to be the amount of data received. + */ + + if (remain < plen) + dlen -= plen - remain; + + /* + * Detect if receive flush is now complete. + */ + + if ((ch->ch_flag & CH_RX_FLUSH) != 0 && + ((ch->ch_flush_seq - nd->nd_seq_out) & SEQ_MASK) >= + ((nd->nd_seq_in - nd->nd_seq_out) & SEQ_MASK)) { + ch->ch_flag &= ~CH_RX_FLUSH; + } + + /* + * If we are ready to receive, move the data into + * the receive buffer. + */ + + ch->ch_s_rin = (ch->ch_s_rin + dlen) & 0xffff; + + if (ch->ch_state == CS_READY && + (ch->ch_tun.un_open_count != 0) && + (ch->ch_tun.un_flag & UN_CLOSING) == 0 && + (ch->ch_cflag & CF_CREAD) != 0 && + (ch->ch_flag & (CH_BAUD0 | CH_RX_FLUSH)) == 0 && + (ch->ch_send & RR_RX_FLUSH) == 0) { + + if (ch->ch_rin + dlen >= RBUF_MAX) { + n = RBUF_MAX - ch->ch_rin; + + memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, n); + + ch->ch_rin = 0; + dbuf += n; + dlen -= n; + } + + memcpy(ch->ch_rbuf + ch->ch_rin, dbuf, dlen); + + ch->ch_rin += dlen; + + + /* + * If we are not in fastcook mode, or + * if there is a fastcook thread + * waiting for data, send the data to + * the line discipline. + */ + + if ((ch->ch_flag & CH_FAST_READ) == 0 || + ch->ch_inwait != 0) { + dgrp_input(ch); + } + + /* + * If there is a read thread waiting + * in select, and we are in fastcook + * mode, wake him up. + */ + + if (waitqueue_active(&ch->ch_tun.un_tty->read_wait) && + (ch->ch_flag & CH_FAST_READ) != 0) + wake_up_interruptible(&ch->ch_tun.un_tty->read_wait); + + /* + * Wake any thread waiting in the + * fastcook loop. + */ + + if ((ch->ch_flag & CH_INPUT) != 0) { + ch->ch_flag &= ~CH_INPUT; + + wake_up_interruptible(&ch->ch_flag_wait); + } + } + + /* + * Fabricate and insert a data packet header to + * preced the remaining data when it comes in. + */ + + if (remain < plen) { + dlen = plen - remain; + b = buf; + + b[0] = 0x90 + n1; + put_unaligned_be16(dlen, b + 1); + + remain = 3; + goto done; + } break; /* diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c index f8788bf0a7d3..cdeffe75496b 100644 --- a/drivers/staging/gdm72xx/gdm_usb.c +++ b/drivers/staging/gdm72xx/gdm_usb.c @@ -635,11 +635,14 @@ static int gdm_usb_probe(struct usb_interface *intf, #endif /* CONFIG_WIMAX_GDM72XX_USB_PM */ ret = register_wimax_device(phy_dev, &intf->dev); + if (ret) + release_usb(udev); out: if (ret) { kfree(phy_dev); kfree(udev); + usb_put_dev(usbdev); } else { usb_set_intfdata(intf, phy_dev); } diff --git a/drivers/staging/iio/Documentation/iio_utils.h b/drivers/staging/iio/Documentation/iio_utils.h index 35154d60faf6..c9fedb79e3a2 100644 --- a/drivers/staging/iio/Documentation/iio_utils.h +++ b/drivers/staging/iio/Documentation/iio_utils.h @@ -77,7 +77,6 @@ struct iio_channel_info { uint64_t mask; unsigned be; unsigned is_signed; - unsigned enabled; unsigned location; }; @@ -335,6 +334,7 @@ inline int build_channel_array(const char *device_dir, while (ent = readdir(dp), ent != NULL) { if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) { + int current_enabled = 0; current = &(*ci_array)[count++]; ret = asprintf(&filename, "%s/%s", scan_el_dir, ent->d_name); @@ -350,10 +350,10 @@ inline int build_channel_array(const char *device_dir, ret = -errno; goto error_cleanup_array; } - fscanf(sysfsfp, "%u", ¤t->enabled); + fscanf(sysfsfp, "%u", ¤t_enabled); fclose(sysfsfp); - if (!current->enabled) { + if (!current_enabled) { free(filename); count--; continue; diff --git a/drivers/staging/iio/adc/ad799x_core.c b/drivers/staging/iio/adc/ad799x_core.c index 5ea36410f716..5708ffc62aec 100644 --- a/drivers/staging/iio/adc/ad799x_core.c +++ b/drivers/staging/iio/adc/ad799x_core.c @@ -393,7 +393,7 @@ static const struct iio_event_spec ad799x_events[] = { }, { .type = IIO_EV_TYPE_THRESH, .dir = IIO_EV_DIR_FALLING, - .mask_separate = BIT(IIO_EV_INFO_VALUE), + .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE), }, { .type = IIO_EV_TYPE_THRESH, @@ -409,7 +409,13 @@ static const struct iio_event_spec ad799x_events[] = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ .scan_index = (_index), \ - .scan_type = IIO_ST('u', _realbits, 16, 12 - (_realbits)), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_realbits), \ + .storagebits = 16, \ + .shift = 12 - (_realbits), \ + .endianness = IIO_BE, \ + }, \ .event_spec = _ev_spec, \ .num_event_specs = _num_ev_spec, \ } @@ -588,7 +594,8 @@ static int ad799x_probe(struct i2c_client *client, return 0; error_free_irq: - free_irq(client->irq, indio_dev); + if (client->irq > 0) + free_irq(client->irq, indio_dev); error_cleanup_ring: ad799x_ring_cleanup(indio_dev); error_disable_reg: diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c index df71669bb60e..514844efac75 100644 --- a/drivers/staging/iio/adc/mxs-lradc.c +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -757,6 +757,7 @@ static void mxs_lradc_finish_touch_event(struct mxs_lradc *lradc, bool valid) } /* if it is released, wait for the next touch via IRQ */ + lradc->cur_plate = LRADC_TOUCH; mxs_lradc_reg_clear(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ, LRADC_CTRL1); mxs_lradc_reg_set(lradc, LRADC_CTRL1_TOUCH_DETECT_IRQ_EN, LRADC_CTRL1); } @@ -1035,8 +1036,6 @@ SHOW_SCALE_AVAILABLE_ATTR(4); SHOW_SCALE_AVAILABLE_ATTR(5); SHOW_SCALE_AVAILABLE_ATTR(6); SHOW_SCALE_AVAILABLE_ATTR(7); -SHOW_SCALE_AVAILABLE_ATTR(8); -SHOW_SCALE_AVAILABLE_ATTR(9); SHOW_SCALE_AVAILABLE_ATTR(10); SHOW_SCALE_AVAILABLE_ATTR(11); SHOW_SCALE_AVAILABLE_ATTR(12); @@ -1053,8 +1052,6 @@ static struct attribute *mxs_lradc_attributes[] = { &iio_dev_attr_in_voltage5_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage6_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage7_scale_available.dev_attr.attr, - &iio_dev_attr_in_voltage8_scale_available.dev_attr.attr, - &iio_dev_attr_in_voltage9_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage10_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage11_scale_available.dev_attr.attr, &iio_dev_attr_in_voltage12_scale_available.dev_attr.attr, @@ -1613,7 +1610,7 @@ static int mxs_lradc_probe(struct platform_device *pdev) * of the array. */ scale_uv = ((u64)lradc->vref_mv[i] * 100000000) >> - (iio->channels[i].scan_type.realbits - s); + (LRADC_RESOLUTION - s); lradc->scale_avail[i][s].nano = do_div(scale_uv, 100000000) * 10; lradc->scale_avail[i][s].integer = scale_uv; diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index 0a4298b744e6..2b96665da8a2 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -629,7 +629,7 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev) struct iio_buffer *buffer; buffer = iio_kfifo_allocate(indio_dev); - if (buffer) + if (!buffer) return -ENOMEM; iio_device_attach_buffer(indio_dev, buffer); diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c index 09ef5fb8bae6..236ed66f116a 100644 --- a/drivers/staging/imx-drm/imx-drm-core.c +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -88,9 +88,9 @@ static int imx_drm_driver_unload(struct drm_device *drm) imx_drm_device_put(); - drm_vblank_cleanup(imxdrm->drm); - drm_kms_helper_poll_fini(imxdrm->drm); - drm_mode_config_cleanup(imxdrm->drm); + drm_vblank_cleanup(drm); + drm_kms_helper_poll_fini(drm); + drm_mode_config_cleanup(drm); return 0; } @@ -142,19 +142,19 @@ EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format); int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) { - return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe); + return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe); } EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get); void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc) { - drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe); + drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe); } EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put); void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc) { - drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe); + drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe); } EXPORT_SYMBOL_GPL(imx_drm_handle_vblank); @@ -370,29 +370,6 @@ static void imx_drm_connector_unregister( } /* - * register a crtc to the drm core - */ -static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc) -{ - struct imx_drm_device *imxdrm = __imx_drm_device(); - int ret; - - ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256); - if (ret) - return ret; - - drm_crtc_helper_add(imx_drm_crtc->crtc, - imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); - - drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc, - imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); - - drm_mode_group_reinit(imxdrm->drm); - - return 0; -} - -/* * Called by the CRTC driver when all CRTCs are registered. This * puts all the pieces together and initializes the driver. * Once this is called no more CRTCs can be registered since @@ -424,15 +401,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) mutex_lock(&imxdrm->mutex); - drm_kms_helper_poll_init(imxdrm->drm); + drm_kms_helper_poll_init(drm); /* setup the grouping for the legacy output */ - ret = drm_mode_group_init_legacy_group(imxdrm->drm, - &imxdrm->drm->primary->mode_group); + ret = drm_mode_group_init_legacy_group(drm, + &drm->primary->mode_group); if (ret) goto err_kms; - ret = drm_vblank_init(imxdrm->drm, MAX_CRTC); + ret = drm_vblank_init(drm, MAX_CRTC); if (ret) goto err_kms; @@ -441,7 +418,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) * by drm timer once a current process gives up ownership of * vblank event.(after drm_vblank_put function is called) */ - imxdrm->drm->vblank_disable_allowed = true; + drm->vblank_disable_allowed = true; if (!imx_drm_device_get()) { ret = -EINVAL; @@ -536,10 +513,18 @@ int imx_drm_add_crtc(struct drm_crtc *crtc, *new_crtc = imx_drm_crtc; - ret = imx_drm_crtc_register(imx_drm_crtc); + ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256); if (ret) goto err_register; + drm_crtc_helper_add(crtc, + imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); + + drm_crtc_init(imxdrm->drm, crtc, + imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); + + drm_mode_group_reinit(imxdrm->drm); + imx_drm_update_possible_crtcs(); mutex_unlock(&imxdrm->mutex); diff --git a/drivers/staging/imx-drm/imx-hdmi.c b/drivers/staging/imx-drm/imx-hdmi.c index f3a1f5e2e492..62ce0e86f14b 100644 --- a/drivers/staging/imx-drm/imx-hdmi.c +++ b/drivers/staging/imx-drm/imx-hdmi.c @@ -16,6 +16,7 @@ #include <linux/delay.h> #include <linux/err.h> #include <linux/clk.h> +#include <linux/hdmi.h> #include <linux/regmap.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> @@ -52,11 +53,6 @@ enum hdmi_datamap { YCbCr422_12B = 0x12, }; -enum hdmi_colorimetry { - ITU601, - ITU709, -}; - enum imx_hdmi_devtype { IMX6Q_HDMI, IMX6DL_HDMI, @@ -489,12 +485,12 @@ static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi) if (is_color_space_conversion(hdmi)) { if (hdmi->hdmi_data.enc_out_format == RGB) { - if (hdmi->hdmi_data.colorimetry == ITU601) + if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) csc_coeff = &csc_coeff_rgb_out_eitu601; else csc_coeff = &csc_coeff_rgb_out_eitu709; } else if (hdmi->hdmi_data.enc_in_format == RGB) { - if (hdmi->hdmi_data.colorimetry == ITU601) + if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) csc_coeff = &csc_coeff_rgb_in_eitu601; else csc_coeff = &csc_coeff_rgb_in_eitu709; @@ -1140,16 +1136,16 @@ static void hdmi_config_AVI(struct imx_hdmi *hdmi) /* Set up colorimetry */ if (hdmi->hdmi_data.enc_out_format == XVYCC444) { colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO; - if (hdmi->hdmi_data.colorimetry == ITU601) + if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601; - else /* hdmi->hdmi_data.colorimetry == ITU709 */ + else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/ ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709; } else if (hdmi->hdmi_data.enc_out_format != RGB) { - if (hdmi->hdmi_data.colorimetry == ITU601) + if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601) colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE; - else /* hdmi->hdmi_data.colorimetry == ITU709 */ + else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR; ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601; } else { /* Carries no data */ @@ -1379,9 +1375,9 @@ static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode) (hdmi->vic == 21) || (hdmi->vic == 22) || (hdmi->vic == 2) || (hdmi->vic == 3) || (hdmi->vic == 17) || (hdmi->vic == 18)) - hdmi->hdmi_data.colorimetry = ITU601; + hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601; else - hdmi->hdmi_data.colorimetry = ITU709; + hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709; if ((hdmi->vic == 10) || (hdmi->vic == 11) || (hdmi->vic == 12) || (hdmi->vic == 13) || diff --git a/drivers/staging/lustre/TODO b/drivers/staging/lustre/TODO index 22742d6d62a8..0a2b6cb3775e 100644 --- a/drivers/staging/lustre/TODO +++ b/drivers/staging/lustre/TODO @@ -9,5 +9,6 @@ * Other minor misc cleanups... Please send any patches to Greg Kroah-Hartman <greg@kroah.com>, Andreas Dilger -<andreas.dilger@intel.com> and Peng Tao <tao.peng@emc.com>. CCing -hpdd-discuss <hpdd-discuss@lists.01.org> would be great too. +<andreas.dilger@intel.com>, Oleg Drokin <oleg.drokin@intel.com> and +Peng Tao <tao.peng@emc.com>. CCing hpdd-discuss <hpdd-discuss@lists.01.org> +would be great too. diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h index 596a15fc8996..037ae8a6d531 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_kernelcomm.h @@ -61,6 +61,8 @@ struct kuc_hdr { __u16 kuc_msglen; /* Including header */ } __attribute__((aligned(sizeof(__u64)))); +#define KUC_CHANGELOG_MSG_MAXSIZE (sizeof(struct kuc_hdr)+CR_MAXSIZE) + #define KUC_MAGIC 0x191C /*Lustre9etLinC */ #define KUC_FL_BLOCK 0x01 /* Wait for send */ diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h index d0d942ced01a..dddccca120c9 100644 --- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h +++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h @@ -120,7 +120,7 @@ do { \ do { \ LASSERT(!in_interrupt() || \ ((size) <= LIBCFS_VMALLOC_SIZE && \ - ((mask) & GFP_ATOMIC)) != 0); \ + ((mask) & __GFP_WAIT) == 0)); \ } while (0) #define LIBCFS_ALLOC_POST(ptr, size) \ diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 93648632ba26..6f58ead20393 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -529,7 +529,7 @@ kiblnd_kvaddr_to_page (unsigned long vaddr) { struct page *page; - if (is_vmalloc_addr(vaddr)) { + if (is_vmalloc_addr((void *)vaddr)) { page = vmalloc_to_page ((void *)vaddr); LASSERT (page != NULL); return page; diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c index 68a4f52ec998..b7b53b579c85 100644 --- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c @@ -924,7 +924,7 @@ ksocknal_launch_packet (lnet_ni_t *ni, ksock_tx_t *tx, lnet_process_id_t id) int ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) { - int mpflag = 0; + int mpflag = 1; int type = lntmsg->msg_type; lnet_process_id_t target = lntmsg->msg_target; unsigned int payload_niov = lntmsg->msg_niov; @@ -993,8 +993,9 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg) /* The first fragment will be set later in pro_pack */ rc = ksocknal_launch_packet(ni, tx, target); - if (lntmsg->msg_vmflush) + if (!mpflag) cfs_memory_pressure_restore(mpflag); + if (rc == 0) return (0); diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h index 6b6c0240e824..7893d83e131f 100644 --- a/drivers/staging/lustre/lustre/include/lustre/lustre_user.h +++ b/drivers/staging/lustre/lustre/include/lustre/lustre_user.h @@ -760,7 +760,8 @@ static inline void hsm_set_cl_error(int *flags, int error) *flags |= (error << CLF_HSM_ERR_L); } -#define CR_MAXSIZE cfs_size_round(2*NAME_MAX + 1 + sizeof(struct changelog_rec)) +#define CR_MAXSIZE cfs_size_round(2*NAME_MAX + 1 + \ + sizeof(struct changelog_ext_rec)) struct changelog_rec { __u16 cr_namelen; diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c index 22d0acc95bc5..52b7731bcc38 100644 --- a/drivers/staging/lustre/lustre/llite/dir.c +++ b/drivers/staging/lustre/lustre/llite/dir.c @@ -1086,7 +1086,7 @@ static int quotactl_ioctl(struct ll_sb_info *sbi, struct if_quotactl *qctl) break; case Q_GETQUOTA: if (((type == USRQUOTA && - uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || + !uid_eq(current_euid(), make_kuid(&init_user_ns, id))) || (type == GRPQUOTA && !in_egroup_p(make_kgid(&init_user_ns, id)))) && (!cfs_capable(CFS_CAP_SYS_ADMIN) || diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c index d1ad91c34ddc..83013927e131 100644 --- a/drivers/staging/lustre/lustre/mdc/mdc_request.c +++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c @@ -1430,7 +1430,7 @@ static struct kuc_hdr *changelog_kuc_hdr(char *buf, int len, int flags) { struct kuc_hdr *lh = (struct kuc_hdr *)buf; - LASSERT(len <= CR_MAXSIZE); + LASSERT(len <= KUC_CHANGELOG_MSG_MAXSIZE); lh->kuc_magic = KUC_MAGIC; lh->kuc_transport = KUC_TRANSPORT_CHANGELOG; @@ -1503,7 +1503,7 @@ static int mdc_changelog_send_thread(void *csdata) CDEBUG(D_CHANGELOG, "changelog to fp=%p start "LPU64"\n", cs->cs_fp, cs->cs_startrec); - OBD_ALLOC(cs->cs_buf, CR_MAXSIZE); + OBD_ALLOC(cs->cs_buf, KUC_CHANGELOG_MSG_MAXSIZE); if (cs->cs_buf == NULL) GOTO(out, rc = -ENOMEM); @@ -1540,7 +1540,7 @@ out: if (ctxt) llog_ctxt_put(ctxt); if (cs->cs_buf) - OBD_FREE(cs->cs_buf, CR_MAXSIZE); + OBD_FREE(cs->cs_buf, KUC_CHANGELOG_MSG_MAXSIZE); OBD_FREE_PTR(cs); return rc; } diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c index eedffed17e39..31b269a5fff7 100644 --- a/drivers/staging/netlogic/xlr_net.c +++ b/drivers/staging/netlogic/xlr_net.c @@ -307,7 +307,7 @@ static netdev_tx_t xlr_net_start_xmit(struct sk_buff *skb, } static u16 xlr_net_select_queue(struct net_device *ndev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { return (u16)smp_processor_id(); } @@ -892,6 +892,11 @@ static int xlr_setup_mdio(struct xlr_net_priv *priv, priv->mii_bus->write = xlr_mii_write; priv->mii_bus->parent = &pdev->dev; priv->mii_bus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL); + if (priv->mii_bus->irq == NULL) { + pr_err("irq alloc failed\n"); + mdiobus_free(priv->mii_bus); + return -ENOMEM; + } priv->mii_bus->irq[priv->phy_addr] = priv->ndev->irq; /* Scan only the enabled address */ diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c index 47e0a91238a1..5a001d9b4252 100644 --- a/drivers/staging/octeon-usb/octeon-hcd.c +++ b/drivers/staging/octeon-usb/octeon-hcd.c @@ -275,13 +275,6 @@ enum cvmx_usb_pipe_flags { */ #define MAX_TRANSFER_PACKETS ((1<<10)-1) -enum { - USB_CLOCK_TYPE_REF_12, - USB_CLOCK_TYPE_REF_24, - USB_CLOCK_TYPE_REF_48, - USB_CLOCK_TYPE_CRYSTAL_12, -}; - /** * Logical transactions may take numerous low level * transactions, especially when splits are concerned. This @@ -471,19 +464,6 @@ struct octeon_hcd { /* Returns the IO address to push/pop stuff data from the FIFOs */ #define USB_FIFO_ADDRESS(channel, usb_index) (CVMX_USBCX_GOTGCTL(usb_index) + ((channel)+1)*0x1000) -static int octeon_usb_get_clock_type(void) -{ - switch (cvmx_sysinfo_get()->board_type) { - case CVMX_BOARD_TYPE_BBGW_REF: - case CVMX_BOARD_TYPE_LANAI2_A: - case CVMX_BOARD_TYPE_LANAI2_U: - case CVMX_BOARD_TYPE_LANAI2_G: - case CVMX_BOARD_TYPE_UBNT_E100: - return USB_CLOCK_TYPE_CRYSTAL_12; - } - return USB_CLOCK_TYPE_REF_48; -} - /** * Read a USB 32bit CSR. It performs the necessary address swizzle * for 32bit CSRs and logs the value in a readable format if @@ -582,37 +562,6 @@ static inline int __cvmx_usb_get_data_pid(struct cvmx_usb_pipe *pipe) return 0; /* Data0 */ } - -/** - * Return the number of USB ports supported by this Octeon - * chip. If the chip doesn't support USB, or is not supported - * by this API, a zero will be returned. Most Octeon chips - * support one usb port, but some support two ports. - * cvmx_usb_initialize() must be called on independent - * struct cvmx_usb_state. - * - * Returns: Number of port, zero if usb isn't supported - */ -static int cvmx_usb_get_num_ports(void) -{ - int arch_ports = 0; - - if (OCTEON_IS_MODEL(OCTEON_CN56XX)) - arch_ports = 1; - else if (OCTEON_IS_MODEL(OCTEON_CN52XX)) - arch_ports = 2; - else if (OCTEON_IS_MODEL(OCTEON_CN50XX)) - arch_ports = 1; - else if (OCTEON_IS_MODEL(OCTEON_CN31XX)) - arch_ports = 1; - else if (OCTEON_IS_MODEL(OCTEON_CN30XX)) - arch_ports = 1; - else - arch_ports = 0; - - return arch_ports; -} - /** * Initialize a USB port for use. This must be called before any * other access to the Octeon USB port is made. The port starts @@ -628,41 +577,16 @@ static int cvmx_usb_get_num_ports(void) * Returns: 0 or a negative error code. */ static int cvmx_usb_initialize(struct cvmx_usb_state *usb, - int usb_port_number) + int usb_port_number, + enum cvmx_usb_initialize_flags flags) { union cvmx_usbnx_clk_ctl usbn_clk_ctl; union cvmx_usbnx_usbp_ctl_status usbn_usbp_ctl_status; - enum cvmx_usb_initialize_flags flags = 0; int i; /* At first allow 0-1 for the usb port number */ if ((usb_port_number < 0) || (usb_port_number > 1)) return -EINVAL; - /* For all chips except 52XX there is only one port */ - if (!OCTEON_IS_MODEL(OCTEON_CN52XX) && (usb_port_number > 0)) - return -EINVAL; - /* Try to determine clock type automatically */ - if (octeon_usb_get_clock_type() == USB_CLOCK_TYPE_CRYSTAL_12) { - /* Only 12 MHZ crystals are supported */ - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; - } else { - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND; - - switch (octeon_usb_get_clock_type()) { - case USB_CLOCK_TYPE_REF_12: - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ; - break; - case USB_CLOCK_TYPE_REF_24: - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ; - break; - case USB_CLOCK_TYPE_REF_48: - flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ; - break; - default: - return -EINVAL; - break; - } - } memset(usb, 0, sizeof(*usb)); usb->init_flags = flags; @@ -3431,7 +3355,6 @@ static int octeon_usb_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, return 0; } - static const struct hc_driver octeon_hc_driver = { .description = "Octeon USB", .product_desc = "Octeon Host Controller", @@ -3448,15 +3371,74 @@ static const struct hc_driver octeon_hc_driver = { .hub_control = octeon_usb_hub_control, }; - -static int octeon_usb_driver_probe(struct device *dev) +static int octeon_usb_probe(struct platform_device *pdev) { int status; - int usb_num = to_platform_device(dev)->id; - int irq = platform_get_irq(to_platform_device(dev), 0); + int initialize_flags; + int usb_num; + struct resource *res_mem; + struct device_node *usbn_node; + int irq = platform_get_irq(pdev, 0); + struct device *dev = &pdev->dev; struct octeon_hcd *priv; struct usb_hcd *hcd; unsigned long flags; + u32 clock_rate = 48000000; + bool is_crystal_clock = false; + const char *clock_type; + int i; + + if (dev->of_node == NULL) { + dev_err(dev, "Error: empty of_node\n"); + return -ENXIO; + } + usbn_node = dev->of_node->parent; + + i = of_property_read_u32(usbn_node, + "refclk-frequency", &clock_rate); + if (i) { + dev_err(dev, "No USBN \"refclk-frequency\"\n"); + return -ENXIO; + } + switch (clock_rate) { + case 12000000: + initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_12MHZ; + break; + case 24000000: + initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_24MHZ; + break; + case 48000000: + initialize_flags = CVMX_USB_INITIALIZE_FLAGS_CLOCK_48MHZ; + break; + default: + dev_err(dev, "Illebal USBN \"refclk-frequency\" %u\n", clock_rate); + return -ENXIO; + + } + + i = of_property_read_string(usbn_node, + "refclk-type", &clock_type); + + if (!i && strcmp("crystal", clock_type) == 0) + is_crystal_clock = true; + + if (is_crystal_clock) + initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_XI; + else + initialize_flags |= CVMX_USB_INITIALIZE_FLAGS_CLOCK_XO_GND; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res_mem == NULL) { + dev_err(dev, "found no memory resource\n"); + return -ENXIO; + } + usb_num = (res_mem->start >> 44) & 1; + + if (irq < 0) { + /* Defective device tree, but we know how to fix it. */ + irq_hw_number_t hwirq = usb_num ? (1 << 6) + 17 : 56; + irq = irq_create_mapping(NULL, hwirq); + } /* * Set the DMA mask to 64bits so we get buffers already translated for @@ -3465,6 +3447,26 @@ static int octeon_usb_driver_probe(struct device *dev) dev->coherent_dma_mask = ~0; dev->dma_mask = &dev->coherent_dma_mask; + /* + * Only cn52XX and cn56XX have DWC_OTG USB hardware and the + * IOB priority registers. Under heavy network load USB + * hardware can be starved by the IOB causing a crash. Give + * it a priority boost if it has been waiting more than 400 + * cycles to avoid this situation. + * + * Testing indicates that a cnt_val of 8192 is not sufficient, + * but no failures are seen with 4096. We choose a value of + * 400 to give a safety factor of 10. + */ + if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) { + union cvmx_iob_n2c_l2c_pri_cnt pri_cnt; + + pri_cnt.u64 = 0; + pri_cnt.s.cnt_enb = 1; + pri_cnt.s.cnt_val = 400; + cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64); + } + hcd = usb_create_hcd(&octeon_hc_driver, dev, dev_name(dev)); if (!hcd) { dev_dbg(dev, "Failed to allocate memory for HCD\n"); @@ -3478,7 +3480,7 @@ static int octeon_usb_driver_probe(struct device *dev) tasklet_init(&priv->dequeue_tasklet, octeon_usb_urb_dequeue_work, (unsigned long)priv); INIT_LIST_HEAD(&priv->dequeue_list); - status = cvmx_usb_initialize(&priv->usb, usb_num); + status = cvmx_usb_initialize(&priv->usb, usb_num, initialize_flags); if (status) { dev_dbg(dev, "USB initialization failed with %d\n", status); kfree(hcd); @@ -3492,7 +3494,7 @@ static int octeon_usb_driver_probe(struct device *dev) cvmx_usb_poll(&priv->usb); spin_unlock_irqrestore(&priv->lock, flags); - status = usb_add_hcd(hcd, irq, IRQF_SHARED); + status = usb_add_hcd(hcd, irq, 0); if (status) { dev_dbg(dev, "USB add HCD failed with %d\n", status); kfree(hcd); @@ -3500,14 +3502,15 @@ static int octeon_usb_driver_probe(struct device *dev) } device_wakeup_enable(hcd->self.controller); - dev_dbg(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq); + dev_info(dev, "Registered HCD for port %d on irq %d\n", usb_num, irq); return 0; } -static int octeon_usb_driver_remove(struct device *dev) +static int octeon_usb_remove(struct platform_device *pdev) { int status; + struct device *dev = &pdev->dev; struct usb_hcd *hcd = dev_get_drvdata(dev); struct octeon_hcd *priv = hcd_to_octeon(hcd); unsigned long flags; @@ -3525,85 +3528,41 @@ static int octeon_usb_driver_remove(struct device *dev) return 0; } -static struct device_driver octeon_usb_driver = { - .name = "OcteonUSB", - .bus = &platform_bus_type, - .probe = octeon_usb_driver_probe, - .remove = octeon_usb_driver_remove, +static struct of_device_id octeon_usb_match[] = { + { + .compatible = "cavium,octeon-5750-usbc", + }, + {}, }; +static struct platform_driver octeon_usb_driver = { + .driver = { + .name = "OcteonUSB", + .owner = THIS_MODULE, + .of_match_table = octeon_usb_match, + }, + .probe = octeon_usb_probe, + .remove = octeon_usb_remove, +}; -#define MAX_USB_PORTS 10 -static struct platform_device *pdev_glob[MAX_USB_PORTS]; -static int octeon_usb_registered; -static int __init octeon_usb_module_init(void) +static int __init octeon_usb_driver_init(void) { - int num_devices = cvmx_usb_get_num_ports(); - int device; - - if (usb_disabled() || num_devices == 0) - return -ENODEV; - - if (driver_register(&octeon_usb_driver)) - return -ENOMEM; - - octeon_usb_registered = 1; - - /* - * Only cn52XX and cn56XX have DWC_OTG USB hardware and the - * IOB priority registers. Under heavy network load USB - * hardware can be starved by the IOB causing a crash. Give - * it a priority boost if it has been waiting more than 400 - * cycles to avoid this situation. - * - * Testing indicates that a cnt_val of 8192 is not sufficient, - * but no failures are seen with 4096. We choose a value of - * 400 to give a safety factor of 10. - */ - if (OCTEON_IS_MODEL(OCTEON_CN52XX) || OCTEON_IS_MODEL(OCTEON_CN56XX)) { - union cvmx_iob_n2c_l2c_pri_cnt pri_cnt; - - pri_cnt.u64 = 0; - pri_cnt.s.cnt_enb = 1; - pri_cnt.s.cnt_val = 400; - cvmx_write_csr(CVMX_IOB_N2C_L2C_PRI_CNT, pri_cnt.u64); - } - - for (device = 0; device < num_devices; device++) { - struct resource irq_resource; - struct platform_device *pdev; - memset(&irq_resource, 0, sizeof(irq_resource)); - irq_resource.start = (device == 0) ? OCTEON_IRQ_USB0 : OCTEON_IRQ_USB1; - irq_resource.end = irq_resource.start; - irq_resource.flags = IORESOURCE_IRQ; - pdev = platform_device_register_simple((char *)octeon_usb_driver. name, device, &irq_resource, 1); - if (IS_ERR(pdev)) { - driver_unregister(&octeon_usb_driver); - octeon_usb_registered = 0; - return PTR_ERR(pdev); - } - if (device < MAX_USB_PORTS) - pdev_glob[device] = pdev; + if (usb_disabled()) + return 0; - } - return 0; + return platform_driver_register(&octeon_usb_driver); } +module_init(octeon_usb_driver_init); -static void __exit octeon_usb_module_cleanup(void) +static void __exit octeon_usb_driver_exit(void) { - int i; + if (usb_disabled()) + return; - for (i = 0; i < MAX_USB_PORTS; i++) - if (pdev_glob[i]) { - platform_device_unregister(pdev_glob[i]); - pdev_glob[i] = NULL; - } - if (octeon_usb_registered) - driver_unregister(&octeon_usb_driver); + platform_driver_unregister(&octeon_usb_driver); } +module_exit(octeon_usb_driver_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Cavium Networks <support@caviumnetworks.com>"); -MODULE_DESCRIPTION("Cavium Networks Octeon USB Host driver."); -module_init(octeon_usb_module_init); -module_exit(octeon_usb_module_cleanup); +MODULE_AUTHOR("Cavium, Inc. <support@cavium.com>"); +MODULE_DESCRIPTION("Cavium Inc. OCTEON USB Host driver."); diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c index cb060364dfe7..5d965cf06d59 100644 --- a/drivers/staging/ozwpan/ozproto.c +++ b/drivers/staging/ozwpan/ozproto.c @@ -668,8 +668,8 @@ void oz_binding_add(const char *net_dev) if (binding) { binding->ptype.type = __constant_htons(OZ_ETHERTYPE); binding->ptype.func = oz_pkt_recv; - memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN); if (net_dev && *net_dev) { + memcpy(binding->name, net_dev, OZ_MAX_BINDING_LEN); oz_dbg(ON, "Adding binding: %s\n", net_dev); binding->ptype.dev = dev_get_by_name(&init_net, net_dev); @@ -680,6 +680,7 @@ void oz_binding_add(const char *net_dev) } } else { oz_dbg(ON, "Binding to all netcards\n"); + memset(binding->name, 0, OZ_MAX_BINDING_LEN); binding->ptype.dev = NULL; } if (binding) { diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c index 153ec61493ab..96df62f95b6b 100644 --- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c +++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c @@ -912,12 +912,12 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) unsigned char *pbuf; u32 wpa_ielen = 0; u8 *pbssid = GetAddr3Ptr(pframe); - u32 hidden_ssid = 0; struct HT_info_element *pht_info = NULL; struct rtw_ieee80211_ht_cap *pht_cap = NULL; u32 bcn_channel; unsigned short ht_cap_info; unsigned char ht_info_infos_0; + int ssid_len; if (is_client_associated_to_ap(Adapter) == false) return true; @@ -999,21 +999,15 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len) } /* checking SSID */ + ssid_len = 0; p = rtw_get_ie(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_); - if (p == NULL) { - DBG_88E("%s marc: cannot find SSID for survey event\n", __func__); - hidden_ssid = true; - } else { - hidden_ssid = false; - } - - if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) { - memcpy(bssid->Ssid.Ssid, (p + 2), *(p + 1)); - bssid->Ssid.SsidLength = *(p + 1); - } else { - bssid->Ssid.SsidLength = 0; - bssid->Ssid.Ssid[0] = '\0'; + if (p) { + ssid_len = *(p + 1); + if (ssid_len > NDIS_802_11_LENGTH_SSID) + ssid_len = 0; } + memcpy(bssid->Ssid.Ssid, (p + 2), ssid_len); + bssid->Ssid.SsidLength = ssid_len; RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d " "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__, bssid->Ssid.Ssid, diff --git a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c index dec992569476..4ad80ae1067f 100644 --- a/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c +++ b/drivers/staging/rtl8188eu/os_dep/ioctl_linux.c @@ -2500,7 +2500,7 @@ static int rtw_mp_ioctl_hdl(struct net_device *dev, struct iw_request_info *info ("rtw_mp_ioctl_hdl: subcode [%d], len[%d], buffer_len[%d]\r\n", poidparam->subcode, poidparam->len, len)); - if (poidparam->subcode >= MAX_MP_IOCTL_SUBCODE) { + if (poidparam->subcode >= ARRAY_SIZE(mp_ioctl_hdl)) { RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_, ("no matching drvext subcodes\r\n")); ret = -EINVAL; goto _rtw_mp_ioctl_hdl_exit; @@ -3164,9 +3164,7 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev, u8 *p2pie; uint p2pielen = 0, attr_contentlen = 0; u8 attr_content[100] = {0x00}; - - u8 go_devadd_str[17 + 10] = {0x00}; - /* +10 is for the str "go_devadd =", we have to clear it at wrqu->data.pointer */ + u8 go_devadd_str[17 + 12] = {}; /* Commented by Albert 20121209 */ /* The input data is the GO's interface address which the application wants to know its device address. */ @@ -3223,12 +3221,12 @@ static int rtw_p2p_get_go_device_address(struct net_device *dev, spin_unlock_bh(&pmlmepriv->scanned_queue.lock); if (!blnMatch) - sprintf(go_devadd_str, "\n\ndev_add = NULL"); + snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add = NULL"); else - sprintf(go_devadd_str, "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + snprintf(go_devadd_str, sizeof(go_devadd_str), "\n\ndev_add =%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", attr_content[0], attr_content[1], attr_content[2], attr_content[3], attr_content[4], attr_content[5]); - if (copy_to_user(wrqu->data.pointer, go_devadd_str, 10 + 17)) + if (copy_to_user(wrqu->data.pointer, go_devadd_str, sizeof(go_devadd_str))) return -EFAULT; return ret; } diff --git a/drivers/staging/rtl8188eu/os_dep/os_intfs.c b/drivers/staging/rtl8188eu/os_dep/os_intfs.c index 68f98fa114d2..7c9ee58f47bb 100644 --- a/drivers/staging/rtl8188eu/os_dep/os_intfs.c +++ b/drivers/staging/rtl8188eu/os_dep/os_intfs.c @@ -653,7 +653,7 @@ static unsigned int rtw_classify8021d(struct sk_buff *skb) } static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb, - void *accel_priv) + void *accel_priv, select_queue_fallback_t fallback) { struct adapter *padapter = rtw_netdev_priv(dev); struct mlme_priv *pmlmepriv = &padapter->mlmepriv; diff --git a/drivers/staging/rtl8188eu/os_dep/usb_intf.c b/drivers/staging/rtl8188eu/os_dep/usb_intf.c index 0a341d6ec51f..2f40ff5901d6 100644 --- a/drivers/staging/rtl8188eu/os_dep/usb_intf.c +++ b/drivers/staging/rtl8188eu/os_dep/usb_intf.c @@ -53,8 +53,9 @@ static struct usb_device_id rtw_usb_id_tbl[] = { {USB_DEVICE(USB_VENDER_ID_REALTEK, 0x0179)}, /* 8188ETV */ /*=== Customer ID ===*/ /****** 8188EUS ********/ - {USB_DEVICE(0x8179, 0x07B8)}, /* Abocom - Abocom */ + {USB_DEVICE(0x07b8, 0x8179)}, /* Abocom - Abocom */ {USB_DEVICE(0x2001, 0x330F)}, /* DLink DWA-125 REV D1 */ + {USB_DEVICE(0x2001, 0x3310)}, /* Dlink DWA-123 REV D1 */ {} /* Terminating entry */ }; diff --git a/drivers/staging/rtl8821ae/Kconfig b/drivers/staging/rtl8821ae/Kconfig index 2aa5dac2f1df..abccc9dabd65 100644 --- a/drivers/staging/rtl8821ae/Kconfig +++ b/drivers/staging/rtl8821ae/Kconfig @@ -1,6 +1,6 @@ config R8821AE tristate "RealTek RTL8821AE Wireless LAN NIC driver" - depends on PCI && WLAN + depends on PCI && WLAN && MAC80211 depends on m select WIRELESS_EXT select WEXT_PRIV diff --git a/drivers/staging/rtl8821ae/wifi.h b/drivers/staging/rtl8821ae/wifi.h index cfe88a1efd55..76bef93ad70a 100644 --- a/drivers/staging/rtl8821ae/wifi.h +++ b/drivers/staging/rtl8821ae/wifi.h @@ -1414,7 +1414,7 @@ struct rtl_dm { /*88e tx power tracking*/ - u8 bb_swing_idx_ofdm[2]; + u8 bb_swing_idx_ofdm[MAX_RF_PATH]; u8 bb_swing_idx_ofdm_current; u8 bb_swing_idx_ofdm_base[MAX_RF_PATH]; bool bb_swing_flag_Ofdm; diff --git a/drivers/staging/usbip/userspace/libsrc/names.c b/drivers/staging/usbip/userspace/libsrc/names.c index 3c8d28b771e0..81ff8522405c 100644 --- a/drivers/staging/usbip/userspace/libsrc/names.c +++ b/drivers/staging/usbip/userspace/libsrc/names.c @@ -169,14 +169,14 @@ static void *my_malloc(size_t size) struct pool *p; p = calloc(1, sizeof(struct pool)); - if (!p) { - free(p); + if (!p) return NULL; - } p->mem = calloc(1, size); - if (!p->mem) + if (!p->mem) { + free(p); return NULL; + } p->next = pool_head; pool_head = p; diff --git a/drivers/staging/usbip/vhci_sysfs.c b/drivers/staging/usbip/vhci_sysfs.c index 9b51586d11d9..0141bc34d5cc 100644 --- a/drivers/staging/usbip/vhci_sysfs.c +++ b/drivers/staging/usbip/vhci_sysfs.c @@ -149,7 +149,8 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed) case USB_SPEED_WIRELESS: break; default: - pr_err("speed %d\n", speed); + pr_err("Failed attach request for unsupported USB speed: %s\n", + usb_speed_string(speed)); return -EINVAL; } diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c index 4a1ddaf5e00f..187fc060de26 100644 --- a/drivers/staging/wlags49_h2/wl_wext.c +++ b/drivers/staging/wlags49_h2/wl_wext.c @@ -1061,7 +1061,7 @@ static int wireless_set_essid(struct net_device *dev, struct iw_request_info *in goto out; } - if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN + 1) { + if (data->flags != 0 && data->length > HCF_MAX_NAME_LEN) { ret = -EINVAL; goto out; } diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index e048d6439f4a..cda4d80cfaef 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -507,7 +507,9 @@ int iscsit_handle_status_snack( u32 last_statsn; int found_cmd; - if (conn->exp_statsn > begrun) { + if (!begrun) { + begrun = conn->exp_statsn; + } else if (conn->exp_statsn > begrun) { pr_err("Got Status SNACK Begrun: 0x%08x, RunLength:" " 0x%08x but already got ExpStatSN: 0x%08x on CID:" " %hu.\n", begrun, runlength, conn->exp_statsn, diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 12da9b386169..c3d9df6aaf5f 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -500,7 +500,7 @@ static inline int core_alua_state_lba_dependent( if (segment_mult) { u64 tmp = lba; - start_lba = sector_div(tmp, segment_size * segment_mult); + start_lba = do_div(tmp, segment_size * segment_mult); last_lba = first_lba + segment_size - 1; if (start_lba >= first_lba && diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 2f5d77932c80..3013287a2aaa 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -2009,7 +2009,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, struct t10_reservation *pr_tmpl = &dev->t10_pr; unsigned char isid_buf[PR_REG_ISID_LEN], *isid_ptr = NULL; sense_reason_t ret = TCM_NO_SENSE; - int pr_holder = 0; + int pr_holder = 0, type; if (!se_sess || !se_lun) { pr_err("SPC-3 PR: se_sess || struct se_lun is NULL!\n"); @@ -2131,6 +2131,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, ret = TCM_RESERVATION_CONFLICT; goto out; } + type = pr_reg->pr_res_type; spin_lock(&pr_tmpl->registration_lock); /* @@ -2161,6 +2162,7 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * Release the calling I_T Nexus registration now.. */ __core_scsi3_free_registration(cmd->se_dev, pr_reg, NULL, 1); + pr_reg = NULL; /* * From spc4r17, section 5.7.11.3 Unregistering @@ -2174,8 +2176,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, * RESERVATIONS RELEASED. */ if (pr_holder && - (pr_reg->pr_res_type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || - pr_reg->pr_res_type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { + (type == PR_TYPE_WRITE_EXCLUSIVE_REGONLY || + type == PR_TYPE_EXCLUSIVE_ACCESS_REGONLY)) { list_for_each_entry(pr_reg_p, &pr_tmpl->registration_list, pr_reg_list) { @@ -2194,7 +2196,8 @@ core_scsi3_emulate_pro_register(struct se_cmd *cmd, u64 res_key, u64 sa_res_key, ret = core_scsi3_update_and_write_aptpl(dev, aptpl); out: - core_scsi3_put_pr_reg(pr_reg); + if (pr_reg) + core_scsi3_put_pr_reg(pr_reg); return ret; } diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index fa3cae393e13..42f18fc1067b 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1074,14 +1074,20 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, struct scatterlist *psg; void *paddr, *addr; unsigned int i, len, left; + unsigned int offset = sg_off; left = sectors * dev->prot_length; for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) { len = min(psg->length, left); + if (offset >= sg->length) { + sg = sg_next(sg); + offset = 0; + } + paddr = kmap_atomic(sg_page(psg)) + psg->offset; - addr = kmap_atomic(sg_page(sg)) + sg_off; + addr = kmap_atomic(sg_page(sg)) + sg->offset + offset; if (read) memcpy(paddr, addr, len); @@ -1089,6 +1095,7 @@ sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read, memcpy(addr, paddr, len); left -= len; + offset += len; kunmap_atomic(paddr); kunmap_atomic(addr); } @@ -1155,7 +1162,7 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, { struct se_device *dev = cmd->se_dev; struct se_dif_v1_tuple *sdt; - struct scatterlist *dsg; + struct scatterlist *dsg, *psg = sg; sector_t sector = start; void *daddr, *paddr; int i, j, offset = sg_off; @@ -1163,14 +1170,14 @@ sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors, for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) { daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; - paddr = kmap_atomic(sg_page(sg)) + sg->offset; + paddr = kmap_atomic(sg_page(psg)) + sg->offset; for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) { - if (offset >= sg->length) { + if (offset >= psg->length) { kunmap_atomic(paddr); - sg = sg_next(sg); - paddr = kmap_atomic(sg_page(sg)) + sg->offset; + psg = sg_next(psg); + paddr = kmap_atomic(sg_page(psg)) + psg->offset; offset = 0; } diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 43c5ca9878bc..3bebc71ea033 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -440,8 +440,8 @@ check_scsi_name: padding = ((-scsi_target_len) & 3); if (padding) scsi_target_len += padding; - if (scsi_name_len > 256) - scsi_name_len = 256; + if (scsi_target_len > 256) + scsi_target_len = 256; buf[off-1] = scsi_target_len; off += scsi_target_len; diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index c50fd9f11aab..2956250b7225 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -669,9 +669,6 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) return; } - if (!success) - cmd->transport_state |= CMD_T_FAILED; - /* * Check for case where an explicit ABORT_TASK has been received * and transport_wait_for_tasks() will be waiting for completion.. @@ -681,7 +678,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) spin_unlock_irqrestore(&cmd->t_state_lock, flags); complete(&cmd->t_transport_stop_comp); return; - } else if (cmd->transport_state & CMD_T_FAILED) { + } else if (!success) { INIT_WORK(&cmd->work, target_complete_failure_work); } else { INIT_WORK(&cmd->work, target_complete_ok_work); @@ -1604,6 +1601,9 @@ void transport_generic_request_failure(struct se_cmd *cmd, case TCM_CHECK_CONDITION_ABORT_CMD: case TCM_CHECK_CONDITION_UNIT_ATTENTION: case TCM_CHECK_CONDITION_NOT_READY: + case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: + case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: + case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: break; case TCM_OUT_OF_RESOURCES: sense_reason = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 6496872e2e47..b01659bd4f7c 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -255,13 +255,7 @@ static int __init hvc_opal_init(void) /* Register as a vio device to receive callbacks */ return platform_driver_register(&hvc_opal_driver); } -module_init(hvc_opal_init); - -static void __exit hvc_opal_exit(void) -{ - platform_driver_unregister(&hvc_opal_driver); -} -module_exit(hvc_opal_exit); +device_initcall(hvc_opal_init); static void udbg_opal_putc(char c) { diff --git a/drivers/tty/hvc/hvc_rtas.c b/drivers/tty/hvc/hvc_rtas.c index 0069bb86ba49..08c87920b74a 100644 --- a/drivers/tty/hvc/hvc_rtas.c +++ b/drivers/tty/hvc/hvc_rtas.c @@ -102,17 +102,7 @@ static int __init hvc_rtas_init(void) return 0; } -module_init(hvc_rtas_init); - -/* This will tear down the tty portion of the driver */ -static void __exit hvc_rtas_exit(void) -{ - /* Really the fun isn't over until the worker thread breaks down and - * the tty cleans up */ - if (hvc_rtas_dev) - hvc_remove(hvc_rtas_dev); -} -module_exit(hvc_rtas_exit); +device_initcall(hvc_rtas_init); /* This will happen prior to module init. There is no tty at this time? */ static int __init hvc_rtas_console_init(void) diff --git a/drivers/tty/hvc/hvc_udbg.c b/drivers/tty/hvc/hvc_udbg.c index 72228276fe31..9cf573d06a29 100644 --- a/drivers/tty/hvc/hvc_udbg.c +++ b/drivers/tty/hvc/hvc_udbg.c @@ -80,14 +80,7 @@ static int __init hvc_udbg_init(void) return 0; } -module_init(hvc_udbg_init); - -static void __exit hvc_udbg_exit(void) -{ - if (hvc_udbg_dev) - hvc_remove(hvc_udbg_dev); -} -module_exit(hvc_udbg_exit); +device_initcall(hvc_udbg_init); static int __init hvc_udbg_console_init(void) { diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index 636c9baad7a5..2dc2831840ca 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -561,18 +561,7 @@ static int __init xen_hvc_init(void) #endif return r; } - -static void __exit xen_hvc_fini(void) -{ - struct xencons_info *entry, *next; - - if (list_empty(&xenconsoles)) - return; - - list_for_each_entry_safe(entry, next, &xenconsoles, list) { - xen_console_remove(entry); - } -} +device_initcall(xen_hvc_init); static int xen_cons_init(void) { @@ -598,10 +587,6 @@ static int xen_cons_init(void) hvc_instantiate(HVC_COOKIE, 0, ops); return 0; } - - -module_init(xen_hvc_init); -module_exit(xen_hvc_fini); console_initcall(xen_cons_init); #ifdef CONFIG_EARLY_PRINTK diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index f34461c5f14e..2ebe47b78a3e 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -1090,6 +1090,7 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) { unsigned int addr = 0; unsigned int modem = 0; + unsigned int brk = 0; struct gsm_dlci *dlci; int len = clen; u8 *dp = data; @@ -1116,6 +1117,16 @@ static void gsm_control_modem(struct gsm_mux *gsm, u8 *data, int clen) if (len == 0) return; } + len--; + if (len > 0) { + while (gsm_read_ea(&brk, *dp++) == 0) { + len--; + if (len == 0) + return; + } + modem <<= 7; + modem |= (brk & 0x7f); + } tty = tty_port_tty_get(&dlci->port); gsm_process_modem(tty, dlci, modem, clen); if (tty) { diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index cb8017aa4434..d15624c1b751 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -817,8 +817,7 @@ static void process_echoes(struct tty_struct *tty) struct n_tty_data *ldata = tty->disc_data; size_t echoed; - if ((!L_ECHO(tty) && !L_ECHONL(tty)) || - ldata->echo_mark == ldata->echo_tail) + if (ldata->echo_mark == ldata->echo_tail) return; mutex_lock(&ldata->output_lock); @@ -1244,7 +1243,8 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) if (L_ECHO(tty)) { echo_char(c, tty); commit_echoes(tty); - } + } else + process_echoes(tty); isig(signal, tty); return; } @@ -1274,7 +1274,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) if (I_IXON(tty)) { if (c == START_CHAR(tty)) { start_tty(tty); - commit_echoes(tty); + process_echoes(tty); return 0; } if (c == STOP_CHAR(tty)) { @@ -1820,8 +1820,10 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) * Fix tty hang when I_IXON(tty) is cleared, but the tty * been stopped by STOP_CHAR(tty) before it. */ - if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) + if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) { start_tty(tty); + process_echoes(tty); + } /* The termios change make the tty ready for I/O */ if (waitqueue_active(&tty->write_wait)) @@ -1896,7 +1898,7 @@ err: static inline int input_available_p(struct tty_struct *tty, int poll) { struct n_tty_data *ldata = tty->disc_data; - int amt = poll && !TIME_CHAR(tty) ? MIN_CHAR(tty) : 1; + int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1; if (ldata->icanon && !L_EXTPROC(tty)) { if (ldata->canon_head != ldata->read_tail) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 61ecd709a722..69932b7556cf 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -2433,6 +2433,24 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, serial_dl_write(up, quot); /* + * XR17V35x UARTs have an extra fractional divisor register (DLD) + * + * We need to recalculate all of the registers, because DLM and DLL + * are already rounded to a whole integer. + * + * When recalculating we use a 32x clock instead of a 16x clock to + * allow 1-bit for rounding in the fractional part. + */ + if (up->port.type == PORT_XR17V35X) { + unsigned int baud_x32 = (port->uartclk * 2) / baud; + u16 quot = baud_x32 / 32; + u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2); + + serial_dl_write(up, quot); + serial_port_out(port, 0x2, quot_frac & 0xf); + } + + /* * LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR * is written without DLAB set, this mode will be disabled. */ diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index faa64e646100..ed3113576740 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -391,7 +391,7 @@ static int dw8250_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int dw8250_suspend(struct device *dev) { struct dw8250_data *data = dev_get_drvdata(dev); @@ -409,7 +409,7 @@ static int dw8250_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ +#endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_PM_RUNTIME static int dw8250_runtime_suspend(struct device *dev) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 50228eed3b6f..0ff3e3624d4c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -783,7 +783,8 @@ static int pci_netmos_9900_setup(struct serial_private *priv, { unsigned int bar; - if ((priv->dev->subsystem_device & 0xff00) == 0x3000) { + if ((priv->dev->device != PCI_DEVICE_ID_NETMOS_9865) && + (priv->dev->subsystem_device & 0xff00) == 0x3000) { /* netmos apparently orders BARs by datasheet layout, so serial * ports get BARs 0 and 3 (or 1 and 4 for memmapped) */ diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index fa511ebab67c..77f035158d6c 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -738,9 +738,6 @@ static int serial_omap_startup(struct uart_port *port) return retval; } disable_irq(up->wakeirq); - } else { - dev_info(up->port.dev, "no wakeirq for uart%d\n", - up->port.line); } dev_dbg(up->port.dev, "serial_omap_startup+%d\n", up->port.line); @@ -1604,8 +1601,11 @@ static int serial_omap_probe_rs485(struct uart_omap_port *up, flags & SER_RS485_RTS_AFTER_SEND); if (ret < 0) return ret; - } else + } else if (up->rts_gpio == -EPROBE_DEFER) { + return -EPROBE_DEFER; + } else { up->rts_gpio = -EINVAL; + } if (of_property_read_u32_array(np, "rs485-rts-delay", rs485_delay, 2) == 0) { @@ -1687,6 +1687,9 @@ static int serial_omap_probe(struct platform_device *pdev) up->port.iotype = UPIO_MEM; up->port.irq = uartirq; up->wakeirq = wakeirq; + if (!up->wakeirq) + dev_info(up->port.dev, "no wakeirq for uart%d\n", + up->port.line); up->port.regshift = 2; up->port.fifosize = 64; diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 49a2ffd101a7..b7bfe24d4ebc 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -542,8 +542,10 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param) wr_regl(port, ureg->sirfsoc_rx_dma_io_ctrl, rd_regl(port, ureg->sirfsoc_rx_dma_io_ctrl) | SIRFUART_IO_MODE); - sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); spin_unlock_irqrestore(&sirfport->rx_lock, flags); + spin_lock(&port->lock); + sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count); + spin_unlock(&port->lock); if (sirfport->rx_io_count == 4) { spin_lock_irqsave(&sirfport->rx_lock, flags); sirfport->rx_io_count = 0; diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c index 61b1137d7e56..23b5d32954bf 100644 --- a/drivers/tty/vt/vt.c +++ b/drivers/tty/vt/vt.c @@ -1164,6 +1164,8 @@ static void csi_J(struct vc_data *vc, int vpar) scr_memsetw(vc->vc_screenbuf, vc->vc_video_erase_char, vc->vc_screenbuf_size >> 1); set_origin(vc); + if (CON_IS_VISIBLE(vc)) + update_screen(vc); /* fall through */ case 2: /* erase whole display */ count = vc->vc_cols * vc->vc_rows; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 80de2f88ed2c..4ab2cb62dfce 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -105,7 +105,7 @@ static int hw_ep_flush(struct ci_hdrc *ci, int num, int dir) do { /* flush any pending transfer */ - hw_write(ci, OP_ENDPTFLUSH, BIT(n), BIT(n)); + hw_write(ci, OP_ENDPTFLUSH, ~0, BIT(n)); while (hw_read(ci, OP_ENDPTFLUSH, BIT(n))) cpu_relax(); } while (hw_read(ci, OP_ENDPTSTAT, BIT(n))); @@ -205,7 +205,7 @@ static int hw_ep_prime(struct ci_hdrc *ci, int num, int dir, int is_ctrl) if (is_ctrl && dir == RX && hw_read(ci, OP_ENDPTSETUPSTAT, BIT(num))) return -EAGAIN; - hw_write(ci, OP_ENDPTPRIME, BIT(n), BIT(n)); + hw_write(ci, OP_ENDPTPRIME, ~0, BIT(n)); while (hw_read(ci, OP_ENDPTPRIME, BIT(n))) cpu_relax(); diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 5d01558cef66..ab90a0156828 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -63,8 +63,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, dynid->id.idProduct = idProduct; dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE; if (fields > 2 && bInterfaceClass) { - if (bInterfaceClass > 255) - return -EINVAL; + if (bInterfaceClass > 255) { + retval = -EINVAL; + goto fail; + } dynid->id.bInterfaceClass = (u8)bInterfaceClass; dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS; @@ -73,17 +75,21 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, if (fields > 4) { const struct usb_device_id *id = id_table; - if (!id) - return -ENODEV; + if (!id) { + retval = -ENODEV; + goto fail; + } for (; id->match_flags; id++) if (id->idVendor == refVendor && id->idProduct == refProduct) break; - if (id->match_flags) + if (id->match_flags) { dynid->id.driver_info = id->driver_info; - else - return -ENODEV; + } else { + retval = -ENODEV; + goto fail; + } } spin_lock(&dynids->lock); @@ -95,6 +101,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, if (retval) return retval; return count; + +fail: + kfree(dynid); + return retval; } EXPORT_SYMBOL_GPL(usb_store_new_id); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 199aaea6bfe0..2518c3250750 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1032,7 +1032,6 @@ static int register_root_hub(struct usb_hcd *hcd) dev_name(&usb_dev->dev), retval); return retval; } - usb_dev->lpm_capable = usb_device_supports_lpm(usb_dev); } retval = usb_new_device (usb_dev); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index babba885978d..64ea21971be2 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -128,7 +128,7 @@ struct usb_hub *usb_hub_to_struct_hub(struct usb_device *hdev) return usb_get_intfdata(hdev->actconfig->interface[0]); } -int usb_device_supports_lpm(struct usb_device *udev) +static int usb_device_supports_lpm(struct usb_device *udev) { /* USB 2.1 (and greater) devices indicate LPM support through * their USB 2.0 Extended Capabilities BOS descriptor. @@ -149,11 +149,6 @@ int usb_device_supports_lpm(struct usb_device *udev) "Power management will be impacted.\n"); return 0; } - - /* udev is root hub */ - if (!udev->parent) - return 1; - if (udev->parent->lpm_capable) return 1; diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index c49383669cd8..823857767a16 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -35,7 +35,6 @@ extern int usb_get_device_descriptor(struct usb_device *dev, unsigned int size); extern int usb_get_bos_descriptor(struct usb_device *dev); extern void usb_release_bos_descriptor(struct usb_device *dev); -extern int usb_device_supports_lpm(struct usb_device *udev); extern char *usb_cache_string(struct usb_device *udev, int index); extern int usb_set_configuration(struct usb_device *dev, int configuration); extern int usb_choose_configuration(struct usb_device *udev); diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c index 8565d87f94b4..1d129884cc39 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -216,7 +216,7 @@ static int dwc2_hs_phy_init(struct dwc2_hsotg *hsotg, bool select_phy) int retval = 0; if (!select_phy) - return -ENODEV; + return 0; usbcfg = readl(hsotg->regs + GUSBCFG); diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c index f59484d43b35..4d918ed8d343 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c @@ -2565,25 +2565,14 @@ static void _dwc2_hcd_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep) { struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd); - int is_control = usb_endpoint_xfer_control(&ep->desc); - int is_out = usb_endpoint_dir_out(&ep->desc); - int epnum = usb_endpoint_num(&ep->desc); - struct usb_device *udev; unsigned long flags; dev_dbg(hsotg->dev, "DWC OTG HCD EP RESET: bEndpointAddress=0x%02x\n", ep->desc.bEndpointAddress); - udev = to_usb_device(hsotg->dev); - spin_lock_irqsave(&hsotg->lock, flags); - - usb_settoggle(udev, epnum, is_out, 0); - if (is_control) - usb_settoggle(udev, epnum, !is_out, 0); dwc2_hcd_endpoint_reset(hsotg, ep); - spin_unlock_irqrestore(&hsotg->lock, flags); } diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c index d01d0d3f2cf0..eaba547ce26b 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -124,6 +124,9 @@ static int dwc2_driver_probe(struct platform_device *dev) int retval; int irq; + if (usb_disabled()) + return -ENODEV; + match = of_match_device(dwc2_of_match_table, &dev->dev); if (match && match->data) { params = match->data; diff --git a/drivers/usb/gadget/bcm63xx_udc.c b/drivers/usb/gadget/bcm63xx_udc.c index 888fbb43b338..e969eb809a85 100644 --- a/drivers/usb/gadget/bcm63xx_udc.c +++ b/drivers/usb/gadget/bcm63xx_udc.c @@ -360,24 +360,30 @@ static inline void usb_dma_writel(struct bcm63xx_udc *udc, u32 val, u32 off) bcm_writel(val, udc->iudma_regs + off); } -static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmac_readl(struct bcm63xx_udc *udc, u32 off, int chan) { - return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off); + return bcm_readl(udc->iudma_regs + IUDMA_DMAC_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmac_writel(struct bcm63xx_udc *udc, u32 val, u32 off, + int chan) { - bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off); + bcm_writel(val, udc->iudma_regs + IUDMA_DMAC_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off) +static inline u32 usb_dmas_readl(struct bcm63xx_udc *udc, u32 off, int chan) { - return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off); + return bcm_readl(udc->iudma_regs + IUDMA_DMAS_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } -static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off) +static inline void usb_dmas_writel(struct bcm63xx_udc *udc, u32 val, u32 off, + int chan) { - bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off); + bcm_writel(val, udc->iudma_regs + IUDMA_DMAS_OFFSET + off + + (ENETDMA_CHAN_WIDTH * chan)); } static inline void set_clocks(struct bcm63xx_udc *udc, bool is_enabled) @@ -638,7 +644,7 @@ static void iudma_write(struct bcm63xx_udc *udc, struct iudma_ch *iudma, } while (!last_bd); usb_dmac_writel(udc, ENETDMAC_CHANCFG_EN_MASK, - ENETDMAC_CHANCFG_REG(iudma->ch_idx)); + ENETDMAC_CHANCFG_REG, iudma->ch_idx); } /** @@ -694,9 +700,9 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) bcm63xx_fifo_reset_ep(udc, max(0, iudma->ep_num)); /* stop DMA, then wait for the hardware to wrap up */ - usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG(ch_idx)); + usb_dmac_writel(udc, 0, ENETDMAC_CHANCFG_REG, ch_idx); - while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)) & + while (usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx) & ENETDMAC_CHANCFG_EN_MASK) { udelay(1); @@ -713,10 +719,10 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) dev_warn(udc->dev, "forcibly halting IUDMA channel %d\n", ch_idx); usb_dmac_writel(udc, ENETDMAC_CHANCFG_BUFHALT_MASK, - ENETDMAC_CHANCFG_REG(ch_idx)); + ENETDMAC_CHANCFG_REG, ch_idx); } } - usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG(ch_idx)); + usb_dmac_writel(udc, ~0, ENETDMAC_IR_REG, ch_idx); /* don't leave "live" HW-owned entries for the next guy to step on */ for (d = iudma->bd_ring; d <= iudma->end_bd; d++) @@ -728,11 +734,11 @@ static void iudma_reset_channel(struct bcm63xx_udc *udc, struct iudma_ch *iudma) /* set up IRQs, UBUS burst size, and BD base for this channel */ usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, - ENETDMAC_IRMASK_REG(ch_idx)); - usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG(ch_idx)); + ENETDMAC_IRMASK_REG, ch_idx); + usb_dmac_writel(udc, 8, ENETDMAC_MAXBURST_REG, ch_idx); - usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG(ch_idx)); - usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG(ch_idx)); + usb_dmas_writel(udc, iudma->bd_ring_dma, ENETDMAS_RSTART_REG, ch_idx); + usb_dmas_writel(udc, 0, ENETDMAS_SRAM2_REG, ch_idx); } /** @@ -2035,7 +2041,7 @@ static irqreturn_t bcm63xx_udc_data_isr(int irq, void *dev_id) spin_lock(&udc->lock); usb_dmac_writel(udc, ENETDMAC_IR_BUFDONE_MASK, - ENETDMAC_IR_REG(iudma->ch_idx)); + ENETDMAC_IR_REG, iudma->ch_idx); bep = iudma->bep; rc = iudma_read(udc, iudma); @@ -2175,18 +2181,18 @@ static int bcm63xx_iudma_dbg_show(struct seq_file *s, void *p) seq_printf(s, " [ep%d]:\n", max_t(int, iudma_defaults[ch_idx].ep_num, 0)); seq_printf(s, " cfg: %08x; irqstat: %08x; irqmask: %08x; maxburst: %08x\n", - usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_IR_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_IRMASK_REG(ch_idx)), - usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG(ch_idx))); + usb_dmac_readl(udc, ENETDMAC_CHANCFG_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_IR_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_IRMASK_REG, ch_idx), + usb_dmac_readl(udc, ENETDMAC_MAXBURST_REG, ch_idx)); - sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG(ch_idx)); - sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG(ch_idx)); + sram2 = usb_dmas_readl(udc, ENETDMAS_SRAM2_REG, ch_idx); + sram3 = usb_dmas_readl(udc, ENETDMAS_SRAM3_REG, ch_idx); seq_printf(s, " base: %08x; index: %04x_%04x; desc: %04x_%04x %08x\n", - usb_dmas_readl(udc, ENETDMAS_RSTART_REG(ch_idx)), + usb_dmas_readl(udc, ENETDMAS_RSTART_REG, ch_idx), sram2 >> 16, sram2 & 0xffff, sram3 >> 16, sram3 & 0xffff, - usb_dmas_readl(udc, ENETDMAS_SRAM4_REG(ch_idx))); + usb_dmas_readl(udc, ENETDMAS_SRAM4_REG, ch_idx)); seq_printf(s, " desc: %d/%d used", iudma->n_bds_used, iudma->n_bds); diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index 306a2b52125c..2b4334394076 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -585,7 +585,6 @@ static ssize_t ffs_epfile_io(struct file *file, char __user *buf, size_t len, int read) { struct ffs_epfile *epfile = file->private_data; - struct usb_gadget *gadget = epfile->ffs->gadget; struct ffs_ep *ep; char *data = NULL; ssize_t ret, data_len; @@ -622,6 +621,12 @@ static ssize_t ffs_epfile_io(struct file *file, /* Allocate & copy */ if (!halt) { /* + * if we _do_ wait above, the epfile->ffs->gadget might be NULL + * before the waiting completes, so do not assign to 'gadget' earlier + */ + struct usb_gadget *gadget = epfile->ffs->gadget; + + /* * Controller may require buffer size to be aligned to * maxpacketsize of an out endpoint. */ diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index bf7a56b6d48a..69b76efd11e9 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -1157,7 +1157,7 @@ static int __init printer_bind_config(struct usb_configuration *c) usb_gadget_set_selfpowered(gadget); - if (gadget->is_otg) { + if (gadget_is_otg(gadget)) { otg_descriptor.bmAttributes |= USB_OTG_HNP; printer_cfg_driver.descriptors = otg_desc; printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index f04b2c3154de..dd9678f85c58 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1629,7 +1629,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev) ep->ep.desc = NULL; ep->halted = 0; INIT_LIST_HEAD(&ep->queue); - usb_ep_set_maxpacket_limit(&ep->ep, &ep->ep.maxpacket); + usb_ep_set_maxpacket_limit(&ep->ep, ep->ep.maxpacket); } } diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 471142725ffe..81cda09b47e3 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -685,8 +685,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) struct ehci_hcd *ehci = hcd_to_ehci (hcd); u32 status, masked_status, pcd_status = 0, cmd; int bh; + unsigned long flags; - spin_lock (&ehci->lock); + /* + * For threadirqs option we use spin_lock_irqsave() variant to prevent + * deadlock with ehci hrtimer callback, because hrtimer callbacks run + * in interrupt context even when threadirqs is specified. We can go + * back to spin_lock() variant when hrtimer callbacks become threaded. + */ + spin_lock_irqsave(&ehci->lock, flags); status = ehci_readl(ehci, &ehci->regs->status); @@ -704,7 +711,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* Shared IRQ? */ if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) { - spin_unlock(&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); return IRQ_NONE; } @@ -815,7 +822,7 @@ dead: if (bh) ehci_work (ehci); - spin_unlock (&ehci->lock); + spin_unlock_irqrestore(&ehci->lock, flags); if (pcd_status) usb_hcd_poll_rh_status(hcd); return IRQ_HANDLED; diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 47b858fc50b2..7ae0c4d51741 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) int port; int mask; int changed; + bool fs_idle_delay; ehci_dbg(ehci, "suspend root hub\n"); @@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) ehci->bus_suspended = 0; ehci->owned_ports = 0; changed = 0; + fs_idle_delay = false; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status [port]; @@ -300,16 +302,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) } if (t1 != t2) { + /* + * On some controllers, Wake-On-Disconnect will + * generate false wakeup signals until the bus + * switches over to full-speed idle. For their + * sake, add a delay if we need one. + */ + if ((t2 & PORT_WKDISC_E) && + ehci_port_speed(ehci, t2) == + USB_PORT_STAT_HIGH_SPEED) + fs_idle_delay = true; ehci_writel(ehci, t2, reg); changed = 1; } } + spin_unlock_irq(&ehci->lock); + + if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) { + /* + * Wait for HCD to enter low-power mode or for the bus + * to switch to full-speed idle. + */ + usleep_range(5000, 5500); + } if (changed && ehci->has_tdi_phy_lpm) { - spin_unlock_irq(&ehci->lock); - msleep(5); /* 5 ms for HCD to enter low-power mode */ spin_lock_irq(&ehci->lock); - port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; @@ -322,8 +340,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) port, (t3 & HOSTPC_PHCD) ? "succeeded" : "failed"); } + spin_unlock_irq(&ehci->lock); } - spin_unlock_irq(&ehci->lock); /* Apparently some devices need a >= 1-uframe delay here */ if (ehci->bus_suspended) diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c index b016d38199f2..eb009a457fb5 100644 --- a/drivers/usb/host/xhci-dbg.c +++ b/drivers/usb/host/xhci-dbg.c @@ -203,12 +203,12 @@ void xhci_print_ir_set(struct xhci_hcd *xhci, int set_num) addr, (unsigned int)temp); addr = &ir_set->erst_base; - temp_64 = readq(addr); + temp_64 = xhci_read_64(xhci, addr); xhci_dbg(xhci, " %p: ir_set.erst_base = @%08llx\n", addr, temp_64); addr = &ir_set->erst_dequeue; - temp_64 = readq(addr); + temp_64 = xhci_read_64(xhci, addr); xhci_dbg(xhci, " %p: ir_set.erst_dequeue = @%08llx\n", addr, temp_64); } @@ -412,7 +412,7 @@ void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci) { u64 val; - val = readq(&xhci->op_regs->cmd_ring); + val = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = @%08x\n", lower_32_bits(val)); xhci_dbg(xhci, "// xHC command ring deq ptr high bits = @%08x\n", diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 873c272b3ef5..bce4391a0e7d 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1958,7 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) xhci_warn(xhci, "WARN something wrong with SW event ring " "dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ - temp = readq(&xhci->ir_set->erst_dequeue); + temp = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; /* Don't clear the EHB bit (which is RW1C) because * there might be more events to service. @@ -1967,7 +1967,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Write event ring dequeue pointer, " "preserving EHB bit"); - writeq(((u64) deq & (u64) ~ERST_PTR_MASK) | temp, + xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &xhci->ir_set->erst_dequeue); } @@ -2269,7 +2269,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Device context base array address = 0x%llx (DMA), %p (virt)", (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); - writeq(dma, &xhci->op_regs->dcbaa_ptr); + xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* * Initialize the ring segment pool. The ring must be a contiguous @@ -2312,13 +2312,13 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) (unsigned long long)xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ - val_64 = readq(&xhci->op_regs->cmd_ring); + val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | (xhci->cmd_ring->first_seg->dma & (u64) ~CMD_RING_RSVD_BITS) | xhci->cmd_ring->cycle_state; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Setting command ring address to 0x%x", val); - writeq(val_64, &xhci->op_regs->cmd_ring); + xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags); @@ -2396,10 +2396,10 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Set ERST base address for ir_set 0 = 0x%llx", (unsigned long long)xhci->erst.erst_dma_addr); - val_64 = readq(&xhci->ir_set->erst_base); + val_64 = xhci_read_64(xhci, &xhci->ir_set->erst_base); val_64 &= ERST_PTR_MASK; val_64 |= (xhci->erst.erst_dma_addr & (u64) ~ERST_PTR_MASK); - writeq(val_64, &xhci->ir_set->erst_base); + xhci_write_64(xhci, val_64, &xhci->ir_set->erst_base); /* Set the event ring dequeue address */ xhci_set_hc_event_deq(xhci); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 3c898c12a06b..04f986d9234f 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -142,6 +142,11 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) "QUIRK: Resetting on resume"); xhci->quirks |= XHCI_TRUST_TX_LENGTH; } + if (pdev->vendor == PCI_VENDOR_ID_RENESAS && + pdev->device == 0x0015 && + pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG && + pdev->subsystem_device == 0xc0cd) + xhci->quirks |= XHCI_RESET_ON_RESUME; if (pdev->vendor == PCI_VENDOR_ID_VIA) xhci->quirks |= XHCI_RESET_ON_RESUME; } diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index a0b248c34526..0ed64eb68e48 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -307,13 +307,14 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci) return 0; } - temp_64 = readq(&xhci->op_regs->cmd_ring); + temp_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); if (!(temp_64 & CMD_RING_RUNNING)) { xhci_dbg(xhci, "Command ring had been stopped\n"); return 0; } xhci->cmd_ring_state = CMD_RING_STATE_ABORTED; - writeq(temp_64 | CMD_RING_ABORT, &xhci->op_regs->cmd_ring); + xhci_write_64(xhci, temp_64 | CMD_RING_ABORT, + &xhci->op_regs->cmd_ring); /* Section 4.6.1.2 of xHCI 1.0 spec says software should * time the completion od all xHCI commands, including @@ -2864,8 +2865,9 @@ hw_died: /* Clear the event handler busy flag (RW1C); * the event ring should be empty. */ - temp_64 = readq(&xhci->ir_set->erst_dequeue); - writeq(temp_64 | ERST_EHB, &xhci->ir_set->erst_dequeue); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + xhci_write_64(xhci, temp_64 | ERST_EHB, + &xhci->ir_set->erst_dequeue); spin_unlock(&xhci->lock); return IRQ_HANDLED; @@ -2877,7 +2879,7 @@ hw_died: */ while (xhci_handle_event(xhci) > 0) {} - temp_64 = readq(&xhci->ir_set->erst_dequeue); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); /* If necessary, update the HW's version of the event ring deq ptr. */ if (event_ring_deq != xhci->event_ring->dequeue) { deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, @@ -2892,7 +2894,7 @@ hw_died: /* Clear the event handler busy flag (RW1C); event ring is empty. */ temp_64 |= ERST_EHB; - writeq(temp_64, &xhci->ir_set->erst_dequeue); + xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); spin_unlock(&xhci->lock); @@ -2965,58 +2967,8 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring, } while (1) { - if (room_on_ring(xhci, ep_ring, num_trbs)) { - union xhci_trb *trb = ep_ring->enqueue; - unsigned int usable = ep_ring->enq_seg->trbs + - TRBS_PER_SEGMENT - 1 - trb; - u32 nop_cmd; - - /* - * Section 4.11.7.1 TD Fragments states that a link - * TRB must only occur at the boundary between - * data bursts (eg 512 bytes for 480M). - * While it is possible to split a large fragment - * we don't know the size yet. - * Simplest solution is to fill the trb before the - * LINK with nop commands. - */ - if (num_trbs == 1 || num_trbs <= usable || usable == 0) - break; - - if (ep_ring->type != TYPE_BULK) - /* - * While isoc transfers might have a buffer that - * crosses a 64k boundary it is unlikely. - * Since we can't add NOPs without generating - * gaps in the traffic just hope it never - * happens at the end of the ring. - * This could be fixed by writing a LINK TRB - * instead of the first NOP - however the - * TRB_TYPE_LINK_LE32() calls would all need - * changing to check the ring length. - */ - break; - - if (num_trbs >= TRBS_PER_SEGMENT) { - xhci_err(xhci, "Too many fragments %d, max %d\n", - num_trbs, TRBS_PER_SEGMENT - 1); - return -EINVAL; - } - - nop_cmd = cpu_to_le32(TRB_TYPE(TRB_TR_NOOP) | - ep_ring->cycle_state); - ep_ring->num_trbs_free -= usable; - do { - trb->generic.field[0] = 0; - trb->generic.field[1] = 0; - trb->generic.field[2] = 0; - trb->generic.field[3] = nop_cmd; - trb++; - } while (--usable); - ep_ring->enqueue = trb; - if (room_on_ring(xhci, ep_ring, num_trbs)) - break; - } + if (room_on_ring(xhci, ep_ring, num_trbs)) + break; if (ep_ring == xhci->cmd_ring) { xhci_err(xhci, "Do not support expand command ring\n"); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index ad364394885a..6fe577d46fa2 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -611,7 +611,7 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg(xhci, "Event ring:\n"); xhci_debug_ring(xhci, xhci->event_ring); xhci_dbg_ring_ptrs(xhci, xhci->event_ring); - temp_64 = readq(&xhci->ir_set->erst_dequeue); + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "ERST deq = 64'h%0lx", (long unsigned int) temp_64); @@ -756,11 +756,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci) { xhci->s3.command = readl(&xhci->op_regs->command); xhci->s3.dev_nt = readl(&xhci->op_regs->dev_notification); - xhci->s3.dcbaa_ptr = readq(&xhci->op_regs->dcbaa_ptr); + xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci->s3.config_reg = readl(&xhci->op_regs->config_reg); xhci->s3.erst_size = readl(&xhci->ir_set->erst_size); - xhci->s3.erst_base = readq(&xhci->ir_set->erst_base); - xhci->s3.erst_dequeue = readq(&xhci->ir_set->erst_dequeue); + xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base); + xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); xhci->s3.irq_pending = readl(&xhci->ir_set->irq_pending); xhci->s3.irq_control = readl(&xhci->ir_set->irq_control); } @@ -769,11 +769,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci) { writel(xhci->s3.command, &xhci->op_regs->command); writel(xhci->s3.dev_nt, &xhci->op_regs->dev_notification); - writeq(xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); + xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr); writel(xhci->s3.config_reg, &xhci->op_regs->config_reg); writel(xhci->s3.erst_size, &xhci->ir_set->erst_size); - writeq(xhci->s3.erst_base, &xhci->ir_set->erst_base); - writeq(xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); + xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base); + xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue); writel(xhci->s3.irq_pending, &xhci->ir_set->irq_pending); writel(xhci->s3.irq_control, &xhci->ir_set->irq_control); } @@ -783,7 +783,7 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) u64 val_64; /* step 2: initialize command ring buffer */ - val_64 = readq(&xhci->op_regs->cmd_ring); + val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); val_64 = (val_64 & (u64) CMD_RING_RSVD_BITS) | (xhci_trb_virt_to_dma(xhci->cmd_ring->deq_seg, xhci->cmd_ring->dequeue) & @@ -792,7 +792,7 @@ static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Setting command ring address to 0x%llx", (long unsigned long) val_64); - writeq(val_64, &xhci->op_regs->cmd_ring); + xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); } /* @@ -3842,7 +3842,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev, if (ret) { return ret; } - temp_64 = readq(&xhci->op_regs->dcbaa_ptr); + temp_64 = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr); xhci_dbg_trace(xhci, trace_xhci_dbg_address, "Op regs DCBAA ptr = %#016llx", temp_64); xhci_dbg_trace(xhci, trace_xhci_dbg_address, @@ -4730,11 +4730,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) struct device *dev = hcd->self.controller; int retval; - /* Limit the block layer scatter-gather lists to half a segment. */ - hcd->self.sg_tablesize = TRBS_PER_SEGMENT / 2; - - /* support to build packet from discontinuous buffers */ - hcd->self.no_sg_constraint = 1; + /* Accept arbitrarily long scatter-gather lists */ + hcd->self.sg_tablesize = ~0; /* XHCI controllers don't stop the ep queue on short packets :| */ hcd->self.no_stop_on_short = 1; @@ -4760,6 +4757,14 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ + xhci = hcd_to_xhci(hcd); + /* + * Support arbitrarily aligned sg-list entries on hosts without + * TD fragment rules (which are currently unsupported). + */ + if (xhci->hci_version < 0x100) + hcd->self.no_sg_constraint = 1; + return 0; } @@ -4788,6 +4793,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) if (xhci->hci_version > 0x96) xhci->quirks |= XHCI_SPURIOUS_SUCCESS; + if (xhci->hci_version < 0x100) + hcd->self.no_sg_constraint = 1; + /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f8416639bf31..58ed9d088e63 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -28,17 +28,6 @@ #include <linux/kernel.h> #include <linux/usb/hcd.h> -/* - * Registers should always be accessed with double word or quad word accesses. - * - * Some xHCI implementations may support 64-bit address pointers. Registers - * with 64-bit address pointers should be written to with dword accesses by - * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. - * xHCI implementations that do not support 64-bit address pointers will ignore - * the high dword, and write order is irrelevant. - */ -#include <asm-generic/io-64-nonatomic-lo-hi.h> - /* Code sharing between pci-quirks and xhci hcd */ #include "xhci-ext-caps.h" #include "pci-quirks.h" @@ -1279,7 +1268,7 @@ union xhci_trb { * since the command ring is 64-byte aligned. * It must also be greater than 16. */ -#define TRBS_PER_SEGMENT 256 +#define TRBS_PER_SEGMENT 64 /* Allow two commands + a link TRB, along with any reserved command TRBs */ #define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3) #define TRB_SEGMENT_SIZE (TRBS_PER_SEGMENT*16) @@ -1614,6 +1603,34 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci) #define xhci_warn_ratelimited(xhci, fmt, args...) \ dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args) +/* + * Registers should always be accessed with double word or quad word accesses. + * + * Some xHCI implementations may support 64-bit address pointers. Registers + * with 64-bit address pointers should be written to with dword accesses by + * writing the low dword first (ptr[0]), then the high dword (ptr[1]) second. + * xHCI implementations that do not support 64-bit address pointers will ignore + * the high dword, and write order is irrelevant. + */ +static inline u64 xhci_read_64(const struct xhci_hcd *xhci, + __le64 __iomem *regs) +{ + __u32 __iomem *ptr = (__u32 __iomem *) regs; + u64 val_lo = readl(ptr); + u64 val_hi = readl(ptr + 1); + return val_lo + (val_hi << 32); +} +static inline void xhci_write_64(struct xhci_hcd *xhci, + const u64 val, __le64 __iomem *regs) +{ + __u32 __iomem *ptr = (__u32 __iomem *) regs; + u32 val_lo = lower_32_bits(val); + u32 val_hi = upper_32_bits(val); + + writel(val_lo, ptr); + writel(val_hi, ptr + 1); +} + static inline int xhci_link_trb_quirk(struct xhci_hcd *xhci) { return xhci->quirks & XHCI_LINK_TRB_QUIRK; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index fc192ad9cc6a..239ad0b1ceb6 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -477,8 +477,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, musb->port1_status |= (USB_PORT_STAT_C_SUSPEND << 16) | MUSB_PORT_STAT_RESUME; + musb->rh_timer = jiffies + + msecs_to_jiffies(20); schedule_delayed_work( - &musb->finish_resume_work, 20); + &musb->finish_resume_work, + msecs_to_jiffies(20)); musb->xceiv->state = OTG_STATE_A_HOST; musb->is_active = 1; @@ -2157,11 +2160,19 @@ static void musb_restore_context(struct musb *musb) void __iomem *musb_base = musb->mregs; void __iomem *ep_target_regs; void __iomem *epio; + u8 power; musb_writew(musb_base, MUSB_FRAME, musb->context.frame); musb_writeb(musb_base, MUSB_TESTMODE, musb->context.testmode); musb_write_ulpi_buscontrol(musb->mregs, musb->context.busctl); - musb_writeb(musb_base, MUSB_POWER, musb->context.power); + + /* Don't affect SUSPENDM/RESUME bits in POWER reg */ + power = musb_readb(musb_base, MUSB_POWER); + power &= MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME; + musb->context.power &= ~(MUSB_POWER_SUSPENDM | MUSB_POWER_RESUME); + power |= musb->context.power; + musb_writeb(musb_base, MUSB_POWER, power); + musb_writew(musb_base, MUSB_INTRTXE, musb->intrtxe); musb_writew(musb_base, MUSB_INTRRXE, musb->intrrxe); musb_writeb(musb_base, MUSB_INTRUSBE, musb->context.intrusbe); diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c index ed455724017b..abb38c3833ef 100644 --- a/drivers/usb/musb/musb_host.c +++ b/drivers/usb/musb/musb_host.c @@ -1183,6 +1183,9 @@ irqreturn_t musb_h_ep0_irq(struct musb *musb) csr = MUSB_CSR0_H_STATUSPKT | MUSB_CSR0_TXPKTRDY; + /* disable ping token in status phase */ + csr |= MUSB_CSR0_H_DIS_PING; + /* flag status stage */ musb->ep0_stage = MUSB_EP0_STATUS; diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index eb634433ef09..e2d2d8c9891b 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c @@ -135,7 +135,8 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; - schedule_delayed_work(&musb->finish_resume_work, 20); + schedule_delayed_work(&musb->finish_resume_work, + msecs_to_jiffies(20)); } } @@ -158,7 +159,6 @@ void musb_port_reset(struct musb *musb, bool do_reset) */ power = musb_readb(mbase, MUSB_POWER); if (do_reset) { - /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let musb start @@ -167,11 +167,22 @@ void musb_port_reset(struct musb *musb, bool do_reset) * detected". */ if (power & MUSB_POWER_RESUME) { - while (time_before(jiffies, musb->rh_timer)) - msleep(1); + long remain = (unsigned long) musb->rh_timer - jiffies; + + if (musb->rh_timer > 0 && remain > 0) { + /* take into account the minimum delay after resume */ + schedule_delayed_work( + &musb->deassert_reset_work, remain); + return; + } + musb_writeb(mbase, MUSB_POWER, - power & ~MUSB_POWER_RESUME); - msleep(1); + power & ~MUSB_POWER_RESUME); + + /* Give the core 1 ms to clear MUSB_POWER_RESUME */ + schedule_delayed_work(&musb->deassert_reset_work, + msecs_to_jiffies(1)); + return; } power &= 0xf0; @@ -180,7 +191,8 @@ void musb_port_reset(struct musb *musb, bool do_reset) musb->port1_status |= USB_PORT_STAT_RESET; musb->port1_status &= ~USB_PORT_STAT_ENABLE; - schedule_delayed_work(&musb->deassert_reset_work, 50); + schedule_delayed_work(&musb->deassert_reset_work, + msecs_to_jiffies(50)); } else { dev_dbg(musb->controller, "root port reset stopped\n"); musb_writeb(mbase, MUSB_POWER, diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 2a408cdaf7b2..8aa59a2c5eb2 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -659,7 +659,6 @@ static int omap2430_runtime_suspend(struct device *dev) OTG_INTERFSEL); omap2430_low_level_exit(musb); - phy_power_off(musb->phy); } return 0; @@ -674,7 +673,6 @@ static int omap2430_runtime_resume(struct device *dev) omap2430_low_level_init(musb); musb_writel(musb->mregs, OTG_INTERFSEL, musb->context.otg_interfsel); - phy_power_on(musb->phy); } return 0; diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c index 8546c8dccd51..d204f745ed05 100644 --- a/drivers/usb/phy/phy-msm-usb.c +++ b/drivers/usb/phy/phy-msm-usb.c @@ -159,32 +159,6 @@ put_3p3: return rc; } -#ifdef CONFIG_PM_SLEEP -#define USB_PHY_SUSP_DIG_VOL 500000 -static int msm_hsusb_config_vddcx(int high) -{ - int max_vol = USB_PHY_VDD_DIG_VOL_MAX; - int min_vol; - int ret; - - if (high) - min_vol = USB_PHY_VDD_DIG_VOL_MIN; - else - min_vol = USB_PHY_SUSP_DIG_VOL; - - ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); - if (ret) { - pr_err("%s: unable to set the voltage for regulator " - "HSUSB_VDDCX\n", __func__); - return ret; - } - - pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); - - return ret; -} -#endif - static int msm_hsusb_ldo_set_mode(int on) { int ret = 0; @@ -440,7 +414,32 @@ static int msm_otg_reset(struct usb_phy *phy) #define PHY_SUSPEND_TIMEOUT_USEC (500 * 1000) #define PHY_RESUME_TIMEOUT_USEC (100 * 1000) -#ifdef CONFIG_PM_SLEEP +#ifdef CONFIG_PM + +#define USB_PHY_SUSP_DIG_VOL 500000 +static int msm_hsusb_config_vddcx(int high) +{ + int max_vol = USB_PHY_VDD_DIG_VOL_MAX; + int min_vol; + int ret; + + if (high) + min_vol = USB_PHY_VDD_DIG_VOL_MIN; + else + min_vol = USB_PHY_SUSP_DIG_VOL; + + ret = regulator_set_voltage(hsusb_vddcx, min_vol, max_vol); + if (ret) { + pr_err("%s: unable to set the voltage for regulator " + "HSUSB_VDDCX\n", __func__); + return ret; + } + + pr_debug("%s: min_vol:%d max_vol:%d\n", __func__, min_vol, max_vol); + + return ret; +} + static int msm_otg_suspend(struct msm_otg *motg) { struct usb_phy *phy = &motg->phy; @@ -1733,22 +1732,18 @@ static int msm_otg_pm_resume(struct device *dev) } #endif -#ifdef CONFIG_PM static const struct dev_pm_ops msm_otg_dev_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(msm_otg_pm_suspend, msm_otg_pm_resume) SET_RUNTIME_PM_OPS(msm_otg_runtime_suspend, msm_otg_runtime_resume, msm_otg_runtime_idle) }; -#endif static struct platform_driver msm_otg_driver = { .remove = msm_otg_remove, .driver = { .name = DRIVER_NAME, .owner = THIS_MODULE, -#ifdef CONFIG_PM .pm = &msm_otg_dev_pm_ops, -#endif }, }; diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c index e6f61e4361df..8afa813d690b 100644 --- a/drivers/usb/phy/phy.c +++ b/drivers/usb/phy/phy.c @@ -130,7 +130,7 @@ struct usb_phy *usb_get_phy(enum usb_phy_type type) phy = __usb_find_phy(&phy_list, type); if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { - pr_err("unable to find transceiver of type %s\n", + pr_debug("PHY: unable to find transceiver of type %s\n", usb_phy_type_string(type)); goto err0; } @@ -228,7 +228,7 @@ struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) phy = __usb_find_phy_dev(dev, &phy_bind_list, index); if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { - pr_err("unable to find transceiver\n"); + dev_dbg(dev, "unable to find transceiver\n"); goto err0; } @@ -424,10 +424,8 @@ int usb_bind_phy(const char *dev_name, u8 index, unsigned long flags; phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL); - if (!phy_bind) { - pr_err("phy_bind(): No memory for phy_bind"); + if (!phy_bind) return -ENOMEM; - } phy_bind->dev_name = dev_name; phy_bind->phy_dev_name = phy_dev_name; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index ce0d7b0db012..44ab12986805 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -152,6 +152,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(FTDI_VID, FTDI_CANUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_CANDAPTER_PID) }, { USB_DEVICE(FTDI_VID, FTDI_NXTCAM_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_EV3CON_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_0_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_1_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SCS_DEVICE_2_PID) }, @@ -191,6 +192,8 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) }, { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) }, { USB_DEVICE(FTDI_VID, FTDI_SPROG_II) }, + { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_LP101_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TAGSYS_P200X_PID) }, { USB_DEVICE(FTDI_VID, FTDI_LENZ_LIUSB_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_632_PID) }, { USB_DEVICE(FTDI_VID, FTDI_XF_634_PID) }, @@ -904,6 +907,8 @@ static const struct usb_device_id id_table_combined[] = { /* Crucible Devices */ { USB_DEVICE(FTDI_VID, FTDI_CT_COMET_PID) }, { USB_DEVICE(FTDI_VID, FTDI_Z3X_PID) }, + /* Cressi Devices */ + { USB_DEVICE(FTDI_VID, FTDI_CRESSI_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index a7019d1e3058..e599fbfcde5f 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -50,6 +50,7 @@ #define TI_XDS100V2_PID 0xa6d0 #define FTDI_NXTCAM_PID 0xABB8 /* NXTCam for Mindstorms NXT */ +#define FTDI_EV3CON_PID 0xABB9 /* Mindstorms EV3 Console Adapter */ /* US Interface Navigator (http://www.usinterface.com/) */ #define FTDI_USINT_CAT_PID 0xb810 /* Navigator CAT and 2nd PTT lines */ @@ -363,6 +364,12 @@ /* Sprog II (Andrew Crosland's SprogII DCC interface) */ #define FTDI_SPROG_II 0xF0C8 +/* + * Two of the Tagsys RFID Readers + */ +#define FTDI_TAGSYS_LP101_PID 0xF0E9 /* Tagsys L-P101 RFID*/ +#define FTDI_TAGSYS_P200X_PID 0xF0EE /* Tagsys Medio P200x RFID*/ + /* an infrared receiver for user access control with IR tags */ #define FTDI_PIEGROUP_PID 0xF208 /* Product Id */ @@ -1313,3 +1320,9 @@ * Manufacturer: Smart GSM Team */ #define FTDI_Z3X_PID 0x0011 + +/* + * Product: Cressi PC Interface + * Manufacturer: Cressi + */ +#define FTDI_CRESSI_PID 0x87d0 diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 5c86f57e4afa..68fc9fe65936 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1362,7 +1362,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1267, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1268, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1269, 0xff, 0xff, 0xff) }, - { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff) }, + { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1270, 0xff, 0xff, 0xff), + .driver_info = (kernel_ulong_t)&net_intf5_blacklist }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1271, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1272, 0xff, 0xff, 0xff) }, { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1273, 0xff, 0xff, 0xff) }, @@ -1525,7 +1526,8 @@ static const struct usb_device_id option_ids[] = { /* Cinterion */ { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_E) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) }, - { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8) }, + { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8), + .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) }, { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX), .driver_info = (kernel_ulong_t)&net_intf4_blacklist }, diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index c65437cfd4a2..968a40201e5f 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -139,6 +139,9 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 0)}, /* Sierra Wireless EM7700 Device Management */ {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 2)}, /* Sierra Wireless EM7700 NMEA */ {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x901c, 3)}, /* Sierra Wireless EM7700 Modem */ + {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 0)}, /* Netgear AirCard 340U Device Management */ + {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 2)}, /* Netgear AirCard 340U NMEA */ + {USB_DEVICE_INTERFACE_NUMBER(0x1199, 0x9051, 3)}, /* Netgear AirCard 340U Modem */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/usb-serial-simple.c b/drivers/usb/serial/usb-serial-simple.c index f112b079ddfc..fb79775447b0 100644 --- a/drivers/usb/serial/usb-serial-simple.c +++ b/drivers/usb/serial/usb-serial-simple.c @@ -71,7 +71,8 @@ DEVICE(hp4x, HP4X_IDS); /* Suunto ANT+ USB Driver */ #define SUUNTO_IDS() \ - { USB_DEVICE(0x0fcf, 0x1008) } + { USB_DEVICE(0x0fcf, 0x1008) }, \ + { USB_DEVICE(0x0fcf, 0x1009) } /* Dynastream ANT USB-m Stick */ DEVICE(suunto, SUUNTO_IDS); /* Siemens USB/MPI adapter */ diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 8470e1b114f2..1dd0604d1911 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -18,7 +18,9 @@ config USB_STORAGE This option depends on 'SCSI' support being enabled, but you probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. + (BLK_DEV_SD) for most USB storage devices. Some devices also + will require 'Probe all LUNs on each SCSI device' + (SCSI_MULTI_LUN). To compile this driver as a module, choose M here: the module will be called usb-storage. diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 18509e6c21ab..9d38ddc8da49 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -78,6 +78,8 @@ static const char* host_info(struct Scsi_Host *host) static int slave_alloc (struct scsi_device *sdev) { + struct us_data *us = host_to_us(sdev->host); + /* * Set the INQUIRY transfer length to 36. We don't use any of * the extra data and many devices choke if asked for more or @@ -102,6 +104,10 @@ static int slave_alloc (struct scsi_device *sdev) */ blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1)); + /* Tell the SCSI layer if we know there is more than one LUN */ + if (us->protocol == USB_PR_BULK && us->max_lun > 0) + sdev->sdev_bflags |= BLIST_FORCELUN; + return 0; } diff --git a/drivers/usb/storage/unusual_cypress.h b/drivers/usb/storage/unusual_cypress.h index 65a6a75066a8..82e8ed0324e3 100644 --- a/drivers/usb/storage/unusual_cypress.h +++ b/drivers/usb/storage/unusual_cypress.h @@ -31,7 +31,7 @@ UNUSUAL_DEV( 0x04b4, 0x6831, 0x0000, 0x9999, "Cypress ISD-300LP", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), -UNUSUAL_DEV( 0x14cd, 0x6116, 0x0000, 0x0219, +UNUSUAL_DEV( 0x14cd, 0x6116, 0x0160, 0x0160, "Super Top", "USB 2.0 SATA BRIDGE", USB_SC_CYP_ATACB, USB_PR_DEVICE, NULL, 0), diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index ad06255c2ade..adbeb255616a 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1455,6 +1455,13 @@ UNUSUAL_DEV( 0x0f88, 0x042e, 0x0100, 0x0100, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Moritz Moeller-Herrmann <moritz-kernel@moeller-herrmann.de> */ +UNUSUAL_DEV( 0x0fca, 0x8004, 0x0201, 0x0201, + "Research In Motion", + "BlackBerry Bold 9000", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_MAX_SECTORS_64 ), + /* Reported by Michael Stattmann <michael@stattmann.com> */ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000, "Sony Ericsson", diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 4fb7a8f83c8a..54af4e933695 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -186,12 +186,12 @@ static bool is_invalid_reserved_pfn(unsigned long pfn) if (pfn_valid(pfn)) { bool reserved; struct page *tail = pfn_to_page(pfn); - struct page *head = compound_trans_head(tail); + struct page *head = compound_head(tail); reserved = !!(PageReserved(head)); if (head != tail) { /* * "head" is not a dangling pointer - * (compound_trans_head takes care of that) + * (compound_head takes care of that) * but the hugepage may have been split * from under us (and we may not hold a * reference count on the head page so it can diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index 9a68409580d5..a0fa5de210cf 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c @@ -70,7 +70,12 @@ enum { }; struct vhost_net_ubuf_ref { - struct kref kref; + /* refcount follows semantics similar to kref: + * 0: object is released + * 1: no outstanding ubufs + * >1: outstanding ubufs + */ + atomic_t refcount; wait_queue_head_t wait; struct vhost_virtqueue *vq; }; @@ -116,14 +121,6 @@ static void vhost_net_enable_zcopy(int vq) vhost_net_zcopy_mask |= 0x1 << vq; } -static void vhost_net_zerocopy_done_signal(struct kref *kref) -{ - struct vhost_net_ubuf_ref *ubufs; - - ubufs = container_of(kref, struct vhost_net_ubuf_ref, kref); - wake_up(&ubufs->wait); -} - static struct vhost_net_ubuf_ref * vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) { @@ -134,21 +131,24 @@ vhost_net_ubuf_alloc(struct vhost_virtqueue *vq, bool zcopy) ubufs = kmalloc(sizeof(*ubufs), GFP_KERNEL); if (!ubufs) return ERR_PTR(-ENOMEM); - kref_init(&ubufs->kref); + atomic_set(&ubufs->refcount, 1); init_waitqueue_head(&ubufs->wait); ubufs->vq = vq; return ubufs; } -static void vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) +static int vhost_net_ubuf_put(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); + int r = atomic_sub_return(1, &ubufs->refcount); + if (unlikely(!r)) + wake_up(&ubufs->wait); + return r; } static void vhost_net_ubuf_put_and_wait(struct vhost_net_ubuf_ref *ubufs) { - kref_put(&ubufs->kref, vhost_net_zerocopy_done_signal); - wait_event(ubufs->wait, !atomic_read(&ubufs->kref.refcount)); + vhost_net_ubuf_put(ubufs); + wait_event(ubufs->wait, !atomic_read(&ubufs->refcount)); } static void vhost_net_ubuf_put_wait_and_free(struct vhost_net_ubuf_ref *ubufs) @@ -306,23 +306,26 @@ static void vhost_zerocopy_callback(struct ubuf_info *ubuf, bool success) { struct vhost_net_ubuf_ref *ubufs = ubuf->ctx; struct vhost_virtqueue *vq = ubufs->vq; - int cnt = atomic_read(&ubufs->kref.refcount); + int cnt; + + rcu_read_lock_bh(); /* set len to mark this desc buffers done DMA */ vq->heads[ubuf->desc].len = success ? VHOST_DMA_DONE_LEN : VHOST_DMA_FAILED_LEN; - vhost_net_ubuf_put(ubufs); + cnt = vhost_net_ubuf_put(ubufs); /* * Trigger polling thread if guest stopped submitting new buffers: - * in this case, the refcount after decrement will eventually reach 1 - * so here it is 2. + * in this case, the refcount after decrement will eventually reach 1. * We also trigger polling periodically after each 16 packets * (the value 16 here is more or less arbitrary, it's tuned to trigger * less than 10% of times). */ - if (cnt <= 2 || !(cnt % 16)) + if (cnt <= 1 || !(cnt % 16)) vhost_poll_queue(&vq->poll); + + rcu_read_unlock_bh(); } /* Expects to be always run from workqueue - which acts as @@ -420,7 +423,7 @@ static void handle_tx(struct vhost_net *net) msg.msg_control = ubuf; msg.msg_controllen = sizeof(ubuf); ubufs = nvq->ubufs; - kref_get(&ubufs->kref); + atomic_inc(&ubufs->refcount); nvq->upend_idx = (nvq->upend_idx + 1) % UIO_MAXIOV; } else { msg.msg_control = NULL; @@ -780,7 +783,7 @@ static void vhost_net_flush(struct vhost_net *n) vhost_net_ubuf_put_and_wait(n->vqs[VHOST_NET_VQ_TX].ubufs); mutex_lock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); n->tx_flush = false; - kref_init(&n->vqs[VHOST_NET_VQ_TX].ubufs->kref); + atomic_set(&n->vqs[VHOST_NET_VQ_TX].ubufs->refcount, 1); mutex_unlock(&n->vqs[VHOST_NET_VQ_TX].vq.mutex); } } @@ -800,6 +803,8 @@ static int vhost_net_release(struct inode *inode, struct file *f) fput(tx_sock->file); if (rx_sock) fput(rx_sock->file); + /* Make sure no callbacks are outstanding */ + synchronize_rcu_bh(); /* We do an extra flush before freeing memory, * since jobs can re-queue themselves. */ vhost_net_flush(n); diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 0a025b8e2a12..e48d4a672580 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1001,6 +1001,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) break; } + /* virtio-scsi spec requires byte 0 of the lun to be 1 */ + if (unlikely(v_req.lun[0] != 1)) { + vhost_scsi_send_bad_target(vs, vq, head, out); + continue; + } + /* Extract the tpgt */ target = v_req.lun[1]; tpg = ACCESS_ONCE(vs_tpg[target]); diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 22262a3a0e2d..dade5b7699bc 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -364,7 +364,7 @@ config FB_SA1100 config FB_IMX tristate "Freescale i.MX1/21/25/27 LCD support" - depends on FB && IMX_HAVE_PLATFORM_IMX_FB + depends on FB && ARCH_MXC select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT diff --git a/drivers/video/exynos/Kconfig b/drivers/video/exynos/Kconfig index 1129d0e9e640..75c8a8e7efc0 100644 --- a/drivers/video/exynos/Kconfig +++ b/drivers/video/exynos/Kconfig @@ -22,7 +22,8 @@ config EXYNOS_MIPI_DSI config EXYNOS_LCD_S6E8AX0 bool "S6E8AX0 MIPI AMOLED LCD Driver" - depends on (EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE && LCD_CLASS_DEVICE) + depends on EXYNOS_MIPI_DSI && BACKLIGHT_CLASS_DEVICE + depends on (LCD_CLASS_DEVICE = y) default n help If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c index bbeb8dd7f108..77d6221618f4 100644 --- a/drivers/video/omap2/dss/dispc.c +++ b/drivers/video/omap2/dss/dispc.c @@ -2160,8 +2160,8 @@ static int dispc_ovl_calc_scaling_24xx(unsigned long pclk, unsigned long lclk, *five_taps = false; do { - in_height = DIV_ROUND_UP(height, *decim_y); - in_width = DIV_ROUND_UP(width, *decim_x); + in_height = height / *decim_y; + in_width = width / *decim_x; *core_clk = dispc.feat->calc_core_clk(pclk, in_width, in_height, out_width, out_height, mem_to_mem); error = (in_width > maxsinglelinewidth || !*core_clk || @@ -2199,8 +2199,8 @@ static int dispc_ovl_calc_scaling_34xx(unsigned long pclk, unsigned long lclk, dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); do { - in_height = DIV_ROUND_UP(height, *decim_y); - in_width = DIV_ROUND_UP(width, *decim_x); + in_height = height / *decim_y; + in_width = width / *decim_x; *five_taps = in_height > out_height; if (in_width > maxsinglelinewidth) @@ -2268,7 +2268,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, { u16 in_width, in_width_max; int decim_x_min = *decim_x; - u16 in_height = DIV_ROUND_UP(height, *decim_y); + u16 in_height = height / *decim_y; const int maxsinglelinewidth = dss_feat_get_param_max(FEAT_PARAM_LINEWIDTH); const int maxdownscale = dss_feat_get_param_max(FEAT_PARAM_DOWNSCALE); @@ -2287,7 +2287,7 @@ static int dispc_ovl_calc_scaling_44xx(unsigned long pclk, unsigned long lclk, return -EINVAL; do { - in_width = DIV_ROUND_UP(width, *decim_x); + in_width = width / *decim_x; } while (*decim_x <= *x_predecim && in_width > maxsinglelinewidth && ++*decim_x); @@ -2466,8 +2466,8 @@ static int dispc_ovl_setup_common(enum omap_plane plane, if (r) return r; - in_width = DIV_ROUND_UP(in_width, x_predecim); - in_height = DIV_ROUND_UP(in_height, y_predecim); + in_width = in_width / x_predecim; + in_height = in_height / y_predecim; if (color_mode == OMAP_DSS_COLOR_YUV2 || color_mode == OMAP_DSS_COLOR_UYVY || diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c index 7411f2674e16..23ef21ffc2c4 100644 --- a/drivers/video/omap2/dss/dpi.c +++ b/drivers/video/omap2/dss/dpi.c @@ -117,7 +117,7 @@ struct dpi_clk_calc_ctx { /* outputs */ struct dsi_clock_info dsi_cinfo; - unsigned long long fck; + unsigned long fck; struct dispc_clock_info dispc_cinfo; }; diff --git a/drivers/video/omap2/dss/sdi.c b/drivers/video/omap2/dss/sdi.c index efb9ee9e3c96..ba806c9e7f54 100644 --- a/drivers/video/omap2/dss/sdi.c +++ b/drivers/video/omap2/dss/sdi.c @@ -46,7 +46,7 @@ static struct { struct sdi_clk_calc_ctx { unsigned long pck_min, pck_max; - unsigned long long fck; + unsigned long fck; struct dispc_clock_info dispc_cinfo; }; diff --git a/drivers/vme/bridges/vme_ca91cx42.c b/drivers/vme/bridges/vme_ca91cx42.c index a06edbfa95ca..1b5d48c578e1 100644 --- a/drivers/vme/bridges/vme_ca91cx42.c +++ b/drivers/vme/bridges/vme_ca91cx42.c @@ -884,7 +884,7 @@ static ssize_t ca91cx42_master_read(struct vme_master_resource *image, if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { *(u8 *)(buf + done) = ioread8(addr + done); done += 1; @@ -938,7 +938,7 @@ static ssize_t ca91cx42_master_write(struct vme_master_resource *image, if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { iowrite8(*(u8 *)(buf + done), addr + done); done += 1; diff --git a/drivers/vme/bridges/vme_tsi148.c b/drivers/vme/bridges/vme_tsi148.c index 16830d8b777c..9911cd5fddb5 100644 --- a/drivers/vme/bridges/vme_tsi148.c +++ b/drivers/vme/bridges/vme_tsi148.c @@ -1289,7 +1289,7 @@ static ssize_t tsi148_master_read(struct vme_master_resource *image, void *buf, if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { *(u8 *)(buf + done) = ioread8(addr + done); done += 1; @@ -1371,7 +1371,7 @@ static ssize_t tsi148_master_write(struct vme_master_resource *image, void *buf, if (done == count) goto out; } - if ((uintptr_t)addr & 0x2) { + if ((uintptr_t)(addr + done) & 0x2) { if ((count - done) < 2) { iowrite8(*(u8 *)(buf + done), addr + done); done += 1; diff --git a/drivers/watchdog/w83697hf_wdt.c b/drivers/watchdog/w83697hf_wdt.c index aaf2995d37f4..68b45fc9ba6a 100644 --- a/drivers/watchdog/w83697hf_wdt.c +++ b/drivers/watchdog/w83697hf_wdt.c @@ -402,7 +402,7 @@ static int __init wdt_init(void) if (!found) { pr_err("No W83697HF/HG could be found\n"); - ret = -EIO; + ret = -ENODEV; goto out; } diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile index d75c811bfa56..45e00afa7f2d 100644 --- a/drivers/xen/Makefile +++ b/drivers/xen/Makefile @@ -16,7 +16,6 @@ xen-pad-$(CONFIG_X86) += xen-acpi-pad.o dom0-$(CONFIG_X86) += pcpu.o obj-$(CONFIG_XEN_DOM0) += $(dom0-y) obj-$(CONFIG_BLOCK) += biomerge.o -obj-$(CONFIG_XEN_XENCOMM) += xencomm.o obj-$(CONFIG_XEN_BALLOON) += xen-balloon.o obj-$(CONFIG_XEN_SELFBALLOONING) += xen-selfballoon.o obj-$(CONFIG_XEN_DEV_EVTCHN) += xen-evtchn.o diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 4672e003c0ad..f4a9e3311297 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -862,6 +862,8 @@ int bind_evtchn_to_irq(unsigned int evtchn) irq = ret; goto out; } + /* New interdomain events are bound to VCPU 0. */ + bind_evtchn_to_cpu(evtchn, 0); } else { struct irq_info *info = info_for_irq(irq); WARN_ON(info == NULL || info->type != IRQT_EVTCHN); diff --git a/drivers/xen/xencomm.c b/drivers/xen/xencomm.c deleted file mode 100644 index 4793fc594549..000000000000 --- a/drivers/xen/xencomm.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) IBM Corp. 2006 - * - * Authors: Hollis Blanchard <hollisb@us.ibm.com> - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/mm.h> -#include <linux/slab.h> -#include <asm/page.h> -#include <xen/xencomm.h> -#include <xen/interface/xen.h> -#include <asm/xen/xencomm.h> /* for xencomm_is_phys_contiguous() */ - -static int xencomm_init(struct xencomm_desc *desc, - void *buffer, unsigned long bytes) -{ - unsigned long recorded = 0; - int i = 0; - - while ((recorded < bytes) && (i < desc->nr_addrs)) { - unsigned long vaddr = (unsigned long)buffer + recorded; - unsigned long paddr; - int offset; - int chunksz; - - offset = vaddr % PAGE_SIZE; /* handle partial pages */ - chunksz = min(PAGE_SIZE - offset, bytes - recorded); - - paddr = xencomm_vtop(vaddr); - if (paddr == ~0UL) { - printk(KERN_DEBUG "%s: couldn't translate vaddr %lx\n", - __func__, vaddr); - return -EINVAL; - } - - desc->address[i++] = paddr; - recorded += chunksz; - } - - if (recorded < bytes) { - printk(KERN_DEBUG - "%s: could only translate %ld of %ld bytes\n", - __func__, recorded, bytes); - return -ENOSPC; - } - - /* mark remaining addresses invalid (just for safety) */ - while (i < desc->nr_addrs) - desc->address[i++] = XENCOMM_INVALID; - - desc->magic = XENCOMM_MAGIC; - - return 0; -} - -static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask, - void *buffer, unsigned long bytes) -{ - struct xencomm_desc *desc; - unsigned long buffer_ulong = (unsigned long)buffer; - unsigned long start = buffer_ulong & PAGE_MASK; - unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK; - unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT; - unsigned long size = sizeof(*desc) + - sizeof(desc->address[0]) * nr_addrs; - - /* - * slab allocator returns at least sizeof(void*) aligned pointer. - * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might - * cross page boundary. - */ - if (sizeof(*desc) > sizeof(void *)) { - unsigned long order = get_order(size); - desc = (struct xencomm_desc *)__get_free_pages(gfp_mask, - order); - if (desc == NULL) - return NULL; - - desc->nr_addrs = - ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) / - sizeof(*desc->address); - } else { - desc = kmalloc(size, gfp_mask); - if (desc == NULL) - return NULL; - - desc->nr_addrs = nr_addrs; - } - return desc; -} - -void xencomm_free(struct xencomm_handle *desc) -{ - if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) { - struct xencomm_desc *desc__ = (struct xencomm_desc *)desc; - if (sizeof(*desc__) > sizeof(void *)) { - unsigned long size = sizeof(*desc__) + - sizeof(desc__->address[0]) * desc__->nr_addrs; - unsigned long order = get_order(size); - free_pages((unsigned long)__va(desc), order); - } else - kfree(__va(desc)); - } -} - -static int xencomm_create(void *buffer, unsigned long bytes, - struct xencomm_desc **ret, gfp_t gfp_mask) -{ - struct xencomm_desc *desc; - int rc; - - pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes); - - if (bytes == 0) { - /* don't create a descriptor; Xen recognizes NULL. */ - BUG_ON(buffer != NULL); - *ret = NULL; - return 0; - } - - BUG_ON(buffer == NULL); /* 'bytes' is non-zero */ - - desc = xencomm_alloc(gfp_mask, buffer, bytes); - if (!desc) { - printk(KERN_DEBUG "%s failure\n", "xencomm_alloc"); - return -ENOMEM; - } - - rc = xencomm_init(desc, buffer, bytes); - if (rc) { - printk(KERN_DEBUG "%s failure: %d\n", "xencomm_init", rc); - xencomm_free((struct xencomm_handle *)__pa(desc)); - return rc; - } - - *ret = desc; - return 0; -} - -static struct xencomm_handle *xencomm_create_inline(void *ptr) -{ - unsigned long paddr; - - BUG_ON(!xencomm_is_phys_contiguous((unsigned long)ptr)); - - paddr = (unsigned long)xencomm_pa(ptr); - BUG_ON(paddr & XENCOMM_INLINE_FLAG); - return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG); -} - -/* "mini" routine, for stack-based communications: */ -static int xencomm_create_mini(void *buffer, - unsigned long bytes, struct xencomm_mini *xc_desc, - struct xencomm_desc **ret) -{ - int rc = 0; - struct xencomm_desc *desc; - BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0); - - desc = (void *)xc_desc; - - desc->nr_addrs = XENCOMM_MINI_ADDRS; - - rc = xencomm_init(desc, buffer, bytes); - if (!rc) - *ret = desc; - - return rc; -} - -struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes) -{ - int rc; - struct xencomm_desc *desc; - - if (xencomm_is_phys_contiguous((unsigned long)ptr)) - return xencomm_create_inline(ptr); - - rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL); - - if (rc || desc == NULL) - return NULL; - - return xencomm_pa(desc); -} - -struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes, - struct xencomm_mini *xc_desc) -{ - int rc; - struct xencomm_desc *desc = NULL; - - if (xencomm_is_phys_contiguous((unsigned long)ptr)) - return xencomm_create_inline(ptr); - - rc = xencomm_create_mini(ptr, bytes, xc_desc, - &desc); - - if (rc) - return NULL; - - return xencomm_pa(desc); -} |